Completed
Push — master ( 9fc385...978746 )
by De
01:15
created

RegexTests.test_bad_operand_unary()   A

Complexity

Conditions 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 2
1
# -*- coding: utf-8
2
"""Unit tests for regexps from didyoumean_re.py."""
3
import unittest2
4
import didyoumean_re as re
5
import sys
6
7
NO_GROUP = ((), dict())
8
# Various technical flags to check more that meet the eyes in tests
9
# Flag used to check that a text only match the expected regexp and not
10
# the other to ensure we do not have ambiguous/double regexp matching.
11
CHECK_OTHERS_DONT_MATCH = True
12
# Flag to check that the regexp provided does correspond to a regexp
13
# listed in re.ALL_REGEXPS
14
CHECK_RE_LISTED = True
15
# Flag to check that the name used for the regexp in re.ALL_REGEXPS
16
# does match the naming convention
17
CHECK_RE_NAME = True
18
# Flag to check that the regex does match a few conventions such as:
19
# stars with ^, ends with $.
20
CHECK_RE_VALUE = True
21
22
23
class RegexTests(unittest2.TestCase):
24
    """Tests to check that error messages match the regexps."""
25
26
    def re_matches(self, text, regexp, results):
27
        """Check that text matches regexp and gives the right match groups.
28
29
        result is a tuple containing the expected return values for groups()
30
        and groupdict().
31
        """
32
        groups, named_groups = results
33
        self.assertRegexpMatches(text, regexp)   # does pretty printing
34
        match = re.match(regexp, text)
35
        self.assertTrue(match)
36
        self.assertEqual(groups, match.groups())
37
        self.assertEqual(named_groups, match.groupdict())
38
        self.check_more_about_re(text, regexp)
39
40
    def check_more_about_re(self, text, regexp):
41
        """Check various properties about the regexp.
42
43
        Properties checked are configurable via global constants. These
44
        properties are not stricly speaking required but they help to
45
        detect potential issues much more quickly."""
46
        if CHECK_RE_VALUE:
47
            self.assertTrue(regexp.startswith('^'))
48
            self.assertTrue(regexp.endswith('$'))
49
        found = False
50
        for other_name, other_re in re.ALL_REGEXPS.items():
51
            if other_re == regexp:
52
                found = True
53
                if CHECK_RE_NAME:
54
                    self.assertTrue(other_name.endswith('_RE'))
55
            elif CHECK_OTHERS_DONT_MATCH:
56
                details = "text '%s' matches %s (on top of %s)" % \
57
                        (text, other_name, regexp)
58
                self.assertNotRegexpMatches(text, other_re, details)
59
                no_match = re.match(other_re, text)
60
                self.assertEqual(no_match, None, details)
61
        if CHECK_RE_LISTED:
62
            self.assertTrue(found)
63
64
    def test_unbound_assignment(self):
65
        """Test VARREFBEFOREASSIGN_RE."""
66
        msgs = [
67
            # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
68
            "local variable 'some_var' referenced before assignment",
69
            "free variable 'some_var' referenced before assignment " \
70
            "in enclosing scope",
71
        ]
72
        groups = ('some_var',)
73
        named_groups = {'name': 'some_var'}
74
        results = (groups, named_groups)
75
        for msg in msgs:
76
            self.re_matches(msg, re.VARREFBEFOREASSIGN_RE, results)
77
78
    def test_name_not_defined(self):
79
        """Test NAMENOTDEFINED_RE."""
80
        msgs = [
81
            # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy3
82
            "name 'some_name' is not defined",
83
            # Python 2.6/2.7/3.2/3.3/PyPy/PyPy3
84
            "global name 'some_name' is not defined",
85
        ]
86
        groups = ('some_name',)
87
        named_groups = {'name': 'some_name'}
88
        for msg in msgs:
89
            self.re_matches(msg, re.NAMENOTDEFINED_RE, (groups, named_groups))
90
91
    def test_attribute_error(self):
92
        """Test ATTRIBUTEERROR_RE."""
93
        group_msg = {
94
            ('some.class', 'attri'): [
95
                # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
96
                "'some.class' object has no attribute 'attri'",
97
            ],
98
            ('SomeClass', 'attri'): [
99
                # Python 2.6/2.7/PyPy
100
                "SomeClass instance has no attribute 'attri'",
101
                # Python 2.6/2.7
102
                "class SomeClass has no attribute 'attri'",
103
                # Python 3.2/3.3/3.4/3.5
104
                "type object 'SomeClass' has no attribute 'attri'",
105
            ],
106
        }
107
        for group, msgs in group_msg.items():
