Completed
Push — master ( f44f4c...2a9ae1 )
by De
01:05
created

RegexTests.test_func_name()   A

Complexity

Conditions 4

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 8
rs 9.2
cc 4
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
from didyoumean_internal import get_subclasses
7
8
NO_GROUP = ((), dict())
9
# Various technical flags to check more that meet the eyes in tests
10
# Flag used to check that a text only match the expected regexp and not
11
# the other to ensure we do not have ambiguous/double regexp matching.
12
CHECK_OTHERS_DONT_MATCH = True
13
# Flag to check that the regexp provided does correspond to a regexp
14
# listed in re.ALL_REGEXPS
15
CHECK_RE_LISTED = True
16
# Flag to check that the name used for the regexp in re.ALL_REGEXPS
17
# does match the naming convention
18
CHECK_RE_NAME = True
19
# Flag to check that the regex does match a few conventions such as:
20
# stars with ^, ends with $.
21
CHECK_RE_VALUE = True
22
23
24
class RegexTests(unittest2.TestCase):
25
    """Tests to check that error messages match the regexps."""
26
27
    def re_matches(self, text, regexp, results):
28
        """Check that text matches regexp and gives the right match groups.
29
30
        result is a tuple containing the expected return values for groups()
31
        and groupdict().
32
        """
33
        groups, named_groups = results
34
        self.assertRegexpMatches(text, regexp)   # does pretty printing
35
        match = re.match(regexp, text)
36
        self.assertTrue(match)
37
        self.assertEqual(groups, match.groups())
38
        self.assertEqual(named_groups, match.groupdict())
39
        self.check_more_about_re(text, regexp)
40
41
    def check_more_about_re(self, text, regexp):
42
        """Check various properties about the regexp.
43
44
        Properties checked are configurable via global constants. These
45
        properties are not stricly speaking required but they help to
46
        detect potential issues much more quickly.
47
        """
48
        if CHECK_RE_VALUE:
49
            self.assertTrue(regexp.startswith('^'))
50
            self.assertTrue(regexp.endswith('$'))
51
        found = False
52
        for other_name, other_re in re.ALL_REGEXPS.items():
53
            if other_re == regexp:
54
                found = True
55
                if CHECK_RE_NAME:
56
                    self.assertTrue(other_name.endswith('_RE'))
57
            elif CHECK_OTHERS_DONT_MATCH:
58
                details = "text '%s' matches %s (on top of %s)" % \
59
                        (text, other_name, regexp)
60
                self.assertNotRegexpMatches(text, other_re, details)
61
                no_match = re.match(other_re, text)
62
                self.assertEqual(no_match, None, details)
63
        if CHECK_RE_LISTED:
64
            self.assertTrue(found)
65
66
    def test_var_name(self):
67
        """Test VAR_NAME."""
68
        regex = r"^" + re.VAR_NAME + r"$"
69
        real_names = set(locals().keys()) | set(globals().keys())
70
        names = ['a', 'a1', '_a1', 'aa_bb'] + list(real_names)
71
        for name in names:
72
            self.assertRegexpMatches(name, regex)
73
        for name in ['1a']:
74
            self.assertNotRegexpMatches(name, regex)
75
76
    def test_attr_name(self):
77
        """Test ATTR_NAME."""
78
        regex = r"^" + re.ATTR_NAME + r"$"
79
        real_attrs = set(att
80
                         for o in get_subclasses(object)
81
                         for att in dir(o))
82
        attrs = ['do_stuff', '__magic__'] + list(real_attrs)
83
        for attr in attrs:
84
            self.assertRegexpMatches(attr, regex)
85
        for attr in ['1a']:
86
            self.assertNotRegexpMatches(attr, regex)
87
88
    def test_type_name(self):
89
        """Test TYPE_NAME."""
90
        regex = r"^" + re.TYPE_NAME + r"$"
91
        real_types = set(c.__name__ for c in get_subclasses(object))
92
        types = ['str', 'int', 'method-wrapper'] + list(real_types)
