platform_build_soong/bp2build/build_conversion_test.go
Chris Parsons 5011e61c71 Add unit test for parsing build files in bp2build
This involves some minor changes to testing infrastructure.

This is a rollforward of aosp/2628496 with a couple of minor changes:

- In ParseBuildFiles, filter out all build files that are kept due
  to ShouldKeepExistingBuildFileForDir

- Add some minor test infrastructure for StubbedBuildDefinitions, with a
  couple of proof of concept tests used to demonstrate its usage. This
  pattern will become immensely more common as we implement allowlist v2
  (as we will need to update all tests which today simulate build
  definitions that have missing deps)

Bug: 285631638
Fixes: 286545783
Test: bp2build.sh
Test: m nothing
Change-Id: I7c3a03b02098e39dd8e51d327482b440f294478f
2023-09-14 19:19:28 +00:00

2033 lines
56 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 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)
}
func TestAlreadyPresentBuildTarget(t *testing.T) {
bp := `
custom {
name: "foo",
}
custom {
name: "bar",
}
`
alreadyPresentBuildFile :=
MakeBazelTarget(
"custom",
"foo",
AttrNameToString{},
)
expectedBazelTargets := []string{
MakeBazelTarget(
"custom",
"bar",
AttrNameToString{},
),
}
registerCustomModule := func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
}
RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
AlreadyExistingBuildContents: alreadyPresentBuildFile,
Blueprint: bp,
ExpectedBazelTargets: expectedBazelTargets,
Description: "Not duplicating work for an already-present BUILD target.",
})
}
// Verifies that if a module is defined in pkg1/Android.bp, that a target present
// in pkg2/BUILD.bazel does not result in the module being labeled "already defined
// in a BUILD file".
func TestBuildTargetPresentOtherDirectory(t *testing.T) {
bp := `
custom {
name: "foo",
}
`
expectedBazelTargets := []string{
MakeBazelTarget(
"custom",
"foo",
AttrNameToString{},
),
}
registerCustomModule := func(ctx android.RegistrationContext) {
ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
}
RunBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
KeepBuildFileForDirs: []string{"other_pkg"},
Filesystem: map[string]string{
"other_pkg/BUILD.bazel": MakeBazelTarget("custom", "foo", AttrNameToString{}),
},
Blueprint: bp,
ExpectedBazelTargets: expectedBazelTargets,
Description: "Not treating a BUILD target as the bazel definition for a module in another package",
})
}
// 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"),
})
}