1// Copyright 2019 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 sdk
16
17import (
18	"android/soong/android"
19	"log"
20	"os"
21	"testing"
22
23	"github.com/google/blueprint/proptools"
24)
25
26// Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE.
27func TestMain(m *testing.M) {
28	if android.BuildOs != android.Linux {
29		// b/145598135 - Generating host snapshots for anything other than linux is not supported.
30		log.Printf("Skipping as sdk snapshot generation is only supported on %s not %s", android.Linux, android.BuildOs)
31		os.Exit(0)
32	}
33
34	runTestWithBuildDir(m)
35}
36
37func TestDepNotInRequiredSdks(t *testing.T) {
38	testSdkError(t, `module "myjavalib".*depends on "otherlib".*that isn't part of the required SDKs:.*`, `
39		sdk {
40			name: "mysdk",
41			java_header_libs: ["sdkmember"],
42		}
43
44		sdk_snapshot {
45			name: "mysdk@1",
46			java_header_libs: ["sdkmember_mysdk_1"],
47		}
48
49		java_import {
50			name: "sdkmember",
51			prefer: false,
52			host_supported: true,
53		}
54
55		java_import {
56			name: "sdkmember_mysdk_1",
57			sdk_member_name: "sdkmember",
58			host_supported: true,
59		}
60
61		java_library {
62			name: "myjavalib",
63			srcs: ["Test.java"],
64			libs: [
65				"sdkmember",
66				"otherlib",
67			],
68			system_modules: "none",
69			sdk_version: "none",
70			compile_dex: true,
71			host_supported: true,
72			apex_available: ["myapex"],
73		}
74
75		// this lib is no in mysdk
76		java_library {
77			name: "otherlib",
78			srcs: ["Test.java"],
79			system_modules: "none",
80			sdk_version: "none",
81			compile_dex: true,
82			host_supported: true,
83		}
84
85		apex {
86			name: "myapex",
87			java_libs: ["myjavalib"],
88			uses_sdks: ["mysdk@1"],
89			key: "myapex.key",
90			certificate: ":myapex.cert",
91		}
92	`)
93}
94
95// Ensure that prebuilt modules have the same effective visibility as the source
96// modules.
97func TestSnapshotVisibility(t *testing.T) {
98	packageBp := `
99		package {
100			default_visibility: ["//other/foo"],
101		}
102
103		sdk {
104			name: "mysdk",
105			visibility: [
106				"//other/foo",
107				// This short form will be replaced with //package:__subpackages__ in the
108				// generated sdk_snapshot.
109				":__subpackages__",
110			],
111			java_header_libs: [
112				"myjavalib",
113				"mypublicjavalib",
114				"mydefaultedjavalib",
115				"myprivatejavalib",
116			],
117		}
118
119		java_library {
120			name: "myjavalib",
121			// Uses package default visibility
122			srcs: ["Test.java"],
123			system_modules: "none",
124			sdk_version: "none",
125		}
126
127		java_defaults {
128			name: "java-defaults",
129			visibility: ["//other/bar"],
130		}
131
132		java_library {
133			name: "mypublicjavalib",
134			defaults: ["java-defaults"],
135      visibility: ["//visibility:public"],
136			srcs: ["Test.java"],
137			system_modules: "none",
138			sdk_version: "none",
139		}
140
141		java_defaults {
142			name: "myjavadefaults",
143			visibility: ["//other/bar"],
144		}
145
146		java_library {
147			name: "mydefaultedjavalib",
148			defaults: ["myjavadefaults"],
149			srcs: ["Test.java"],
150			system_modules: "none",
151			sdk_version: "none",
152		}
153
154		java_library {
155			name: "myprivatejavalib",
156			srcs: ["Test.java"],
157			visibility: ["//visibility:private"],
158			system_modules: "none",
159			sdk_version: "none",
160		}
161	`
162
163	result := testSdkWithFs(t, ``,
164		map[string][]byte{
165			"package/Test.java":  nil,
166			"package/Android.bp": []byte(packageBp),
167		})
168
169	result.CheckSnapshot("mysdk", "package",
170		checkAndroidBpContents(`
171// This is auto-generated. DO NOT EDIT.
172
173java_import {
174    name: "mysdk_myjavalib@current",
175    sdk_member_name: "myjavalib",
176    visibility: [
177        "//other/foo",
178        "//package",
179    ],
180    jars: ["java/myjavalib.jar"],
181}
182
183java_import {
184    name: "myjavalib",
185    prefer: false,
186    visibility: [
187        "//other/foo",
188        "//package",
189    ],
190    jars: ["java/myjavalib.jar"],
191}
192
193java_import {
194    name: "mysdk_mypublicjavalib@current",
195    sdk_member_name: "mypublicjavalib",
196    visibility: ["//visibility:public"],
197    jars: ["java/mypublicjavalib.jar"],
198}
199
200java_import {
201    name: "mypublicjavalib",
202    prefer: false,
203    visibility: ["//visibility:public"],
204    jars: ["java/mypublicjavalib.jar"],
205}
206
207java_import {
208    name: "mysdk_mydefaultedjavalib@current",
209    sdk_member_name: "mydefaultedjavalib",
210    visibility: [
211        "//other/bar",
212        "//package",
213    ],
214    jars: ["java/mydefaultedjavalib.jar"],
215}
216
217java_import {
218    name: "mydefaultedjavalib",
219    prefer: false,
220    visibility: [
221        "//other/bar",
222        "//package",
223    ],
224    jars: ["java/mydefaultedjavalib.jar"],
225}
226
227java_import {
228    name: "mysdk_myprivatejavalib@current",
229    sdk_member_name: "myprivatejavalib",
230    visibility: ["//package"],
231    jars: ["java/myprivatejavalib.jar"],
232}
233
234java_import {
235    name: "myprivatejavalib",
236    prefer: false,
237    visibility: ["//package"],
238    jars: ["java/myprivatejavalib.jar"],
239}
240
241sdk_snapshot {
242    name: "mysdk@current",
243    visibility: [
244        "//other/foo",
245        "//package:__subpackages__",
246    ],
247    java_header_libs: [
248        "mysdk_myjavalib@current",
249        "mysdk_mypublicjavalib@current",
250        "mysdk_mydefaultedjavalib@current",
251        "mysdk_myprivatejavalib@current",
252    ],
253}
254`))
255}
256
257func TestSDkInstall(t *testing.T) {
258	sdk := `
259		sdk {
260			name: "mysdk",
261		}
262	`
263	result := testSdkWithFs(t, ``,
264		map[string][]byte{
265			"Android.bp": []byte(sdk),
266		})
267
268	result.CheckSnapshot("mysdk", "",
269		checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`),
270	)
271}
272
273type EmbeddedPropertiesStruct struct {
274	S_Embedded_Common    string `android:"arch_variant"`
275	S_Embedded_Different string `android:"arch_variant"`
276}
277
278type testPropertiesStruct struct {
279	name        string
280	private     string
281	Public_Kept string `sdk:"keep"`
282	S_Common    string
283	S_Different string `android:"arch_variant"`
284	A_Common    []string
285	A_Different []string `android:"arch_variant"`
286	F_Common    *bool
287	F_Different *bool `android:"arch_variant"`
288	EmbeddedPropertiesStruct
289}
290
291func (p *testPropertiesStruct) optimizableProperties() interface{} {
292	return p
293}
294
295func (p *testPropertiesStruct) String() string {
296	return p.name
297}
298
299var _ propertiesContainer = (*testPropertiesStruct)(nil)
300
301func TestCommonValueOptimization(t *testing.T) {
302	common := &testPropertiesStruct{name: "common"}
303	structs := []propertiesContainer{
304		&testPropertiesStruct{
305			name:        "struct-0",
306			private:     "common",
307			Public_Kept: "common",
308			S_Common:    "common",
309			S_Different: "upper",
310			A_Common:    []string{"first", "second"},
311			A_Different: []string{"alpha", "beta"},
312			F_Common:    proptools.BoolPtr(false),
313			F_Different: proptools.BoolPtr(false),
314			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
315				S_Embedded_Common:    "embedded_common",
316				S_Embedded_Different: "embedded_upper",
317			},
318		},
319		&testPropertiesStruct{
320			name:        "struct-1",
321			private:     "common",
322			Public_Kept: "common",
323			S_Common:    "common",
324			S_Different: "lower",
325			A_Common:    []string{"first", "second"},
326			A_Different: []string{"alpha", "delta"},
327			F_Common:    proptools.BoolPtr(false),
328			F_Different: proptools.BoolPtr(true),
329			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
330				S_Embedded_Common:    "embedded_common",
331				S_Embedded_Different: "embedded_lower",
332			},
333		},
334	}
335
336	extractor := newCommonValueExtractor(common)
337
338	h := TestHelper{t}
339
340	err := extractor.extractCommonProperties(common, structs)
341	h.AssertDeepEquals("unexpected error", nil, err)
342
343	h.AssertDeepEquals("common properties not correct",
344		&testPropertiesStruct{
345			name:        "common",
346			private:     "",
347			Public_Kept: "",
348			S_Common:    "common",
349			S_Different: "",
350			A_Common:    []string{"first", "second"},
351			A_Different: []string(nil),
352			F_Common:    proptools.BoolPtr(false),
353			F_Different: nil,
354			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
355				S_Embedded_Common:    "embedded_common",
356				S_Embedded_Different: "",
357			},
358		},
359		common)
360
361	h.AssertDeepEquals("updated properties[0] not correct",
362		&testPropertiesStruct{
363			name:        "struct-0",
364			private:     "common",
365			Public_Kept: "common",
366			S_Common:    "",
367			S_Different: "upper",
368			A_Common:    nil,
369			A_Different: []string{"alpha", "beta"},
370			F_Common:    nil,
371			F_Different: proptools.BoolPtr(false),
372			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
373				S_Embedded_Common:    "",
374				S_Embedded_Different: "embedded_upper",
375			},
376		},
377		structs[0])
378
379	h.AssertDeepEquals("updated properties[1] not correct",
380		&testPropertiesStruct{
381			name:        "struct-1",
382			private:     "common",
383			Public_Kept: "common",
384			S_Common:    "",
385			S_Different: "lower",
386			A_Common:    nil,
387			A_Different: []string{"alpha", "delta"},
388			F_Common:    nil,
389			F_Different: proptools.BoolPtr(true),
390			EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
391				S_Embedded_Common:    "",
392				S_Embedded_Different: "embedded_lower",
393			},
394		},
395		structs[1])
396}
397
398func TestCommonValueOptimization_InvalidArchSpecificVariants(t *testing.T) {
399	common := &testPropertiesStruct{name: "common"}
400	structs := []propertiesContainer{
401		&testPropertiesStruct{
402			name:     "struct-0",
403			S_Common: "should-be-but-is-not-common0",
404		},
405		&testPropertiesStruct{
406			name:     "struct-1",
407			S_Common: "should-be-but-is-not-common1",
408		},
409	}
410
411	extractor := newCommonValueExtractor(common)
412
413	h := TestHelper{t}
414
415	err := extractor.extractCommonProperties(common, structs)
416	h.AssertErrorMessageEquals("unexpected error", `field "S_Common" is not tagged as "arch_variant" but has arch specific properties:
417    "struct-0" has value "should-be-but-is-not-common0"
418    "struct-1" has value "should-be-but-is-not-common1"`, err)
419}
420