93
        for type_ in types:
94
            self.assertRegexpMatches(type_, regex)
95
96
    def test_func_name(self):
97
        """Test FUNC_NAME."""
98
        regex = r"^" + re.FUNC_NAME + r"$"
99
        real_funcs = [lambda x:x, range, dir, dict.get, classmethod]  # TODO
100
        real_func_names = [f.__name__ for f in real_funcs]
101
        funcs = ['get', 'range', '<lambda>', 'print'] + list(real_func_names)
102
        for func in funcs:
103
            self.assertRegexpMatches(func, regex)
104
105
    def test_module_name(self):
106
        """Test MODULE_NAME."""
107
        regex = r"^" + re.MODULE_NAME + r"$"
108
        real_modules = set(sys.modules.keys())
109
        modules = ['sys', 'unittest.runner'] + list(real_modules)
110
        for mod in modules:
111
            self.assertRegexpMatches(mod, regex)
112
113
    def test_unbound_assignment(self):
114
        """Test VARREFBEFOREASSIGN_RE."""
115
        msgs = [
116
            # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
117
            "local variable 'some_var' referenced before assignment",
118
            "free variable 'some_var' referenced before assignment " \
119
            "in enclosing scope",
120
        ]
121
        groups = ('some_var',)
122
        named_groups = {'name': 'some_var'}
123
        results = (groups, named_groups)
124
        for msg in msgs:
125
            self.re_matches(msg, re.VARREFBEFOREASSIGN_RE, results)
126
127
    def test_name_not_defined(self):
128
        """Test NAMENOTDEFINED_RE."""
129
        msgs = [
130
            # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy3
131
            "name 'some_name' is not defined",
132
            # Python 2.6/2.7/3.2/3.3/PyPy/PyPy3
133
            "global name 'some_name' is not defined",
134
        ]
135
        groups = ('some_name',)
136
        named_groups = {'name': 'some_name'}
137
        results = (groups, named_groups)
138
        for msg in msgs:
139
            self.re_matches(msg, re.NAMENOTDEFINED_RE, results)
140
141
    def test_attribute_error(self):
142
        """Test ATTRIBUTEERROR_RE."""
143
        group_msg = {
144
            ('some.class', 'attri'): [
145
                # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
146
                "'some.class' object has no attribute 'attri'",
147
            ],
148
            ('SomeClass', 'attri'): [
149
                # Python 2.6/2.7/PyPy
150
                "SomeClass instance has no attribute 'attri'",
151
                # Python 2.6/2.7
152
                "class SomeClass has no attribute 'attri'",
153
                # Python 3.2/3.3/3.4/3.5
154
                "type object 'SomeClass' has no attribute 'attri'",
155
            ],
156
        }
157
        for groups, msgs in group_msg.items():
158
            _, attr = groups
159
            named_groups = {'attr': attr}
160
            results = (groups, named_groups)
161
            for msg in msgs:
162
                self.re_matches(msg, re.ATTRIBUTEERROR_RE, results)
163
164
    def test_module_attribute_error(self):
165
        """Test MODULEHASNOATTRIBUTE_RE."""
166
        # Python 3.5
167
        msg = "module 'some_module' has no attribute 'attri'"
168
        groups = ('some_module', 'attri')
169
        _, attr = groups
170
        named_groups = {'attr': attr}
171
        results = (groups, named_groups)
172
        self.re_matches(msg, re.MODULEHASNOATTRIBUTE_RE, results)
173
174
    def test_cannot_import(self):
175
        """Test CANNOTIMPORT_RE."""
176
        msgs = [
177
            # Python 2.6/2.7/3.2/3.3
178
            "cannot import name pie",
179
            # Python 3.4/3.5/PyPy/PyPy3
180
            "cannot import name 'pie'",
181
        ]
182
        groups = ('pie',)
183
        results = (groups, dict())
184
        for msg in msgs:
185
            self.re_matches(msg, re.CANNOTIMPORT_RE, results)
186
187
    def test_no_module_named(self):
188
        """Test NOMODULE_RE."""
