1 | import os |
||
2 | import unittest |
||
3 | from unittest.mock import patch |
||
4 | from collections import OrderedDict |
||
5 | from os.path import abspath, relpath |
||
6 | |||
7 | from pyprint.ConsolePrinter import ConsolePrinter |
||
8 | from pyprint.NullPrinter import NullPrinter |
||
9 | from pyprint.StringPrinter import StringPrinter |
||
10 | |||
11 | from coalib.bearlib.spacing.SpacingHelper import SpacingHelper |
||
12 | from coalib.bears.Bear import Bear |
||
13 | from coalib.misc.ContextManagers import ( |
||
14 | make_temp, retrieve_stdout, simulate_console_inputs) |
||
15 | from coalib.output.ConsoleInteraction import ( |
||
16 | acquire_actions_and_apply, acquire_settings, get_action_info, nothing_done, |
||
17 | print_affected_files, print_result, print_results, |
||
18 | print_results_formatted, print_results_no_input, print_section_beginning, |
||
19 | show_bear, show_bears, ask_for_action_and_apply, print_diffs_info, |
||
20 | show_language_bears_capabilities) |
||
21 | from coalib.output.printers.LogPrinter import LogPrinter |
||
22 | from coalib.output.ConsoleInteraction import (BackgroundSourceRangeStyle, |
||
23 | BackgroundMessageStyle, |
||
24 | highlight_text) |
||
25 | from coalib.results.Diff import Diff |
||
26 | from coalib.results.Result import Result |
||
27 | from coalib.results.result_actions.ApplyPatchAction import ApplyPatchAction |
||
28 | from coalib.results.result_actions.OpenEditorAction import OpenEditorAction |
||
29 | from coalib.results.result_actions.ResultAction import ResultAction |
||
30 | from coalib.results.SourceRange import SourceRange |
||
31 | from coalib.settings.Section import Section |
||
32 | from coalib.settings.Setting import Setting |
||
33 | |||
34 | from pygments import highlight |
||
0 ignored issues
–
show
Unused Code
introduced
by
![]() |
|||
35 | from pygments.formatters import (TerminalTrueColorFormatter, |
||
0 ignored issues
–
show
|
|||
36 | TerminalFormatter) |
||
37 | from pygments.filters import VisibleWhitespaceFilter |
||
38 | from pygments.lexers import TextLexer |
||
39 | from pygments.style import Style |
||
0 ignored issues
–
show
|
|||
40 | from pygments.token import Token |
||
0 ignored issues
–
show
|
|||
41 | |||
42 | |||
43 | STR_GET_VAL_FOR_SETTING = ("Please enter a value for the setting \"{}\" ({}) " |
||
44 | "needed by {}: ") |
||
45 | STR_LINE_DOESNT_EXIST = ("The line belonging to the following result " |
||
46 | "cannot be printed because it refers to a line " |
||
47 | "that doesn't seem to exist in the given file.") |
||
48 | STR_PROJECT_WIDE = "Project wide:" |
||
49 | |||
50 | |||
51 | class TestAction(ResultAction): |
||
52 | |||
53 | def apply(self, result, original_file_dict, file_diff_dict, param): |
||
54 | pass |
||
55 | |||
56 | |||
57 | class TestBear(Bear): |
||
58 | |||
59 | CAN_DETECT = {'Formatting'} |
||
60 | CAN_FIX = {'Formatting'} |
||
61 | LANGUAGES = list(sorted({'F#', 'Shakespearean Programming Language'})) |
||
62 | |||
63 | def run(self, setting1, setting2: int=None): |
||
64 | """ |
||
65 | Test bear Description. |
||
66 | |||
67 | :param setting1: Required Setting. |
||
68 | :param setting2: Optional Setting. |
||
69 | """ |
||
70 | return None |
||
71 | |||
72 | |||
73 | class TestBear2(Bear): |
||
74 | |||
75 | LANGUAGES = {'TestLanguage'} |
||
76 | |||
77 | def run(self, setting1): |
||
78 | """ |
||
79 | Test bear 2 description. |
||
80 | |||
81 | :param setting1: Required Setting. |
||
82 | """ |
||
83 | return None |
||
84 | |||
85 | |||
86 | class SomeBear(Bear): |
||
87 | |||
88 | def run(self): |
||
89 | """ |
||
90 | Some Description. |
||
91 | """ |
||
92 | return None |
||
93 | |||
94 | |||
95 | class SomeOtherBear(Bear): |
||
96 | |||
97 | def run(self, setting: int=None): |
||
98 | """ |
||
99 | This is a Bear. |
||
100 | :param setting: This is an optional setting. |
||
101 | """ |
||
102 | setting = 1 |
||
103 | return None |
||
104 | |||
105 | |||
106 | class SomeglobalBear(Bear): |
||
107 | |||
108 | def run(self): |
||
109 | """ |
||
110 | Some global-bear Description. |
||
111 | """ |
||
112 | return None |
||
113 | |||
114 | |||
115 | class SomelocalBear(Bear): |
||
116 | |||
117 | def run(self): |
||
118 | """ |
||
119 | Some local-bear Description. |
||
120 | """ |
||
121 | return None |
||
122 | |||
123 | |||
124 | class ConsoleInteractionTest(unittest.TestCase): |
||
125 | |||
126 | def setUp(self): |
||
127 | self.log_printer = LogPrinter(ConsolePrinter(print_colored=False)) |
||
128 | self.console_printer = ConsolePrinter(print_colored=False) |
||
129 | self.file_diff_dict = {} |
||
130 | self.section = Section("t") |
||
131 | self.local_bears = OrderedDict([("default", [SomelocalBear]), |
||
132 | ("test", [SomelocalBear])]) |
||
133 | self.global_bears = OrderedDict([("default", [SomeglobalBear]), |
||
134 | ("test", [SomeglobalBear])]) |
||
135 | |||
136 | self.old_open_editor_applicable = OpenEditorAction.is_applicable |
||
137 | OpenEditorAction.is_applicable = staticmethod(lambda *args: False) |
||
138 | |||
139 | self.old_apply_patch_applicable = ApplyPatchAction.is_applicable |
||
140 | ApplyPatchAction.is_applicable = staticmethod(lambda *args: False) |
||
141 | self.lexer = TextLexer() |
||
142 | self.lexer.add_filter(VisibleWhitespaceFilter( |
||
143 | spaces="•", |
||
144 | tabs=True, |
||
145 | tabsize=SpacingHelper.DEFAULT_TAB_WIDTH)) |
||
146 | |||
147 | def tearDown(self): |
||
148 | OpenEditorAction.is_applicable = self.old_open_editor_applicable |
||
149 | ApplyPatchAction.is_applicable = self.old_apply_patch_applicable |
||
150 | |||
151 | def test_require_settings(self): |
||
152 | self.assertRaises(TypeError, acquire_settings, self.log_printer, 0) |
||
153 | |||
154 | with simulate_console_inputs(0, 1, 2) as generator: |
||
155 | self.assertEqual(acquire_settings(self.log_printer, |
||
156 | {"setting": ["help text", |
||
157 | "SomeBear"]}), |
||
158 | {"setting": 0}) |
||
159 | |||
160 | self.assertEqual(acquire_settings(self.log_printer, |
||
161 | {"setting": ["help text", |
||
162 | "SomeBear", |
||
163 | "AnotherBear"]}), |
||
164 | {"setting": 1}) |
||
165 | |||
166 | self.assertEqual(acquire_settings(self.log_printer, |
||
167 | {"setting": ["help text", |
||
168 | "SomeBear", |
||
169 | "AnotherBear", |
||
170 | "YetAnotherBear"]}), |
||
171 | {"setting": 2}) |
||
172 | |||
173 | self.assertEqual(generator.last_input, 2) |
||
174 | |||
175 | def test_print_diffs_info(self): |
||
176 | file_dict = {"a": ["a\n", "b\n", "c\n"], "b": ["old_first\n"]} |
||
177 | diff_dict = {"a": Diff(file_dict['a']), |
||
178 | "b": Diff(file_dict['b'])} |
||
179 | diff_dict["a"].add_lines(1, ["test\n"]) |
||
180 | diff_dict["a"].delete_line(3) |
||
181 | diff_dict["b"].add_lines(0, ["first\n"]) |
||
182 | previous_diffs = {"a": Diff(file_dict['a'])} |
||
183 | previous_diffs["a"].change_line(2, "b\n", "b_changed\n") |
||
184 | with retrieve_stdout() as stdout: |
||
185 | print_diffs_info(diff_dict, self.console_printer) |
||
186 | self.assertEqual(stdout.getvalue(), |
||
187 | "| | +1 -1 in a\n" |
||
188 | "| | +1 -0 in b\n") |
||
189 | |||
190 | @patch("coalib.output.ConsoleInteraction.acquire_actions_and_apply") |
||
191 | @patch("coalib.output.ConsoleInteraction.ShowPatchAction." |
||
192 | "apply_from_section") |
||
193 | def test_print_result_interactive_small_patch(self, apply_from_section, _): |
||
194 | file_dict = {"a": ["a\n", "b\n", "c\n"], "b": ["old_first\n"]} |
||
195 | diff_dict = {"a": Diff(file_dict['a']), |
||
196 | "b": Diff(file_dict['b'])} |
||
197 | diff_dict["a"].add_lines(1, ["test\n"]) |
||
198 | diff_dict["a"].delete_line(3) |
||
199 | result = Result("origin", "msg", diffs=diff_dict) |
||
200 | section = Section("test") |
||
201 | |||
202 | print_result(self.console_printer, |
||
203 | self.log_printer, |
||
204 | section, |
||
205 | self.file_diff_dict, |
||
206 | result, |
||
207 | file_dict, |
||
208 | True) |
||
209 | apply_from_section.assert_called_once_with( |
||
210 | result, file_dict, self.file_diff_dict, section) |
||
211 | |||
212 | @patch("coalib.output.ConsoleInteraction.acquire_actions_and_apply") |
||
213 | @patch("coalib.output.ConsoleInteraction.print_diffs_info") |
||
214 | def test_print_result_interactive_big_patch(self, diffs_info, _): |
||
215 | file_dict = {"a": ["a\n", "b\n", "c\n"], "b": ["old_first\n"]} |
||
216 | diff_dict = {"a": Diff(file_dict['a']), |
||
217 | "b": Diff(file_dict['b'])} |
||
218 | diff_dict["a"].add_lines(1, ["test\n", "test1\n", "test2\n"]) |
||
219 | diff_dict["a"].delete_line(3) |
||
220 | diff_dict["a"].add_lines(3, ["3test\n"]) |
||
221 | result = Result("origin", "msg", diffs=diff_dict) |
||
222 | section = Section("test") |
||
223 | |||
224 | print_result(self.console_printer, |
||
225 | self.log_printer, |
||
226 | section, |
||
227 | self.file_diff_dict, |
||
228 | result, |
||
229 | file_dict, |
||
230 | True) |
||
231 | diffs_info.assert_called_once_with(diff_dict, self.console_printer) |
||
232 | |||
233 | def test_print_result(self): |
||
234 | print_result(self.console_printer, |
||
235 | self.log_printer, |
||
236 | None, |
||
237 | self.file_diff_dict, |
||
238 | "illegal value", |
||
239 | {}) |
||
240 | |||
241 | with simulate_console_inputs(0): |
||
242 | print_result(self.console_printer, |
||
243 | self.log_printer, |
||
244 | self.section, |
||
245 | self.file_diff_dict, |
||
246 | Result("origin", "msg", diffs={}), |
||
247 | {}) |
||
248 | |||
249 | with make_temp() as testfile_path: |
||
250 | file_dict = { |
||
251 | testfile_path: ["1\n", "2\n", "3\n"], |
||
252 | "f_b": ["1", "2", "3"] |
||
253 | } |
||
254 | diff = Diff(file_dict[testfile_path]) |
||
255 | diff.delete_line(2) |
||
256 | diff.change_line(3, "3\n", "3_changed\n") |
||
257 | |||
258 | ApplyPatchAction.is_applicable = staticmethod( |
||
259 | lambda *args: True) |
||
260 | |||
261 | # Interaction must be closed by the user with `0` if it's not a |
||
262 | # param |
||
263 | with simulate_console_inputs("INVALID", |
||
264 | -1, |
||
265 | 1, |
||
266 | 0, |
||
267 | 3) as input_generator: |
||
268 | curr_section = Section("") |
||
269 | print_section_beginning(self.console_printer, curr_section) |
||
270 | print_result(self.console_printer, |
||
271 | self.log_printer, |
||
272 | curr_section, |
||
273 | self.file_diff_dict, |
||
274 | Result("origin", "msg", diffs={ |
||
275 | testfile_path: diff}), |
||
276 | file_dict) |
||
277 | self.assertEqual(input_generator.last_input, 3) |
||
278 | |||
279 | self.file_diff_dict.clear() |
||
280 | |||
281 | with open(testfile_path) as f: |
||
282 | self.assertEqual(f.readlines(), ["1\n", "3_changed\n"]) |
||
283 | |||
284 | os.remove(testfile_path + ".orig") |
||
285 | |||
286 | name, section = get_action_info(curr_section, |
||
287 | TestAction().get_metadata(), |
||
288 | failed_actions=set()) |
||
289 | self.assertEqual(input_generator.last_input, 4) |
||
290 | self.assertEqual(str(section), " {param : '3'}") |
||
291 | self.assertEqual(name, "TestAction") |
||
292 | |||
293 | # Check if the user is asked for the parameter only the first time. |
||
294 | # Use OpenEditorAction that needs this parameter (editor command). |
||
295 | with simulate_console_inputs(1, "test_editor", 0, 1, 0) as generator: |
||
296 | OpenEditorAction.is_applicable = staticmethod(lambda *args: True) |
||
297 | |||
298 | patch_result = Result("origin", "msg", diffs={testfile_path: diff}) |
||
299 | patch_result.file = "f_b" |
||
300 | |||
301 | print_result(self.console_printer, |
||
302 | self.log_printer, |
||
303 | curr_section, |
||
304 | self.file_diff_dict, |
||
305 | patch_result, |
||
306 | file_dict) |
||
307 | # choose action, choose editor, choose no action (-1 -> 2) |
||
308 | self.assertEqual(generator.last_input, 2) |
||
309 | |||
310 | # It shoudn't ask for parameter again |
||
311 | print_result(self.console_printer, |
||
312 | self.log_printer, |
||
313 | curr_section, |
||
314 | self.file_diff_dict, |
||
315 | patch_result, |
||
316 | file_dict) |
||
317 | self.assertEqual(generator.last_input, 4) |
||
318 | |||
319 | def test_print_affected_files(self): |
||
320 | with retrieve_stdout() as stdout, \ |
||
321 | make_temp() as some_file: |
||
322 | file_dict = {some_file: ["1\n", "2\n", "3\n"]} |
||
323 | affected_code = (SourceRange.from_values(some_file),) |
||
324 | print_affected_files(self.console_printer, |
||
325 | self.log_printer, |
||
326 | Section(""), |
||
327 | Result("origin", |
||
328 | "message", |
||
329 | affected_code=affected_code), |
||
330 | file_dict, |
||
331 | color=True) |
||
332 | self.assertEqual(stdout.getvalue(), |
||
333 | "\n"+relpath(some_file)+"\n") |
||
334 | |||
335 | def test_acquire_actions_and_apply(self): |
||
336 | with make_temp() as testfile_path: |
||
337 | file_dict = {testfile_path: ["1\n", "2\n", "3\n"]} |
||
338 | diff = Diff(file_dict[testfile_path]) |
||
339 | diff.delete_line(2) |
||
340 | diff.change_line(3, "3\n", "3_changed\n") |
||
341 | with simulate_console_inputs(1, 0) as generator, \ |
||
342 | retrieve_stdout() as sio: |
||
343 | ApplyPatchAction.is_applicable = staticmethod( |
||
344 | lambda *args: True) |
||
345 | acquire_actions_and_apply(self.console_printer, |
||
346 | self.log_printer, |
||
347 | Section(""), |
||
348 | self.file_diff_dict, |
||
349 | Result("origin", "message", diffs={ |
||
350 | testfile_path: diff}), |
||
351 | file_dict) |
||
352 | self.assertEqual(generator.last_input, 1) |
||
353 | self.assertIn(ApplyPatchAction.SUCCESS_MESSAGE, sio.getvalue()) |
||
354 | |||
355 | class InvalidateTestAction(ResultAction): |
||
356 | |||
357 | is_applicable = staticmethod(lambda *args: True) |
||
358 | |||
359 | def apply(*args, **kwargs): |
||
360 | ApplyPatchAction.is_applicable = staticmethod( |
||
361 | lambda *args: False) |
||
362 | |||
363 | old_applypatch_is_applicable = ApplyPatchAction.is_applicable |
||
364 | ApplyPatchAction.is_applicable = staticmethod(lambda *args: True) |
||
365 | cli_actions = [ApplyPatchAction(), InvalidateTestAction()] |
||
366 | |||
367 | with simulate_console_inputs(2, 1, 0) as generator, \ |
||
368 | retrieve_stdout() as sio: |
||
369 | acquire_actions_and_apply(self.console_printer, |
||
370 | self.log_printer, |
||
371 | Section(""), |
||
372 | self.file_diff_dict, |
||
373 | Result("origin", "message", |
||
374 | diffs={testfile_path: diff}), |
||
375 | file_dict, |
||
376 | cli_actions=cli_actions) |
||
377 | self.assertEqual(generator.last_input, 2) |
||
378 | |||
379 | action_fail = "Failed to execute the action" |
||
380 | self.assertNotIn(action_fail, sio.getvalue()) |
||
381 | |||
382 | apply_path_desc = ApplyPatchAction().get_metadata().desc |
||
383 | self.assertEqual(sio.getvalue().count(apply_path_desc), 1) |
||
384 | |||
385 | ApplyPatchAction.is_applicable = old_applypatch_is_applicable |
||
386 | |||
387 | def test_ask_for_actions_and_apply(self): |
||
388 | failed_actions = set() |
||
389 | action = TestAction() |
||
390 | args = [self.log_printer, self.console_printer, Section(""), |
||
391 | [action.get_metadata()], {'TestAction': action}, |
||
392 | failed_actions, Result("origin", "message"), {}, {}] |
||
393 | |||
394 | with simulate_console_inputs(1, 'param1', 1, 'param2') as generator: |
||
395 | action.apply = unittest.mock.Mock(side_effect=AssertionError) |
||
396 | ask_for_action_and_apply(*args) |
||
397 | self.assertEqual(generator.last_input, 1) |
||
398 | self.assertIn('TestAction', failed_actions) |
||
399 | |||
400 | action.apply = lambda *args, **kwargs: {} |
||
401 | ask_for_action_and_apply(*args) |
||
402 | self.assertEqual(generator.last_input, 3) |
||
403 | self.assertNotIn('TestAction', failed_actions) |
||
404 | |||
405 | def test_default_input(self): |
||
406 | action = TestAction() |
||
407 | args = [self.log_printer, self.console_printer, Section(""), |
||
408 | [action.get_metadata()], {'TestAction': action}, |
||
409 | set(), Result("origin", "message"), {}, {}] |
||
410 | |||
411 | with simulate_console_inputs("") as generator: |
||
412 | self.assertFalse(ask_for_action_and_apply(*args)) |
||
413 | |||
414 | def test_print_result_no_input(self): |
||
415 | with make_temp() as testfile_path: |
||
416 | file_dict = {testfile_path: ["1\n", "2\n", "3\n"]} |
||
417 | diff = Diff(file_dict[testfile_path]) |
||
418 | diff.delete_line(2) |
||
419 | diff.change_line(3, "3\n", "3_changed\n") |
||
420 | with simulate_console_inputs(1, 2, 3) as generator, \ |
||
421 | retrieve_stdout() as stdout: |
||
422 | ApplyPatchAction.is_applicable = staticmethod( |
||
423 | lambda *args: True) |
||
424 | print_results_no_input(self.log_printer, |
||
425 | Section("someSection"), |
||
426 | [Result("origin", "message", diffs={ |
||
427 | testfile_path: diff})], |
||
428 | file_dict, |
||
429 | self.file_diff_dict, |
||
430 | color=False) |
||
431 | self.assertEqual(generator.last_input, -1) |
||
432 | self.assertEqual(stdout.getvalue(), |
||
433 | """ |
||
434 | Project wide: |
||
435 | | | [NORMAL] origin: |
||
436 | | | {}\n""".format(highlight_text("message", style=BackgroundMessageStyle))) |
||
437 | |||
438 | def test_print_section_beginning(self): |
||
439 | with retrieve_stdout() as stdout: |
||
440 | print_section_beginning(self.console_printer, Section("name")) |
||
441 | self.assertEqual(stdout.getvalue(), "Executing section name...\n") |
||
442 | |||
443 | def test_nothing_done(self): |
||
444 | with retrieve_stdout() as stdout: |
||
445 | nothing_done(self.log_printer) |
||
446 | self.assertIn("No existent section was targeted or enabled. " |
||
447 | "Nothing to do.\n", |
||
448 | stdout.getvalue()) |
||
449 | |||
450 | def test_print_results_empty(self): |
||
451 | with retrieve_stdout() as stdout: |
||
452 | print_results(self.log_printer, Section(""), [], {}, {}) |
||
453 | self.assertEqual(stdout.getvalue(), "") |
||
454 | |||
455 | def test_print_results_project_wide(self): |
||
456 | with retrieve_stdout() as stdout: |
||
457 | print_results(self.log_printer, |
||
458 | Section(""), |
||
459 | [Result("origin", "message")], |
||
460 | {}, |
||
461 | {}, |
||
462 | color=False) |
||
463 | self.assertEqual( |
||
464 | "\n{}\n| | [NORMAL] origin:\n| | {}\n".format( |
||
465 | STR_PROJECT_WIDE, |
||
466 | highlight_text("message", style=BackgroundMessageStyle)), |
||
467 | stdout.getvalue()) |
||
468 | |||
469 | def test_print_results_for_file(self): |
||
470 | with retrieve_stdout() as stdout: |
||
471 | print_results( |
||
472 | self.log_printer, |
||
473 | Section(""), |
||
474 | [Result.from_values("SpaceConsistencyBear", |
||
475 | "Trailing whitespace found", |
||
476 | file="filename", |
||
477 | line=2)], |
||
478 | {abspath("filename"): ["test line\n", "line 2\n", "line 3\n"]}, |
||
479 | {}, |
||
480 | color=False) |
||
481 | self.assertEqual("""\nfilename |
||
482 | | 2| {} |
||
483 | | | [NORMAL] SpaceConsistencyBear: |
||
484 | | | {}\n""".format(highlight_text('line 2', self.lexer), |
||
485 | highlight_text("Trailing whitespace found", |
||
486 | style=BackgroundMessageStyle)), |
||
487 | stdout.getvalue()) |
||
488 | |||
489 | with retrieve_stdout() as stdout: |
||
490 | print_results( |
||
491 | self.log_printer, |
||
492 | Section(""), |
||
493 | [Result.from_values("SpaceConsistencyBear", |
||
494 | "Trailing whitespace found", |
||
495 | file="filename", |
||
496 | line=5)], |
||
497 | {abspath("filename"): ["test line\n", |
||
498 | "line 2\n", |
||
499 | "line 3\n", |
||
500 | "line 4\n", |
||
501 | "line 5\n"]}, |
||
502 | {}, |
||
503 | color=False) |
||
504 | self.assertEqual("""\nfilename |
||
505 | | 5| {} |
||
506 | | | [NORMAL] SpaceConsistencyBear: |
||
507 | | | {}\n""".format(highlight_text('line 5', self.lexer), |
||
508 | highlight_text("Trailing whitespace found", |
||
509 | style=BackgroundMessageStyle)), |
||
510 | stdout.getvalue()) |
||
511 | |||
512 | def test_print_results_sorting(self): |
||
513 | with retrieve_stdout() as stdout: |
||
514 | print_results(self.log_printer, |
||
515 | Section(""), |
||
516 | [Result.from_values("SpaceConsistencyBear", |
||
517 | "Trailing whitespace found", |
||
518 | file="file", |
||
519 | line=5), |
||
520 | Result.from_values("SpaceConsistencyBear", |
||
521 | "Trailing whitespace found", |
||
522 | file="file", |
||
523 | line=2)], |
||
524 | {abspath("file"): ["test line\n", |
||
525 | "\t\n", |
||
526 | "line 3\n", |
||
527 | "line 4\n", |
||
528 | "line 5\t\n"]}, |
||
529 | {}, |
||
530 | color=False) |
||
531 | |||
532 | self.assertEqual(""" |
||
533 | file |
||
534 | | 2| {0} |
||
535 | | | [NORMAL] SpaceConsistencyBear: |
||
536 | | | {1} |
||
537 | |||
538 | file |
||
539 | | 5| {2} |
||
540 | | | [NORMAL] SpaceConsistencyBear: |
||
541 | | | {1}\n""".format(highlight_text('\t', self.lexer), |
||
542 | highlight_text("Trailing whitespace found", |
||
543 | style=BackgroundMessageStyle), |
||
544 | highlight_text('line 5\t', self.lexer)), |
||
545 | stdout.getvalue()) |
||
546 | |||
547 | def test_print_results_multiple_ranges(self): |
||
548 | affected_code = ( |
||
549 | SourceRange.from_values("some_file", 5, end_line=7), |
||
550 | SourceRange.from_values("another_file", 1, 3, 1, 5), |
||
551 | SourceRange.from_values("another_file", 3, 3, 3, 5)) |
||
552 | with retrieve_stdout() as stdout: |
||
553 | print_results( |
||
554 | self.log_printer, |
||
555 | Section(""), |
||
556 | [Result("ClangCloneDetectionBear", |
||
557 | "Clone Found", |
||
558 | affected_code)], |
||
559 | {abspath("some_file"): ["line " + str(i + 1) + "\n" |
||
560 | for i in range(10)], |
||
561 | abspath("another_file"): ["line " + str(i + 1) |
||
562 | for i in range(10)]}, |
||
563 | {}, |
||
564 | color=False) |
||
565 | self.assertEqual(""" |
||
566 | another_file |
||
567 | | 1| li{0}{1} |
||
568 | |||
569 | another_file |
||
570 | | 3| li{0}{2} |
||
571 | |||
572 | some_file |
||
573 | | 5| {3} |
||
574 | | 6| {4} |
||
575 | | 7| {5} |
||
576 | | | [NORMAL] ClangCloneDetectionBear: |
||
577 | | | {6}\n""".format(highlight_text('ne', self.lexer, |
||
578 | BackgroundSourceRangeStyle), |
||
579 | highlight_text(' 1', self.lexer), |
||
580 | highlight_text(' 3', self.lexer), |
||
581 | highlight_text('line 5', self.lexer), |
||
582 | highlight_text('line 6', self.lexer), |
||
583 | highlight_text('line 7', self.lexer), |
||
584 | highlight_text("Clone Found", |
||
585 | style=BackgroundMessageStyle)), |
||
586 | stdout.getvalue()) |
||
587 | |||
588 | def test_print_results_missing_file(self): |
||
589 | self.log_printer = LogPrinter(NullPrinter()) |
||
590 | with retrieve_stdout() as stdout: |
||
591 | print_results( |
||
592 | self.log_printer, |
||
593 | Section(""), |
||
594 | [Result("t", "msg"), |
||
595 | Result.from_values("t", "msg", file="file", line=5)], |
||
596 | {}, |
||
597 | {}, |
||
598 | color=False) |
||
599 | self.assertEqual("\n" + STR_PROJECT_WIDE + "\n" |
||
600 | "| | [NORMAL] t:\n" |
||
601 | "| | {0}\n" |
||
602 | # Second results file isn't there, no context is |
||
603 | # printed, only a warning log message which we |
||
604 | # don't catch |
||
605 | "| | [NORMAL] t:\n" |
||
606 | "| | {0}\n".format( |
||
607 | highlight_text("msg", |
||
608 | style=BackgroundMessageStyle)), |
||
609 | stdout.getvalue()) |
||
610 | |||
611 | def test_print_results_missing_line(self): |
||
612 | with retrieve_stdout() as stdout: |
||
613 | print_results( |
||
614 | self.log_printer, |
||
615 | Section(""), |
||
616 | [Result.from_values("t", "msg", file="file", line=5), |
||
617 | Result.from_values("t", "msg", file="file", line=6)], |
||
618 | {abspath("file"): ["line " + str(i + 1) for i in range(5)]}, |
||
619 | {}, |
||
620 | color=False) |
||
621 | self.assertEqual("\n" |
||
622 | "file\n" |
||
623 | "| 5| {0}\n" |
||
624 | "| | [NORMAL] t:\n" |
||
625 | "| | {1}\n" |
||
626 | "\n" |
||
627 | "file\n" |
||
628 | "| 6| {2}\n" |
||
629 | "| | [NORMAL] t:\n" |
||
630 | "| | {1}\n".format( |
||
631 | highlight_text('line 5', self.lexer), |
||
632 | highlight_text("msg", |
||
633 | style=BackgroundMessageStyle), |
||
634 | STR_LINE_DOESNT_EXIST), |
||
635 | stdout.getvalue()) |
||
636 | |||
637 | def test_print_results_without_line(self): |
||
638 | with retrieve_stdout() as stdout: |
||
639 | print_results( |
||
640 | self.log_printer, |
||
641 | Section(""), |
||
642 | [Result.from_values("t", "msg", file="file")], |
||
643 | {abspath("file"): []}, |
||
644 | {}, |
||
645 | color=False) |
||
646 | self.assertEqual( |
||
647 | "\nfile\n" |
||
648 | "| | [NORMAL] t:\n" |
||
649 | "| | {}\n".format(highlight_text( |
||
650 | "msg", style=BackgroundMessageStyle)), |
||
651 | stdout.getvalue()) |
||
652 | |||
653 | |||
654 | class ShowBearsTest(unittest.TestCase): |
||
655 | |||
656 | def setUp(self): |
||
657 | self.console_printer = ConsolePrinter(print_colored=False) |
||
658 | |||
659 | def test_show_bear_minimal(self): |
||
660 | with retrieve_stdout() as stdout: |
||
661 | show_bear( |
||
662 | SomelocalBear, False, False, self.console_printer) |
||
663 | self.assertEqual(stdout.getvalue(), 'SomelocalBear\n') |
||
664 | |||
665 | def test_show_bear_desc_only(self): |
||
666 | with retrieve_stdout() as stdout: |
||
667 | show_bear( |
||
668 | SomelocalBear, True, False, self.console_printer) |
||
669 | self.assertEqual( |
||
670 | stdout.getvalue(), |
||
671 | 'SomelocalBear\n Some local-bear Description.\n\n') |
||
672 | |||
673 | def test_show_bear_details_only(self): |
||
674 | with retrieve_stdout() as stdout: |
||
675 | show_bear( |
||
676 | SomelocalBear, False, True, self.console_printer) |
||
677 | self.assertEqual(stdout.getvalue(), |
||
678 | 'SomelocalBear\n' |
||
679 | ' The bear does not provide information about ' |
||
680 | 'which languages it can analyze.\n\n' |
||
681 | ' No needed settings.\n\n' |
||
682 | ' No optional settings.\n\n' |
||
683 | ' This bear does not provide information about ' |
||
684 | 'what categories it can detect.\n\n' |
||
685 | ' This bear cannot fix issues or does not ' |
||
686 | 'provide information about what categories it ' |
||
687 | 'can fix.\n\n') |
||
688 | |||
689 | def test_show_bear_long_without_content(self): |
||
690 | with retrieve_stdout() as stdout: |
||
691 | show_bear( |
||
692 | SomelocalBear, True, True, self.console_printer) |
||
693 | self.assertEqual(stdout.getvalue(), |
||
694 | 'SomelocalBear\n' |
||
695 | ' Some local-bear Description.\n\n' |
||
696 | ' The bear does not provide information about ' |
||
697 | 'which languages it can analyze.\n\n' |
||
698 | ' No needed settings.\n\n' |
||
699 | ' No optional settings.\n\n' |
||
700 | ' This bear does not provide information about ' |
||
701 | 'what categories it can detect.\n\n' |
||
702 | ' This bear cannot fix issues or does not ' |
||
703 | 'provide information about what categories it ' |
||
704 | 'can fix.\n\n') |
||
705 | |||
706 | def test_show_bear_with_content(self): |
||
707 | with retrieve_stdout() as stdout: |
||
708 | show_bear(TestBear, True, True, self.console_printer) |
||
709 | self.assertEqual(stdout.getvalue(), |
||
710 | "TestBear\n" |
||
711 | " Test bear Description.\n\n" |
||
712 | " Supported languages:\n" |
||
713 | " * F#\n" |
||
714 | " * Shakespearean Programming Language\n\n" |
||
715 | " Needed Settings:\n" |
||
716 | " * setting1: Required Setting.\n\n" |
||
717 | " Optional Settings:\n" |
||
718 | " * setting2: Optional Setting. (" |
||
719 | "Optional, defaults to 'None'." |
||
720 | ")\n\n" |
||
721 | ' Can detect:\n * Formatting\n\n' |
||
722 | ' Can fix:\n * Formatting\n\n') |
||
723 | |||
724 | def test_show_bears_empty(self): |
||
725 | with retrieve_stdout() as stdout: |
||
726 | show_bears({}, {}, True, True, self.console_printer) |
||
727 | self.assertIn("No bears to show.", stdout.getvalue()) |
||
728 | |||
729 | @patch('coalib.output.ConsoleInteraction.show_bear') |
||
730 | def test_show_bears(self, show_bear): |
||
0 ignored issues
–
show
show_bear is re-defining a name which is already available in the outer-scope (previously defined on line 15 ).
It is generally a bad practice to shadow variables from the outer-scope. In most cases, this is done unintentionally and might lead to unexpected behavior: param = 5
class Foo:
def __init__(self, param): # "param" would be flagged here
self.param = param
![]() |
|||
731 | local_bears = OrderedDict([("default", [SomelocalBear]), |
||
732 | ("test", [SomelocalBear])]) |
||
733 | show_bears(local_bears, {}, True, True, self.console_printer) |
||
734 | show_bear.assert_called_once_with(SomelocalBear, |
||
735 | True, |
||
736 | True, |
||
737 | self.console_printer) |
||
738 | |||
739 | def test_show_bears_capabilities(self): |
||
740 | with retrieve_stdout() as stdout: |
||
741 | show_language_bears_capabilities( |
||
742 | {'some_language': ({'Formatting', 'Security'}, {'Formatting'})}, |
||
743 | self.console_printer) |
||
744 | self.assertIn('coala can do the following for SOME_LANGUAGE\n' |
||
745 | ' Can detect only: Formatting, Security\n' |
||
746 | ' Can fix : Formatting\n', |
||
747 | stdout.getvalue()) |
||
748 | show_language_bears_capabilities( |
||
749 | {'some_language': (set(), set())}, self.console_printer) |
||
750 | self.assertIn('coala does not support some_language', |
||
751 | stdout.getvalue()) |
||
752 | show_language_bears_capabilities( |
||
753 | {}, self.console_printer) |
||
754 | self.assertIn( |
||
755 | 'There is no bear available for this language', |
||
756 | stdout.getvalue()) |
||
757 | show_language_bears_capabilities( |
||
758 | {'some_language': ({'Formatting', 'Security'}, set())}, |
||
759 | self.console_printer) |
||
760 | self.assertIn('coala can do the following for SOME_LANGUAGE\n' |
||
761 | ' Can detect only: Formatting, Security\n', |
||
762 | stdout.getvalue()) |
||
763 | # Own test because this is easy and not tied to the rest |
||
764 | |||
765 | |||
766 | class PrintFormattedResultsTest(unittest.TestCase): |
||
767 | |||
768 | def setUp(self): |
||
769 | self.printer = StringPrinter() |
||
770 | self.logger = LogPrinter(self.printer) |
||
771 | self.section = Section("t") |
||
772 | |||
773 | def test_default_format(self): |
||
774 | expected_string = ("id:-?[0-9]+:origin:1:file:None:line:None:" |
||
775 | "column:None:end_line:None:end_column:None:" |
||
776 | "severity:1:severity_str:NORMAL:message:2\n") |
||
777 | with retrieve_stdout() as stdout: |
||
778 | print_results_formatted(self.logger, |
||
779 | self.section, |
||
780 | [Result("1", "2")], |
||
781 | None, |
||
782 | None) |
||
783 | self.assertRegex(stdout.getvalue(), expected_string) |
||
784 | |||
785 | def test_multiple_ranges(self): |
||
786 | expected_string = ( |
||
787 | "id:-?[0-9]+:origin:1:.*file:.*another_file:line:5:" |
||
788 | "column:3:end_line:5:end_column:5:" |
||
789 | "severity:1:severity_str:NORMAL:message:2\n" |
||
790 | "id:-?[0-9]+:origin:1:.*file:.*some_file:line:5:" |
||
791 | "column:None:end_line:7:end_column:None:" |
||
792 | "severity:1:severity_str:NORMAL:message:2\n") |
||
793 | affected_code = (SourceRange.from_values("some_file", 5, end_line=7), |
||
794 | SourceRange.from_values("another_file", 5, 3, 5, 5)) |
||
795 | with retrieve_stdout() as stdout: |
||
796 | print_results_formatted(self.logger, |
||
797 | self.section, |
||
798 | [Result("1", "2", affected_code)], |
||
799 | None, |
||
800 | None) |
||
801 | self.assertRegex(stdout.getvalue(), expected_string) |
||
802 | |||
803 | def test_bad_format(self): |
||
804 | self.section.append(Setting("format_str", "{nonexistant}")) |
||
805 | print_results_formatted(self.logger, |
||
806 | self.section, |
||
807 | [Result("1", "2")], |
||
808 | None, |
||
809 | None) |
||
810 | self.assertRegex(self.printer.string, ".*Unable to print.*") |
||
811 | |||
812 | def test_good_format(self): |
||
813 | self.section.append(Setting("format_str", "{origin}")) |
||
814 | with retrieve_stdout() as stdout: |
||
815 | print_results_formatted(self.logger, |
||
816 | self.section, |
||
817 | [Result("1", "2")], |
||
818 | None, |
||
819 | None) |
||
820 | self.assertEqual(stdout.getvalue(), "1\n") |
||
821 | |||
822 | def test_empty_list(self): |
||
823 | self.section.append(Setting("format_str", "{origin}")) |
||
824 | # Shouldn't attempt to format the string None and will fail badly if |
||
825 | # its done wrong. |
||
826 | print_results_formatted(None, |
||
827 | self.section, |
||
828 | [], |
||
829 | None, |
||
830 | None, |
||
831 | None) |
||
832 |