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