• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2020 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package bp2build
16
17import (
18	"fmt"
19	"strings"
20	"testing"
21
22	"android/soong/android"
23	"android/soong/android/allowlists"
24	"android/soong/python"
25)
26
27func TestGenerateSoongModuleTargets(t *testing.T) {
28	testCases := []struct {
29		description         string
30		bp                  string
31		expectedBazelTarget string
32	}{
33		{
34			description: "only name",
35			bp: `custom { name: "foo" }
36    `,
37			expectedBazelTarget: `soong_module(
38    name = "foo",
39    soong_module_name = "foo",
40    soong_module_type = "custom",
41    soong_module_variant = "",
42    soong_module_deps = [
43    ],
44    bool_prop = False,
45    string_prop = "",
46)`,
47		},
48		{
49			description: "handles bool",
50			bp: `custom {
51  name: "foo",
52  bool_prop: true,
53}
54    `,
55			expectedBazelTarget: `soong_module(
56    name = "foo",
57    soong_module_name = "foo",
58    soong_module_type = "custom",
59    soong_module_variant = "",
60    soong_module_deps = [
61    ],
62    bool_prop = True,
63    string_prop = "",
64)`,
65		},
66		{
67			description: "string escaping",
68			bp: `custom {
69  name: "foo",
70  owner: "a_string_with\"quotes\"_and_\\backslashes\\\\",
71}
72    `,
73			expectedBazelTarget: `soong_module(
74    name = "foo",
75    soong_module_name = "foo",
76    soong_module_type = "custom",
77    soong_module_variant = "",
78    soong_module_deps = [
79    ],
80    bool_prop = False,
81    owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
82    string_prop = "",
83)`,
84		},
85		{
86			description: "single item string list",
87			bp: `custom {
88  name: "foo",
89  required: ["bar"],
90}
91    `,
92			expectedBazelTarget: `soong_module(
93    name = "foo",
94    soong_module_name = "foo",
95    soong_module_type = "custom",
96    soong_module_variant = "",
97    soong_module_deps = [
98    ],
99    bool_prop = False,
100    required = ["bar"],
101    string_prop = "",
102)`,
103		},
104		{
105			description: "list of strings",
106			bp: `custom {
107  name: "foo",
108  target_required: ["qux", "bazqux"],
109}
110    `,
111			expectedBazelTarget: `soong_module(
112    name = "foo",
113    soong_module_name = "foo",
114    soong_module_type = "custom",
115    soong_module_variant = "",
116    soong_module_deps = [
117    ],
118    bool_prop = False,
119    string_prop = "",
120    target_required = [
121        "qux",
122        "bazqux",
123    ],
124)`,
125		},
126		{
127			description: "dist/dists",
128			bp: `custom {
129  name: "foo",
130  dist: {
131    targets: ["goal_foo"],
132    tag: ".foo",
133  },
134  dists: [{
135    targets: ["goal_bar"],
136    tag: ".bar",
137  }],
138}
139    `,
140			expectedBazelTarget: `soong_module(
141    name = "foo",
142    soong_module_name = "foo",
143    soong_module_type = "custom",
144    soong_module_variant = "",
145    soong_module_deps = [
146    ],
147    bool_prop = False,
148    dist = {
149        "tag": ".foo",
150        "targets": ["goal_foo"],
151    },
152    dists = [{
153        "tag": ".bar",
154        "targets": ["goal_bar"],
155    }],
156    string_prop = "",
157)`,
158		},
159		{
160			description: "put it together",
161			bp: `custom {
162  name: "foo",
163  required: ["bar"],
164  target_required: ["qux", "bazqux"],
165  bool_prop: true,
166  owner: "custom_owner",
167  dists: [
168    {
169      tag: ".tag",
170      targets: ["my_goal"],
171    },
172  ],
173}
174    `,
175			expectedBazelTarget: `soong_module(
176    name = "foo",
177    soong_module_name = "foo",
178    soong_module_type = "custom",
179    soong_module_variant = "",
180    soong_module_deps = [
181    ],
182    bool_prop = True,
183    dists = [{
184        "tag": ".tag",
185        "targets": ["my_goal"],
186    }],
187    owner = "custom_owner",
188    required = ["bar"],
189    string_prop = "",
190    target_required = [
191        "qux",
192        "bazqux",
193    ],
194)`,
195		},
196	}
197
198	dir := "."
199	for _, testCase := range testCases {
200		t.Run(testCase.description, func(t *testing.T) {
201			config := android.TestConfig(buildDir, nil, testCase.bp, nil)
202			ctx := android.NewTestContext(config)
203
204			ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
205			ctx.Register()
206
207			_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
208			android.FailIfErrored(t, errs)
209			_, errs = ctx.PrepareBuildActions(config)
210			android.FailIfErrored(t, errs)
211
212			codegenCtx := NewCodegenContext(config, ctx.Context, QueryView, "")
213			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
214			android.FailIfErrored(t, err)
215			if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
216				t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
217			}
218
219			actualBazelTarget := bazelTargets[0]
220			if actualBazelTarget.content != testCase.expectedBazelTarget {
221				t.Errorf(
222					"Expected generated Bazel target to be '%s', got '%s'",
223					testCase.expectedBazelTarget,
224					actualBazelTarget.content,
225				)
226			}
227		})
228	}
229}
230
231func TestGenerateBazelTargetModules(t *testing.T) {
232	testCases := []Bp2buildTestCase{
233		{
234			Description: "string prop empty",
235			Blueprint: `custom {
236	name: "foo",
237    string_literal_prop: "",
238    bazel_module: { bp2build_available: true },
239}`,
240			ExpectedBazelTargets: []string{
241				MakeBazelTarget("custom", "foo", AttrNameToString{
242					"string_literal_prop": `""`,
243				}),
244			},
245		},
246		{
247			Description: `string prop "PROP"`,
248			Blueprint: `custom {
249	name: "foo",
250    string_literal_prop: "PROP",
251    bazel_module: { bp2build_available: true },
252}`,
253			ExpectedBazelTargets: []string{
254				MakeBazelTarget("custom", "foo", AttrNameToString{
255					"string_literal_prop": `"PROP"`,
256				}),
257			},
258		},
259		{
260			Description: `string prop arch variant`,
261			Blueprint: `custom {
262    name: "foo",
263    arch: {
264        arm: { string_literal_prop: "ARM" },
265        arm64: { string_literal_prop: "ARM64" },
266    },
267    bazel_module: { bp2build_available: true },
268}`,
269			ExpectedBazelTargets: []string{
270				MakeBazelTarget("custom", "foo", AttrNameToString{
271					"string_literal_prop": `select({
272        "//build/bazel/platforms/arch:arm": "ARM",
273        "//build/bazel/platforms/arch:arm64": "ARM64",
274        "//conditions:default": None,
275    })`,
276				}),
277			},
278		},
279		{
280			Description: "string ptr props",
281			Blueprint: `custom {
282	name: "foo",
283    string_ptr_prop: "",
284    bazel_module: { bp2build_available: true },
285}`,
286			ExpectedBazelTargets: []string{
287				MakeBazelTarget("custom", "foo", AttrNameToString{
288					"string_ptr_prop": `""`,
289				}),
290			},
291		},
292		{
293			Description: "string list props",
294			Blueprint: `custom {
295  name: "foo",
296    string_list_prop: ["a", "b"],
297    string_ptr_prop: "a",
298    bazel_module: { bp2build_available: true },
299}`,
300			ExpectedBazelTargets: []string{
301				MakeBazelTarget("custom", "foo", AttrNameToString{
302					"string_list_prop": `[
303        "a",
304        "b",
305    ]`,
306					"string_ptr_prop": `"a"`,
307				}),
308			},
309		},
310		{
311			Description: "control characters",
312			Blueprint: `custom {
313    name: "foo",
314    string_list_prop: ["\t", "\n"],
315    string_ptr_prop: "a\t\n\r",
316    bazel_module: { bp2build_available: true },
317}`,
318			ExpectedBazelTargets: []string{
319				MakeBazelTarget("custom", "foo", AttrNameToString{
320					"string_list_prop": `[
321        "\t",
322        "\n",
323    ]`,
324					"string_ptr_prop": `"a\t\n\r"`,
325				}),
326			},
327		},
328		{
329			Description: "handles dep",
330			Blueprint: `custom {
331  name: "has_dep",
332  arch_paths: [":dep"],
333  bazel_module: { bp2build_available: true },
334}
335
336custom {
337  name: "dep",
338  arch_paths: ["abc"],
339  bazel_module: { bp2build_available: true },
340}`,
341			ExpectedBazelTargets: []string{
342				MakeBazelTarget("custom", "dep", AttrNameToString{
343					"arch_paths": `["abc"]`,
344				}),
345				MakeBazelTarget("custom", "has_dep", AttrNameToString{
346					"arch_paths": `[":dep"]`,
347				}),
348			},
349		},
350		{
351			Description: "non-existent dep",
352			Blueprint: `custom {
353  name: "has_dep",
354  arch_paths: [":dep"],
355  bazel_module: { bp2build_available: true },
356}`,
357			ExpectedBazelTargets: []string{
358				MakeBazelTarget("custom", "has_dep", AttrNameToString{
359					"arch_paths": `[":dep__BP2BUILD__MISSING__DEP"]`,
360				}),
361			},
362		},
363		{
364			Description: "arch-variant srcs",
365			Blueprint: `custom {
366    name: "arch_paths",
367    arch: {
368      x86: { arch_paths: ["x86.txt"] },
369      x86_64:  { arch_paths: ["x86_64.txt"] },
370      arm:  { arch_paths: ["arm.txt"] },
371      arm64:  { arch_paths: ["arm64.txt"] },
372      riscv64: { arch_paths: ["riscv64.txt"] },
373    },
374    target: {
375      linux: { arch_paths: ["linux.txt"] },
376      bionic: { arch_paths: ["bionic.txt"] },
377      host: { arch_paths: ["host.txt"] },
378      not_windows: { arch_paths: ["not_windows.txt"] },
379      android: { arch_paths: ["android.txt"] },
380      linux_musl: { arch_paths: ["linux_musl.txt"] },
381      musl: { arch_paths: ["musl.txt"] },
382      linux_glibc: { arch_paths: ["linux_glibc.txt"] },
383      glibc: { arch_paths: ["glibc.txt"] },
384      linux_bionic: { arch_paths: ["linux_bionic.txt"] },
385      darwin: { arch_paths: ["darwin.txt"] },
386      windows: { arch_paths: ["windows.txt"] },
387    },
388    multilib: {
389        lib32: { arch_paths: ["lib32.txt"] },
390        lib64: { arch_paths: ["lib64.txt"] },
391    },
392    bazel_module: { bp2build_available: true },
393}`,
394			ExpectedBazelTargets: []string{
395				MakeBazelTarget("custom", "arch_paths", AttrNameToString{
396					"arch_paths": `select({
397        "//build/bazel/platforms/arch:arm": [
398            "arm.txt",
399            "lib32.txt",
400        ],
401        "//build/bazel/platforms/arch:arm64": [
402            "arm64.txt",
403            "lib64.txt",
404        ],
405        "//build/bazel/platforms/arch:riscv64": [
406            "riscv64.txt",
407            "lib64.txt",
408        ],
409        "//build/bazel/platforms/arch:x86": [
410            "x86.txt",
411            "lib32.txt",
412        ],
413        "//build/bazel/platforms/arch:x86_64": [
414            "x86_64.txt",
415            "lib64.txt",
416        ],
417        "//conditions:default": [],
418    }) + select({
419        "//build/bazel/platforms/os:android": [
420            "linux.txt",
421            "bionic.txt",
422            "android.txt",
423        ],
424        "//build/bazel/platforms/os:darwin": [
425            "host.txt",
426            "darwin.txt",
427            "not_windows.txt",
428        ],
429        "//build/bazel/platforms/os:linux_bionic": [
430            "host.txt",
431            "linux.txt",
432            "bionic.txt",
433            "linux_bionic.txt",
434            "not_windows.txt",
435        ],
436        "//build/bazel/platforms/os:linux_glibc": [
437            "host.txt",
438            "linux.txt",
439            "glibc.txt",
440            "linux_glibc.txt",
441            "not_windows.txt",
442        ],
443        "//build/bazel/platforms/os:linux_musl": [
444            "host.txt",
445            "linux.txt",
446            "musl.txt",
447            "linux_musl.txt",
448            "not_windows.txt",
449        ],
450        "//build/bazel/platforms/os:windows": [
451            "host.txt",
452            "windows.txt",
453        ],
454        "//conditions:default": [],
455    })`,
456				}),
457			},
458		},
459		{
460			Description: "arch-variant deps",
461			Blueprint: `custom {
462  name: "has_dep",
463  arch: {
464    x86: {
465      arch_paths: [":dep"],
466    },
467  },
468  bazel_module: { bp2build_available: true },
469}
470
471custom {
472    name: "dep",
473    arch_paths: ["abc"],
474    bazel_module: { bp2build_available: true },
475}`,
476			ExpectedBazelTargets: []string{
477				MakeBazelTarget("custom", "dep", AttrNameToString{
478					"arch_paths": `["abc"]`,
479				}),
480				MakeBazelTarget("custom", "has_dep", AttrNameToString{
481					"arch_paths": `select({
482        "//build/bazel/platforms/arch:x86": [":dep"],
483        "//conditions:default": [],
484    })`,
485				}),
486			},
487		},
488		{
489			Description: "embedded props",
490			Blueprint: `custom {
491    name: "embedded_props",
492    embedded_prop: "abc",
493    bazel_module: { bp2build_available: true },
494}`,
495			ExpectedBazelTargets: []string{
496				MakeBazelTarget("custom", "embedded_props", AttrNameToString{
497					"embedded_attr": `"abc"`,
498				}),
499			},
500		},
501		{
502			Description: "ptr to embedded props",
503			Blueprint: `custom {
504    name: "ptr_to_embedded_props",
505    other_embedded_prop: "abc",
506    bazel_module: { bp2build_available: true },
507}`,
508			ExpectedBazelTargets: []string{
509				MakeBazelTarget("custom", "ptr_to_embedded_props", AttrNameToString{
510					"other_embedded_attr": `"abc"`,
511				}),
512			},
513		},
514	}
515
516	dir := "."
517	for _, testCase := range testCases {
518		t.Run(testCase.Description, func(t *testing.T) {
519			config := android.TestConfig(buildDir, nil, testCase.Blueprint, nil)
520			ctx := android.NewTestContext(config)
521
522			registerCustomModuleForBp2buildConversion(ctx)
523
524			_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
525			if errored(t, testCase, errs) {
526				return
527			}
528			_, errs = ctx.ResolveDependencies(config)
529			if errored(t, testCase, errs) {
530				return
531			}
532
533			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
534			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
535			android.FailIfErrored(t, err)
536
537			if actualCount, expectedCount := len(bazelTargets), len(testCase.ExpectedBazelTargets); actualCount != expectedCount {
538				t.Errorf("Expected %d bazel target (%s),\ngot %d (%s)", expectedCount, testCase.ExpectedBazelTargets, actualCount, bazelTargets)
539			} else {
540				for i, expectedBazelTarget := range testCase.ExpectedBazelTargets {
541					actualBazelTarget := bazelTargets[i]
542					if actualBazelTarget.content != expectedBazelTarget {
543						t.Errorf(
544							"Expected generated Bazel target to be '%s', got '%s'",
545							expectedBazelTarget,
546							actualBazelTarget.content,
547						)
548					}
549				}
550			}
551		})
552	}
553}
554
555func TestBp2buildHostAndDevice(t *testing.T) {
556	testCases := []Bp2buildTestCase{
557		{
558			Description:                "host and device, device only",
559			ModuleTypeUnderTest:        "custom",
560			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
561			Blueprint: `custom {
562		name: "foo",
563		bazel_module: { bp2build_available: true },
564}`,
565			ExpectedBazelTargets: []string{
566				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
567			},
568		},
569		{
570			Description:                "host and device, both",
571			ModuleTypeUnderTest:        "custom",
572			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
573			Blueprint: `custom {
574		name: "foo",
575		host_supported: true,
576		bazel_module: { bp2build_available: true },
577}`,
578			ExpectedBazelTargets: []string{
579				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}),
580			},
581		},
582		{
583			Description:                "host and device, host explicitly disabled",
584			ModuleTypeUnderTest:        "custom",
585			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
586			Blueprint: `custom {
587		name: "foo",
588		host_supported: false,
589		bazel_module: { bp2build_available: true },
590}`,
591			ExpectedBazelTargets: []string{
592				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
593			},
594		},
595		{
596			Description:                "host and device, neither",
597			ModuleTypeUnderTest:        "custom",
598			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
599			Blueprint: `custom {
600		name: "foo",
601		host_supported: false,
602		device_supported: false,
603		bazel_module: { bp2build_available: true },
604}`,
605			ExpectedBazelTargets: []string{
606				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
607					"target_compatible_with": `["@platforms//:incompatible"]`,
608				}),
609			},
610		},
611		{
612			Description:                "host and device, neither, cannot override with product_var",
613			ModuleTypeUnderTest:        "custom",
614			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
615			Blueprint: `custom {
616		name: "foo",
617		host_supported: false,
618		device_supported: false,
619		product_variables: { unbundled_build: { enabled: true } },
620		bazel_module: { bp2build_available: true },
621}`,
622			ExpectedBazelTargets: []string{
623				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
624					"target_compatible_with": `["@platforms//:incompatible"]`,
625				}),
626			},
627		},
628		{
629			Description:                "host and device, both, disabled overrided with product_var",
630			ModuleTypeUnderTest:        "custom",
631			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
632			Blueprint: `custom {
633		name: "foo",
634		host_supported: true,
635		device_supported: true,
636		enabled: false,
637		product_variables: { unbundled_build: { enabled: true } },
638		bazel_module: { bp2build_available: true },
639}`,
640			ExpectedBazelTargets: []string{
641				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
642					"target_compatible_with": `["//build/bazel/product_variables:unbundled_build"]`,
643				}),
644			},
645		},
646		{
647			Description:                "host and device, neither, cannot override with arch enabled",
648			ModuleTypeUnderTest:        "custom",
649			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
650			Blueprint: `custom {
651		name: "foo",
652		host_supported: false,
653		device_supported: false,
654		arch: { x86: { enabled: true } },
655		bazel_module: { bp2build_available: true },
656}`,
657			ExpectedBazelTargets: []string{
658				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
659					"target_compatible_with": `["@platforms//:incompatible"]`,
660				}),
661			},
662		},
663		{
664			Description:                "host and device, host only",
665			ModuleTypeUnderTest:        "custom",
666			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
667			Blueprint: `custom {
668		name: "foo",
669		host_supported: true,
670		device_supported: false,
671		bazel_module: { bp2build_available: true },
672}`,
673			ExpectedBazelTargets: []string{
674				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
675			},
676		},
677		{
678			Description:                "host only",
679			ModuleTypeUnderTest:        "custom",
680			ModuleTypeUnderTestFactory: customModuleFactoryHostSupported,
681			Blueprint: `custom {
682		name: "foo",
683		bazel_module: { bp2build_available: true },
684}`,
685			ExpectedBazelTargets: []string{
686				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
687			},
688		},
689		{
690			Description:                "device only",
691			ModuleTypeUnderTest:        "custom",
692			ModuleTypeUnderTestFactory: customModuleFactoryDeviceSupported,
693			Blueprint: `custom {
694		name: "foo",
695		bazel_module: { bp2build_available: true },
696}`,
697			ExpectedBazelTargets: []string{
698				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
699			},
700		},
701		{
702			Description:                "host and device default, default",
703			ModuleTypeUnderTest:        "custom",
704			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
705			Blueprint: `custom {
706		name: "foo",
707		bazel_module: { bp2build_available: true },
708}`,
709			ExpectedBazelTargets: []string{
710				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{}),
711			},
712		},
713		{
714			Description:                "host and device default, device only",
715			ModuleTypeUnderTest:        "custom",
716			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
717			Blueprint: `custom {
718		name: "foo",
719		host_supported: false,
720		bazel_module: { bp2build_available: true },
721}`,
722			ExpectedBazelTargets: []string{
723				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.DeviceSupported),
724			},
725		},
726		{
727			Description:                "host and device default, host only",
728			ModuleTypeUnderTest:        "custom",
729			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
730			Blueprint: `custom {
731		name: "foo",
732		device_supported: false,
733		bazel_module: { bp2build_available: true },
734}`,
735			ExpectedBazelTargets: []string{
736				makeBazelTargetHostOrDevice("custom", "foo", AttrNameToString{}, android.HostSupported),
737			},
738		},
739		{
740			Description:                "host and device default, neither",
741			ModuleTypeUnderTest:        "custom",
742			ModuleTypeUnderTestFactory: customModuleFactoryHostAndDeviceDefault,
743			Blueprint: `custom {
744		name: "foo",
745		host_supported: false,
746		device_supported: false,
747		bazel_module: { bp2build_available: true },
748}`,
749			ExpectedBazelTargets: []string{
750				MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
751					"target_compatible_with": `["@platforms//:incompatible"]`,
752				}),
753			},
754		},
755	}
756
757	for _, tc := range testCases {
758		t.Run(tc.Description, func(t *testing.T) {
759			RunBp2BuildTestCaseSimple(t, tc)
760		})
761	}
762}
763
764func TestLoadStatements(t *testing.T) {
765	testCases := []struct {
766		bazelTargets           BazelTargets
767		expectedLoadStatements string
768	}{
769		{
770			bazelTargets: BazelTargets{
771				BazelTarget{
772					name:            "foo",
773					ruleClass:       "cc_library",
774					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
775				},
776			},
777			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
778		},
779		{
780			bazelTargets: BazelTargets{
781				BazelTarget{
782					name:            "foo",
783					ruleClass:       "cc_library",
784					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
785				},
786				BazelTarget{
787					name:            "bar",
788					ruleClass:       "cc_library",
789					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
790				},
791			},
792			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
793		},
794		{
795			bazelTargets: BazelTargets{
796				BazelTarget{
797					name:            "foo",
798					ruleClass:       "cc_library",
799					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
800				},
801				BazelTarget{
802					name:            "bar",
803					ruleClass:       "cc_binary",
804					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
805				},
806			},
807			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")`,
808		},
809		{
810			bazelTargets: BazelTargets{
811				BazelTarget{
812					name:            "foo",
813					ruleClass:       "cc_library",
814					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
815				},
816				BazelTarget{
817					name:            "bar",
818					ruleClass:       "cc_binary",
819					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
820				},
821				BazelTarget{
822					name:            "baz",
823					ruleClass:       "java_binary",
824					bzlLoadLocation: "//build/bazel/rules:java.bzl",
825				},
826			},
827			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")
828load("//build/bazel/rules:java.bzl", "java_binary")`,
829		},
830		{
831			bazelTargets: BazelTargets{
832				BazelTarget{
833					name:            "foo",
834					ruleClass:       "cc_binary",
835					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
836				},
837				BazelTarget{
838					name:            "bar",
839					ruleClass:       "java_binary",
840					bzlLoadLocation: "//build/bazel/rules:java.bzl",
841				},
842				BazelTarget{
843					name:      "baz",
844					ruleClass: "genrule",
845					// Note: no bzlLoadLocation for native rules
846				},
847			},
848			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary")
849load("//build/bazel/rules:java.bzl", "java_binary")`,
850		},
851	}
852
853	for _, testCase := range testCases {
854		actual := testCase.bazelTargets.LoadStatements()
855		expected := testCase.expectedLoadStatements
856		if actual != expected {
857			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
858		}
859	}
860
861}
862
863func TestGenerateBazelTargetModules_OneToMany_LoadedFromStarlark(t *testing.T) {
864	testCases := []struct {
865		bp                       string
866		expectedBazelTarget      string
867		expectedBazelTargetCount int
868		expectedLoadStatements   string
869	}{
870		{
871			bp: `custom {
872    name: "bar",
873    host_supported: true,
874    one_to_many_prop: true,
875    bazel_module: { bp2build_available: true  },
876}`,
877			expectedBazelTarget: `my_library(
878    name = "bar",
879)
880
881proto_library(
882    name = "bar_proto_library_deps",
883)
884
885my_proto_library(
886    name = "bar_my_proto_library_deps",
887)`,
888			expectedBazelTargetCount: 3,
889			expectedLoadStatements: `load("//build/bazel/rules:proto.bzl", "my_proto_library", "proto_library")
890load("//build/bazel/rules:rules.bzl", "my_library")`,
891		},
892	}
893
894	dir := "."
895	for _, testCase := range testCases {
896		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
897		ctx := android.NewTestContext(config)
898		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
899		ctx.RegisterForBazelConversion()
900
901		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
902		android.FailIfErrored(t, errs)
903		_, errs = ctx.ResolveDependencies(config)
904		android.FailIfErrored(t, errs)
905
906		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
907		bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
908		android.FailIfErrored(t, err)
909		if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount {
910			t.Fatalf("Expected %d bazel target, got %d", testCase.expectedBazelTargetCount, actualCount)
911		}
912
913		actualBazelTargets := bazelTargets.String()
914		if actualBazelTargets != testCase.expectedBazelTarget {
915			t.Errorf(
916				"Expected generated Bazel target to be '%s', got '%s'",
917				testCase.expectedBazelTarget,
918				actualBazelTargets,
919			)
920		}
921
922		actualLoadStatements := bazelTargets.LoadStatements()
923		if actualLoadStatements != testCase.expectedLoadStatements {
924			t.Errorf(
925				"Expected generated load statements to be '%s', got '%s'",
926				testCase.expectedLoadStatements,
927				actualLoadStatements,
928			)
929		}
930	}
931}
932
933func TestModuleTypeBp2Build(t *testing.T) {
934	testCases := []Bp2buildTestCase{
935		{
936			Description:                "filegroup with does not specify srcs",
937			ModuleTypeUnderTest:        "filegroup",
938			ModuleTypeUnderTestFactory: android.FileGroupFactory,
939			Blueprint: `filegroup {
940    name: "fg_foo",
941    bazel_module: { bp2build_available: true },
942}`,
943			ExpectedBazelTargets: []string{
944				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
945			},
946		},
947		{
948			Description:                "filegroup with no srcs",
949			ModuleTypeUnderTest:        "filegroup",
950			ModuleTypeUnderTestFactory: android.FileGroupFactory,
951			Blueprint: `filegroup {
952    name: "fg_foo",
953    srcs: [],
954    bazel_module: { bp2build_available: true },
955}`,
956			ExpectedBazelTargets: []string{
957				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
958			},
959		},
960		{
961			Description:                "filegroup with srcs",
962			ModuleTypeUnderTest:        "filegroup",
963			ModuleTypeUnderTestFactory: android.FileGroupFactory,
964			Blueprint: `filegroup {
965    name: "fg_foo",
966    srcs: ["a", "b"],
967    bazel_module: { bp2build_available: true },
968}`,
969			ExpectedBazelTargets: []string{
970				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
971					"srcs": `[
972        "a",
973        "b",
974    ]`,
975				}),
976			},
977		},
978		{
979			Description:                "filegroup with dot-slash-prefixed srcs",
980			ModuleTypeUnderTest:        "filegroup",
981			ModuleTypeUnderTestFactory: android.FileGroupFactory,
982			Blueprint: `filegroup {
983    name: "fg_foo",
984    srcs: ["./a", "./b"],
985    bazel_module: { bp2build_available: true },
986}`,
987			ExpectedBazelTargets: []string{
988				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
989					"srcs": `[
990        "a",
991        "b",
992    ]`,
993				}),
994			},
995		},
996		{
997			Description:                "filegroup with excludes srcs",
998			ModuleTypeUnderTest:        "filegroup",
999			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1000			Blueprint: `filegroup {
1001    name: "fg_foo",
1002    srcs: ["a", "b"],
1003    exclude_srcs: ["a"],
1004    bazel_module: { bp2build_available: true },
1005}`,
1006			ExpectedBazelTargets: []string{
1007				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1008					"srcs": `["b"]`,
1009				}),
1010			},
1011		},
1012		{
1013			Description:                "depends_on_other_dir_module",
1014			ModuleTypeUnderTest:        "filegroup",
1015			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1016			Blueprint: `filegroup {
1017    name: "fg_foo",
1018    srcs: [
1019        ":foo",
1020        "c",
1021    ],
1022    bazel_module: { bp2build_available: true },
1023}`,
1024			Filesystem: map[string]string{
1025				"other/Android.bp": `filegroup {
1026    name: "foo",
1027    srcs: ["a", "b"],
1028    bazel_module: { bp2build_available: true },
1029}`,
1030			},
1031			ExpectedBazelTargets: []string{
1032				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1033					"srcs": `[
1034        "//other:foo",
1035        "c",
1036    ]`,
1037				}),
1038			},
1039		},
1040		{
1041			Description:                "depends_on_other_unconverted_module_error",
1042			ModuleTypeUnderTest:        "filegroup",
1043			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1044			UnconvertedDepsMode:        errorModulesUnconvertedDeps,
1045			Blueprint: `filegroup {
1046    name: "foobar",
1047    srcs: [
1048        ":foo",
1049        "c",
1050    ],
1051    bazel_module: { bp2build_available: true },
1052}`,
1053			ExpectedErr: fmt.Errorf(`filegroup .:foobar depends on unconverted modules: foo`),
1054			Filesystem: map[string]string{
1055				"other/Android.bp": `filegroup {
1056    name: "foo",
1057    srcs: ["a", "b"],
1058}`,
1059			},
1060		},
1061		{
1062			Description:                "depends_on_other_missing_module_error",
1063			ModuleTypeUnderTest:        "filegroup",
1064			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1065			UnconvertedDepsMode:        errorModulesUnconvertedDeps,
1066			Blueprint: `filegroup {
1067    name: "foobar",
1068    srcs: [
1069        "c",
1070        "//other:foo",
1071        "//other:goo",
1072    ],
1073    bazel_module: { bp2build_available: true },
1074}`,
1075			ExpectedErr: fmt.Errorf(`filegroup .:foobar depends on missing modules: //other:goo`),
1076			Filesystem: map[string]string{"other/Android.bp": `filegroup {
1077    name: "foo",
1078    srcs: ["a"],
1079    bazel_module: { bp2build_available: true },
1080}
1081`,
1082			},
1083		},
1084	}
1085
1086	for _, testCase := range testCases {
1087		t.Run(testCase.Description, func(t *testing.T) {
1088			RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, testCase)
1089		})
1090	}
1091}
1092
1093func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) {
1094	testCases := []struct {
1095		moduleTypeUnderTest        string
1096		moduleTypeUnderTestFactory android.ModuleFactory
1097		bp                         string
1098		expectedCount              int
1099		description                string
1100	}{
1101		{
1102			description:                "explicitly unavailable",
1103			moduleTypeUnderTest:        "filegroup",
1104			moduleTypeUnderTestFactory: android.FileGroupFactory,
1105			bp: `filegroup {
1106    name: "foo",
1107    srcs: ["a", "b"],
1108    bazel_module: { bp2build_available: false },
1109}`,
1110			expectedCount: 0,
1111		},
1112		{
1113			description:                "implicitly unavailable",
1114			moduleTypeUnderTest:        "filegroup",
1115			moduleTypeUnderTestFactory: android.FileGroupFactory,
1116			bp: `filegroup {
1117    name: "foo",
1118    srcs: ["a", "b"],
1119}`,
1120			expectedCount: 0,
1121		},
1122		{
1123			description:                "explicitly available",
1124			moduleTypeUnderTest:        "filegroup",
1125			moduleTypeUnderTestFactory: android.FileGroupFactory,
1126			bp: `filegroup {
1127    name: "foo",
1128    srcs: ["a", "b"],
1129    bazel_module: { bp2build_available: true },
1130}`,
1131			expectedCount: 1,
1132		},
1133		{
1134			description:                "generates more than 1 target if needed",
1135			moduleTypeUnderTest:        "custom",
1136			moduleTypeUnderTestFactory: customModuleFactoryHostAndDevice,
1137			bp: `custom {
1138    name: "foo",
1139    one_to_many_prop: true,
1140    bazel_module: { bp2build_available: true },
1141}`,
1142			expectedCount: 3,
1143		},
1144	}
1145
1146	dir := "."
1147	for _, testCase := range testCases {
1148		t.Run(testCase.description, func(t *testing.T) {
1149			config := android.TestConfig(buildDir, nil, testCase.bp, nil)
1150			ctx := android.NewTestContext(config)
1151			ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
1152			ctx.RegisterForBazelConversion()
1153
1154			_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
1155			android.FailIfErrored(t, errs)
1156			_, errs = ctx.ResolveDependencies(config)
1157			android.FailIfErrored(t, errs)
1158
1159			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
1160			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
1161			android.FailIfErrored(t, err)
1162			if actualCount := len(bazelTargets); actualCount != testCase.expectedCount {
1163				t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, testCase.expectedCount, actualCount)
1164			}
1165		})
1166	}
1167}
1168
1169func TestAllowlistingBp2buildTargetsWithConfig(t *testing.T) {
1170	testCases := []struct {
1171		moduleTypeUnderTest        string
1172		moduleTypeUnderTestFactory android.ModuleFactory
1173		expectedCount              map[string]int
1174		description                string
1175		bp2buildConfig             allowlists.Bp2BuildConfig
1176		checkDir                   string
1177		fs                         map[string]string
1178		forceEnabledModules        []string
1179		expectedErrorMessages      []string
1180	}{
1181		{
1182			description:                "test bp2build config package and subpackages config",
1183			moduleTypeUnderTest:        "filegroup",
1184			moduleTypeUnderTestFactory: android.FileGroupFactory,
1185			expectedCount: map[string]int{
1186				"migrated":                           1,
1187				"migrated/but_not_really":            0,
1188				"migrated/but_not_really/but_really": 1,
1189				"not_migrated":                       0,
1190				"also_not_migrated":                  0,
1191			},
1192			bp2buildConfig: allowlists.Bp2BuildConfig{
1193				"migrated":                allowlists.Bp2BuildDefaultTrueRecursively,
1194				"migrated/but_not_really": allowlists.Bp2BuildDefaultFalse,
1195				"not_migrated":            allowlists.Bp2BuildDefaultFalse,
1196			},
1197			fs: map[string]string{
1198				"migrated/Android.bp":                           `filegroup { name: "a" }`,
1199				"migrated/but_not_really/Android.bp":            `filegroup { name: "b" }`,
1200				"migrated/but_not_really/but_really/Android.bp": `filegroup { name: "c" }`,
1201				"not_migrated/Android.bp":                       `filegroup { name: "d" }`,
1202				"also_not_migrated/Android.bp":                  `filegroup { name: "e" }`,
1203			},
1204		},
1205		{
1206			description:                "test bp2build config opt-in and opt-out",
1207			moduleTypeUnderTest:        "filegroup",
1208			moduleTypeUnderTestFactory: android.FileGroupFactory,
1209			expectedCount: map[string]int{
1210				"package-opt-in":             2,
1211				"package-opt-in/subpackage":  0,
1212				"package-opt-out":            1,
1213				"package-opt-out/subpackage": 0,
1214			},
1215			bp2buildConfig: allowlists.Bp2BuildConfig{
1216				"package-opt-in":  allowlists.Bp2BuildDefaultFalse,
1217				"package-opt-out": allowlists.Bp2BuildDefaultTrueRecursively,
1218			},
1219			fs: map[string]string{
1220				"package-opt-in/Android.bp": `
1221filegroup { name: "opt-in-a" }
1222filegroup { name: "opt-in-b", bazel_module: { bp2build_available: true } }
1223filegroup { name: "opt-in-c", bazel_module: { bp2build_available: true } }
1224`,
1225
1226				"package-opt-in/subpackage/Android.bp": `
1227filegroup { name: "opt-in-d" } // parent package not configured to DefaultTrueRecursively
1228`,
1229
1230				"package-opt-out/Android.bp": `
1231filegroup { name: "opt-out-a" }
1232filegroup { name: "opt-out-b", bazel_module: { bp2build_available: false } }
1233filegroup { name: "opt-out-c", bazel_module: { bp2build_available: false } }
1234`,
1235
1236				"package-opt-out/subpackage/Android.bp": `
1237filegroup { name: "opt-out-g", bazel_module: { bp2build_available: false } }
1238filegroup { name: "opt-out-h", bazel_module: { bp2build_available: false } }
1239`,
1240			},
1241		},
1242		{
1243			description:                "test force-enabled errors out",
1244			moduleTypeUnderTest:        "filegroup",
1245			moduleTypeUnderTestFactory: android.FileGroupFactory,
1246			expectedCount: map[string]int{
1247				"migrated":     0,
1248				"not_migrated": 0,
1249			},
1250			bp2buildConfig: allowlists.Bp2BuildConfig{
1251				"migrated/but_not_really": allowlists.Bp2BuildDefaultFalse,
1252				"not_migrated":            allowlists.Bp2BuildDefaultFalse,
1253			},
1254			fs: map[string]string{
1255				"migrated/Android.bp": `filegroup { name: "a" }`,
1256			},
1257			forceEnabledModules:   []string{"a"},
1258			expectedErrorMessages: []string{"Force Enabled Module a not converted"},
1259		},
1260	}
1261
1262	dir := "."
1263	for _, testCase := range testCases {
1264		fs := make(map[string][]byte)
1265		toParse := []string{
1266			"Android.bp",
1267		}
1268		for f, content := range testCase.fs {
1269			if strings.HasSuffix(f, "Android.bp") {
1270				toParse = append(toParse, f)
1271			}
1272			fs[f] = []byte(content)
1273		}
1274		config := android.TestConfig(buildDir, nil, "", fs)
1275		config.AddForceEnabledModules(testCase.forceEnabledModules)
1276		ctx := android.NewTestContext(config)
1277		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
1278		allowlist := android.NewBp2BuildAllowlist().SetDefaultConfig(testCase.bp2buildConfig)
1279		ctx.RegisterBp2BuildConfig(allowlist)
1280		ctx.RegisterForBazelConversion()
1281
1282		_, errs := ctx.ParseFileList(dir, toParse)
1283		android.FailIfErrored(t, errs)
1284		_, errs = ctx.ResolveDependencies(config)
1285		android.FailIfErrored(t, errs)
1286
1287		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
1288
1289		// For each directory, test that the expected number of generated targets is correct.
1290		for dir, expectedCount := range testCase.expectedCount {
1291			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
1292			android.CheckErrorsAgainstExpectations(t, err, testCase.expectedErrorMessages)
1293			if actualCount := len(bazelTargets); actualCount != expectedCount {
1294				t.Fatalf(
1295					"%s: Expected %d bazel target for %s package, got %d",
1296					testCase.description,
1297					expectedCount,
1298					dir,
1299					actualCount)
1300			}
1301
1302		}
1303	}
1304}
1305
1306func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
1307	testCases := []Bp2buildTestCase{
1308		{
1309			Description:                "filegroup bazel_module.label",
1310			ModuleTypeUnderTest:        "filegroup",
1311			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1312			Blueprint: `filegroup {
1313    name: "fg_foo",
1314    bazel_module: { label: "//other:fg_foo" },
1315}`,
1316			ExpectedBazelTargets: []string{},
1317			Filesystem: map[string]string{
1318				"other/BUILD.bazel": `// BUILD file`,
1319			},
1320		},
1321		{
1322			Description:                "multiple bazel_module.label same BUILD",
1323			ModuleTypeUnderTest:        "filegroup",
1324			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1325			Blueprint: `filegroup {
1326        name: "fg_foo",
1327        bazel_module: { label: "//other:fg_foo" },
1328    }
1329
1330    filegroup {
1331        name: "foo",
1332        bazel_module: { label: "//other:foo" },
1333    }`,
1334			ExpectedBazelTargets: []string{},
1335			Filesystem: map[string]string{
1336				"other/BUILD.bazel": `// BUILD file`,
1337			},
1338		},
1339		{
1340			Description:                "filegroup bazel_module.label and bp2build in subdir",
1341			ModuleTypeUnderTest:        "filegroup",
1342			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1343			Dir:                        "other",
1344			Blueprint:                  ``,
1345			Filesystem: map[string]string{
1346				"other/Android.bp": `filegroup {
1347        name: "fg_foo",
1348        bazel_module: {
1349          bp2build_available: true,
1350        },
1351      }
1352      filegroup {
1353        name: "fg_bar",
1354        bazel_module: {
1355          label: "//other:fg_bar"
1356        },
1357      }`,
1358				"other/BUILD.bazel": `// definition for fg_bar`,
1359			},
1360			ExpectedBazelTargets: []string{
1361				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{}),
1362			},
1363		},
1364		{
1365			Description:                "filegroup bazel_module.label and filegroup bp2build",
1366			ModuleTypeUnderTest:        "filegroup",
1367			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1368
1369			Filesystem: map[string]string{
1370				"other/BUILD.bazel": `// BUILD file`,
1371			},
1372			Blueprint: `filegroup {
1373        name: "fg_foo",
1374        bazel_module: {
1375          label: "//other:fg_foo",
1376        },
1377    }
1378
1379    filegroup {
1380        name: "fg_bar",
1381        bazel_module: {
1382          bp2build_available: true,
1383        },
1384    }`,
1385			ExpectedBazelTargets: []string{
1386				MakeBazelTargetNoRestrictions("filegroup", "fg_bar", map[string]string{}),
1387			},
1388		},
1389	}
1390
1391	dir := "."
1392	for _, testCase := range testCases {
1393		t.Run(testCase.Description, func(t *testing.T) {
1394			fs := make(map[string][]byte)
1395			toParse := []string{
1396				"Android.bp",
1397			}
1398			for f, content := range testCase.Filesystem {
1399				if strings.HasSuffix(f, "Android.bp") {
1400					toParse = append(toParse, f)
1401				}
1402				fs[f] = []byte(content)
1403			}
1404			config := android.TestConfig(buildDir, nil, testCase.Blueprint, fs)
1405			ctx := android.NewTestContext(config)
1406			ctx.RegisterModuleType(testCase.ModuleTypeUnderTest, testCase.ModuleTypeUnderTestFactory)
1407			ctx.RegisterForBazelConversion()
1408
1409			_, errs := ctx.ParseFileList(dir, toParse)
1410			if errored(t, testCase, errs) {
1411				return
1412			}
1413			_, errs = ctx.ResolveDependencies(config)
1414			if errored(t, testCase, errs) {
1415				return
1416			}
1417
1418			checkDir := dir
1419			if testCase.Dir != "" {
1420				checkDir = testCase.Dir
1421			}
1422			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build, "")
1423			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
1424			android.FailIfErrored(t, err)
1425			bazelTargets.sort()
1426			actualCount := len(bazelTargets)
1427			expectedCount := len(testCase.ExpectedBazelTargets)
1428			if actualCount != expectedCount {
1429				t.Errorf("Expected %d bazel target, got %d\n%s", expectedCount, actualCount, bazelTargets)
1430			}
1431			for i, target := range bazelTargets {
1432				actualContent := target.content
1433				expectedContent := testCase.ExpectedBazelTargets[i]
1434				if expectedContent != actualContent {
1435					t.Errorf(
1436						"Expected generated Bazel target to be '%s', got '%s'",
1437						expectedContent,
1438						actualContent,
1439					)
1440				}
1441			}
1442		})
1443	}
1444}
1445
1446func TestGlob(t *testing.T) {
1447	testCases := []Bp2buildTestCase{
1448		{
1449			Description:                "filegroup with glob",
1450			ModuleTypeUnderTest:        "filegroup",
1451			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1452			Blueprint: `filegroup {
1453    name: "fg_foo",
1454    srcs: ["**/*.txt"],
1455    bazel_module: { bp2build_available: true },
1456}`,
1457			ExpectedBazelTargets: []string{
1458				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1459					"srcs": `[
1460        "other/a.txt",
1461        "other/b.txt",
1462        "other/subdir/a.txt",
1463    ]`,
1464				}),
1465			},
1466			Filesystem: map[string]string{
1467				"other/a.txt":        "",
1468				"other/b.txt":        "",
1469				"other/subdir/a.txt": "",
1470				"other/file":         "",
1471			},
1472		},
1473		{
1474			Description:                "filegroup with glob in subdir",
1475			ModuleTypeUnderTest:        "filegroup",
1476			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1477			Dir:                        "other",
1478			Filesystem: map[string]string{
1479				"other/Android.bp": `filegroup {
1480    name: "fg_foo",
1481    srcs: ["**/*.txt"],
1482    bazel_module: { bp2build_available: true },
1483}`,
1484				"other/a.txt":        "",
1485				"other/b.txt":        "",
1486				"other/subdir/a.txt": "",
1487				"other/file":         "",
1488			},
1489			ExpectedBazelTargets: []string{
1490				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1491					"srcs": `[
1492        "a.txt",
1493        "b.txt",
1494        "subdir/a.txt",
1495    ]`,
1496				}),
1497			},
1498		},
1499		{
1500			Description:                "filegroup with glob with no kept BUILD files",
1501			ModuleTypeUnderTest:        "filegroup",
1502			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1503			KeepBuildFileForDirs:       []string{
1504				// empty
1505			},
1506			Blueprint: `filegroup {
1507    name: "fg_foo",
1508    srcs: ["**/*.txt"],
1509    bazel_module: { bp2build_available: true },
1510}`,
1511			Filesystem: map[string]string{
1512				"a.txt":         "",
1513				"b.txt":         "",
1514				"foo/BUILD":     "",
1515				"foo/a.txt":     "",
1516				"foo/bar/BUILD": "",
1517				"foo/bar/b.txt": "",
1518			},
1519			ExpectedBazelTargets: []string{
1520				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1521					"srcs": `[
1522        "a.txt",
1523        "b.txt",
1524        "foo/a.txt",
1525        "foo/bar/b.txt",
1526    ]`,
1527				}),
1528			},
1529		},
1530		{
1531			Description:                "filegroup with glob with kept BUILD file",
1532			ModuleTypeUnderTest:        "filegroup",
1533			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1534			KeepBuildFileForDirs: []string{
1535				"foo",
1536			},
1537			Blueprint: `filegroup {
1538    name: "fg_foo",
1539    srcs: ["**/*.txt"],
1540    bazel_module: { bp2build_available: true },
1541}`,
1542			Filesystem: map[string]string{
1543				"a.txt":         "",
1544				"b.txt":         "",
1545				"foo/BUILD":     "",
1546				"foo/a.txt":     "",
1547				"foo/bar/BUILD": "",
1548				"foo/bar/b.txt": "",
1549			},
1550			ExpectedBazelTargets: []string{
1551				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1552					"srcs": `[
1553        "a.txt",
1554        "b.txt",
1555        "//foo:a.txt",
1556        "//foo:bar/b.txt",
1557    ]`,
1558				}),
1559			},
1560		},
1561		{
1562			Description:                "filegroup with glob with kept BUILD.bazel file",
1563			ModuleTypeUnderTest:        "filegroup",
1564			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1565			KeepBuildFileForDirs: []string{
1566				"foo",
1567			},
1568			Blueprint: `filegroup {
1569    name: "fg_foo",
1570    srcs: ["**/*.txt"],
1571    bazel_module: { bp2build_available: true },
1572}`,
1573			Filesystem: map[string]string{
1574				"a.txt":               "",
1575				"b.txt":               "",
1576				"foo/BUILD.bazel":     "",
1577				"foo/a.txt":           "",
1578				"foo/bar/BUILD.bazel": "",
1579				"foo/bar/b.txt":       "",
1580			},
1581			ExpectedBazelTargets: []string{
1582				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1583					"srcs": `[
1584        "a.txt",
1585        "b.txt",
1586        "//foo:a.txt",
1587        "//foo:bar/b.txt",
1588    ]`,
1589				}),
1590			},
1591		},
1592		{
1593			Description:                "filegroup with glob with Android.bp file as boundary",
1594			ModuleTypeUnderTest:        "filegroup",
1595			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1596			Blueprint: `filegroup {
1597    name: "fg_foo",
1598    srcs: ["**/*.txt"],
1599    bazel_module: { bp2build_available: true },
1600}`,
1601			Filesystem: map[string]string{
1602				"a.txt":              "",
1603				"b.txt":              "",
1604				"foo/Android.bp":     "",
1605				"foo/a.txt":          "",
1606				"foo/bar/Android.bp": "",
1607				"foo/bar/b.txt":      "",
1608			},
1609			ExpectedBazelTargets: []string{
1610				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1611					"srcs": `[
1612        "a.txt",
1613        "b.txt",
1614        "//foo:a.txt",
1615        "//foo/bar:b.txt",
1616    ]`,
1617				}),
1618			},
1619		},
1620		{
1621			Description:                "filegroup with glob in subdir with kept BUILD and BUILD.bazel file",
1622			ModuleTypeUnderTest:        "filegroup",
1623			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1624			Dir:                        "other",
1625			KeepBuildFileForDirs: []string{
1626				"other/foo",
1627				"other/foo/bar",
1628				// deliberately not other/foo/baz/BUILD.
1629			},
1630			Filesystem: map[string]string{
1631				"other/Android.bp": `filegroup {
1632    name: "fg_foo",
1633    srcs: ["**/*.txt"],
1634    bazel_module: { bp2build_available: true },
1635}`,
1636				"other/a.txt":               "",
1637				"other/b.txt":               "",
1638				"other/foo/BUILD":           "",
1639				"other/foo/a.txt":           "",
1640				"other/foo/bar/BUILD.bazel": "",
1641				"other/foo/bar/b.txt":       "",
1642				"other/foo/baz/BUILD":       "",
1643				"other/foo/baz/c.txt":       "",
1644			},
1645			ExpectedBazelTargets: []string{
1646				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1647					"srcs": `[
1648        "a.txt",
1649        "b.txt",
1650        "//other/foo:a.txt",
1651        "//other/foo/bar:b.txt",
1652        "//other/foo:baz/c.txt",
1653    ]`,
1654				}),
1655			},
1656		},
1657	}
1658
1659	for _, testCase := range testCases {
1660		t.Run(testCase.Description, func(t *testing.T) {
1661			RunBp2BuildTestCaseSimple(t, testCase)
1662		})
1663	}
1664}
1665
1666func TestGlobExcludeSrcs(t *testing.T) {
1667	testCases := []Bp2buildTestCase{
1668		{
1669			Description:                "filegroup top level exclude_srcs",
1670			ModuleTypeUnderTest:        "filegroup",
1671			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1672			Blueprint: `filegroup {
1673    name: "fg_foo",
1674    srcs: ["**/*.txt"],
1675    exclude_srcs: ["c.txt"],
1676    bazel_module: { bp2build_available: true },
1677}`,
1678			Filesystem: map[string]string{
1679				"a.txt":          "",
1680				"b.txt":          "",
1681				"c.txt":          "",
1682				"dir/Android.bp": "",
1683				"dir/e.txt":      "",
1684				"dir/f.txt":      "",
1685			},
1686			ExpectedBazelTargets: []string{
1687				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1688					"srcs": `[
1689        "a.txt",
1690        "b.txt",
1691        "//dir:e.txt",
1692        "//dir:f.txt",
1693    ]`,
1694				}),
1695			},
1696		},
1697		{
1698			Description:                "filegroup in subdir exclude_srcs",
1699			ModuleTypeUnderTest:        "filegroup",
1700			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1701			Blueprint:                  "",
1702			Dir:                        "dir",
1703			Filesystem: map[string]string{
1704				"dir/Android.bp": `filegroup {
1705    name: "fg_foo",
1706    srcs: ["**/*.txt"],
1707    exclude_srcs: ["b.txt"],
1708    bazel_module: { bp2build_available: true },
1709}
1710`,
1711				"dir/a.txt":             "",
1712				"dir/b.txt":             "",
1713				"dir/subdir/Android.bp": "",
1714				"dir/subdir/e.txt":      "",
1715				"dir/subdir/f.txt":      "",
1716			},
1717			ExpectedBazelTargets: []string{
1718				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1719					"srcs": `[
1720        "a.txt",
1721        "//dir/subdir:e.txt",
1722        "//dir/subdir:f.txt",
1723    ]`,
1724				}),
1725			},
1726		},
1727	}
1728
1729	for _, testCase := range testCases {
1730		t.Run(testCase.Description, func(t *testing.T) {
1731			RunBp2BuildTestCaseSimple(t, testCase)
1732		})
1733	}
1734}
1735
1736func TestCommonBp2BuildModuleAttrs(t *testing.T) {
1737	testCases := []Bp2buildTestCase{
1738		{
1739			Description:                "Required into data test",
1740			ModuleTypeUnderTest:        "filegroup",
1741			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1742			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
1743filegroup {
1744    name: "fg_foo",
1745    required: ["reqd"],
1746    bazel_module: { bp2build_available: true },
1747}`,
1748			ExpectedBazelTargets: []string{
1749				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1750					"data": `[":reqd"]`,
1751				}),
1752			},
1753		},
1754		{
1755			Description:                "Required into data test, cyclic self reference is filtered out",
1756			ModuleTypeUnderTest:        "filegroup",
1757			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1758			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
1759filegroup {
1760    name: "fg_foo",
1761    required: ["reqd", "fg_foo"],
1762    bazel_module: { bp2build_available: true },
1763}`,
1764			ExpectedBazelTargets: []string{
1765				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1766					"data": `[":reqd"]`,
1767				}),
1768			},
1769		},
1770		{
1771			Description:                "Required via arch into data test",
1772			ModuleTypeUnderTest:        "python_library",
1773			ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
1774			Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqdx86") +
1775				simpleModuleDoNotConvertBp2build("python_library", "reqdarm") + `
1776python_library {
1777    name: "fg_foo",
1778    arch: {
1779       arm: {
1780         required: ["reqdarm"],
1781       },
1782       x86: {
1783         required: ["reqdx86"],
1784       },
1785    },
1786    bazel_module: { bp2build_available: true },
1787}`,
1788			ExpectedBazelTargets: []string{
1789				MakeBazelTarget("py_library", "fg_foo", map[string]string{
1790					"data": `select({
1791        "//build/bazel/platforms/arch:arm": [":reqdarm"],
1792        "//build/bazel/platforms/arch:x86": [":reqdx86"],
1793        "//conditions:default": [],
1794    })`,
1795					"srcs_version": `"PY3"`,
1796					"imports":      `["."]`,
1797				}),
1798			},
1799		},
1800		{
1801			Description:                "Required appended to data test",
1802			ModuleTypeUnderTest:        "python_library",
1803			ModuleTypeUnderTestFactory: python.PythonLibraryFactory,
1804			Filesystem: map[string]string{
1805				"data.bin": "",
1806				"src.py":   "",
1807			},
1808			Blueprint: simpleModuleDoNotConvertBp2build("python_library", "reqd") + `
1809python_library {
1810    name: "fg_foo",
1811    data: ["data.bin"],
1812    required: ["reqd"],
1813    bazel_module: { bp2build_available: true },
1814}`,
1815			ExpectedBazelTargets: []string{
1816				MakeBazelTarget("py_library", "fg_foo", map[string]string{
1817					"data": `[
1818        "data.bin",
1819        ":reqd",
1820    ]`,
1821					"srcs_version": `"PY3"`,
1822					"imports":      `["."]`,
1823				}),
1824			},
1825		},
1826		{
1827			Description:                "All props-to-attrs at once together test",
1828			ModuleTypeUnderTest:        "filegroup",
1829			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1830			Blueprint: simpleModuleDoNotConvertBp2build("filegroup", "reqd") + `
1831filegroup {
1832    name: "fg_foo",
1833    required: ["reqd"],
1834    bazel_module: { bp2build_available: true },
1835}`,
1836			ExpectedBazelTargets: []string{
1837				MakeBazelTargetNoRestrictions("filegroup", "fg_foo", map[string]string{
1838					"data": `[":reqd"]`,
1839				}),
1840			},
1841		},
1842	}
1843
1844	for _, tc := range testCases {
1845		t.Run(tc.Description, func(t *testing.T) {
1846			RunBp2BuildTestCaseSimple(t, tc)
1847		})
1848	}
1849}
1850
1851func TestLicensesAttrConversion(t *testing.T) {
1852	RunBp2BuildTestCase(t,
1853		func(ctx android.RegistrationContext) {
1854			ctx.RegisterModuleType("license", android.LicenseFactory)
1855		},
1856		Bp2buildTestCase{
1857			Description:                "Test that licenses: attribute is converted",
1858			ModuleTypeUnderTest:        "filegroup",
1859			ModuleTypeUnderTestFactory: android.FileGroupFactory,
1860			Blueprint: `
1861license {
1862    name: "my_license",
1863}
1864filegroup {
1865    name: "my_filegroup",
1866    licenses: ["my_license"],
1867}
1868`,
1869			ExpectedBazelTargets: []string{
1870				MakeBazelTargetNoRestrictions("filegroup", "my_filegroup", AttrNameToString{
1871					"applicable_licenses": `[":my_license"]`,
1872				}),
1873				MakeBazelTargetNoRestrictions("android_license", "my_license", AttrNameToString{}),
1874			},
1875		})
1876}
1877
1878func TestGenerateApiBazelTargets(t *testing.T) {
1879	bp := `
1880	custom {
1881		name: "foo",
1882		api: "foo.txt",
1883	}
1884	`
1885	expectedBazelTarget := MakeBazelTarget(
1886		"custom_api_contribution",
1887		"foo",
1888		AttrNameToString{
1889			"api": `"foo.txt"`,
1890		},
1891	)
1892	registerCustomModule := func(ctx android.RegistrationContext) {
1893		ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
1894	}
1895	RunApiBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
1896		Blueprint:            bp,
1897		ExpectedBazelTargets: []string{expectedBazelTarget},
1898		Description:          "Generating API contribution Bazel targets for custom module",
1899	})
1900}
1901