// Copyright 2020 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package bp2build import ( "fmt" "strings" "testing" "android/soong/android" "android/soong/android/allowlists" "android/soong/python" ) func TestGenerateSoongModuleTargets(t *testing.T) { testCases := []struct { description string bp string expectedBazelTarget string }{ { description: "only name", bp: `custom { name: "foo" } `, expectedBazelTarget: `soong_module( name = "foo", soong_module_name = "foo", soong_module_type = "custom", soong_module_variant = "", soong_module_deps = [ ], bool_prop = False, string_prop = "", )`, }, { description: "handles bool", bp: `custom { name: "foo", bool_prop: true, } `, expectedBazelTarget: `soong_module( name = "foo", soong_module_name = "foo", soong_module_type = "custom", soong_module_variant = "", soong_module_deps = [ ], bool_prop = True, string_prop = "", )`, }, { description: "string escaping", bp: `custom { name: "foo", owner: "a_string_with\"quotes\"_and_\\backslashes\\\\", } `, expectedBazelTarget: `soong_module( name = "foo", soong_module_name = "foo", soong_module_type = "custom", soong_module_variant = "", soong_module_deps = [ ], bool_prop = False, owner = "a_string_with\"quotes\"_and_\\backslashes\\\\", string_prop = "", )`, }, { description: "single item string list", bp: `custom { name: "foo", required: ["bar"], } `, expectedBazelTarget: `soong_module( name = "foo", soong_module_name = "foo", soong_module_type = "custom", soong_module_variant = "", soong_module_deps = [ ], bool_prop = False, required = ["bar"], string_prop = "", )`, }, { description: "list of strings", bp: `custom { name: "foo", target_required: ["qux", "bazqux"], } `, expectedBazelTarget: `soong_module( name = "foo", soong_module_name = "foo", soong_module_type = "custom", soong_module_variant = "", soong_module_deps = [ ], bool_prop = False, string_prop = "", target_required = [ "qux", "bazqux", ], )`, }, { description: "dist/dists", bp: `custom { name: "foo", dist: { targets: ["goal_foo"], tag: ".foo", }, dists: [{ targets: ["goal_bar"], tag: ".bar", }], } `, expectedBazelTarget: `soong_module( name = "foo", soong_module_name = "foo", soong_module_type = "custom", soong_module_variant = "", soong_module_deps = [ ], bool_prop = False, dist = { "tag": ".foo", "targets": ["goal_foo"], }, dists = [{ "tag": ".bar", "targets": ["goal_bar"], }], string_prop = "", )`, }, { description: "put it together", bp: `custom { name: "foo", required: ["bar"], target_required: ["qux", "bazqux"], bool_prop: true, owner: "custom_owner", dists: [ { tag: ".tag", targets: ["my_goal"], }, ], } `, expectedBazelTarget: `soong_module( name = "foo", soong_module_name = "foo", soong_module_type = "custom", soong_module_variant = "", soong_module_deps = [ ], bool_prop = True, dists = [{ "tag": ".tag", "targets": ["my_goal"], }], owner = "custom_owner", required = ["bar"], string_prop = "", target_required = [ "qux", "bazqux", ], )`, }, } dir := "." for _, testCase := range testCases { t.Run(testCase.description, func(t *testing.T) { config := android.TestConfig(buildDir, nil, testCase.bp, nil) ctx := android.NewTestContext(config) ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) ctx.Register() _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) android.FailIfErrored(t, errs) _, errs = ctx.PrepareBuildActions(config) android.FailIfErrored(t, errs) codegenCtx := NewCodegenContext(config, *ctx.Context, QueryView) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir) android.FailIfErrored(t, err) if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount { t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount) } actualBazelTarget := bazelTargets[0] if actualBazelTarget.content != testCase.expectedBazelTarget { t.Errorf( "Expected generated Bazel target to be '%s', got '%s'", testCase.expectedBazelTarget, actualBazelTarget.content, ) } }) } } func TestGenerateBazelTargetModules(t *testing.T) { testCases := []Bp2buildTestCase{ { Description: "string prop empty", Blueprint: `custom { name: "foo", string_literal_prop: "", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "foo", AttrNameToString{ "string_literal_prop": `""`, }), }, }, { Description: `string prop "PROP"`, Blueprint: `custom { name: "foo", string_literal_prop: "PROP", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "foo", AttrNameToString{ "string_literal_prop": `"PROP"`, }), }, }, { Description: `string prop arch variant`, Blueprint: `custom { name: "foo", arch: { arm: { string_literal_prop: "ARM" }, arm64: { string_literal_prop: "ARM64" }, }, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "foo", AttrNameToString{ "string_literal_prop": `select({ "//build/bazel/platforms/arch:arm": "ARM", "//build/bazel/platforms/arch:arm64": "ARM64", "//conditions:default": None, })`, }), }, }, { Description: "string ptr props", Blueprint: `custom { name: "foo", string_ptr_prop: "", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "foo", AttrNameToString{ "string_ptr_prop": `""`, }), }, }, { Description: "string list props", Blueprint: `custom { name: "foo", string_list_prop: ["a", "b"], string_ptr_prop: "a", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "foo", AttrNameToString{ "string_list_prop": `[ "a", "b", ]`, "string_ptr_prop": `"a"`, }), }, }, { Description: "control characters", Blueprint: `custom { name: "foo", string_list_prop: ["\t", "\n"], string_ptr_prop: "a\t\n\r", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "foo", AttrNameToString{ "string_list_prop": `[ "\t", "\n", ]`, "string_ptr_prop": `"a\t\n\r"`, }), }, }, { Description: "handles dep", Blueprint: `custom { name: "has_dep", arch_paths: [":dep"], bazel_module: { bp2build_available: true }, } custom { name: "dep", arch_paths: ["abc"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "dep", AttrNameToString{ "arch_paths": `["abc"]`, }), MakeBazelTarget("custom", "has_dep", AttrNameToString{ "arch_paths": `[":dep"]`, }), }, }, { Description: "non-existent dep", Blueprint: `custom { name: "has_dep", arch_paths: [":dep"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "has_dep", AttrNameToString{ "arch_paths": `[":dep__BP2BUILD__MISSING__DEP"]`, }), }, }, { Description: "arch-variant srcs", Blueprint: `custom { name: "arch_paths", arch: { x86: { arch_paths: ["x86.txt"] }, x86_64: { arch_paths: ["x86_64.txt"] }, arm: { arch_paths: ["arm.txt"] }, arm64: { arch_paths: ["arm64.txt"] }, riscv64: { arch_paths: ["riscv64.txt"] }, }, target: { linux: { arch_paths: ["linux.txt"] }, bionic: { arch_paths: ["bionic.txt"] }, host: { arch_paths: ["host.txt"] }, not_windows: { arch_paths: ["not_windows.txt"] }, android: { arch_paths: ["android.txt"] }, linux_musl: { arch_paths: ["linux_musl.txt"] }, musl: { arch_paths: ["musl.txt"] }, linux_glibc: { arch_paths: ["linux_glibc.txt"] }, glibc: { arch_paths: ["glibc.txt"] }, linux_bionic: { arch_paths: ["linux_bionic.txt"] }, darwin: { arch_paths: ["darwin.txt"] }, windows: { arch_paths: ["windows.txt"] }, }, multilib: { lib32: { arch_paths: ["lib32.txt"] }, lib64: { arch_paths: ["lib64.txt"] }, }, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "arch_paths", AttrNameToString{ "arch_paths": `select({ "//build/bazel/platforms/arch:arm": [ "arm.txt", "lib32.txt", ], "//build/bazel/platforms/arch:arm64": [ "arm64.txt", "lib64.txt", ], "//build/bazel/platforms/arch:riscv64": [ "riscv64.txt", "lib64.txt", ], "//build/bazel/platforms/arch:x86": [ "x86.txt", "lib32.txt", ], "//build/bazel/platforms/arch:x86_64": [ "x86_64.txt", "lib64.txt", ], "//conditions:default": [], }) + select({ "//build/bazel/platforms/os:android": [ "linux.txt", "bionic.txt", "android.txt", ], "//build/bazel/platforms/os:darwin": [ "host.txt", "darwin.txt", "not_windows.txt", ], "//build/bazel/platforms/os:linux": [ "host.txt", "linux.txt", "glibc.txt", "linux_glibc.txt", "not_windows.txt", ], "//build/bazel/platforms/os:linux_bionic": [ "host.txt", "linux.txt", "bionic.txt", "linux_bionic.txt", "not_windows.txt", ], "//build/bazel/platforms/os:linux_musl": [ "host.txt", "linux.txt", "musl.txt", "linux_musl.txt", "not_windows.txt", ], "//build/bazel/platforms/os:windows": [ "host.txt", "windows.txt", ], "//conditions:default": [], })`, }), }, }, { Description: "arch-variant deps", Blueprint: `custom { name: "has_dep", arch: { x86: { arch_paths: [":dep"], }, }, bazel_module: { bp2build_available: true }, } custom { name: "dep", arch_paths: ["abc"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "dep", AttrNameToString{ "arch_paths": `["abc"]`, }), MakeBazelTarget("custom", "has_dep", AttrNameToString{ "arch_paths": `select({ "//build/bazel/platforms/arch:x86": [":dep"], "//conditions:default": [], })`, }), }, }, { Description: "embedded props", Blueprint: `custom { name: "embedded_props", embedded_prop: "abc", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "embedded_props", AttrNameToString{ "embedded_attr": `"abc"`, }), }, }, { Description: "ptr to embedded props", Blueprint: `custom { name: "ptr_to_embedded_props", other_embedded_prop: "abc", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("custom", "ptr_to_embedded_props", AttrNameToString{ "other_embedded_attr": `"abc"`, }), }, }, } dir := "." for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { config := android.TestConfig(buildDir, nil, testCase.Blueprint, nil) ctx := android.NewTestContext(config) registerCustomModuleForBp2buildConversion(ctx) _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) if errored(t, testCase, errs) { return } _, errs = ctx.ResolveDependencies(config) if errored(t, testCase, errs) { return } codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir) android.FailIfErrored(t, err) if actualCount, expectedCount := len(bazelTargets), len(testCase.ExpectedBazelTargets); actualCount != expectedCount { t.Errorf("Expected %d bazel target (%s),\ngot %d (%s)", expectedCount, testCase.ExpectedBazelTargets, actualCount, bazelTargets) } else { for i, expectedBazelTarget := range testCase.ExpectedBazelTargets { actualBazelTarget := bazelTargets[i] if actualBazelTarget.content != expectedBazelTarget { t.Errorf( "Expected generated Bazel target to be '%s', got '%s'", expectedBazelTarget, actualBazelTarget.content, ) } } } }) } } func TestBp2buildHostAndDevice(t *testing.T) { testCases := []Bp2buildTestCase{ { Description: "host and device, device only", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice, Blueprint: `custom { name: "foo", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported), }, }, { Description: "host and device, both", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice, Blueprint: `custom { name: "foo", host_supported: true, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}), }, }, { Description: "host and device, host explicitly disabled", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice, Blueprint: `custom { name: "foo", host_supported: false, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported), }, }, { Description: "host and device, neither", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice, Blueprint: `custom { name: "foo", host_supported: false, device_supported: false, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{ "target_compatible_with": `["@platforms//:incompatible"]`, }), }, }, { Description: "host and device, neither, cannot override with product_var", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice, Blueprint: `custom { name: "foo", host_supported: false, device_supported: false, product_variables: { unbundled_build: { enabled: true } }, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{ "target_compatible_with": `["@platforms//:incompatible"]`, }), }, }, { Description: "host and device, both, disabled overrided with product_var", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice, Blueprint: `custom { name: "foo", host_supported: true, device_supported: true, enabled: false, product_variables: { unbundled_build: { enabled: true } }, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{ "target_compatible_with": `["//build/bazel/product_variables:unbundled_build"]`, }), }, }, { Description: "host and device, neither, cannot override with arch enabled", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice, Blueprint: `custom { name: "foo", host_supported: false, device_supported: false, arch: { x86: { enabled: true } }, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{ "target_compatible_with": `["@platforms//:incompatible"]`, }), }, }, { Description: "host and device, host only", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice, Blueprint: `custom { name: "foo", host_supported: true, device_supported: false, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported), }, }, { Description: "host only", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostSupported, Blueprint: `custom { name: "foo", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported), }, }, { Description: "device only", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryDeviceSupported, Blueprint: `custom { name: "foo", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported), }, }, { Description: "host and device default, default", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault, Blueprint: `custom { name: "foo", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}), }, }, { Description: "host and device default, device only", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault, Blueprint: `custom { name: "foo", host_supported: false, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported), }, }, { Description: "host and device default, host only", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault, Blueprint: `custom { name: "foo", device_supported: false, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported), }, }, { Description: "host and device default, neither", ModuleTypeUnderTest: "custom", ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault, Blueprint: `custom { name: "foo", host_supported: false, device_supported: false, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{ "target_compatible_with": `["@platforms//:incompatible"]`, }), }, }, } for _, tc := range testCases { t.Run(tc.Description, func(t *testing.T) { RunBp2BuildTestCaseSimple(t, tc) }) } } func TestLoadStatements(t *testing.T) { testCases := []struct { bazelTargets BazelTargets expectedLoadStatements string }{ { bazelTargets: BazelTargets{ BazelTarget{ name: "foo", ruleClass: "cc_library", bzlLoadLocation: "//build/bazel/rules:cc.bzl", }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`, }, { bazelTargets: BazelTargets{ BazelTarget{ name: "foo", ruleClass: "cc_library", bzlLoadLocation: "//build/bazel/rules:cc.bzl", }, BazelTarget{ name: "bar", ruleClass: "cc_library", bzlLoadLocation: "//build/bazel/rules:cc.bzl", }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`, }, { bazelTargets: BazelTargets{ BazelTarget{ name: "foo", ruleClass: "cc_library", bzlLoadLocation: "//build/bazel/rules:cc.bzl", }, BazelTarget{ name: "bar", ruleClass: "cc_binary", bzlLoadLocation: "//build/bazel/rules:cc.bzl", }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")`, }, { bazelTargets: BazelTargets{ BazelTarget{ name: "foo", ruleClass: "cc_library", bzlLoadLocation: "//build/bazel/rules:cc.bzl", }, BazelTarget{ name: "bar", ruleClass: "cc_binary", bzlLoadLocation: "//build/bazel/rules:cc.bzl", }, BazelTarget{ name: "baz", ruleClass: "java_binary", bzlLoadLocation: "//build/bazel/rules:java.bzl", }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library") load("//build/bazel/rules:java.bzl", "java_binary")`, }, { bazelTargets: BazelTargets{ BazelTarget{ name: "foo", ruleClass: "cc_binary", bzlLoadLocation: "//build/bazel/rules:cc.bzl", }, BazelTarget{ name: "bar", ruleClass: "java_binary", bzlLoadLocation: "//build/bazel/rules:java.bzl", }, BazelTarget{ name: "baz", ruleClass: "genrule", // Note: no bzlLoadLocation for native rules }, }, expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary") load("//build/bazel/rules:java.bzl", "java_binary")`, }, } for _, testCase := range testCases { actual := testCase.bazelTargets.LoadStatements() expected := testCase.expectedLoadStatements if actual != expected { t.Fatalf("Expected load statements to be %s, got %s", expected, actual) } } } func TestGenerateBazelTargetModules_OneToMany_LoadedFromStarlark(t *testing.T) { testCases := []struct { bp string expectedBazelTarget string expectedBazelTargetCount int expectedLoadStatements string }{ { bp: `custom { name: "bar", host_supported: true, one_to_many_prop: true, bazel_module: { bp2build_available: true }, }`, expectedBazelTarget: `my_library( name = "bar", ) proto_library( name = "bar_proto_library_deps", ) my_proto_library( name = "bar_my_proto_library_deps", )`, expectedBazelTargetCount: 3, expectedLoadStatements: `load("//build/bazel/rules:proto.bzl", "my_proto_library", "proto_library") load("//build/bazel/rules:rules.bzl", "my_library")`, }, } dir := "." for _, testCase := range testCases { config := android.TestConfig(buildDir, nil, testCase.bp, nil) ctx := android.NewTestContext(config) ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) ctx.RegisterForBazelConversion() _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) android.FailIfErrored(t, errs) _, errs = ctx.ResolveDependencies(config) android.FailIfErrored(t, errs) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir) android.FailIfErrored(t, err) if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount { t.Fatalf("Expected %d bazel target, got %d", testCase.expectedBazelTargetCount, actualCount) } actualBazelTargets := bazelTargets.String() if actualBazelTargets != testCase.expectedBazelTarget { t.Errorf( "Expected generated Bazel target to be '%s', got '%s'", testCase.expectedBazelTarget, actualBazelTargets, ) } actualLoadStatements := bazelTargets.LoadStatements() if actualLoadStatements != testCase.expectedLoadStatements { t.Errorf( "Expected generated load statements to be '%s', got '%s'", testCase.expectedLoadStatements, actualLoadStatements, ) } } } func TestModuleTypeBp2Build(t *testing.T) { testCases := []Bp2buildTestCase{ { Description: "filegroup with does not specify srcs", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}), }, }, { Description: "filegroup with no srcs", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", srcs: [], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}), }, }, { Description: "filegroup with srcs", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", srcs: ["a", "b"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a", "b", ]`, }), }, }, { Description: "filegroup with dot-slash-prefixed srcs", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", srcs: ["./a", "./b"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a", "b", ]`, }), }, }, { Description: "filegroup with excludes srcs", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", srcs: ["a", "b"], exclude_srcs: ["a"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `["b"]`, }), }, }, { Description: "depends_on_other_dir_module", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", srcs: [ ":foo", "c", ], bazel_module: { bp2build_available: true }, }`, Filesystem: map[string]string{ "other/Android.bp": `filegroup { name: "foo", srcs: ["a", "b"], bazel_module: { bp2build_available: true }, }`, }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "//other:foo", "c", ]`, }), }, }, { Description: "depends_on_other_unconverted_module_error", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, UnconvertedDepsMode: errorModulesUnconvertedDeps, Blueprint: `filegroup { name: "foobar", srcs: [ ":foo", "c", ], bazel_module: { bp2build_available: true }, }`, ExpectedErr: fmt.Errorf(`filegroup .:foobar depends on unconverted modules: foo`), Filesystem: map[string]string{ "other/Android.bp": `filegroup { name: "foo", srcs: ["a", "b"], }`, }, }, { Description: "depends_on_other_missing_module_error", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, UnconvertedDepsMode: errorModulesUnconvertedDeps, Blueprint: `filegroup { name: "foobar", srcs: [ "c", "//other:foo", "//other:goo", ], bazel_module: { bp2build_available: true }, }`, ExpectedErr: fmt.Errorf(`filegroup .:foobar depends on missing modules: //other:goo`), Filesystem: map[string]string{"other/Android.bp": `filegroup { name: "foo", srcs: ["a"], bazel_module: { bp2build_available: true }, } `, }, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, testCase) }) } } func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) { testCases := []struct { moduleTypeUnderTest string moduleTypeUnderTestFactory android.ModuleFactory bp string expectedCount int description string }{ { description: "explicitly unavailable", moduleTypeUnderTest: "filegroup", moduleTypeUnderTestFactory: android.FileGroupFactory, bp: `filegroup { name: "foo", srcs: ["a", "b"], bazel_module: { bp2build_available: false }, }`, expectedCount: 0, }, { description: "implicitly unavailable", moduleTypeUnderTest: "filegroup", moduleTypeUnderTestFactory: android.FileGroupFactory, bp: `filegroup { name: "foo", srcs: ["a", "b"], }`, expectedCount: 0, }, { description: "explicitly available", moduleTypeUnderTest: "filegroup", moduleTypeUnderTestFactory: android.FileGroupFactory, bp: `filegroup { name: "foo", srcs: ["a", "b"], bazel_module: { bp2build_available: true }, }`, expectedCount: 1, }, { description: "generates more than 1 target if needed", moduleTypeUnderTest: "custom", moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice, bp: `custom { name: "foo", one_to_many_prop: true, bazel_module: { bp2build_available: true }, }`, expectedCount: 3, }, } dir := "." for _, testCase := range testCases { t.Run(testCase.description, func(t *testing.T) { config := android.TestConfig(buildDir, nil, testCase.bp, nil) ctx := android.NewTestContext(config) ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) ctx.RegisterForBazelConversion() _, errs := ctx.ParseFileList(dir, []string{"Android.bp"}) android.FailIfErrored(t, errs) _, errs = ctx.ResolveDependencies(config) android.FailIfErrored(t, errs) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir) android.FailIfErrored(t, err) if actualCount := len(bazelTargets); actualCount != testCase.expectedCount { t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, testCase.expectedCount, actualCount) } }) } } func TestAllowlistingBp2buildTargetsWithConfig(t *testing.T) { testCases := []struct { moduleTypeUnderTest string moduleTypeUnderTestFactory android.ModuleFactory expectedCount map[string]int description string bp2buildConfig allowlists.Bp2BuildConfig checkDir string fs map[string]string }{ { description: "test bp2build config package and subpackages config", moduleTypeUnderTest: "filegroup", moduleTypeUnderTestFactory: android.FileGroupFactory, expectedCount: map[string]int{ "migrated": 1, "migrated/but_not_really": 0, "migrated/but_not_really/but_really": 1, "not_migrated": 0, "also_not_migrated": 0, }, bp2buildConfig: allowlists.Bp2BuildConfig{ "migrated": allowlists.Bp2BuildDefaultTrueRecursively, "migrated/but_not_really": allowlists.Bp2BuildDefaultFalse, "not_migrated": allowlists.Bp2BuildDefaultFalse, }, fs: map[string]string{ "migrated/Android.bp": `filegroup { name: "a" }`, "migrated/but_not_really/Android.bp": `filegroup { name: "b" }`, "migrated/but_not_really/but_really/Android.bp": `filegroup { name: "c" }`, "not_migrated/Android.bp": `filegroup { name: "d" }`, "also_not_migrated/Android.bp": `filegroup { name: "e" }`, }, }, { description: "test bp2build config opt-in and opt-out", moduleTypeUnderTest: "filegroup", moduleTypeUnderTestFactory: android.FileGroupFactory, expectedCount: map[string]int{ "package-opt-in": 2, "package-opt-in/subpackage": 0, "package-opt-out": 1, "package-opt-out/subpackage": 0, }, bp2buildConfig: allowlists.Bp2BuildConfig{ "package-opt-in": allowlists.Bp2BuildDefaultFalse, "package-opt-out": allowlists.Bp2BuildDefaultTrueRecursively, }, fs: map[string]string{ "package-opt-in/Android.bp": ` filegroup { name: "opt-in-a" } filegroup { name: "opt-in-b", bazel_module: { bp2build_available: true } } filegroup { name: "opt-in-c", bazel_module: { bp2build_available: true } } `, "package-opt-in/subpackage/Android.bp": ` filegroup { name: "opt-in-d" } // parent package not configured to DefaultTrueRecursively `, "package-opt-out/Android.bp": ` filegroup { name: "opt-out-a" } filegroup { name: "opt-out-b", bazel_module: { bp2build_available: false } } filegroup { name: "opt-out-c", bazel_module: { bp2build_available: false } } `, "package-opt-out/subpackage/Android.bp": ` filegroup { name: "opt-out-g", bazel_module: { bp2build_available: false } } filegroup { name: "opt-out-h", bazel_module: { bp2build_available: false } } `, }, }, } dir := "." for _, testCase := range testCases { fs := make(map[string][]byte) toParse := []string{ "Android.bp", } for f, content := range testCase.fs { if strings.HasSuffix(f, "Android.bp") { toParse = append(toParse, f) } fs[f] = []byte(content) } config := android.TestConfig(buildDir, nil, "", fs) ctx := android.NewTestContext(config) ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) allowlist := android.NewBp2BuildAllowlist().SetDefaultConfig(testCase.bp2buildConfig) ctx.RegisterBp2BuildConfig(allowlist) ctx.RegisterForBazelConversion() _, errs := ctx.ParseFileList(dir, toParse) android.FailIfErrored(t, errs) _, errs = ctx.ResolveDependencies(config) android.FailIfErrored(t, errs) codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) // For each directory, test that the expected number of generated targets is correct. for dir, expectedCount := range testCase.expectedCount { bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir) android.FailIfErrored(t, err) if actualCount := len(bazelTargets); actualCount != expectedCount { t.Fatalf( "%s: Expected %d bazel target for %s package, got %d", testCase.description, expectedCount, dir, actualCount) } } } } func TestCombineBuildFilesBp2buildTargets(t *testing.T) { testCases := []Bp2buildTestCase{ { Description: "filegroup bazel_module.label", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", bazel_module: { label: "//other:fg_foo" }, }`, ExpectedBazelTargets: []string{}, Filesystem: map[string]string{ "other/BUILD.bazel": `// BUILD file`, }, }, { Description: "multiple bazel_module.label same BUILD", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", bazel_module: { label: "//other:fg_foo" }, } filegroup { name: "foo", bazel_module: { label: "//other:foo" }, }`, ExpectedBazelTargets: []string{}, Filesystem: map[string]string{ "other/BUILD.bazel": `// BUILD file`, }, }, { Description: "filegroup bazel_module.label and bp2build in subdir", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Dir: "other", Blueprint: ``, Filesystem: map[string]string{ "other/Android.bp": `filegroup { name: "fg_foo", bazel_module: { bp2build_available: true, }, } filegroup { name: "fg_bar", bazel_module: { label: "//other:fg_bar" }, }`, "other/BUILD.bazel": `// definition for fg_bar`, }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}), }, }, { Description: "filegroup bazel_module.label and filegroup bp2build", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Filesystem: map[string]string{ "other/BUILD.bazel": `// BUILD file`, }, Blueprint: `filegroup { name: "fg_foo", bazel_module: { label: "//other:fg_foo", }, } filegroup { name: "fg_bar", bazel_module: { bp2build_available: true, }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_bar", map[string]string{}), }, }, } dir := "." for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { fs := make(map[string][]byte) toParse := []string{ "Android.bp", } for f, content := range testCase.Filesystem { if strings.HasSuffix(f, "Android.bp") { toParse = append(toParse, f) } fs[f] = []byte(content) } config := android.TestConfig(buildDir, nil, testCase.Blueprint, fs) ctx := android.NewTestContext(config) ctx.RegisterModuleType(testCase.ModuleTypeUnderTest, testCase.ModuleTypeUnderTestFactory) ctx.RegisterForBazelConversion() _, errs := ctx.ParseFileList(dir, toParse) if errored(t, testCase, errs) { return } _, errs = ctx.ResolveDependencies(config) if errored(t, testCase, errs) { return } checkDir := dir if testCase.Dir != "" { checkDir = testCase.Dir } codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir) android.FailIfErrored(t, err) bazelTargets.sort() actualCount := len(bazelTargets) expectedCount := len(testCase.ExpectedBazelTargets) if actualCount != expectedCount { t.Errorf("Expected %d bazel target, got %d\n%s", expectedCount, actualCount, bazelTargets) } for i, target := range bazelTargets { actualContent := target.content expectedContent := testCase.ExpectedBazelTargets[i] if expectedContent != actualContent { t.Errorf( "Expected generated Bazel target to be '%s', got '%s'", expectedContent, actualContent, ) } } }) } } func TestGlob(t *testing.T) { testCases := []Bp2buildTestCase{ { Description: "filegroup with glob", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", srcs: ["**/*.txt"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "other/a.txt", "other/b.txt", "other/subdir/a.txt", ]`, }), }, Filesystem: map[string]string{ "other/a.txt": "", "other/b.txt": "", "other/subdir/a.txt": "", "other/file": "", }, }, { Description: "filegroup with glob in subdir", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Dir: "other", Filesystem: map[string]string{ "other/Android.bp": `filegroup { name: "fg_foo", srcs: ["**/*.txt"], bazel_module: { bp2build_available: true }, }`, "other/a.txt": "", "other/b.txt": "", "other/subdir/a.txt": "", "other/file": "", }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a.txt", "b.txt", "subdir/a.txt", ]`, }), }, }, { Description: "filegroup with glob with no kept BUILD files", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, KeepBuildFileForDirs: []string{ // empty }, Blueprint: `filegroup { name: "fg_foo", srcs: ["**/*.txt"], bazel_module: { bp2build_available: true }, }`, Filesystem: map[string]string{ "a.txt": "", "b.txt": "", "foo/BUILD": "", "foo/a.txt": "", "foo/bar/BUILD": "", "foo/bar/b.txt": "", }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a.txt", "b.txt", "foo/a.txt", "foo/bar/b.txt", ]`, }), }, }, { Description: "filegroup with glob with kept BUILD file", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, KeepBuildFileForDirs: []string{ "foo", }, Blueprint: `filegroup { name: "fg_foo", srcs: ["**/*.txt"], bazel_module: { bp2build_available: true }, }`, Filesystem: map[string]string{ "a.txt": "", "b.txt": "", "foo/BUILD": "", "foo/a.txt": "", "foo/bar/BUILD": "", "foo/bar/b.txt": "", }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a.txt", "b.txt", "//foo:a.txt", "//foo:bar/b.txt", ]`, }), }, }, { Description: "filegroup with glob with kept BUILD.bazel file", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, KeepBuildFileForDirs: []string{ "foo", }, Blueprint: `filegroup { name: "fg_foo", srcs: ["**/*.txt"], bazel_module: { bp2build_available: true }, }`, Filesystem: map[string]string{ "a.txt": "", "b.txt": "", "foo/BUILD.bazel": "", "foo/a.txt": "", "foo/bar/BUILD.bazel": "", "foo/bar/b.txt": "", }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a.txt", "b.txt", "//foo:a.txt", "//foo:bar/b.txt", ]`, }), }, }, { Description: "filegroup with glob with Android.bp file as boundary", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", srcs: ["**/*.txt"], bazel_module: { bp2build_available: true }, }`, Filesystem: map[string]string{ "a.txt": "", "b.txt": "", "foo/Android.bp": "", "foo/a.txt": "", "foo/bar/Android.bp": "", "foo/bar/b.txt": "", }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a.txt", "b.txt", "//foo:a.txt", "//foo/bar:b.txt", ]`, }), }, }, { Description: "filegroup with glob in subdir with kept BUILD and BUILD.bazel file", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Dir: "other", KeepBuildFileForDirs: []string{ "other/foo", "other/foo/bar", // deliberately not other/foo/baz/BUILD. }, Filesystem: map[string]string{ "other/Android.bp": `filegroup { name: "fg_foo", srcs: ["**/*.txt"], bazel_module: { bp2build_available: true }, }`, "other/a.txt": "", "other/b.txt": "", "other/foo/BUILD": "", "other/foo/a.txt": "", "other/foo/bar/BUILD.bazel": "", "other/foo/bar/b.txt": "", "other/foo/baz/BUILD": "", "other/foo/baz/c.txt": "", }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a.txt", "b.txt", "//other/foo:a.txt", "//other/foo/bar:b.txt", "//other/foo:baz/c.txt", ]`, }), }, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { RunBp2BuildTestCaseSimple(t, testCase) }) } } func TestGlobExcludeSrcs(t *testing.T) { testCases := []Bp2buildTestCase{ { Description: "filegroup top level exclude_srcs", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: `filegroup { name: "fg_foo", srcs: ["**/*.txt"], exclude_srcs: ["c.txt"], bazel_module: { bp2build_available: true }, }`, Filesystem: map[string]string{ "a.txt": "", "b.txt": "", "c.txt": "", "dir/Android.bp": "", "dir/e.txt": "", "dir/f.txt": "", }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a.txt", "b.txt", "//dir:e.txt", "//dir:f.txt", ]`, }), }, }, { Description: "filegroup in subdir exclude_srcs", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: "", Dir: "dir", Filesystem: map[string]string{ "dir/Android.bp": `filegroup { name: "fg_foo", srcs: ["**/*.txt"], exclude_srcs: ["b.txt"], bazel_module: { bp2build_available: true }, } `, "dir/a.txt": "", "dir/b.txt": "", "dir/subdir/Android.bp": "", "dir/subdir/e.txt": "", "dir/subdir/f.txt": "", }, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "srcs": `[ "a.txt", "//dir/subdir:e.txt", "//dir/subdir:f.txt", ]`, }), }, }, } for _, testCase := range testCases { t.Run(testCase.Description, func(t *testing.T) { RunBp2BuildTestCaseSimple(t, testCase) }) } } func TestCommonBp2BuildModuleAttrs(t *testing.T) { testCases := []Bp2buildTestCase{ { Description: "Required into data test", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + ` filegroup { name: "fg_foo", required: ["reqd"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "data": `[":reqd"]`, }), }, }, { Description: "Required into data test, cyclic self reference is filtered out", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + ` filegroup { name: "fg_foo", required: ["reqd", "fg_foo"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "data": `[":reqd"]`, }), }, }, { Description: "Required via arch into data test", ModuleTypeUnderTest: "python_library", ModuleTypeUnderTestFactory: python.PythonLibraryFactory, Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") + simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + ` python_library { name: "fg_foo", arch: { arm: { required: ["reqdarm"], }, x86: { required: ["reqdx86"], }, }, bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("py_library", "fg_foo", map[string]string{ "data": `select({ "//build/bazel/platforms/arch:arm": [":reqdarm"], "//build/bazel/platforms/arch:x86": [":reqdx86"], "//conditions:default": [], })`, "srcs_version": `"PY3"`, "imports": `["."]`, }), }, }, { Description: "Required appended to data test", ModuleTypeUnderTest: "python_library", ModuleTypeUnderTestFactory: python.PythonLibraryFactory, Filesystem: map[string]string{ "data.bin": "", "src.py": "", }, Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + ` python_library { name: "fg_foo", data: ["data.bin"], required: ["reqd"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTarget("py_library", "fg_foo", map[string]string{ "data": `[ "data.bin", ":reqd", ]`, "srcs_version": `"PY3"`, "imports": `["."]`, }), }, }, { Description: "All props-to-attrs at once together test", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + ` filegroup { name: "fg_foo", required: ["reqd"], bazel_module: { bp2build_available: true }, }`, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{ "data": `[":reqd"]`, }), }, }, } for _, tc := range testCases { t.Run(tc.Description, func(t *testing.T) { RunBp2BuildTestCaseSimple(t, tc) }) } } func TestLicensesAttrConversion(t *testing.T) { RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) { ctx.RegisterModuleType("license", android.LicenseFactory) }, Bp2buildTestCase{ Description: "Test that licenses: attribute is converted", ModuleTypeUnderTest: "filegroup", ModuleTypeUnderTestFactory: android.FileGroupFactory, Blueprint: ` license { name: "my_license", } filegroup { name: "my_filegroup", licenses: ["my_license"], } `, ExpectedBazelTargets: []string{ MakeBazelTargetNoRestrictions("filegroup", "my_filegroup", AttrNameToString{ "applicable_licenses": `[":my_license"]`, }), MakeBazelTargetNoRestrictions("android_license", "my_license", AttrNameToString{}), }, }) } func TestGenerateApiBazelTargets(t *testing.T) { bp := ` custom { name: "foo", api: "foo.txt", } ` expectedBazelTarget := MakeBazelTarget( "custom_api_contribution", "foo", AttrNameToString{ "api": `"foo.txt"`, }, ) registerCustomModule := func(ctx android.RegistrationContext) { ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) } RunApiBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ Blueprint: bp, ExpectedBazelTargets: []string{expectedBazelTarget}, Description: "Generating API contribution Bazel targets for custom module", }) }