Completed
Pull Request — master (#2558)
by Lasse
01:55
created

RootDirTestLinter.get_config_dir()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
dl 0
loc 2
rs 10
1
import platform
2
import os
3
import re
4
import sys
5
import unittest
6
from unittest.mock import ANY, Mock
7
8
from coalib.bearlib.abstractions.Linter import linter
9
from coalib.results.Diff import Diff
10
from coalib.results.Result import Result
11
from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY
12
from coalib.results.SourceRange import SourceRange
13
from coalib.settings.Section import Section
14
from unittest.case import skipIf
15
16
17
def get_testfile_name(name):
18
    """
19
    Gets the full path to a testfile inside ``linter_test_files`` directory.
20
21
    :param name: The filename of the testfile to get the full path for.
22
    :return:     The full path to given testfile name.
23
    """
24
    return os.path.join(os.path.dirname(os.path.realpath(__file__)),
25
                        "linter_test_files",
26
                        name)
27
28
29
class LinterComponentTest(unittest.TestCase):
30
31
    # Using `object` instead of an empty class results in inheritance problems
32
    # inside the linter decorator.
33
    class EmptyTestLinter:
34
        pass
35
36
    class RootDirTestLinter:
37
        def create_arguments(self, *args, **kwargs):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
38
            return tuple()
39
40
        def get_config_dir(self):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
41
            return '/'
42 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
43
        def process_output(self, output, *args, **kwargs):
0 ignored issues
show
Coding Style introduced by
This method could be written as a function/class method.

If a method does not access any attributes of the class, it could also be implemented as a function or static method. This can help improve readability. For example

class Foo:
    def some_method(self, x, y):
        return x + y;

could be written as

class Foo:
    @classmethod
    def some_method(cls, x, y):
        return x + y;
Loading history...
44
            assert output == '/\n', ("The linter doesn't run the command in "
45
                                     "the right directory!")
46
47
    class ManualProcessingTestLinter:
48
49
        def process_output(self, *args, **kwargs):
50
            pass
51
52
    def setUp(self):
53
        self.section = Section("TEST_SECTION")
54
55
    def test_decorator_invalid_parameters(self):
56
        with self.assertRaises(ValueError) as cm:
57
            linter("some-executable", invalid_arg=88, ABC=2000)
58
        self.assertEqual(
59
            str(cm.exception),
60
            "Invalid keyword arguments provided: 'ABC', 'invalid_arg'")
61
62
        with self.assertRaises(ValueError) as cm:
63
            linter("some-executable", diff_severity=RESULT_SEVERITY.MAJOR)
64
        self.assertEqual(str(cm.exception),
65
                         "Invalid keyword arguments provided: 'diff_severity'")
66
67
        with self.assertRaises(ValueError) as cm:
68
            linter("some-executable", result_message="Custom message")
69
        self.assertEqual(str(cm.exception),
70
                         "Invalid keyword arguments provided: "
71
                         "'result_message'")
72
73
        with self.assertRaises(ValueError) as cm:
74
            linter("some-executable",
75
                   output_format="corrected",
76
                   output_regex=".*")
77
        self.assertEqual(str(cm.exception),
78
                         "Invalid keyword arguments provided: 'output_regex'")
79
80
        with self.assertRaises(ValueError) as cm:
81 View Code Duplication
            linter("some-executable",
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
82
                   output_format="corrected",
83
                   severity_map={})
84
        self.assertEqual(str(cm.exception),
85
                         "Invalid keyword arguments provided: 'severity_map'")
86
87
        with self.assertRaises(ValueError) as cm:
88
            linter("some-executable",
89
                   prerequisite_check_fail_message="some_message")
90
        self.assertEqual(str(cm.exception),
91
                         "Invalid keyword arguments provided: "
92
                         "'prerequisite_check_fail_message'")
93
94
    def test_decorator_invalid_states(self):
95
        with self.assertRaises(ValueError) as cm:
96
            linter("some-executable", use_stdout=False, use_stderr=False)
97
        self.assertEqual(str(cm.exception),
98
                         "No output streams provided at all.")
99
100
        with self.assertRaises(ValueError) as cm:
101
            linter("some-executable", output_format="INVALID")
102
        self.assertEqual(str(cm.exception),
103
                         "Invalid `output_format` specified.")
104
105
        with self.assertRaises(ValueError) as cm:
106
            linter("some-executable", output_format="regex")
107
        self.assertEqual(
108
            str(cm.exception),
109
            "`output_regex` needed when specified output-format 'regex'.")
110
111
        with self.assertRaises(ValueError) as cm:
112
            linter("some-executable",
113
                   output_format="regex",
114
                   output_regex="",
115
                   severity_map={})
116
        self.assertEqual(
117
            str(cm.exception),
118
            "Provided `severity_map` but named group `severity` is not used "
119
            "in `output_regex`.")
120
121
        with self.assertRaises(ValueError) as cm:
122
            linter("some-executable")(object)
123
        self.assertEqual(
124
            str(cm.exception),
125
            "`process_output` not provided by given class 'object'.")
126
127
        with self.assertRaises(ValueError) as cm:
128
            (linter("some-executable", output_format="regex", output_regex="")
129
             (self.ManualProcessingTestLinter))
130
        self.assertEqual(
131
            str(cm.exception),
132
            "Found `process_output` already defined by class "
133
            "'ManualProcessingTestLinter', but 'regex' output-format is "
134
            "specified.")
135
136
    def test_decorator_generated_default_interface(self):
137
        uut = linter("some-executable")(self.ManualProcessingTestLinter)
138
        with self.assertRaises(NotImplementedError):
139
            uut.create_arguments("filename", "content", None)
140
141
    def test_decorator_invalid_parameter_types(self):
142
        # Provide some invalid severity maps.
143
        with self.assertRaises(TypeError):
144
            linter("some-executable",
145
                   output_format="regex",
146
                   output_regex="(?P<severity>)",
147
                   severity_map=list())
148
149
        with self.assertRaises(TypeError):
150
            linter("some-executable",
151
                   output_format="regex",
152
                   output_regex="(?P<severity>)",
153
                   severity_map={3: 0})
154
155
        with self.assertRaises(TypeError) as cm:
156
            linter("some-executable",
157
                   output_format="regex",
158
                   output_regex="(?P<severity>)",
159
                   severity_map={"critical": "invalid"})
160
        self.assertEqual(str(cm.exception),
161
                         "The value 'invalid' for key 'critical' inside given "
162
                         "severity-map is no valid severity value.")
163
164
        with self.assertRaises(TypeError) as cm:
165
            linter("some-executable",
166
                   output_format="regex",
167
                   output_regex="(?P<severity>)",
168
                   severity_map={"critical-error": 389274234})
169
        self.assertEqual(str(cm.exception),
170
                         "Invalid severity value 389274234 for key "
171
                         "'critical-error' inside given severity-map.")
172
173
        # Other type-error test cases.
174
175
        with self.assertRaises(TypeError):
176
            linter("some-executable",
177
                   output_format="regex",
178
                   output_regex="(?P<message>)",
179
                   result_message=None)
180
181
        with self.assertRaises(TypeError):
182
            linter("some-executable",
183
                   output_format="corrected",
184
                   result_message=list())
185
186
        with self.assertRaises(TypeError) as cm:
187
            linter("some-executable",
188
                   output_format="corrected",
189
                   diff_severity=999888777)
190
        self.assertEqual(str(cm.exception),
191
                         "Invalid value for `diff_severity`: 999888777")
192
193
        with self.assertRaises(TypeError):
194
            linter("some-executable",
195
                   prerequisite_check_command=("command",),
196
                   prerequisite_check_fail_message=382983)
197
198
    def test_get_executable(self):
199
        uut = linter("some-executable")(self.ManualProcessingTestLinter)
200
        self.assertEqual(uut.get_executable(), "some-executable")
201
202
    def test_check_prerequisites(self):
203
        uut = linter(sys.executable)(self.ManualProcessingTestLinter)
204
        self.assertTrue(uut.check_prerequisites())
205
206
        uut = (linter("invalid_nonexisting_programv412")
207
               (self.ManualProcessingTestLinter))
208
        self.assertEqual(uut.check_prerequisites(),
209
                         "'invalid_nonexisting_programv412' is not installed.")
210
211
        uut = (linter("invalid_nonexisting_programv412",
212
                      executable_check_fail_info="You can't install it.")
213
               (self.ManualProcessingTestLinter))
214
        self.assertEqual(uut.check_prerequisites(),
215
                         "'invalid_nonexisting_programv412' is not installed. "
216
                         "You can't install it.")
217
218
        uut = (linter(sys.executable,
219
                      prerequisite_check_command=(sys.executable, "--version"))
220
               (self.ManualProcessingTestLinter))
221
        self.assertTrue(uut.check_prerequisites())
222
223
        uut = (linter(sys.executable,
224
                      prerequisite_check_command=("invalid_programv413",))
225
               (self.ManualProcessingTestLinter))
226
        self.assertEqual(uut.check_prerequisites(),
227
                         "Prerequisite check failed.")
228
229
        uut = (linter(sys.executable,
230
                      prerequisite_check_command=("invalid_programv413",),
231
                      prerequisite_check_fail_message="NOPE")
232
               (self.ManualProcessingTestLinter))
233
        self.assertEqual(uut.check_prerequisites(), "NOPE")
234
235
    def test_output_stream(self):
236
        process_output_mock = Mock()
237
238
        class TestLinter:
239
240
            @staticmethod
241
            def process_output(output, filename, file):
242
                process_output_mock(output, filename, file)
243
244
            @staticmethod
245
            def create_arguments(filename, file, config_file):
246
                code = "\n".join(["import sys",
247
                                  "print('hello stdout')",
248
                                  "print('hello stderr', file=sys.stderr)"])
249
                return "-c", code
250
251
        uut = (linter(sys.executable, use_stdout=True)
0 ignored issues
show
Bug introduced by
linter(sys.executable, u...tdout=True)(TestLinter) does not seem to be callable.
Loading history...
252
               (TestLinter)
253
               (self.section, None))
254
        uut.run("", [])
255
256
        process_output_mock.assert_called_once_with("hello stdout\n", "", [])
257
        process_output_mock.reset_mock()
258
259
        uut = (linter(sys.executable, use_stdout=False, use_stderr=True)
0 ignored issues
show
Bug introduced by
linter(sys.executable, u...tderr=True)(TestLinter) does not seem to be callable.
Loading history...
260
               (TestLinter)
261
               (self.section, None))
262
        uut.run("", [])
263
264
        process_output_mock.assert_called_once_with("hello stderr\n", "", [])
265
        process_output_mock.reset_mock()
266
267
        uut = (linter(sys.executable, use_stdout=True, use_stderr=True)
0 ignored issues
show
Bug introduced by
linter(sys.executable, u...tderr=True)(TestLinter) does not seem to be callable.
Loading history...
268
               (TestLinter)
269
               (self.section, None))
270
271
        uut.run("", [])
272
273
        process_output_mock.assert_called_once_with(("hello stdout\n",
274
                                                     "hello stderr\n"), "", [])
275
276
    def test_process_output_corrected(self):
277
        uut = (linter(sys.executable, output_format="corrected")
0 ignored issues
show
Bug introduced by
linter(sys.executable, o...)(self.EmptyTestLinter) does not seem to be callable.
Loading history...
278
               (self.EmptyTestLinter)
279
               (self.section, None))
280
281
        original = ["void main()  {\n", "return 09;\n", "}\n"]
282
        fixed = ["void main()\n", "{\n", "return 9;\n", "}\n"]
283
        fixed_string = "".join(fixed)
284
285
        results = list(uut.process_output(fixed_string,
286
                                          "some-file.c",
287
                                          original))
288
289
        diffs = list(Diff.from_string_arrays(original, fixed).split_diff())
290
        expected = [Result.from_values(uut,
291
                                       "Inconsistency found.",
292
                                       "some-file.c",
293
                                       1, None, 2, None,
294
                                       RESULT_SEVERITY.NORMAL,
295
                                       diffs={"some-file.c": diffs[0]})]
296
297
        self.assertEqual(results, expected)
298
299
        # Test when providing a sequence as output.
300
301
        results = list(uut.process_output([fixed_string, fixed_string],
302
                                          "some-file.c",
303
                                          original))
304
        self.assertEqual(results, 2 * expected)
305
306
        # Test diff_distance
307
308
        uut = (linter(sys.executable,
0 ignored issues
show
Bug introduced by
linter(sys.executable, o...)(self.EmptyTestLinter) does not seem to be callable.
Loading history...
309
                      output_format="corrected",
310
                      diff_distance=-1)
311
               (self.EmptyTestLinter)
312
               (self.section, None))
313
314
        results = list(uut.process_output(fixed_string,
315
                                          "some-file.c",
316
                                          original))
317
        self.assertEqual(len(results), 2)
318
319
    def test_process_output_regex(self):
320
        # Also test the case when an unknown severity is matched.
321
        test_output = ("12:4-14:0-Serious issue (error) -> ORIGIN=X -> D\n"
322
                       "0:0-0:1-This is a warning (warning) -> ORIGIN=Y -> A\n"
323
                       "813:77-1024:32-Just a note (info) -> ORIGIN=Z -> C\n"
324
                       "0:0-0:0-Some unknown sev (???) -> ORIGIN=W -> B\n")
325
        regex = (r"(?P<line>\d+):(?P<column>\d+)-"
326
                 r"(?P<end_line>\d+):(?P<end_column>\d+)-"
327
                 r"(?P<message>.*) \((?P<severity>.*)\) -> "
328
                 r"ORIGIN=(?P<origin>.*) -> (?P<additional_info>.*)")
329
330
        uut = (linter(sys.executable,
0 ignored issues
show
Bug introduced by
linter(sys.executable, o...)(self.EmptyTestLinter) does not seem to be callable.
Loading history...
331
                      output_format="regex",
332
                      output_regex=regex)
333
               (self.EmptyTestLinter)
334
               (self.section, None))
335
        uut.warn = Mock()
336
337
        sample_file = "some-file.xtx"
338
        results = list(uut.process_output(test_output, sample_file, [""]))
339
        expected = [Result.from_values("EmptyTestLinter (X)",
340
                                       "Serious issue",
341
                                       sample_file,
342
                                       12, 4, 14, 0,
343
                                       RESULT_SEVERITY.MAJOR,
344
                                       additional_info="D"),
345
                    Result.from_values("EmptyTestLinter (Y)",
346
                                       "This is a warning",
347
                                       sample_file,
348
                                       0, 0, 0, 1,
349
                                       RESULT_SEVERITY.NORMAL,
350
                                       additional_info="A"),
351
                    Result.from_values("EmptyTestLinter (Z)",
352
                                       "Just a note",
353
                                       sample_file,
354
                                       813, 77, 1024, 32,
355
                                       RESULT_SEVERITY.INFO,
356
                                       additional_info="C"),
357
                    Result.from_values("EmptyTestLinter (W)",
358
                                       "Some unknown sev",
359
                                       sample_file,
360
                                       0, 0, 0, 0,
361
                                       RESULT_SEVERITY.NORMAL,
362
                                       additional_info="B")]
363
364
        self.assertEqual(results, expected)
365
        uut.warn.assert_called_once_with(
366
            "'???' not found in severity-map. Assuming "
367
            "`RESULT_SEVERITY.NORMAL`.")
368
369
        # Test when providing a sequence as output.
370
        test_output = ["",
371
                       "12:4-14:0-Serious issue (error) -> ORIGIN=X -> XYZ\n"]
372
        results = list(uut.process_output(test_output, sample_file, [""]))
373
        expected = [Result.from_values("EmptyTestLinter (X)",
374
                                       "Serious issue",
375
                                       sample_file,
376
                                       12, 4, 14, 0,
377
                                       RESULT_SEVERITY.MAJOR,
378
                                       additional_info="XYZ")]
379
380
        self.assertEqual(results, expected)
381
382
        # Test with using `result_message` parameter.
383
        uut = (linter(sys.executable,
0 ignored issues
show
Bug introduced by
linter(sys.executable, o...)(self.EmptyTestLinter) does not seem to be callable.
Loading history...
384
                      output_format="regex",
385
                      output_regex=regex,
386
                      result_message="Hello world")
387
               (self.EmptyTestLinter)
388
               (self.section, None))
389
390
        results = list(uut.process_output(test_output, sample_file, [""]))
391
        expected = [Result.from_values("EmptyTestLinter (X)",
392
                                       "Hello world",
393
                                       sample_file,
394
                                       12, 4, 14, 0,
395
                                       RESULT_SEVERITY.MAJOR,
396
                                       additional_info="XYZ")]
397
398
        self.assertEqual(results, expected)
399
400
    def test_minimal_regex(self):
401
        uut = (linter(sys.executable,
0 ignored issues
show
Bug introduced by
linter(sys.executable, o...)(self.EmptyTestLinter) does not seem to be callable.
Loading history...
402
                      output_format="regex",
403
                      output_regex="an_issue")
404
               (self.EmptyTestLinter)
405
               (self.section, None))
406
407
        results = list(uut.process_output(['not an issue'], 'file', [""]))
408
        self.assertEqual(results, [])
409
410
        results = list(uut.process_output(['an_issue'], 'file', [""]))
411
        self.assertEqual(results, [Result.from_values("EmptyTestLinter", "",
412
                                                      file="file")])
413
414
    def test_get_non_optional_settings(self):
415
        class Handler(self.ManualProcessingTestLinter):
416
417
            @staticmethod
418
            def create_arguments(filename, file, config_file, param_x: int):
419
                pass
420
421
            @staticmethod
422
            def generate_config(filename, file, superparam):
423
                """
424
                :param superparam: A superparam!
425
                """
426
                return None
427
428
        uut = linter(sys.executable)(Handler)
429
430
        self.assertEqual(uut.get_non_optional_settings(),
431
                         {"param_x": ("No description given.", int),
432
                          "superparam": ("A superparam!", None)})
433
434
    def test_process_output_metadata_omits_on_builtin_formats(self):
435
        uut = (linter(executable='', output_format='corrected')
436
               (self.EmptyTestLinter))
437
        # diff_severity and result_message should now not occur inside the
438
        # metadata definition.
439
        self.assertNotIn("diff_severity", uut.get_metadata().optional_params)
440
        self.assertNotIn("result_message", uut.get_metadata().optional_params)
441
        self.assertNotIn("diff_severity",
442
                         uut.get_metadata().non_optional_params)
443
        self.assertNotIn("result_message",
444
                         uut.get_metadata().non_optional_params)
445
446
        # But every parameter manually defined in process_output shall appear
447
        # inside the metadata signature.
448
        class Handler:
449
450
            @staticmethod
451
            def create_arguments(filename, file, config_file):
452
                pass
453
454
            @staticmethod
455
            def process_output(output, filename, file, diff_severity):
456
                pass
457
458
        uut = linter(executable='')(Handler)
459
        self.assertIn("diff_severity", uut.get_metadata().non_optional_params)
460
461
    def test_section_settings_forwarding(self):
462
        create_arguments_mock = Mock()
463
        generate_config_mock = Mock()
464
        process_output_mock = Mock()
465
466
        class Handler(self.ManualProcessingTestLinter):
467
468
            @staticmethod
469
            def create_arguments(filename, file, config_file, my_param: int):
470
                create_arguments_mock(filename, file, config_file, my_param)
471
                # Execute python and do nothing.
472
                return "-c", "print('coala!')"
473
474
            @staticmethod
475
            def generate_config(filename, file, my_config_param: int):
476
                generate_config_mock(filename, file, my_config_param)
477
                return None
478
479
            def process_output(self, output, filename, file, makman2: str):
480
                process_output_mock(output, filename, file, makman2)
481
482
        self.section["my_param"] = "109"
483
        self.section["my_config_param"] = "88"
484
        self.section["makman2"] = "is cool"
485
486
        uut = linter(sys.executable)(Handler)(self.section, None)
487
488
        self.assertIsNotNone(list(uut.execute(filename="some_file.cs",
489
                                              file=[])))
490
        create_arguments_mock.assert_called_once_with(
491
            "some_file.cs", [], None, 109)
492
        generate_config_mock.assert_called_once_with("some_file.cs", [], 88)
493
        process_output_mock.assert_called_once_with(
494
            "coala!\n", "some_file.cs", [], "is cool")
495
496
    def test_section_settings_defaults_forwarding(self):
497
        create_arguments_mock = Mock()
498
        generate_config_mock = Mock()
499
        process_output_mock = Mock()
500
501
        class Handler:
502
503
            @staticmethod
504
            def generate_config(filename, file, some_default: str="x"):
505
                generate_config_mock(filename, file, some_default)
506
                return None
507
508
            @staticmethod
509
            def create_arguments(filename, file, config_file, default: int=3):
510
                create_arguments_mock(
511
                    filename, file, config_file, default)
512
                return "-c", "print('hello')"
513
514
            @staticmethod
515
            def process_output(output, filename, file, xxx: int=64):
516
                process_output_mock(output, filename, file, xxx)
517
518
        uut = linter(sys.executable)(Handler)(self.section, None)
519
520
        self.assertIsNotNone(list(uut.execute(filename="abc.py", file=[])))
521
        create_arguments_mock.assert_called_once_with("abc.py", [], None, 3)
522
        generate_config_mock.assert_called_once_with("abc.py", [], "x")
523
        process_output_mock.assert_called_once_with(
524
            "hello\n", "abc.py", [], 64)
525
526
        create_arguments_mock.reset_mock()
527
        generate_config_mock.reset_mock()
528
        process_output_mock.reset_mock()
529
530
        self.section["default"] = "1000"
531
        self.section["some_default"] = "xyz"
532
        self.section["xxx"] = "-50"
533
        self.assertIsNotNone(list(uut.execute(filename="def.py", file=[])))
534
        create_arguments_mock.assert_called_once_with("def.py", [], None, 1000)
535
        generate_config_mock.assert_called_once_with("def.py", [], "xyz")
536
        process_output_mock.assert_called_once_with(
537
            "hello\n", "def.py", [], -50)
538
539
    def test_invalid_arguments(self):
540
541
        class InvalidArgumentsLinter(self.ManualProcessingTestLinter):
542
543
            @staticmethod
544
            def create_arguments(filename, file, config_file):
545
                return None
546
547
        uut = (linter(sys.executable)(InvalidArgumentsLinter)
0 ignored issues
show
Bug introduced by
linter(sys.executable)(InvalidArgumentsLinter) does not seem to be callable.
Loading history...
548
               (self.section, None))
549
        self.assertEqual(uut.run("", []), None)
550
551
    def test_generate_config(self):
552
        uut = linter("")(self.ManualProcessingTestLinter)
553
        with uut._create_config("filename", []) as config_file:
554
            self.assertIsNone(config_file)
555
556
        class ConfigurationTestLinter(self.ManualProcessingTestLinter):
557
558
            @staticmethod
559
            def generate_config(filename, file, val):
560
                return "config_value = " + str(val)
561
562
        uut = linter("", config_suffix=".xml")(ConfigurationTestLinter)
563
        with uut._create_config("filename", [], val=88) as config_file:
564
            self.assertTrue(os.path.isfile(config_file))
565
            self.assertEqual(config_file[-4:], ".xml")
566
            with open(config_file, mode="r") as fl:
567
                self.assertEqual(fl.read(), "config_value = 88")
568
        self.assertFalse(os.path.isfile(config_file))
569
570
    def test_metaclass_repr(self):
571
        uut = linter("my-tool")(self.ManualProcessingTestLinter)
572
        self.assertEqual(
573
            repr(uut),
574
            "<ManualProcessingTestLinter linter class (wrapping 'my-tool')>")
575
576
        # Test also whether derivatives change the class name accordingly.
577
        class DerivedLinter(uut):
578
            pass
579
        self.assertEqual(repr(DerivedLinter),
580
                         "<DerivedLinter linter class (wrapping 'my-tool')>")
581
582
    def test_repr(self):
583
        uut = (linter(sys.executable)
0 ignored issues
show
Bug introduced by
linter(sys.executable)(s...alProcessingTestLinter) does not seem to be callable.
Loading history...
584
               (self.ManualProcessingTestLinter)
585
               (self.section, None))
586
587
        self.assertRegex(
588
            repr(uut),
589
            "<ManualProcessingTestLinter linter object \\(wrapping " +
590
            re.escape(repr(sys.executable)) + "\\) at 0x[a-fA-F0-9]+>")
591
592
    @skipIf(platform.system() == "Windows",
593
            "Nobody can sanely test things on windows")
594
    def test_process_directory(self):
595
        """
596
        The linter shall run the process in the right directory so tools can
597
        use the current working directory to resolve import like things.
598
        """
599
        uut = (linter("pwd")
0 ignored issues
show
Bug introduced by
linter('pwd')(self.RootDirTestLinter) does not seem to be callable.
Loading history...
600
               (self.RootDirTestLinter)
601
               (self.section, None))
602
        uut.run('', [])  # Does an assert in the output processing
603
604
605
class LinterReallifeTest(unittest.TestCase):
606
607
    def setUp(self):
608
        self.section = Section("REALLIFE_TEST_SECTION")
609
610
        self.test_program_path = get_testfile_name("test_linter.py")
611
        self.test_program_regex = (
612
            r"L(?P<line>\d+)C(?P<column>\d+)-"
613
            r"L(?P<end_line>\d+)C(?P<end_column>\d+):"
614
            r" (?P<message>.*) \| (?P<severity>.+) SEVERITY")
615
        self.test_program_severity_map = {"MAJOR": RESULT_SEVERITY.MAJOR}
616
617
        self.testfile_path = get_testfile_name("test_file.txt")
618
        with open(self.testfile_path, mode="r") as fl:
619
            self.testfile_content = fl.read().splitlines(keepends=True)
620
621
        self.testfile2_path = get_testfile_name("test_file2.txt")
622
        with open(self.testfile2_path, mode="r") as fl:
623
            self.testfile2_content = fl.read().splitlines(keepends=True)
624
625
    def test_nostdin_nostderr_noconfig_nocorrection(self):
626
        create_arguments_mock = Mock()
627
628
        class Handler:
629
630
            @staticmethod
631
            def create_arguments(filename, file, config_file):
632
                create_arguments_mock(filename, file, config_file)
633
                return self.test_program_path, filename
634
635
        uut = (linter(sys.executable,
0 ignored issues
show
Bug introduced by
linter(sys.executable, o..._severity_map)(Handler) does not seem to be callable.
Loading history...
636
                      output_format="regex",
637
                      output_regex=self.test_program_regex,
638
                      severity_map=self.test_program_severity_map)
639
               (Handler)
640
               (self.section, None))
641
642
        results = list(uut.run(self.testfile_path, self.testfile_content))
643
        expected = [Result.from_values(uut,
644
                                       "Invalid char ('0')",
645
                                       self.testfile_path,
646
                                       3, 0, 3, 1,
647
                                       RESULT_SEVERITY.MAJOR),
648
                    Result.from_values(uut,
649
                                       "Invalid char ('.')",
650
                                       self.testfile_path,
651
                                       5, 0, 5, 1,
652
                                       RESULT_SEVERITY.MAJOR),
653
                    Result.from_values(uut,
654
                                       "Invalid char ('p')",
655
                                       self.testfile_path,
656
                                       9, 0, 9, 1,
657
                                       RESULT_SEVERITY.MAJOR)]
658
659
        self.assertEqual(results, expected)
660
        create_arguments_mock.assert_called_once_with(
661
            self.testfile_path, self.testfile_content, None)
662
663
    def test_stdin_stderr_noconfig_nocorrection(self):
664
        create_arguments_mock = Mock()
665
666
        class Handler:
667
668
            @staticmethod
669
            def create_arguments(filename, file, config_file):
670
                create_arguments_mock(filename, file, config_file)
671
                return (self.test_program_path,
672
                        "--use_stderr",
673
                        "--use_stdin",
674
                        filename)
675
676
        uut = (linter(sys.executable,
0 ignored issues
show
Bug introduced by
linter(sys.executable, u..._severity_map)(Handler) does not seem to be callable.
Loading history...
677
                      use_stdin=True,
678
                      use_stdout=False,
679
                      use_stderr=True,
680
                      output_format="regex",
681
                      output_regex=self.test_program_regex,
682
                      severity_map=self.test_program_severity_map)
683
               (Handler)
684
               (self.section, None))
685
686
        results = list(uut.run(self.testfile2_path, self.testfile2_content))
687
        expected = [Result.from_values(uut,
688
                                       "Invalid char ('X')",
689
                                       self.testfile2_path,
690
                                       0, 0, 0, 1,
691
                                       RESULT_SEVERITY.MAJOR),
692
                    Result.from_values(uut,
693
                                       "Invalid char ('i')",
694
                                       self.testfile2_path,
695
                                       4, 0, 4, 1,
696
                                       RESULT_SEVERITY.MAJOR)]
697
698
        self.assertEqual(results, expected)
699
        create_arguments_mock.assert_called_once_with(
700
            self.testfile2_path, self.testfile2_content, None)
701
702
    def test_nostdin_nostderr_noconfig_correction(self):
703
        create_arguments_mock = Mock()
704
705
        class Handler:
706
707
            @staticmethod
708
            def create_arguments(filename, file, config_file):
709
                create_arguments_mock(filename, file, config_file)
710
                return self.test_program_path, "--correct", filename
711
712
        uut = (linter(sys.executable,
0 ignored issues
show
Bug introduced by
linter(sys.executable, o...stom message')(Handler) does not seem to be callable.
Loading history...
713
                      output_format="corrected",
714
                      diff_severity=RESULT_SEVERITY.INFO,
715
                      result_message="Custom message")
716
               (Handler)
717
               (self.section, None))
718
719
        results = list(uut.run(self.testfile_path, self.testfile_content))
720
721
        expected_correction = [s + "\n"
722
                               for s in ["+", "-", "*", "++", "-", "-", "+"]]
723
724
        diffs = list(Diff.from_string_arrays(
725
            self.testfile_content,
726
            expected_correction).split_diff())
727
728
        expected = [Result(uut, "Custom message",
729
                           affected_code=(
730
                               SourceRange.from_values(self.testfile_path, 4),
731
                               SourceRange.from_values(self.testfile_path, 6)),
732
                           severity=RESULT_SEVERITY.INFO,
733
                           diffs={self.testfile_path: diffs[0]}),
734
                    Result.from_values(uut,
735
                                       "Custom message",
736
                                       self.testfile_path,
737
                                       10, None, 10, None,
738
                                       RESULT_SEVERITY.INFO,
739
                                       diffs={self.testfile_path: diffs[1]})]
740
741
        self.assertEqual(results, expected)
742
        create_arguments_mock.assert_called_once_with(
743
            self.testfile_path, self.testfile_content, None)
744
745
    def test_stdin_stdout_stderr_config_nocorrection(self):
746
        create_arguments_mock = Mock()
747
        generate_config_mock = Mock()
748
749
        class Handler:
750
751
            @staticmethod
752
            def generate_config(filename, file, some_val):
753
                # some_val shall only test the argument delegation from run().
754
                generate_config_mock(filename, file, some_val)
755
                return "\n".join(["use_stdin", "use_stderr"])
756
757
            @staticmethod
758
            def create_arguments(filename, file, config_file, some_val):
759
                create_arguments_mock(filename, file, config_file, some_val)
760
                return self.test_program_path, "--config", config_file
761
762
        uut = (linter(sys.executable,
0 ignored issues
show
Bug introduced by
linter(sys.executable, u...ar provided!')(Handler) does not seem to be callable.
Loading history...
763
                      use_stdin=True,
764
                      use_stderr=True,
765
                      output_format="regex",
766
                      output_regex=self.test_program_regex,
767
                      severity_map=self.test_program_severity_map,
768
                      result_message="Invalid char provided!")
769
               (Handler)
770
               (self.section, None))
771
772
        results = list(uut.run(self.testfile_path,
773
                               self.testfile_content,
774
                               some_val=33))
775
        expected = [Result.from_values(uut,
776
                                       "Invalid char provided!",
777
                                       self.testfile_path,
778
                                       3, 0, 3, 1,
779
                                       RESULT_SEVERITY.MAJOR),
780
                    Result.from_values(uut,
781
                                       "Invalid char provided!",
782
                                       self.testfile_path,
783
                                       5, 0, 5, 1,
784
                                       RESULT_SEVERITY.MAJOR),
785
                    Result.from_values(uut,
786
                                       "Invalid char provided!",
787
                                       self.testfile_path,
788
                                       9, 0, 9, 1,
789
                                       RESULT_SEVERITY.MAJOR)]
790
791
        self.assertEqual(results, expected)
792
        create_arguments_mock.assert_called_once_with(
793
            self.testfile_path, self.testfile_content, ANY, 33)
794
        self.assertIsNotNone(create_arguments_mock.call_args[0][2])
795
        generate_config_mock.assert_called_once_with(
796
            self.testfile_path, self.testfile_content, 33)
797
798
    def test_stdin_stderr_config_correction(self):
799
        create_arguments_mock = Mock()
800
        generate_config_mock = Mock()
801
802
        # `some_value_A` and `some_value_B` are used to test the different
803
        # delegation to `generate_config()` and `create_arguments()`
804
        # accordingly.
805
        class Handler:
806
807
            @staticmethod
808
            def generate_config(filename, file, some_value_A):
809
                generate_config_mock(filename, file, some_value_A)
810
                return "\n".join(["use_stdin", "use_stderr", "correct"])
811
812
            @staticmethod
813
            def create_arguments(filename, file, config_file, some_value_B):
814
                create_arguments_mock(filename, file, config_file,
815
                                      some_value_B)
816
                return self.test_program_path, "--config", config_file
817
818
        uut = (linter(sys.executable,
0 ignored issues
show
Bug introduced by
linter(sys.executable, u...uffix='.conf')(Handler) does not seem to be callable.
Loading history...
819
                      use_stdin=True,
820
                      use_stdout=False,
821
                      use_stderr=True,
822
                      output_format="corrected",
823
                      config_suffix=".conf")
824
               (Handler)
825
               (self.section, None))
826
827
        results = list(uut.run(self.testfile2_path,
828
                               self.testfile2_content,
829
                               some_value_A=124,
830
                               some_value_B=-78))
831
832
        expected_correction = [s + "\n" for s in ["+", "/", "/", "-"]]
833
834
        diffs = list(Diff.from_string_arrays(
835
            self.testfile2_content,
836
            expected_correction).split_diff())
837
838
        expected = [Result.from_values(uut,
839
                                       "Inconsistency found.",
840
                                       self.testfile2_path,
841
                                       1, None, 1, None,
842
                                       RESULT_SEVERITY.NORMAL,
843
                                       diffs={self.testfile2_path: diffs[0]}),
844
                    Result.from_values(uut,
845
                                       "Inconsistency found.",
846
                                       self.testfile2_path,
847
                                       5, None, 5, None,
848
                                       RESULT_SEVERITY.NORMAL,
849
                                       diffs={self.testfile2_path: diffs[1]})]
850
851
        self.assertEqual(results, expected)
852
        create_arguments_mock.assert_called_once_with(
853
            self.testfile2_path, self.testfile2_content, ANY, -78)
854
        self.assertEqual(create_arguments_mock.call_args[0][2][-5:], ".conf")
855
        generate_config_mock.assert_called_once_with(
856
            self.testfile2_path, self.testfile2_content, 124)
857