xref: /aosp_15_r20/build/soong/java/sdk_library_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright 2021 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	"path/filepath"
20	"regexp"
21	"strings"
22	"testing"
23
24	"android/soong/android"
25)
26
27func TestJavaSdkLibrary(t *testing.T) {
28	result := android.GroupFixturePreparers(
29		prepareForJavaTest,
30		PrepareForTestWithJavaSdkLibraryFiles,
31		FixtureWithPrebuiltApis(map[string][]string{
32			"28": {"foo"},
33			"29": {"foo"},
34			"30": {"bar", "barney", "baz", "betty", "foo", "fred", "quuz", "wilma"},
35		}),
36		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
37	).RunTestWithBp(t, `
38		droiddoc_exported_dir {
39			name: "droiddoc-templates-sdk",
40			path: ".",
41		}
42		java_sdk_library {
43			name: "foo",
44			srcs: ["a.java", "b.java"],
45			api_packages: ["foo"],
46		}
47		java_sdk_library {
48			name: "bar",
49			srcs: ["a.java", "b.java"],
50			api_packages: ["bar"],
51			exclude_kotlinc_generated_files: true,
52		}
53		java_library {
54			name: "baz",
55			srcs: ["c.java"],
56			libs: ["foo.stubs.system", "bar.stubs"],
57			sdk_version: "system_current",
58		}
59		java_sdk_library {
60			name: "barney",
61			srcs: ["c.java"],
62			api_only: true,
63		}
64		java_sdk_library {
65			name: "betty",
66			srcs: ["c.java"],
67			shared_library: false,
68		}
69		java_sdk_library_import {
70		    name: "quuz",
71				public: {
72					jars: ["c.jar"],
73					current_api: "api/current.txt",
74					removed_api: "api/removed.txt",
75				},
76		}
77		java_sdk_library_import {
78		    name: "fred",
79				public: {
80					jars: ["b.jar"],
81				},
82		}
83		java_sdk_library_import {
84		    name: "wilma",
85				public: {
86					jars: ["b.jar"],
87				},
88				shared_library: false,
89		}
90		java_library {
91		    name: "qux",
92		    srcs: ["c.java"],
93		    libs: ["baz", "fred.stubs", "quuz.stubs", "wilma.stubs", "barney.stubs.system", "betty.stubs.system"],
94		    sdk_version: "system_current",
95		}
96		java_library {
97			name: "baz-test",
98			srcs: ["c.java"],
99			libs: ["foo.stubs.test"],
100			sdk_version: "test_current",
101		}
102		java_library {
103			name: "baz-29",
104			srcs: ["c.java"],
105			libs: ["sdk_system_29_foo"],
106			sdk_version: "system_29",
107		}
108		java_library {
109			name: "baz-module-30",
110			srcs: ["c.java"],
111			libs: ["sdk_module-lib_30_foo"],
112			sdk_version: "module_30",
113		}
114	`)
115
116	// check the existence of the internal modules
117	foo := result.ModuleForTests("foo", "android_common")
118	result.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common")
119	result.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common")
120	result.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common")
121	result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common")
122	result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
123	result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
124	result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo")+".api.contribution", "")
125	result.ModuleForTests(apiScopePublic.apiLibraryModuleName("foo"), "android_common")
126	result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
127	result.ModuleForTests("foo.api.public.28", "")
128	result.ModuleForTests("foo.api.system.28", "")
129	result.ModuleForTests("foo.api.test.28", "")
130
131	exportedComponentsInfo, _ := android.OtherModuleProvider(result, foo.Module(), android.ExportedComponentsInfoProvider)
132	expectedFooExportedComponents := []string{
133		"foo-removed.api.combined.public.latest",
134		"foo-removed.api.combined.system.latest",
135		"foo.api.combined.public.latest",
136		"foo.api.combined.system.latest",
137		"foo.stubs",
138		"foo.stubs.exportable",
139		"foo.stubs.exportable.system",
140		"foo.stubs.exportable.test",
141		"foo.stubs.source",
142		"foo.stubs.source.system",
143		"foo.stubs.source.test",
144		"foo.stubs.system",
145		"foo.stubs.test",
146	}
147	android.AssertArrayString(t, "foo exported components", expectedFooExportedComponents, exportedComponentsInfo.Components)
148
149	bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac")
150	// tests if baz is actually linked to the stubs lib
151	android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.system.jar")
152	// ... and not to the impl lib
153	android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.jar")
154	// test if baz is not linked to the system variant of foo
155	android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.jar")
156
157	bazTestJavac := result.ModuleForTests("baz-test", "android_common").Rule("javac")
158	// tests if baz-test is actually linked to the test stubs lib
159	android.AssertStringDoesContain(t, "baz-test javac classpath", bazTestJavac.Args["classpath"], "foo.stubs.test.jar")
160
161	baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac")
162	// tests if baz-29 is actually linked to the system 29 stubs lib
163	android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/sdk_system_29_foo/android_common/combined/sdk_system_29_foo.jar")
164
165	bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac")
166	// tests if "baz-module-30" is actually linked to the module 30 stubs lib
167	android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/sdk_module-lib_30_foo/android_common/combined/sdk_module-lib_30_foo.jar")
168
169	// test if baz has exported SDK lib names foo and bar to qux
170	qux := result.ModuleForTests("qux", "android_common")
171	if quxLib, ok := qux.Module().(*Library); ok {
172		requiredSdkLibs, optionalSdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
173		android.AssertDeepEquals(t, "qux exports (required)", []string{"fred", "quuz", "foo", "bar"}, requiredSdkLibs)
174		android.AssertDeepEquals(t, "qux exports (optional)", []string{}, optionalSdkLibs)
175	}
176
177	// test if quuz have created the api_contribution module
178	result.ModuleForTests(apiScopePublic.stubsSourceModuleName("quuz")+".api.contribution", "")
179
180	fooImplDexJar := result.ModuleForTests("foo.impl", "android_common").Rule("d8")
181	// tests if kotlinc generated files are NOT excluded from output of foo.impl.
182	android.AssertStringDoesNotContain(t, "foo.impl dex", fooImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module")
183
184	barImplDexJar := result.ModuleForTests("bar.impl", "android_common").Rule("d8")
185	// tests if kotlinc generated files are excluded from output of bar.impl.
186	android.AssertStringDoesContain(t, "bar.impl dex", barImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module")
187}
188
189func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) {
190	result := android.GroupFixturePreparers(
191		prepareForJavaTest,
192		PrepareForTestWithJavaSdkLibraryFiles,
193		FixtureWithPrebuiltApis(map[string][]string{
194			"28": {"foo"},
195			"29": {"foo"},
196			"30": {"foo", "fooUpdatable", "fooUpdatableErr"},
197		}),
198		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
199			variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V", "W", "X"}
200		}),
201	).RunTestWithBp(t,
202		`
203		java_sdk_library {
204			name: "fooUpdatable",
205			srcs: ["a.java", "b.java"],
206			api_packages: ["foo"],
207			on_bootclasspath_since: "U",
208			on_bootclasspath_before: "V",
209			min_device_sdk: "W",
210			max_device_sdk: "X",
211			min_sdk_version: "S",
212		}
213		java_sdk_library {
214			name: "foo",
215			srcs: ["a.java", "b.java"],
216			api_packages: ["foo"],
217		}
218`)
219
220	// test that updatability attributes are passed on correctly
221	fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Output("fooUpdatable.xml")
222	fooUpdatableContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooUpdatable)
223	android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `on-bootclasspath-since="U"`)
224	android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `on-bootclasspath-before="V"`)
225	android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `min-device-sdk="W"`)
226	android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `max-device-sdk="X"`)
227
228	// double check that updatability attributes are not written if they don't exist in the bp file
229	// the permissions file for the foo library defined above
230	fooPermissions := result.ModuleForTests("foo.xml", "android_common").Output("foo.xml")
231	fooPermissionsContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooPermissions)
232	android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `on-bootclasspath-since`)
233	android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `on-bootclasspath-before`)
234	android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `min-device-sdk`)
235	android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `max-device-sdk`)
236}
237
238func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) {
239	android.GroupFixturePreparers(
240		prepareForJavaTest,
241		PrepareForTestWithJavaSdkLibraryFiles,
242		FixtureWithPrebuiltApis(map[string][]string{
243			"30": {"fooUpdatable", "fooUpdatableErr"},
244		}),
245	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
246		[]string{
247			`on_bootclasspath_since: "aaa" could not be parsed as an integer and is not a recognized codename`,
248			`on_bootclasspath_before: "bbc" could not be parsed as an integer and is not a recognized codename`,
249			`min_device_sdk: "ccc" could not be parsed as an integer and is not a recognized codename`,
250			`max_device_sdk: "current" is not an allowed value for this attribute`,
251		})).RunTestWithBp(t,
252		`
253	java_sdk_library {
254			name: "fooUpdatableErr",
255			srcs: ["a.java", "b.java"],
256			api_packages: ["foo"],
257			on_bootclasspath_since: "aaa",
258			on_bootclasspath_before: "bbc",
259			min_device_sdk: "ccc",
260			max_device_sdk: "current",
261		}
262`)
263}
264
265func TestJavaSdkLibrary_UpdatableLibrary_Validation_AtLeastTAttributes(t *testing.T) {
266	android.GroupFixturePreparers(
267		prepareForJavaTest,
268		PrepareForTestWithJavaSdkLibraryFiles,
269		FixtureWithPrebuiltApis(map[string][]string{
270			"28": {"foo"},
271		}),
272	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
273		[]string{
274			"on_bootclasspath_since: Attribute value needs to be at least T",
275			"on_bootclasspath_before: Attribute value needs to be at least T",
276			"min_device_sdk: Attribute value needs to be at least T",
277			"max_device_sdk: Attribute value needs to be at least T",
278		},
279	)).RunTestWithBp(t,
280		`
281		java_sdk_library {
282			name: "foo",
283			srcs: ["a.java", "b.java"],
284			api_packages: ["foo"],
285			on_bootclasspath_since: "S",
286			on_bootclasspath_before: "S",
287			min_device_sdk: "S",
288			max_device_sdk: "S",
289			min_sdk_version: "S",
290		}
291`)
292}
293
294func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdk(t *testing.T) {
295	android.GroupFixturePreparers(
296		prepareForJavaTest,
297		PrepareForTestWithJavaSdkLibraryFiles,
298		FixtureWithPrebuiltApis(map[string][]string{
299			"28": {"foo"},
300		}),
301		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
302			variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"}
303		}),
304	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
305		[]string{
306			"min_device_sdk can't be greater than max_device_sdk",
307		},
308	)).RunTestWithBp(t,
309		`
310		java_sdk_library {
311			name: "foo",
312			srcs: ["a.java", "b.java"],
313			api_packages: ["foo"],
314			min_device_sdk: "V",
315			max_device_sdk: "U",
316			min_sdk_version: "S",
317		}
318`)
319}
320
321func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdkAndModuleMinSdk(t *testing.T) {
322	android.GroupFixturePreparers(
323		prepareForJavaTest,
324		PrepareForTestWithJavaSdkLibraryFiles,
325		FixtureWithPrebuiltApis(map[string][]string{
326			"28": {"foo"},
327		}),
328		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
329			variables.Platform_version_active_codenames = []string{"Tiramisu", "U", "V"}
330		}),
331	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(
332		[]string{
333			regexp.QuoteMeta("min_device_sdk: Can't be less than module's min sdk (V)"),
334			regexp.QuoteMeta("max_device_sdk: Can't be less than module's min sdk (V)"),
335		},
336	)).RunTestWithBp(t,
337		`
338		java_sdk_library {
339			name: "foo",
340			srcs: ["a.java", "b.java"],
341			api_packages: ["foo"],
342			min_device_sdk: "U",
343			max_device_sdk: "U",
344			min_sdk_version: "V",
345		}
346`)
347}
348
349func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) {
350	result := android.GroupFixturePreparers(
351		prepareForJavaTest,
352		PrepareForTestWithJavaSdkLibraryFiles,
353		FixtureWithPrebuiltApis(map[string][]string{
354			"30": {"foo"},
355		}),
356	).RunTestWithBp(t,
357		`
358		java_sdk_library {
359			name: "foo",
360			srcs: ["a.java", "b.java"],
361			min_device_sdk: "Tiramisu",
362			min_sdk_version: "S",
363		}
364`)
365	// test that updatability attributes are passed on correctly
366	fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Output("foo.xml")
367	fooUpdatableContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooUpdatable)
368	android.AssertStringDoesContain(t, "foo.xml contents", fooUpdatableContents, `<apex-library`)
369	android.AssertStringDoesNotContain(t, "foo.xml contents", fooUpdatableContents, `<library`)
370}
371
372func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
373	result := android.GroupFixturePreparers(
374		prepareForJavaTest,
375		PrepareForTestWithJavaSdkLibraryFiles,
376		FixtureWithLastReleaseApis("sdklib"),
377	).RunTestWithBp(t, `
378		java_sdk_library {
379			name: "sdklib",
380			srcs: ["a.java"],
381			libs: ["lib"],
382			static_libs: ["static-lib"],
383			impl_only_libs: ["impl-only-lib"],
384			stub_only_libs: ["stub-only-lib"],
385			stub_only_static_libs: ["stub-only-static-lib"],
386		}
387		java_defaults {
388			name: "defaults",
389			srcs: ["a.java"],
390			sdk_version: "current",
391		}
392		java_library { name: "lib", defaults: ["defaults"] }
393		java_library { name: "static-lib", defaults: ["defaults"] }
394		java_library { name: "impl-only-lib", defaults: ["defaults"] }
395		java_library { name: "stub-only-lib", defaults: ["defaults"] }
396		java_library { name: "stub-only-static-lib", defaults: ["defaults"] }
397		`)
398	var expectations = []struct {
399		lib               string
400		on_impl_classpath bool
401		on_stub_classpath bool
402		in_impl_combined  bool
403		in_stub_combined  bool
404	}{
405		{lib: "lib", on_impl_classpath: true},
406		{lib: "static-lib", in_impl_combined: true},
407		{lib: "impl-only-lib", on_impl_classpath: true},
408		{lib: "stub-only-lib", on_stub_classpath: true},
409		{lib: "stub-only-static-lib", in_stub_combined: true},
410	}
411	verify := func(sdklib, dep string, cp, combined bool) {
412		sdklibCp := result.ModuleForTests(sdklib, "android_common").Rule("javac").Args["classpath"]
413		expected := cp || combined // Every combined jar is also on the classpath.
414		android.AssertStringContainsEquals(t, "bad classpath for "+sdklib, sdklibCp, "/"+dep+".jar", expected)
415
416		combineJarInputs := result.ModuleForTests(sdklib, "android_common").Rule("combineJar").Inputs.Strings()
417		depPath := filepath.Join("out", "soong", ".intermediates", dep, "android_common", "turbine-combined", dep+".jar")
418		android.AssertStringListContainsEquals(t, "bad combined inputs for "+sdklib, combineJarInputs, depPath, combined)
419	}
420	for _, expectation := range expectations {
421		verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
422
423		stubName := apiScopePublic.sourceStubsLibraryModuleName("sdklib")
424		verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined)
425	}
426}
427
428func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) {
429	result := android.GroupFixturePreparers(
430		prepareForJavaTest,
431		PrepareForTestWithJavaSdkLibraryFiles,
432		FixtureWithLastReleaseApis("foo"),
433	).RunTestWithBp(t, `
434		java_sdk_library {
435			name: "foo",
436			srcs: ["a.java"],
437			api_only: true,
438			public: {
439				enabled: true,
440			},
441		}
442
443		java_library {
444			name: "bar",
445			srcs: ["b.java"],
446			libs: ["foo.stubs"],
447		}
448		`)
449
450	// The bar library should depend on the stubs jar.
451	barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac")
452	if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
453		t.Errorf("expected %q, found %#q", expected, actual)
454	}
455}
456
457func TestJavaSdkLibrary_AccessOutputFiles(t *testing.T) {
458	android.GroupFixturePreparers(
459		prepareForJavaTest,
460		PrepareForTestWithJavaSdkLibraryFiles,
461		FixtureWithLastReleaseApis("foo"),
462	).RunTestWithBp(t, `
463		java_sdk_library {
464			name: "foo",
465			srcs: ["a.java"],
466			api_packages: ["foo"],
467			annotations_enabled: true,
468			public: {
469				enabled: true,
470			},
471		}
472		java_library {
473			name: "bar",
474			srcs: ["b.java", ":foo{.public.stubs.source}"],
475			java_resources: [":foo{.public.annotations.zip}"],
476		}
477		`)
478}
479
480func TestJavaSdkLibrary_AccessOutputFiles_NoAnnotations(t *testing.T) {
481	android.GroupFixturePreparers(
482		prepareForJavaTest,
483		PrepareForTestWithJavaSdkLibraryFiles,
484		FixtureWithLastReleaseApis("foo"),
485	).
486		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "bar" variant "android_common": unsupported module reference tag ".public.annotations.zip"`)).
487		RunTestWithBp(t, `
488		java_sdk_library {
489			name: "foo",
490			srcs: ["a.java"],
491			api_packages: ["foo"],
492			public: {
493				enabled: true,
494			},
495		}
496
497		java_library {
498			name: "bar",
499			srcs: ["b.java", ":foo{.public.stubs.source}"],
500			java_resources: [":foo{.public.annotations.zip}"],
501		}
502		`)
503}
504
505func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) {
506	android.GroupFixturePreparers(
507		prepareForJavaTest,
508		PrepareForTestWithJavaSdkLibraryFiles,
509		FixtureWithLastReleaseApis("foo"),
510	).
511		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "bar" variant "android_common": unsupported module reference tag ".system.stubs.source"`)).
512		RunTestWithBp(t, `
513		java_sdk_library {
514			name: "foo",
515			srcs: ["a.java"],
516			api_packages: ["foo"],
517			public: {
518				enabled: true,
519			},
520		}
521
522		java_library {
523			name: "bar",
524			srcs: ["b.java", ":foo{.system.stubs.source}"],
525		}
526		`)
527}
528
529func TestJavaSdkLibrary_Deps(t *testing.T) {
530	result := android.GroupFixturePreparers(
531		prepareForJavaTest,
532		PrepareForTestWithJavaSdkLibraryFiles,
533		FixtureWithLastReleaseApis("sdklib"),
534		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
535	).RunTestWithBp(t, `
536		java_sdk_library {
537			name: "sdklib",
538			srcs: ["a.java"],
539			sdk_version: "none",
540			system_modules: "none",
541			public: {
542				enabled: true,
543			},
544		}
545		`)
546
547	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
548		`dex2oatd`,
549		`sdklib-removed.api.combined.public.latest`,
550		`sdklib.api.combined.public.latest`,
551		`sdklib.impl`,
552		`sdklib.stubs`,
553		`sdklib.stubs.exportable`,
554		`sdklib.stubs.source`,
555		`sdklib.xml`,
556	})
557}
558
559func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
560	prepareForJavaTest.RunTestWithBp(t, `
561		java_sdk_library_import {
562			name: "foo",
563			public: {
564				jars: ["a.jar"],
565				stub_srcs: ["a.java"],
566				current_api: "api/current.txt",
567				removed_api: "api/removed.txt",
568				annotations: "x/annotations.zip",
569			},
570		}
571
572		java_library {
573			name: "bar",
574			srcs: [":foo{.public.stubs.source}"],
575			java_resources: [
576				":foo{.public.api.txt}",
577				":foo{.public.removed-api.txt}",
578				":foo{.public.annotations.zip}",
579			],
580		}
581		`)
582}
583
584func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) {
585	bp := `
586		java_sdk_library_import {
587			name: "foo",
588			public: {
589				jars: ["a.jar"],
590			},
591		}
592		`
593
594	t.Run("stubs.source", func(t *testing.T) {
595		prepareForJavaTest.
596			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo" is not a SourceFileProducer or having valid output file for tag ".public.stubs.source"`)).
597			RunTestWithBp(t, bp+`
598				java_library {
599					name: "bar",
600					srcs: [":foo{.public.stubs.source}"],
601					java_resources: [
602						":foo{.public.api.txt}",
603						":foo{.public.removed-api.txt}",
604					],
605				}
606			`)
607	})
608
609	t.Run("api.txt", func(t *testing.T) {
610		prepareForJavaTest.
611			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo" is not a SourceFileProducer or having valid output file for tag ".public.api.txt"`)).
612			RunTestWithBp(t, bp+`
613				java_library {
614					name: "bar",
615					srcs: ["a.java"],
616					java_resources: [
617						":foo{.public.api.txt}",
618					],
619				}
620			`)
621	})
622
623	t.Run("removed-api.txt", func(t *testing.T) {
624		prepareForJavaTest.
625			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo" is not a SourceFileProducer or having valid output file for tag ".public.removed-api.txt"`)).
626			RunTestWithBp(t, bp+`
627				java_library {
628					name: "bar",
629					srcs: ["a.java"],
630					java_resources: [
631						":foo{.public.removed-api.txt}",
632					],
633				}
634			`)
635	})
636}
637
638func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
639	prepareForJavaTest.
640		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": enabled api scope "system" depends on disabled scope "public"`)).
641		RunTestWithBp(t, `
642			java_sdk_library {
643				name: "foo",
644				srcs: ["a.java", "b.java"],
645				api_packages: ["foo"],
646				// Explicitly disable public to test the check that ensures the set of enabled
647				// scopes is consistent.
648				public: {
649					enabled: false,
650				},
651				system: {
652					enabled: true,
653				},
654			}
655		`)
656}
657
658func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) {
659	android.GroupFixturePreparers(
660		prepareForJavaTest,
661		PrepareForTestWithJavaSdkLibraryFiles,
662		FixtureWithLastReleaseApis("foo"),
663	).RunTestWithBp(t, `
664		java_sdk_library {
665			name: "foo",
666			srcs: ["a.java", "b.java"],
667			api_packages: ["foo"],
668			system: {
669				enabled: true,
670				sdk_version: "module_current",
671			},
672		}
673		`)
674}
675
676func TestJavaSdkLibrary_ModuleLib(t *testing.T) {
677	android.GroupFixturePreparers(
678		prepareForJavaTest,
679		PrepareForTestWithJavaSdkLibraryFiles,
680		FixtureWithLastReleaseApis("foo"),
681	).RunTestWithBp(t, `
682		java_sdk_library {
683			name: "foo",
684			srcs: ["a.java", "b.java"],
685			api_packages: ["foo"],
686			system: {
687				enabled: true,
688			},
689			module_lib: {
690				enabled: true,
691			},
692		}
693		`)
694}
695
696func TestJavaSdkLibrary_SystemServer(t *testing.T) {
697	android.GroupFixturePreparers(
698		prepareForJavaTest,
699		PrepareForTestWithJavaSdkLibraryFiles,
700		FixtureWithLastReleaseApis("foo"),
701	).RunTestWithBp(t, `
702		java_sdk_library {
703			name: "foo",
704			srcs: ["a.java", "b.java"],
705			api_packages: ["foo"],
706			system: {
707				enabled: true,
708			},
709			system_server: {
710				enabled: true,
711			},
712		}
713		`)
714}
715
716func TestJavaSdkLibrary_SystemServer_AccessToStubScopeLibs(t *testing.T) {
717	result := android.GroupFixturePreparers(
718		prepareForJavaTest,
719		PrepareForTestWithJavaSdkLibraryFiles,
720		FixtureWithLastReleaseApis("foo-public", "foo-system", "foo-module-lib", "foo-system-server"),
721	).RunTestWithBp(t, `
722		java_sdk_library {
723			name: "foo-public",
724			srcs: ["a.java"],
725			api_packages: ["foo"],
726			public: {
727				enabled: true,
728			},
729		}
730
731		java_sdk_library {
732			name: "foo-system",
733			srcs: ["a.java"],
734			api_packages: ["foo"],
735			system: {
736				enabled: true,
737			},
738		}
739
740		java_sdk_library {
741			name: "foo-module-lib",
742			srcs: ["a.java"],
743			api_packages: ["foo"],
744			system: {
745				enabled: true,
746			},
747			module_lib: {
748				enabled: true,
749			},
750		}
751
752		java_sdk_library {
753			name: "foo-system-server",
754			srcs: ["a.java"],
755			api_packages: ["foo"],
756			system_server: {
757				enabled: true,
758			},
759		}
760
761		java_library {
762			name: "bar",
763			srcs: ["a.java"],
764			libs: ["foo-public.stubs", "foo-system.stubs.system", "foo-module-lib.stubs.module_lib", "foo-system-server.stubs.system_server"],
765			sdk_version: "system_server_current",
766		}
767		`)
768
769	stubsPath := func(name string, scope *apiScope) string {
770		name = scope.stubsLibraryModuleName(name)
771		return fmt.Sprintf("out/soong/.intermediates/%[1]s/android_common/turbine-combined/%[1]s.jar", name)
772	}
773
774	// The bar library should depend on the highest (where system server is highest and public is
775	// lowest) API scopes provided by each of the foo-* modules. The highest API scope provided by the
776	// foo-<x> module is <x>.
777	barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac")
778	stubLibraries := []string{
779		stubsPath("foo-public", apiScopePublic),
780		stubsPath("foo-system", apiScopeSystem),
781		stubsPath("foo-module-lib", apiScopeModuleLib),
782		stubsPath("foo-system-server", apiScopeSystemServer),
783	}
784	expectedPattern := fmt.Sprintf(`^-classpath .*:\Q%s\E$`, strings.Join(stubLibraries, ":"))
785	if expected, actual := expectedPattern, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
786		t.Errorf("expected pattern %q to match %#q", expected, actual)
787	}
788}
789
790func TestJavaSdkLibraryImport(t *testing.T) {
791	result := prepareForJavaTest.RunTestWithBp(t, `
792		java_library {
793			name: "foo",
794			srcs: ["a.java"],
795			libs: ["sdklib.stubs"],
796			sdk_version: "current",
797		}
798
799		java_library {
800			name: "foo.system",
801			srcs: ["a.java"],
802			libs: ["sdklib.stubs.system"],
803			sdk_version: "system_current",
804		}
805
806		java_library {
807			name: "foo.test",
808			srcs: ["a.java"],
809			libs: ["sdklib.stubs.test"],
810			sdk_version: "test_current",
811		}
812
813		java_sdk_library_import {
814			name: "sdklib",
815			public: {
816				jars: ["a.jar"],
817			},
818			system: {
819				jars: ["b.jar"],
820			},
821			test: {
822				jars: ["c.jar"],
823				stub_srcs: ["c.java"],
824			},
825		}
826		`)
827
828	for _, scope := range []string{"", ".system", ".test"} {
829		fooModule := result.ModuleForTests("foo"+scope, "android_common")
830		javac := fooModule.Rule("javac")
831
832		sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Output("combined/sdklib.stubs" + scope + ".jar").Output
833		android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String())
834	}
835
836	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
837		`all_apex_contributions`,
838		`dex2oatd`,
839		`prebuilt_sdklib.stubs`,
840		`prebuilt_sdklib.stubs.source.test`,
841		`prebuilt_sdklib.stubs.system`,
842		`prebuilt_sdklib.stubs.test`,
843	})
844}
845
846func TestJavaSdkLibraryImport_WithSource(t *testing.T) {
847	result := android.GroupFixturePreparers(
848		prepareForJavaTest,
849		PrepareForTestWithJavaSdkLibraryFiles,
850		FixtureWithLastReleaseApis("sdklib"),
851		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
852	).RunTestWithBp(t, `
853		java_sdk_library {
854			name: "sdklib",
855			srcs: ["a.java"],
856			sdk_version: "none",
857			system_modules: "none",
858			public: {
859				enabled: true,
860			},
861		}
862
863		java_sdk_library_import {
864			name: "sdklib",
865			public: {
866				jars: ["a.jar"],
867			},
868		}
869		`)
870
871	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
872		`dex2oatd`,
873		`prebuilt_sdklib`,
874		`sdklib-removed.api.combined.public.latest`,
875		`sdklib.api.combined.public.latest`,
876		`sdklib.impl`,
877		`sdklib.stubs`,
878		`sdklib.stubs.exportable`,
879		`sdklib.stubs.source`,
880		`sdklib.xml`,
881	})
882
883	CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
884		`all_apex_contributions`,
885		`prebuilt_sdklib.stubs`,
886		`sdklib.impl`,
887		// This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
888		// dependency is added after prebuilts may have been renamed and so has to use
889		// the renamed name.
890		`sdklib.xml`,
891	})
892}
893
894func testJavaSdkLibraryImport_Preferred(t *testing.T, prefer string, preparer android.FixturePreparer) {
895	result := android.GroupFixturePreparers(
896		prepareForJavaTest,
897		PrepareForTestWithJavaSdkLibraryFiles,
898		FixtureWithLastReleaseApis("sdklib"),
899		preparer,
900		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
901	).RunTestWithBp(t, `
902		java_sdk_library {
903			name: "sdklib",
904			srcs: ["a.java"],
905			sdk_version: "none",
906			system_modules: "none",
907			public: {
908				enabled: true,
909			},
910		}
911
912		java_sdk_library_import {
913			name: "sdklib",
914			`+prefer+`
915			public: {
916				jars: ["a.jar"],
917				stub_srcs: ["a.java"],
918				current_api: "current.txt",
919				removed_api: "removed.txt",
920				annotations: "annotations.zip",
921			},
922		}
923
924		java_library {
925			name: "combined",
926			static_libs: [
927				"sdklib.stubs",
928			],
929			java_resources: [
930				":sdklib.stubs.source",
931				":sdklib{.public.api.txt}",
932				":sdklib{.public.removed-api.txt}",
933				":sdklib{.public.annotations.zip}",
934			],
935			sdk_version: "none",
936			system_modules: "none",
937		}
938
939		java_library {
940			name: "public",
941			srcs: ["a.java"],
942			libs: ["sdklib.stubs"],
943			sdk_version: "current",
944		}
945		`)
946
947	CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
948		`prebuilt_sdklib`,
949		`sdklib-removed.api.combined.public.latest`,
950		`sdklib.api.combined.public.latest`,
951		`sdklib.impl`,
952		`sdklib.stubs`,
953		`sdklib.stubs.exportable`,
954		`sdklib.stubs.source`,
955		`sdklib.xml`,
956	})
957
958	CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
959		`all_apex_contributions`,
960		`dex2oatd`,
961		`prebuilt_sdklib.stubs`,
962		`prebuilt_sdklib.stubs.source`,
963		`sdklib.impl`,
964		`sdklib.xml`,
965	})
966
967	// Make sure that dependencies on child modules use the prebuilt when preferred.
968	CheckModuleDependencies(t, result.TestContext, "combined", "android_common", []string{
969		// Each use of :sdklib{...} adds a dependency onto prebuilt_sdklib.
970		`prebuilt_sdklib`,
971		`prebuilt_sdklib`,
972		`prebuilt_sdklib`,
973		`prebuilt_sdklib.stubs`,
974		`prebuilt_sdklib.stubs.source`,
975	})
976
977	// Make sure that dependencies on sdklib that resolve to one of the child libraries use the
978	// prebuilt library.
979	public := result.ModuleForTests("public", "android_common")
980	rule := public.Output("javac/public.jar")
981	inputs := rule.Implicits.Strings()
982	expected := "out/soong/.intermediates/prebuilt_sdklib.stubs/android_common/combined/sdklib.stubs.jar"
983	if !android.InList(expected, inputs) {
984		t.Errorf("expected %q to contain %q", inputs, expected)
985	}
986}
987
988func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
989	t.Run("prefer", func(t *testing.T) {
990		testJavaSdkLibraryImport_Preferred(t, "prefer: true,", android.NullFixturePreparer)
991	})
992}
993
994// If a module is listed in `mainline_module_contributions, it should be used
995// It will supersede any other source vs prebuilt selection mechanism like `prefer` attribute
996func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) {
997	bp := `
998		apex_contributions {
999			name: "my_mainline_module_contributions",
1000			api_domain: "my_mainline_module",
1001			contents: [
1002				// legacy mechanism prefers the prebuilt
1003				// mainline_module_contributions supersedes this since source is listed explicitly
1004				"sdklib.prebuilt_preferred_using_legacy_flags",
1005
1006				// legacy mechanism prefers the source
1007				// mainline_module_contributions supersedes this since prebuilt is listed explicitly
1008				"prebuilt_sdklib.source_preferred_using_legacy_flags",
1009			],
1010		}
1011		java_sdk_library {
1012			name: "sdklib.prebuilt_preferred_using_legacy_flags",
1013			srcs: ["a.java"],
1014			sdk_version: "none",
1015			system_modules: "none",
1016			public: {
1017				enabled: true,
1018			},
1019			system: {
1020				enabled: true,
1021			}
1022		}
1023		java_sdk_library_import {
1024			name: "sdklib.prebuilt_preferred_using_legacy_flags",
1025			prefer: true, // prebuilt is preferred using legacy mechanism
1026			public: {
1027				jars: ["a.jar"],
1028				stub_srcs: ["a.java"],
1029				current_api: "current.txt",
1030				removed_api: "removed.txt",
1031				annotations: "annotations.zip",
1032			},
1033			system: {
1034				jars: ["a.jar"],
1035				stub_srcs: ["a.java"],
1036				current_api: "current.txt",
1037				removed_api: "removed.txt",
1038				annotations: "annotations.zip",
1039			},
1040		}
1041		java_sdk_library {
1042			name: "sdklib.source_preferred_using_legacy_flags",
1043			srcs: ["a.java"],
1044			sdk_version: "none",
1045			system_modules: "none",
1046			public: {
1047				enabled: true,
1048			},
1049			system: {
1050				enabled: true,
1051			}
1052		}
1053		java_sdk_library_import {
1054			name: "sdklib.source_preferred_using_legacy_flags",
1055			prefer: false, // source is preferred using legacy mechanism
1056			public: {
1057				jars: ["a.jar"],
1058				stub_srcs: ["a.java"],
1059				current_api: "current.txt",
1060				removed_api: "removed.txt",
1061				annotations: "annotations.zip",
1062			},
1063			system: {
1064				jars: ["a.jar"],
1065				stub_srcs: ["a.java"],
1066				current_api: "current.txt",
1067				removed_api: "removed.txt",
1068				annotations: "annotations.zip",
1069			},
1070		}
1071
1072		// rdeps
1073		java_library {
1074			name: "public",
1075			srcs: ["a.java"],
1076			libs: [
1077				// this should get source since source is listed in my_mainline_module_contributions
1078				"sdklib.prebuilt_preferred_using_legacy_flags.stubs",
1079				"sdklib.prebuilt_preferred_using_legacy_flags.stubs.system",
1080
1081				// this should get prebuilt since source is listed in my_mainline_module_contributions
1082				"sdklib.source_preferred_using_legacy_flags.stubs",
1083				"sdklib.source_preferred_using_legacy_flags.stubs.system",
1084
1085			],
1086		}
1087	`
1088	result := android.GroupFixturePreparers(
1089		prepareForJavaTest,
1090		PrepareForTestWithJavaSdkLibraryFiles,
1091		FixtureWithLastReleaseApis("sdklib.source_preferred_using_legacy_flags", "sdklib.prebuilt_preferred_using_legacy_flags"),
1092		android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ADSERVICES", "my_mainline_module_contributions"),
1093	).RunTestWithBp(t, bp)
1094
1095	// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
1096	public := result.ModuleForTests("public", "android_common")
1097	rule := public.Output("javac/public.jar")
1098	inputs := rule.Implicits.Strings()
1099	expectedInputs := []string{
1100		// source
1101		"out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.jar",
1102		"out/soong/.intermediates/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system/android_common/turbine-combined/sdklib.prebuilt_preferred_using_legacy_flags.stubs.system.jar",
1103
1104		// prebuilt
1105		"out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.jar",
1106		"out/soong/.intermediates/prebuilt_sdklib.source_preferred_using_legacy_flags.stubs.system/android_common/combined/sdklib.source_preferred_using_legacy_flags.stubs.system.jar",
1107	}
1108	for _, expected := range expectedInputs {
1109		if !android.InList(expected, inputs) {
1110			t.Errorf("expected %q to contain %q", inputs, expected)
1111		}
1112	}
1113}
1114
1115func TestJavaSdkLibraryDist(t *testing.T) {
1116	result := android.GroupFixturePreparers(
1117		PrepareForTestWithJavaBuildComponents,
1118		PrepareForTestWithJavaDefaultModules,
1119		PrepareForTestWithJavaSdkLibraryFiles,
1120		FixtureWithLastReleaseApis(
1121			"sdklib_no_group",
1122			"sdklib_group_foo",
1123			"sdklib_owner_foo",
1124			"foo"),
1125		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
1126	).RunTestWithBp(t, `
1127		java_sdk_library {
1128			name: "sdklib_no_group",
1129			srcs: ["foo.java"],
1130		}
1131
1132		java_sdk_library {
1133			name: "sdklib_group_foo",
1134			srcs: ["foo.java"],
1135			dist_group: "foo",
1136		}
1137
1138		java_sdk_library {
1139			name: "sdklib_owner_foo",
1140			srcs: ["foo.java"],
1141			owner: "foo",
1142		}
1143
1144		java_sdk_library {
1145			name: "sdklib_stem_foo",
1146			srcs: ["foo.java"],
1147			dist_stem: "foo",
1148		}
1149	`)
1150
1151	type testCase struct {
1152		module   string
1153		distDir  string
1154		distStem string
1155	}
1156	testCases := []testCase{
1157		{
1158			module:   "sdklib_no_group",
1159			distDir:  "apistubs/unknown/public",
1160			distStem: "sdklib_no_group.jar",
1161		},
1162		{
1163			module:   "sdklib_group_foo",
1164			distDir:  "apistubs/foo/public",
1165			distStem: "sdklib_group_foo.jar",
1166		},
1167		{
1168			// Owner doesn't affect distDir after b/186723288.
1169			module:   "sdklib_owner_foo",
1170			distDir:  "apistubs/unknown/public",
1171			distStem: "sdklib_owner_foo.jar",
1172		},
1173		{
1174			module:   "sdklib_stem_foo",
1175			distDir:  "apistubs/unknown/public",
1176			distStem: "foo.jar",
1177		},
1178	}
1179
1180	for _, tt := range testCases {
1181		t.Run(tt.module, func(t *testing.T) {
1182			m := result.ModuleForTests(apiScopePublic.exportableStubsLibraryModuleName(tt.module), "android_common").Module().(*Library)
1183			dists := m.Dists()
1184			if len(dists) != 1 {
1185				t.Fatalf("expected exactly 1 dist entry, got %d", len(dists))
1186			}
1187			if g, w := String(dists[0].Dir), tt.distDir; g != w {
1188				t.Errorf("expected dist dir %q, got %q", w, g)
1189			}
1190			if g, w := String(dists[0].Dest), tt.distStem; g != w {
1191				t.Errorf("expected dist stem %q, got %q", w, g)
1192			}
1193		})
1194	}
1195}
1196
1197func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) {
1198	preparer := android.GroupFixturePreparers(
1199		PrepareForTestWithJavaBuildComponents,
1200		PrepareForTestWithJavaDefaultModules,
1201		PrepareForTestWithJavaSdkLibraryFiles,
1202	)
1203
1204	preparer.RunTestWithBp(t, `
1205		java_sdk_library {
1206			name: "sdklib",
1207			srcs: ["a.java"],
1208			static_libs: ["util"],
1209			min_sdk_version: "30",
1210			unsafe_ignore_missing_latest_api: true,
1211		}
1212
1213		java_library {
1214			name: "util",
1215			srcs: ["a.java"],
1216			min_sdk_version: "30",
1217		}
1218	`)
1219
1220	preparer.
1221		RunTestWithBp(t, `
1222			java_sdk_library {
1223				name: "sdklib",
1224				srcs: ["a.java"],
1225				libs: ["util"],
1226				impl_only_libs: ["util"],
1227				stub_only_libs: ["util"],
1228				stub_only_static_libs: ["util"],
1229				min_sdk_version: "30",
1230				unsafe_ignore_missing_latest_api: true,
1231			}
1232
1233			java_library {
1234				name: "util",
1235				srcs: ["a.java"],
1236			}
1237		`)
1238
1239	preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "util".*should support min_sdk_version\(30\)`)).
1240		RunTestWithBp(t, `
1241			java_sdk_library {
1242				name: "sdklib",
1243				srcs: ["a.java"],
1244				static_libs: ["util"],
1245				min_sdk_version: "30",
1246				unsafe_ignore_missing_latest_api: true,
1247			}
1248
1249			java_library {
1250				name: "util",
1251				srcs: ["a.java"],
1252				min_sdk_version: "31",
1253			}
1254		`)
1255
1256	preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "another_util".*should support min_sdk_version\(30\)`)).
1257		RunTestWithBp(t, `
1258			java_sdk_library {
1259				name: "sdklib",
1260				srcs: ["a.java"],
1261				static_libs: ["util"],
1262				min_sdk_version: "30",
1263				unsafe_ignore_missing_latest_api: true,
1264			}
1265
1266			java_library {
1267				name: "util",
1268				srcs: ["a.java"],
1269				static_libs: ["another_util"],
1270				min_sdk_version: "30",
1271			}
1272
1273			java_library {
1274				name: "another_util",
1275				srcs: ["a.java"],
1276				min_sdk_version: "31",
1277			}
1278		`)
1279}
1280
1281func TestJavaSdkLibrary_StubOnlyLibs_PassedToDroidstubs(t *testing.T) {
1282	result := android.GroupFixturePreparers(
1283		prepareForJavaTest,
1284		PrepareForTestWithJavaSdkLibraryFiles,
1285		FixtureWithLastReleaseApis("foo"),
1286	).RunTestWithBp(t, `
1287		java_sdk_library {
1288			name: "foo",
1289			srcs: ["a.java"],
1290			public: {
1291				enabled: true,
1292			},
1293			stub_only_libs: ["bar-lib"],
1294		}
1295
1296		java_library {
1297			name: "bar-lib",
1298			srcs: ["b.java"],
1299		}
1300		`)
1301
1302	// The foo.stubs.source should depend on bar-lib
1303	fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
1304	eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
1305	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib")
1306}
1307
1308func TestJavaSdkLibrary_Scope_Libs_PassedToDroidstubs(t *testing.T) {
1309	result := android.GroupFixturePreparers(
1310		prepareForJavaTest,
1311		PrepareForTestWithJavaSdkLibraryFiles,
1312		FixtureWithLastReleaseApis("foo"),
1313	).RunTestWithBp(t, `
1314		java_sdk_library {
1315			name: "foo",
1316			srcs: ["a.java"],
1317			public: {
1318				enabled: true,
1319				libs: ["bar-lib"],
1320			},
1321		}
1322
1323		java_library {
1324			name: "bar-lib",
1325			srcs: ["b.java"],
1326		}
1327		`)
1328
1329	// The foo.stubs.source should depend on bar-lib
1330	fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs)
1331	eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
1332	android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib")
1333}
1334
1335func TestJavaSdkLibrary_ApiLibrary(t *testing.T) {
1336	result := android.GroupFixturePreparers(
1337		prepareForJavaTest,
1338		PrepareForTestWithJavaSdkLibraryFiles,
1339		FixtureWithLastReleaseApis("foo"),
1340	).RunTestWithBp(t, `
1341		java_sdk_library {
1342			name: "foo",
1343			srcs: ["a.java", "b.java"],
1344			api_packages: ["foo"],
1345			system: {
1346				enabled: true,
1347			},
1348			module_lib: {
1349				enabled: true,
1350			},
1351			test: {
1352				enabled: true,
1353			},
1354		}
1355	`)
1356
1357	testCases := []struct {
1358		scope            *apiScope
1359		apiContributions []string
1360	}{
1361		{
1362			scope:            apiScopePublic,
1363			apiContributions: []string{"foo.stubs.source.api.contribution"},
1364		},
1365		{
1366			scope:            apiScopeSystem,
1367			apiContributions: []string{"foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
1368		},
1369		{
1370			scope:            apiScopeTest,
1371			apiContributions: []string{"foo.stubs.source.test.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
1372		},
1373		{
1374			scope:            apiScopeModuleLib,
1375			apiContributions: []string{"foo.stubs.source.module_lib.api.contribution", "foo.stubs.source.system.api.contribution", "foo.stubs.source.api.contribution"},
1376		},
1377	}
1378
1379	for _, c := range testCases {
1380		m := result.ModuleForTests(c.scope.apiLibraryModuleName("foo"), "android_common").Module().(*ApiLibrary)
1381		android.AssertArrayString(t, "Module expected to contain api contributions", c.apiContributions, m.properties.Api_contributions)
1382	}
1383}
1384
1385func TestStaticDepStubLibrariesVisibility(t *testing.T) {
1386	android.GroupFixturePreparers(
1387		prepareForJavaTest,
1388		PrepareForTestWithJavaSdkLibraryFiles,
1389		FixtureWithLastReleaseApis("foo"),
1390		android.FixtureMergeMockFs(
1391			map[string][]byte{
1392				"A.java": nil,
1393				"dir/Android.bp": []byte(
1394					`
1395					java_library {
1396						name: "bar",
1397						srcs: ["A.java"],
1398						libs: ["foo.stubs.from-source"],
1399					}
1400					`),
1401				"dir/A.java": nil,
1402			},
1403		).ExtendWithErrorHandler(
1404			android.FixtureExpectsAtLeastOneErrorMatchingPattern(
1405				`module "bar" variant "android_common": depends on //.:foo.stubs.from-source which is not visible to this module`)),
1406	).RunTestWithBp(t, `
1407		java_sdk_library {
1408			name: "foo",
1409			srcs: ["A.java"],
1410		}
1411	`)
1412}
1413
1414func TestSdkLibraryDependency(t *testing.T) {
1415	result := android.GroupFixturePreparers(
1416		prepareForJavaTest,
1417		PrepareForTestWithJavaSdkLibraryFiles,
1418		FixtureWithPrebuiltApis(map[string][]string{
1419			"30": {"bar", "foo"},
1420		}),
1421	).RunTestWithBp(t,
1422		`
1423		java_sdk_library {
1424			name: "foo",
1425			srcs: ["a.java", "b.java"],
1426			api_packages: ["foo"],
1427		}
1428
1429		java_sdk_library {
1430			name: "bar",
1431			srcs: ["c.java", "b.java"],
1432			libs: [
1433				"foo.stubs",
1434			],
1435			uses_libs: [
1436				"foo",
1437			],
1438		}
1439`)
1440
1441	barPermissions := result.ModuleForTests("bar.xml", "android_common").Output("bar.xml")
1442	barContents := android.ContentFromFileRuleForTests(t, result.TestContext, barPermissions)
1443	android.AssertStringDoesContain(t, "bar.xml java_sdk_xml command", barContents, `dependency="foo"`)
1444}
1445
1446func TestSdkLibraryExportableStubsLibrary(t *testing.T) {
1447	result := android.GroupFixturePreparers(
1448		prepareForJavaTest,
1449		PrepareForTestWithJavaSdkLibraryFiles,
1450		FixtureWithLastReleaseApis("foo"),
1451	).RunTestWithBp(t, `
1452		aconfig_declarations {
1453			name: "bar",
1454			package: "com.example.package",
1455			container: "com.android.foo",
1456			srcs: [
1457				"bar.aconfig",
1458			],
1459		}
1460		java_sdk_library {
1461			name: "foo",
1462			srcs: ["a.java", "b.java"],
1463			api_packages: ["foo"],
1464			system: {
1465				enabled: true,
1466			},
1467			module_lib: {
1468				enabled: true,
1469			},
1470			test: {
1471				enabled: true,
1472			},
1473			aconfig_declarations: [
1474				"bar",
1475			],
1476		}
1477	`)
1478
1479	exportableStubsLibraryModuleName := apiScopePublic.exportableStubsLibraryModuleName("foo")
1480	exportableSourceStubsLibraryModuleName := apiScopePublic.exportableSourceStubsLibraryModuleName("foo")
1481
1482	// Check modules generation
1483	result.ModuleForTests(exportableStubsLibraryModuleName, "android_common")
1484	result.ModuleForTests(exportableSourceStubsLibraryModuleName, "android_common")
1485
1486	// Check static lib dependency
1487	android.AssertBoolEquals(t, "exportable top level stubs library module depends on the"+
1488		"exportable source stubs library module", true,
1489		CheckModuleHasDependencyWithTag(t, result.TestContext, exportableStubsLibraryModuleName,
1490			"android_common", staticLibTag, exportableSourceStubsLibraryModuleName),
1491	)
1492}
1493
1494// For java libraries depending on java_sdk_library(_import) via libs, assert that
1495// rdep gets stubs of source if source is listed in apex_contributions and prebuilt has prefer (legacy mechanism)
1496func TestStubResolutionOfJavaSdkLibraryInLibs(t *testing.T) {
1497	bp := `
1498		apex_contributions {
1499			name: "my_mainline_module_contributions",
1500			api_domain: "my_mainline_module",
1501			contents: ["sdklib"], // source is selected using apex_contributions, but prebuilt is selected using prefer
1502		}
1503		java_sdk_library {
1504			name: "sdklib",
1505			srcs: ["a.java"],
1506			sdk_version: "none",
1507			system_modules: "none",
1508			public: {
1509				enabled: true,
1510			},
1511		}
1512		java_sdk_library_import {
1513			name: "sdklib",
1514			public: {
1515				jars: ["a.jar"],
1516				stub_srcs: ["a.java"],
1517				current_api: "current.txt",
1518				removed_api: "removed.txt",
1519				annotations: "annotations.zip",
1520			},
1521			prefer: true, // Set prefer explicitly on the prebuilt. We will assert that rdep gets source in a test case.
1522		}
1523		// rdeps
1524		java_library {
1525			name: "mymodule",
1526			srcs: ["a.java"],
1527			sdk_version: "current",
1528			libs: ["sdklib.stubs",], // this should be dynamically resolved to sdklib.stubs (source) or prebuilt_sdklib.stubs (prebuilt)
1529		}
1530	`
1531
1532	fixture := android.GroupFixturePreparers(
1533		prepareForJavaTest,
1534		PrepareForTestWithJavaSdkLibraryFiles,
1535		FixtureWithLastReleaseApis("sdklib"),
1536		// We can use any of the apex contribution build flags from build/soong/android/config.go#mainlineApexContributionBuildFlags here
1537		android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ADSERVICES", "my_mainline_module_contributions"),
1538	)
1539
1540	result := fixture.RunTestWithBp(t, bp)
1541	// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
1542	public := result.ModuleForTests("mymodule", "android_common")
1543	rule := public.Output("javac/mymodule.jar")
1544	inputs := rule.Implicits.Strings()
1545	android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, "out/soong/.intermediates/sdklib.stubs/android_common/turbine-combined/sdklib.stubs.jar")
1546}
1547
1548// test that rdep gets resolved to the correct version of a java_sdk_library (source or a specific prebuilt)
1549func TestMultipleSdkLibraryPrebuilts(t *testing.T) {
1550	bp := `
1551		apex_contributions {
1552			name: "my_mainline_module_contributions",
1553			api_domain: "my_mainline_module",
1554			contents: ["%s"],
1555		}
1556		java_sdk_library {
1557			name: "sdklib",
1558			srcs: ["a.java"],
1559			sdk_version: "none",
1560			system_modules: "none",
1561			public: {
1562				enabled: true,
1563			},
1564		}
1565		java_sdk_library_import {
1566			name: "sdklib.v1", //prebuilt
1567			source_module_name: "sdklib",
1568			public: {
1569				jars: ["a.jar"],
1570				stub_srcs: ["a.java"],
1571				current_api: "current.txt",
1572				removed_api: "removed.txt",
1573				annotations: "annotations.zip",
1574			},
1575		}
1576		java_sdk_library_import {
1577			name: "sdklib.v2", //prebuilt
1578			source_module_name: "sdklib",
1579			public: {
1580				jars: ["a.jar"],
1581				stub_srcs: ["a.java"],
1582				current_api: "current.txt",
1583				removed_api: "removed.txt",
1584				annotations: "annotations.zip",
1585			},
1586		}
1587		// rdeps
1588		java_library {
1589			name: "mymodule",
1590			srcs: ["a.java"],
1591			libs: ["sdklib.stubs",],
1592		}
1593	`
1594	testCases := []struct {
1595		desc                   string
1596		selectedDependencyName string
1597		expectedStubPath       string
1598	}{
1599		{
1600			desc:                   "Source library is selected using apex_contributions",
1601			selectedDependencyName: "sdklib",
1602			expectedStubPath:       "out/soong/.intermediates/sdklib.stubs/android_common/turbine-combined/sdklib.stubs.jar",
1603		},
1604		{
1605			desc:                   "Prebuilt library v1 is selected using apex_contributions",
1606			selectedDependencyName: "prebuilt_sdklib.v1",
1607			expectedStubPath:       "out/soong/.intermediates/prebuilt_sdklib.v1.stubs/android_common/combined/sdklib.stubs.jar",
1608		},
1609		{
1610			desc:                   "Prebuilt library v2 is selected using apex_contributions",
1611			selectedDependencyName: "prebuilt_sdklib.v2",
1612			expectedStubPath:       "out/soong/.intermediates/prebuilt_sdklib.v2.stubs/android_common/combined/sdklib.stubs.jar",
1613		},
1614	}
1615
1616	fixture := android.GroupFixturePreparers(
1617		prepareForJavaTest,
1618		PrepareForTestWithJavaSdkLibraryFiles,
1619		FixtureWithLastReleaseApis("sdklib", "sdklib.v1", "sdklib.v2"),
1620		android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ADSERVICES", "my_mainline_module_contributions"),
1621	)
1622
1623	for _, tc := range testCases {
1624		result := fixture.RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName))
1625
1626		// Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions
1627		public := result.ModuleForTests("mymodule", "android_common")
1628		rule := public.Output("javac/mymodule.jar")
1629		inputs := rule.Implicits.Strings()
1630		android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, tc.expectedStubPath)
1631	}
1632}
1633
1634func TestStubLinkType(t *testing.T) {
1635	android.GroupFixturePreparers(
1636		prepareForJavaTest,
1637		PrepareForTestWithJavaSdkLibraryFiles,
1638		FixtureWithLastReleaseApis("foo"),
1639	).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
1640		`module "baz" variant "android_common": compiles against system API, but dependency `+
1641			`"bar.stubs.system" is compiling against module API. In order to fix this, `+
1642			`consider adjusting sdk_version: OR platform_apis: property of the source or `+
1643			`target module so that target module is built with the same or smaller API set `+
1644			`when compared to the source.`),
1645	).RunTestWithBp(t, `
1646		java_sdk_library {
1647			name: "foo",
1648			srcs: ["a.java"],
1649			sdk_version: "current",
1650		}
1651		java_library {
1652			name: "bar.stubs.system",
1653			srcs: ["a.java"],
1654			sdk_version: "module_current",
1655			is_stubs_module: false,
1656		}
1657
1658		java_library {
1659			name: "baz",
1660			srcs: ["b.java"],
1661			libs: [
1662				"foo.stubs.system",
1663				"bar.stubs.system",
1664			],
1665			sdk_version: "system_current",
1666		}
1667		`)
1668}
1669
1670func TestSdkLibDirectDependency(t *testing.T) {
1671	android.GroupFixturePreparers(
1672		prepareForJavaTest,
1673		PrepareForTestWithJavaSdkLibraryFiles,
1674		FixtureWithLastReleaseApis("foo", "bar"),
1675	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{
1676		`module "baz" variant "android_common": cannot depend directly on java_sdk_library ` +
1677			`"foo"; try depending on "foo.stubs", or "foo.impl" instead`,
1678		`module "baz" variant "android_common": cannot depend directly on java_sdk_library ` +
1679			`"prebuilt_bar"; try depending on "bar.stubs", or "bar.impl" instead`,
1680	}),
1681	).RunTestWithBp(t, `
1682		java_sdk_library {
1683			name: "foo",
1684			srcs: ["a.java"],
1685			sdk_version: "current",
1686			public: {
1687				enabled: true,
1688			},
1689		}
1690
1691		java_sdk_library_import {
1692			name: "foo",
1693			public: {
1694				jars: ["a.jar"],
1695				stub_srcs: ["a.java"],
1696				current_api: "current.txt",
1697				removed_api: "removed.txt",
1698				annotations: "annotations.zip",
1699			},
1700		}
1701
1702		java_sdk_library {
1703			name: "bar",
1704			srcs: ["a.java"],
1705			sdk_version: "current",
1706			public: {
1707				enabled: true,
1708			},
1709		}
1710
1711		java_sdk_library_import {
1712			name: "bar",
1713			prefer: true,
1714			public: {
1715				jars: ["a.jar"],
1716				stub_srcs: ["a.java"],
1717				current_api: "current.txt",
1718				removed_api: "removed.txt",
1719				annotations: "annotations.zip",
1720			},
1721		}
1722
1723		java_library {
1724			name: "baz",
1725			srcs: ["b.java"],
1726			libs: [
1727				"foo",
1728				"bar",
1729			],
1730		}
1731	`)
1732}
1733
1734func TestSdkLibDirectDependencyWithPrebuiltSdk(t *testing.T) {
1735	android.GroupFixturePreparers(
1736		prepareForJavaTest,
1737		PrepareForTestWithJavaSdkLibraryFiles,
1738		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
1739			variables.Platform_sdk_version = intPtr(34)
1740			variables.Platform_sdk_codename = stringPtr("VanillaIceCream")
1741			variables.Platform_version_active_codenames = []string{"VanillaIceCream"}
1742			variables.Platform_systemsdk_versions = []string{"33", "34", "VanillaIceCream"}
1743			variables.DeviceSystemSdkVersions = []string{"VanillaIceCream"}
1744		}),
1745		FixtureWithPrebuiltApis(map[string][]string{
1746			"33": {"foo"},
1747			"34": {"foo"},
1748			"35": {"foo"},
1749		}),
1750	).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(
1751		`module "baz" variant "android_common": cannot depend directly on java_sdk_library "foo"; `+
1752			`try depending on "sdk_public_33_foo", "sdk_system_33_foo", "sdk_test_33_foo", `+
1753			`"sdk_module-lib_33_foo", or "sdk_system-server_33_foo" instead`),
1754	).RunTestWithBp(t, `
1755		java_sdk_library {
1756			name: "foo",
1757			srcs: ["a.java"],
1758			sdk_version: "current",
1759			public: {
1760				enabled: true,
1761			},
1762			system: {
1763				enabled: true,
1764			},
1765		}
1766
1767		java_library {
1768			name: "baz",
1769			srcs: ["b.java"],
1770			libs: [
1771				"foo",
1772			],
1773			sdk_version: "system_33",
1774		}
1775	`)
1776}
1777