1#!/usr/bin/env python
2#
3# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import unittest
18
19from check_kconfigs import CONFIG_NAME_MAX_LENGTH, IndentAndNameChecker, InputError, LineRuleChecker, SourceChecker
20
21
22class ApplyLine(object):
23    def apply_line(self, string):
24        self.checker.process_line(string + '\n', 0)
25
26    def expect_error(self, string, expect, cleanup=None):
27        try:
28            with self.assertRaises(InputError) as cm:
29                self.apply_line(string)
30            if expect:
31                self.assertEqual(cm.exception.suggested_line, expect + '\n')
32        finally:
33            if cleanup:
34                # cleanup of the previous failure
35                self.apply_line(cleanup)
36
37    def expt_success(self, string):
38        self.apply_line(string)
39
40
41class TestLineRuleChecker(unittest.TestCase, ApplyLine):
42    def setUp(self):
43        self.checker = LineRuleChecker('Kconfig')
44
45    def tearDown(self):
46        pass
47
48    def test_tabulators(self):
49        self.expect_error('\ttest', expect='    test')
50        self.expect_error('\t    test', expect='        test')
51        self.expect_error('   \ttest', expect='       test')
52        self.expect_error('     \t     test', expect='              test')
53        self.expt_success('         test')
54        self.expt_success('test')
55
56    def test_trailing_whitespaces(self):
57        self.expect_error(' ', expect='')
58        self.expect_error('     ', expect='')
59        self.expect_error('test ', expect='test')
60        self.expt_success('test')
61        self.expt_success('')
62
63    def test_line_length(self):
64        self.expect_error('x' * 120, expect=None)
65        self.expt_success('x' * 119)
66        self.expt_success('')
67
68    def test_backslashes(self):
69        self.expect_error('test \\', expect=None)
70
71
72class TestSourceChecker(unittest.TestCase, ApplyLine):
73    def setUp(self):
74        self.checker = SourceChecker('Kconfig')
75
76    def tearDown(self):
77        pass
78
79    def test_source_file_name(self):
80        self.expect_error('source "notKconfig.test"', expect='source "Kconfig.notKconfig.test"')
81        self.expect_error('source "Kconfig"', expect='source "Kconfig.Kconfig"')
82        self.expt_success('source "Kconfig.in"')
83        self.expt_success('source "/tmp/Kconfig.test"')
84        self.expt_success('source "/tmp/Kconfig.in"')
85        self.expect_error('source"Kconfig.in"', expect='source "Kconfig.in"')
86        self.expt_success('source "/tmp/Kconfig.in"  # comment')
87
88
89class TestIndentAndNameChecker(unittest.TestCase, ApplyLine):
90    def setUp(self):
91        self.checker = IndentAndNameChecker('Kconfig')
92        self.checker.min_prefix_length = 4
93
94    def tearDown(self):
95        self.checker.__exit__('Kconfig', None, None)
96
97
98class TestIndent(TestIndentAndNameChecker):
99    def setUp(self):
100        super(TestIndent, self).setUp()
101        self.checker.min_prefix_length = 0  # prefixes are ignored in this test case
102
103    def test_indent_characters(self):
104        self.expt_success('menu "test"')
105        self.expect_error(' test', expect='    test')
106        self.expect_error('  test', expect='    test')
107        self.expect_error('   test', expect='    test')
108        self.expect_error('     test', expect='    test')
109        self.expt_success('    test')
110        self.expt_success('    test2')
111        self.expt_success('    config')
112        self.expect_error('    default', expect='        default')
113        self.expt_success('        help')
114        self.expect_error('         text', expect='            text')
115        self.expt_success('            help text')
116        self.expt_success('    menu')
117        self.expt_success('    endmenu')
118        self.expect_error('         choice', expect='    choice', cleanup='    endchoice')
119        self.expect_error('       choice', expect='    choice', cleanup='    endchoice')
120        self.expt_success('    choice')
121        self.expt_success('    endchoice')
122        self.expt_success('    config')
123        self.expt_success('endmenu')
124
125    def test_help_content(self):
126        self.expt_success('menu "test"')
127        self.expt_success('    config')
128        self.expt_success('        help')
129        self.expt_success('            description')
130        self.expt_success('            config keyword in the help')
131        self.expt_success('            menu keyword in the help')
132        self.expt_success('            menuconfig keyword in the help')
133        self.expt_success('            endmenu keyword in the help')
134        self.expt_success('            endmenu keyword in the help')
135        self.expt_success('')  # newline in help
136        self.expt_success('            endmenu keyword in the help')
137        self.expect_error('          menu "real menu with wrong indent"',
138                          expect='    menu "real menu with wrong indent"', cleanup='    endmenu')
139        self.expt_success('endmenu')
140
141    def test_mainmenu(self):
142        self.expt_success('mainmenu "test"')
143        self.expect_error('test', expect='    test')
144        self.expt_success('    not_a_keyword')
145        self.expt_success('    config')
146        self.expt_success('    menuconfig')
147        self.expect_error('test', expect='        test')
148        self.expect_error('   test', expect='        test')
149        self.expt_success('    menu')
150        self.expt_success('    endmenu')
151
152    def test_ifendif(self):
153        self.expt_success('menu "test"')
154        self.expt_success('    config')
155        self.expt_success('        help')
156        self.expect_error('        if', expect='    if', cleanup='    endif')
157        self.expt_success('    if')
158        self.expect_error('    config', expect='        config')
159        self.expt_success('        config')
160        self.expt_success('            help')
161        self.expt_success('    endif')
162        self.expt_success('    config')
163        self.expt_success('endmenu')
164
165    def test_config_without_menu(self):
166        self.expt_success('menuconfig')
167        self.expt_success('    help')
168        self.expt_success('        text')
169        self.expt_success('')
170        self.expt_success('        text')
171        self.expt_success('config')
172        self.expt_success('    help')
173
174    def test_source_after_config(self):
175        self.expt_success('menuconfig')
176        self.expt_success('    help')
177        self.expt_success('        text')
178        self.expect_error('    source', expect='source')
179        self.expt_success('source "Kconfig.in"')
180
181    def test_comment_after_config(self):
182        self.expt_success('menuconfig')
183        self.expt_success('    # comment')
184        self.expt_success('    help')
185        self.expt_success('        text')
186        self.expect_error('# comment', expect='        # comment')
187        self.expt_success('        # second not realcomment"')
188
189
190class TestName(TestIndentAndNameChecker):
191    def setUp(self):
192        super(TestName, self).setUp()
193        self.checker.min_prefix_length = 0  # prefixes are ignored in this test case
194
195    def test_name_length(self):
196        max_length = CONFIG_NAME_MAX_LENGTH
197        too_long = max_length + 1
198        self.expt_success('menu "test"')
199        self.expt_success('    config ABC')
200        self.expt_success('    config ' + ('X' * max_length))
201        self.expect_error('    config ' + ('X' * too_long), expect=None)
202        self.expt_success('    menuconfig ' + ('X' * max_length))
203        self.expect_error('    menuconfig ' + ('X' * too_long), expect=None)
204        self.expt_success('    choice ' + ('X' * max_length))
205        self.expect_error('    choice ' + ('X' * too_long), expect=None)
206        self.expt_success('endmenu')
207
208
209class TestPrefix(TestIndentAndNameChecker):
210    def test_prefix_len(self):
211        self.expt_success('menu "test"')
212        self.expt_success('    config ABC_1')
213        self.expt_success('    config ABC_2')
214        self.expt_success('    config ABC_DEBUG')
215        self.expt_success('    config ABC_ANOTHER')
216        self.expt_success('endmenu')
217        self.expt_success('menu "test2"')
218        self.expt_success('    config A')
219        self.expt_success('    config B')
220        self.expect_error('endmenu', expect=None)
221
222    def test_choices(self):
223        self.expt_success('menu "test"')
224        self.expt_success('    choice ASSERTION_LEVEL')
225        self.expt_success('        config ASSERTION_DEBUG')
226        self.expt_success('        config ASSERTION_RELEASE')
227        self.expt_success('        menuconfig ASSERTION_XY')
228        self.expt_success('    endchoice')
229        self.expt_success('    choice DEBUG')
230        self.expt_success('        config DE_1')
231        self.expt_success('        config DE_2')
232        self.expect_error('    endchoice', expect=None)
233        self.expect_error('endmenu', expect=None)
234
235    def test_nested_menu(self):
236        self.expt_success('menu "test"')
237        self.expt_success('    config DOESNT_MATTER')
238        self.expt_success('    menu "inner menu"')
239        self.expt_success('        config MENUOP_1')
240        self.expt_success('        config MENUOP_2')
241        self.expt_success('        config MENUOP_3')
242        self.expt_success('    endmenu')
243        self.expt_success('endmenu')
244
245    def test_nested_ifendif(self):
246        self.expt_success('menu "test"')
247        self.expt_success('    config MENUOP_1')
248        self.expt_success('    if MENUOP_1')
249        self.expt_success('        config MENUOP_2')
250        self.expt_success('    endif')
251        self.expt_success('endmenu')
252
253
254if __name__ == '__main__':
255    unittest.main()
256