• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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	"io/ioutil"
19	"os"
20	"path/filepath"
21	"reflect"
22	"regexp"
23	"sort"
24	"strconv"
25	"strings"
26	"testing"
27
28	"github.com/google/blueprint/proptools"
29
30	"android/soong/android"
31	"android/soong/cc"
32	"android/soong/dexpreopt"
33	"android/soong/genrule"
34)
35
36var buildDir string
37
38func setUp() {
39	var err error
40	buildDir, err = ioutil.TempDir("", "soong_java_test")
41	if err != nil {
42		panic(err)
43	}
44}
45
46func tearDown() {
47	os.RemoveAll(buildDir)
48}
49
50func TestMain(m *testing.M) {
51	run := func() int {
52		setUp()
53		defer tearDown()
54
55		return m.Run()
56	}
57
58	os.Exit(run())
59}
60
61func testConfig(env map[string]string, bp string, fs map[string][]byte) android.Config {
62	bp += dexpreopt.BpToolModulesForTest()
63
64	config := TestConfig(buildDir, env, bp, fs)
65
66	// Set up the global Once cache used for dexpreopt.GlobalSoongConfig, so that
67	// it doesn't create a real one, which would fail.
68	_ = dexpreopt.GlobalSoongConfigForTests(config)
69
70	return config
71}
72
73func testContext() *android.TestContext {
74
75	ctx := android.NewTestArchContext()
76	RegisterJavaBuildComponents(ctx)
77	RegisterAppBuildComponents(ctx)
78	RegisterAARBuildComponents(ctx)
79	RegisterGenRuleBuildComponents(ctx)
80	RegisterSystemModulesBuildComponents(ctx)
81	ctx.RegisterModuleType("java_plugin", PluginFactory)
82	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
83	ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
84	RegisterDocsBuildComponents(ctx)
85	RegisterStubsBuildComponents(ctx)
86	RegisterSdkLibraryBuildComponents(ctx)
87	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
88
89	RegisterPrebuiltApisBuildComponents(ctx)
90
91	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
92	ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
93	ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory))
94
95	// Register module types and mutators from cc needed for JNI testing
96	cc.RegisterRequiredBuildComponentsForTest(ctx)
97
98	dexpreopt.RegisterToolModulesForTest(ctx)
99
100	return ctx
101}
102
103func run(t *testing.T, ctx *android.TestContext, config android.Config) {
104	t.Helper()
105
106	pathCtx := android.PathContextForTesting(config)
107	dexpreopt.SetTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
108
109	ctx.Register(config)
110	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
111	android.FailIfErrored(t, errs)
112	_, errs = ctx.PrepareBuildActions(config)
113	android.FailIfErrored(t, errs)
114}
115
116func testJavaError(t *testing.T, pattern string, bp string) (*android.TestContext, android.Config) {
117	t.Helper()
118	return testJavaErrorWithConfig(t, pattern, testConfig(nil, bp, nil))
119}
120
121func testJavaErrorWithConfig(t *testing.T, pattern string, config android.Config) (*android.TestContext, android.Config) {
122	t.Helper()
123	ctx := testContext()
124
125	pathCtx := android.PathContextForTesting(config)
126	dexpreopt.SetTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
127
128	ctx.Register(config)
129	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
130	if len(errs) > 0 {
131		android.FailIfNoMatchingErrors(t, pattern, errs)
132		return ctx, config
133	}
134	_, errs = ctx.PrepareBuildActions(config)
135	if len(errs) > 0 {
136		android.FailIfNoMatchingErrors(t, pattern, errs)
137		return ctx, config
138	}
139
140	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
141
142	return ctx, config
143}
144
145func testJavaWithFS(t *testing.T, bp string, fs map[string][]byte) (*android.TestContext, android.Config) {
146	t.Helper()
147	return testJavaWithConfig(t, testConfig(nil, bp, fs))
148}
149
150func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) {
151	t.Helper()
152	return testJavaWithFS(t, bp, nil)
153}
154
155func testJavaWithConfig(t *testing.T, config android.Config) (*android.TestContext, android.Config) {
156	t.Helper()
157	ctx := testContext()
158	run(t, ctx, config)
159
160	return ctx, config
161}
162
163func moduleToPath(name string) string {
164	switch {
165	case name == `""`:
166		return name
167	case strings.HasSuffix(name, ".jar"):
168		return name
169	default:
170		return filepath.Join(buildDir, ".intermediates", name, "android_common", "turbine-combined", name+".jar")
171	}
172}
173
174func TestJavaLinkType(t *testing.T) {
175	testJava(t, `
176		java_library {
177			name: "foo",
178			srcs: ["a.java"],
179			libs: ["bar"],
180			static_libs: ["baz"],
181		}
182
183		java_library {
184			name: "bar",
185			sdk_version: "current",
186			srcs: ["b.java"],
187		}
188
189		java_library {
190			name: "baz",
191			sdk_version: "system_current",
192			srcs: ["c.java"],
193		}
194	`)
195
196	testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
197		java_library {
198			name: "foo",
199			srcs: ["a.java"],
200			libs: ["bar"],
201			sdk_version: "current",
202			static_libs: ["baz"],
203		}
204
205		java_library {
206			name: "bar",
207			sdk_version: "current",
208			srcs: ["b.java"],
209		}
210
211		java_library {
212			name: "baz",
213			sdk_version: "system_current",
214			srcs: ["c.java"],
215		}
216	`)
217
218	testJava(t, `
219		java_library {
220			name: "foo",
221			srcs: ["a.java"],
222			libs: ["bar"],
223			sdk_version: "system_current",
224			static_libs: ["baz"],
225		}
226
227		java_library {
228			name: "bar",
229			sdk_version: "current",
230			srcs: ["b.java"],
231		}
232
233		java_library {
234			name: "baz",
235			sdk_version: "system_current",
236			srcs: ["c.java"],
237		}
238	`)
239
240	testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
241		java_library {
242			name: "foo",
243			srcs: ["a.java"],
244			libs: ["bar"],
245			sdk_version: "system_current",
246			static_libs: ["baz"],
247		}
248
249		java_library {
250			name: "bar",
251			sdk_version: "current",
252			srcs: ["b.java"],
253		}
254
255		java_library {
256			name: "baz",
257			srcs: ["c.java"],
258		}
259	`)
260}
261
262func TestSimple(t *testing.T) {
263	ctx, _ := testJava(t, `
264		java_library {
265			name: "foo",
266			srcs: ["a.java"],
267			libs: ["bar"],
268			static_libs: ["baz"],
269		}
270
271		java_library {
272			name: "bar",
273			srcs: ["b.java"],
274		}
275
276		java_library {
277			name: "baz",
278			srcs: ["c.java"],
279		}
280	`)
281
282	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
283	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
284
285	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
286		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
287	}
288
289	baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
290	barTurbine := filepath.Join(buildDir, ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
291	bazTurbine := filepath.Join(buildDir, ".intermediates", "baz", "android_common", "turbine-combined", "baz.jar")
292
293	if !strings.Contains(javac.Args["classpath"], barTurbine) {
294		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barTurbine)
295	}
296
297	if !strings.Contains(javac.Args["classpath"], bazTurbine) {
298		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bazTurbine)
299	}
300
301	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
302		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
303	}
304}
305
306func TestExportedPlugins(t *testing.T) {
307	type Result struct {
308		library    string
309		processors string
310	}
311	var tests = []struct {
312		name    string
313		extra   string
314		results []Result
315	}{
316		{
317			name:    "Exported plugin is not a direct plugin",
318			extra:   `java_library { name: "exports", srcs: ["a.java"], exported_plugins: ["plugin"] }`,
319			results: []Result{{library: "exports", processors: "-proc:none"}},
320		},
321		{
322			name: "Exports plugin to dependee",
323			extra: `
324				java_library{name: "exports", exported_plugins: ["plugin"]}
325				java_library{name: "foo", srcs: ["a.java"], libs: ["exports"]}
326				java_library{name: "bar", srcs: ["a.java"], static_libs: ["exports"]}
327			`,
328			results: []Result{
329				{library: "foo", processors: "-processor com.android.TestPlugin"},
330				{library: "bar", processors: "-processor com.android.TestPlugin"},
331			},
332		},
333		{
334			name: "Exports plugin to android_library",
335			extra: `
336				java_library{name: "exports", exported_plugins: ["plugin"]}
337				android_library{name: "foo", srcs: ["a.java"],  libs: ["exports"]}
338				android_library{name: "bar", srcs: ["a.java"], static_libs: ["exports"]}
339			`,
340			results: []Result{
341				{library: "foo", processors: "-processor com.android.TestPlugin"},
342				{library: "bar", processors: "-processor com.android.TestPlugin"},
343			},
344		},
345		{
346			name: "Exports plugin is not propagated via transitive deps",
347			extra: `
348				java_library{name: "exports", exported_plugins: ["plugin"]}
349				java_library{name: "foo", srcs: ["a.java"], libs: ["exports"]}
350				java_library{name: "bar", srcs: ["a.java"], static_libs: ["foo"]}
351			`,
352			results: []Result{
353				{library: "foo", processors: "-processor com.android.TestPlugin"},
354				{library: "bar", processors: "-proc:none"},
355			},
356		},
357		{
358			name: "Exports plugin appends to plugins",
359			extra: `
360                java_plugin{name: "plugin2", processor_class: "com.android.TestPlugin2"}
361				java_library{name: "exports", exported_plugins: ["plugin"]}
362				java_library{name: "foo", srcs: ["a.java"], libs: ["exports"], plugins: ["plugin2"]}
363			`,
364			results: []Result{
365				{library: "foo", processors: "-processor com.android.TestPlugin,com.android.TestPlugin2"},
366			},
367		},
368	}
369
370	for _, test := range tests {
371		t.Run(test.name, func(t *testing.T) {
372			ctx, _ := testJava(t, `
373				java_plugin {
374					name: "plugin",
375					processor_class: "com.android.TestPlugin",
376				}
377			`+test.extra)
378
379			for _, want := range test.results {
380				javac := ctx.ModuleForTests(want.library, "android_common").Rule("javac")
381				if javac.Args["processor"] != want.processors {
382					t.Errorf("For library %v, expected %v, found %v", want.library, want.processors, javac.Args["processor"])
383				}
384			}
385		})
386	}
387}
388
389func TestSdkVersionByPartition(t *testing.T) {
390	testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", `
391		java_library {
392			name: "foo",
393			srcs: ["a.java"],
394			vendor: true,
395		}
396	`)
397
398	testJava(t, `
399		java_library {
400			name: "bar",
401			srcs: ["b.java"],
402		}
403	`)
404
405	for _, enforce := range []bool{true, false} {
406		bp := `
407			java_library {
408				name: "foo",
409				srcs: ["a.java"],
410				product_specific: true,
411			}
412		`
413
414		config := testConfig(nil, bp, nil)
415		config.TestProductVariables.EnforceProductPartitionInterface = proptools.BoolPtr(enforce)
416		if enforce {
417			testJavaErrorWithConfig(t, "sdk_version must have a value when the module is located at vendor or product", config)
418		} else {
419			testJavaWithConfig(t, config)
420		}
421	}
422}
423
424func TestArchSpecific(t *testing.T) {
425	ctx, _ := testJava(t, `
426		java_library {
427			name: "foo",
428			srcs: ["a.java"],
429			target: {
430				android: {
431					srcs: ["b.java"],
432				},
433			},
434		}
435	`)
436
437	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
438	if len(javac.Inputs) != 2 || javac.Inputs[0].String() != "a.java" || javac.Inputs[1].String() != "b.java" {
439		t.Errorf(`foo inputs %v != ["a.java", "b.java"]`, javac.Inputs)
440	}
441}
442
443func TestBinary(t *testing.T) {
444	ctx, _ := testJava(t, `
445		java_library_host {
446			name: "foo",
447			srcs: ["a.java"],
448		}
449
450		java_binary_host {
451			name: "bar",
452			srcs: ["b.java"],
453			static_libs: ["foo"],
454		}
455	`)
456
457	buildOS := android.BuildOs.String()
458
459	bar := ctx.ModuleForTests("bar", buildOS+"_common")
460	barJar := bar.Output("bar.jar").Output.String()
461	barWrapper := ctx.ModuleForTests("bar", buildOS+"_x86_64")
462	barWrapperDeps := barWrapper.Output("bar").Implicits.Strings()
463
464	// Test that the install binary wrapper depends on the installed jar file
465	if len(barWrapperDeps) != 1 || barWrapperDeps[0] != barJar {
466		t.Errorf("expected binary wrapper implicits [%q], got %v",
467			barJar, barWrapperDeps)
468	}
469
470}
471
472func TestPrebuilts(t *testing.T) {
473	ctx, _ := testJava(t, `
474		java_library {
475			name: "foo",
476			srcs: ["a.java", ":stubs-source"],
477			libs: ["bar", "sdklib"],
478			static_libs: ["baz"],
479		}
480
481		java_import {
482			name: "bar",
483			jars: ["a.jar"],
484		}
485
486		java_import {
487			name: "baz",
488			jars: ["b.jar"],
489		}
490
491		dex_import {
492			name: "qux",
493			jars: ["b.jar"],
494		}
495
496		java_sdk_library_import {
497			name: "sdklib",
498			public: {
499				jars: ["c.jar"],
500			},
501		}
502
503		prebuilt_stubs_sources {
504			name: "stubs-source",
505			srcs: ["stubs/sources"],
506		}
507
508		java_test_import {
509			name: "test",
510			jars: ["a.jar"],
511			test_suites: ["cts"],
512			test_config: "AndroidTest.xml",
513		}
514		`)
515
516	fooModule := ctx.ModuleForTests("foo", "android_common")
517	javac := fooModule.Rule("javac")
518	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
519	barJar := ctx.ModuleForTests("bar", "android_common").Rule("combineJar").Output
520	bazJar := ctx.ModuleForTests("baz", "android_common").Rule("combineJar").Output
521	sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output
522
523	fooLibrary := fooModule.Module().(*Library)
524	assertDeepEquals(t, "foo java sources incorrect",
525		[]string{"a.java"}, fooLibrary.compiledJavaSrcs.Strings())
526
527	assertDeepEquals(t, "foo java source jars incorrect",
528		[]string{".intermediates/stubs-source/android_common/stubs-source-stubs.srcjar"},
529		android.NormalizePathsForTesting(fooLibrary.compiledSrcJars))
530
531	if !strings.Contains(javac.Args["classpath"], barJar.String()) {
532		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String())
533	}
534
535	if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
536		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
537	}
538
539	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != bazJar.String() {
540		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String())
541	}
542
543	ctx.ModuleForTests("qux", "android_common").Rule("Cp")
544}
545
546func assertDeepEquals(t *testing.T, message string, expected interface{}, actual interface{}) {
547	if !reflect.DeepEqual(expected, actual) {
548		t.Errorf("%s: expected %q, found %q", message, expected, actual)
549	}
550}
551
552func TestJavaSdkLibraryImport(t *testing.T) {
553	ctx, _ := testJava(t, `
554		java_library {
555			name: "foo",
556			srcs: ["a.java"],
557			libs: ["sdklib"],
558			sdk_version: "current",
559		}
560
561		java_library {
562			name: "foo.system",
563			srcs: ["a.java"],
564			libs: ["sdklib"],
565			sdk_version: "system_current",
566		}
567
568		java_library {
569			name: "foo.test",
570			srcs: ["a.java"],
571			libs: ["sdklib"],
572			sdk_version: "test_current",
573		}
574
575		java_sdk_library_import {
576			name: "sdklib",
577			public: {
578				jars: ["a.jar"],
579			},
580			system: {
581				jars: ["b.jar"],
582			},
583			test: {
584				jars: ["c.jar"],
585				stub_srcs: ["c.java"],
586			},
587		}
588		`)
589
590	for _, scope := range []string{"", ".system", ".test"} {
591		fooModule := ctx.ModuleForTests("foo"+scope, "android_common")
592		javac := fooModule.Rule("javac")
593
594		sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
595		if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
596			t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
597		}
598	}
599}
600
601func TestDefaults(t *testing.T) {
602	ctx, _ := testJava(t, `
603		java_defaults {
604			name: "defaults",
605			srcs: ["a.java"],
606			libs: ["bar"],
607			static_libs: ["baz"],
608			optimize: {enabled: false},
609		}
610
611		java_library {
612			name: "foo",
613			defaults: ["defaults"],
614		}
615
616		java_library {
617			name: "bar",
618			srcs: ["b.java"],
619		}
620
621		java_library {
622			name: "baz",
623			srcs: ["c.java"],
624		}
625
626		android_test {
627			name: "atestOptimize",
628			defaults: ["defaults"],
629			optimize: {enabled: true},
630		}
631
632		android_test {
633			name: "atestNoOptimize",
634			defaults: ["defaults"],
635		}
636
637		android_test {
638			name: "atestDefault",
639			srcs: ["a.java"],
640		}
641		`)
642
643	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
644	combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac")
645
646	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
647		t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
648	}
649
650	barTurbine := filepath.Join(buildDir, ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
651	if !strings.Contains(javac.Args["classpath"], barTurbine) {
652		t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barTurbine)
653	}
654
655	baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String()
656	if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
657		t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
658	}
659
660	atestOptimize := ctx.ModuleForTests("atestOptimize", "android_common").MaybeRule("r8")
661	if atestOptimize.Output == nil {
662		t.Errorf("atestOptimize should optimize APK")
663	}
664
665	atestNoOptimize := ctx.ModuleForTests("atestNoOptimize", "android_common").MaybeRule("d8")
666	if atestNoOptimize.Output == nil {
667		t.Errorf("atestNoOptimize should not optimize APK")
668	}
669
670	atestDefault := ctx.ModuleForTests("atestDefault", "android_common").MaybeRule("r8")
671	if atestDefault.Output == nil {
672		t.Errorf("atestDefault should optimize APK")
673	}
674}
675
676func TestResources(t *testing.T) {
677	var table = []struct {
678		name  string
679		prop  string
680		extra string
681		args  string
682	}{
683		{
684			// Test that a module with java_resource_dirs includes the files
685			name: "resource dirs",
686			prop: `java_resource_dirs: ["java-res"]`,
687			args: "-C java-res -f java-res/a/a -f java-res/b/b",
688		},
689		{
690			// Test that a module with java_resources includes the files
691			name: "resource files",
692			prop: `java_resources: ["java-res/a/a", "java-res/b/b"]`,
693			args: "-C . -f java-res/a/a -f java-res/b/b",
694		},
695		{
696			// Test that a module with a filegroup in java_resources includes the files with the
697			// path prefix
698			name: "resource filegroup",
699			prop: `java_resources: [":foo-res"]`,
700			extra: `
701				filegroup {
702					name: "foo-res",
703					path: "java-res",
704					srcs: ["java-res/a/a", "java-res/b/b"],
705				}`,
706			args: "-C java-res -f java-res/a/a -f java-res/b/b",
707		},
708		{
709			// Test that a module with wildcards in java_resource_dirs has the correct path prefixes
710			name: "wildcard dirs",
711			prop: `java_resource_dirs: ["java-res/*"]`,
712			args: "-C java-res/a -f java-res/a/a -C java-res/b -f java-res/b/b",
713		},
714		{
715			// Test that a module exclude_java_resource_dirs excludes the files
716			name: "wildcard dirs",
717			prop: `java_resource_dirs: ["java-res/*"], exclude_java_resource_dirs: ["java-res/b"]`,
718			args: "-C java-res/a -f java-res/a/a",
719		},
720		{
721			// Test wildcards in java_resources
722			name: "wildcard files",
723			prop: `java_resources: ["java-res/**/*"]`,
724			args: "-C . -f java-res/a/a -f java-res/b/b",
725		},
726		{
727			// Test exclude_java_resources with java_resources
728			name: "wildcard files with exclude",
729			prop: `java_resources: ["java-res/**/*"], exclude_java_resources: ["java-res/b/*"]`,
730			args: "-C . -f java-res/a/a",
731		},
732		{
733			// Test exclude_java_resources with java_resource_dirs
734			name: "resource dirs with exclude files",
735			prop: `java_resource_dirs: ["java-res"], exclude_java_resources: ["java-res/b/b"]`,
736			args: "-C java-res -f java-res/a/a",
737		},
738		{
739			// Test exclude_java_resource_dirs with java_resource_dirs
740			name: "resource dirs with exclude files",
741			prop: `java_resource_dirs: ["java-res", "java-res2"], exclude_java_resource_dirs: ["java-res2"]`,
742			args: "-C java-res -f java-res/a/a -f java-res/b/b",
743		},
744	}
745
746	for _, test := range table {
747		t.Run(test.name, func(t *testing.T) {
748			ctx, _ := testJavaWithFS(t, `
749				java_library {
750					name: "foo",
751					srcs: [
752						"a.java",
753						"b.java",
754						"c.java",
755					],
756					`+test.prop+`,
757				}
758			`+test.extra,
759				map[string][]byte{
760					"java-res/a/a": nil,
761					"java-res/b/b": nil,
762					"java-res2/a":  nil,
763				},
764			)
765
766			foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
767			fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
768
769			if !inList(fooRes.Output.String(), foo.Inputs.Strings()) {
770				t.Errorf("foo combined jars %v does not contain %q",
771					foo.Inputs.Strings(), fooRes.Output.String())
772			}
773
774			if fooRes.Args["jarArgs"] != test.args {
775				t.Errorf("foo resource jar args %q is not %q",
776					fooRes.Args["jarArgs"], test.args)
777			}
778		})
779	}
780}
781
782func TestIncludeSrcs(t *testing.T) {
783	ctx, _ := testJavaWithFS(t, `
784		java_library {
785			name: "foo",
786			srcs: [
787				"a.java",
788				"b.java",
789				"c.java",
790			],
791			include_srcs: true,
792		}
793
794		java_library {
795			name: "bar",
796			srcs: [
797				"a.java",
798				"b.java",
799				"c.java",
800			],
801			java_resource_dirs: ["java-res"],
802			include_srcs: true,
803		}
804	`, map[string][]byte{
805		"java-res/a/a": nil,
806		"java-res/b/b": nil,
807		"java-res2/a":  nil,
808	})
809
810	// Test a library with include_srcs: true
811	foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
812	fooSrcJar := ctx.ModuleForTests("foo", "android_common").Output("foo.srcjar")
813
814	if g, w := fooSrcJar.Output.String(), foo.Inputs.Strings(); !inList(g, w) {
815		t.Errorf("foo combined jars %v does not contain %q", w, g)
816	}
817
818	if g, w := fooSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
819		t.Errorf("foo source jar args %q is not %q", w, g)
820	}
821
822	// Test a library with include_srcs: true and resources
823	bar := ctx.ModuleForTests("bar", "android_common").Output("withres/bar.jar")
824	barResCombined := ctx.ModuleForTests("bar", "android_common").Output("res-combined/bar.jar")
825	barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
826	barSrcJar := ctx.ModuleForTests("bar", "android_common").Output("bar.srcjar")
827
828	if g, w := barSrcJar.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
829		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
830	}
831
832	if g, w := barRes.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) {
833		t.Errorf("bar combined resource jars %v does not contain %q", w, g)
834	}
835
836	if g, w := barResCombined.Output.String(), bar.Inputs.Strings(); !inList(g, w) {
837		t.Errorf("bar combined jars %v does not contain %q", w, g)
838	}
839
840	if g, w := barSrcJar.Args["jarArgs"], "-C . -f a.java -f b.java -f c.java"; g != w {
841		t.Errorf("bar source jar args %q is not %q", w, g)
842	}
843
844	if g, w := barRes.Args["jarArgs"], "-C java-res -f java-res/a/a -f java-res/b/b"; g != w {
845		t.Errorf("bar resource jar args %q is not %q", w, g)
846	}
847}
848
849func TestGeneratedSources(t *testing.T) {
850	ctx, _ := testJavaWithFS(t, `
851		java_library {
852			name: "foo",
853			srcs: [
854				"a*.java",
855				":gen",
856				"b*.java",
857			],
858		}
859
860		genrule {
861			name: "gen",
862			tool_files: ["java-res/a"],
863			out: ["gen.java"],
864		}
865	`, map[string][]byte{
866		"a.java": nil,
867		"b.java": nil,
868	})
869
870	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
871	genrule := ctx.ModuleForTests("gen", "").Rule("generator")
872
873	if filepath.Base(genrule.Output.String()) != "gen.java" {
874		t.Fatalf(`gen output file %v is not ".../gen.java"`, genrule.Output.String())
875	}
876
877	if len(javac.Inputs) != 3 ||
878		javac.Inputs[0].String() != "a.java" ||
879		javac.Inputs[1].String() != genrule.Output.String() ||
880		javac.Inputs[2].String() != "b.java" {
881		t.Errorf(`foo inputs %v != ["a.java", ".../gen.java", "b.java"]`, javac.Inputs)
882	}
883}
884
885func TestTurbine(t *testing.T) {
886	ctx, _ := testJava(t, `
887		java_library {
888			name: "foo",
889			srcs: ["a.java"],
890			sdk_version: "14",
891		}
892
893		java_library {
894			name: "bar",
895			srcs: ["b.java"],
896			static_libs: ["foo"],
897			sdk_version: "14",
898		}
899
900		java_library {
901			name: "baz",
902			srcs: ["c.java"],
903			libs: ["bar"],
904			sdk_version: "14",
905		}
906		`)
907
908	fooTurbine := ctx.ModuleForTests("foo", "android_common").Rule("turbine")
909	barTurbine := ctx.ModuleForTests("bar", "android_common").Rule("turbine")
910	barJavac := ctx.ModuleForTests("bar", "android_common").Rule("javac")
911	barTurbineCombined := ctx.ModuleForTests("bar", "android_common").Description("for turbine")
912	bazJavac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
913
914	if len(fooTurbine.Inputs) != 1 || fooTurbine.Inputs[0].String() != "a.java" {
915		t.Errorf(`foo inputs %v != ["a.java"]`, fooTurbine.Inputs)
916	}
917
918	fooHeaderJar := filepath.Join(buildDir, ".intermediates", "foo", "android_common", "turbine-combined", "foo.jar")
919	if !strings.Contains(barTurbine.Args["classpath"], fooHeaderJar) {
920		t.Errorf("bar turbine classpath %v does not contain %q", barTurbine.Args["classpath"], fooHeaderJar)
921	}
922	if !strings.Contains(barJavac.Args["classpath"], fooHeaderJar) {
923		t.Errorf("bar javac classpath %v does not contain %q", barJavac.Args["classpath"], fooHeaderJar)
924	}
925	if len(barTurbineCombined.Inputs) != 2 || barTurbineCombined.Inputs[1].String() != fooHeaderJar {
926		t.Errorf("bar turbine combineJar inputs %v does not contain %q", barTurbineCombined.Inputs, fooHeaderJar)
927	}
928	if !strings.Contains(bazJavac.Args["classpath"], "prebuilts/sdk/14/public/android.jar") {
929		t.Errorf("baz javac classpath %v does not contain %q", bazJavac.Args["classpath"],
930			"prebuilts/sdk/14/public/android.jar")
931	}
932}
933
934func TestSharding(t *testing.T) {
935	ctx, _ := testJava(t, `
936		java_library {
937			name: "bar",
938			srcs: ["a.java","b.java","c.java"],
939			javac_shard_size: 1
940		}
941		`)
942
943	barHeaderJar := filepath.Join(buildDir, ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
944	for i := 0; i < 3; i++ {
945		barJavac := ctx.ModuleForTests("bar", "android_common").Description("javac" + strconv.Itoa(i))
946		if !strings.Contains(barJavac.Args["classpath"], barHeaderJar) {
947			t.Errorf("bar javac classpath %v does not contain %q", barJavac.Args["classpath"], barHeaderJar)
948		}
949	}
950}
951
952func TestDroiddoc(t *testing.T) {
953	ctx, _ := testJavaWithFS(t, `
954		droiddoc_exported_dir {
955		    name: "droiddoc-templates-sdk",
956		    path: ".",
957		}
958		filegroup {
959		    name: "bar-doc-aidl-srcs",
960		    srcs: ["bar-doc/IBar.aidl"],
961		    path: "bar-doc",
962		}
963		droiddoc {
964		    name: "bar-doc",
965		    srcs: [
966		        "bar-doc/a.java",
967		        "bar-doc/IFoo.aidl",
968		        ":bar-doc-aidl-srcs",
969		    ],
970		    exclude_srcs: [
971		        "bar-doc/b.java"
972		    ],
973		    custom_template: "droiddoc-templates-sdk",
974		    hdf: [
975		        "android.whichdoc offline",
976		    ],
977		    knowntags: [
978		        "bar-doc/known_oj_tags.txt",
979		    ],
980		    proofread_file: "libcore-proofread.txt",
981		    todo_file: "libcore-docs-todo.html",
982		    args: "-offlinemode -title \"libcore\"",
983		}
984		`,
985		map[string][]byte{
986			"bar-doc/a.java": nil,
987			"bar-doc/b.java": nil,
988		})
989
990	barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc")
991	var javaSrcs []string
992	for _, i := range barDoc.Inputs {
993		javaSrcs = append(javaSrcs, i.Base())
994	}
995	if len(javaSrcs) != 1 || javaSrcs[0] != "a.java" {
996		t.Errorf("inputs of bar-doc must be []string{\"a.java\"}, but was %#v.", javaSrcs)
997	}
998
999	aidl := ctx.ModuleForTests("bar-doc", "android_common").Rule("aidl")
1000	if g, w := barDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) {
1001		t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g)
1002	}
1003
1004	if g, w := aidl.Implicits.Strings(), []string{"bar-doc/IBar.aidl", "bar-doc/IFoo.aidl"}; !reflect.DeepEqual(w, g) {
1005		t.Errorf("aidl inputs must be %q, but was %q", w, g)
1006	}
1007}
1008
1009func TestDroidstubs(t *testing.T) {
1010	ctx, _ := testJavaWithFS(t, `
1011		droiddoc_exported_dir {
1012		    name: "droiddoc-templates-sdk",
1013		    path: ".",
1014		}
1015
1016		droidstubs {
1017		    name: "bar-stubs",
1018		    srcs: [
1019		        "bar-doc/a.java",
1020				],
1021				api_levels_annotations_dirs: [
1022					"droiddoc-templates-sdk",
1023				],
1024				api_levels_annotations_enabled: true,
1025		}
1026
1027		droidstubs {
1028		    name: "bar-stubs-other",
1029		    srcs: [
1030		        "bar-doc/a.java",
1031				],
1032				api_levels_annotations_dirs: [
1033					"droiddoc-templates-sdk",
1034				],
1035				api_levels_annotations_enabled: true,
1036				api_levels_jar_filename: "android.other.jar",
1037		}
1038		`,
1039		map[string][]byte{
1040			"bar-doc/a.java": nil,
1041		})
1042	testcases := []struct {
1043		moduleName          string
1044		expectedJarFilename string
1045	}{
1046		{
1047			moduleName:          "bar-stubs",
1048			expectedJarFilename: "android.jar",
1049		},
1050		{
1051			moduleName:          "bar-stubs-other",
1052			expectedJarFilename: "android.other.jar",
1053		},
1054	}
1055	for _, c := range testcases {
1056		m := ctx.ModuleForTests(c.moduleName, "android_common")
1057		metalava := m.Rule("metalava")
1058		expected := "--android-jar-pattern ./%/public/" + c.expectedJarFilename
1059		if actual := metalava.RuleParams.Command; !strings.Contains(actual, expected) {
1060			t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, actual)
1061		}
1062	}
1063}
1064
1065func TestDroidstubsWithSystemModules(t *testing.T) {
1066	ctx, _ := testJava(t, `
1067		droidstubs {
1068		    name: "stubs-source-system-modules",
1069		    srcs: [
1070		        "bar-doc/a.java",
1071		    ],
1072				sdk_version: "none",
1073				system_modules: "source-system-modules",
1074		}
1075
1076		java_library {
1077				name: "source-jar",
1078		    srcs: [
1079		        "a.java",
1080		    ],
1081		}
1082
1083		java_system_modules {
1084				name: "source-system-modules",
1085				libs: ["source-jar"],
1086		}
1087
1088		droidstubs {
1089		    name: "stubs-prebuilt-system-modules",
1090		    srcs: [
1091		        "bar-doc/a.java",
1092		    ],
1093				sdk_version: "none",
1094				system_modules: "prebuilt-system-modules",
1095		}
1096
1097		java_import {
1098				name: "prebuilt-jar",
1099				jars: ["a.jar"],
1100		}
1101
1102		java_system_modules_import {
1103				name: "prebuilt-system-modules",
1104				libs: ["prebuilt-jar"],
1105		}
1106		`)
1107
1108	checkSystemModulesUseByDroidstubs(t, ctx, "stubs-source-system-modules", "source-jar.jar")
1109
1110	checkSystemModulesUseByDroidstubs(t, ctx, "stubs-prebuilt-system-modules", "prebuilt-jar.jar")
1111}
1112
1113func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, moduleName string, systemJar string) {
1114	metalavaRule := ctx.ModuleForTests(moduleName, "android_common").Rule("metalava")
1115	var systemJars []string
1116	for _, i := range metalavaRule.Implicits {
1117		systemJars = append(systemJars, i.Base())
1118	}
1119	if len(systemJars) < 1 || systemJars[0] != systemJar {
1120		t.Errorf("inputs of %q must be []string{%q}, but was %#v.", moduleName, systemJar, systemJars)
1121	}
1122}
1123
1124func TestJarGenrules(t *testing.T) {
1125	ctx, _ := testJava(t, `
1126		java_library {
1127			name: "foo",
1128			srcs: ["a.java"],
1129		}
1130
1131		java_genrule {
1132			name: "jargen",
1133			tool_files: ["b.java"],
1134			cmd: "$(location b.java) $(in) $(out)",
1135			out: ["jargen.jar"],
1136			srcs: [":foo"],
1137		}
1138
1139		java_library {
1140			name: "bar",
1141			static_libs: ["jargen"],
1142			srcs: ["c.java"],
1143		}
1144
1145		java_library {
1146			name: "baz",
1147			libs: ["jargen"],
1148			srcs: ["c.java"],
1149		}
1150	`)
1151
1152	foo := ctx.ModuleForTests("foo", "android_common").Output("javac/foo.jar")
1153	jargen := ctx.ModuleForTests("jargen", "android_common").Output("jargen.jar")
1154	bar := ctx.ModuleForTests("bar", "android_common").Output("javac/bar.jar")
1155	baz := ctx.ModuleForTests("baz", "android_common").Output("javac/baz.jar")
1156	barCombined := ctx.ModuleForTests("bar", "android_common").Output("combined/bar.jar")
1157
1158	if len(jargen.Inputs) != 1 || jargen.Inputs[0].String() != foo.Output.String() {
1159		t.Errorf("expected jargen inputs [%q], got %q", foo.Output.String(), jargen.Inputs.Strings())
1160	}
1161
1162	if !strings.Contains(bar.Args["classpath"], jargen.Output.String()) {
1163		t.Errorf("bar classpath %v does not contain %q", bar.Args["classpath"], jargen.Output.String())
1164	}
1165
1166	if !strings.Contains(baz.Args["classpath"], jargen.Output.String()) {
1167		t.Errorf("baz classpath %v does not contain %q", baz.Args["classpath"], jargen.Output.String())
1168	}
1169
1170	if len(barCombined.Inputs) != 2 ||
1171		barCombined.Inputs[0].String() != bar.Output.String() ||
1172		barCombined.Inputs[1].String() != jargen.Output.String() {
1173		t.Errorf("bar combined jar inputs %v is not [%q, %q]",
1174			barCombined.Inputs.Strings(), bar.Output.String(), jargen.Output.String())
1175	}
1176}
1177
1178func TestExcludeFileGroupInSrcs(t *testing.T) {
1179	ctx, _ := testJava(t, `
1180		java_library {
1181			name: "foo",
1182			srcs: ["a.java", ":foo-srcs"],
1183			exclude_srcs: ["a.java", ":foo-excludes"],
1184		}
1185
1186		filegroup {
1187			name: "foo-srcs",
1188			srcs: ["java-fg/a.java", "java-fg/b.java", "java-fg/c.java"],
1189		}
1190
1191		filegroup {
1192			name: "foo-excludes",
1193			srcs: ["java-fg/a.java", "java-fg/b.java"],
1194		}
1195	`)
1196
1197	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
1198
1199	if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "java-fg/c.java" {
1200		t.Errorf(`foo inputs %v != ["java-fg/c.java"]`, javac.Inputs)
1201	}
1202}
1203
1204func TestJavaLibrary(t *testing.T) {
1205	config := testConfig(nil, "", map[string][]byte{
1206		"libcore/Android.bp": []byte(`
1207				java_library {
1208						name: "core",
1209						sdk_version: "none",
1210						system_modules: "none",
1211				}`),
1212	})
1213	ctx := testContext()
1214	run(t, ctx, config)
1215}
1216
1217func TestJavaSdkLibrary(t *testing.T) {
1218	ctx, _ := testJava(t, `
1219		droiddoc_exported_dir {
1220			name: "droiddoc-templates-sdk",
1221			path: ".",
1222		}
1223		java_sdk_library {
1224			name: "foo",
1225			srcs: ["a.java", "b.java"],
1226			api_packages: ["foo"],
1227		}
1228		java_sdk_library {
1229			name: "bar",
1230			srcs: ["a.java", "b.java"],
1231			api_packages: ["bar"],
1232		}
1233		java_library {
1234			name: "baz",
1235			srcs: ["c.java"],
1236			libs: ["foo", "bar.stubs"],
1237			sdk_version: "system_current",
1238		}
1239		java_sdk_library {
1240			name: "barney",
1241			srcs: ["c.java"],
1242			api_only: true,
1243		}
1244		java_sdk_library {
1245			name: "betty",
1246			srcs: ["c.java"],
1247			shared_library: false,
1248		}
1249		java_sdk_library_import {
1250		    name: "quuz",
1251				public: {
1252					jars: ["c.jar"],
1253				},
1254		}
1255		java_sdk_library_import {
1256		    name: "fred",
1257				public: {
1258					jars: ["b.jar"],
1259				},
1260		}
1261		java_sdk_library_import {
1262		    name: "wilma",
1263				public: {
1264					jars: ["b.jar"],
1265				},
1266				shared_library: false,
1267		}
1268		java_library {
1269		    name: "qux",
1270		    srcs: ["c.java"],
1271		    libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"],
1272		    sdk_version: "system_current",
1273		}
1274		java_library {
1275			name: "baz-test",
1276			srcs: ["c.java"],
1277			libs: ["foo"],
1278			sdk_version: "test_current",
1279		}
1280		java_library {
1281			name: "baz-29",
1282			srcs: ["c.java"],
1283			libs: ["foo"],
1284			sdk_version: "system_29",
1285		}
1286		`)
1287
1288	// check the existence of the internal modules
1289	ctx.ModuleForTests("foo", "android_common")
1290	ctx.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common")
1291	ctx.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common")
1292	ctx.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common")
1293	ctx.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common")
1294	ctx.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
1295	ctx.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
1296	ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
1297	ctx.ModuleForTests("foo.api.public.28", "")
1298	ctx.ModuleForTests("foo.api.system.28", "")
1299	ctx.ModuleForTests("foo.api.test.28", "")
1300
1301	bazJavac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
1302	// tests if baz is actually linked to the stubs lib
1303	if !strings.Contains(bazJavac.Args["classpath"], "foo.stubs.system.jar") {
1304		t.Errorf("baz javac classpath %v does not contain %q", bazJavac.Args["classpath"],
1305			"foo.stubs.system.jar")
1306	}
1307	// ... and not to the impl lib
1308	if strings.Contains(bazJavac.Args["classpath"], "foo.jar") {
1309		t.Errorf("baz javac classpath %v should not contain %q", bazJavac.Args["classpath"],
1310			"foo.jar")
1311	}
1312	// test if baz is not linked to the system variant of foo
1313	if strings.Contains(bazJavac.Args["classpath"], "foo.stubs.jar") {
1314		t.Errorf("baz javac classpath %v should not contain %q", bazJavac.Args["classpath"],
1315			"foo.stubs.jar")
1316	}
1317
1318	bazTestJavac := ctx.ModuleForTests("baz-test", "android_common").Rule("javac")
1319	// tests if baz-test is actually linked to the test stubs lib
1320	if !strings.Contains(bazTestJavac.Args["classpath"], "foo.stubs.test.jar") {
1321		t.Errorf("baz-test javac classpath %v does not contain %q", bazTestJavac.Args["classpath"],
1322			"foo.stubs.test.jar")
1323	}
1324
1325	baz29Javac := ctx.ModuleForTests("baz-29", "android_common").Rule("javac")
1326	// tests if baz-29 is actually linked to the system 29 stubs lib
1327	if !strings.Contains(baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar") {
1328		t.Errorf("baz-29 javac classpath %v does not contain %q", baz29Javac.Args["classpath"],
1329			"prebuilts/sdk/29/system/foo.jar")
1330	}
1331
1332	// test if baz has exported SDK lib names foo and bar to qux
1333	qux := ctx.ModuleForTests("qux", "android_common")
1334	if quxLib, ok := qux.Module().(*Library); ok {
1335		sdkLibs := quxLib.ExportedSdkLibs()
1336		sort.Strings(sdkLibs)
1337		if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
1338			t.Errorf("qux should export %q but exports %q", w, sdkLibs)
1339		}
1340	}
1341}
1342
1343func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) {
1344	ctx, _ := testJava(t, `
1345		java_sdk_library {
1346			name: "foo",
1347			srcs: ["a.java"],
1348			api_only: true,
1349			public: {
1350				enabled: true,
1351			},
1352		}
1353
1354		java_library {
1355			name: "bar",
1356			srcs: ["b.java"],
1357			libs: ["foo"],
1358		}
1359		`)
1360
1361	// The bar library should depend on the stubs jar.
1362	barLibrary := ctx.ModuleForTests("bar", "android_common").Rule("javac")
1363	if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
1364		t.Errorf("expected %q, found %#q", expected, actual)
1365	}
1366}
1367
1368func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
1369	testJava(t, `
1370		java_sdk_library {
1371			name: "foo",
1372			srcs: ["a.java"],
1373			api_packages: ["foo"],
1374			public: {
1375				enabled: true,
1376			},
1377		}
1378
1379		java_library {
1380			name: "bar",
1381			srcs: ["b.java", ":foo{.public.stubs.source}"],
1382		}
1383		`)
1384}
1385
1386func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) {
1387	testJavaError(t, `"foo" does not provide api scope system`, `
1388		java_sdk_library {
1389			name: "foo",
1390			srcs: ["a.java"],
1391			api_packages: ["foo"],
1392			public: {
1393				enabled: true,
1394			},
1395		}
1396
1397		java_library {
1398			name: "bar",
1399			srcs: ["b.java", ":foo{.system.stubs.source}"],
1400		}
1401		`)
1402}
1403
1404func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
1405	testJava(t, `
1406		java_sdk_library_import {
1407			name: "foo",
1408			public: {
1409				jars: ["a.jar"],
1410				stub_srcs: ["a.java"],
1411				current_api: "api/current.txt",
1412				removed_api: "api/removed.txt",
1413			},
1414		}
1415
1416		java_library {
1417			name: "bar",
1418			srcs: [":foo{.public.stubs.source}"],
1419			java_resources: [
1420				":foo{.public.api.txt}",
1421				":foo{.public.removed-api.txt}",
1422			],
1423		}
1424		`)
1425}
1426
1427func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) {
1428	bp := `
1429		java_sdk_library_import {
1430			name: "foo",
1431			public: {
1432				jars: ["a.jar"],
1433			},
1434		}
1435		`
1436
1437	t.Run("stubs.source", func(t *testing.T) {
1438		testJavaError(t, `stubs.source not available for api scope public`, bp+`
1439		java_library {
1440			name: "bar",
1441			srcs: [":foo{.public.stubs.source}"],
1442			java_resources: [
1443				":foo{.public.api.txt}",
1444				":foo{.public.removed-api.txt}",
1445			],
1446		}
1447		`)
1448	})
1449
1450	t.Run("api.txt", func(t *testing.T) {
1451		testJavaError(t, `api.txt not available for api scope public`, bp+`
1452		java_library {
1453			name: "bar",
1454			srcs: ["a.java"],
1455			java_resources: [
1456				":foo{.public.api.txt}",
1457			],
1458		}
1459		`)
1460	})
1461
1462	t.Run("removed-api.txt", func(t *testing.T) {
1463		testJavaError(t, `removed-api.txt not available for api scope public`, bp+`
1464		java_library {
1465			name: "bar",
1466			srcs: ["a.java"],
1467			java_resources: [
1468				":foo{.public.removed-api.txt}",
1469			],
1470		}
1471		`)
1472	})
1473}
1474
1475func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
1476	testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, `
1477		java_sdk_library {
1478			name: "foo",
1479			srcs: ["a.java", "b.java"],
1480			api_packages: ["foo"],
1481			// Explicitly disable public to test the check that ensures the set of enabled
1482			// scopes is consistent.
1483			public: {
1484				enabled: false,
1485			},
1486			system: {
1487				enabled: true,
1488			},
1489		}
1490		`)
1491}
1492
1493func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) {
1494	testJava(t, `
1495		java_sdk_library {
1496			name: "foo",
1497			srcs: ["a.java", "b.java"],
1498			api_packages: ["foo"],
1499			system: {
1500				enabled: true,
1501				sdk_version: "module_current",
1502			},
1503		}
1504		`)
1505}
1506
1507func TestJavaSdkLibrary_ModuleLib(t *testing.T) {
1508	testJava(t, `
1509		java_sdk_library {
1510			name: "foo",
1511			srcs: ["a.java", "b.java"],
1512			api_packages: ["foo"],
1513			system: {
1514				enabled: true,
1515			},
1516			module_lib: {
1517				enabled: true,
1518			},
1519		}
1520		`)
1521}
1522
1523func TestJavaSdkLibrary_SystemServer(t *testing.T) {
1524	testJava(t, `
1525		java_sdk_library {
1526			name: "foo",
1527			srcs: ["a.java", "b.java"],
1528			api_packages: ["foo"],
1529			system: {
1530				enabled: true,
1531			},
1532			system_server: {
1533				enabled: true,
1534			},
1535		}
1536		`)
1537}
1538
1539func TestJavaSdkLibrary_MissingScope(t *testing.T) {
1540	testJavaError(t, `requires api scope module-lib from foo but it only has \[\] available`, `
1541		java_sdk_library {
1542			name: "foo",
1543			srcs: ["a.java"],
1544			public: {
1545				enabled: false,
1546			},
1547		}
1548
1549		java_library {
1550			name: "baz",
1551			srcs: ["a.java"],
1552			libs: ["foo"],
1553			sdk_version: "module_current",
1554		}
1555		`)
1556}
1557
1558func TestJavaSdkLibrary_FallbackScope(t *testing.T) {
1559	testJava(t, `
1560		java_sdk_library {
1561			name: "foo",
1562			srcs: ["a.java"],
1563			system: {
1564				enabled: true,
1565			},
1566		}
1567
1568		java_library {
1569			name: "baz",
1570			srcs: ["a.java"],
1571			libs: ["foo"],
1572			// foo does not have module-lib scope so it should fallback to system
1573			sdk_version: "module_current",
1574		}
1575		`)
1576}
1577
1578func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) {
1579	ctx, _ := testJava(t, `
1580		java_sdk_library {
1581			name: "foo",
1582			srcs: ["a.java"],
1583			system: {
1584				enabled: true,
1585			},
1586			default_to_stubs: true,
1587		}
1588
1589		java_library {
1590			name: "baz",
1591			srcs: ["a.java"],
1592			libs: ["foo"],
1593			// does not have sdk_version set, should fallback to module,
1594			// which will then fallback to system because the module scope
1595			// is not enabled.
1596		}
1597		`)
1598	// The baz library should depend on the system stubs jar.
1599	bazLibrary := ctx.ModuleForTests("baz", "android_common").Rule("javac")
1600	if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
1601		t.Errorf("expected %q, found %#q", expected, actual)
1602	}
1603}
1604
1605var compilerFlagsTestCases = []struct {
1606	in  string
1607	out bool
1608}{
1609	{
1610		in:  "a",
1611		out: false,
1612	},
1613	{
1614		in:  "-a",
1615		out: true,
1616	},
1617	{
1618		in:  "-no-jdk",
1619		out: false,
1620	},
1621	{
1622		in:  "-no-stdlib",
1623		out: false,
1624	},
1625	{
1626		in:  "-kotlin-home",
1627		out: false,
1628	},
1629	{
1630		in:  "-kotlin-home /some/path",
1631		out: false,
1632	},
1633	{
1634		in:  "-include-runtime",
1635		out: false,
1636	},
1637	{
1638		in:  "-Xintellij-plugin-root",
1639		out: false,
1640	},
1641}
1642
1643type mockContext struct {
1644	android.ModuleContext
1645	result bool
1646}
1647
1648func (ctx *mockContext) PropertyErrorf(property, format string, args ...interface{}) {
1649	// CheckBadCompilerFlags calls this function when the flag should be rejected
1650	ctx.result = false
1651}
1652
1653func TestCompilerFlags(t *testing.T) {
1654	for _, testCase := range compilerFlagsTestCases {
1655		ctx := &mockContext{result: true}
1656		CheckKotlincFlags(ctx, []string{testCase.in})
1657		if ctx.result != testCase.out {
1658			t.Errorf("incorrect output:")
1659			t.Errorf("     input: %#v", testCase.in)
1660			t.Errorf("  expected: %#v", testCase.out)
1661			t.Errorf("       got: %#v", ctx.result)
1662		}
1663	}
1664}
1665
1666// TODO(jungjw): Consider making this more robust by ignoring path order.
1667func checkPatchModuleFlag(t *testing.T, ctx *android.TestContext, moduleName string, expected string) {
1668	variables := ctx.ModuleForTests(moduleName, "android_common").Module().VariablesForTests()
1669	flags := strings.Split(variables["javacFlags"], " ")
1670	got := ""
1671	for _, flag := range flags {
1672		keyEnd := strings.Index(flag, "=")
1673		if keyEnd > -1 && flag[:keyEnd] == "--patch-module" {
1674			got = flag[keyEnd+1:]
1675			break
1676		}
1677	}
1678	if expected != got {
1679		t.Errorf("Unexpected patch-module flag for module %q - expected %q, but got %q", moduleName, expected, got)
1680	}
1681}
1682
1683func TestPatchModule(t *testing.T) {
1684	t.Run("Java language level 8", func(t *testing.T) {
1685		// Test with legacy javac -source 1.8 -target 1.8
1686		bp := `
1687			java_library {
1688				name: "foo",
1689				srcs: ["a.java"],
1690				java_version: "1.8",
1691			}
1692
1693			java_library {
1694				name: "bar",
1695				srcs: ["b.java"],
1696				sdk_version: "none",
1697				system_modules: "none",
1698				patch_module: "java.base",
1699				java_version: "1.8",
1700			}
1701
1702			java_library {
1703				name: "baz",
1704				srcs: ["c.java"],
1705				patch_module: "java.base",
1706				java_version: "1.8",
1707			}
1708		`
1709		ctx, _ := testJava(t, bp)
1710
1711		checkPatchModuleFlag(t, ctx, "foo", "")
1712		checkPatchModuleFlag(t, ctx, "bar", "")
1713		checkPatchModuleFlag(t, ctx, "baz", "")
1714	})
1715
1716	t.Run("Java language level 9", func(t *testing.T) {
1717		// Test with default javac -source 9 -target 9
1718		bp := `
1719			java_library {
1720				name: "foo",
1721				srcs: ["a.java"],
1722			}
1723
1724			java_library {
1725				name: "bar",
1726				srcs: ["b.java"],
1727				sdk_version: "none",
1728				system_modules: "none",
1729				patch_module: "java.base",
1730			}
1731
1732			java_library {
1733				name: "baz",
1734				srcs: ["c.java"],
1735				patch_module: "java.base",
1736			}
1737		`
1738		ctx, _ := testJava(t, bp)
1739
1740		checkPatchModuleFlag(t, ctx, "foo", "")
1741		expected := "java.base=.:" + buildDir
1742		checkPatchModuleFlag(t, ctx, "bar", expected)
1743		expected = "java.base=" + strings.Join([]string{".", buildDir, moduleToPath("ext"), moduleToPath("framework")}, ":")
1744		checkPatchModuleFlag(t, ctx, "baz", expected)
1745	})
1746}
1747
1748func TestJavaSystemModules(t *testing.T) {
1749	ctx, _ := testJava(t, `
1750		java_system_modules {
1751			name: "system-modules",
1752			libs: ["system-module1", "system-module2"],
1753		}
1754		java_library {
1755			name: "system-module1",
1756			srcs: ["a.java"],
1757			sdk_version: "none",
1758			system_modules: "none",
1759		}
1760		java_library {
1761			name: "system-module2",
1762			srcs: ["b.java"],
1763			sdk_version: "none",
1764			system_modules: "none",
1765		}
1766		`)
1767
1768	// check the existence of the module
1769	systemModules := ctx.ModuleForTests("system-modules", "android_common")
1770
1771	cmd := systemModules.Rule("jarsTosystemModules")
1772
1773	// make sure the command compiles against the supplied modules.
1774	for _, module := range []string{"system-module1.jar", "system-module2.jar"} {
1775		if !strings.Contains(cmd.Args["classpath"], module) {
1776			t.Errorf("system modules classpath %v does not contain %q", cmd.Args["classpath"],
1777				module)
1778		}
1779	}
1780}
1781
1782func TestJavaSystemModulesImport(t *testing.T) {
1783	ctx, _ := testJava(t, `
1784		java_system_modules_import {
1785			name: "system-modules",
1786			libs: ["system-module1", "system-module2"],
1787		}
1788		java_import {
1789			name: "system-module1",
1790			jars: ["a.jar"],
1791		}
1792		java_import {
1793			name: "system-module2",
1794			jars: ["b.jar"],
1795		}
1796		`)
1797
1798	// check the existence of the module
1799	systemModules := ctx.ModuleForTests("system-modules", "android_common")
1800
1801	cmd := systemModules.Rule("jarsTosystemModules")
1802
1803	// make sure the command compiles against the supplied modules.
1804	for _, module := range []string{"system-module1.jar", "system-module2.jar"} {
1805		if !strings.Contains(cmd.Args["classpath"], module) {
1806			t.Errorf("system modules classpath %v does not contain %q", cmd.Args["classpath"],
1807				module)
1808		}
1809	}
1810}
1811
1812func TestJavaLibraryWithSystemModules(t *testing.T) {
1813	ctx, _ := testJava(t, `
1814		java_library {
1815		    name: "lib-with-source-system-modules",
1816		    srcs: [
1817		        "a.java",
1818		    ],
1819				sdk_version: "none",
1820				system_modules: "source-system-modules",
1821		}
1822
1823		java_library {
1824				name: "source-jar",
1825		    srcs: [
1826		        "a.java",
1827		    ],
1828		}
1829
1830		java_system_modules {
1831				name: "source-system-modules",
1832				libs: ["source-jar"],
1833		}
1834
1835		java_library {
1836		    name: "lib-with-prebuilt-system-modules",
1837		    srcs: [
1838		        "a.java",
1839		    ],
1840				sdk_version: "none",
1841				system_modules: "prebuilt-system-modules",
1842		}
1843
1844		java_import {
1845				name: "prebuilt-jar",
1846				jars: ["a.jar"],
1847		}
1848
1849		java_system_modules_import {
1850				name: "prebuilt-system-modules",
1851				libs: ["prebuilt-jar"],
1852		}
1853		`)
1854
1855	checkBootClasspathForSystemModule(t, ctx, "lib-with-source-system-modules", "/source-jar.jar")
1856
1857	checkBootClasspathForSystemModule(t, ctx, "lib-with-prebuilt-system-modules", "/prebuilt-jar.jar")
1858}
1859
1860func checkBootClasspathForSystemModule(t *testing.T, ctx *android.TestContext, moduleName string, expectedSuffix string) {
1861	javacRule := ctx.ModuleForTests(moduleName, "android_common").Rule("javac")
1862	bootClasspath := javacRule.Args["bootClasspath"]
1863	if strings.HasPrefix(bootClasspath, "--system ") && strings.HasSuffix(bootClasspath, expectedSuffix) {
1864		t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath)
1865	}
1866}
1867