aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/tests/unit/test_hacking_checks.py
blob: 962f5f8abde48f4e37217d76bb3bf4db9d973fcc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import textwrap

import mock
import pep8

from keystone.tests.hacking import checks
from keystone.tests import unit
from keystone.tests.unit.ksfixtures import hacking as hacking_fixtures


class BaseStyleCheck(unit.BaseTestCase):

    def setUp(self):
        super(BaseStyleCheck, self).setUp()
        self.code_ex = self.useFixture(self.get_fixture())
        self.addCleanup(delattr, self, 'code_ex')

    def get_checker(self):
        """Returns the checker to be used for tests in this class."""
        raise NotImplemented('subclasses must provide a real implementation')

    def get_fixture(self):
        return hacking_fixtures.HackingCode()

    # We are patching pep8 so that only the check under test is actually
    # installed.
    @mock.patch('pep8._checks',
                {'physical_line': {}, 'logical_line': {}, 'tree': {}})
    def run_check(self, code):
        pep8.register_check(self.get_checker())

        lines = textwrap.dedent(code).strip().splitlines(True)

        checker = pep8.Checker(lines=lines)
        checker.check_all()
        checker.report._deferred_print.sort()
        return checker.report._deferred_print

    def assert_has_errors(self, code, expected_errors=None):
        actual_errors = [e[:3] for e in self.run_check(code)]
        self.assertEqual(expected_errors or [], actual_errors)


class TestCheckForMutableDefaultArgs(BaseStyleCheck):

    def get_checker(self):
        return checks.CheckForMutableDefaultArgs

    def test(self):
        code = self.code_ex.mutable_default_args['code']
        errors = self.code_ex.mutable_default_args['expected_errors']
        self.assert_has_errors(code, expected_errors=errors)


class TestBlockCommentsBeginWithASpace(BaseStyleCheck):

    def get_checker(self):
        return checks.block_comments_begin_with_a_space

    def test(self):
        code = self.code_ex.comments_begin_with_space['code']
        errors = self.code_ex.comments_begin_with_space['expected_errors']
        self.assert_has_errors(code, expected_errors=errors)


class TestAssertingNoneEquality(BaseStyleCheck):

    def get_checker(self):
        return checks.CheckForAssertingNoneEquality

    def test(self):
        code = self.code_ex.asserting_none_equality['code']
        errors = self.code_ex.asserting_none_equality['expected_errors']
        self.assert_has_errors(code, expected_errors=errors)


class TestCheckForDebugLoggingIssues(BaseStyleCheck):

    def get_checker(self):
        return checks.CheckForLoggingIssues

    def test_for_translations(self):
        fixture = self.code_ex.assert_no_translations_for_debug_logging
        code = fixture['code']
        errors = fixture['expected_errors']
        self.assert_has_errors(code, expected_errors=errors)


class TestCheckForNonDebugLoggingIssues(BaseStyleCheck):

    def get_checker(self):
        return checks.CheckForLoggingIssues

    def get_fixture(self):
        return hacking_fixtures.HackingLogging()

    def test_for_translations(self):
        for example in self.code_ex.examples:
            code = self.code_ex.shared_imports + example['code']
            errors = example['expected_errors']
            self.assert_has_errors(code, expected_errors=errors)

    def assert_has_errors(self, code, expected_errors=None):
        # pull out the parts of the error that we'll match against
        actual_errors = (e[:3] for e in self.run_check(code))
        # adjust line numbers to make the fixure data more readable.
        import_lines = len(self.code_ex.shared_imports.split('\n')) - 1
        actual_errors = [(e[0] - import_lines, e[1], e[2])
                         for e in actual_errors]
        self.assertEqual(expected_errors or [], actual_errors)


class TestDictConstructorWithSequenceCopy(BaseStyleCheck):

    def get_checker(self):
        return checks.dict_constructor_with_sequence_copy

    def test(self):
        code = self.code_ex.dict_constructor['code']
        errors = self.code_ex.dict_constructor['expected_errors']
        self.assert_has_errors(code, expected_errors=errors)