189
        msgs = [
190
            # Python 2.6/2.7/3.2/PyPy/PyPy3
191
            "No module named fake_module",
192
            # Python 3.3/3.4/3.5
193
            "No module named 'fake_module'",
194
        ]
195
        groups = ('fake_module',)
196
        results = (groups, dict())
197
        for msg in msgs:
198
            self.re_matches(msg, re.NOMODULE_RE, results)
199
200
    def test_index_out_of_range(self):
201
        """Test INDEXOUTOFRANGE_RE."""
202
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
203
        msg = "list index out of range"
204
        self.re_matches(msg, re.INDEXOUTOFRANGE_RE, NO_GROUP)
205
206
    def test_unsubscriptable(self):
207
        """Test UNSUBSCRIPTABLE_RE."""
208
        msgs = [
209
            # Python 2.6
210
            "'function' object is unsubscriptable",
211
            # Python 3.2/3.3/3.4/3.5/PyPy/PyPy3
212
            "'function' object is not subscriptable",
213
        ]
214
        groups = ('function',)
215
        results = (groups, dict())
216
        for msg in msgs:
217
            self.re_matches(msg, re.UNSUBSCRIPTABLE_RE, results)
218
219
    def test_unexpected_kw_arg(self):
220
        """Test UNEXPECTED_KEYWORDARG_RE."""
221
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
222
        msgs = [
223
            ("some_func() got an unexpected keyword argument 'a'",
224
                ('some_func', 'a')),
225
            ("<lambda>() got an unexpected keyword argument 'a'",
226
                ('<lambda>', 'a')),
227
        ]
228
        for msg, groups in msgs:
229
            func, kw_arg = groups
230
            named_groups = {'arg': kw_arg, 'func': func}
231
            results = (groups, named_groups)
232
            self.re_matches(msg, re.UNEXPECTED_KEYWORDARG_RE, results)
233
234
    def test_unexpected_kw_arg2(self):
235
        """Test UNEXPECTED_KEYWORDARG2_RE."""
236
        # Python 2.6/2.7/3.2/3.3/3.4/3.5
237
        msg = "'this_doesnt_exist' is an invalid " \
238
            "keyword argument for this function"
239
        groups = ('this_doesnt_exist', )
240
        kw_arg, = groups
241
        named_groups = {'arg': kw_arg}
242
        results = (groups, named_groups)
243
        self.re_matches(msg, re.UNEXPECTED_KEYWORDARG2_RE, results)
244
245
    def test_unexpected_kw_arg3(self):
246
        """Test UNEXPECTED_KEYWORDARG3_RE."""
247
        # PyPy/PyPy3
248
        msg = "invalid keyword arguments to print()"
249
        func = 'print'
250
        groups = (func, )
251
        named_groups = {'func': func}
252
        results = (groups, named_groups)
253
        self.re_matches(msg, re.UNEXPECTED_KEYWORDARG3_RE, results)
254
255
    def test_func_takes_no_kwarg(self):
256
        """Test FUNC_TAKES_NO_KEYWORDARG_RE."""
257
        msgs = [
258
            # Cython : most versions
259
            "get() takes no keyword arguments",
260
            # Cython nightly (as of 21 January 2017) - Python 3.7
261
            "get does not take keyword arguments",
262
        ]
263
        func = 'get'
264
        groups = (func, )
265
        named_groups = {'func': func}
266
        results = (groups, named_groups)
267
        for msg in msgs:
268
            self.re_matches(msg, re.FUNC_TAKES_NO_KEYWORDARG_RE, results)
269
270
    def test_zero_length_field(self):
271
        """Test ZERO_LEN_FIELD_RE."""
272
        # Python 2.6
273
        msg = "zero length field name in format"
274
        self.re_matches(msg, re.ZERO_LEN_FIELD_RE, NO_GROUP)
275
276
    def test_math_domain_error(self):
277
        """Test MATH_DOMAIN_ERROR_RE."""
278
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
279
        msg = "math domain error"
