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	"strings"
19	"testing"
20
21	"android/soong/android"
22)
23
24func TestJavaLint(t *testing.T) {
25	ctx, _ := testJavaWithFS(t, `
26		java_library {
27			name: "foo",
28			srcs: [
29				"a.java",
30				"b.java",
31				"c.java",
32			],
33			min_sdk_version: "29",
34			sdk_version: "system_current",
35		}
36       `, map[string][]byte{
37		"lint-baseline.xml": nil,
38	})
39
40	foo := ctx.ModuleForTests("foo", "android_common")
41
42	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
43	if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml") {
44		t.Error("did not pass --baseline flag")
45	}
46}
47
48func TestJavaLintWithoutBaseline(t *testing.T) {
49	ctx, _ := testJavaWithFS(t, `
50		java_library {
51			name: "foo",
52			srcs: [
53				"a.java",
54				"b.java",
55				"c.java",
56			],
57			min_sdk_version: "29",
58			sdk_version: "system_current",
59		}
60       `, map[string][]byte{})
61
62	foo := ctx.ModuleForTests("foo", "android_common")
63
64	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
65	if strings.Contains(*sboxProto.Commands[0].Command, "--baseline") {
66		t.Error("passed --baseline flag for non existent file")
67	}
68}
69
70func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) {
71	android.GroupFixturePreparers(
72		PrepareForTestWithJavaDefaultModules,
73		android.PrepareForTestDisallowNonExistentPaths,
74	).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern([]string{`source path "mybaseline.xml" does not exist`})).
75		RunTestWithBp(t, `
76			java_library {
77				name: "foo",
78				srcs: [
79				],
80				min_sdk_version: "29",
81				sdk_version: "system_current",
82				lint: {
83					baseline_filename: "mybaseline.xml",
84				},
85			}
86	 `)
87}
88
89func TestJavaLintUsesCorrectBpConfig(t *testing.T) {
90	ctx, _ := testJavaWithFS(t, `
91		java_library {
92			name: "foo",
93			srcs: [
94				"a.java",
95				"b.java",
96				"c.java",
97			],
98			min_sdk_version: "29",
99			sdk_version: "system_current",
100			lint: {
101				error_checks: ["SomeCheck"],
102				baseline_filename: "mybaseline.xml",
103			},
104		}
105       `, map[string][]byte{
106		"mybaseline.xml": nil,
107	})
108
109	foo := ctx.ModuleForTests("foo", "android_common")
110
111	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
112	if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline mybaseline.xml") {
113		t.Error("did not use the correct file for baseline")
114	}
115
116	if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") {
117		t.Error("should check NewApi errors")
118	}
119
120	if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") {
121		t.Error("should combine NewApi errors with SomeCheck errors")
122	}
123}
124
125func TestJavaLintBypassUpdatableChecks(t *testing.T) {
126	testCases := []struct {
127		name  string
128		bp    string
129		error string
130	}{
131		{
132			name: "warning_checks",
133			bp: `
134				java_library {
135					name: "foo",
136					srcs: [
137						"a.java",
138					],
139					min_sdk_version: "29",
140					sdk_version: "current",
141					lint: {
142						warning_checks: ["NewApi"],
143					},
144				}
145			`,
146			error: "lint.warning_checks: Can't treat \\[NewApi\\] checks as warnings if min_sdk_version is different from sdk_version.",
147		},
148		{
149			name: "disable_checks",
150			bp: `
151				java_library {
152					name: "foo",
153					srcs: [
154						"a.java",
155					],
156					min_sdk_version: "29",
157					sdk_version: "current",
158					lint: {
159						disabled_checks: ["NewApi"],
160					},
161				}
162			`,
163			error: "lint.disabled_checks: Can't disable \\[NewApi\\] checks if min_sdk_version is different from sdk_version.",
164		},
165	}
166
167	for _, testCase := range testCases {
168		t.Run(testCase.name, func(t *testing.T) {
169			errorHandler := android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.error)
170			android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules).
171				ExtendWithErrorHandler(errorHandler).
172				RunTestWithBp(t, testCase.bp)
173		})
174	}
175}
176
177func TestJavaLintStrictUpdatabilityLinting(t *testing.T) {
178	bp := `
179		java_library {
180			name: "foo",
181			srcs: [
182				"a.java",
183			],
184			static_libs: ["bar"],
185			min_sdk_version: "29",
186			sdk_version: "current",
187			lint: {
188				strict_updatability_linting: true,
189			},
190		}
191
192		java_library {
193			name: "bar",
194			srcs: [
195				"a.java",
196			],
197			min_sdk_version: "29",
198			sdk_version: "current",
199		}
200	`
201	fs := android.MockFS{
202		"lint-baseline.xml": nil,
203	}
204
205	result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, fs.AddToFixture()).
206		RunTestWithBp(t, bp)
207
208	foo := result.ModuleForTests("foo", "android_common")
209	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
210	if !strings.Contains(*sboxProto.Commands[0].Command,
211		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
212		t.Error("did not restrict baselining NewApi")
213	}
214
215	bar := result.ModuleForTests("bar", "android_common")
216	sboxProto = android.RuleBuilderSboxProtoForTests(t, bar.Output("lint.sbox.textproto"))
217	if !strings.Contains(*sboxProto.Commands[0].Command,
218		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
219		t.Error("did not restrict baselining NewApi")
220	}
221}
222
223func TestJavaLintDatabaseSelectionFull(t *testing.T) {
224	testCases := []string{
225		"current", "core_platform", "system_current", "S", "30", "10000",
226	}
227	bp := `
228		java_library {
229			name: "foo",
230			srcs: [
231				"a.java",
232			],
233			min_sdk_version: "29",
234			sdk_version: "XXX",
235			lint: {
236				strict_updatability_linting: true,
237			},
238		}
239`
240	for _, testCase := range testCases {
241		thisBp := strings.Replace(bp, "XXX", testCase, 1)
242
243		result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, FixtureWithPrebuiltApis(map[string][]string{
244			"30":    {"foo"},
245			"10000": {"foo"},
246		})).
247			RunTestWithBp(t, thisBp)
248
249		foo := result.ModuleForTests("foo", "android_common")
250		sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
251		if strings.Contains(*sboxProto.Commands[0].Command,
252			"/api_versions_public_filtered.xml") {
253			t.Error("used public-filtered lint api database for case", testCase)
254		}
255		if !strings.Contains(*sboxProto.Commands[0].Command,
256			"/api_versions.xml") {
257			t.Error("did not use full api database for case", testCase)
258		}
259	}
260
261}
262
263func TestJavaLintDatabaseSelectionPublicFiltered(t *testing.T) {
264	testCases := []string{
265		"module_current", "system_server_current",
266	}
267	bp := `
268		java_library {
269			name: "foo",
270			srcs: [
271				"a.java",
272			],
273			min_sdk_version: "29",
274			sdk_version: "module_current",
275			lint: {
276				strict_updatability_linting: true,
277			},
278		}
279`
280	for _, testCase := range testCases {
281		thisBp := strings.Replace(bp, "XXX", testCase, 1)
282		result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules).
283			RunTestWithBp(t, thisBp)
284
285		foo := result.ModuleForTests("foo", "android_common")
286		sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
287		if !strings.Contains(*sboxProto.Commands[0].Command,
288			"/api_versions_public_filtered.xml") {
289			t.Error("did not use public-filtered lint api database for case", testCase)
290		}
291		if strings.Contains(*sboxProto.Commands[0].Command,
292			"/api_versions.xml") {
293			t.Error("used full api database for case", testCase)
294		}
295	}
296}
297