108
            for msg in msgs:
109
                self.re_matches(msg, re.ATTRIBUTEERROR_RE, (group, dict()))
110
111
    def test_module_attribute_error(self):
112
        """Test MODULEHASNOATTRIBUTE_RE."""
113
        # Python 3.5
114
        msg = "module 'some_module' has no attribute 'attri'"
115
        group = ('some_module', 'attri')
116
        self.re_matches(msg, re.MODULEHASNOATTRIBUTE_RE, (group, dict()))
117
118
    def test_cannot_import(self):
119
        """Test CANNOTIMPORT_RE."""
120
        msgs = [
121
            # Python 2.6/2.7/3.2/3.3
122
            "cannot import name pie",
123
            # Python 3.4/3.5/PyPy/PyPy3
124
            "cannot import name 'pie'",
125
        ]
126
        groups = ('pie',)
127
        for msg in msgs:
128
            self.re_matches(msg, re.CANNOTIMPORT_RE, (groups, dict()))
129
130
    def test_no_module_named(self):
131
        """Test NOMODULE_RE."""
132
        msgs = [
133
            # Python 2.6/2.7/3.2/PyPy/PyPy3
134
            "No module named fake_module",
135
            # Python 3.3/3.4/3.5
136
            "No module named 'fake_module'",
137
        ]
138
        groups = ('fake_module',)
139
        for msg in msgs:
140
            self.re_matches(msg, re.NOMODULE_RE, (groups, dict()))
141
142
    def test_index_out_of_range(self):
143
        """Test INDEXOUTOFRANGE_RE."""
144
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
145
        msg = "list index out of range"
146
        self.re_matches(msg, re.INDEXOUTOFRANGE_RE, NO_GROUP)
147
148
    def test_unsubscriptable(self):
149
        """Test UNSUBSCRIPTABLE_RE."""
150
        msgs = [
151
            # Python 2.6
152
            "'function' object is unsubscriptable",
153
            # Python 3.2/3.3/3.4/3.5/PyPy/PyPy3
154
            "'function' object is not subscriptable",
155
        ]
156
        groups = ('function',)
157
        for msg in msgs:
158
            self.re_matches(msg, re.UNSUBSCRIPTABLE_RE, (groups, dict()))
159
160
    def test_unexpected_kw_arg(self):
161
        """Test UNEXPECTED_KEYWORDARG_RE."""
162
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
163
        msgs = [
164
            ("some_func() got an unexpected keyword argument 'a'",
165
                ('some_func', 'a')),
166
            ("<lambda>() got an unexpected keyword argument 'a'",
167
                ('<lambda>', 'a')),
168
        ]
169
        for msg, groups in msgs:
170
            self.re_matches(msg, re.UNEXPECTED_KEYWORDARG_RE, (groups, dict()))
171
172
    def test_unexpected_kw_arg2(self):
173
        """Test UNEXPECTED_KEYWORDARG2_RE."""
174
        # Python 2.6/2.7/3.2/3.3/3.4/3.5
175
        msg = "'this_doesnt_exist' is an invalid " \
176
            "keyword argument for this function"
177
        groups = ('this_doesnt_exist', )
178
        self.re_matches(msg, re.UNEXPECTED_KEYWORDARG2_RE, (groups, dict()))
179
180
    def test_unexpected_kw_arg3(self):
181
        """Test UNEXPECTED_KEYWORDARG3_RE."""
182
        # PyPy/PyPy3
183
        msg = "invalid keyword arguments to print()"
184
        groups = ('print', )
185
        self.re_matches(msg, re.UNEXPECTED_KEYWORDARG3_RE, (groups, dict()))
186
187
    def test_zero_length_field(self):
188
        """Test ZERO_LEN_FIELD_RE."""
189
        # Python 2.6
190
        msg = "zero length field name in format"
191
        self.re_matches(msg, re.ZERO_LEN_FIELD_RE, NO_GROUP)
192
193
    def test_math_domain_error(self):
194
        """Test MATH_DOMAIN_ERROR_RE."""
195
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
196
        msg = "math domain error"
197
        self.re_matches(msg, re.MATH_DOMAIN_ERROR_RE, NO_GROUP)
198
199
    def test_too_many_values(self):
200
        """Test TOO_MANY_VALUES_UNPACK_RE."""
201
        msgs = [
202
            # Python 2.6/2.7
203
            "too many values to unpack",
204
            # Python 3.2/3.3/3.4/3.5/PyPy3
205
            "too many values to unpack (expected 3)",
206
        ]
207
        for msg in msgs:
