1// Copyright 2019 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 android 16 17import ( 18 "reflect" 19 "runtime" 20 "testing" 21 22 "github.com/google/blueprint/proptools" 23) 24 25type Named struct { 26 A *string `android:"arch_variant"` 27 B *string 28} 29 30type NamedAllFiltered struct { 31 A *string 32} 33 34type NamedNoneFiltered struct { 35 A *string `android:"arch_variant"` 36} 37 38func TestFilterArchStruct(t *testing.T) { 39 tests := []struct { 40 name string 41 in interface{} 42 out interface{} 43 filtered bool 44 }{ 45 // Property tests 46 { 47 name: "basic", 48 in: &struct { 49 A *string `android:"arch_variant"` 50 B *string 51 }{}, 52 out: &struct { 53 A *string 54 }{}, 55 filtered: true, 56 }, 57 { 58 name: "tags", 59 in: &struct { 60 A *string `android:"arch_variant"` 61 B *string `android:"arch_variant,path"` 62 C *string `android:"arch_variant,path,variant_prepend"` 63 D *string `android:"path,variant_prepend,arch_variant"` 64 E *string `android:"path"` 65 F *string 66 }{}, 67 out: &struct { 68 A *string 69 B *string `android:"path"` 70 C *string `android:"path"` 71 D *string `android:"path"` 72 }{}, 73 filtered: true, 74 }, 75 { 76 name: "all filtered", 77 in: &struct { 78 A *string 79 }{}, 80 out: nil, 81 filtered: true, 82 }, 83 { 84 name: "none filtered", 85 in: &struct { 86 A *string `android:"arch_variant"` 87 }{}, 88 out: &struct { 89 A *string `android:"arch_variant"` 90 }{}, 91 filtered: false, 92 }, 93 94 // Sub-struct tests 95 { 96 name: "substruct", 97 in: &struct { 98 A struct { 99 A *string `android:"arch_variant"` 100 B *string 101 } `android:"arch_variant"` 102 }{}, 103 out: &struct { 104 A struct { 105 A *string 106 } 107 }{}, 108 filtered: true, 109 }, 110 { 111 name: "substruct all filtered", 112 in: &struct { 113 A struct { 114 A *string 115 } `android:"arch_variant"` 116 }{}, 117 out: nil, 118 filtered: true, 119 }, 120 { 121 name: "substruct none filtered", 122 in: &struct { 123 A struct { 124 A *string `android:"arch_variant"` 125 } `android:"arch_variant"` 126 }{}, 127 out: &struct { 128 A struct { 129 A *string `android:"arch_variant"` 130 } `android:"arch_variant"` 131 }{}, 132 filtered: false, 133 }, 134 135 // Named sub-struct tests 136 { 137 name: "named substruct", 138 in: &struct { 139 A Named `android:"arch_variant"` 140 }{}, 141 out: &struct { 142 A struct { 143 A *string 144 } 145 }{}, 146 filtered: true, 147 }, 148 { 149 name: "substruct all filtered", 150 in: &struct { 151 A NamedAllFiltered `android:"arch_variant"` 152 }{}, 153 out: nil, 154 filtered: true, 155 }, 156 { 157 name: "substruct none filtered", 158 in: &struct { 159 A NamedNoneFiltered `android:"arch_variant"` 160 }{}, 161 out: &struct { 162 A NamedNoneFiltered `android:"arch_variant"` 163 }{}, 164 filtered: false, 165 }, 166 167 // Pointer to sub-struct tests 168 { 169 name: "pointer substruct", 170 in: &struct { 171 A *struct { 172 A *string `android:"arch_variant"` 173 B *string 174 } `android:"arch_variant"` 175 }{}, 176 out: &struct { 177 A *struct { 178 A *string 179 } 180 }{}, 181 filtered: true, 182 }, 183 { 184 name: "pointer substruct all filtered", 185 in: &struct { 186 A *struct { 187 A *string 188 } `android:"arch_variant"` 189 }{}, 190 out: nil, 191 filtered: true, 192 }, 193 { 194 name: "pointer substruct none filtered", 195 in: &struct { 196 A *struct { 197 A *string `android:"arch_variant"` 198 } `android:"arch_variant"` 199 }{}, 200 out: &struct { 201 A *struct { 202 A *string `android:"arch_variant"` 203 } `android:"arch_variant"` 204 }{}, 205 filtered: false, 206 }, 207 208 // Pointer to named sub-struct tests 209 { 210 name: "pointer named substruct", 211 in: &struct { 212 A *Named `android:"arch_variant"` 213 }{}, 214 out: &struct { 215 A *struct { 216 A *string 217 } 218 }{}, 219 filtered: true, 220 }, 221 { 222 name: "pointer substruct all filtered", 223 in: &struct { 224 A *NamedAllFiltered `android:"arch_variant"` 225 }{}, 226 out: nil, 227 filtered: true, 228 }, 229 { 230 name: "pointer substruct none filtered", 231 in: &struct { 232 A *NamedNoneFiltered `android:"arch_variant"` 233 }{}, 234 out: &struct { 235 A *NamedNoneFiltered `android:"arch_variant"` 236 }{}, 237 filtered: false, 238 }, 239 } 240 241 for _, test := range tests { 242 t.Run(test.name, func(t *testing.T) { 243 out, filtered := proptools.FilterPropertyStruct(reflect.TypeOf(test.in), filterArchStruct) 244 if filtered != test.filtered { 245 t.Errorf("expected filtered %v, got %v", test.filtered, filtered) 246 } 247 expected := reflect.TypeOf(test.out) 248 if out != expected { 249 t.Errorf("expected type %v, got %v", expected, out) 250 } 251 }) 252 } 253} 254 255type archTestModule struct { 256 ModuleBase 257 props struct { 258 Deps []string 259 } 260} 261 262func (m *archTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 263} 264 265func (m *archTestModule) DepsMutator(ctx BottomUpMutatorContext) { 266 ctx.AddDependency(ctx.Module(), nil, m.props.Deps...) 267} 268 269func archTestModuleFactory() Module { 270 m := &archTestModule{} 271 m.AddProperties(&m.props) 272 InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth) 273 return m 274} 275 276var prepareForArchTest = GroupFixturePreparers( 277 PrepareForTestWithArchMutator, 278 FixtureRegisterWithContext(func(ctx RegistrationContext) { 279 ctx.RegisterModuleType("module", archTestModuleFactory) 280 }), 281) 282 283func TestArchMutator(t *testing.T) { 284 var buildOSVariants []string 285 var buildOS32Variants []string 286 switch runtime.GOOS { 287 case "linux": 288 buildOSVariants = []string{"linux_glibc_x86_64", "linux_glibc_x86"} 289 buildOS32Variants = []string{"linux_glibc_x86"} 290 case "darwin": 291 buildOSVariants = []string{"darwin_x86_64"} 292 buildOS32Variants = nil 293 } 294 295 bp := ` 296 module { 297 name: "foo", 298 } 299 300 module { 301 name: "bar", 302 host_supported: true, 303 } 304 305 module { 306 name: "baz", 307 device_supported: false, 308 } 309 310 module { 311 name: "qux", 312 host_supported: true, 313 compile_multilib: "32", 314 } 315 ` 316 317 testCases := []struct { 318 name string 319 preparer FixturePreparer 320 fooVariants []string 321 barVariants []string 322 bazVariants []string 323 quxVariants []string 324 }{ 325 { 326 name: "normal", 327 preparer: nil, 328 fooVariants: []string{"android_arm64_armv8-a", "android_arm_armv7-a-neon"}, 329 barVariants: append(buildOSVariants, "android_arm64_armv8-a", "android_arm_armv7-a-neon"), 330 bazVariants: nil, 331 quxVariants: append(buildOS32Variants, "android_arm_armv7-a-neon"), 332 }, 333 { 334 name: "host-only", 335 preparer: FixtureModifyConfig(func(config Config) { 336 config.BuildOSTarget = Target{} 337 config.BuildOSCommonTarget = Target{} 338 config.Targets[Android] = nil 339 }), 340 fooVariants: nil, 341 barVariants: buildOSVariants, 342 bazVariants: nil, 343 quxVariants: buildOS32Variants, 344 }, 345 } 346 347 enabledVariants := func(ctx *TestContext, name string) []string { 348 var ret []string 349 variants := ctx.ModuleVariantsForTests(name) 350 for _, variant := range variants { 351 m := ctx.ModuleForTests(name, variant) 352 if m.Module().Enabled() { 353 ret = append(ret, variant) 354 } 355 } 356 return ret 357 } 358 359 for _, tt := range testCases { 360 t.Run(tt.name, func(t *testing.T) { 361 result := GroupFixturePreparers( 362 prepareForArchTest, 363 // Test specific preparer 364 OptionalFixturePreparer(tt.preparer), 365 FixtureWithRootAndroidBp(bp), 366 ).RunTest(t) 367 ctx := result.TestContext 368 369 if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { 370 t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) 371 } 372 373 if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { 374 t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) 375 } 376 377 if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { 378 t.Errorf("want baz variants:\n%q\ngot:\n%q\n", w, g) 379 } 380 381 if g, w := enabledVariants(ctx, "qux"), tt.quxVariants; !reflect.DeepEqual(w, g) { 382 t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) 383 } 384 }) 385 } 386} 387 388func TestArchMutatorNativeBridge(t *testing.T) { 389 bp := ` 390 // This module is only enabled for x86. 391 module { 392 name: "foo", 393 } 394 395 // This module is enabled for x86 and arm (via native bridge). 396 module { 397 name: "bar", 398 native_bridge_supported: true, 399 } 400 401 // This module is enabled for arm (native_bridge) only. 402 module { 403 name: "baz", 404 native_bridge_supported: true, 405 enabled: false, 406 target: { 407 native_bridge: { 408 enabled: true, 409 } 410 } 411 } 412 ` 413 414 testCases := []struct { 415 name string 416 preparer FixturePreparer 417 fooVariants []string 418 barVariants []string 419 bazVariants []string 420 }{ 421 { 422 name: "normal", 423 preparer: nil, 424 fooVariants: []string{"android_x86_64_silvermont", "android_x86_silvermont"}, 425 barVariants: []string{"android_x86_64_silvermont", "android_native_bridge_arm64_armv8-a", "android_x86_silvermont", "android_native_bridge_arm_armv7-a-neon"}, 426 bazVariants: []string{"android_native_bridge_arm64_armv8-a", "android_native_bridge_arm_armv7-a-neon"}, 427 }, 428 } 429 430 enabledVariants := func(ctx *TestContext, name string) []string { 431 var ret []string 432 variants := ctx.ModuleVariantsForTests(name) 433 for _, variant := range variants { 434 m := ctx.ModuleForTests(name, variant) 435 if m.Module().Enabled() { 436 ret = append(ret, variant) 437 } 438 } 439 return ret 440 } 441 442 for _, tt := range testCases { 443 t.Run(tt.name, func(t *testing.T) { 444 result := GroupFixturePreparers( 445 prepareForArchTest, 446 // Test specific preparer 447 OptionalFixturePreparer(tt.preparer), 448 // Prepare for native bridge test 449 FixtureModifyConfig(func(config Config) { 450 config.Targets[Android] = []Target{ 451 {Android, Arch{ArchType: X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false}, 452 {Android, Arch{ArchType: X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false}, 453 {Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeEnabled, "x86_64", "arm64", false}, 454 {Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeEnabled, "x86", "arm", false}, 455 } 456 }), 457 FixtureWithRootAndroidBp(bp), 458 ).RunTest(t) 459 460 ctx := result.TestContext 461 462 if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) { 463 t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g) 464 } 465 466 if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) { 467 t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g) 468 } 469 470 if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) { 471 t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g) 472 } 473 }) 474 } 475} 476