280
        self.re_matches(msg, re.MATH_DOMAIN_ERROR_RE, NO_GROUP)
281
282
    def test_too_many_values(self):
283
        """Test TOO_MANY_VALUES_UNPACK_RE."""
284
        msgs = [
285
            # Python 2.6/2.7
286
            "too many values to unpack",
287
            # Python 3.2/3.3/3.4/3.5/PyPy3
288
            "too many values to unpack (expected 3)",
289
        ]
290
        for msg in msgs:
291
            self.re_matches(msg, re.TOO_MANY_VALUES_UNPACK_RE, NO_GROUP)
292
293
    def test_unhashable_type(self):
294
        """Test UNHASHABLE_RE."""
295
        msgs = [
296
            # Python 2.6/2.7/3.2/3.3/3.4/3.5
297
            "unhashable type: 'list'",
298
            # PyPy/PyPy3
299
            "'list' objects are unhashable",
300
        ]
301
        groups = ('list',)
302
        results = (groups, dict())
303
        for msg in msgs:
304
            self.re_matches(msg, re.UNHASHABLE_RE, results)
305
306
    def test_cannot_be_interpreted_as_integer(self):
307
        """Test CANNOT_BE_INTERPRETED_INT_RE."""
308
        msgs = {
309
            "'str' object cannot be interpreted as an integer": 'str',
310
            "'list' object cannot be interpreted as an integer": 'list',
311
        }
312
        for msg, typ in msgs.items():
313
            results = ((typ,), dict())
314
            self.re_matches(msg, re.CANNOT_BE_INTERPRETED_INT_RE, results)
315
316
    def test_int_expected_got(self):
317
        """Test INTEGER_EXPECTED_GOT_RE."""
318
        msgs = {
319
            "expected integer, got str object": 'str',
320
            "range() integer end argument expected, got list.": 'list',
321
            "range() integer start argument expected, got list.": 'list',
322
        }
323
        for msg, typ in msgs.items():
324
            results = ((typ,), dict())
325
            self.re_matches(msg, re.INTEGER_EXPECTED_GOT_RE, results)
326
327
    def test_indices_must_be_int(self):
328
        """Test INDICES_MUST_BE_INT_RE."""
329
        msgs = {
330
            # Python 2.6, 2.7, 3.2, 3.3, 3.4
331
            "list indices must be integers, not str": "str",
332
            "list indices must be integers or slices, not str": "str",
333
            # Python 3.5
334
            "tuple indices must be integers or slices, not str": "str",
335
            # PyPy
336
            "list index must be an integer, not str": "str",
337
        }
338
        for msg, typ in msgs.items():
339
            results = ((typ,), dict())
340
            self.re_matches(msg, re.INDICES_MUST_BE_INT_RE, results)
341
342
    def test_outside_function(self):
343
        """Test OUTSIDE_FUNCTION_RE."""
344
        msgs = [
345
            # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
346
            "'return' outside function",
347
            # PyPy/PyPy3
348
            "return outside function",
349
        ]
350
        groups = ('return',)
351
        results = (groups, dict())
352
        for msg in msgs:
353
            self.re_matches(msg, re.OUTSIDE_FUNCTION_RE, results)
354
355
    def test_nb_positional_argument(self):
356
        """Test NB_ARG_RE."""
357
        msgs = [
358
            # Python 2.6/2.7/PyPy/PyPy3
359
            ("some_func() takes exactly 1 argument (2 given)",
360
                '1', '2'),
361
            ("some_func() takes exactly 3 arguments (1 given)",
362
                '3', '1'),
363
            ("some_func() takes no arguments (1 given)",
364
                'no', '1'),
365
            ("some_func() takes at least 2 non-keyword arguments (0 given)",
366
                '2', '0'),
367
            # Python 3.2
368
            ("some_func() takes exactly 1 positional argument (2 given)",
369
                '1', '2'),
370
            # Python 3.3/3.4/3.5
371
            ("some_func() takes 1 positional argument but 2 were given",
372
                '1', '2'),
373
            ("some_func() takes 0 positional arguments but 1 was given",
374
                '0', '1'),
375
            # PyPy adds suggestions sometimes:
376
            ("some_func() takes no arguments (1 given)"
377
             ". Did you forget 'self' in the function definition?",
378
                'no', '1'),
379
        ]
