blob: 8d2711fadd7323c1a6c3f38292112aff1187f09f [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 = {
19 json.dumps({
20 'reason': 'compiler-message',
21 'package_id': 'package_id_1',
22 'target': {
23 'kind': ['lib'],
24 'crate_types': ['lib'],
25 'name': 'trace_events',
Ryan Beltran923a1312021-07-30 00:28:13 +000026 'src_path': '/path/to/some/git/repo/path/to/file_path_1',
Ryan Beltrancfc5c362021-03-02 18:36:18 +000027 'edition': '2018',
28 'doctest': True,
29 'test': True
30 },
31 'message': {
32 'rendered': 'warning: rendered message 1',
33 'children': [
34 {
35 'children': [],
36 'level': 'note',
37 'message': '`#[warn(bare_trait_objects)]` message 1',
38 'spans': []
39 },
40 {
41 'children': [],
42 'level': 'help',
43 'message': 'sub message 1',
44 'spans': [{
45 'file_name': 'file_name_1',
46 'byte_end': 7342, 'byte_start': 7336,
47 'column_end': 35, 'column_start': 29,
48 'is_primary': True,
49 'line_end': 262, 'line_start': 262,
50 'suggested_replacement': 'dyn Tracer',
51 'suggestion_applicability': 'MachineApplicable',
52 'text': [{
53 'highlight_end': 35, 'highlight_start': 29,
54 'text': 'highlight 1'
55 }]
56 }]
57 }
58 ],
59 'code': {'code': 'bare_trait_objects'},
60 'level': 'warning',
61 'message': 'message 1',
62 'spans': [{
63 'byte_end': 7342, 'byte_start': 7336,
64 'column_end': 35, 'column_start': 29,
65 'file_name': 'file_name_1',
66 'is_primary': True,
67 'line_end': 262, 'line_start': 262,
68 'text': [{
69 'highlight_end': 35, 'highlight_start': 29,
70 'text': 'highlight 1'
71 }]
72 }]
73 }
74 }): {
Ryan Beltran923a1312021-07-30 00:28:13 +000075 'file_path': 'path/to/file_path_1',
Ryan Beltrancfc5c362021-03-02 18:36:18 +000076 'locations': [
77 tricium_cargo_clippy.CodeLocation(
Ryan Beltran923a1312021-07-30 00:28:13 +000078 file_path='path/to/file_path_1',
Ryan Beltrancfc5c362021-03-02 18:36:18 +000079 file_name='file_name_1',
80 line_start=262,
81 line_end=262,
82 column_start=29,
83 column_end=35
84 )
85 ],
86 'level': 'warning',
87 'message': 'warning: rendered message 1',
88 },
89 json.dumps({
90 'reason': 'compiler-message',
91 'package_id': 'package_id 1',
92 'target': {
93 'kind': ['lib'],
94 'crate_types': ['lib'],
95 'name': 'trace_events',
96 'src_path': '/absolute/path/to/file_path_2',
97 'edition': '2018', 'doctest': True, 'test': True
98 },
99 'message': {
100 'rendered': 'warning: rendered message 2',
101 'children': [
102 {
103 'level': 'note',
104 'children': [],
105 'message': 'submessage 2.1',
106 'spans': []
107 },
108 {
109 'level': 'help',
110 'children': [],
111 'message': 'submessage 2.2',
112 'spans': []
113 },
114 {
115 'level': 'help',
116 'children': [],
117 'message': 'submessage 2.3',
118 'spans': [{
119 'file_name': 'file_name_2',
120 'byte_end': 7342, 'byte_start': 7327,
121 'column_end': 35, 'column_start': 20,
122 'line_end': 262, 'line_start': 262,
123 'is_primary': True,
124 'suggested_replacement': '&Tracer',
125 'suggestion_applicability': 'MachineApplicable',
126 'text': [{
127 'highlight_end': 35,
128 'highlight_start': 20,
129 'text': 'highlight 2'
130 }]
131 }]
132 }
133 ],
134 'code': {'code': 'clippy::redundant_static_lifetimes'},
135 'level': 'warning',
136 'message': 'message 2',
137 'spans': [{
138 'file_name': 'file_name_2',
139 'byte_end': 7335, 'byte_start': 7328,
140 'column_end': 28, 'column_start': 21,
141 'line_end': 262, 'line_start': 262,
142 'is_primary': True,
143 'text': [{
144 'highlight_end': 28,
145 'highlight_start': 21,
146 'text': 'highlight 2'
147 }]
148 }]
149 }
150 }): {
151 'file_path': '/absolute/path/to/file_path_2',
152 'locations': [
153 tricium_cargo_clippy.CodeLocation(
154 file_path='/absolute/path/to/file_path_2',
155 file_name='file_name_2',
156 line_start=262,
157 line_end=262,
158 column_start=21,
159 column_end=28
160 ),
161 tricium_cargo_clippy.CodeLocation(
162 file_path='/absolute/path/to/file_path_2',
163 file_name='file_name_2',
164 line_start=262,
165 line_end=262,
166 column_start=20,
167 column_end=35
168 )
169 ],
170 'level': 'warning',
171 'message': 'warning: rendered message 2',
172 },
173 json.dumps({
174 'reason': 'compiler-message',
175 'package_id': 'package id 3',
176 'target': {
177 'kind': ['lib'],
178 'crate_types': ['lib'],
179 'name': 'trace_events',
Ryan Beltran923a1312021-07-30 00:28:13 +0000180 'src_path': '/path/to/some/git/repo//path/to/file_path_3',
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000181 'edition': '2018', 'doctest': True, 'test': True
182 },
183 'message': {
184 'rendered': 'warning: rendered message 3',
185 'children': [
186 {
187 'children': [],
188 'level': 'note',
189 'message': 'submessage 3.1',
190 'spans': []
191 },
192 {
193 'children': [],
194 'level': 'help',
195 'message': 'submessage 3.2',
196 'spans': [
197 {
198 'file_name': 'file_name_3',
199 'byte_end': 448, 'byte_start': 447,
200 'column_end': 8, 'column_start': 7,
201 'line_end': 14, 'line_start': 14,
202 'is_primary': True,
203 'suggested_replacement': '_x',
204 'suggestion_applicability': 'MachineApplicable',
205 'text': [{
206 'highlight_end': 8, 'highlight_start': 7,
207 'text': 'highlight 3'
208 }]
209 }
210 ]
211 }
212 ],
213 'code': {'code': 'unused_variables'},
214 'level': 'warning',
215 'message': 'message 3',
216 'spans': [{
217 'file_name': 'file_name_3',
218 'byte_end': 448, 'byte_start': 447,
219 'column_end': 8, 'column_start': 7,
220 'line_end': 14, 'line_start': 14,
221 'is_primary': True,
222 'text': [{
223 'highlight_end': 8,
224 'highlight_start': 7,
225 'text': 'highlight 3'
226 }]
227 }]
228 }
229 }): {
Ryan Beltran923a1312021-07-30 00:28:13 +0000230 'file_path': 'path/to/file_path_3',
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000231 'locations': [
232 tricium_cargo_clippy.CodeLocation(
Ryan Beltran923a1312021-07-30 00:28:13 +0000233 file_path='path/to/file_path_3',
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000234 file_name='file_name_3',
235 line_start=14,
236 line_end=14,
237 column_start=7,
238 column_end=8
239 )
240 ],
241 'level': 'warning',
242 'message': 'warning: rendered message 3',
243 },
244 json.dumps({'reason': 'build-script-executed'}): {
245 'skipped': True
246 },
247 json.dumps({'reason': 'compiler-artifact'}): {
248 'skipped': True
249 }
250}
251
252invalid_test_cases = {
253 'not json': ['json'],
254 r'{}': ['reason'],
255 json.dumps({
256 'reason': 'compiler-message',
257 }): ['file_path', 'level', 'message'],
258 json.dumps({
259 'reason': 'compiler-message',
260 'level': 'warning',
261 'message': {
262 'rendered': 'warning: a message'
263 }
264 }): ['file_path'],
265 json.dumps({
266 'reason': 'compiler-message',
267 'target': {
268 'src_path': 'file path'
269 },
270 'message': {
271 'rendered': 'warning: a message'
272 }
273 }): ['level'],
274 json.dumps({
275 'reason': 'compiler-message',
276 'level': 'warning',
277 'target': {
278 'src_path': 'file path'
279 },
280 }): ['message'],
281}
282
Ryan Beltran923a1312021-07-30 00:28:13 +0000283test_git_repo = '/path/to/some/git/repo'
284
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000285
286class TriciumCargoClippyTests(cros_test_lib.LoggingTestCase):
287 """Tests for Cargo Clippy."""
288
289 def test_parse_file_path(self):
290 """Tests that parse_file_path is as expected."""
291 for i, (test_case, exp_results) in enumerate(valid_test_cases.items()):
292 if 'file_path' not in exp_results:
293 continue
294 test_json = json.loads(test_case)
Ryan Beltran923a1312021-07-30 00:28:13 +0000295 file_path = tricium_cargo_clippy.parse_file_path(
296 'valid', i, test_json, test_git_repo)
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000297 self.assertEqual(file_path, exp_results['file_path'])
298
299 def test_parse_locations(self):
300 """Tests that parse_locations is as expected."""
Ryan Beltran43a00662021-05-17 16:55:24 +0000301 for test_case, exp_results in valid_test_cases.items():
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000302 if 'locations' not in exp_results:
303 continue
304 test_json = json.loads(test_case)
305 locations = list(tricium_cargo_clippy.parse_locations(
Ryan Beltran43a00662021-05-17 16:55:24 +0000306 test_json, exp_results['file_path']))
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000307 self.assertEqual(locations, exp_results['locations'])
308
309 def test_parse_level(self):
310 """Tests that parse_level is as expected."""
311 for i, (test_case, exp_results) in enumerate(valid_test_cases.items()):
312 if 'level' not in exp_results:
313 continue
314 test_json = json.loads(test_case)
315 level = tricium_cargo_clippy.parse_level('valid', i, test_json)
316 self.assertEqual(level, exp_results['level'])
317
318 def test_parse_message(self):
319 """Tests that parse_message is as expected."""
320 for i, (test_case, exp_results) in enumerate(valid_test_cases.items()):
321 if 'message' not in exp_results:
322 continue
323 test_json = json.loads(test_case)
324 message = tricium_cargo_clippy.parse_message('valid', i, test_json)
325 self.assertEqual(message, exp_results['message'])
326
327 def test_parse_diagnostics(self):
328 """Tests that parse_diagnostics yields correct diagnostics."""
329 diags = list(tricium_cargo_clippy.parse_diagnostics(
Ryan Beltran923a1312021-07-30 00:28:13 +0000330 'valid_test_cases', list(valid_test_cases.keys()), test_git_repo))
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000331
332 # Verify parse_diagnostics retrieved correct amount of diagnostics
333 exp_len = len([
334 values for values in valid_test_cases.values()
335 if not values.get('skipped')
336 ])
337 self.assertEqual(len(diags), exp_len)
338
339 # Verify diagnostics are from correct source
340 for i, diag in enumerate(diags):
341 locations = list(diag.locations)
342 expected_locations = list(valid_test_cases.values())[i].get('locations')
343 self.assertEqual(locations, expected_locations)
344
345 def test_logs_invalid_parse_diagnostic_cases(self):
346 """Tests that parse_diagnostics logs proper exceptions."""
347 for invalid_case, exp_errors in invalid_test_cases.items():
348 with self.assertRaises(
349 tricium_cargo_clippy.Error,
350 msg=f'Expected error parsing {invalid_case} but got none.') as ctx:
Ryan Beltran923a1312021-07-30 00:28:13 +0000351 list(tricium_cargo_clippy.parse_diagnostics(
352 'invalid', [invalid_case], test_git_repo))
Ryan Beltrancfc5c362021-03-02 18:36:18 +0000353 if 'json' in exp_errors:
354 exp_error = tricium_cargo_clippy.CargoClippyJSONError('invalid', 0)
355 elif 'reason' in exp_errors:
356 exp_error = tricium_cargo_clippy.CargoClippyReasonError('invalid', 0)
357 else:
358 for field in ('file_path', 'locations', 'level', 'message'):
359 if field in exp_errors:
360 exp_error = tricium_cargo_clippy.CargoClippyFieldError(
361 'invalid', 0, field)
362 break
363 self.assertIs(type(ctx.exception), type(exp_error))
364 self.assertEqual(ctx.exception.args, exp_error.args)
365
Ryan Beltran43a00662021-05-17 16:55:24 +0000366 def test_filter_diagnostics(self):
Ryan Beltran923a1312021-07-30 00:28:13 +0000367 file_path = 'some_filepath.json'
Ryan Beltran43a00662021-05-17 16:55:24 +0000368 example_code_location = tricium_cargo_clippy.CodeLocation(
Ryan Beltran923a1312021-07-30 00:28:13 +0000369 file_path=file_path,
370 file_name=file_path,
Ryan Beltran43a00662021-05-17 16:55:24 +0000371 line_start=1,
372 line_end=4,
373 column_start=0,
374 column_end=12
375 )
376 accepted_diags = [
377 tricium_cargo_clippy.ClippyDiagnostic(
Ryan Beltran923a1312021-07-30 00:28:13 +0000378 file_path=file_path,
Ryan Beltran43a00662021-05-17 16:55:24 +0000379 locations=[example_code_location],
380 level='warning',
381 message='warning: be warned.'
382 )
383 ]
384 ignored_diags = [
Ryan Beltran43a00662021-05-17 16:55:24 +0000385 # "aborting due to previous error" messages
386 tricium_cargo_clippy.ClippyDiagnostic(
Ryan Beltran923a1312021-07-30 00:28:13 +0000387 file_path=file_path,
Ryan Beltran43a00662021-05-17 16:55:24 +0000388 locations=[example_code_location],
389 level='warning',
390 message='warning: aborting due to previous error...'
391 ),
392 # No locations provided
393 tricium_cargo_clippy.ClippyDiagnostic(
Ryan Beltran923a1312021-07-30 00:28:13 +0000394 file_path=file_path,
Ryan Beltran43a00662021-05-17 16:55:24 +0000395 locations=[],
396 level='warning',
397 message='warning: 6 warnings emitted.'
398 )
399 ]
400 filtered_diags = list(tricium_cargo_clippy.filter_diagnostics(
Ryan Beltran923a1312021-07-30 00:28:13 +0000401 accepted_diags + ignored_diags))
Ryan Beltran43a00662021-05-17 16:55:24 +0000402 self.assertEqual(filtered_diags, accepted_diags)