1// Copyright 2021 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 bp2build 16 17import ( 18 "android/soong/android" 19 "android/soong/cc" 20 "strings" 21 "testing" 22) 23 24const ( 25 // See cc/testing.go for more context 26 soongCcLibraryHeadersPreamble = ` 27cc_defaults { 28 name: "linux_bionic_supported", 29} 30 31toolchain_library { 32 name: "libclang_rt.builtins-x86_64-android", 33 defaults: ["linux_bionic_supported"], 34 vendor_available: true, 35 vendor_ramdisk_available: true, 36 product_available: true, 37 recovery_available: true, 38 native_bridge_supported: true, 39 src: "", 40}` 41) 42 43func TestCcLibraryHeadersLoadStatement(t *testing.T) { 44 testCases := []struct { 45 bazelTargets BazelTargets 46 expectedLoadStatements string 47 }{ 48 { 49 bazelTargets: BazelTargets{ 50 BazelTarget{ 51 name: "cc_library_headers_target", 52 ruleClass: "cc_library_headers", 53 // Note: no bzlLoadLocation for native rules 54 }, 55 }, 56 expectedLoadStatements: ``, 57 }, 58 } 59 60 for _, testCase := range testCases { 61 actual := testCase.bazelTargets.LoadStatements() 62 expected := testCase.expectedLoadStatements 63 if actual != expected { 64 t.Fatalf("Expected load statements to be %s, got %s", expected, actual) 65 } 66 } 67 68} 69 70func TestCcLibraryHeadersBp2Build(t *testing.T) { 71 testCases := []struct { 72 description string 73 moduleTypeUnderTest string 74 moduleTypeUnderTestFactory android.ModuleFactory 75 moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext) 76 preArchMutators []android.RegisterMutatorFunc 77 depsMutators []android.RegisterMutatorFunc 78 bp string 79 expectedBazelTargets []string 80 filesystem map[string]string 81 dir string 82 }{ 83 { 84 description: "cc_library_headers test", 85 moduleTypeUnderTest: "cc_library_headers", 86 moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, 87 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, 88 filesystem: map[string]string{ 89 "lib-1/lib1a.h": "", 90 "lib-1/lib1b.h": "", 91 "lib-2/lib2a.h": "", 92 "lib-2/lib2b.h": "", 93 "dir-1/dir1a.h": "", 94 "dir-1/dir1b.h": "", 95 "dir-2/dir2a.h": "", 96 "dir-2/dir2b.h": "", 97 "arch_arm64_exported_include_dir/a.h": "", 98 "arch_x86_exported_include_dir/b.h": "", 99 "arch_x86_64_exported_include_dir/c.h": "", 100 }, 101 bp: soongCcLibraryHeadersPreamble + ` 102cc_library_headers { 103 name: "lib-1", 104 export_include_dirs: ["lib-1"], 105} 106 107cc_library_headers { 108 name: "lib-2", 109 export_include_dirs: ["lib-2"], 110} 111 112cc_library_headers { 113 name: "foo_headers", 114 export_include_dirs: ["dir-1", "dir-2"], 115 header_libs: ["lib-1", "lib-2"], 116 117 arch: { 118 arm64: { 119 // We expect dir-1 headers to be dropped, because dir-1 is already in export_include_dirs 120 export_include_dirs: ["arch_arm64_exported_include_dir", "dir-1"], 121 }, 122 x86: { 123 export_include_dirs: ["arch_x86_exported_include_dir"], 124 }, 125 x86_64: { 126 export_include_dirs: ["arch_x86_64_exported_include_dir"], 127 }, 128 }, 129 130 // TODO: Also support export_header_lib_headers 131}`, 132 expectedBazelTargets: []string{`cc_library_headers( 133 name = "foo_headers", 134 copts = ["-I."], 135 deps = [ 136 ":lib-1", 137 ":lib-2", 138 ], 139 includes = [ 140 "dir-1", 141 "dir-2", 142 ] + select({ 143 "//build/bazel/platforms/arch:arm64": ["arch_arm64_exported_include_dir"], 144 "//build/bazel/platforms/arch:x86": ["arch_x86_exported_include_dir"], 145 "//build/bazel/platforms/arch:x86_64": ["arch_x86_64_exported_include_dir"], 146 "//conditions:default": [], 147 }), 148)`, `cc_library_headers( 149 name = "lib-1", 150 copts = ["-I."], 151 includes = ["lib-1"], 152)`, `cc_library_headers( 153 name = "lib-2", 154 copts = ["-I."], 155 includes = ["lib-2"], 156)`}, 157 }, 158 { 159 description: "cc_library_headers test with os-specific header_libs props", 160 moduleTypeUnderTest: "cc_library_headers", 161 moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, 162 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, 163 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 164 filesystem: map[string]string{}, 165 bp: soongCcLibraryPreamble + ` 166cc_library_headers { name: "android-lib" } 167cc_library_headers { name: "base-lib" } 168cc_library_headers { name: "darwin-lib" } 169cc_library_headers { name: "fuchsia-lib" } 170cc_library_headers { name: "linux-lib" } 171cc_library_headers { name: "linux_bionic-lib" } 172cc_library_headers { name: "windows-lib" } 173cc_library_headers { 174 name: "foo_headers", 175 header_libs: ["base-lib"], 176 target: { 177 android: { header_libs: ["android-lib"] }, 178 darwin: { header_libs: ["darwin-lib"] }, 179 fuchsia: { header_libs: ["fuchsia-lib"] }, 180 linux_bionic: { header_libs: ["linux_bionic-lib"] }, 181 linux_glibc: { header_libs: ["linux-lib"] }, 182 windows: { header_libs: ["windows-lib"] }, 183 }, 184 bazel_module: { bp2build_available: true }, 185}`, 186 expectedBazelTargets: []string{`cc_library_headers( 187 name = "android-lib", 188 copts = ["-I."], 189)`, `cc_library_headers( 190 name = "base-lib", 191 copts = ["-I."], 192)`, `cc_library_headers( 193 name = "darwin-lib", 194 copts = ["-I."], 195)`, `cc_library_headers( 196 name = "foo_headers", 197 copts = ["-I."], 198 deps = [":base-lib"] + select({ 199 "//build/bazel/platforms/os:android": [":android-lib"], 200 "//build/bazel/platforms/os:darwin": [":darwin-lib"], 201 "//build/bazel/platforms/os:fuchsia": [":fuchsia-lib"], 202 "//build/bazel/platforms/os:linux": [":linux-lib"], 203 "//build/bazel/platforms/os:linux_bionic": [":linux_bionic-lib"], 204 "//build/bazel/platforms/os:windows": [":windows-lib"], 205 "//conditions:default": [], 206 }), 207)`, `cc_library_headers( 208 name = "fuchsia-lib", 209 copts = ["-I."], 210)`, `cc_library_headers( 211 name = "linux-lib", 212 copts = ["-I."], 213)`, `cc_library_headers( 214 name = "linux_bionic-lib", 215 copts = ["-I."], 216)`, `cc_library_headers( 217 name = "windows-lib", 218 copts = ["-I."], 219)`}, 220 }, 221 { 222 description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props", 223 moduleTypeUnderTest: "cc_library_headers", 224 moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, 225 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, 226 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 227 filesystem: map[string]string{}, 228 bp: soongCcLibraryPreamble + ` 229cc_library_headers { name: "android-lib" } 230cc_library_headers { name: "exported-lib" } 231cc_library_headers { 232 name: "foo_headers", 233 target: { 234 android: { header_libs: ["android-lib"], export_header_lib_headers: ["exported-lib"] }, 235 }, 236}`, 237 expectedBazelTargets: []string{`cc_library_headers( 238 name = "android-lib", 239 copts = ["-I."], 240)`, `cc_library_headers( 241 name = "exported-lib", 242 copts = ["-I."], 243)`, `cc_library_headers( 244 name = "foo_headers", 245 copts = ["-I."], 246 deps = select({ 247 "//build/bazel/platforms/os:android": [ 248 ":android-lib", 249 ":exported-lib", 250 ], 251 "//conditions:default": [], 252 }), 253)`}, 254 }, 255 { 256 description: "cc_library_headers test with arch-specific and target-specific export_system_include_dirs props", 257 moduleTypeUnderTest: "cc_library_headers", 258 moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, 259 moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, 260 depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, 261 filesystem: map[string]string{}, 262 bp: soongCcLibraryPreamble + `cc_library_headers { 263 name: "foo_headers", 264 export_system_include_dirs: [ 265 "shared_include_dir", 266 ], 267 target: { 268 android: { 269 export_system_include_dirs: [ 270 "android_include_dir", 271 ], 272 }, 273 linux_glibc: { 274 export_system_include_dirs: [ 275 "linux_include_dir", 276 ], 277 }, 278 darwin: { 279 export_system_include_dirs: [ 280 "darwin_include_dir", 281 ], 282 }, 283 }, 284 arch: { 285 arm: { 286 export_system_include_dirs: [ 287 "arm_include_dir", 288 ], 289 }, 290 x86_64: { 291 export_system_include_dirs: [ 292 "x86_64_include_dir", 293 ], 294 }, 295 }, 296}`, 297 expectedBazelTargets: []string{`cc_library_headers( 298 name = "foo_headers", 299 copts = ["-I."], 300 includes = ["shared_include_dir"] + select({ 301 "//build/bazel/platforms/arch:arm": ["arm_include_dir"], 302 "//build/bazel/platforms/arch:x86_64": ["x86_64_include_dir"], 303 "//conditions:default": [], 304 }) + select({ 305 "//build/bazel/platforms/os:android": ["android_include_dir"], 306 "//build/bazel/platforms/os:darwin": ["darwin_include_dir"], 307 "//build/bazel/platforms/os:linux": ["linux_include_dir"], 308 "//conditions:default": [], 309 }), 310)`}, 311 }, 312 } 313 314 dir := "." 315 for _, testCase := range testCases { 316 filesystem := make(map[string][]byte) 317 toParse := []string{ 318 "Android.bp", 319 } 320 for f, content := range testCase.filesystem { 321 if strings.HasSuffix(f, "Android.bp") { 322 toParse = append(toParse, f) 323 } 324 filesystem[f] = []byte(content) 325 } 326 config := android.TestConfig(buildDir, nil, testCase.bp, filesystem) 327 ctx := android.NewTestContext(config) 328 329 // TODO(jingwen): make this default for all bp2build tests 330 ctx.RegisterBp2BuildConfig(bp2buildConfig) 331 332 cc.RegisterCCBuildComponents(ctx) 333 ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory) 334 335 ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) 336 for _, m := range testCase.depsMutators { 337 ctx.DepsBp2BuildMutators(m) 338 } 339 ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator) 340 ctx.RegisterForBazelConversion() 341 342 _, errs := ctx.ParseFileList(dir, toParse) 343 if Errored(t, testCase.description, errs) { 344 continue 345 } 346 _, errs = ctx.ResolveDependencies(config) 347 if Errored(t, testCase.description, errs) { 348 continue 349 } 350 351 checkDir := dir 352 if testCase.dir != "" { 353 checkDir = testCase.dir 354 } 355 codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) 356 bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir) 357 if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { 358 t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount) 359 } else { 360 for i, target := range bazelTargets { 361 if w, g := testCase.expectedBazelTargets[i], target.content; w != g { 362 t.Errorf( 363 "%s: Expected generated Bazel target to be '%s', got '%s'", 364 testCase.description, 365 w, 366 g, 367 ) 368 } 369 } 370 } 371 } 372} 373