summaryrefslogtreecommitdiffstats
path: root/gitlint/tests/config/test_config_builder.py
blob: 051a52f0aa104fdf3f2d8fc54c558f87b47a60ea (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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# -*- coding: utf-8 -*-

from gitlint.tests.base import BaseTestCase

from gitlint.config import LintConfig, LintConfigBuilder, LintConfigError


class LintConfigBuilderTests(BaseTestCase):
    def test_set_option(self):
        config_builder = LintConfigBuilder()
        config = config_builder.build()

        # assert some defaults
        self.assertEqual(config.get_rule_option('title-max-length', 'line-length'), 72)
        self.assertEqual(config.get_rule_option('body-max-line-length', 'line-length'), 80)
        self.assertListEqual(config.get_rule_option('title-must-not-contain-word', 'words'), ["WIP"])
        self.assertEqual(config.verbosity, 3)

        # Make some changes and check blueprint
        config_builder.set_option('title-max-length', 'line-length', 100)
        config_builder.set_option('general', 'verbosity', 2)
        config_builder.set_option('title-must-not-contain-word', 'words', ["foo", "bar"])
        expected_blueprint = {'title-must-not-contain-word': {'words': ['foo', 'bar']},
                              'title-max-length': {'line-length': 100}, 'general': {'verbosity': 2}}
        self.assertDictEqual(config_builder._config_blueprint, expected_blueprint)

        # Build config and verify that the changes have occurred and no other changes
        config = config_builder.build()
        self.assertEqual(config.get_rule_option('title-max-length', 'line-length'), 100)
        self.assertEqual(config.get_rule_option('body-max-line-length', 'line-length'), 80)  # should be unchanged
        self.assertListEqual(config.get_rule_option('title-must-not-contain-word', 'words'), ["foo", "bar"])
        self.assertEqual(config.verbosity, 2)

    def test_set_from_commit_ignore_all(self):
        config = LintConfig()
        original_rules = config.rules
        original_rule_ids = [rule.id for rule in original_rules]

        config_builder = LintConfigBuilder()

        # nothing gitlint
        config_builder.set_config_from_commit(self.gitcommit(u"tëst\ngitlint\nfoo"))
        config = config_builder.build()
        self.assertSequenceEqual(config.rules, original_rules)
        self.assertListEqual(config.ignore, [])

        # ignore all rules
        config_builder.set_config_from_commit(self.gitcommit(u"tëst\ngitlint-ignore: all\nfoo"))
        config = config_builder.build()
        self.assertEqual(config.ignore, original_rule_ids)

        # ignore all rules, no space
        config_builder.set_config_from_commit(self.gitcommit(u"tëst\ngitlint-ignore:all\nfoo"))
        config = config_builder.build()
        self.assertEqual(config.ignore, original_rule_ids)

        # ignore all rules, more spacing
        config_builder.set_config_from_commit(self.gitcommit(u"tëst\ngitlint-ignore: \t all\nfoo"))
        config = config_builder.build()
        self.assertEqual(config.ignore, original_rule_ids)

    def test_set_from_commit_ignore_specific(self):
        # ignore specific rules
        config_builder = LintConfigBuilder()
        config_builder.set_config_from_commit(self.gitcommit(u"tëst\ngitlint-ignore: T1, body-hard-tab"))
        config = config_builder.build()
        self.assertEqual(config.ignore, ["T1", "body-hard-tab"])

    def test_set_from_config_file(self):
        # regular config file load, no problems
        config_builder = LintConfigBuilder()
        config_builder.set_from_config_file(self.get_sample_path("config/gitlintconfig"))
        config = config_builder.build()

        # Do some assertions on the config
        self.assertEqual(config.verbosity, 1)
        self.assertFalse(config.debug)
        self.assertFalse(config.ignore_merge_commits)
        self.assertIsNone(config.extra_path)
        self.assertEqual(config.ignore, ["title-trailing-whitespace", "B2"])

        self.assertEqual(config.get_rule_option('title-max-length', 'line-length'), 20)
        self.assertEqual(config.get_rule_option('body-max-line-length', 'line-length'), 30)

    def test_set_from_config_file_negative(self):
        config_builder = LintConfigBuilder()

        # bad config file load
        foo_path = self.get_sample_path(u"föo")
        expected_error_msg = u"Invalid file path: {0}".format(foo_path)
        with self.assertRaisesRegex(LintConfigError, expected_error_msg):
            config_builder.set_from_config_file(foo_path)

        # error during file parsing
        path = self.get_sample_path("config/no-sections")
        expected_error_msg = u"File contains no section headers."
        with self.assertRaisesRegex(LintConfigError, expected_error_msg):
            config_builder.set_from_config_file(path)

        # non-existing rule
        path = self.get_sample_path("config/nonexisting-rule")
        config_builder = LintConfigBuilder()
        config_builder.set_from_config_file(path)
        expected_error_msg = u"No such rule 'föobar'"
        with self.assertRaisesRegex(LintConfigError, expected_error_msg):
            config_builder.build()

        # non-existing general option
        path = self.get_sample_path("config/nonexisting-general-option")
        config_builder = LintConfigBuilder()
        config_builder.set_from_config_file(path)
        expected_error_msg = u"'foo' is not a valid gitlint option"
        with self.assertRaisesRegex(LintConfigError, expected_error_msg):
            config_builder.build()

        # non-existing option
        path = self.get_sample_path("config/nonexisting-option")
        config_builder = LintConfigBuilder()
        config_builder.set_from_config_file(path)
        expected_error_msg = u"Rule 'title-max-length' has no option 'föobar'"
        with self.assertRaisesRegex(LintConfigError, expected_error_msg):
            config_builder.build()

        # invalid option value
        path = self.get_sample_path("config/invalid-option-value")
        config_builder = LintConfigBuilder()
        config_builder.set_from_config_file(path)
        expected_error_msg = u"'föo' is not a valid value for option 'title-max-length.line-length'. " + \
                             u"Option 'line-length' must be a positive integer (current value: 'föo')."
        with self.assertRaisesRegex(LintConfigError, expected_error_msg):
            config_builder.build()

    def test_set_config_from_string_list(self):
        config = LintConfig()

        # change and assert changes
        config_builder = LintConfigBuilder()
        config_builder.set_config_from_string_list(['general.verbosity=1', 'title-max-length.line-length=60',
                                                    'body-max-line-length.line-length=120',
                                                    u"title-must-not-contain-word.words=håha"])

        config = config_builder.build()
        self.assertEqual(config.get_rule_option('title-max-length', 'line-length'), 60)
        self.assertEqual(config.get_rule_option('body-max-line-length', 'line-length'), 120)
        self.assertListEqual(config.get_rule_option('title-must-not-contain-word', 'words'), [u"håha"])
        self.assertEqual(config.verbosity, 1)

    def test_set_config_from_string_list_negative(self):
        config_builder = LintConfigBuilder()

        # assert error on incorrect rule - this happens at build time
        config_builder.set_config_from_string_list([u"föo.bar=1"])
        with self.assertRaisesRegex(LintConfigError, u"No such rule 'föo'"):
            config_builder.build()

        # no equal sign
        expected_msg = u"'föo.bar' is an invalid configuration option. Use '<rule>.<option>=<value>'"
        with self.assertRaisesRegex(LintConfigError, expected_msg):
            config_builder.set_config_from_string_list([u"föo.bar"])

        # missing value
        expected_msg = u"'föo.bar=' is an invalid configuration option. Use '<rule>.<option>=<value>'"
        with self.assertRaisesRegex(LintConfigError, expected_msg):
            config_builder.set_config_from_string_list([u"föo.bar="])

        # space instead of equal sign
        expected_msg = u"'föo.bar 1' is an invalid configuration option. Use '<rule>.<option>=<value>'"
        with self.assertRaisesRegex(LintConfigError, expected_msg):
            config_builder.set_config_from_string_list([u"föo.bar 1"])

        # no period between rule and option names
        expected_msg = u"'föobar=1' is an invalid configuration option. Use '<rule>.<option>=<value>'"
        with self.assertRaisesRegex(LintConfigError, expected_msg):
            config_builder.set_config_from_string_list([u'föobar=1'])

    def test_rebuild_config(self):
        # normal config build
        config_builder = LintConfigBuilder()
        config_builder.set_option('general', 'verbosity', 3)
        lint_config = config_builder.build()
        self.assertEqual(lint_config.verbosity, 3)

        # check that existing config gets overwritten when we pass it to a configbuilder with different options
        existing_lintconfig = LintConfig()
        existing_lintconfig.verbosity = 2
        lint_config = config_builder.build(existing_lintconfig)
        self.assertEqual(lint_config.verbosity, 3)
        self.assertEqual(existing_lintconfig.verbosity, 3)

    def test_clone(self):
        config_builder = LintConfigBuilder()
        config_builder.set_option('general', 'verbosity', 2)
        config_builder.set_option('title-max-length', 'line-length', 100)
        expected = {'title-max-length': {'line-length': 100}, 'general': {'verbosity': 2}}
        self.assertDictEqual(config_builder._config_blueprint, expected)

        # Clone and verify that the blueprint is the same as the original
        cloned_builder = config_builder.clone()
        self.assertDictEqual(cloned_builder._config_blueprint, expected)

        # Modify the original and make sure we're not modifying the clone (i.e. check that the copy is a deep copy)
        config_builder.set_option('title-max-length', 'line-length', 120)
        self.assertDictEqual(cloned_builder._config_blueprint, expected)