1// Copyright 2020 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package soongconfig 16 17import ( 18 "reflect" 19 "testing" 20 21 "github.com/google/blueprint/proptools" 22) 23 24func Test_CanonicalizeToProperty(t *testing.T) { 25 tests := []struct { 26 name string 27 arg string 28 want string 29 }{ 30 { 31 name: "lowercase", 32 arg: "board", 33 want: "board", 34 }, 35 { 36 name: "uppercase", 37 arg: "BOARD", 38 want: "BOARD", 39 }, 40 { 41 name: "numbers", 42 arg: "BOARD123", 43 want: "BOARD123", 44 }, 45 { 46 name: "underscore", 47 arg: "TARGET_BOARD", 48 want: "TARGET_BOARD", 49 }, 50 { 51 name: "dash", 52 arg: "TARGET-BOARD", 53 want: "TARGET_BOARD", 54 }, 55 { 56 name: "unicode", 57 arg: "boardλ", 58 want: "board_", 59 }, 60 } 61 for _, tt := range tests { 62 t.Run(tt.name, func(t *testing.T) { 63 if got := CanonicalizeToProperty(tt.arg); got != tt.want { 64 t.Errorf("canonicalizeToProperty() = %v, want %v", got, tt.want) 65 } 66 }) 67 } 68} 69 70func Test_typeForPropertyFromPropertyStruct(t *testing.T) { 71 tests := []struct { 72 name string 73 ps interface{} 74 property string 75 want string 76 }{ 77 { 78 name: "string", 79 ps: struct { 80 A string 81 }{}, 82 property: "a", 83 want: "string", 84 }, 85 { 86 name: "list", 87 ps: struct { 88 A []string 89 }{}, 90 property: "a", 91 want: "[]string", 92 }, 93 { 94 name: "missing", 95 ps: struct { 96 A []string 97 }{}, 98 property: "b", 99 want: "", 100 }, 101 { 102 name: "nested", 103 ps: struct { 104 A struct { 105 B string 106 } 107 }{}, 108 property: "a.b", 109 want: "string", 110 }, 111 { 112 name: "missing nested", 113 ps: struct { 114 A struct { 115 B string 116 } 117 }{}, 118 property: "a.c", 119 want: "", 120 }, 121 { 122 name: "not a struct", 123 ps: struct { 124 A string 125 }{}, 126 property: "a.b", 127 want: "", 128 }, 129 { 130 name: "nested pointer", 131 ps: struct { 132 A *struct { 133 B string 134 } 135 }{}, 136 property: "a.b", 137 want: "string", 138 }, 139 { 140 name: "nested interface", 141 ps: struct { 142 A interface{} 143 }{ 144 A: struct { 145 B string 146 }{}, 147 }, 148 property: "a.b", 149 want: "string", 150 }, 151 { 152 name: "nested interface pointer", 153 ps: struct { 154 A interface{} 155 }{ 156 A: &struct { 157 B string 158 }{}, 159 }, 160 property: "a.b", 161 want: "string", 162 }, 163 { 164 name: "nested interface nil pointer", 165 ps: struct { 166 A interface{} 167 }{ 168 A: (*struct { 169 B string 170 })(nil), 171 }, 172 property: "a.b", 173 want: "string", 174 }, 175 } 176 for _, tt := range tests { 177 t.Run(tt.name, func(t *testing.T) { 178 typ := typeForPropertyFromPropertyStruct(tt.ps, tt.property) 179 got := "" 180 if typ != nil { 181 got = typ.String() 182 } 183 if got != tt.want { 184 t.Errorf("typeForPropertyFromPropertyStruct() = %v, want %v", got, tt.want) 185 } 186 }) 187 } 188} 189 190func Test_createAffectablePropertiesType(t *testing.T) { 191 tests := []struct { 192 name string 193 affectableProperties []string 194 factoryProps interface{} 195 want string 196 }{ 197 { 198 name: "string", 199 affectableProperties: []string{"cflags"}, 200 factoryProps: struct { 201 Cflags string 202 }{}, 203 want: "*struct { Cflags string }", 204 }, 205 { 206 name: "list", 207 affectableProperties: []string{"cflags"}, 208 factoryProps: struct { 209 Cflags []string 210 }{}, 211 want: "*struct { Cflags []string }", 212 }, 213 { 214 name: "string pointer", 215 affectableProperties: []string{"cflags"}, 216 factoryProps: struct { 217 Cflags *string 218 }{}, 219 want: "*struct { Cflags *string }", 220 }, 221 { 222 name: "subset", 223 affectableProperties: []string{"cflags"}, 224 factoryProps: struct { 225 Cflags string 226 Ldflags string 227 }{}, 228 want: "*struct { Cflags string }", 229 }, 230 { 231 name: "none", 232 affectableProperties: []string{"cflags"}, 233 factoryProps: struct { 234 Ldflags string 235 }{}, 236 want: "", 237 }, 238 { 239 name: "nested", 240 affectableProperties: []string{"multilib.lib32.cflags"}, 241 factoryProps: struct { 242 Multilib struct { 243 Lib32 struct { 244 Cflags string 245 } 246 } 247 }{}, 248 want: "*struct { Multilib struct { Lib32 struct { Cflags string } } }", 249 }, 250 { 251 name: "complex", 252 affectableProperties: []string{ 253 "cflags", 254 "multilib.lib32.cflags", 255 "multilib.lib32.ldflags", 256 "multilib.lib64.cflags", 257 "multilib.lib64.ldflags", 258 "zflags", 259 }, 260 factoryProps: struct { 261 Cflags string 262 Multilib struct { 263 Lib32 struct { 264 Cflags string 265 Ldflags string 266 } 267 Lib64 struct { 268 Cflags string 269 Ldflags string 270 } 271 } 272 Zflags string 273 }{}, 274 want: "*struct { Cflags string; Multilib struct { Lib32 struct { Cflags string; Ldflags string }; Lib64 struct { Cflags string; Ldflags string } }; Zflags string }", 275 }, 276 } 277 for _, tt := range tests { 278 t.Run(tt.name, func(t *testing.T) { 279 typ := createAffectablePropertiesType(tt.affectableProperties, []interface{}{tt.factoryProps}) 280 got := "" 281 if typ != nil { 282 got = typ.String() 283 } 284 if !reflect.DeepEqual(got, tt.want) { 285 t.Errorf("createAffectablePropertiesType() = %v, want %v", got, tt.want) 286 } 287 }) 288 } 289} 290 291type properties struct { 292 A *string 293 B bool 294} 295 296type boolVarProps struct { 297 A *string 298 B bool 299 Conditions_default *properties 300} 301 302type soongConfigVars struct { 303 Bool_var interface{} 304} 305 306func Test_PropertiesToApply(t *testing.T) { 307 mt, _ := newModuleType(&ModuleTypeProperties{ 308 Module_type: "foo", 309 Config_namespace: "bar", 310 Bool_variables: []string{"bool_var"}, 311 Properties: []string{"a", "b"}, 312 }) 313 boolVarPositive := &properties{ 314 A: proptools.StringPtr("A"), 315 B: true, 316 } 317 conditionsDefault := &properties{ 318 A: proptools.StringPtr("default"), 319 B: false, 320 } 321 actualProps := &struct { 322 Soong_config_variables soongConfigVars 323 }{ 324 Soong_config_variables: soongConfigVars{ 325 Bool_var: &boolVarProps{ 326 A: boolVarPositive.A, 327 B: boolVarPositive.B, 328 Conditions_default: conditionsDefault, 329 }, 330 }, 331 } 332 props := reflect.ValueOf(actualProps) 333 334 testCases := []struct { 335 name string 336 config SoongConfig 337 wantProps []interface{} 338 }{ 339 { 340 name: "no_vendor_config", 341 config: Config(map[string]string{}), 342 wantProps: []interface{}{conditionsDefault}, 343 }, 344 { 345 name: "vendor_config_false", 346 config: Config(map[string]string{"bool_var": "n"}), 347 wantProps: []interface{}{conditionsDefault}, 348 }, 349 { 350 name: "bool_var_true", 351 config: Config(map[string]string{"bool_var": "y"}), 352 wantProps: []interface{}{boolVarPositive}, 353 }, 354 } 355 356 for _, tc := range testCases { 357 gotProps, err := PropertiesToApply(mt, props, tc.config) 358 if err != nil { 359 t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err) 360 } 361 362 if !reflect.DeepEqual(gotProps, tc.wantProps) { 363 t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps) 364 } 365 } 366} 367