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