1// Copyright 2017 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 java
16
17import (
18	"fmt"
19	"os"
20	"path/filepath"
21	"reflect"
22	"runtime"
23	"strconv"
24	"strings"
25	"testing"
26
27	"github.com/google/blueprint/proptools"
28
29	"android/soong/android"
30	"android/soong/cc"
31	"android/soong/dexpreopt"
32	"android/soong/genrule"
33	"android/soong/python"
34)
35
36// Legacy preparer used for running tests within the java package.
37//
38// This includes everything that was needed to run any test in the java package prior to the
39// introduction of the test fixtures. Tests that are being converted to use fixtures directly
40// rather than through the testJava...() methods should avoid using this and instead use the
41// various preparers directly, using android.GroupFixturePreparers(...) to group them when
42// necessary.
43//
44// deprecated
45var prepareForJavaTest = android.GroupFixturePreparers(
46	genrule.PrepareForTestWithGenRuleBuildComponents,
47	// Get the CC build components but not default modules.
48	cc.PrepareForTestWithCcBuildComponents,
49	// Include all the default java modules.
50	PrepareForTestWithJavaDefaultModules,
51	PrepareForTestWithOverlayBuildComponents,
52	python.PrepareForTestWithPythonBuildComponents,
53	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
54		ctx.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
55	}),
56	PrepareForTestWithDexpreopt,
57)
58
59func TestMain(m *testing.M) {
60	os.Exit(m.Run())
61}
62
63// testJavaError is a legacy way of running tests of java modules that expect errors.
64//
65// See testJava for an explanation as to how to stop using this deprecated method.
66//
67// deprecated
68func testJavaError(t *testing.T, pattern string, bp string) (*android.TestContext, android.Config) {
69	t.Helper()
70	result := android.GroupFixturePreparers(
71		prepareForJavaTest, dexpreopt.PrepareForTestByEnablingDexpreopt).
72		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
73		RunTestWithBp(t, bp)
74	return result.TestContext, result.Config
75}
76
77// testJavaWithFS runs tests using the prepareForJavaTest
78//
79// See testJava for an explanation as to how to stop using this deprecated method.
80//
81// deprecated
82func testJavaWithFS(t *testing.T, bp string, fs android.MockFS) (*android.TestContext, android.Config) {
83	t.Helper()
84	result := android.GroupFixturePreparers(
85		prepareForJavaTest, fs.AddToFixture()).RunTestWithBp(t, bp)
86	return result.TestContext, result.Config
87}
88
89// testJava runs tests using the prepareForJavaTest
90//
91// Do not add any new usages of this, instead use the prepareForJavaTest directly as it makes it
92// much easier to customize the test behavior.
93//
94// If it is necessary to customize the behavior of an existing test that uses this then please first
95// convert the test to using prepareForJavaTest first and then in a following change add the
96// appropriate fixture preparers. Keeping the conversion change separate makes it easy to verify
97// that it did not change the test behavior unexpectedly.
98//
99// deprecated
100func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) {
101	t.Helper()
102	result := prepareForJavaTest.RunTestWithBp(t, bp)
103	return result.TestContext, result.Config
104}
105
106// defaultModuleToPath constructs a path to the turbine generate jar for a default test module that
107// is defined in PrepareForIntegrationTestWithJava
108func defaultModuleToPath(name string) string {
109	switch {
110	case name == `""`:
111		return name
112	case strings.HasSuffix(name, ".jar"):
113		return name
114	default:
115		return filepath.Join("out", "soong", ".intermediates", defaultJavaDir, name, "android_common", "turbine-combined", name+".jar")
116	}
117}
118
119// Test that the PrepareForTestWithJavaDefaultModules provides all the files that it uses by
120// running it in a fixture that requires all source files to exist.
121func TestPrepareForTestWithJavaDefaultModules(t *testing.T) {
122	android.GroupFixturePreparers(
123		PrepareForTestWithJavaDefaultModules,
124		android.PrepareForTestDisallowNonExistentPaths,
125	).RunTest(t)
126}
127
128func TestJavaLinkType(t *testing.T) {
129	testJava(t, `
130		java_library {
131			name: "foo",
132			srcs: ["a.java"],
133			libs: ["bar"],
134			static_libs: ["baz"],
135		}
136
137		java_library {
138			name: "bar",
139			sdk_version: "current",
140			srcs: ["b.java"],
141		}
142
143		java_library {
144			name: "baz",
145			sdk_version: "system_current",
146			srcs: ["c.java"],
147		}
148	`)
149
150	testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
151		java_library {
152			name: "foo",
153			srcs: ["a.java"],
154			libs: ["bar"],
155			sdk_version: "current",
156			static_libs: ["baz"],
157		}
158
159		java_library {
160			name: "bar",
161			sdk_version: "current",
162			srcs: ["b.java"],
163		}
164
165		java_library {
166			name: "baz",
167			sdk_version: "system_current",
168			srcs: ["c.java"],
169		}
170	`)
171
172	testJava(t, `
173		java_library {
174			name: "foo",
175			srcs: ["a.java"],
176			libs: ["bar"],
177			sdk_version: "system_current",
178			static_libs: ["baz"],
179		}
180
181		java_library {
182			name: "bar",
183			sdk_version: "current",
184			srcs: ["b.java"],
185		}
186
187		java_library {
188			name: "baz",
189			sdk_version: "system_current",
190			srcs: ["c.java"],
191		}
192	`)
193
194	testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", `
195		java_library {
196			name: "foo",
197			srcs: ["a.java"],
198			libs: ["bar"],
199			sdk_version: "system_current",
200			static_libs: ["baz"],
201		}
202
203		java_library {
204			name: "bar",
205			sdk_version: "current",
206			srcs: ["b.java"],
207		}
208
209		java_library {
210			name: "baz",
211			srcs: ["c.java"],
212		}
213	`)
214}
215
216func TestSimple(t *testing.T) {
217	ctx, _ := testJava(t, `
218		java_library {
219			name: "foo",
220			srcs: ["a.java"],
221			libs: ["bar"],
222			static_libs: ["baz"],
223		}
224
225		java_library {
226			name: "bar",
227			srcs: ["b.java"],
228		}
229
230		java_library {
231			name: "baz",
232			srcs: ["c.java"],
233		}
234	`)
235
236	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
237	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
238
239	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
240		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
241	}
242
243	baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
244	barTurbine := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
245	bazTurbine := filepath.Join("out", "soong", ".intermediates", "baz", "android_common", "turbine-combined", "baz.jar")
246
247	android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barTurbine)
248
249	android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazTurbine)
250
251	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
252		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
253	}
254}
255
256func TestExportedPlugins(t *testing.T) {
257	type Result struct {
258		library        string
259		processors     string
260		disableTurbine bool
261	}
262	var tests = []struct {
263		name    string
264		extra   string
265		results []Result
266	}{
267		{
268			name:    "Exported plugin is not a direct plugin",
269			extra:   `java_library { name: "exports", srcs: ["a.java"], exported_plugins: ["plugin"] }`,
270			results: []Result{{library: "exports", processors: "-proc:none"}},
271		},
272		{
273			name: "Exports plugin to dependee",
274			extra: `
275				java_library{name: "exports", exported_plugins: ["plugin"]}
276				java_library{name: "foo", srcs: ["a.java"], libs: ["exports"]}
277				java_library{name: "bar", srcs: ["a.java"], static_libs: ["exports"]}
278			`,
279			results: []Result{
280				{library: "foo", processors: "-processor com.android.TestPlugin"},
281				{library: "bar", processors: "-processor com.android.TestPlugin"},
282			},
283		},
284		{
285			name: "Exports plugin to android_library",
286			extra: `
287				java_library{name: "exports", exported_plugins: ["plugin"]}
288				android_library{name: "foo", srcs: ["a.java"],  libs: ["exports"]}
289				android_library{name: "bar", srcs: ["a.java"], static_libs: ["exports"]}
290			`,
291			results: []Result{
292				{library: "foo", processors: "-processor com.android.TestPlugin"},
293				{library: "bar", processors: "-processor com.android.TestPlugin"},
294			},
295		},
296		{
297			name: "Exports plugin is not propagated via transitive deps",
298			extra: `
299				java_library{name: "exports", exported_plugins: ["plugin"]}
300				java_library{name: "foo", srcs: ["a.java"], libs: ["exports"]}
301				java_library{name: "bar", srcs: ["a.java"], static_libs: ["foo"]}
302			`,
303			results: []Result{
304				{library: "foo", processors: "-processor com.android.TestPlugin"},
305				{library: "bar", processors: "-proc:none"},
306			},
307		},
308		{
309			name: "Exports plugin appends to plugins",
310			extra: `
311                java_plugin{name: "plugin2", processor_class: "com.android.TestPlugin2"}
312				java_library{name: "exports", exported_plugins: ["plugin"]}
313				java_library{name: "foo", srcs: ["a.java"], libs: ["exports"], plugins: ["plugin2"]}
314			`,
315			results: []Result{
316				{library: "foo", processors: "-processor com.android.TestPlugin,com.android.TestPlugin2"},
317			},
318		},
319		{
320			name: "Exports plugin to with generates_api to dependee",
321			extra: `
322				java_library{name: "exports", exported_plugins: ["plugin_generates_api"]}
323				java_library{name: "foo", srcs: ["a.java"], libs: ["exports"]}
324				java_library{name: "bar", srcs: ["a.java"], static_libs: ["exports"]}
325			`,
326			results: []Result{
327				{library: "foo", processors: "-processor com.android.TestPlugin", disableTurbine: true},
328				{library: "bar", processors: "-processor com.android.TestPlugin", disableTurbine: true},
329			},
330		},
331	}
332
333	for _, test := range tests {
334		t.Run(test.name, func(t *testing.T) {
335			ctx, _ := testJava(t, `
336				java_plugin {
337					name: "plugin",
338					processor_class: "com.android.TestPlugin",
339				}
340				java_plugin {
341					name: "plugin_generates_api",
342					generates_api: true,
343					processor_class: "com.android.TestPlugin",
344				}
345			`+test.extra)
346
347			for _, want := range test.results {
348				javac := ctx.ModuleForTests(want.library, "android_common").Rule("javac")
349				if javac.Args["processor"] != want.processors {
350					t.Errorf("For library %v, expected %v, found %v", want.library, want.processors, javac.Args["processor"])
351				}
352				turbine := ctx.ModuleForTests(want.library, "android_common").MaybeRule("turbine")
353				disableTurbine := turbine.BuildParams.Rule == nil
354				if disableTurbine != want.disableTurbine {
355					t.Errorf("For library %v, expected disableTurbine %v, found %v", want.library, want.disableTurbine, disableTurbine)
356				}
357			}
358		})
359	}
360}
361
362func TestSdkVersionByPartition(t *testing.T) {
363	testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", `
364		java_library {
365			name: "foo",
366			srcs: ["a.java"],
367			vendor: true,
368		}
369	`)
370
371	testJava(t, `
372		java_library {
373			name: "bar",
374			srcs: ["b.java"],
375		}
376	`)
377
378	for _, enforce := range []bool{true, false} {
379		bp := `
380			java_library {
381				name: "foo",
382				srcs: ["a.java"],
383				product_specific: true,
384			}
385		`
386
387		errorHandler := android.FixtureExpectsNoErrors
388		if enforce {
389			errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern("sdk_version must have a value when the module is located at vendor or product")
390		}
391
392		android.GroupFixturePreparers(
393			PrepareForTestWithJavaDefaultModules,
394			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
395				variables.EnforceProductPartitionInterface = proptools.BoolPtr(enforce)
396			}),
397		).
398			ExtendWithErrorHandler(errorHandler).
399			RunTestWithBp(t, bp)
400	}
401}
402
403func TestArchSpecific(t *testing.T) {
404	ctx, _ := testJava(t, `
405		java_library {
406			name: "foo",
407			srcs: ["a.java"],
408			target: {
409				android: {
410					srcs: ["b.java"],
411				},
412			},
413		}
414	`)
415
416	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
417	if len(javac.Inputs) != 2 || javac.Inputs[0].String() != "a.java" || javac.Inputs[1].String() != "b.java" {
418		t.Errorf(`foo inputs %v != ["a.java", "b.java"]`, javac.Inputs)
419	}
420}
421
422func TestBinary(t *testing.T) {
423	ctx, _ := testJava(t, `
424		java_library_host {
425			name: "foo",
426			srcs: ["a.java"],
427		}
428
429		java_binary_host {
430			name: "bar",
431			srcs: ["b.java"],
432			static_libs: ["foo"],
433			jni_libs: ["libjni"],
434		}
435
436		cc_library_shared {
437			name: "libjni",
438			host_supported: true,
439			device_supported: false,
440			stl: "none",
441		}
442	`)
443
444	buildOS := android.BuildOs.String()
445
446	bar := ctx.ModuleForTests("bar", buildOS+"_common")
447	barJar := bar.Output("bar.jar").Output.String()
448	barWrapper := ctx.ModuleForTests("bar", buildOS+"_x86_64")
449	barWrapperDeps := barWrapper.Output("bar").Implicits.Strings()
450
451	libjni := ctx.ModuleForTests("libjni", buildOS+"_x86_64_shared")
452	libjniSO := libjni.Rule("Cp").Output.String()
453
454	// Test that the install binary wrapper depends on the installed jar file
455	if g, w := barWrapperDeps, barJar; !android.InList(w, g) {
456		t.Errorf("expected binary wrapper implicits to contain %q, got %q", w, g)
457	}
458
459	// Test that the install binary wrapper depends on the installed JNI libraries
460	if g, w := barWrapperDeps, libjniSO; !android.InList(w, g) {
461		t.Errorf("expected binary wrapper implicits to contain %q, got %q", w, g)
462	}
463}
464
465func TestTest(t *testing.T) {
466	ctx, _ := testJava(t, `
467		java_test_host {
468			name: "foo",
469			srcs: ["a.java"],
470			jni_libs: ["libjni"],
471		}
472
473		cc_library_shared {
474			name: "libjni",
475			host_supported: true,
476			device_supported: false,
477			stl: "none",
478		}
479	`)
480
481	buildOS := android.BuildOs.String()
482
483	foo := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
484
485	expected := "lib64/libjni.so"
486	if runtime.GOOS == "darwin" {
487		expected = "lib64/libjni.dylib"
488	}
489
490	fooTestData := foo.data
491	if len(fooTestData) != 1 || fooTestData[0].Rel() != expected {
492		t.Errorf(`expected foo test data relative path [%q], got %q`,
493			expected, fooTestData.Strings())
494	}
495}
496
497func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) {
498	bp := `
499		java_library {
500			name: "target_library",
501			srcs: ["a.java"],
502		}
503
504		java_binary_host {
505			name: "host_binary",
506			srcs: ["b.java"],
507		}
508	`
509
510	result := android.GroupFixturePreparers(
511		PrepareForTestWithJavaDefaultModules,
512		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
513			variables.MinimizeJavaDebugInfo = proptools.BoolPtr(true)
514		}),
515	).RunTestWithBp(t, bp)
516
517	// first, check that the -g flag is added to target modules
518	targetLibrary := result.ModuleForTests("target_library", "android_common")
519	targetJavaFlags := targetLibrary.Module().VariablesForTests()["javacFlags"]
520	if !strings.Contains(targetJavaFlags, "-g:source,lines") {
521		t.Errorf("target library javac flags %v should contain "+
522			"-g:source,lines override with MinimizeJavaDebugInfo", targetJavaFlags)
523	}
524
525	// check that -g is not overridden for host modules
526	buildOS := android.BuildOs.String()
527	hostBinary := result.ModuleForTests("host_binary", buildOS+"_common")
528	hostJavaFlags := hostBinary.Module().VariablesForTests()["javacFlags"]
529	if strings.Contains(hostJavaFlags, "-g:source,lines") {
530		t.Errorf("java_binary_host javac flags %v should not have "+
531			"-g:source,lines override with MinimizeJavaDebugInfo", hostJavaFlags)
532	}
533}
534
535func TestPrebuilts(t *testing.T) {
536	ctx, _ := testJava(t, `
537		java_library {
538			name: "foo",
539			srcs: ["a.java", ":stubs-source"],
540			libs: ["bar", "sdklib"],
541			static_libs: ["baz"],
542		}
543
544		java_import {
545			name: "bar",
546			jars: ["a.jar"],
547		}
548
549		java_import {
550			name: "baz",
551			jars: ["b.jar"],
552			sdk_version: "current",
553			compile_dex: true,
554		}
555
556		dex_import {
557			name: "qux",
558			jars: ["b.jar"],
559		}
560
561		java_sdk_library_import {
562			name: "sdklib",
563			public: {
564				jars: ["c.jar"],
565			},
566		}
567
568		prebuilt_stubs_sources {
569			name: "stubs-source",
570			srcs: ["stubs/sources"],
571		}
572
573		java_test_import {
574			name: "test",
575			jars: ["a.jar"],
576			test_suites: ["cts"],
577			test_config: "AndroidTest.xml",
578		}
579		`)
580
581	fooModule := ctx.ModuleForTests("foo", "android_common")
582	javac := fooModule.Rule("javac")
583	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
584	barModule := ctx.ModuleForTests("bar", "android_common")
585	barJar := barModule.Rule("combineJar").Output
586	bazModule := ctx.ModuleForTests("baz", "android_common")
587	bazJar := bazModule.Rule("combineJar").Output
588	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
589
590	fooLibrary := fooModule.Module().(*Library)
591	assertDeepEquals(t, "foo java sources incorrect",
592		[]string{"a.java"}, fooLibrary.compiledJavaSrcs.Strings())
593
594	assertDeepEquals(t, "foo java source jars incorrect",
595		[]string{".intermediates/stubs-source/android_common/stubs-source-stubs.srcjar"},
596		android.NormalizePathsForTesting(fooLibrary.compiledSrcJars))
597
598	if !strings.Contains(javac.Args["classpath"], barJar.String()) {
599		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String())
600	}
601
602	barDexJar := barModule.Module().(*Import).DexJarBuildPath()
603	if barDexJar != nil {
604		t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar)
605	}
606
607	if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
608		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
609	}
610
611	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != bazJar.String() {
612		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String())
613	}
614
615	bazDexJar := bazModule.Module().(*Import).DexJarBuildPath()
616	expectedDexJar := "out/soong/.intermediates/baz/android_common/dex/baz.jar"
617	android.AssertPathRelativeToTopEquals(t, "baz dex jar build path", expectedDexJar, bazDexJar)
618
619	ctx.ModuleForTests("qux", "android_common").Rule("Cp")
620}
621
622func assertDeepEquals(t *testing.T, message string, expected interface{}, actual interface{}) {
623	if !reflect.DeepEqual(expected, actual) {
624		t.Errorf("%s: expected %q, found %q", message, expected, actual)
625	}
626}
627
628func TestPrebuiltStubsSources(t *testing.T) {
629	test := func(t *testing.T, sourcesPath string, expectedInputs []string) {
630		ctx, _ := testJavaWithFS(t, fmt.Sprintf(`
631prebuilt_stubs_sources {
632  name: "stubs-source",
633	srcs: ["%s"],
634}`, sourcesPath), map[string][]byte{
635			"stubs/sources/pkg/A.java": nil,
636			"stubs/sources/pkg/B.java": nil,
637		})
638
639		zipSrc := ctx.ModuleForTests("stubs-source", "android_common").Rule("zip_src")
640		if expected, actual := expectedInputs, zipSrc.Inputs.Strings(); !reflect.DeepEqual(expected, actual) {
641			t.Errorf("mismatch of inputs to soong_zip: expected %q, actual %q", expected, actual)
642		}
643	}
644
645	t.Run("empty/missing directory", func(t *testing.T) {
646		test(t, "empty-directory", nil)
647	})
648
649	t.Run("non-empty set of sources", func(t *testing.T) {
650		test(t, "stubs/sources", []string{
651			"stubs/sources/pkg/A.java",
652			"stubs/sources/pkg/B.java",
653		})
654	})
655}
656
657func TestDefaults(t *testing.T) {
658	ctx, _ := testJava(t, `
659		java_defaults {
660			name: "defaults",
661			srcs: ["a.java"],
662			libs: ["bar"],
663			static_libs: ["baz"],
664			optimize: {enabled: false},
665		}
666
667		java_library {
668			name: "foo",
669			defaults: ["defaults"],
670		}
671
672		java_library {
673			name: "bar",
674			srcs: ["b.java"],
675		}
676
677		java_library {
678			name: "baz",
679			srcs: ["c.java"],
680		}
681
682		android_test {
683			name: "atestOptimize",
684			defaults: ["defaults"],
685			optimize: {enabled: true},
686		}
687
688		android_test {
689			name: "atestNoOptimize",
690			defaults: ["defaults"],
691		}
692
693		android_test {
694			name: "atestDefault",
695			srcs: ["a.java"],
696		}
697		`)
698
699	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
700	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
701
702	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
703		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
704	}
705
706	barTurbine := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
707	if !strings.Contains(javac.Args["classpath"], barTurbine) {
708		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barTurbine)
709	}
710
711	baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
712	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
713		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
714	}
715
716	atestOptimize := ctx.ModuleForTests("atestOptimize", "android_common").MaybeRule("r8")
717	if atestOptimize.Output == nil {
718		t.Errorf("atestOptimize should optimize APK")
719	}
720
721	atestNoOptimize := ctx.ModuleForTests("atestNoOptimize", "android_common").MaybeRule("d8")
722	if atestNoOptimize.Output == nil {
723		t.Errorf("atestNoOptimize should not optimize APK")
724	}
725
726	atestDefault := ctx.ModuleForTests("atestDefault", "android_common").MaybeRule("r8")
727	if atestDefault.Output == nil {
728		t.Errorf("atestDefault should optimize APK")
729	}
730}
731
732func TestResources(t *testing.T) {
733	var table = []struct {
734		name  string
735		prop  string
736		extra string
737		args  string
738	}{
739		{
740			// Test that a module with java_resource_dirs includes the files
741			name: "resource dirs",
742			prop: `java_resource_dirs: ["java-res"]`,
743			args: "-C java-res -f java-res/a/a -f java-res/b/b",
744		},
745		{
746			// Test that a module with java_resources includes the files
747			name: "resource files",
748			prop: `java_resources: ["java-res/a/a", "java-res/b/b"]`,
749			args: "-C . -f java-res/a/a -f java-res/b/b",
750		},
751		{
752			// Test that a module with a filegroup in java_resources includes the files with the
753			// path prefix
754			name: "resource filegroup",
755			prop: `java_resources: [":foo-res"]`,
756			extra: `
757				filegroup {
758					name: "foo-res",
759					path: "java-res",
760					srcs: ["java-res/a/a", "java-res/b/b"],
761				}`,
762			args: "-C java-res -f java-res/a/a -f java-res/b/b",
763		},
764		{
765			// Test that a module with wildcards in java_resource_dirs has the correct path prefixes
766			name: "wildcard dirs",
767			prop: `java_resource_dirs: ["java-res/*"]`,
768			args: "-C java-res/a -f java-res/a/a -C java-res/b -f java-res/b/b",
769		},
770		{
771			// Test that a module exclude_java_resource_dirs excludes the files
772			name: "wildcard dirs",
773			prop: `java_resource_dirs: ["java-res/*"], exclude_java_resource_dirs: ["java-res/b"]`,
774			args: "-C java-res/a -f java-res/a/a",
775		},
776		{
777			// Test wildcards in java_resources
778			name: "wildcard files",
779			prop: `java_resources: ["java-res/**/*"]`,
780			args: "-C . -f java-res/a/a -f java-res/b/b",
781		},
782		{
783			// Test exclude_java_resources with java_resources
784			name: "wildcard files with exclude",
785			prop: `java_resources: ["java-res/**/*"], exclude_java_resources: ["java-res/b/*"]`,
786			args: "-C . -f java-res/a/a",
787		},
788		{
789			// Test exclude_java_resources with java_resource_dirs
790			name: "resource dirs with exclude files",
791			prop: `java_resource_dirs: ["java-res"], exclude_java_resources: ["java-res/b/b"]`,
792			args: "-C java-res -f java-res/a/a",
793		},
794		{
795			// Test exclude_java_resource_dirs with java_resource_dirs
796			name: "resource dirs with exclude files",
797			prop: `java_resource_dirs: ["java-res", "java-res2"], exclude_java_resource_dirs: ["java-res2"]`,
798			args: "-C java-res -f java-res/a/a -f java-res/b/b",
799		},
800	}
801
802	for _, test := range table {
803		t.Run(test.name, func(t *testing.T) {
804			ctx, _ := testJavaWithFS(t, `
805				java_library {
806					name: "foo",
807					srcs: [
808						"a.java",
809						"b.java",
810						"c.java",
811					],
812					`+test.prop+`,
813				}
814			`+test.extra,
815				map[string][]byte{
816					"java-res/a/a": nil,
817					"java-res/b/b": nil,
818					"java-res2/a":  nil,
819				},
820			)
821
822			foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
823			fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
824
825			if !inList(fooRes.Output.String(), foo.Inputs.Strings()) {
826				t.Errorf("foo combined jars %v does not contain %q",
827					foo.Inputs.Strings(), fooRes.Output.String())
828			}
829
830			if fooRes.Args["jarArgs"] != test.args {
831				t.Errorf("foo resource jar args %q is not %q",
832					fooRes.Args["jarArgs"], test.args)
833			}
834		})
835	}
836}
837
838func TestIncludeSrcs(t *testing.T) {
839	ctx, _ := testJavaWithFS(t, `
840		java_library {
841			name: "foo",
842			srcs: [
843				"a.java",
844				"b.java",
845				"c.java",
846			],
847			include_srcs: true,
848		}
849
850		java_library {
851			name: "bar",
852			srcs: [
853				"a.java",
854				"b.java",
855				"c.java",
856			],
857			java_resource_dirs: ["java-res"],
858			include_srcs: true,
859		}
860	`, map[string][]byte{
861		"java-res/a/a": nil,
862		"java-res/b/b": nil,
863		"java-res2/a":  nil,
864	})
865
866	// Test a library with include_srcs: true
867	foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
868	fooSrcJar := ctx.ModuleForTests("foo", "android_common").Output("foo.srcjar")
869
870	if g, w := fooSrcJar.Output.String(), foo.Inputs.Strings(); !inList(g, w) {
871		t.Errorf("foo combined jars %v does not contain %q", w, g)
872	}
873
874	if g, w := fooSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
875		t.Errorf("foo source jar args %q is not %q", w, g)
876	}
877
878	// Test a library with include_srcs: true and resources
879	bar := ctx.ModuleForTests("bar", "android_common").Output("withres/bar.jar")
880	barResCombined := ctx.ModuleForTests("bar", "android_common").Output("res-combined/bar.jar")
881	barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
882	barSrcJar := ctx.ModuleForTests("bar", "android_common").Output("bar.srcjar")
883
884	if g, w := barSrcJar.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
885		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
886	}
887
888	if g, w := barRes.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
889		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
890	}
891
892	if g, w := barResCombined.Output.String(), bar.Inputs.Strings(); !inList(g, w) {
893		t.Errorf("bar combined jars %v does not contain %q", w, g)
894	}
895
896	if g, w := barSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
897		t.Errorf("bar source jar args %q is not %q", w, g)
898	}
899
900	if g, w := barRes.Args["jarArgs"], "-C java-res -f java-res/a/a -f java-res/b/b"; g != w {
901		t.Errorf("bar resource jar args %q is not %q", w, g)
902	}
903}
904
905func TestGeneratedSources(t *testing.T) {
906	ctx, _ := testJavaWithFS(t, `
907		java_library {
908			name: "foo",
909			srcs: [
910				"a*.java",
911				":gen",
912				"b*.java",
913			],
914		}
915
916		genrule {
917			name: "gen",
918			tool_files: ["java-res/a"],
919			out: ["gen.java"],
920		}
921	`, map[string][]byte{
922		"a.java": nil,
923		"b.java": nil,
924	})
925
926	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
927	genrule := ctx.ModuleForTests("gen", "").Rule("generator")
928
929	if filepath.Base(genrule.Output.String()) != "gen.java" {
930		t.Fatalf(`gen output file %v is not ".../gen.java"`, genrule.Output.String())
931	}
932
933	if len(javac.Inputs) != 3 ||
934		javac.Inputs[0].String() != "a.java" ||
935		javac.Inputs[1].String() != genrule.Output.String() ||
936		javac.Inputs[2].String() != "b.java" {
937		t.Errorf(`foo inputs %v != ["a.java", ".../gen.java", "b.java"]`, javac.Inputs)
938	}
939}
940
941func TestTurbine(t *testing.T) {
942	result := android.GroupFixturePreparers(
943		prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{"14": {"foo"}})).
944		RunTestWithBp(t, `
945		java_library {
946			name: "foo",
947			srcs: ["a.java"],
948			sdk_version: "14",
949		}
950
951		java_library {
952			name: "bar",
953			srcs: ["b.java"],
954			static_libs: ["foo"],
955			sdk_version: "14",
956		}
957
958		java_library {
959			name: "baz",
960			srcs: ["c.java"],
961			libs: ["bar"],
962			sdk_version: "14",
963		}
964		`)
965
966	fooTurbine := result.ModuleForTests("foo", "android_common").Rule("turbine")
967	barTurbine := result.ModuleForTests("bar", "android_common").Rule("turbine")
968	barJavac := result.ModuleForTests("bar", "android_common").Rule("javac")
969	barTurbineCombined := result.ModuleForTests("bar", "android_common").Description("for turbine")
970	bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac")
971
972	android.AssertPathsRelativeToTopEquals(t, "foo inputs", []string{"a.java"}, fooTurbine.Inputs)
973
974	fooHeaderJar := filepath.Join("out", "soong", ".intermediates", "foo", "android_common", "turbine-combined", "foo.jar")
975	barTurbineJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine", "bar.jar")
976	android.AssertStringDoesContain(t, "bar turbine classpath", barTurbine.Args["classpath"], fooHeaderJar)
977	android.AssertStringDoesContain(t, "bar javac classpath", barJavac.Args["classpath"], fooHeaderJar)
978	android.AssertPathsRelativeToTopEquals(t, "bar turbine combineJar", []string{barTurbineJar, fooHeaderJar}, barTurbineCombined.Inputs)
979	android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "prebuilts/sdk/14/public/android.jar")
980}
981
982func TestSharding(t *testing.T) {
983	ctx, _ := testJava(t, `
984		java_library {
985			name: "bar",
986			srcs: ["a.java","b.java","c.java"],
987			javac_shard_size: 1
988		}
989		`)
990
991	barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
992	for i := 0; i < 3; i++ {
993		barJavac := ctx.ModuleForTests("bar", "android_common").Description("javac" + strconv.Itoa(i))
994		if !strings.Contains(barJavac.Args["classpath"], barHeaderJar) {
995			t.Errorf("bar javac classpath %v does not contain %q", barJavac.Args["classpath"], barHeaderJar)
996		}
997	}
998}
999
1000func TestJarGenrules(t *testing.T) {
1001	ctx, _ := testJava(t, `
1002		java_library {
1003			name: "foo",
1004			srcs: ["a.java"],
1005		}
1006
1007		java_genrule {
1008			name: "jargen",
1009			tool_files: ["b.java"],
1010			cmd: "$(location b.java) $(in) $(out)",
1011			out: ["jargen.jar"],
1012			srcs: [":foo"],
1013		}
1014
1015		java_library {
1016			name: "bar",
1017			static_libs: ["jargen"],
1018			srcs: ["c.java"],
1019		}
1020
1021		java_library {
1022			name: "baz",
1023			libs: ["jargen"],
1024			srcs: ["c.java"],
1025		}
1026	`)
1027
1028	foo := ctx.ModuleForTests("foo", "android_common").Output("javac/foo.jar")
1029	jargen := ctx.ModuleForTests("jargen", "android_common").Output("jargen.jar")
1030	bar := ctx.ModuleForTests("bar", "android_common").Output("javac/bar.jar")
1031	baz := ctx.ModuleForTests("baz", "android_common").Output("javac/baz.jar")
1032	barCombined := ctx.ModuleForTests("bar", "android_common").Output("combined/bar.jar")
1033
1034	if g, w := jargen.Implicits.Strings(), foo.Output.String(); !android.InList(w, g) {
1035		t.Errorf("expected jargen inputs [%q], got %q", w, g)
1036	}
1037
1038	if !strings.Contains(bar.Args["classpath"], jargen.Output.String()) {
1039		t.Errorf("bar classpath %v does not contain %q", bar.Args["classpath"], jargen.Output.String())
1040	}
1041
1042	if !strings.Contains(baz.Args["classpath"], jargen.Output.String()) {
1043		t.Errorf("baz classpath %v does not contain %q", baz.Args["classpath"], jargen.Output.String())
1044	}
1045
1046	if len(barCombined.Inputs) != 2 ||
1047		barCombined.Inputs[0].String() != bar.Output.String() ||
1048		barCombined.Inputs[1].String() != jargen.Output.String() {
1049		t.Errorf("bar combined jar inputs %v is not [%q, %q]",
1050			barCombined.Inputs.Strings(), bar.Output.String(), jargen.Output.String())
1051	}
1052}
1053
1054func TestExcludeFileGroupInSrcs(t *testing.T) {
1055	ctx, _ := testJava(t, `
1056		java_library {
1057			name: "foo",
1058			srcs: ["a.java", ":foo-srcs"],
1059			exclude_srcs: ["a.java", ":foo-excludes"],
1060		}
1061
1062		filegroup {
1063			name: "foo-srcs",
1064			srcs: ["java-fg/a.java", "java-fg/b.java", "java-fg/c.java"],
1065		}
1066
1067		filegroup {
1068			name: "foo-excludes",
1069			srcs: ["java-fg/a.java", "java-fg/b.java"],
1070		}
1071	`)
1072
1073	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
1074
1075	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "java-fg/c.java" {
1076		t.Errorf(`foo inputs %v != ["java-fg/c.java"]`, javac.Inputs)
1077	}
1078}
1079
1080func TestJavaLibrary(t *testing.T) {
1081	testJavaWithFS(t, "", map[string][]byte{
1082		"libcore/Android.bp": []byte(`
1083				java_library {
1084						name: "core",
1085						sdk_version: "none",
1086						system_modules: "none",
1087				}
1088
1089				filegroup {
1090					name: "core-jar",
1091					srcs: [":core{.jar}"],
1092				}
1093		`),
1094	})
1095}
1096
1097func TestJavaImport(t *testing.T) {
1098	testJavaWithFS(t, "", map[string][]byte{
1099		"libcore/Android.bp": []byte(`
1100				java_import {
1101						name: "core",
1102						sdk_version: "none",
1103				}
1104
1105				filegroup {
1106					name: "core-jar",
1107					srcs: [":core{.jar}"],
1108				}
1109		`),
1110	})
1111}
1112
1113var compilerFlagsTestCases = []struct {
1114	in  string
1115	out bool
1116}{
1117	{
1118		in:  "a",
1119		out: false,
1120	},
1121	{
1122		in:  "-a",
1123		out: true,
1124	},
1125	{
1126		in:  "-no-jdk",
1127		out: false,
1128	},
1129	{
1130		in:  "-no-stdlib",
1131		out: false,
1132	},
1133	{
1134		in:  "-kotlin-home",
1135		out: false,
1136	},
1137	{
1138		in:  "-kotlin-home /some/path",
1139		out: false,
1140	},
1141	{
1142		in:  "-include-runtime",
1143		out: false,
1144	},
1145	{
1146		in:  "-Xintellij-plugin-root",
1147		out: false,
1148	},
1149}
1150
1151type mockContext struct {
1152	android.ModuleContext
1153	result bool
1154}
1155
1156func (ctx *mockContext) PropertyErrorf(property, format string, args ...interface{}) {
1157	// CheckBadCompilerFlags calls this function when the flag should be rejected
1158	ctx.result = false
1159}
1160
1161func TestCompilerFlags(t *testing.T) {
1162	for _, testCase := range compilerFlagsTestCases {
1163		ctx := &mockContext{result: true}
1164		CheckKotlincFlags(ctx, []string{testCase.in})
1165		if ctx.result != testCase.out {
1166			t.Errorf("incorrect output:")
1167			t.Errorf("     input: %#v", testCase.in)
1168			t.Errorf("  expected: %#v", testCase.out)
1169			t.Errorf("       got: %#v", ctx.result)
1170		}
1171	}
1172}
1173
1174// TODO(jungjw): Consider making this more robust by ignoring path order.
1175func checkPatchModuleFlag(t *testing.T, ctx *android.TestContext, moduleName string, expected string) {
1176	variables := ctx.ModuleForTests(moduleName, "android_common").VariablesForTestsRelativeToTop()
1177	flags := strings.Split(variables["javacFlags"], " ")
1178	got := ""
1179	for _, flag := range flags {
1180		keyEnd := strings.Index(flag, "=")
1181		if keyEnd > -1 && flag[:keyEnd] == "--patch-module" {
1182			got = flag[keyEnd+1:]
1183			break
1184		}
1185	}
1186	if expected != android.StringPathRelativeToTop(ctx.Config().BuildDir(), got) {
1187		t.Errorf("Unexpected patch-module flag for module %q - expected %q, but got %q", moduleName, expected, got)
1188	}
1189}
1190
1191func TestPatchModule(t *testing.T) {
1192	t.Run("Java language level 8", func(t *testing.T) {
1193		// Test with legacy javac -source 1.8 -target 1.8
1194		bp := `
1195			java_library {
1196				name: "foo",
1197				srcs: ["a.java"],
1198				java_version: "1.8",
1199			}
1200
1201			java_library {
1202				name: "bar",
1203				srcs: ["b.java"],
1204				sdk_version: "none",
1205				system_modules: "none",
1206				patch_module: "java.base",
1207				java_version: "1.8",
1208			}
1209
1210			java_library {
1211				name: "baz",
1212				srcs: ["c.java"],
1213				patch_module: "java.base",
1214				java_version: "1.8",
1215			}
1216		`
1217		ctx, _ := testJava(t, bp)
1218
1219		checkPatchModuleFlag(t, ctx, "foo", "")
1220		checkPatchModuleFlag(t, ctx, "bar", "")
1221		checkPatchModuleFlag(t, ctx, "baz", "")
1222	})
1223
1224	t.Run("Java language level 9", func(t *testing.T) {
1225		// Test with default javac -source 9 -target 9
1226		bp := `
1227			java_library {
1228				name: "foo",
1229				srcs: ["a.java"],
1230			}
1231
1232			java_library {
1233				name: "bar",
1234				srcs: ["b.java"],
1235				sdk_version: "none",
1236				system_modules: "none",
1237				patch_module: "java.base",
1238			}
1239
1240			java_library {
1241				name: "baz",
1242				srcs: [
1243					"c.java",
1244					// Tests for b/150878007
1245					"dir/d.java",
1246					"dir2/e.java",
1247					"dir2/f.java",
1248					"nested/dir/g.java"
1249				],
1250				patch_module: "java.base",
1251			}
1252		`
1253		ctx, _ := testJava(t, bp)
1254
1255		checkPatchModuleFlag(t, ctx, "foo", "")
1256		expected := "java.base=.:out/soong"
1257		checkPatchModuleFlag(t, ctx, "bar", expected)
1258		expected = "java.base=" + strings.Join([]string{
1259			".", "out/soong", "dir", "dir2", "nested", defaultModuleToPath("ext"), defaultModuleToPath("framework")}, ":")
1260		checkPatchModuleFlag(t, ctx, "baz", expected)
1261	})
1262}
1263
1264func TestJavaLibraryWithSystemModules(t *testing.T) {
1265	ctx, _ := testJava(t, `
1266		java_library {
1267		    name: "lib-with-source-system-modules",
1268		    srcs: [
1269		        "a.java",
1270		    ],
1271				sdk_version: "none",
1272				system_modules: "source-system-modules",
1273		}
1274
1275		java_library {
1276				name: "source-jar",
1277		    srcs: [
1278		        "a.java",
1279		    ],
1280		}
1281
1282		java_system_modules {
1283				name: "source-system-modules",
1284				libs: ["source-jar"],
1285		}
1286
1287		java_library {
1288		    name: "lib-with-prebuilt-system-modules",
1289		    srcs: [
1290		        "a.java",
1291		    ],
1292				sdk_version: "none",
1293				system_modules: "prebuilt-system-modules",
1294		}
1295
1296		java_import {
1297				name: "prebuilt-jar",
1298				jars: ["a.jar"],
1299		}
1300
1301		java_system_modules_import {
1302				name: "prebuilt-system-modules",
1303				libs: ["prebuilt-jar"],
1304		}
1305		`)
1306
1307	checkBootClasspathForSystemModule(t, ctx, "lib-with-source-system-modules", "/source-jar.jar")
1308
1309	checkBootClasspathForSystemModule(t, ctx, "lib-with-prebuilt-system-modules", "/prebuilt-jar.jar")
1310}
1311
1312func checkBootClasspathForSystemModule(t *testing.T, ctx *android.TestContext, moduleName string, expectedSuffix string) {
1313	javacRule := ctx.ModuleForTests(moduleName, "android_common").Rule("javac")
1314	bootClasspath := javacRule.Args["bootClasspath"]
1315	if strings.HasPrefix(bootClasspath, "--system ") && strings.HasSuffix(bootClasspath, expectedSuffix) {
1316		t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath)
1317	}
1318}
1319
1320func TestAidlExportIncludeDirsFromImports(t *testing.T) {
1321	ctx, _ := testJava(t, `
1322		java_library {
1323			name: "foo",
1324			srcs: ["aidl/foo/IFoo.aidl"],
1325			libs: ["bar"],
1326		}
1327
1328		java_import {
1329			name: "bar",
1330			jars: ["a.jar"],
1331			aidl: {
1332				export_include_dirs: ["aidl/bar"],
1333			},
1334		}
1335	`)
1336
1337	aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
1338	expectedAidlFlag := "-Iaidl/bar"
1339	if !strings.Contains(aidlCommand, expectedAidlFlag) {
1340		t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
1341	}
1342}
1343
1344func TestAidlFlagsArePassedToTheAidlCompiler(t *testing.T) {
1345	ctx, _ := testJava(t, `
1346		java_library {
1347			name: "foo",
1348			srcs: ["aidl/foo/IFoo.aidl"],
1349			aidl: { flags: ["-Werror"], },
1350		}
1351	`)
1352
1353	aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
1354	expectedAidlFlag := "-Werror"
1355	if !strings.Contains(aidlCommand, expectedAidlFlag) {
1356		t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
1357	}
1358}
1359
1360func TestDataNativeBinaries(t *testing.T) {
1361	ctx, _ := testJava(t, `
1362		java_test_host {
1363			name: "foo",
1364			srcs: ["a.java"],
1365			data_native_bins: ["bin"]
1366		}
1367
1368		python_binary_host {
1369			name: "bin",
1370			srcs: ["bin.py"],
1371		}
1372	`)
1373
1374	buildOS := android.BuildOs.String()
1375
1376	test := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
1377	entries := android.AndroidMkEntriesForTest(t, ctx, test)[0]
1378	expected := []string{"out/soong/.intermediates/bin/" + buildOS + "_x86_64_PY3/bin:bin"}
1379	actual := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"]
1380	android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_COMPATIBILITY_SUPPORT_FILES", ctx.Config(), expected, actual)
1381}
1382
1383func TestDefaultInstallable(t *testing.T) {
1384	ctx, _ := testJava(t, `
1385		java_test_host {
1386			name: "foo"
1387		}
1388	`)
1389
1390	buildOS := android.BuildOs.String()
1391	module := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
1392	assertDeepEquals(t, "Default installable value should be true.", proptools.BoolPtr(true),
1393		module.properties.Installable)
1394}
1395