|  | // 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/bazel" | 
|  | "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_bionic": [ | 
|  | "host.txt", | 
|  | "linux.txt", | 
|  | "bionic.txt", | 
|  | "linux_bionic.txt", | 
|  | "not_windows.txt", | 
|  | ], | 
|  | "//build/bazel/platforms/os:linux_glibc": [ | 
|  | "host.txt", | 
|  | "linux.txt", | 
|  | "glibc.txt", | 
|  | "linux_glibc.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": `select({ | 
|  | "//build/bazel/product_config/config_settings:unbundled_build": [], | 
|  | "//conditions:default": ["@platforms//:incompatible"], | 
|  | })`, | 
|  | }), | 
|  | }, | 
|  | }, | 
|  | { | 
|  | 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 | 
|  | forceEnabledModules        []string | 
|  | expectedErrorMessages      []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 } } | 
|  | `, | 
|  | }, | 
|  | }, | 
|  | { | 
|  | description:                "test force-enabled errors out", | 
|  | moduleTypeUnderTest:        "filegroup", | 
|  | moduleTypeUnderTestFactory: android.FileGroupFactory, | 
|  | expectedCount: map[string]int{ | 
|  | "migrated":     0, | 
|  | "not_migrated": 0, | 
|  | }, | 
|  | bp2buildConfig: allowlists.Bp2BuildConfig{ | 
|  | "migrated/but_not_really": allowlists.Bp2BuildDefaultFalse, | 
|  | "not_migrated":            allowlists.Bp2BuildDefaultFalse, | 
|  | }, | 
|  | fs: map[string]string{ | 
|  | "migrated/Android.bp": `filegroup { name: "a" }`, | 
|  | }, | 
|  | forceEnabledModules:   []string{"a"}, | 
|  | expectedErrorMessages: []string{"Force Enabled Module a not converted"}, | 
|  | }, | 
|  | } | 
|  |  | 
|  | 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) | 
|  | config.AddForceEnabledModules(testCase.forceEnabledModules) | 
|  | 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.CheckErrorsAgainstExpectations(t, err, testCase.expectedErrorMessages) | 
|  | 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", | 
|  | }) | 
|  | } | 
|  |  | 
|  | func TestGenerateConfigSetting(t *testing.T) { | 
|  | bp := ` | 
|  | custom { | 
|  | name: "foo", | 
|  | test_config_setting: true, | 
|  | } | 
|  | ` | 
|  | expectedBazelTargets := []string{ | 
|  | MakeBazelTargetNoRestrictions( | 
|  | "config_setting", | 
|  | "foo_config_setting", | 
|  | AttrNameToString{ | 
|  | "flag_values": `{ | 
|  | "//build/bazel/rules/my_string_setting": "foo", | 
|  | }`, | 
|  | }, | 
|  | ), | 
|  | MakeBazelTarget( | 
|  | "custom", | 
|  | "foo", | 
|  | AttrNameToString{}, | 
|  | ), | 
|  | } | 
|  | registerCustomModule := func(ctx android.RegistrationContext) { | 
|  | ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) | 
|  | } | 
|  | RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ | 
|  | Blueprint:            bp, | 
|  | ExpectedBazelTargets: expectedBazelTargets, | 
|  | Description:          "Generating API contribution Bazel targets for custom module", | 
|  | }) | 
|  | } | 
|  |  | 
|  | // If values of all keys in an axis are equal to //conditions:default, drop the axis and print the common value | 
|  | func TestPrettyPrintSelectMapEqualValues(t *testing.T) { | 
|  | lla := bazel.LabelListAttribute{ | 
|  | Value: bazel.LabelList{}, | 
|  | } | 
|  | libFooImplLabel := bazel.Label{ | 
|  | Label: ":libfoo.impl", | 
|  | } | 
|  | lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.AndroidPlatform, bazel.MakeLabelList([]bazel.Label{libFooImplLabel})) | 
|  | lla.SetSelectValue(bazel.OsAndInApexAxis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{libFooImplLabel})) | 
|  | actual, _ := prettyPrintAttribute(lla, 0) | 
|  | android.AssertStringEquals(t, "Print the common value if all keys in an axis have the same value", `[":libfoo.impl"]`, actual) | 
|  | } | 
|  |  | 
|  | // If CommonAttributes.Dir is set, the bazel target should be created in that dir | 
|  | func TestCreateBazelTargetInDifferentDir(t *testing.T) { | 
|  | t.Parallel() | 
|  | bp := ` | 
|  | custom { | 
|  | name: "foo", | 
|  | dir: "subdir", | 
|  | } | 
|  | ` | 
|  | registerCustomModule := func(ctx android.RegistrationContext) { | 
|  | ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice) | 
|  | } | 
|  | // Check that foo is not created in root dir | 
|  | RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ | 
|  | Description: "foo is not created in root dir because it sets dir explicitly", | 
|  | Blueprint:   bp, | 
|  | Filesystem: map[string]string{ | 
|  | "subdir/Android.bp": "", | 
|  | }, | 
|  | ExpectedBazelTargets: []string{}, | 
|  | }) | 
|  | // Check that foo is created in `subdir` | 
|  | RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ | 
|  | Description: "foo is created in `subdir` because it sets dir explicitly", | 
|  | Blueprint:   bp, | 
|  | Filesystem: map[string]string{ | 
|  | "subdir/Android.bp": "", | 
|  | }, | 
|  | Dir: "subdir", | 
|  | ExpectedBazelTargets: []string{ | 
|  | MakeBazelTarget("custom", "foo", AttrNameToString{}), | 
|  | }, | 
|  | }) | 
|  | // Check that we cannot create target in different dir if it is does not an Android.bp | 
|  | RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{ | 
|  | Description: "foo cannot be created in `subdir` because it does not contain an Android.bp file", | 
|  | Blueprint:   bp, | 
|  | Dir:         "subdir", | 
|  | ExpectedErr: fmt.Errorf("Cannot use ca.Dir to create a BazelTarget in dir: subdir since it does not contain an Android.bp file"), | 
|  | }) | 
|  |  | 
|  | } |