Completed
Push — master ( 154999...b1f2dd )
by De
52s
created

RegexTests.test_future_first()   A

Complexity

Conditions 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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