blob: 3652a45099a36847be7f44bf1674098f72a9d1ca [file] [log] [blame]
Ryan Beltrancfc5c362021-03-02 18:36:18 +00001# Copyright 2021 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Unit tests for tricium_cargo_tidy.py."""
6
7import json
Ryan Beltrancfc5c362021-03-02 18:36:18 +00008
9from chromite.lib import cros_test_lib
10from chromite.scripts import tricium_cargo_clippy
11
Ryan Beltrancfc5c362021-03-02 18:36:18 +000012
13# These test cases were made by:
14# 1) modifying trace_events to lint poorly
15# 2) running USE="rust_clippy" emerge trace_events
16# 3) removing null fields
17# 4) replacing strings with shorter test strings
18valid_test_cases = {
Alex Klein1699fab2022-09-08 08:46:06 -060019 json.dumps(
20 {
21 "reason": "compiler-message",
22 "package_id": "pkg 0.1.0 (path+file:///path/to/repo/pkg)",
23 "target": {
24 "kind": ["lib"],
25 "crate_types": ["lib"],
26 "name": "trace_events",
27 "src_path": "/path/to/repo/pkg/src/main_file",
28 "edition": "2018",
29 "doctest": True,
30 "test": True,
31 },
32 "message": {
33 "rendered": "warning: rendered message 1",
34 "children": [
35 {
36 "children": [],
37 "level": "note",
38 "message": "`#[warn(bare_trait_objects)]` message 1",
39 "spans": [],
40 },
41 {
42 "children": [],
43 "level": "help",
44 "message": "sub message 1",
45 "spans": [
46 {
47 "file_name": "src/file_name_1",
48 "byte_end": 7342,
49 "byte_start": 7336,
50 "column_end": 35,
51 "column_start": 29,
52 "is_primary": True,
53 "line_end": 262,
54 "line_start": 262,
55 "suggested_replacement": "dyn Tracer",
56 "suggestion_applicability": "MachineApplicable",
57 "text": [
58 {
59 "highlight_end": 35,
60 "highlight_start": 29,
61 "text": "highlight 1",
62 }
63 ],
64 }
65 ],
66 },
67 ],
68 "code": {"code": "bare_trait_objects"},
69 "level": "warning",
70 "message": "message 1",
71 "spans": [
72 {
73 "byte_end": 7342,
74 "byte_start": 7336,
75 "column_end": 35,
76 "column_start": 29,
77 "file_name": "src/file_name_1",
78 "is_primary": True,
79 "line_end": 262,
80 "line_start": 262,
81 "text": [
82 {
83 "highlight_end": 35,
84 "highlight_start": 29,
85 "text": "highlight 1",
86 }
87 ],
88 }
89 ],
90 },
Ryan Beltrancfc5c362021-03-02 18:36:18 +000091 }
Alex Klein1699fab2022-09-08 08:46:06 -060092 ): {
93 "locations": [
Ryan Beltrancfc5c362021-03-02 18:36:18 +000094 tricium_cargo_clippy.CodeLocation(
Alex Klein1699fab2022-09-08 08:46:06 -060095 file_path="pkg/src/file_name_1",
Ryan Beltrancfc5c362021-03-02 18:36:18 +000096 line_start=262,
97 line_end=262,
98 column_start=29,
Alex Klein1699fab2022-09-08 08:46:06 -060099 column_end=35,
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000100 )
101 ],
Alex Klein1699fab2022-09-08 08:46:06 -0600102 "level": "warning",
103 "message": "warning: rendered message 1",
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000104 },
Alex Klein1699fab2022-09-08 08:46:06 -0600105 json.dumps(
106 {
107 "reason": "compiler-message",
108 "package_id": "pkg 1.2.3 (path+file:///path/to/repo/pkg)",
109 "target": {
110 "kind": ["lib"],
111 "crate_types": ["lib"],
112 "name": "trace_events",
113 "src_path": "/path/to/repo/pkg/src/main",
114 "edition": "2018",
115 "doctest": True,
116 "test": True,
117 },
118 "message": {
119 "rendered": "warning: rendered message 2",
120 "children": [
121 {
122 "level": "note",
123 "children": [],
124 "message": "submessage 2.1",
125 "spans": [],
126 },
127 {
128 "level": "help",
129 "children": [],
130 "message": "submessage 2.2",
131 "spans": [],
132 },
133 {
134 "level": "help",
135 "children": [],
136 "message": "submessage 2.3",
137 "spans": [
138 {
139 "file_name": "src/file_name_2",
140 "byte_end": 7342,
141 "byte_start": 7327,
142 "column_end": 35,
143 "column_start": 20,
144 "line_end": 262,
145 "line_start": 262,
146 "is_primary": True,
147 "suggested_replacement": "&Tracer",
148 "suggestion_applicability": "MachineApplicable",
149 "text": [
150 {
151 "highlight_end": 35,
152 "highlight_start": 20,
153 "text": "highlight 2",
154 }
155 ],
156 }
157 ],
158 },
159 ],
160 "code": {"code": "clippy::redundant_static_lifetimes"},
161 "level": "warning",
162 "message": "message 2",
163 "spans": [
164 {
165 "file_name": "src/file_name_2",
166 "byte_end": 7335,
167 "byte_start": 7328,
168 "column_end": 28,
169 "column_start": 21,
170 "line_end": 262,
171 "line_start": 262,
172 "is_primary": True,
173 "text": [
174 {
175 "highlight_end": 28,
176 "highlight_start": 21,
177 "text": "highlight 2",
178 }
179 ],
180 }
181 ],
182 },
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000183 }
Alex Klein1699fab2022-09-08 08:46:06 -0600184 ): {
185 "locations": [
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000186 tricium_cargo_clippy.CodeLocation(
Alex Klein1699fab2022-09-08 08:46:06 -0600187 file_path="pkg/src/file_name_2",
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000188 line_start=262,
189 line_end=262,
190 column_start=21,
Alex Klein1699fab2022-09-08 08:46:06 -0600191 column_end=28,
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000192 ),
193 tricium_cargo_clippy.CodeLocation(
Alex Klein1699fab2022-09-08 08:46:06 -0600194 file_path="pkg/src/file_name_2",
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000195 line_start=262,
196 line_end=262,
197 column_start=20,
Alex Klein1699fab2022-09-08 08:46:06 -0600198 column_end=35,
199 ),
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000200 ],
Alex Klein1699fab2022-09-08 08:46:06 -0600201 "level": "warning",
202 "message": "warning: rendered message 2",
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000203 },
Alex Klein1699fab2022-09-08 08:46:06 -0600204 json.dumps(
205 {
206 "reason": "compiler-message",
207 "package_id": "pkg 0.1.0 (path+file:///path/to/repo/pkg)",
208 "target": {
209 "kind": ["lib"],
210 "crate_types": ["lib"],
211 "name": "trace_events",
212 "src_path": "/path/to/repo/pkg/path/to/main",
213 "edition": "2018",
214 "doctest": True,
215 "test": True,
216 },
217 "message": {
218 "rendered": "warning: rendered message 3",
219 "children": [
220 {
221 "children": [],
222 "level": "note",
223 "message": "submessage 3.1",
224 "spans": [],
225 },
226 {
227 "children": [],
228 "level": "help",
229 "message": "submessage 3.2",
230 "spans": [
231 {
232 "file_name": "path/to/file_name_3",
233 "byte_end": 448,
234 "byte_start": 447,
235 "column_end": 8,
236 "column_start": 7,
237 "line_end": 14,
238 "line_start": 14,
239 "is_primary": True,
240 "suggested_replacement": "_x",
241 "suggestion_applicability": "MachineApplicable",
242 "text": [
243 {
244 "highlight_end": 8,
245 "highlight_start": 7,
246 "text": "highlight 3",
247 }
248 ],
249 }
250 ],
251 },
252 ],
253 "code": {"code": "unused_variables"},
254 "level": "warning",
255 "message": "message 3",
256 "spans": [
257 {
258 "file_name": "path/to/file_name_3",
259 "byte_end": 448,
260 "byte_start": 447,
261 "column_end": 8,
262 "column_start": 7,
263 "line_end": 14,
264 "line_start": 14,
265 "is_primary": True,
266 "text": [
267 {
268 "highlight_end": 8,
269 "highlight_start": 7,
270 "text": "highlight 3",
271 }
272 ],
273 }
274 ],
275 },
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000276 }
Alex Klein1699fab2022-09-08 08:46:06 -0600277 ): {
278 "locations": [
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000279 tricium_cargo_clippy.CodeLocation(
Alex Klein1699fab2022-09-08 08:46:06 -0600280 file_path="pkg/path/to/file_name_3",
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000281 line_start=14,
282 line_end=14,
283 column_start=7,
Alex Klein1699fab2022-09-08 08:46:06 -0600284 column_end=8,
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000285 )
286 ],
Alex Klein1699fab2022-09-08 08:46:06 -0600287 "level": "warning",
288 "message": "warning: rendered message 3",
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000289 },
Alex Klein1699fab2022-09-08 08:46:06 -0600290 json.dumps({"reason": "build-script-executed"}): {"skipped": True},
291 json.dumps({"reason": "compiler-artifact"}): {"skipped": True},
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000292}
293
294invalid_test_cases = {
Alex Klein1699fab2022-09-08 08:46:06 -0600295 "not json": ["json"],
296 r"{}": ["reason"],
297 json.dumps(
298 {
299 "reason": "compiler-message",
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000300 }
Alex Klein1699fab2022-09-08 08:46:06 -0600301 ): ["level", "message"],
302 json.dumps(
303 {
304 "reason": "compiler-message",
305 "target": {"src_path": "file path"},
306 "message": {"rendered": "warning: a message"},
307 }
308 ): ["level"],
309 json.dumps(
310 {
311 "reason": "compiler-message",
312 "level": "warning",
313 "target": {"src_path": "file path"},
314 }
315 ): ["message"],
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000316}
317
Alex Klein1699fab2022-09-08 08:46:06 -0600318test_git_repo = "/path/to/repo"
319test_package_path = "/path/to/repo/pkg"
320
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000321
322class TriciumCargoClippyTests(cros_test_lib.LoggingTestCase):
Alex Klein1699fab2022-09-08 08:46:06 -0600323 """Tests for Cargo Clippy."""
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000324
Alex Klein1699fab2022-09-08 08:46:06 -0600325 def test_parse_locations(self):
326 """Tests that parse_locations is as expected."""
327 for test_case, exp_results in valid_test_cases.items():
328 if "locations" not in exp_results:
329 continue
330 test_json = json.loads(test_case)
331 locations = list(
332 tricium_cargo_clippy.parse_locations(
333 test_json, test_package_path, test_git_repo
334 )
335 )
336 self.assertEqual(locations, exp_results["locations"])
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000337
Alex Klein1699fab2022-09-08 08:46:06 -0600338 def test_parse_locations_ebuild_directories(self):
339 """Tests that parse_locations strips ebuild work directories."""
340 expected_location = "src/foo"
341 example_finding = json.dumps(
342 {
343 "reason": "compiler-message",
344 "level": "warning",
345 "message": {
346 "rendered": "warning: a message",
347 "spans": [
348 {
349 "file_name": expected_location,
350 "column_end": 1,
351 "column_start": 2,
352 "line_end": 3,
353 "line_start": 4,
354 }
355 ],
356 },
357 }
Ryan Beltran43a00662021-05-17 16:55:24 +0000358 )
Alex Klein1699fab2022-09-08 08:46:06 -0600359 for work_dir in (
360 "/build/atlas/tmp/portage/dev-rust/pkg-0.12.3-r3/work/pkg-0.12.3",
361 "/build/atlas/tmp/portage/dev-rust/pkg-99999/work/pkg-9999",
362 ):
363 inputs = [json.dumps({"package_path": work_dir}), example_finding]
364 diagnostic = next(
365 tricium_cargo_clippy.parse_diagnostics("", inputs, "")
366 )
367 self.assertEqual(
368 next(diagnostic.locations).file_path, expected_location
369 )
370
371 def test_parse_level(self):
372 """Tests that parse_level is as expected."""
373 for i, (test_case, exp_results) in enumerate(valid_test_cases.items()):
374 if "level" not in exp_results:
375 continue
376 test_json = json.loads(test_case)
377 level = tricium_cargo_clippy.parse_level("valid", i, test_json)
378 self.assertEqual(level, exp_results["level"])
379
380 def test_parse_message(self):
381 """Tests that parse_message is as expected."""
382 for i, (test_case, exp_results) in enumerate(valid_test_cases.items()):
383 if "message" not in exp_results:
384 continue
385 test_json = json.loads(test_case)
386 message = tricium_cargo_clippy.parse_message("valid", i, test_json)
387 self.assertEqual(message, exp_results["message"])
388
389 def test_parse_diagnostics(self):
390 """Tests that parse_diagnostics yields correct diagnostics."""
391 package_path_json = json.dumps({"package_path": test_package_path})
392 orig_jsons = [package_path_json] + list(valid_test_cases.keys())
393 diags = list(
394 tricium_cargo_clippy.parse_diagnostics(
395 "valid_test_cases", orig_jsons, test_git_repo
396 )
Ryan Beltran43a00662021-05-17 16:55:24 +0000397 )
Alex Klein1699fab2022-09-08 08:46:06 -0600398
399 # Verify parse_diagnostics retrieved correct amount of diagnostics
400 exp_len = len(
401 [
402 values
403 for values in valid_test_cases.values()
404 if not values.get("skipped")
405 ]
406 )
407 self.assertEqual(len(diags), exp_len)
408
409 # Verify diagnostics are from correct source
410 for i, diag in enumerate(diags):
411 locations = list(diag.locations)
412 expected_locations = list(valid_test_cases.values())[i].get(
413 "locations"
414 )
415 self.assertEqual(locations, expected_locations)
416
417 def test_logs_invalid_parse_diagnostic_cases(self):
418 """Tests that parse_diagnostics logs proper exceptions."""
419 package_path_json = json.dumps({"package_path": test_package_path})
420 for invalid_case, exp_errors in invalid_test_cases.items():
421 with self.assertRaises(
422 tricium_cargo_clippy.Error,
423 msg=f"Expected error parsing {invalid_case} but got none.",
424 ) as ctx:
425 list(
426 tricium_cargo_clippy.parse_diagnostics(
427 "invalid",
428 [package_path_json, invalid_case],
429 test_git_repo,
430 )
431 )
432 if "json" in exp_errors:
433 exp_error = tricium_cargo_clippy.CargoClippyJSONError(
434 "invalid", 1
435 )
436 elif "reason" in exp_errors:
437 exp_error = tricium_cargo_clippy.CargoClippyReasonError(
438 "invalid", 1
439 )
440 else:
441 for field in ("locations", "level", "message"):
442 if field in exp_errors:
443 exp_error = tricium_cargo_clippy.CargoClippyFieldError(
444 "invalid", 1, field
445 )
446 break
447 self.assertIs(type(ctx.exception), type(exp_error))
448 self.assertEqual(ctx.exception.args, exp_error.args)
449
450 def test_filter_diagnostics(self):
451 file_path = "some_filepath.json"
452 example_code_location = tricium_cargo_clippy.CodeLocation(
453 file_path=file_path,
454 line_start=1,
455 line_end=4,
456 column_start=0,
457 column_end=12,
458 )
459 accepted_diags = [
460 tricium_cargo_clippy.ClippyDiagnostic(
461 locations=[example_code_location],
462 level="warning",
463 message="warning: be warned.",
464 )
465 ]
466 ignored_diags = [
467 # "aborting due to previous error" messages
468 tricium_cargo_clippy.ClippyDiagnostic(
469 locations=[example_code_location],
470 level="warning",
471 message="warning: aborting due to previous error...",
472 ),
473 # No locations provided
474 tricium_cargo_clippy.ClippyDiagnostic(
475 locations=[],
476 level="warning",
477 message="warning: 6 warnings emitted.",
478 ),
479 ]
480 filtered_diags = list(
481 tricium_cargo_clippy.filter_diagnostics(
482 accepted_diags + ignored_diags
483 )
484 )
485 self.assertEqual(filtered_diags, accepted_diags)