208
            self.re_matches(msg, re.TOO_MANY_VALUES_UNPACK_RE, NO_GROUP)
209
210
    def test_unhashable_type(self):
211
        """Test UNHASHABLE_RE."""
212
        msgs = [
213
            # Python 2.6/2.7/3.2/3.3/3.4/3.5
214
            "unhashable type: 'list'",
215
            # PyPy/PyPy3
216
            "'list' objects are unhashable",
217
        ]
218
        groups = ('list',)
219
        for msg in msgs:
220
            self.re_matches(msg, re.UNHASHABLE_RE, (groups, dict()))
221
222
    def test_outside_function(self):
223
        """Test OUTSIDE_FUNCTION_RE."""
224
        msgs = [
225
            # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
226
            "'return' outside function",
227
            # PyPy/PyPy3
228
            "return outside function",
229
        ]
230
        groups = ('return',)
231
        for msg in msgs:
232
            self.re_matches(msg, re.OUTSIDE_FUNCTION_RE, (groups, dict()))
233
234
    def test_nb_positional_argument(self):
235
        """Test NB_ARG_RE."""
236
        msgs = [
237
            # Python 2.6/2.7/PyPy/PyPy3
238
            ("some_func() takes exactly 1 argument (2 given)",
239
                '1', '2'),
240
            ("some_func() takes exactly 3 arguments (1 given)",
241
                '3', '1'),
242
            ("some_func() takes no arguments (1 given)",
243
                'no', '1'),
244
            ("some_func() takes at least 2 non-keyword arguments (0 given)",
245
                '2', '0'),
246
            # Python 3.2
247
            ("some_func() takes exactly 1 positional argument (2 given)",
248
                '1', '2'),
249
            # Python 3.3/3.4/3.5
250
            ("some_func() takes 1 positional argument but 2 were given",
251
                '1', '2'),
252
            ("some_func() takes 0 positional arguments but 1 was given",
253
                '0', '1'),
254
        ]
255
        for msg, exp, nb in msgs:
256
            groups = ('some_func', exp, nb)
257
            self.re_matches(msg, re.NB_ARG_RE, (groups, dict()))
258
259
    def test_missing_positional_arg(self):
260
        """Test MISSING_POS_ARG_RE."""
261
        msgs = [
262
            # Python 3.3/3.4/3.5
263
            "some_func() missing 2 required positional arguments: "
264
            "'much' and 'args'",
265
            "some_func() missing 1 required positional argument: "
266
            "'much'",
267
        ]
268
        groups = ('some_func',)
269
        for msg in msgs:
270
            self.re_matches(msg, re.MISSING_POS_ARG_RE, (groups, dict()))
271
272
    def test_need_more_values_to_unpack(self):
273
        """Test NEED_MORE_VALUES_RE."""
274
        msgs = [
275
            # Python 2.6/2.7/3.2/3.3/3.4/3.5(?)/PyPy3
276
            "need more than 2 values to unpack",
277
            # Python 3.5
278
            "not enough values to unpack (expected 3, got 2)",
279
        ]
280
        for msg in msgs:
281
            self.re_matches(msg, re.NEED_MORE_VALUES_RE, NO_GROUP)
282
283
    def test_missing_parentheses(self):
284
        """Test MISSING_PARENT_RE."""
285
        # Python 3.4/3.5
286
        msg = "Missing parentheses in call to 'exec'"
287
        groups = ('exec',)
288
        self.re_matches(msg, re.MISSING_PARENT_RE, (groups, dict()))
289
290
    def test_invalid_literal(self):
291
        """Test INVALID_LITERAL_RE."""
292
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
293
        msg = "invalid literal for int() with base 10: 'toto'"
294
        groups = ('int', 'toto')
295
        self.re_matches(msg, re.INVALID_LITERAL_RE, (groups, dict()))
296
297
    def test_invalid_syntax(self):
298
        """Test INVALID_SYNTAX_RE."""
299
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy3
300
        msg = "invalid syntax"
301
        self.re_matches(msg, re.INVALID_SYNTAX_RE, NO_GROUP)
302
303
    def test_invalid_comp(self):
304
        """Test INVALID_COMP_RE."""
305
        # PyPy3
306
        msg = "invalid comparison"
307
        self.re_matches(msg, re.INVALID_COMP_RE, NO_GROUP)
308
309
    def test_expected_length(self):
310
        """Test EXPECTED_LENGTH_RE."""
311
        # PyPy
312
        msg = "expected length 3, got 2"
313
        groups = ('3', '2')
314
        self.re_matches(msg, re.EXPECTED_LENGTH_RE, (groups, dict()))