380
        for msg, exp, nb in msgs:
381
            func = 'some_func'
382
            groups = (func, exp, nb)
383
            named_groups = {'func': func}
384
            results = (groups, named_groups)
385
            self.re_matches(msg, re.NB_ARG_RE, results)
386
387
    def test_missing_positional_arg(self):
388
        """Test MISSING_POS_ARG_RE."""
389
        msgs = [
390
            # Python 3.3/3.4/3.5
391
            "some_func() missing 2 required positional arguments: "
392
            "'much' and 'args'",
393
            "some_func() missing 1 required positional argument: "
394
            "'much'",
395
        ]
396
        func = 'some_func'
397
        groups = (func,)
398
        named_groups = {'func': func}
399
        results = (groups, named_groups)
400
        for msg in msgs:
401
            self.re_matches(msg, re.MISSING_POS_ARG_RE, results)
402
403
    def test_need_more_values_to_unpack(self):
404
        """Test NEED_MORE_VALUES_RE."""
405
        msgs = [
406
            # Python 2.6/2.7/3.2/3.3/3.4/3.5(?)/PyPy3
407
            "need more than 2 values to unpack",
408
            # Python 3.5
409
            "not enough values to unpack (expected 3, got 2)",
410
        ]
411
        for msg in msgs:
412
            self.re_matches(msg, re.NEED_MORE_VALUES_RE, NO_GROUP)
413
414
    def test_missing_parentheses(self):
415
        """Test MISSING_PARENT_RE."""
416
        # Python 3.4/3.5
417
        msg = "Missing parentheses in call to 'exec'"
418
        func = 'exec'
419
        groups = (func,)
420
        named_groups = {'func': func}
421
        results = (groups, named_groups)
422
        self.re_matches(msg, re.MISSING_PARENT_RE, results)
423
424
    def test_invalid_literal(self):
425
        """Test INVALID_LITERAL_RE."""
426
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
427
        msg = "invalid literal for int() with base 10: 'toto'"
428
        groups = ('int', 'toto')
429
        results = (groups, dict())
430
        self.re_matches(msg, re.INVALID_LITERAL_RE, results)
431
432
    def test_invalid_syntax(self):
433
        """Test INVALID_SYNTAX_RE."""
434
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy3
435
        msg = "invalid syntax"
436
        self.re_matches(msg, re.INVALID_SYNTAX_RE, NO_GROUP)
437
438
    def test_invalid_comp(self):
439
        """Test INVALID_COMP_RE."""
440
        # PyPy3
441
        msg = "invalid comparison"
442
        self.re_matches(msg, re.INVALID_COMP_RE, NO_GROUP)
443
444
    def test_expected_length(self):
445
        """Test EXPECTED_LENGTH_RE."""
446
        # PyPy
447
        msg = "expected length 3, got 2"
448
        groups = ('3', '2')
449
        results = (groups, dict())
450
        self.re_matches(msg, re.EXPECTED_LENGTH_RE, results)
451
452
    def test_future_first(self):
453
        """Test FUTURE_FIRST_RE."""
454
        msgs = [
455
            # Python 2.6/2.7/3.2/3.3/3.4/3.5
456
            "from __future__ imports must occur at the beginning of the file",
457
            # PyPy/PyPy3
458
            "__future__ statements must appear at beginning of file",
459
        ]
460
        for msg in msgs:
461
            self.re_matches(msg, re.FUTURE_FIRST_RE, NO_GROUP)
462
463
    def test_future_feature_not_def(self):
464
        """Test FUTURE_FEATURE_NOT_DEF_RE."""
465
        # Python 2.6/2.7/3.2/3.3/3.4/3.5/PyPy/PyPy3
466
        msg = "future feature divisio is not defined"
