1import sys
2import unittest
3
4from .. import tool_imports_for_tests
5with tool_imports_for_tests():
6    from c_analyzer.variables import info
7    from cpython import SOURCE_DIRS
8    from cpython.supported import IGNORED_FILE
9    from cpython.known import DATA_FILE as KNOWN_FILE
10    from cpython.__main__ import (
11            cmd_check, cmd_show, parse_args, main,
12            )
13
14
15TYPICAL = [
16        (info.Variable.from_parts('src1/spam.c', None, 'var1', 'const char *'),
17         True,
18         ),
19        (info.Variable.from_parts('src1/spam.c', 'ham', 'initialized', 'int'),
20         True,
21         ),
22        (info.Variable.from_parts('src1/spam.c', None, 'var2', 'PyObject *'),
23         False,
24         ),
25        (info.Variable.from_parts('src1/eggs.c', 'tofu', 'ready', 'int'),
26         True,
27         ),
28        (info.Variable.from_parts('src1/spam.c', None, 'freelist', '(PyTupleObject *)[10]'),
29         False,
30         ),
31        (info.Variable.from_parts('src1/sub/ham.c', None, 'var1', 'const char const *'),
32         True,
33         ),
34        (info.Variable.from_parts('src2/jam.c', None, 'var1', 'int'),
35         True,
36         ),
37        (info.Variable.from_parts('src2/jam.c', None, 'var2', 'MyObject *'),
38         False,
39         ),
40        (info.Variable.from_parts('Include/spam.h', None, 'data', 'const int'),
41         True,
42         ),
43        ]
44
45
46class CMDBase(unittest.TestCase):
47
48    maxDiff = None
49
50#    _return_known_from_file = None
51#    _return_ignored_from_file = None
52    _return_find = ()
53
54    @property
55    def calls(self):
56        try:
57            return self._calls
58        except AttributeError:
59            self._calls = []
60            return self._calls
61
62#    def _known_from_file(self, *args):
63#        self.calls.append(('_known_from_file', args))
64#        return self._return_known_from_file or {}
65#
66#    def _ignored_from_file(self, *args):
67#        self.calls.append(('_ignored_from_file', args))
68#        return self._return_ignored_from_file or {}
69
70    def _find(self, known, ignored, skip_objects=False):
71        self.calls.append(('_find', (known, ignored, skip_objects)))
72        return self._return_find
73
74    def _show(self, *args):
75        self.calls.append(('_show', args))
76
77    def _print(self, *args):
78        self.calls.append(('_print', args))
79
80
81class CheckTests(CMDBase):
82
83    def test_defaults(self):
84        self._return_find = []
85
86        cmd_check('check',
87                  _find=self._find,
88                  _show=self._show,
89                  _print=self._print,
90                  )
91
92        self.assertEqual(
93                self.calls[0],
94                ('_find', (KNOWN_FILE, IGNORED_FILE, False)),
95                )
96
97    def test_all_supported(self):
98        self._return_find = [(v, s) for v, s in TYPICAL if s]
99        dirs = ['src1', 'src2', 'Include']
100
101        cmd_check('check',
102                  known='known.tsv',
103                  ignored='ignored.tsv',
104                  _find=self._find,
105                  _show=self._show,
106                  _print=self._print,
107                  )
108
109        self.assertEqual(self.calls, [
110            ('_find', ('known.tsv', 'ignored.tsv', False)),
111            #('_print', ('okay',)),
112            ])
113
114    def test_some_unsupported(self):
115        self._return_find = TYPICAL
116
117        with self.assertRaises(SystemExit) as cm:
118            cmd_check('check',
119                      known='known.tsv',
120                      ignored='ignored.tsv',
121                      _find=self._find,
122                      _show=self._show,
123                      _print=self._print,
124                      )
125
126        unsupported = [v for v, s in TYPICAL if not s]
127        self.assertEqual(self.calls, [
128            ('_find', ('known.tsv', 'ignored.tsv', False)),
129            ('_print', ('ERROR: found unsupported global variables',)),
130            ('_print', ()),
131            ('_show', (sorted(unsupported),)),
132            ('_print', (' (3 total)',)),
133            ])
134        self.assertEqual(cm.exception.code, 1)
135
136
137class ShowTests(CMDBase):
138
139    def test_defaults(self):
140        self._return_find = []
141
142        cmd_show('show',
143                 _find=self._find,
144                 _show=self._show,
145                 _print=self._print,
146                 )
147
148        self.assertEqual(
149                self.calls[0],
150                ('_find', (KNOWN_FILE, IGNORED_FILE, False)),
151                )
152
153    def test_typical(self):
154        self._return_find = TYPICAL
155
156        cmd_show('show',
157                 known='known.tsv',
158                 ignored='ignored.tsv',
159                 _find=self._find,
160                 _show=self._show,
161                 _print=self._print,
162                 )
163
164        supported = [v for v, s in TYPICAL if s]
165        unsupported = [v for v, s in TYPICAL if not s]
166        self.assertEqual(self.calls, [
167            ('_find', ('known.tsv', 'ignored.tsv', False)),
168            ('_print', ('supported:',)),
169            ('_print', ('----------',)),
170            ('_show', (sorted(supported),)),
171            ('_print', (' (6 total)',)),
172            ('_print', ()),
173            ('_print', ('unsupported:',)),
174            ('_print', ('------------',)),
175            ('_show', (sorted(unsupported),)),
176            ('_print', (' (3 total)',)),
177            ])
178
179
180class ParseArgsTests(unittest.TestCase):
181
182    maxDiff = None
183
184    def test_no_args(self):
185        self.errmsg = None
186        def fail(msg):
187            self.errmsg = msg
188            sys.exit(msg)
189
190        with self.assertRaises(SystemExit):
191            parse_args('cg', [], _fail=fail)
192
193        self.assertEqual(self.errmsg, 'missing command')
194
195    def test_check_no_args(self):
196        cmd, cmdkwargs = parse_args('cg', [
197            'check',
198            ])
199
200        self.assertEqual(cmd, 'check')
201        self.assertEqual(cmdkwargs, {
202            'ignored': IGNORED_FILE,
203            'known': KNOWN_FILE,
204            #'dirs': SOURCE_DIRS,
205            })
206
207    def test_check_full_args(self):
208        cmd, cmdkwargs = parse_args('cg', [
209            'check',
210            '--ignored', 'spam.tsv',
211            '--known', 'eggs.tsv',
212            #'dir1',
213            #'dir2',
214            #'dir3',
215            ])
216
217        self.assertEqual(cmd, 'check')
218        self.assertEqual(cmdkwargs, {
219            'ignored': 'spam.tsv',
220            'known': 'eggs.tsv',
221            #'dirs': ['dir1', 'dir2', 'dir3']
222            })
223
224    def test_show_no_args(self):
225        cmd, cmdkwargs = parse_args('cg', [
226            'show',
227            ])
228
229        self.assertEqual(cmd, 'show')
230        self.assertEqual(cmdkwargs, {
231            'ignored': IGNORED_FILE,
232            'known': KNOWN_FILE,
233            #'dirs': SOURCE_DIRS,
234            'skip_objects': False,
235            })
236
237    def test_show_full_args(self):
238        cmd, cmdkwargs = parse_args('cg', [
239            'show',
240            '--ignored', 'spam.tsv',
241            '--known', 'eggs.tsv',
242            #'dir1',
243            #'dir2',
244            #'dir3',
245            ])
246
247        self.assertEqual(cmd, 'show')
248        self.assertEqual(cmdkwargs, {
249            'ignored': 'spam.tsv',
250            'known': 'eggs.tsv',
251            #'dirs': ['dir1', 'dir2', 'dir3'],
252            'skip_objects': False,
253            })
254
255
256def new_stub_commands(*names):
257    calls = []
258    def cmdfunc(cmd, **kwargs):
259        calls.append((cmd, kwargs))
260    commands = {name: cmdfunc for name in names}
261    return commands, calls
262
263
264class MainTests(unittest.TestCase):
265
266    def test_no_command(self):
267        with self.assertRaises(ValueError):
268            main(None, {})
269
270    def test_check(self):
271        commands, calls = new_stub_commands('check', 'show')
272
273        cmdkwargs = {
274            'ignored': 'spam.tsv',
275            'known': 'eggs.tsv',
276            'dirs': ['dir1', 'dir2', 'dir3'],
277            }
278        main('check', cmdkwargs, _COMMANDS=commands)
279
280        self.assertEqual(calls, [
281            ('check', cmdkwargs),
282            ])
283
284    def test_show(self):
285        commands, calls = new_stub_commands('check', 'show')
286
287        cmdkwargs = {
288            'ignored': 'spam.tsv',
289            'known': 'eggs.tsv',
290            'dirs': ['dir1', 'dir2', 'dir3'],
291            }
292        main('show', cmdkwargs, _COMMANDS=commands)
293
294        self.assertEqual(calls, [
295            ('show', cmdkwargs),
296            ])
297