315
316
    def test_future_first(self):
317
        """Test FUTURE_FIRST_RE."""
318
        msgs = [
319
            # Python 2.6/2.7/3.2/3.3/3.4/3.5
320
            "from __future__ imports must occur at the beginning of the file",
321
            # PyPy/PyPy3
322
            "__future__ statements must appear at beginning of file",
323
        ]
324
        for msg in msgs:
325
            self.re_matches(msg, re.FUTURE_FIRST_RE, NO_GROUP)
326
327
    def test_future_feature_not_def(self):
328
        """Test FUTURE_FEATURE_NOT_DEF_RE."""
329
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
330
        msg = "future feature divisio is not defined"
331
        groups = ('divisio',)
332
        self.re_matches(msg, re.FUTURE_FEATURE_NOT_DEF_RE, (groups, dict()))
333
334
    def test_result_has_too_many_items(self):
335
        """Test RESULT_TOO_MANY_ITEMS_RE."""
336
        # Python 2.6
337
        msg = "range() result has too many items"
338
        groups = ('range',)
339
        self.re_matches(msg, re.RESULT_TOO_MANY_ITEMS_RE, (groups, dict()))
340
341
    def test_unqualified_exec(self):
342
        """Test UNQUALIFIED_EXEC_RE."""
343
        msgs = [
344
            # Python 2.6
345
            "unqualified exec is not allowed in function 'func_name' "
346
            "it is a nested function",
347
            # Python 2.7
348
            "unqualified exec is not allowed in function 'func_name' "
349
            "because it is a nested function",
350
            # Python 2.6
351
            "unqualified exec is not allowed in function 'func_name' "
352
            "it contains a nested function with free variables",
353
            # Python 2.7
354
            "unqualified exec is not allowed in function 'func_name' "
355
            "because it contains a nested function with free variables",
356
        ]
357
        for msg in msgs:
358
            self.re_matches(msg, re.UNQUALIFIED_EXEC_RE, NO_GROUP)
359
360
    def test_import_star(self):
361
        """Test IMPORTSTAR_RE."""
362
        msgs = [
363
            # Python 2.6
364
            "import * is not allowed in function 'func_name' because it "
365
            "is contains a nested function with free variables",
366
            # Python 2.7
367
            "import * is not allowed in function 'func_name' because it "
368
            "contains a nested function with free variables",
369
            # Python 2.6
370
            "import * is not allowed in function 'func_name' because it "
371
            "is is a nested function",
372
            # Python 2.7
373
            "import * is not allowed in function 'func_name' because it "
374
            "is a nested function",
375
            # Python 3
376
            "import * only allowed at module level"
377
        ]
378
        for msg in msgs:
379
            self.re_matches(msg, re.IMPORTSTAR_RE, NO_GROUP)
380
381
    def test_does_not_support(self):
382
        """Test OBJ_DOES_NOT_SUPPORT_RE."""
383
        msgs = [
384
            ("'range' object does not support item assignment",
385
                ("range", "item assignment")),
386
            ("'str' object doesn't support item deletion",
387
                ("str", "item deletion")),
388
            ("'set' object does not support indexing",
389
                ("set", "indexing")),
390
        ]
391
        for msg, groups in msgs:
392
            self.re_matches(msg, re.OBJ_DOES_NOT_SUPPORT_RE, (groups, dict()))
393
394
    def test_cant_convert(self):
395
        """Test CANT_CONVERT_RE."""
396
        msg = "Can't convert 'int' object to str implicitly"
397
        groups = ('int', 'str')
398
        self.re_matches(msg, re.CANT_CONVERT_RE, (groups, dict()))
399
400
    def test_must_be_type1_not_type2(self):
401
        """Test MUST_BE_TYPE1_NOT_TYPE2_RE."""
402
        msg = "must be str, not int"
403
        groups = ('str', 'int')
404
        self.re_matches(msg, re.MUST_BE_TYPE1_NOT_TYPE2_RE, (groups, dict()))
405
406
    def test_cannot_concat(self):
407
        """Test CANNOT_CONCAT_RE."""
408
        msg = "cannot concatenate 'str' and 'int' objects"
409
        groups = ('str', 'int')
410
        self.re_matches(msg, re.CANNOT_CONCAT_RE, (groups, dict()))
411
412
    def test_unsupported_operand(self):
413
        """Test UNSUPPORTED_OP_RE."""
414
        msg = "unsupported operand type(s) for +: 'int' and 'str'"
415
        groups = ('+', 'int', 'str')
