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	"android/soong/android"
19	"android/soong/genrule"
20	"strings"
21	"testing"
22)
23
24func TestGenerateSoongModuleTargets(t *testing.T) {
25	testCases := []struct {
26		bp                  string
27		expectedBazelTarget string
28	}{
29		{
30			bp: `custom { name: "foo" }
31		`,
32			expectedBazelTarget: `soong_module(
33    name = "foo",
34    soong_module_name = "foo",
35    soong_module_type = "custom",
36    soong_module_variant = "",
37    soong_module_deps = [
38    ],
39)`,
40		},
41		{
42			bp: `custom {
43	name: "foo",
44	ramdisk: true,
45}
46		`,
47			expectedBazelTarget: `soong_module(
48    name = "foo",
49    soong_module_name = "foo",
50    soong_module_type = "custom",
51    soong_module_variant = "",
52    soong_module_deps = [
53    ],
54    ramdisk = True,
55)`,
56		},
57		{
58			bp: `custom {
59	name: "foo",
60	owner: "a_string_with\"quotes\"_and_\\backslashes\\\\",
61}
62		`,
63			expectedBazelTarget: `soong_module(
64    name = "foo",
65    soong_module_name = "foo",
66    soong_module_type = "custom",
67    soong_module_variant = "",
68    soong_module_deps = [
69    ],
70    owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
71)`,
72		},
73		{
74			bp: `custom {
75	name: "foo",
76	required: ["bar"],
77}
78		`,
79			expectedBazelTarget: `soong_module(
80    name = "foo",
81    soong_module_name = "foo",
82    soong_module_type = "custom",
83    soong_module_variant = "",
84    soong_module_deps = [
85    ],
86    required = ["bar"],
87)`,
88		},
89		{
90			bp: `custom {
91	name: "foo",
92	target_required: ["qux", "bazqux"],
93}
94		`,
95			expectedBazelTarget: `soong_module(
96    name = "foo",
97    soong_module_name = "foo",
98    soong_module_type = "custom",
99    soong_module_variant = "",
100    soong_module_deps = [
101    ],
102    target_required = [
103        "qux",
104        "bazqux",
105    ],
106)`,
107		},
108		{
109			bp: `custom {
110	name: "foo",
111	dist: {
112		targets: ["goal_foo"],
113		tag: ".foo",
114	},
115	dists: [{
116		targets: ["goal_bar"],
117		tag: ".bar",
118	}],
119}
120		`,
121			expectedBazelTarget: `soong_module(
122    name = "foo",
123    soong_module_name = "foo",
124    soong_module_type = "custom",
125    soong_module_variant = "",
126    soong_module_deps = [
127    ],
128    dist = {
129        "tag": ".foo",
130        "targets": ["goal_foo"],
131    },
132    dists = [{
133        "tag": ".bar",
134        "targets": ["goal_bar"],
135    }],
136)`,
137		},
138		{
139			bp: `custom {
140	name: "foo",
141	required: ["bar"],
142	target_required: ["qux", "bazqux"],
143	ramdisk: true,
144	owner: "custom_owner",
145	dists: [
146		{
147			tag: ".tag",
148			targets: ["my_goal"],
149		},
150	],
151}
152		`,
153			expectedBazelTarget: `soong_module(
154    name = "foo",
155    soong_module_name = "foo",
156    soong_module_type = "custom",
157    soong_module_variant = "",
158    soong_module_deps = [
159    ],
160    dists = [{
161        "tag": ".tag",
162        "targets": ["my_goal"],
163    }],
164    owner = "custom_owner",
165    ramdisk = True,
166    required = ["bar"],
167    target_required = [
168        "qux",
169        "bazqux",
170    ],
171)`,
172		},
173	}
174
175	dir := "."
176	for _, testCase := range testCases {
177		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
178		ctx := android.NewTestContext(config)
179
180		ctx.RegisterModuleType("custom", customModuleFactory)
181		ctx.Register()
182
183		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
184		android.FailIfErrored(t, errs)
185		_, errs = ctx.PrepareBuildActions(config)
186		android.FailIfErrored(t, errs)
187
188		codegenCtx := NewCodegenContext(config, *ctx.Context, QueryView)
189		bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
190		if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
191			t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
192		}
193
194		actualBazelTarget := bazelTargets[0]
195		if actualBazelTarget.content != testCase.expectedBazelTarget {
196			t.Errorf(
197				"Expected generated Bazel target to be '%s', got '%s'",
198				testCase.expectedBazelTarget,
199				actualBazelTarget.content,
200			)
201		}
202	}
203}
204
205func TestGenerateBazelTargetModules(t *testing.T) {
206	testCases := []struct {
207		name                 string
208		bp                   string
209		expectedBazelTargets []string
210	}{
211		{
212			bp: `custom {
213	name: "foo",
214    string_list_prop: ["a", "b"],
215    string_prop: "a",
216    bazel_module: { bp2build_available: true },
217}`,
218			expectedBazelTargets: []string{`custom(
219    name = "foo",
220    string_list_prop = [
221        "a",
222        "b",
223    ],
224    string_prop = "a",
225)`,
226			},
227		},
228		{
229			bp: `custom {
230	name: "control_characters",
231    string_list_prop: ["\t", "\n"],
232    string_prop: "a\t\n\r",
233    bazel_module: { bp2build_available: true },
234}`,
235			expectedBazelTargets: []string{`custom(
236    name = "control_characters",
237    string_list_prop = [
238        "\t",
239        "\n",
240    ],
241    string_prop = "a\t\n\r",
242)`,
243			},
244		},
245		{
246			bp: `custom {
247  name: "has_dep",
248  arch_paths: [":dep"],
249  bazel_module: { bp2build_available: true },
250}
251
252custom {
253  name: "dep",
254  arch_paths: ["abc"],
255  bazel_module: { bp2build_available: true },
256}`,
257			expectedBazelTargets: []string{`custom(
258    name = "dep",
259    arch_paths = ["abc"],
260)`,
261				`custom(
262    name = "has_dep",
263    arch_paths = [":dep"],
264)`,
265			},
266		},
267		{
268			bp: `custom {
269    name: "arch_paths",
270    arch: {
271      x86: {
272        arch_paths: ["abc"],
273      },
274    },
275    bazel_module: { bp2build_available: true },
276}`,
277			expectedBazelTargets: []string{`custom(
278    name = "arch_paths",
279    arch_paths = select({
280        "//build/bazel/platforms/arch:x86": ["abc"],
281        "//conditions:default": [],
282    }),
283)`,
284			},
285		},
286		{
287			bp: `custom {
288  name: "has_dep",
289  arch: {
290    x86: {
291      arch_paths: [":dep"],
292    },
293  },
294  bazel_module: { bp2build_available: true },
295}
296
297custom {
298    name: "dep",
299    arch_paths: ["abc"],
300    bazel_module: { bp2build_available: true },
301}`,
302			expectedBazelTargets: []string{`custom(
303    name = "dep",
304    arch_paths = ["abc"],
305)`,
306				`custom(
307    name = "has_dep",
308    arch_paths = select({
309        "//build/bazel/platforms/arch:x86": [":dep"],
310        "//conditions:default": [],
311    }),
312)`,
313			},
314		},
315	}
316
317	dir := "."
318	for _, testCase := range testCases {
319		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
320		ctx := android.NewTestContext(config)
321
322		ctx.RegisterModuleType("custom", customModuleFactory)
323		ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutator)
324		ctx.RegisterForBazelConversion()
325
326		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
327		if Errored(t, "", errs) {
328			continue
329		}
330		_, errs = ctx.ResolveDependencies(config)
331		if Errored(t, "", errs) {
332			continue
333		}
334
335		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
336		bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
337
338		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
339			t.Errorf("Expected %d bazel target, got %d", expectedCount, actualCount)
340		} else {
341			for i, expectedBazelTarget := range testCase.expectedBazelTargets {
342				actualBazelTarget := bazelTargets[i]
343				if actualBazelTarget.content != expectedBazelTarget {
344					t.Errorf(
345						"Expected generated Bazel target to be '%s', got '%s'",
346						expectedBazelTarget,
347						actualBazelTarget.content,
348					)
349				}
350			}
351		}
352	}
353}
354
355func TestLoadStatements(t *testing.T) {
356	testCases := []struct {
357		bazelTargets           BazelTargets
358		expectedLoadStatements string
359	}{
360		{
361			bazelTargets: BazelTargets{
362				BazelTarget{
363					name:            "foo",
364					ruleClass:       "cc_library",
365					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
366				},
367			},
368			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
369		},
370		{
371			bazelTargets: BazelTargets{
372				BazelTarget{
373					name:            "foo",
374					ruleClass:       "cc_library",
375					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
376				},
377				BazelTarget{
378					name:            "bar",
379					ruleClass:       "cc_library",
380					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
381				},
382			},
383			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_library")`,
384		},
385		{
386			bazelTargets: BazelTargets{
387				BazelTarget{
388					name:            "foo",
389					ruleClass:       "cc_library",
390					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
391				},
392				BazelTarget{
393					name:            "bar",
394					ruleClass:       "cc_binary",
395					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
396				},
397			},
398			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")`,
399		},
400		{
401			bazelTargets: BazelTargets{
402				BazelTarget{
403					name:            "foo",
404					ruleClass:       "cc_library",
405					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
406				},
407				BazelTarget{
408					name:            "bar",
409					ruleClass:       "cc_binary",
410					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
411				},
412				BazelTarget{
413					name:            "baz",
414					ruleClass:       "java_binary",
415					bzlLoadLocation: "//build/bazel/rules:java.bzl",
416				},
417			},
418			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary", "cc_library")
419load("//build/bazel/rules:java.bzl", "java_binary")`,
420		},
421		{
422			bazelTargets: BazelTargets{
423				BazelTarget{
424					name:            "foo",
425					ruleClass:       "cc_binary",
426					bzlLoadLocation: "//build/bazel/rules:cc.bzl",
427				},
428				BazelTarget{
429					name:            "bar",
430					ruleClass:       "java_binary",
431					bzlLoadLocation: "//build/bazel/rules:java.bzl",
432				},
433				BazelTarget{
434					name:      "baz",
435					ruleClass: "genrule",
436					// Note: no bzlLoadLocation for native rules
437				},
438			},
439			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary")
440load("//build/bazel/rules:java.bzl", "java_binary")`,
441		},
442	}
443
444	for _, testCase := range testCases {
445		actual := testCase.bazelTargets.LoadStatements()
446		expected := testCase.expectedLoadStatements
447		if actual != expected {
448			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
449		}
450	}
451
452}
453
454func TestGenerateBazelTargetModules_OneToMany_LoadedFromStarlark(t *testing.T) {
455	testCases := []struct {
456		bp                       string
457		expectedBazelTarget      string
458		expectedBazelTargetCount int
459		expectedLoadStatements   string
460	}{
461		{
462			bp: `custom {
463    name: "bar",
464    bazel_module: { bp2build_available: true  },
465}`,
466			expectedBazelTarget: `my_library(
467    name = "bar",
468)
469
470my_proto_library(
471    name = "bar_my_proto_library_deps",
472)
473
474proto_library(
475    name = "bar_proto_library_deps",
476)`,
477			expectedBazelTargetCount: 3,
478			expectedLoadStatements: `load("//build/bazel/rules:proto.bzl", "my_proto_library", "proto_library")
479load("//build/bazel/rules:rules.bzl", "my_library")`,
480		},
481	}
482
483	dir := "."
484	for _, testCase := range testCases {
485		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
486		ctx := android.NewTestContext(config)
487		ctx.RegisterModuleType("custom", customModuleFactory)
488		ctx.RegisterBp2BuildMutator("custom", customBp2BuildMutatorFromStarlark)
489		ctx.RegisterForBazelConversion()
490
491		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
492		android.FailIfErrored(t, errs)
493		_, errs = ctx.ResolveDependencies(config)
494		android.FailIfErrored(t, errs)
495
496		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
497		bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
498		if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount {
499			t.Fatalf("Expected %d bazel target, got %d", testCase.expectedBazelTargetCount, actualCount)
500		}
501
502		actualBazelTargets := bazelTargets.String()
503		if actualBazelTargets != testCase.expectedBazelTarget {
504			t.Errorf(
505				"Expected generated Bazel target to be '%s', got '%s'",
506				testCase.expectedBazelTarget,
507				actualBazelTargets,
508			)
509		}
510
511		actualLoadStatements := bazelTargets.LoadStatements()
512		if actualLoadStatements != testCase.expectedLoadStatements {
513			t.Errorf(
514				"Expected generated load statements to be '%s', got '%s'",
515				testCase.expectedLoadStatements,
516				actualLoadStatements,
517			)
518		}
519	}
520}
521
522func TestModuleTypeBp2Build(t *testing.T) {
523	otherGenruleBp := map[string]string{
524		"other/Android.bp": `genrule {
525    name: "foo.tool",
526    out: ["foo_tool.out"],
527    srcs: ["foo_tool.in"],
528    cmd: "cp $(in) $(out)",
529}
530genrule {
531    name: "other.tool",
532    out: ["other_tool.out"],
533    srcs: ["other_tool.in"],
534    cmd: "cp $(in) $(out)",
535}`,
536	}
537
538	testCases := []struct {
539		description                        string
540		moduleTypeUnderTest                string
541		moduleTypeUnderTestFactory         android.ModuleFactory
542		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
543		preArchMutators                    []android.RegisterMutatorFunc
544		depsMutators                       []android.RegisterMutatorFunc
545		bp                                 string
546		expectedBazelTargets               []string
547		fs                                 map[string]string
548		dir                                string
549	}{
550		{
551			description:                        "filegroup with does not specify srcs",
552			moduleTypeUnderTest:                "filegroup",
553			moduleTypeUnderTestFactory:         android.FileGroupFactory,
554			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
555			bp: `filegroup {
556    name: "fg_foo",
557    bazel_module: { bp2build_available: true },
558}`,
559			expectedBazelTargets: []string{
560				`filegroup(
561    name = "fg_foo",
562)`,
563			},
564		},
565		{
566			description:                        "filegroup with no srcs",
567			moduleTypeUnderTest:                "filegroup",
568			moduleTypeUnderTestFactory:         android.FileGroupFactory,
569			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
570			bp: `filegroup {
571    name: "fg_foo",
572    srcs: [],
573    bazel_module: { bp2build_available: true },
574}`,
575			expectedBazelTargets: []string{
576				`filegroup(
577    name = "fg_foo",
578)`,
579			},
580		},
581		{
582			description:                        "filegroup with srcs",
583			moduleTypeUnderTest:                "filegroup",
584			moduleTypeUnderTestFactory:         android.FileGroupFactory,
585			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
586			bp: `filegroup {
587    name: "fg_foo",
588    srcs: ["a", "b"],
589    bazel_module: { bp2build_available: true },
590}`,
591			expectedBazelTargets: []string{`filegroup(
592    name = "fg_foo",
593    srcs = [
594        "a",
595        "b",
596    ],
597)`,
598			},
599		},
600		{
601			description:                        "filegroup with excludes srcs",
602			moduleTypeUnderTest:                "filegroup",
603			moduleTypeUnderTestFactory:         android.FileGroupFactory,
604			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
605			bp: `filegroup {
606    name: "fg_foo",
607    srcs: ["a", "b"],
608    exclude_srcs: ["a"],
609    bazel_module: { bp2build_available: true },
610}`,
611			expectedBazelTargets: []string{`filegroup(
612    name = "fg_foo",
613    srcs = ["b"],
614)`,
615			},
616		},
617		{
618			description:                        "filegroup with glob",
619			moduleTypeUnderTest:                "filegroup",
620			moduleTypeUnderTestFactory:         android.FileGroupFactory,
621			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
622			bp: `filegroup {
623    name: "foo",
624    srcs: ["**/*.txt"],
625    bazel_module: { bp2build_available: true },
626}`,
627			expectedBazelTargets: []string{`filegroup(
628    name = "foo",
629    srcs = [
630        "other/a.txt",
631        "other/b.txt",
632        "other/subdir/a.txt",
633    ],
634)`,
635			},
636			fs: map[string]string{
637				"other/a.txt":        "",
638				"other/b.txt":        "",
639				"other/subdir/a.txt": "",
640				"other/file":         "",
641			},
642		},
643		{
644			description:                        "filegroup with glob in subdir",
645			moduleTypeUnderTest:                "filegroup",
646			moduleTypeUnderTestFactory:         android.FileGroupFactory,
647			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
648			bp: `filegroup {
649    name: "foo",
650    srcs: ["a.txt"],
651    bazel_module: { bp2build_available: true },
652}`,
653			dir: "other",
654			expectedBazelTargets: []string{`filegroup(
655    name = "fg_foo",
656    srcs = [
657        "a.txt",
658        "b.txt",
659        "subdir/a.txt",
660    ],
661)`,
662			},
663			fs: map[string]string{
664				"other/Android.bp": `filegroup {
665    name: "fg_foo",
666    srcs: ["**/*.txt"],
667    bazel_module: { bp2build_available: true },
668}`,
669				"other/a.txt":        "",
670				"other/b.txt":        "",
671				"other/subdir/a.txt": "",
672				"other/file":         "",
673			},
674		},
675		{
676			description:                        "depends_on_other_dir_module",
677			moduleTypeUnderTest:                "filegroup",
678			moduleTypeUnderTestFactory:         android.FileGroupFactory,
679			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
680			bp: `filegroup {
681    name: "foobar",
682    srcs: [
683        ":foo",
684        "c",
685    ],
686    bazel_module: { bp2build_available: true },
687}`,
688			expectedBazelTargets: []string{`filegroup(
689    name = "foobar",
690    srcs = [
691        "//other:foo",
692        "c",
693    ],
694)`,
695			},
696			fs: map[string]string{
697				"other/Android.bp": `filegroup {
698    name: "foo",
699    srcs: ["a", "b"],
700}`,
701			},
702		},
703		{
704			description:                        "genrule with command line variable replacements",
705			moduleTypeUnderTest:                "genrule",
706			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
707			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
708			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
709			bp: `genrule {
710    name: "foo.tool",
711    out: ["foo_tool.out"],
712    srcs: ["foo_tool.in"],
713    cmd: "cp $(in) $(out)",
714    bazel_module: { bp2build_available: true },
715}
716
717genrule {
718    name: "foo",
719    out: ["foo.out"],
720    srcs: ["foo.in"],
721    tools: [":foo.tool"],
722    cmd: "$(location :foo.tool) --genDir=$(genDir) arg $(in) $(out)",
723    bazel_module: { bp2build_available: true },
724}`,
725			expectedBazelTargets: []string{
726				`genrule(
727    name = "foo",
728    cmd = "$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)",
729    outs = ["foo.out"],
730    srcs = ["foo.in"],
731    tools = [":foo.tool"],
732)`,
733				`genrule(
734    name = "foo.tool",
735    cmd = "cp $(SRCS) $(OUTS)",
736    outs = ["foo_tool.out"],
737    srcs = ["foo_tool.in"],
738)`,
739			},
740		},
741		{
742			description:                        "genrule using $(locations :label)",
743			moduleTypeUnderTest:                "genrule",
744			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
745			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
746			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
747			bp: `genrule {
748    name: "foo.tools",
749    out: ["foo_tool.out", "foo_tool2.out"],
750    srcs: ["foo_tool.in"],
751    cmd: "cp $(in) $(out)",
752    bazel_module: { bp2build_available: true },
753}
754
755genrule {
756    name: "foo",
757    out: ["foo.out"],
758    srcs: ["foo.in"],
759    tools: [":foo.tools"],
760    cmd: "$(locations :foo.tools) -s $(out) $(in)",
761    bazel_module: { bp2build_available: true },
762}`,
763			expectedBazelTargets: []string{`genrule(
764    name = "foo",
765    cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
766    outs = ["foo.out"],
767    srcs = ["foo.in"],
768    tools = [":foo.tools"],
769)`,
770				`genrule(
771    name = "foo.tools",
772    cmd = "cp $(SRCS) $(OUTS)",
773    outs = [
774        "foo_tool.out",
775        "foo_tool2.out",
776    ],
777    srcs = ["foo_tool.in"],
778)`,
779			},
780		},
781		{
782			description:                        "genrule using $(locations //absolute:label)",
783			moduleTypeUnderTest:                "genrule",
784			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
785			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
786			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
787			bp: `genrule {
788    name: "foo",
789    out: ["foo.out"],
790    srcs: ["foo.in"],
791    tool_files: [":foo.tool"],
792    cmd: "$(locations :foo.tool) -s $(out) $(in)",
793    bazel_module: { bp2build_available: true },
794}`,
795			expectedBazelTargets: []string{`genrule(
796    name = "foo",
797    cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
798    outs = ["foo.out"],
799    srcs = ["foo.in"],
800    tools = ["//other:foo.tool"],
801)`,
802			},
803			fs: otherGenruleBp,
804		},
805		{
806			description:                        "genrule srcs using $(locations //absolute:label)",
807			moduleTypeUnderTest:                "genrule",
808			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
809			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
810			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
811			bp: `genrule {
812    name: "foo",
813    out: ["foo.out"],
814    srcs: [":other.tool"],
815    tool_files: [":foo.tool"],
816    cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)",
817    bazel_module: { bp2build_available: true },
818}`,
819			expectedBazelTargets: []string{`genrule(
820    name = "foo",
821    cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
822    outs = ["foo.out"],
823    srcs = ["//other:other.tool"],
824    tools = ["//other:foo.tool"],
825)`,
826			},
827			fs: otherGenruleBp,
828		},
829		{
830			description:                        "genrule using $(location) label should substitute first tool label automatically",
831			moduleTypeUnderTest:                "genrule",
832			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
833			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
834			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
835			bp: `genrule {
836    name: "foo",
837    out: ["foo.out"],
838    srcs: ["foo.in"],
839    tool_files: [":foo.tool", ":other.tool"],
840    cmd: "$(location) -s $(out) $(in)",
841    bazel_module: { bp2build_available: true },
842}`,
843			expectedBazelTargets: []string{`genrule(
844    name = "foo",
845    cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
846    outs = ["foo.out"],
847    srcs = ["foo.in"],
848    tools = [
849        "//other:foo.tool",
850        "//other:other.tool",
851    ],
852)`,
853			},
854			fs: otherGenruleBp,
855		},
856		{
857			description:                        "genrule using $(locations) label should substitute first tool label automatically",
858			moduleTypeUnderTest:                "genrule",
859			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
860			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
861			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
862			bp: `genrule {
863    name: "foo",
864    out: ["foo.out"],
865    srcs: ["foo.in"],
866    tools: [":foo.tool", ":other.tool"],
867    cmd: "$(locations) -s $(out) $(in)",
868    bazel_module: { bp2build_available: true },
869}`,
870			expectedBazelTargets: []string{`genrule(
871    name = "foo",
872    cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
873    outs = ["foo.out"],
874    srcs = ["foo.in"],
875    tools = [
876        "//other:foo.tool",
877        "//other:other.tool",
878    ],
879)`,
880			},
881			fs: otherGenruleBp,
882		},
883		{
884			description:                        "genrule without tools or tool_files can convert successfully",
885			moduleTypeUnderTest:                "genrule",
886			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
887			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
888			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
889			bp: `genrule {
890    name: "foo",
891    out: ["foo.out"],
892    srcs: ["foo.in"],
893    cmd: "cp $(in) $(out)",
894    bazel_module: { bp2build_available: true },
895}`,
896			expectedBazelTargets: []string{`genrule(
897    name = "foo",
898    cmd = "cp $(SRCS) $(OUTS)",
899    outs = ["foo.out"],
900    srcs = ["foo.in"],
901)`,
902			},
903		},
904	}
905
906	dir := "."
907	for _, testCase := range testCases {
908		fs := make(map[string][]byte)
909		toParse := []string{
910			"Android.bp",
911		}
912		for f, content := range testCase.fs {
913			if strings.HasSuffix(f, "Android.bp") {
914				toParse = append(toParse, f)
915			}
916			fs[f] = []byte(content)
917		}
918		config := android.TestConfig(buildDir, nil, testCase.bp, fs)
919		ctx := android.NewTestContext(config)
920		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
921		for _, m := range testCase.depsMutators {
922			ctx.DepsBp2BuildMutators(m)
923		}
924		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
925		ctx.RegisterForBazelConversion()
926
927		_, errs := ctx.ParseFileList(dir, toParse)
928		if Errored(t, testCase.description, errs) {
929			continue
930		}
931		_, errs = ctx.ResolveDependencies(config)
932		if Errored(t, testCase.description, errs) {
933			continue
934		}
935
936		checkDir := dir
937		if testCase.dir != "" {
938			checkDir = testCase.dir
939		}
940
941		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
942		bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
943		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
944			t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
945		} else {
946			for i, target := range bazelTargets {
947				if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
948					t.Errorf(
949						"%s: Expected generated Bazel target to be '%s', got '%s'",
950						testCase.description,
951						w,
952						g,
953					)
954				}
955			}
956		}
957	}
958}
959
960func Errored(t *testing.T, desc string, errs []error) bool {
961	t.Helper()
962	if len(errs) > 0 {
963		for _, err := range errs {
964			t.Errorf("%s: %s", desc, err)
965		}
966		return true
967	}
968	return false
969}
970
971type bp2buildMutator = func(android.TopDownMutatorContext)
972
973func TestBp2BuildInlinesDefaults(t *testing.T) {
974	testCases := []struct {
975		moduleTypesUnderTest      map[string]android.ModuleFactory
976		bp2buildMutatorsUnderTest map[string]bp2buildMutator
977		bp                        string
978		expectedBazelTarget       string
979		description               string
980	}{
981		{
982			moduleTypesUnderTest: map[string]android.ModuleFactory{
983				"genrule":          genrule.GenRuleFactory,
984				"genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
985			},
986			bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
987				"genrule": genrule.GenruleBp2Build,
988			},
989			bp: `genrule_defaults {
990    name: "gen_defaults",
991    cmd: "do-something $(in) $(out)",
992}
993genrule {
994    name: "gen",
995    out: ["out"],
996    srcs: ["in1"],
997    defaults: ["gen_defaults"],
998    bazel_module: { bp2build_available: true },
999}
1000`,
1001			expectedBazelTarget: `genrule(
1002    name = "gen",
1003    cmd = "do-something $(SRCS) $(OUTS)",
1004    outs = ["out"],
1005    srcs = ["in1"],
1006)`,
1007			description: "genrule applies properties from a genrule_defaults dependency if not specified",
1008		},
1009		{
1010			moduleTypesUnderTest: map[string]android.ModuleFactory{
1011				"genrule":          genrule.GenRuleFactory,
1012				"genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
1013			},
1014			bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
1015				"genrule": genrule.GenruleBp2Build,
1016			},
1017			bp: `genrule_defaults {
1018    name: "gen_defaults",
1019    out: ["out-from-defaults"],
1020    srcs: ["in-from-defaults"],
1021    cmd: "cmd-from-defaults",
1022}
1023genrule {
1024    name: "gen",
1025    out: ["out"],
1026    srcs: ["in1"],
1027    defaults: ["gen_defaults"],
1028    cmd: "do-something $(in) $(out)",
1029    bazel_module: { bp2build_available: true },
1030}
1031`,
1032			expectedBazelTarget: `genrule(
1033    name = "gen",
1034    cmd = "do-something $(SRCS) $(OUTS)",
1035    outs = [
1036        "out-from-defaults",
1037        "out",
1038    ],
1039    srcs = [
1040        "in-from-defaults",
1041        "in1",
1042    ],
1043)`,
1044			description: "genrule does merges properties from a genrule_defaults dependency, latest-first",
1045		},
1046		{
1047			moduleTypesUnderTest: map[string]android.ModuleFactory{
1048				"genrule":          genrule.GenRuleFactory,
1049				"genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
1050			},
1051			bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
1052				"genrule": genrule.GenruleBp2Build,
1053			},
1054			bp: `genrule_defaults {
1055    name: "gen_defaults1",
1056    cmd: "cp $(in) $(out)",
1057}
1058
1059genrule_defaults {
1060    name: "gen_defaults2",
1061    srcs: ["in1"],
1062}
1063
1064genrule {
1065    name: "gen",
1066    out: ["out"],
1067    defaults: ["gen_defaults1", "gen_defaults2"],
1068    bazel_module: { bp2build_available: true },
1069}
1070`,
1071			expectedBazelTarget: `genrule(
1072    name = "gen",
1073    cmd = "cp $(SRCS) $(OUTS)",
1074    outs = ["out"],
1075    srcs = ["in1"],
1076)`,
1077			description: "genrule applies properties from list of genrule_defaults",
1078		},
1079		{
1080			moduleTypesUnderTest: map[string]android.ModuleFactory{
1081				"genrule":          genrule.GenRuleFactory,
1082				"genrule_defaults": func() android.Module { return genrule.DefaultsFactory() },
1083			},
1084			bp2buildMutatorsUnderTest: map[string]bp2buildMutator{
1085				"genrule": genrule.GenruleBp2Build,
1086			},
1087			bp: `genrule_defaults {
1088    name: "gen_defaults1",
1089    defaults: ["gen_defaults2"],
1090    cmd: "cmd1 $(in) $(out)", // overrides gen_defaults2's cmd property value.
1091}
1092
1093genrule_defaults {
1094    name: "gen_defaults2",
1095    defaults: ["gen_defaults3"],
1096    cmd: "cmd2 $(in) $(out)",
1097    out: ["out-from-2"],
1098    srcs: ["in1"],
1099}
1100
1101genrule_defaults {
1102    name: "gen_defaults3",
1103    out: ["out-from-3"],
1104    srcs: ["srcs-from-3"],
1105}
1106
1107genrule {
1108    name: "gen",
1109    out: ["out"],
1110    defaults: ["gen_defaults1"],
1111    bazel_module: { bp2build_available: true },
1112}
1113`,
1114			expectedBazelTarget: `genrule(
1115    name = "gen",
1116    cmd = "cmd1 $(SRCS) $(OUTS)",
1117    outs = [
1118        "out-from-3",
1119        "out-from-2",
1120        "out",
1121    ],
1122    srcs = [
1123        "in1",
1124        "srcs-from-3",
1125    ],
1126)`,
1127			description: "genrule applies properties from genrule_defaults transitively",
1128		},
1129	}
1130
1131	dir := "."
1132	for _, testCase := range testCases {
1133		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
1134		ctx := android.NewTestContext(config)
1135		for m, factory := range testCase.moduleTypesUnderTest {
1136			ctx.RegisterModuleType(m, factory)
1137		}
1138		for mutator, f := range testCase.bp2buildMutatorsUnderTest {
1139			ctx.RegisterBp2BuildMutator(mutator, f)
1140		}
1141		ctx.RegisterForBazelConversion()
1142
1143		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
1144		android.FailIfErrored(t, errs)
1145		_, errs = ctx.ResolveDependencies(config)
1146		android.FailIfErrored(t, errs)
1147
1148		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
1149		bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
1150		if actualCount := len(bazelTargets); actualCount != 1 {
1151			t.Fatalf("%s: Expected 1 bazel target, got %d", testCase.description, actualCount)
1152		}
1153
1154		actualBazelTarget := bazelTargets[0]
1155		if actualBazelTarget.content != testCase.expectedBazelTarget {
1156			t.Errorf(
1157				"%s: Expected generated Bazel target to be '%s', got '%s'",
1158				testCase.description,
1159				testCase.expectedBazelTarget,
1160				actualBazelTarget.content,
1161			)
1162		}
1163	}
1164}
1165
1166func TestAllowlistingBp2buildTargetsExplicitly(t *testing.T) {
1167	testCases := []struct {
1168		moduleTypeUnderTest                string
1169		moduleTypeUnderTestFactory         android.ModuleFactory
1170		moduleTypeUnderTestBp2BuildMutator bp2buildMutator
1171		bp                                 string
1172		expectedCount                      int
1173		description                        string
1174	}{
1175		{
1176			description:                        "explicitly unavailable",
1177			moduleTypeUnderTest:                "filegroup",
1178			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1179			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1180			bp: `filegroup {
1181    name: "foo",
1182    srcs: ["a", "b"],
1183    bazel_module: { bp2build_available: false },
1184}`,
1185			expectedCount: 0,
1186		},
1187		{
1188			description:                        "implicitly unavailable",
1189			moduleTypeUnderTest:                "filegroup",
1190			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1191			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1192			bp: `filegroup {
1193    name: "foo",
1194    srcs: ["a", "b"],
1195}`,
1196			expectedCount: 0,
1197		},
1198		{
1199			description:                        "explicitly available",
1200			moduleTypeUnderTest:                "filegroup",
1201			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1202			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1203			bp: `filegroup {
1204    name: "foo",
1205    srcs: ["a", "b"],
1206    bazel_module: { bp2build_available: true },
1207}`,
1208			expectedCount: 1,
1209		},
1210		{
1211			description:                        "generates more than 1 target if needed",
1212			moduleTypeUnderTest:                "custom",
1213			moduleTypeUnderTestFactory:         customModuleFactory,
1214			moduleTypeUnderTestBp2BuildMutator: customBp2BuildMutatorFromStarlark,
1215			bp: `custom {
1216    name: "foo",
1217    bazel_module: { bp2build_available: true },
1218}`,
1219			expectedCount: 3,
1220		},
1221	}
1222
1223	dir := "."
1224	for _, testCase := range testCases {
1225		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
1226		ctx := android.NewTestContext(config)
1227		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
1228		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
1229		ctx.RegisterForBazelConversion()
1230
1231		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
1232		android.FailIfErrored(t, errs)
1233		_, errs = ctx.ResolveDependencies(config)
1234		android.FailIfErrored(t, errs)
1235
1236		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
1237		bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
1238		if actualCount := len(bazelTargets); actualCount != testCase.expectedCount {
1239			t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, testCase.expectedCount, actualCount)
1240		}
1241	}
1242}
1243
1244func TestAllowlistingBp2buildTargetsWithConfig(t *testing.T) {
1245	testCases := []struct {
1246		moduleTypeUnderTest                string
1247		moduleTypeUnderTestFactory         android.ModuleFactory
1248		moduleTypeUnderTestBp2BuildMutator bp2buildMutator
1249		expectedCount                      map[string]int
1250		description                        string
1251		bp2buildConfig                     android.Bp2BuildConfig
1252		checkDir                           string
1253		fs                                 map[string]string
1254	}{
1255		{
1256			description:                        "test bp2build config package and subpackages config",
1257			moduleTypeUnderTest:                "filegroup",
1258			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1259			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1260			expectedCount: map[string]int{
1261				"migrated":                           1,
1262				"migrated/but_not_really":            0,
1263				"migrated/but_not_really/but_really": 1,
1264				"not_migrated":                       0,
1265				"also_not_migrated":                  0,
1266			},
1267			bp2buildConfig: android.Bp2BuildConfig{
1268				"migrated":                android.Bp2BuildDefaultTrueRecursively,
1269				"migrated/but_not_really": android.Bp2BuildDefaultFalse,
1270				"not_migrated":            android.Bp2BuildDefaultFalse,
1271			},
1272			fs: map[string]string{
1273				"migrated/Android.bp":                           `filegroup { name: "a" }`,
1274				"migrated/but_not_really/Android.bp":            `filegroup { name: "b" }`,
1275				"migrated/but_not_really/but_really/Android.bp": `filegroup { name: "c" }`,
1276				"not_migrated/Android.bp":                       `filegroup { name: "d" }`,
1277				"also_not_migrated/Android.bp":                  `filegroup { name: "e" }`,
1278			},
1279		},
1280		{
1281			description:                        "test bp2build config opt-in and opt-out",
1282			moduleTypeUnderTest:                "filegroup",
1283			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1284			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1285			expectedCount: map[string]int{
1286				"package-opt-in":             2,
1287				"package-opt-in/subpackage":  0,
1288				"package-opt-out":            1,
1289				"package-opt-out/subpackage": 0,
1290			},
1291			bp2buildConfig: android.Bp2BuildConfig{
1292				"package-opt-in":  android.Bp2BuildDefaultFalse,
1293				"package-opt-out": android.Bp2BuildDefaultTrueRecursively,
1294			},
1295			fs: map[string]string{
1296				"package-opt-in/Android.bp": `
1297filegroup { name: "opt-in-a" }
1298filegroup { name: "opt-in-b", bazel_module: { bp2build_available: true } }
1299filegroup { name: "opt-in-c", bazel_module: { bp2build_available: true } }
1300`,
1301
1302				"package-opt-in/subpackage/Android.bp": `
1303filegroup { name: "opt-in-d" } // parent package not configured to DefaultTrueRecursively
1304`,
1305
1306				"package-opt-out/Android.bp": `
1307filegroup { name: "opt-out-a" }
1308filegroup { name: "opt-out-b", bazel_module: { bp2build_available: false } }
1309filegroup { name: "opt-out-c", bazel_module: { bp2build_available: false } }
1310`,
1311
1312				"package-opt-out/subpackage/Android.bp": `
1313filegroup { name: "opt-out-g", bazel_module: { bp2build_available: false } }
1314filegroup { name: "opt-out-h", bazel_module: { bp2build_available: false } }
1315`,
1316			},
1317		},
1318	}
1319
1320	dir := "."
1321	for _, testCase := range testCases {
1322		fs := make(map[string][]byte)
1323		toParse := []string{
1324			"Android.bp",
1325		}
1326		for f, content := range testCase.fs {
1327			if strings.HasSuffix(f, "Android.bp") {
1328				toParse = append(toParse, f)
1329			}
1330			fs[f] = []byte(content)
1331		}
1332		config := android.TestConfig(buildDir, nil, "", fs)
1333		ctx := android.NewTestContext(config)
1334		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
1335		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
1336		ctx.RegisterBp2BuildConfig(testCase.bp2buildConfig)
1337		ctx.RegisterForBazelConversion()
1338
1339		_, errs := ctx.ParseFileList(dir, toParse)
1340		android.FailIfErrored(t, errs)
1341		_, errs = ctx.ResolveDependencies(config)
1342		android.FailIfErrored(t, errs)
1343
1344		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
1345
1346		// For each directory, test that the expected number of generated targets is correct.
1347		for dir, expectedCount := range testCase.expectedCount {
1348			bazelTargets := generateBazelTargetsForDir(codegenCtx, dir)
1349			if actualCount := len(bazelTargets); actualCount != expectedCount {
1350				t.Fatalf(
1351					"%s: Expected %d bazel target for %s package, got %d",
1352					testCase.description,
1353					expectedCount,
1354					dir,
1355					actualCount)
1356			}
1357
1358		}
1359	}
1360}
1361
1362func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
1363	testCases := []struct {
1364		description                        string
1365		moduleTypeUnderTest                string
1366		moduleTypeUnderTestFactory         android.ModuleFactory
1367		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
1368		preArchMutators                    []android.RegisterMutatorFunc
1369		depsMutators                       []android.RegisterMutatorFunc
1370		bp                                 string
1371		expectedBazelTargets               []string
1372		fs                                 map[string]string
1373		dir                                string
1374	}{
1375		{
1376			description:                        "filegroup bazel_module.label",
1377			moduleTypeUnderTest:                "filegroup",
1378			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1379			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1380			bp: `filegroup {
1381    name: "fg_foo",
1382    bazel_module: { label: "//other:fg_foo" },
1383}`,
1384			expectedBazelTargets: []string{
1385				`// BUILD file`,
1386			},
1387			fs: map[string]string{
1388				"other/BUILD.bazel": `// BUILD file`,
1389			},
1390		},
1391		{
1392			description:                        "multiple bazel_module.label same BUILD",
1393			moduleTypeUnderTest:                "filegroup",
1394			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1395			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1396			bp: `filegroup {
1397    name: "fg_foo",
1398    bazel_module: { label: "//other:fg_foo" },
1399}
1400
1401filegroup {
1402    name: "foo",
1403    bazel_module: { label: "//other:foo" },
1404}`,
1405			expectedBazelTargets: []string{
1406				`// BUILD file`,
1407			},
1408			fs: map[string]string{
1409				"other/BUILD.bazel": `// BUILD file`,
1410			},
1411		},
1412		{
1413			description:                        "filegroup bazel_module.label and bp2build",
1414			moduleTypeUnderTest:                "filegroup",
1415			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1416			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1417			bp: `filegroup {
1418    name: "fg_foo",
1419    bazel_module: {
1420      label: "//other:fg_foo",
1421      bp2build_available: true,
1422    },
1423}`,
1424			expectedBazelTargets: []string{
1425				`filegroup(
1426    name = "fg_foo",
1427)`,
1428				`// BUILD file`,
1429			},
1430			fs: map[string]string{
1431				"other/BUILD.bazel": `// BUILD file`,
1432			},
1433		},
1434		{
1435			description:                        "filegroup bazel_module.label and filegroup bp2build",
1436			moduleTypeUnderTest:                "filegroup",
1437			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1438			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1439			bp: `filegroup {
1440    name: "fg_foo",
1441    bazel_module: {
1442      label: "//other:fg_foo",
1443    },
1444}
1445
1446filegroup {
1447    name: "fg_bar",
1448    bazel_module: {
1449      bp2build_available: true,
1450    },
1451}`,
1452			expectedBazelTargets: []string{
1453				`filegroup(
1454    name = "fg_bar",
1455)`,
1456				`// BUILD file`,
1457			},
1458			fs: map[string]string{
1459				"other/BUILD.bazel": `// BUILD file`,
1460			},
1461		},
1462	}
1463
1464	dir := "."
1465	for _, testCase := range testCases {
1466		fs := make(map[string][]byte)
1467		toParse := []string{
1468			"Android.bp",
1469		}
1470		for f, content := range testCase.fs {
1471			if strings.HasSuffix(f, "Android.bp") {
1472				toParse = append(toParse, f)
1473			}
1474			fs[f] = []byte(content)
1475		}
1476		config := android.TestConfig(buildDir, nil, testCase.bp, fs)
1477		ctx := android.NewTestContext(config)
1478		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
1479		for _, m := range testCase.depsMutators {
1480			ctx.DepsBp2BuildMutators(m)
1481		}
1482		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
1483		ctx.RegisterForBazelConversion()
1484
1485		_, errs := ctx.ParseFileList(dir, toParse)
1486		if Errored(t, testCase.description, errs) {
1487			continue
1488		}
1489		_, errs = ctx.ResolveDependencies(config)
1490		if Errored(t, testCase.description, errs) {
1491			continue
1492		}
1493
1494		checkDir := dir
1495		if testCase.dir != "" {
1496			checkDir = testCase.dir
1497		}
1498		bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir)
1499		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
1500			t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets)
1501		} else {
1502			for i, target := range bazelTargets {
1503				if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
1504					t.Errorf(
1505						"%s: Expected generated Bazel target to be '%s', got '%s'",
1506						testCase.description,
1507						w,
1508						g,
1509					)
1510				}
1511			}
1512		}
1513	}
1514}
1515
1516func TestGlobExcludeSrcs(t *testing.T) {
1517	testCases := []struct {
1518		description                        string
1519		moduleTypeUnderTest                string
1520		moduleTypeUnderTestFactory         android.ModuleFactory
1521		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
1522		bp                                 string
1523		expectedBazelTargets               []string
1524		fs                                 map[string]string
1525		dir                                string
1526	}{
1527		{
1528			description:                        "filegroup top level exclude_srcs",
1529			moduleTypeUnderTest:                "filegroup",
1530			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1531			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1532			bp: `filegroup {
1533    name: "fg_foo",
1534    srcs: ["**/*.txt"],
1535    exclude_srcs: ["c.txt"],
1536    bazel_module: { bp2build_available: true },
1537}`,
1538			expectedBazelTargets: []string{`filegroup(
1539    name = "fg_foo",
1540    srcs = [
1541        "//dir:e.txt",
1542        "//dir:f.txt",
1543        "a.txt",
1544        "b.txt",
1545    ],
1546)`,
1547			},
1548			fs: map[string]string{
1549				"a.txt":          "",
1550				"b.txt":          "",
1551				"c.txt":          "",
1552				"dir/Android.bp": "",
1553				"dir/e.txt":      "",
1554				"dir/f.txt":      "",
1555			},
1556		},
1557		{
1558			description:                        "filegroup in subdir exclude_srcs",
1559			moduleTypeUnderTest:                "filegroup",
1560			moduleTypeUnderTestFactory:         android.FileGroupFactory,
1561			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
1562			bp:                                 "",
1563			dir:                                "dir",
1564			fs: map[string]string{
1565				"dir/Android.bp": `filegroup {
1566    name: "fg_foo",
1567    srcs: ["**/*.txt"],
1568    exclude_srcs: ["b.txt"],
1569    bazel_module: { bp2build_available: true },
1570}
1571`,
1572				"dir/a.txt":             "",
1573				"dir/b.txt":             "",
1574				"dir/subdir/Android.bp": "",
1575				"dir/subdir/e.txt":      "",
1576				"dir/subdir/f.txt":      "",
1577			},
1578			expectedBazelTargets: []string{`filegroup(
1579    name = "fg_foo",
1580    srcs = [
1581        "//dir/subdir:e.txt",
1582        "//dir/subdir:f.txt",
1583        "a.txt",
1584    ],
1585)`,
1586			},
1587		},
1588	}
1589
1590	dir := "."
1591	for _, testCase := range testCases {
1592		fs := make(map[string][]byte)
1593		toParse := []string{
1594			"Android.bp",
1595		}
1596		for f, content := range testCase.fs {
1597			if strings.HasSuffix(f, "Android.bp") {
1598				toParse = append(toParse, f)
1599			}
1600			fs[f] = []byte(content)
1601		}
1602		config := android.TestConfig(buildDir, nil, testCase.bp, fs)
1603		ctx := android.NewTestContext(config)
1604		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
1605		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
1606		ctx.RegisterForBazelConversion()
1607
1608		_, errs := ctx.ParseFileList(dir, toParse)
1609		if Errored(t, testCase.description, errs) {
1610			continue
1611		}
1612		_, errs = ctx.ResolveDependencies(config)
1613		if Errored(t, testCase.description, errs) {
1614			continue
1615		}
1616
1617		checkDir := dir
1618		if testCase.dir != "" {
1619			checkDir = testCase.dir
1620		}
1621		bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir)
1622		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
1623			t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets)
1624		} else {
1625			for i, target := range bazelTargets {
1626				if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
1627					t.Errorf(
1628						"%s: Expected generated Bazel target to be '%s', got '%s'",
1629						testCase.description,
1630						w,
1631						g,
1632					)
1633				}
1634			}
1635		}
1636	}
1637}
1638