467
        groups = ('divisio',)
468
        results = (groups, dict())
469
        self.re_matches(msg, re.FUTURE_FEATURE_NOT_DEF_RE, results)
470
471
    def test_result_has_too_many_items(self):
472
        """Test RESULT_TOO_MANY_ITEMS_RE."""
473
        # Python 2.6
474
        msg = "range() result has too many items"
475
        func = 'range'
476
        groups = (func, )
477
        named_groups = {'func': func}
478
        results = (groups, named_groups)
479
        self.re_matches(msg, re.RESULT_TOO_MANY_ITEMS_RE, results)
480
481
    def test_unqualified_exec(self):
482
        """Test UNQUALIFIED_EXEC_RE."""
483
        msgs = [
484
            # Python 2.6
485
            "unqualified exec is not allowed in function 'func_name' "
486
            "it is a nested function",
487
            # Python 2.7
488
            "unqualified exec is not allowed in function 'func_name' "
489
            "because it is a nested function",
490
            # Python 2.6
491
            "unqualified exec is not allowed in function 'func_name' "
492
            "it contains a nested function with free variables",
493
            # Python 2.7
494
            "unqualified exec is not allowed in function 'func_name' "
495
            "because it contains a nested function with free variables",
496
        ]
497
        for msg in msgs:
498
            self.re_matches(msg, re.UNQUALIFIED_EXEC_RE, NO_GROUP)
499
500
    def test_import_star(self):
501
        """Test IMPORTSTAR_RE."""
502
        msgs = [
503
            # Python 2.6
504
            "import * is not allowed in function 'func_name' because it "
505
            "is contains a nested function with free variables",
506
            # Python 2.7
507
            "import * is not allowed in function 'func_name' because it "
508
            "contains a nested function with free variables",
509
            # Python 2.6
510
            "import * is not allowed in function 'func_name' because it "
511
            "is is a nested function",
512
            # Python 2.7
513
            "import * is not allowed in function 'func_name' because it "
514
            "is a nested function",
515
            # Python 3
516
            "import * only allowed at module level"
517
        ]
518
        for msg in msgs:
519
            self.re_matches(msg, re.IMPORTSTAR_RE, NO_GROUP)
520
521
    def test_does_not_support(self):
522
        """Test OBJ_DOES_NOT_SUPPORT_RE."""
523
        msgs = [
524
            ("'range' object does not support item assignment",
525
                ("range", "item assignment")),
526
            ("'str' object doesn't support item deletion",
527
                ("str", "item deletion")),
528
            ("'set' object does not support indexing",
529
                ("set", "indexing")),
530
        ]
531
        for msg, groups in msgs:
532
            results = (groups, dict())
533
            self.re_matches(msg, re.OBJ_DOES_NOT_SUPPORT_RE, results)
534
535
    def test_cant_convert(self):
536
        """Test CANT_CONVERT_RE."""
537
        msg = "Can't convert 'int' object to str implicitly"
538
        groups = ('int', 'str')
539
        results = (groups, dict())
540
        self.re_matches(msg, re.CANT_CONVERT_RE, results)
541
542
    def test_must_be_type1_not_type2(self):
543
        """Test MUST_BE_TYPE1_NOT_TYPE2_RE."""
544
        msg = "must be str, not int"
545
        groups = ('str', 'int')
546
        results = (groups, dict())
547
        self.re_matches(msg, re.MUST_BE_TYPE1_NOT_TYPE2_RE, results)
548
549
    def test_cannot_concat(self):
550
        """Test CANNOT_CONCAT_RE."""
551
        msg = "cannot concatenate 'str' and 'int' objects"
552
        groups = ('str', 'int')
553
        results = (groups, dict())
554
        self.re_matches(msg, re.CANNOT_CONCAT_RE, results)
555
556
    def test_only_concat(self):
557
        """Test ONLY_CONCAT_RE."""
558
        msg = 'can only concatenate list (not "set") to list'
559
        self.re_matches(msg, re.ONLY_CONCAT_RE, NO_GROUP)