416
        self.re_matches(msg, re.UNSUPPORTED_OP_RE, (groups, dict()))
417
418
    def test_bad_operand_unary(self):
419
        """Test BAD_OPERAND_UNARY_RE."""
420
        msgs = [
421
            ("bad operand type for unary ~: 'set'", ('~', 'set')),
422
            ("bad operand type for abs(): 'set'", ('abs()', 'set')),
423
            ("unsupported operand type for unary neg: 'Foobar'",
424
                ('neg', 'Foobar')),
425
        ]
426
        for msg, group in msgs:
427
            self.re_matches(msg, re.BAD_OPERAND_UNARY_RE, (group, dict()))
428
429
    def test_not_callable(self):
430
        """Test NOT_CALLABLE_RE."""
431
        msg = "'list' object is not callable"
432
        groups = ('list',)
433
        self.re_matches(msg, re.NOT_CALLABLE_RE, (groups, dict()))
434
435
    def test_descriptor_requires(self):
436
        """Test DESCRIPT_REQUIRES_TYPE_RE."""
437
        msg = "descriptor 'add' requires a 'set' object but received a 'int'"
438
        groups = ('add', 'set', 'int')
439
        self.re_matches(
440
            msg, re.DESCRIPT_REQUIRES_TYPE_RE, (groups, dict()))
441
442
    def test_argument_not_iterable(self):
443
        """Test ARG_NOT_ITERABLE_RE."""
444
        msgs = [
445
            # Python 2.6/2.7/3.2/3.3/3.4/3.5
446
            "argument of type 'type' is not iterable",
447
            # PyPy/PyPy3
448
            "'type' object is not iterable"
449
        ]
450
        groups = ('type',)
451
        for msg in msgs:
452
            self.re_matches(msg, re.ARG_NOT_ITERABLE_RE, (groups, dict()))
453
454
    def test_must_be_called_with_instance(self):
455
        """Test MUST_BE_CALLED_WITH_INST_RE."""
456
        msg = "unbound method add() must be called with set " \
457
              "instance as first argument (got int instance instead)"
458
        groups = ('add', 'set', 'int')
459
        self.re_matches(
460
            msg, re.MUST_BE_CALLED_WITH_INST_RE, (groups, dict()))
461
462
    def test_object_has_no(self):
463
        """Test OBJECT_HAS_NO_FUNC_RE."""
464
        msgs = {
465
            # Python 2.6/2.7/3.2/3.3/3.4/3.5
466
            'len': "object of type 'generator' has no len()",
467
            # PyPy/PyPy3
468
            'length': "'generator' has no length",
469
        }
470
        for name, msg in msgs.items():
471
            groups = ('generator', name)
472
            self.re_matches(msg, re.OBJECT_HAS_NO_FUNC_RE, (groups, dict()))
473
474
    def test_nobinding_nonlocal(self):
475
        """Test NO_BINDING_NONLOCAL_RE."""
476
        msg = "no binding for nonlocal 'foo' found"
477
        groups = ('foo',)
478
        self.re_matches(msg, re.NO_BINDING_NONLOCAL_RE, (groups, dict()))
479
480
    def test_nosuchfile(self):
481
        """Test NO_SUCH_FILE_RE."""
482
        msg = "No such file or directory"
483
        self.re_matches(msg, re.NO_SUCH_FILE_RE, NO_GROUP)
484
485
    def test_timedata_does_not_match_format(self):
486
        """Test TIME_DATA_DOES_NOT_MATCH_FORMAT_RE."""
487
        msg = "time data '%d %b %y' does not match format '30 Nov 00'"
488
        # 'time data "%d \'%b %y" does not match format \'30 Nov 00\''
489
        groups = ("'%d %b %y'", "'30 Nov 00'")
490
        named_groups = {'format': "'30 Nov 00'", 'timedata': "'%d %b %y'"}
491
        self.re_matches(msg,
492
                        re.TIME_DATA_DOES_NOT_MATCH_FORMAT_RE,
493
                        (groups, named_groups))
494
495
    def test_invalid_token(self):
496
        """Test INVALID_TOKEN_RE."""
497
        msg = 'invalid token'
498
        self.re_matches(msg, re.INVALID_TOKEN_RE, NO_GROUP)
499
500
    def test_max_recursion_depth(self):
501
        """Test MAX_RECURSION_DEPTH_RE."""
502
        msg = 'maximum recursion depth exceeded'
503
        self.re_matches(msg, re.MAX_RECURSION_DEPTH_RE, NO_GROUP)
504
505
if __name__ == '__main__':
506
    print(sys.version_info)
507
    unittest2.main()
508