Issues (70)

tests/output/ConsoleInteractionTest.py (6 issues)

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 highlight imported from pygments
Loading history...
35
from pygments.formatters import (TerminalTrueColorFormatter,
0 ignored issues
show
Unused TerminalFormatter imported from pygments.formatters
Loading history...
Unused TerminalTrueColorFormatter imported from pygments.formatters
Loading history...
36
                                 TerminalFormatter)
37
from pygments.filters import VisibleWhitespaceFilter
38
from pygments.lexers import TextLexer
39
from pygments.style import Style
0 ignored issues
show
Unused Style imported from pygments.style
Loading history...
40
from pygments.token import Token
0 ignored issues
show
Unused Token imported from pygments.token
Loading history...
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
Comprehensibility Bug introduced by
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
Loading history...
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