1// Copyright (C) 2021 The Android Open Source Project
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	"testing"
19
20	"android/soong/android"
21	"android/soong/dexpreopt"
22)
23
24// Contains some simple tests for bootclasspath_fragment logic, additional tests can be found in
25// apex/bootclasspath_fragment_test.go as the ART boot image requires modules from the ART apex.
26
27var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers(
28	PrepareForTestWithJavaDefaultModules,
29	dexpreopt.PrepareForTestByEnablingDexpreopt,
30)
31
32func TestBootclasspathFragment_UnknownImageName(t *testing.T) {
33	prepareForTestWithBootclasspathFragment.
34		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
35			`\Qimage_name: unknown image name "unknown", expected "art"\E`)).
36		RunTestWithBp(t, `
37			bootclasspath_fragment {
38				name: "unknown-bootclasspath-fragment",
39				image_name: "unknown",
40				contents: ["foo"],
41			}
42		`)
43}
44
45func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) {
46	prepareForTestWithBootclasspathFragment.
47		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
48			`\Qimage_name: unknown image name "unknown", expected "art"\E`)).
49		RunTestWithBp(t, `
50			prebuilt_bootclasspath_fragment {
51				name: "unknown-bootclasspath-fragment",
52				image_name: "unknown",
53				contents: ["foo"],
54			}
55		`)
56}
57
58func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T) {
59	android.GroupFixturePreparers(
60		prepareForTestWithBootclasspathFragment,
61		dexpreopt.FixtureSetArtBootJars("platform:foo", "apex:bar"),
62	).
63		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
64			`\QArtApexJars is invalid as it requests a platform variant of "foo"\E`)).
65		RunTestWithBp(t, `
66			bootclasspath_fragment {
67				name: "bootclasspath-fragment",
68				image_name: "art",
69				contents: ["foo", "bar"],
70				apex_available: [
71					"apex",
72				],
73			}
74		`)
75}
76
77func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testing.T) {
78	android.GroupFixturePreparers(
79		prepareForTestWithBootclasspathFragment,
80		dexpreopt.FixtureSetArtBootJars("apex1:foo", "apex2:bar"),
81	).
82		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
83			`\QArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex "apex1" and "apex2"\E`)).
84		RunTestWithBp(t, `
85			bootclasspath_fragment {
86				name: "bootclasspath-fragment",
87				image_name: "art",
88				contents: ["foo", "bar"],
89				apex_available: [
90					"apex1",
91					"apex2",
92				],
93			}
94		`)
95}
96
97func TestBootclasspathFragment_Coverage(t *testing.T) {
98	prepareForTestWithFrameworkCoverage := android.FixtureMergeEnv(map[string]string{
99		"EMMA_INSTRUMENT":           "true",
100		"EMMA_INSTRUMENT_FRAMEWORK": "true",
101	})
102
103	prepareWithBp := android.FixtureWithRootAndroidBp(`
104		bootclasspath_fragment {
105			name: "myfragment",
106			contents: [
107				"mybootlib",
108			],
109			api: {
110				stub_libs: [
111					"mysdklibrary",
112				],
113			},
114			coverage: {
115				contents: [
116					"coveragelib",
117				],
118				api: {
119					stub_libs: [
120						"mycoveragestubs",
121					],
122				},
123			},
124		}
125
126		java_library {
127			name: "mybootlib",
128			srcs: ["Test.java"],
129			system_modules: "none",
130			sdk_version: "none",
131			compile_dex: true,
132		}
133
134		java_library {
135			name: "coveragelib",
136			srcs: ["Test.java"],
137			system_modules: "none",
138			sdk_version: "none",
139			compile_dex: true,
140		}
141
142		java_sdk_library {
143			name: "mysdklibrary",
144			srcs: ["Test.java"],
145			compile_dex: true,
146			public: {enabled: true},
147			system: {enabled: true},
148		}
149
150		java_sdk_library {
151			name: "mycoveragestubs",
152			srcs: ["Test.java"],
153			compile_dex: true,
154			public: {enabled: true},
155		}
156	`)
157
158	checkContents := func(t *testing.T, result *android.TestResult, expected ...string) {
159		module := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule)
160		android.AssertArrayString(t, "contents property", expected, module.properties.Contents)
161	}
162
163	preparer := android.GroupFixturePreparers(
164		prepareForTestWithBootclasspathFragment,
165		PrepareForTestWithJavaSdkLibraryFiles,
166		FixtureWithLastReleaseApis("mysdklibrary", "mycoveragestubs"),
167		prepareWithBp,
168	)
169
170	t.Run("without coverage", func(t *testing.T) {
171		result := preparer.RunTest(t)
172		checkContents(t, result, "mybootlib")
173	})
174
175	t.Run("with coverage", func(t *testing.T) {
176		result := android.GroupFixturePreparers(
177			prepareForTestWithFrameworkCoverage,
178			preparer,
179		).RunTest(t)
180		checkContents(t, result, "mybootlib", "coveragelib")
181	})
182}
183
184func TestBootclasspathFragment_StubLibs(t *testing.T) {
185	result := android.GroupFixturePreparers(
186		prepareForTestWithBootclasspathFragment,
187		PrepareForTestWithJavaSdkLibraryFiles,
188		FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
189	).RunTestWithBp(t, `
190		bootclasspath_fragment {
191			name: "myfragment",
192			contents: ["mysdklibrary"],
193			api: {
194				stub_libs: [
195					"mystublib",
196					"myothersdklibrary",
197				],
198			},
199			core_platform_api: {
200				stub_libs: ["mycoreplatform.stubs"],
201			},
202		}
203
204		java_library {
205			name: "mystublib",
206			srcs: ["Test.java"],
207			system_modules: "none",
208			sdk_version: "none",
209			compile_dex: true,
210		}
211
212		java_sdk_library {
213			name: "mysdklibrary",
214			srcs: ["a.java"],
215			shared_library: false,
216			public: {enabled: true},
217			system: {enabled: true},
218		}
219
220		java_sdk_library {
221			name: "myothersdklibrary",
222			srcs: ["a.java"],
223			shared_library: false,
224			public: {enabled: true},
225		}
226
227		java_sdk_library {
228			name: "mycoreplatform",
229			srcs: ["a.java"],
230			shared_library: false,
231			public: {enabled: true},
232		}
233	`)
234
235	fragment := result.Module("myfragment", "android_common")
236	info := result.ModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
237
238	stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar"
239
240	// Stubs jars for mysdklibrary
241	publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar"
242	systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.system/android_common/dex/mysdklibrary.stubs.system.jar"
243
244	// Stubs jars for myothersdklibrary
245	otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs/android_common/dex/myothersdklibrary.stubs.jar"
246
247	// Check that SdkPublic uses public stubs for all sdk libraries.
248	android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(PublicHiddenAPIScope))
249
250	// Check that SdkSystem uses system stubs for mysdklibrary and public stubs for myothersdklibrary
251	// as it does not provide system stubs.
252	android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(SystemHiddenAPIScope))
253
254	// Check that SdkTest also uses system stubs for mysdklibrary as it does not provide test stubs
255	// and public stubs for myothersdklibrary as it does not provide test stubs either.
256	android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(TestHiddenAPIScope))
257
258	// Check that SdkCorePlatform uses public stubs from the mycoreplatform library.
259	corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar"
260	android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(CorePlatformHiddenAPIScope))
261
262	// Check the widest stubs.. The list contains the widest stub dex jar provided by each module.
263	expectedWidestPaths := []string{
264		// mycoreplatform's widest API is core platform.
265		corePlatformStubsJar,
266
267		// myothersdklibrary's widest API is public.
268		otherPublicStubsJar,
269
270		// sdklibrary's widest API is system.
271		systemStubsJar,
272
273		// mystublib's only provides one API and so it must be the widest.
274		stubsJar,
275	}
276
277	android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope())
278}
279