Completed
Pull Request — master (#1228)
by Mischa
01:24
created

test_print_results_project_wide()   A

Complexity

Conditions 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 2
dl 0
loc 12
rs 9.4285
1
import unittest
2
import sys
3
import os
4
from collections import OrderedDict
5
from pyprint.NullPrinter import NullPrinter
6
from pyprint.ConsolePrinter import ConsolePrinter
7
8
sys.path.insert(0, ".")
9
from coalib.results.result_actions.ResultAction import ResultAction
10
from coalib.results.Result import Result
11
from coalib.results.SourceRange import SourceRange
12
from coalib.results.Diff import Diff
13
from coalib.settings.Section import Section
14
from coalib.settings.Setting import Setting
15
from coalib.misc.ContextManagers import (simulate_console_inputs,
16
                                         retrieve_stdout,
17
                                         make_temp)
18
from coalib.output.ConsoleInteraction import (nothing_done,
19
                                              acquire_settings,
20
                                              print_bears,
21
                                              get_action_info,
22
                                              print_result,
23
                                              print_section_beginning,
24
                                              print_results,
25
                                              show_bears,
26
                                              print_results_formatted)
27
from coalib.output.printers.LogPrinter import LogPrinter
28
from coalib.output.printers.StringPrinter import StringPrinter
29
from coalib.results.result_actions.ApplyPatchAction import ApplyPatchAction
30
from coalib.results.result_actions.OpenEditorAction import OpenEditorAction
31
from coalib.bears.Bear import Bear
32
from bears.general.KeywordBear import KeywordBear
33
from bears.general.LineLengthBear import LineLengthBear
34
35
36
STR_GET_VAL_FOR_SETTING = ("Please enter a value for the setting \"{}\" ({}) "
37
                           "needed by {}: ")
38
STR_LINE_DOESNT_EXIST = ("The line belonging to the following result "
39
                         "cannot be printed because it refers to a line "
40
                         "that doesn't seem to exist in the given file.")
41
STR_PROJECT_WIDE = "Project wide:"
42
43
44
class TestAction(ResultAction):
45
46
    def apply(self, result, original_file_dict, file_diff_dict, param):
47
        pass
48
49
50
class TestBear(Bear):
51
52
    def run(self, setting1, setting2: int=None):
53
        """
54
        Test bear Description.
55
56
        :param setting1: Required Setting.
57
        :param setting2: Optional Setting.
58
        """
59
        return None
60
61
62
class TestBear2(Bear):
63
64
    def run(self, setting1):
65
        """
66
        Test bear 2 description.
67
68
        :param setting1: Required Setting.
69
        """
70
        return None
71
72
73
class SomeBear(Bear):
74
75
    def run(self):
76
        """
77
        Some Description.
78
        """
79
        return None
80
81
82
class SomeOtherBear(Bear):
83
84
    def run(self, setting: int=None):
85
        """
86
        This is a Bear.
87
        :param setting: This is an optional setting.
88
        """
89
        setting = 1
90
        return None
91
92
93
class SomeglobalBear(Bear):
94
95
    def run(self):
96
        """
97
        Some Description.
98
        """
99
        return None
100
101
102
class ConsoleInteractionTest(unittest.TestCase):
103
104
    def setUp(self):
105
        self.log_printer = LogPrinter(ConsolePrinter(print_colored=False))
106
        self.console_printer = ConsolePrinter(print_colored=False)
107
        self.file_diff_dict = {}
108
        self.local_bears = OrderedDict([("default", [KeywordBear]),
109
                                        ("test", [LineLengthBear,
110
                                                  KeywordBear])])
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_section_beginning(self):
243
        with retrieve_stdout() as stdout:
244
            print_section_beginning(self.console_printer, Section("name"))
245
            self.assertEqual(stdout.getvalue(), "Executing section name...\n")
246
247
    def test_nothing_done(self):
248
        with retrieve_stdout() as stdout:
249
            nothing_done(self.log_printer)
250
            self.assertIn("No existent section was targeted or enabled. "
251
                          "Nothing to do.\n",
252
                          stdout.getvalue())
253
254
    def test_print_results_empty(self):
255
        with retrieve_stdout() as stdout:
256
            print_results(self.log_printer, Section(""), [], {}, {})
257
            self.assertEqual(stdout.getvalue(), "")
258
259
    def test_print_results_project_wide(self):
260
        with retrieve_stdout() as stdout:
261
            print_results(self.log_printer,
262
                          Section(""),
263
                          [Result("origin", "message")],
264
                          {},
265
                          {},
266
                          color=False)
267
            self.assertEqual(
268
                "\n{}\n|    | [NORMAL] origin:\n|    | message"
269
                "\n".format(STR_PROJECT_WIDE),
270
                stdout.getvalue())
271
272
    def test_print_results_for_file(self):
273
        with retrieve_stdout() as stdout:
274
            print_results(
275
                self.log_printer,
276
                Section(""),
277
                [Result.from_values("SpaceConsistencyBear",
278
                                    "Trailing whitespace found",
279
                                    file="filename",
280
                                    line=2)],
281
                {"filename": ["test line\n", "line 2\n", "line 3\n"]},
282
                {},
283
                color=False)
284
            self.assertEqual("""\nfilename
285
|   2| line 2
286
|    | [NORMAL] SpaceConsistencyBear:
287
|    | Trailing whitespace found
288
""",
289
                             stdout.getvalue())
290
291
        with retrieve_stdout() as stdout:
292
            print_results(
293
                self.log_printer,
294
                Section(""),
295
                [Result.from_values("SpaceConsistencyBear",
296
                                    "Trailing whitespace found",
297
                                    file="filename",
298
                                    line=5)],
299
                {"filename": ["test line\n",
300
                              "line 2\n",
301
                              "line 3\n",
302
                              "line 4\n",
303
                              "line 5\n"]},
304
                {},
305
                color=False)
306
            self.assertEqual("""\nfilename
307
|   5| line 5
308
|    | [NORMAL] SpaceConsistencyBear:
309
|    | Trailing whitespace found
310
""",
311
                             stdout.getvalue())
312
313
    def test_print_results_sorting(self):
314
        with retrieve_stdout() as stdout:
315
            print_results(self.log_printer,
316
                          Section(""),
317
                          [Result.from_values("SpaceConsistencyBear",
318
                                              "Trailing whitespace found",
319
                                              file="file",
320
                                              line=5),
321
                           Result.from_values("SpaceConsistencyBear",
322
                                              "Trailing whitespace found",
323
                                              file="file",
324
                                              line=2)],
325
                          {"file": ["test line\n",
326
                                    "line 2\n",
327
                                    "line 3\n",
328
                                    "line 4\n",
329
                                    "line 5\n"]},
330
                          {},
331
                          color=False)
332
333
            self.assertEqual("""
334
file
335
|   2| line 2
336
|    | [NORMAL] SpaceConsistencyBear:
337
|    | Trailing whitespace found
338
339
file
340
|   5| line 5
341
|    | [NORMAL] SpaceConsistencyBear:
342
|    | Trailing whitespace found
343
""",
344
                             stdout.getvalue())
345
346
    def test_print_results_multiple_ranges(self):
347
        affected_code = (SourceRange.from_values("some_file", 5, end_line=7),
348
                         SourceRange.from_values("another_file", 1, 3, 1, 5),
349
                         SourceRange.from_values("another_file", 3, 3, 3, 5))
350
        with retrieve_stdout() as stdout:
351
            print_results(
352
                self.log_printer,
353
                Section(""),
354
                [Result("ClangCloneDetectionBear",
355
                        "Clone Found",
356
                        affected_code)],
357
                {"some_file": ["line "+str(i+1)+"\n" for i in range(10)],
358
                 "another_file": ["line "+str(i+1)+"\n" for i in range(10)]},
359
                {},
360
                color=False)
361
            self.assertEqual("""
362
another_file
363
|   1| line 1
364
365
another_file
366
|   3| line 3
367
368
some_file
369
|   5| line 5
370
|   6| line 6
371
|   7| line 7
372
|    | [NORMAL] ClangCloneDetectionBear:
373
|    | Clone Found
374
""",
375
                             stdout.getvalue())
376
377
    def test_print_results_missing_file(self):
378
        self.log_printer = LogPrinter(NullPrinter())
379
        with retrieve_stdout() as stdout:
380
            print_results(
381
                self.log_printer,
382
                Section(""),
383
                [Result("t", "msg"),
384
                 Result.from_values("t", "msg", file="file", line=5)],
385
                {},
386
                {},
387
                color=False)
388
            self.assertEqual("\n" + STR_PROJECT_WIDE + "\n"
389
                             "|    | [NORMAL] t:\n"
390
                             "|    | msg\n"
391
                             # Second results file isn't there, no context is
392
                             # printed, only a warning log message which we
393
                             # don't catch
394
                             "|    | [NORMAL] t:\n"
395
                             "|    | msg\n", stdout.getvalue())
396
397
    def test_print_results_missing_line(self):
398
        with retrieve_stdout() as stdout:
399
            print_results(
400
                self.log_printer,
401
                Section(""),
402
                [Result.from_values("t", "msg", file="file", line=5),
403
                 Result.from_values("t", "msg", file="file", line=6)],
404
                {"file": ["line " + str(i+1) for i in range(5)]},
405
                {},
406
                color=False)
407
            self.assertEqual("\n"
408
                             "file\n"
409
                             "|   5| line 5\n"
410
                             "|    | [NORMAL] t:\n"
411
                             "|    | msg\n"
412
                             "\n"
413
                             "file\n"
414
                             "|    | {}\n"
415
                             "|    | [NORMAL] t:\n"
416
                             "|    | msg\n".format(STR_LINE_DOESNT_EXIST),
417
                             stdout.getvalue())
418
419
    def test_print_results_without_line(self):
420
        with retrieve_stdout() as stdout:
421
            print_results(
422
                self.log_printer,
423
                Section(""),
424
                [Result.from_values("t", "msg", file="file")],
425
                {"file": []},
426
                {},
427
                color=False)
428
            self.assertEqual(
429
                "\nfile\n"
430
                "|    | [NORMAL] t:\n"
431
                "|    | msg\n",
432
                stdout.getvalue())
433
434
    def test_print_bears_empty(self):
435
        with retrieve_stdout() as stdout:
436
            bears = {}
437
            print_bears(self.log_printer.printer, bears, True)
438
            self.assertEqual("No bears to show.\n", stdout.getvalue())
439
        with retrieve_stdout() as stdout:
440
            bears = {}
441
            print_bears(self.log_printer.printer, bears, False)
442
            self.assertEqual("No bears to show.\n", stdout.getvalue())
443
444
    def test_print_bears(self):
445
        with retrieve_stdout() as stdout:
446
            bears = {TestBear: ["default", "docs"]}
447
            print_bears(self.log_printer.printer, bears, False)
448
            expected_string = "TestBear:\n"
449
            expected_string += "  Test bear Description.\n\n"
450
            expected_string += "  Used in:\n"
451
            expected_string += "   * default\n"
452
            expected_string += "   * docs\n\n"
453
            expected_string += "  Needed Settings:\n"
454
            expected_string += "   * setting1: Required Setting.\n\n"
455
            expected_string += "  Optional Settings:\n"
456
            expected_string += "   * setting2: Optional Setting. ("
457
            expected_string += "Optional, defaults to 'None'."
458
            expected_string += ")\n\n"
459
460
            self.assertEqual(expected_string, stdout.getvalue())
461
462
    def test_print_bears_no_settings(self):
463
        with retrieve_stdout() as stdout:
464
            bears = {SomeBear: ["default"]}
465
            print_bears(self.log_printer.printer, bears, False)
466
            expected_string = "SomeBear:\n"
467
            expected_string += "  Some Description.\n\n"
468
            expected_string += "  Used in:\n"
469
            expected_string += "   * default\n\n"
470
            expected_string += "  No needed settings.\n\n"
471
            expected_string += "  No optional settings.\n\n"
472
473
            self.assertEqual(expected_string, stdout.getvalue())
474
475
    def test_print_bears_no_needed_settings(self):
476
        with retrieve_stdout() as stdout:
477
            bears = {SomeOtherBear: ["test"]}
478
            print_bears(self.log_printer.printer, bears, False)
479
            expected_string = "SomeOtherBear:\n"
480
            expected_string += "  This is a Bear.\n\n"
481
            expected_string += "  Used in:\n"
482
            expected_string += "   * test\n\n"
483
            expected_string += "  No needed settings.\n\n"
484
            expected_string += "  Optional Settings:\n"
485
            expected_string += "   * setting: This is an optional setting. ("
486
            expected_string += "Optional, defaults to 'None'."
487
            expected_string += ")\n\n"
488
489
            self.assertEqual(expected_string, stdout.getvalue())
490
491
    def test_print_bears_no_optional_settings(self):
492
        with retrieve_stdout() as stdout:
493
            bears = {TestBear2: ["test"]}
494
            print_bears(self.log_printer.printer, bears, False)
495
            expected_string = "TestBear2:\n"
496
            expected_string += "  Test bear 2 description.\n\n"
497
            expected_string += "  Used in:\n"
498
            expected_string += "   * test\n\n"
499
            expected_string += "  Needed Settings:\n"
500
            expected_string += "   * setting1: Required Setting.\n\n"
501
            expected_string += "  No optional settings.\n\n"
502
503
            self.assertEqual(expected_string, stdout.getvalue())
504
505
    def test_print_bears_no_sections(self):
506
        with retrieve_stdout() as stdout:
507
            bears = {SomeBear: []}
508
            print_bears(self.log_printer.printer, bears, False)
509
            expected_string = "SomeBear:\n"
510
            expected_string += "  Some Description.\n\n"
511
            expected_string += "  No sections.\n\n"
512
            expected_string += "  No needed settings.\n\n"
513
            expected_string += "  No optional settings.\n\n"
514
515
            self.assertEqual(expected_string, stdout.getvalue())
516
517
    def test_show_bears(self):
518
        with retrieve_stdout() as stdout:
519
            bears = {KeywordBear: ['default', 'test'],
520
                     LineLengthBear: ['test'],
521
                     SomeglobalBear: ['default', 'test']}
522
            print_bears(self.log_printer.printer, bears, False)
523
            expected_string = stdout.getvalue()
524
        self.maxDiff = None
525
        with retrieve_stdout() as stdout:
526
            show_bears(self.local_bears,
527
                       self.global_bears,
528
                       False,
529
                       self.log_printer.printer)
530
            self.assertEqual(expected_string, stdout.getvalue())
531
532
        with retrieve_stdout() as stdout:
533
            show_bears(self.local_bears,
534
                       self.global_bears,
535
                       True,
536
                       self.log_printer.printer)
537
            self.assertEqual(" * KeywordBear\n"
538
                             " * LineLengthBear\n"
539
                             " * SomeglobalBear\n", stdout.getvalue())
540
541
542
# Own test because this is easy and not tied to the rest
543
class PrintFormattedResultsTest(unittest.TestCase):
544
545
    def setUp(self):
546
        self.printer = StringPrinter()
547
        self.logger = LogPrinter(self.printer)
548
        self.section = Section("t")
549
550
    def test_default_format(self):
551
        expected_string = ("id:-?[0-9]+:origin:1:file:None:from_line:None:"
552
                           "from_column:None:to_line:None:to_column:None:"
553
                           "severity:1:msg:2\n")
554
        with retrieve_stdout() as stdout:
555
            print_results_formatted(self.logger,
556
                                    self.section,
557
                                    [Result("1", "2")],
558
                                    None,
559
                                    None)
560
            self.assertRegex(stdout.getvalue(), expected_string)
561
562
    def test_multiple_ranges(self):
563
        expected_string = (
564
            "id:-?[0-9]+:origin:1:file:another_file:from_line:5:"
565
            "from_column:3:to_line:5:to_column:5:"
566
            "severity:1:msg:2\n"
567
            "id:-?[0-9]+:origin:1:file:some_file:from_line:5:"
568
            "from_column:None:to_line:7:to_column:None:"
569
            "severity:1:msg:2\n")
570
        affected_code = (SourceRange.from_values("some_file", 5, end_line=7),
571
                         SourceRange.from_values("another_file", 5, 3, 5, 5))
572
        with retrieve_stdout() as stdout:
573
            print_results_formatted(self.logger,
574
                                    self.section,
575
                                    [Result("1", "2", affected_code)],
576
                                    None,
577
                                    None)
578
            self.assertRegex(stdout.getvalue(), expected_string)
579
580
    def test_bad_format(self):
581
        self.section.append(Setting("format_str", "{nonexistant}"))
582
        print_results_formatted(self.logger,
583
                                self.section,
584
                                [Result("1", "2")],
585
                                None,
586
                                None)
587
        self.assertRegex(self.printer.string, ".*Unable to print.*")
588
589
    def test_good_format(self):
590
        self.section.append(Setting("format_str", "{origin}"))
591
        with retrieve_stdout() as stdout:
592
            print_results_formatted(self.logger,
593
                                    self.section,
594
                                    [Result("1", "2")],
595
                                    None,
596
                                    None)
597
            self.assertEqual(stdout.getvalue(), "1\n")
598
599
    def test_empty_list(self):
600
        self.section.append(Setting("format_str", "{origin}"))
601
        # Shouldn't attempt to format the string None and will fail badly if
602
        # its done wrong.
603
        print_results_formatted(None,
604
                                self.section,
605
                                [],
606
                                None,
607
                                None,
608
                                None)
609
610
611
if __name__ == '__main__':
612
    unittest.main(verbosity=2)
613