platform_build_soong/bp2build/build_conversion_test.go
Cole Faust 87c0c33a65 Make bp2build-generated selects() based on product config build settings
...instead of based on constraint settings.

Bug: 269577299
Test: m nothing and ./build/bazel/ci/bp2build.sh
Change-Id: Ib9caec79c92b8fd304e46be841de5612bd1637e3
2023-08-03 10:12:09 -07:00

1951 lines
54 KiB
Go

// 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)
}