Failed Conditions
Pull Request — master (#1626)
by Abdeali
01:44
created

coalib.tests.output.ConsoleInteractionTest.test_show_bears()   A

Complexity

Conditions 4

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 4
dl 0
loc 21
rs 9.0534
1
import os
2
import unittest
3
from collections import OrderedDict
4
from os.path import abspath, relpath
5
6
from pyprint.ConsolePrinter import ConsolePrinter
7
from pyprint.NullPrinter import NullPrinter
8
9
from coalib.bears.Bear import Bear
10
from coalib.misc.ContextManagers import (
11
    make_temp, retrieve_stdout, simulate_console_inputs)
12
from coalib.output.ConsoleInteraction import (
13
    acquire_actions_and_apply, acquire_settings, get_action_info, nothing_done,
14
    print_affected_files, print_bears, print_result, print_results,
15
    print_results_formatted, print_results_no_input, print_section_beginning,
16
    show_bears)
17
from coalib.output.printers.LogPrinter import LogPrinter
18
from coalib.output.printers.StringPrinter import StringPrinter
19
from coalib.results.Diff import Diff
20
from coalib.results.Result import Result
21
from coalib.results.result_actions.ApplyPatchAction import ApplyPatchAction
22
from coalib.results.result_actions.OpenEditorAction import OpenEditorAction
23
from coalib.results.result_actions.ResultAction import ResultAction
24
from coalib.results.SourceRange import SourceRange
25
from coalib.settings.Section import Section
26
from coalib.settings.Setting import Setting
27
28
STR_GET_VAL_FOR_SETTING = ("Please enter a value for the setting \"{}\" ({}) "
29
                           "needed by {}: ")
30
STR_LINE_DOESNT_EXIST = ("The line belonging to the following result "
31
                         "cannot be printed because it refers to a line "
32
                         "that doesn't seem to exist in the given file.")
33
STR_PROJECT_WIDE = "Project wide:"
34
35
36
class TestAction(ResultAction):
37
38
    def apply(self, result, original_file_dict, file_diff_dict, param):
39
        pass
40
41
42
class TestBear(Bear):
43
44
    def run(self, setting1, setting2: int=None):
45
        """
46
        Test bear Description.
47
48
        :param setting1: Required Setting.
49
        :param setting2: Optional Setting.
50
        """
51
        return None
52
53
54
class TestBear2(Bear):
55
56
    def run(self, setting1):
57
        """
58
        Test bear 2 description.
59
60
        :param setting1: Required Setting.
61
        """
62
        return None
63
64
65
class SomeBear(Bear):
66
67
    def run(self):
68
        """
69
        Some Description.
70
        """
71
        return None
72
73
74
class SomeOtherBear(Bear):
75
76
    def run(self, setting: int=None):
77
        """
78
        This is a Bear.
79
        :param setting: This is an optional setting.
80
        """
81
        setting = 1
82
        return None
83
84
85
class SomeglobalBear(Bear):
86
87
    def run(self):
88
        """
89
        Some global-bear Description.
90
        """
91
        return None
92
93
94
class SomelocalBear(Bear):
95
96
    def run(self):
97
        """
98
        Some local-bear Description.
99
        """
100
        return None
101
102
103
class ConsoleInteractionTest(unittest.TestCase):
104
105
    def setUp(self):
106
        self.log_printer = LogPrinter(ConsolePrinter(print_colored=False))
107
        self.console_printer = ConsolePrinter(print_colored=False)
108
        self.file_diff_dict = {}
109
        self.local_bears = OrderedDict([("default", [SomelocalBear]),
110
                                        ("test", [SomelocalBear])])
111
        self.global_bears = OrderedDict([("default", [SomeglobalBear]),
112
                                         ("test", [SomeglobalBear])])
113
114
        self.old_open_editor_applicable = OpenEditorAction.is_applicable
115
        OpenEditorAction.is_applicable = staticmethod(lambda *args: False)
116
117
        self.old_apply_patch_applicable = ApplyPatchAction.is_applicable
118
        ApplyPatchAction.is_applicable = staticmethod(lambda *args: False)
119
120
    def tearDown(self):
121
        OpenEditorAction.is_applicable = self.old_open_editor_applicable
122
        ApplyPatchAction.is_applicable = self.old_apply_patch_applicable
123
124
    def test_require_settings(self):
125
        self.assertRaises(TypeError, acquire_settings, self.log_printer, 0)
126
        self.assertEqual(acquire_settings(self.log_printer, {0: 0}), {})
127
128
        with simulate_console_inputs(0, 1, 2) as generator:
129
            self.assertEqual(acquire_settings(self.log_printer,
130
                                              {"setting": ["help text",
131
                                                           "SomeBear"]}),
132
                             {"setting": 0})
133
134
            self.assertEqual(acquire_settings(self.log_printer,
135
                                              {"setting": ["help text",
136
                                                           "SomeBear",
137
                                                           "AnotherBear"]}),
138
                             {"setting": 1})
139
140
            self.assertEqual(acquire_settings(self.log_printer,
141
                                              {"setting": ["help text",
142
                                                           "SomeBear",
143
                                                           "AnotherBear",
144
                                                           "YetAnotherBear"]}),
145
                             {"setting": 2})
146
147
            self.assertEqual(generator.last_input, 2)
148
149
    def test_print_result(self):
150
        print_result(self.console_printer,
151
                     self.log_printer,
152
                     None,
153
                     self.file_diff_dict,
154
                     "illegal value",
155
                     {})
156
157
        with simulate_console_inputs(0):
158
            print_result(self.console_printer,
159
                         self.log_printer,
160
                         None,
161
                         self.file_diff_dict,
162
                         Result("origin", "msg", diffs={}),
163
                         {})
164
165
        with make_temp() as testfile_path:
166
            file_dict = {
167
                testfile_path: ["1\n", "2\n", "3\n"],
168
                "f_b": ["1", "2", "3"]
169
            }
170
            diff = Diff(file_dict[testfile_path])
171
            diff.delete_line(2)
172
            diff.change_line(3, "3\n", "3_changed\n")
173
174
            with simulate_console_inputs(1), self.assertRaises(ValueError):
175
                ApplyPatchAction.is_applicable = staticmethod(
176
                    lambda *args: True)
177
                print_result(self.console_printer,
178
                             self.log_printer,
179
                             None,
180
                             self.file_diff_dict,
181
                             Result("origin", "msg", diffs={
182
                                    testfile_path: diff}),
183
                             file_dict)
184
185
            # Interaction must be closed by the user with `0` if it's not a
186
            # param
187
            with simulate_console_inputs("INVALID",
188
                                         -1,
189
                                         1,
190
                                         0,
191
                                         3) as input_generator:
192
                curr_section = Section("")
193
                print_section_beginning(self.console_printer, curr_section)
194
                print_result(self.console_printer,
195
                             self.log_printer,
196
                             curr_section,
197
                             self.file_diff_dict,
198
                             Result("origin", "msg", diffs={
199
                                    testfile_path: diff}),
200
                             file_dict)
201
                self.assertEqual(input_generator.last_input, 3)
202
203
                self.file_diff_dict.clear()
204
205
                with open(testfile_path) as f:
206
                    self.assertEqual(f.readlines(), ["1\n", "3_changed\n"])
207
208
                os.remove(testfile_path + ".orig")
209
210
                name, section = get_action_info(curr_section,
211
                                                TestAction().get_metadata())
212
                self.assertEqual(input_generator.last_input, 4)
213
                self.assertEqual(str(section), " {param : '3'}")
214
                self.assertEqual(name, "TestAction")
215
216
        # Check if the user is asked for the parameter only the first time.
217
        # Use OpenEditorAction that needs this parameter (editor command).
218
        with simulate_console_inputs(1, "test_editor", 0, 1, 0) as generator:
219
            OpenEditorAction.is_applicable = staticmethod(lambda *args: True)
220
221
            patch_result = Result("origin", "msg", diffs={testfile_path: diff})
222
            patch_result.file = "f_b"
223
224
            print_result(self.console_printer,
225
                         self.log_printer,
226
                         curr_section,
227
                         self.file_diff_dict,
228
                         patch_result,
229
                         file_dict)
230
            # choose action, choose editor, choose no action (-1 -> 2)
231
            self.assertEqual(generator.last_input, 2)
232
233
            # It shoudn't ask for parameter again
234
            print_result(self.console_printer,
235
                         self.log_printer,
236
                         curr_section,
237
                         self.file_diff_dict,
238
                         patch_result,
239
                         file_dict)
240
            self.assertEqual(generator.last_input, 4)
241
242
    def test_print_affected_files(self):
243
        with retrieve_stdout() as stdout, \
244
             make_temp() as some_file:
245
            file_dict = {some_file: ["1\n", "2\n", "3\n"]}
246
            affected_code = (SourceRange.from_values(some_file),)
247
            print_affected_files(self.console_printer,
248
                                 self.log_printer,
249
                                 Section(""),
250
                                 Result("origin",
251
                                        "message",
252
                                        affected_code=affected_code),
253
                                 file_dict,
254
                                 color=True)
255
            self.assertEqual(stdout.getvalue(),
256
                             "\n"+relpath(some_file)+"\n")
257
258
    def test_acquire_actions_and_apply(self):
259
        with make_temp() as testfile_path:
260
            file_dict = {testfile_path: ["1\n", "2\n", "3\n"]}
261
            diff = Diff(file_dict[testfile_path])
262
            diff.delete_line(2)
263
            diff.change_line(3, "3\n", "3_changed\n")
264
            with simulate_console_inputs(1, 0) as generator, \
265
                    retrieve_stdout() as sio:
266
                ApplyPatchAction.is_applicable = staticmethod(
267
                        lambda *args: True)
268
                acquire_actions_and_apply(self.console_printer,
269
                                          self.log_printer,
270
                                          Section(""),
271
                                          self.file_diff_dict,
272
                                          Result("origin", "message", diffs={
273
                                           testfile_path: diff}),
274
                                          file_dict)
275
                self.assertEqual(generator.last_input, 1)
276
                self.assertIn(ApplyPatchAction.success_message, sio.getvalue())
277
278
            class TestAction(ResultAction):
0 ignored issues
show
Comprehensibility Bug introduced by
TestAction is re-defining a name which is already available in the outer-scope (previously defined on line 36).

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...
279
280
                is_applicable = staticmethod(lambda *args: True)
281
282
                def apply(*args, **kwargs):
283
                    ApplyPatchAction.is_applicable = staticmethod(
284
                        lambda *args: False)
285
286
            old_applypatch_is_applicable = ApplyPatchAction.is_applicable
287
            cli_actions = [ApplyPatchAction(), TestAction()]
288
            # First apply TestAction() which makes ApplyPatchAction() invalid
289
            with simulate_console_inputs(2, 1, 0) as generator, \
290
                    retrieve_stdout() as sio:
291
                ApplyPatchAction.is_applicable = staticmethod(
292
                        lambda *args: True)
293
                acquire_actions_and_apply(self.console_printer,
294
                                          self.log_printer,
295
                                          Section(""),
296
                                          self.file_diff_dict,
297
                                          Result("origin", "message", diffs={
298
                                           testfile_path: diff}),
299
                                          file_dict,
300
                                          cli_actions=cli_actions)
301
                self.assertEqual(generator.last_input, 2)
302
303
                action_fail = "Failed to execute the action"
304
                self.assertNotIn(action_fail, sio.getvalue())
305
306
                apply_path_desc = ApplyPatchAction().get_metadata().desc
307
                self.assertEqual(sio.getvalue().count(apply_path_desc), 1)
308
309
            ApplyPatchAction.is_applicable = old_applypatch_is_applicable
310
311
    def test_print_result_no_input(self):
312
        with make_temp() as testfile_path:
313
            file_dict = {testfile_path: ["1\n", "2\n", "3\n"]}
314
            diff = Diff(file_dict[testfile_path])
315
            diff.delete_line(2)
316
            diff.change_line(3, "3\n", "3_changed\n")
317
            with simulate_console_inputs(1, 2, 3) as generator, \
318
                    retrieve_stdout() as stdout:
319
                ApplyPatchAction.is_applicable = staticmethod(
320
                      lambda *args: True)
321
                print_results_no_input(self.log_printer,
322
                                       Section("someSection"),
323
                                       [Result("origin", "message", diffs={
324
                                           testfile_path: diff})],
325
                                       file_dict,
326
                                       self.file_diff_dict,
327
                                       color=False)
328
                self.assertEqual(generator.last_input, -1)
329
                self.assertEqual(stdout.getvalue(),
330
                                 """
331
Project wide:
332
|    | [NORMAL] origin:
333
|    | message
334
""")
335
336
    def test_print_section_beginning(self):
337
        with retrieve_stdout() as stdout:
338
            print_section_beginning(self.console_printer, Section("name"))
339
            self.assertEqual(stdout.getvalue(), "Executing section name...\n")
340
341
    def test_nothing_done(self):
342
        with retrieve_stdout() as stdout:
343
            nothing_done(self.log_printer)
344
            self.assertIn("No existent section was targeted or enabled. "
345
                          "Nothing to do.\n",
346
                          stdout.getvalue())
347
348
    def test_print_results_empty(self):
349
        with retrieve_stdout() as stdout:
350
            print_results(self.log_printer, Section(""), [], {}, {})
351
            self.assertEqual(stdout.getvalue(), "")
352
353
    def test_print_results_project_wide(self):
354
        with retrieve_stdout() as stdout:
355
            print_results(self.log_printer,
356
                          Section(""),
357
                          [Result("origin", "message")],
358
                          {},
359
                          {},
360
                          color=False)
361
            self.assertEqual(
362
                "\n{}\n|    | [NORMAL] origin:\n|    | message"
363
                "\n".format(STR_PROJECT_WIDE),
364
                stdout.getvalue())
365
366
    def test_print_results_for_file(self):
367
        with retrieve_stdout() as stdout:
368
            print_results(
369
                self.log_printer,
370
                Section(""),
371
                [Result.from_values("SpaceConsistencyBear",
372
                                    "Trailing whitespace found",
373
                                    file="filename",
374
                                    line=2)],
375
                {abspath("filename"): ["test line\n", "line 2\n", "line 3\n"]},
376
                {},
377
                color=False)
378
            self.assertEqual("""\nfilename
379
|   2| line 2
380
|    | [NORMAL] SpaceConsistencyBear:
381
|    | Trailing whitespace found
382
""",
383
                             stdout.getvalue())
384
385
        with retrieve_stdout() as stdout:
386
            print_results(
387
                self.log_printer,
388
                Section(""),
389
                [Result.from_values("SpaceConsistencyBear",
390
                                    "Trailing whitespace found",
391
                                    file="filename",
392
                                    line=5)],
393
                {abspath("filename"): ["test line\n",
394
                                       "line 2\n",
395
                                       "line 3\n",
396
                                       "line 4\n",
397
                                       "line 5\n"]},
398
                {},
399
                color=False)
400
            self.assertEqual("""\nfilename
401
|   5| line 5
402
|    | [NORMAL] SpaceConsistencyBear:
403
|    | Trailing whitespace found
404
""",
405
                             stdout.getvalue())
406
407
    def test_print_results_sorting(self):
408
        with retrieve_stdout() as stdout:
409
            print_results(self.log_printer,
410
                          Section(""),
411
                          [Result.from_values("SpaceConsistencyBear",
412
                                              "Trailing whitespace found",
413
                                              file="file",
414
                                              line=5),
415
                           Result.from_values("SpaceConsistencyBear",
416
                                              "Trailing whitespace found",
417
                                              file="file",
418
                                              line=2)],
419
                          {abspath("file"): ["test line\n",
420
                                             "line 2\n",
421
                                             "line 3\n",
422
                                             "line 4\n",
423
                                             "line 5\n"]},
424
                          {},
425
                          color=False)
426
427
            self.assertEqual("""
428
file
429
|   2| line 2
430
|    | [NORMAL] SpaceConsistencyBear:
431
|    | Trailing whitespace found
432
433
file
434
|   5| line 5
435
|    | [NORMAL] SpaceConsistencyBear:
436
|    | Trailing whitespace found
437
""",
438
                             stdout.getvalue())
439
440
    def test_print_results_multiple_ranges(self):
441
        affected_code = (
442
            SourceRange.from_values("some_file", 5, end_line=7),
443
            SourceRange.from_values("another_file", 1, 3, 1, 5),
444
            SourceRange.from_values("another_file", 3, 3, 3, 5))
445
        with retrieve_stdout() as stdout:
446
            print_results(
447
                self.log_printer,
448
                Section(""),
449
                [Result("ClangCloneDetectionBear",
450
                        "Clone Found",
451
                        affected_code)],
452
                {abspath("some_file"): ["line " + str(i + 1) + "\n"
453
                                        for i in range(10)],
454
                 abspath("another_file"): ["line " + str(i + 1) + "\n"
455
                                           for i in range(10)]},
456
                {},
457
                color=False)
458
            self.assertEqual("""
459
another_file
460
|   1| line 1
461
462
another_file
463
|   3| line 3
464
465
some_file
466
|   5| line 5
467
|   6| line 6
468
|   7| line 7
469
|    | [NORMAL] ClangCloneDetectionBear:
470
|    | Clone Found
471
""",
472
                             stdout.getvalue())
473
474
    def test_print_results_missing_file(self):
475
        self.log_printer = LogPrinter(NullPrinter())
476
        with retrieve_stdout() as stdout:
477
            print_results(
478
                self.log_printer,
479
                Section(""),
480
                [Result("t", "msg"),
481
                 Result.from_values("t", "msg", file="file", line=5)],
482
                {},
483
                {},
484
                color=False)
485
            self.assertEqual("\n" + STR_PROJECT_WIDE + "\n"
486
                             "|    | [NORMAL] t:\n"
487
                             "|    | msg\n"
488
                             # Second results file isn't there, no context is
489
                             # printed, only a warning log message which we
490
                             # don't catch
491
                             "|    | [NORMAL] t:\n"
492
                             "|    | msg\n", stdout.getvalue())
493
494
    def test_print_results_missing_line(self):
495
        with retrieve_stdout() as stdout:
496
            print_results(
497
                self.log_printer,
498
                Section(""),
499
                [Result.from_values("t", "msg", file="file", line=5),
500
                 Result.from_values("t", "msg", file="file", line=6)],
501
                {abspath("file"): ["line " + str(i + 1) for i in range(5)]},
502
                {},
503
                color=False)
504
            self.assertEqual("\n"
505
                             "file\n"
506
                             "|   5| line 5\n"
507
                             "|    | [NORMAL] t:\n"
508
                             "|    | msg\n"
509
                             "\n"
510
                             "file\n"
511
                             "|    | {}\n"
512
                             "|    | [NORMAL] t:\n"
513
                             "|    | msg\n".format(STR_LINE_DOESNT_EXIST),
514
                             stdout.getvalue())
515
516
    def test_print_results_without_line(self):
517
        with retrieve_stdout() as stdout:
518
            print_results(
519
                self.log_printer,
520
                Section(""),
521
                [Result.from_values("t", "msg", file="file")],
522
                {abspath("file"): []},
523
                {},
524
                color=False)
525
            self.assertEqual(
526
                "\nfile\n"
527
                "|    | [NORMAL] t:\n"
528
                "|    | msg\n",
529
                stdout.getvalue())
530
531
    def test_print_bears_empty(self):
532
        with retrieve_stdout() as stdout:
533
            bears = {}
534
            print_bears(self.log_printer.printer, bears, True)
535
            self.assertEqual("No bears to show.\n", stdout.getvalue())
536
        with retrieve_stdout() as stdout:
537
            bears = {}
538
            print_bears(self.log_printer.printer, bears, False)
539
            self.assertEqual("No bears to show.\n", stdout.getvalue())
540
541
    def test_print_bears(self):
542
        with retrieve_stdout() as stdout:
543
            bears = {TestBear: ["default", "docs"]}
544
            print_bears(self.log_printer.printer, bears, False)
545
            expected_string = "TestBear:\n"
546
            expected_string += "  Test bear Description.\n\n"
547
            expected_string += "  Used in:\n"
548
            expected_string += "   * default\n"
549
            expected_string += "   * docs\n\n"
550
            expected_string += "  Needed Settings:\n"
551
            expected_string += "   * setting1: Required Setting.\n\n"
552
            expected_string += "  Optional Settings:\n"
553
            expected_string += "   * setting2: Optional Setting. ("
554
            expected_string += "Optional, defaults to 'None'."
555
            expected_string += ")\n\n"
556
557
            self.assertEqual(expected_string, stdout.getvalue())
558
559
    def test_print_bears_no_settings(self):
560
        with retrieve_stdout() as stdout:
561
            bears = {SomeBear: ["default"]}
562
            print_bears(self.log_printer.printer, bears, False)
563
            expected_string = "SomeBear:\n"
564
            expected_string += "  Some Description.\n\n"
565
            expected_string += "  Used in:\n"
566
            expected_string += "   * default\n\n"
567
            expected_string += "  No needed settings.\n\n"
568
            expected_string += "  No optional settings.\n\n"
569
570
            self.assertEqual(expected_string, stdout.getvalue())
571
572
    def test_print_bears_no_needed_settings(self):
573
        with retrieve_stdout() as stdout:
574
            bears = {SomeOtherBear: ["test"]}
575
            print_bears(self.log_printer.printer, bears, False)
576
            expected_string = "SomeOtherBear:\n"
577
            expected_string += "  This is a Bear.\n\n"
578
            expected_string += "  Used in:\n"
579
            expected_string += "   * test\n\n"
580
            expected_string += "  No needed settings.\n\n"
581
            expected_string += "  Optional Settings:\n"
582
            expected_string += "   * setting: This is an optional setting. ("
583
            expected_string += "Optional, defaults to 'None'."
584
            expected_string += ")\n\n"
585
586
            self.assertEqual(expected_string, stdout.getvalue())
587
588
    def test_print_bears_no_optional_settings(self):
589
        with retrieve_stdout() as stdout:
590
            bears = {TestBear2: ["test"]}
591
            print_bears(self.log_printer.printer, bears, False)
592
            expected_string = "TestBear2:\n"
593
            expected_string += "  Test bear 2 description.\n\n"
594
            expected_string += "  Used in:\n"
595
            expected_string += "   * test\n\n"
596
            expected_string += "  Needed Settings:\n"
597
            expected_string += "   * setting1: Required Setting.\n\n"
598
            expected_string += "  No optional settings.\n\n"
599
600
            self.assertEqual(expected_string, stdout.getvalue())
601
602
    def test_print_bears_no_sections(self):
603
        with retrieve_stdout() as stdout:
604
            bears = {SomeBear: []}
605
            print_bears(self.log_printer.printer, bears, False)
606
            expected_string = "SomeBear:\n"
607
            expected_string += "  Some Description.\n\n"
608
            expected_string += "  No sections.\n\n"
609
            expected_string += "  No needed settings.\n\n"
610
            expected_string += "  No optional settings.\n\n"
611
612
            self.assertEqual(expected_string, stdout.getvalue())
613
614
    def test_show_bears(self):
615
        with retrieve_stdout() as stdout:
616
            bears = {SomelocalBear: ['default', 'test'],
617
                     SomeglobalBear: ['default', 'test']}
618
            print_bears(self.log_printer.printer, bears, False)
619
            expected_string = stdout.getvalue()
620
        self.maxDiff = None
621
        with retrieve_stdout() as stdout:
622
            show_bears(self.local_bears,
623
                       self.global_bears,
624
                       False,
625
                       self.log_printer.printer)
626
            self.assertEqual(expected_string, stdout.getvalue())
627
628
        with retrieve_stdout() as stdout:
629
            show_bears(self.local_bears,
630
                       self.global_bears,
631
                       True,
632
                       self.log_printer.printer)
633
            self.assertEqual(" * SomeglobalBear\n"
634
                             " * SomelocalBear\n", stdout.getvalue())
635
636
637
# Own test because this is easy and not tied to the rest
638
class PrintFormattedResultsTest(unittest.TestCase):
639
640
    def setUp(self):
641
        self.printer = StringPrinter()
642
        self.logger = LogPrinter(self.printer)
643
        self.section = Section("t")
644
645
    def test_default_format(self):
646
        expected_string = ("id:-?[0-9]+:origin:1:file:None:from_line:None:"
647
                           "from_column:None:to_line:None:to_column:None:"
648
                           "severity:1:msg:2\n")
649
        with retrieve_stdout() as stdout:
650
            print_results_formatted(self.logger,
651
                                    self.section,
652
                                    [Result("1", "2")],
653
                                    None,
654
                                    None)
655
            self.assertRegex(stdout.getvalue(), expected_string)
656
657
    def test_multiple_ranges(self):
658
        expected_string = (
659
            "id:-?[0-9]+:origin:1:.*file:.*another_file:from_line:5:"
660
            "from_column:3:to_line:5:to_column:5:"
661
            "severity:1:msg:2\n"
662
            "id:-?[0-9]+:origin:1:.*file:.*some_file:from_line:5:"
663
            "from_column:None:to_line:7:to_column:None:"
664
            "severity:1:msg:2\n")
665
        affected_code = (SourceRange.from_values("some_file", 5, end_line=7),
666
                         SourceRange.from_values("another_file", 5, 3, 5, 5))
667
        with retrieve_stdout() as stdout:
668
            print_results_formatted(self.logger,
669
                                    self.section,
670
                                    [Result("1", "2", affected_code)],
671
                                    None,
672
                                    None)
673
            self.assertRegex(stdout.getvalue(), expected_string)
674
675
    def test_bad_format(self):
676
        self.section.append(Setting("format_str", "{nonexistant}"))
677
        print_results_formatted(self.logger,
678
                                self.section,
679
                                [Result("1", "2")],
680
                                None,
681
                                None)
682
        self.assertRegex(self.printer.string, ".*Unable to print.*")
683
684
    def test_good_format(self):
685
        self.section.append(Setting("format_str", "{origin}"))
686
        with retrieve_stdout() as stdout:
687
            print_results_formatted(self.logger,
688
                                    self.section,
689
                                    [Result("1", "2")],
690
                                    None,
691
                                    None)
692
            self.assertEqual(stdout.getvalue(), "1\n")
693
694
    def test_empty_list(self):
695
        self.section.append(Setting("format_str", "{origin}"))
696
        # Shouldn't attempt to format the string None and will fail badly if
697
        # its done wrong.
698
        print_results_formatted(None,
699
                                self.section,
700
                                [],
701
                                None,
702
                                None,
703
                                None)
704