Completed
Pull Request — master (#1626)
by Abdeali
01:33
created

coalib.tests.output.SomeOtherBear   A

Complexity

Total Complexity 1

Size/Duplication

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