560
561
    def test_unsupported_operand(self):
562
        """Test UNSUPPORTED_OP_RE."""
563
        msg = "unsupported operand type(s) for +: 'int' and 'str'"
564
        groups = ('+', 'int', 'str')
565
        results = (groups, dict())
566
        self.re_matches(msg, re.UNSUPPORTED_OP_RE, results)
567
568
    def test_bad_operand_unary(self):
569
        """Test BAD_OPERAND_UNARY_RE."""
570
        msgs = [
571
            ("bad operand type for unary ~: 'set'", ('~', 'set')),
572
            ("bad operand type for abs(): 'set'", ('abs()', 'set')),
573
            ("unsupported operand type for unary neg: 'Foobar'",
574
                ('neg', 'Foobar')),
575
        ]
576
        for msg, groups in msgs:
577
            results = (groups, dict())
578
            self.re_matches(msg, re.BAD_OPERAND_UNARY_RE, results)
579
580
    def test_not_callable(self):
581
        """Test NOT_CALLABLE_RE."""
582
        msg = "'list' object is not callable"
583
        groups = ('list',)
584
        results = (groups, dict())
585
        self.re_matches(msg, re.NOT_CALLABLE_RE, results)
586
587
    def test_descriptor_requires(self):
588
        """Test DESCRIPT_REQUIRES_TYPE_RE."""
589
        msg = "descriptor 'add' requires a 'set' object but received a 'int'"
590
        groups = ('add', 'set', 'int')
591
        results = (groups, dict())
592
        self.re_matches(msg, re.DESCRIPT_REQUIRES_TYPE_RE, results)
593
594
    def test_argument_not_iterable(self):
595
        """Test ARG_NOT_ITERABLE_RE."""
596
        msgs = [
597
            # Python 2.6/2.7/3.2/3.3/3.4/3.5
598
            "argument of type 'type' is not iterable",
599
            # PyPy/PyPy3
600
            "'type' object is not iterable"
601
        ]
602
        groups = ('type',)
603
        results = (groups, dict())
604
        for msg in msgs:
605
            self.re_matches(msg, re.ARG_NOT_ITERABLE_RE, results)
606
607
    def test_must_be_called_with_instance(self):
608
        """Test MUST_BE_CALLED_WITH_INST_RE."""
609
        msg = "unbound method add() must be called with set " \
610
              "instance as first argument (got int instance instead)"
611
        groups = ('add', 'set', 'int')
612
        results = (groups, dict())
613
        self.re_matches(msg, re.MUST_BE_CALLED_WITH_INST_RE, results)
614
615
    def test_object_has_no(self):
616
        """Test OBJECT_HAS_NO_FUNC_RE."""
617
        msgs = {
618
            # Python 2.6/2.7/3.2/3.3/3.4/3.5
619
            'len': "object of type 'generator' has no len()",
620
            # PyPy/PyPy3
621
            'length': "'generator' has no length",
622
        }
623
        for name, msg in msgs.items():
624
            groups = ('generator', name)
625
            results = (groups, dict())
626
            self.re_matches(msg, re.OBJECT_HAS_NO_FUNC_RE, results)
627
628
    def test_instance_has_no_meth(self):
629
        """Test INSTANCE_HAS_NO_METH_RE."""
630
        # Python 2.6/2.7
631
        msg = "CustomClass instance has no __call__ method"
632
        class_, method = 'CustomClass', '__call__'
633
        groups = (class_, method)
634
        results = (groups, dict())
635
        self.re_matches(msg, re.INSTANCE_HAS_NO_METH_RE, results)
636
637
    def test_nobinding_nonlocal(self):
638
        """Test NO_BINDING_NONLOCAL_RE."""
639
        msg = "no binding for nonlocal 'foo' found"
640
        groups = ('foo',)
641
        results = (groups, dict())
642
        self.re_matches(msg, re.NO_BINDING_NONLOCAL_RE, results)
643
644
    def test_nonlocal_at_module_level(self):
645
        """Test NONLOCAL_AT_MODULE_RE."""
646
        msg = "nonlocal declaration not allowed at module level"
647
        self.re_matches(msg, re.NONLOCAL_AT_MODULE_RE, NO_GROUP)
648
649
    def test_unexpected_eof(self):
650
        """Test UNEXPECTED_EOF_RE."""
651
        msg = "unexpected EOF while parsing"
652
        self.re_matches(msg, re.UNEXPECTED_EOF_RE, NO_GROUP)
653
654
    def test_nosuchfile(self):
655
        """Test NO_SUCH_FILE_RE."""
656
        msg = "No such file or directory"
657
        self.re_matches(msg, re.NO_SUCH_FILE_RE, NO_GROUP)
658
659
    def test_timedata_does_not_match_format(self):
660
        """Test TIME_DATA_DOES_NOT_MATCH_FORMAT_RE."""
661
        msg = "time data '%d %b %y' does not match format '30 Nov 00'"
662
        # 'time data "%d \'%b %y" does not match format \'30 Nov 00\''
663
        groups = ("'%d %b %y'", "'30 Nov 00'")
664
        named_groups = {'format': "'30 Nov 00'", 'timedata': "'%d %b %y'"}
665
        results = (groups, named_groups)
666
        self.re_matches(msg, re.TIME_DATA_DOES_NOT_MATCH_FORMAT_RE, results)
667
668
    def test_invalid_token(self):
669
        """Test INVALID_TOKEN_RE."""
670
        msg = 'invalid token'
671
        self.re_matches(msg, re.INVALID_TOKEN_RE, NO_GROUP)
672
673
    def test_exc_must_derive_from(self):
674
        """Test EXC_MUST_DERIVE_FROM_RE."""
675
        msgs = [
676
            # Python 2.7
677
            "exceptions must be old-style classes or derived from "
678
            "BaseException, not NoneType",
679
            # Python 3.3 / 3.4
680
            "exceptions must derive from BaseException",
681
        ]
682
        for msg in msgs:
683
            self.re_matches(msg, re.EXC_MUST_DERIVE_FROM_RE, NO_GROUP)
684
685
    def test_unorderable_types(self):
686
        """Test UNORDERABLE_TYPES_RE."""
687
        msgs = [
688
            # Python 3.2 to 3.5
689
            "unorderable types: str() > int()",
690
            "unorderable types: FoobarClass() <= int()",
691
            # PyPy
692
            "unorderable types: FoobarClass > FoobarClass",
693
        ]
694
        for msg in msgs:
695
            self.re_matches(msg, re.UNORDERABLE_TYPES_RE, NO_GROUP)
696
697
    def test_op_not_supported_between_instances(self):
698
        """Test OP_NOT_SUPP_BETWEEN_INSTANCES_RE."""
699
        msgs = [
700
            # Python 3.6
701
            "'<' not supported between instances of 'int' and 'NoneType'",
702
            "'>' not supported between instances of 'Foo' and 'Foo'",
703
        ]
704
        for msg in msgs:
705
            self.re_matches(msg, re.OP_NOT_SUPP_BETWEEN_INSTANCES_RE, NO_GROUP)
706
707
    def test_max_recursion_depth(self):
708
        """Test MAX_RECURSION_DEPTH_RE."""
709
        msg = 'maximum recursion depth exceeded'
710
        self.re_matches(msg, re.MAX_RECURSION_DEPTH_RE, NO_GROUP)
711
712
    def test_size_changed_during_iter(self):
713
        """Test SIZE_CHANGED_DURING_ITER_RE."""
714
        msgs = {
715
            "Set": "Set changed size during iteration",
716
            "dictionnary": "dictionnary changed size during iteration",
717
        }
718
        for name, msg in msgs.items():
719
            groups = (name, )
720
            results = (groups, dict())
721
            self.re_matches(msg, re.SIZE_CHANGED_DURING_ITER_RE, results)
722
723
if __name__ == '__main__':
724
    print(sys.version_info)
725
    unittest2.main()
726