diff options
Diffstat (limited to 'tests/run/test_patma.py')
-rw-r--r-- | tests/run/test_patma.py | 159 |
1 files changed, 99 insertions, 60 deletions
diff --git a/tests/run/test_patma.py b/tests/run/test_patma.py index 0baee3fff..d84e5d976 100644 --- a/tests/run/test_patma.py +++ b/tests/run/test_patma.py @@ -1,43 +1,21 @@ -### COPIED FROM CPython 3.9 +### COPIED FROM CPython 3.12 alpha (July 2022) ### Original part after ############ # cython: language_level=3 # new code import cython -from Cython.Compiler.Main import compile as cython_compile, CompileError -from Cython.Build.Inline import cython_inline -import contextlib -from tempfile import NamedTemporaryFile - -@contextlib.contextmanager -def hidden_stderr(): - try: - from StringIO import StringIO - except ImportError: - from io import StringIO - - old_stderr = sys.stderr - try: - sys.stderr = StringIO() - yield - finally: - sys.stderr = old_stderr - -def _compile(code): - with NamedTemporaryFile(suffix='.py') as f: - f.write(code.encode('utf8')) - f.flush() - - with hidden_stderr(): - result = cython_compile(f.name, language_level=3) - return result +from Cython.TestUtils import py_parse_code + if cython.compiled: def compile(code, name, what): assert what == 'exec' - result = _compile(code) - if not result.c_file: - raise SyntaxError('unexpected EOF') # compile is only used for testing errors + py_parse_code(code) + + +def disable(func): + pass + ############## SLIGHTLY MODIFIED ORIGINAL CODE import array @@ -68,9 +46,47 @@ else: return self.x == other.x and self.y == other.y # TestCompiler removed - it's very CPython-specific -# TestTracing also removed - doesn't seem like a core test +# TestTracing also mainly removed - doesn't seem like a core test +# except for one test that seems misplaced in CPython (which is below) + +class TestTracing(unittest.TestCase): + if sys.version_info < (3, 4): + class SubTestClass(object): + def __enter__(self): + return self + def __exit__(self, exc_type, exc_value, traceback): + return + def __call__(self, *args): + return self + subTest = SubTestClass() + + def test_parser_deeply_nested_patterns(self): + # Deeply nested patterns can cause exponential backtracking when parsing. + # See CPython gh-93671 for more information. + # + # DW: Cython note - this doesn't break the parser but may cause a + # RecursionError later in the code-generation. I don't believe that's + # easily avoidable with the way Cython visitors currently work + + levels = 100 + + patterns = [ + "A" + "(" * levels + ")" * levels, + "{1:" * levels + "1" + "}" * levels, + "[" * levels + "1" + "]" * levels, + ] -# FIXME - return all the "return"s added to cause code to be dropped + for pattern in patterns: + with self.subTest(pattern): + code = inspect.cleandoc(""" + match None: + case {}: + pass + """.format(pattern)) + compile(code, "<string>", "exec") + + +# FIXME - remove all the "return"s added to cause code to be dropped ############## ORIGINAL PART FROM CPYTHON @@ -372,7 +388,7 @@ class TestPatma(unittest.TestCase): self.assertIs(y, None) def test_patma_025(self): - return + return # disabled x = {0: 0} match x: case {0: (0 | 1 | 2 as z)}: @@ -382,7 +398,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, 0) def test_patma_026(self): - return + return # disabled x = {0: 1} match x: case {0: (0 | 1 | 2 as z)}: @@ -392,7 +408,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, 1) def test_patma_027(self): - return + return # disabled x = {0: 2} match x: case {0: (0 | 1 | 2 as z)}: @@ -402,7 +418,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, 2) def test_patma_028(self): - return + return # disabled x = {0: 3} y = None match x: @@ -473,7 +489,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 2) def test_patma_034(self): - return + return # disabled x = {0: 0} match x: case {0: [1, 2, {}]}: @@ -486,7 +502,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 1) def test_patma_035(self): - return + return # disabled x = {0: 0} match x: case {0: [1, 2, {}]}: @@ -532,7 +548,7 @@ class TestPatma(unittest.TestCase): self.assertIs(y, None) def test_patma_040(self): - return + return # disabled x = 0 match x: case (0 as z) | (1 as z) | (2 as z) if z == x % 2: @@ -542,7 +558,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, 0) def test_patma_041(self): - return + return # disabled x = 1 match x: case (0 as z) | (1 as z) | (2 as z) if z == x % 2: @@ -552,7 +568,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, 1) def test_patma_042(self): - return + return # disabled x = 2 y = None match x: @@ -563,7 +579,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, 2) def test_patma_043(self): - return + return # disabled x = 3 y = None match x: @@ -605,7 +621,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 0) def test_patma_048(self): - return + return # disabled x = [0, 1] match x: case [0, 1] | [1, 0]: @@ -614,7 +630,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 0) def test_patma_049(self): - return + return # disabled x = [1, 0] match x: case [0, 1] | [1, 0]: @@ -623,7 +639,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 0) def test_patma_050(self): - return + return # disabled x = [0, 0] y = None match x: @@ -633,7 +649,7 @@ class TestPatma(unittest.TestCase): self.assertIs(y, None) def test_patma_051(self): - return + return # disabled w = None x = [1, 0] match x: @@ -1005,7 +1021,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, 0) def test_patma_087(self): - return + return # disabled x = 0 match x: case (0 | 1) | 2: @@ -1014,7 +1030,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 0) def test_patma_088(self): - return + return # disabled x = 1 match x: case (0 | 1) | 2: @@ -1023,7 +1039,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 0) def test_patma_089(self): - return + return # disabled x = 2 match x: case (0 | 1) | 2: @@ -1032,7 +1048,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 0) def test_patma_090(self): - return + return # disabled x = 3 y = None match x: @@ -1042,7 +1058,7 @@ class TestPatma(unittest.TestCase): self.assertIs(y, None) def test_patma_091(self): - return + return # disabled x = 0 match x: case 0 | (1 | 2): @@ -1051,7 +1067,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 0) def test_patma_092(self): - return + return # disabled x = 1 match x: case 0 | (1 | 2): @@ -1060,7 +1076,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 0) def test_patma_093(self): - return + return # disabled x = 2 match x: case 0 | (1 | 2): @@ -1069,7 +1085,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 0) def test_patma_094(self): - return + return # disabled x = 3 y = None match x: @@ -2282,7 +2298,7 @@ class TestPatma(unittest.TestCase): self.assertIs(f("1"), None) def test_patma_207(self): - return + return # disabled def f(w): match w: case [1, 2] | [3, 4]: @@ -2623,7 +2639,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, {0: 1}) def test_patma_241(self): - return + return # disabled x = [[{0: 0}]] match x: case list([({-0-0j: int(real=0+0j, imag=0-0j) | (1) as z},)]): @@ -2661,7 +2677,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, 0) def test_patma_245(self): - return + return # disabled x = {"y": 1} match x: case {"y": (0 as y) | (1 as y)}: @@ -2671,7 +2687,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(z, 0) def test_patma_246(self): - return + return # disabled def f(x): match x: case ((a, b, c, d, e, f, g, h, i, 9) | @@ -2696,7 +2712,7 @@ class TestPatma(unittest.TestCase): self.assertEqual(f(range(10, 20)), alts[4]) def test_patma_247(self): - return + return # disabled def f(x): match x: case [y, (a, b, c, d, e, f, g, h, i, 9) | @@ -2733,6 +2749,21 @@ class TestPatma(unittest.TestCase): self.assertEqual(y, 'bar') + def test_patma_249(self): + return # disabled + class C: + __attr = "eggs" # mangled to _C__attr + _Outer__attr = "bacon" + class Outer: + def f(self, x): + match x: + # looks up __attr, not _C__attr or _Outer__attr + case C(__attr=y): + return y + c = C() + setattr(c, "__attr", "spam") # setattr is needed because we're in a class scope + self.assertEqual(Outer().f(c), "spam") + class TestSyntaxErrors(unittest.TestCase): @@ -2755,6 +2786,7 @@ class TestSyntaxErrors(unittest.TestCase): """) + @disable # validation will be added when class patterns are added def test_attribute_name_repeated_in_class_pattern(self): self.assert_syntax_error(""" match ...: @@ -2853,6 +2885,7 @@ class TestSyntaxErrors(unittest.TestCase): pass """) + @disable # will be implemented as part of sequence patterns def test_multiple_starred_names_in_sequence_pattern_0(self): self.assert_syntax_error(""" match ...: @@ -2860,6 +2893,7 @@ class TestSyntaxErrors(unittest.TestCase): pass """) + @disable # will be implemented as part of sequence patterns def test_multiple_starred_names_in_sequence_pattern_1(self): self.assert_syntax_error(""" match ...: @@ -2994,6 +3028,7 @@ class TestSyntaxErrors(unittest.TestCase): pass """) + @disable # validation will be added when class patterns are added def test_mapping_pattern_duplicate_key(self): self.assert_syntax_error(""" match ...: @@ -3001,6 +3036,7 @@ class TestSyntaxErrors(unittest.TestCase): pass """) + @disable # validation will be added when class patterns are added def test_mapping_pattern_duplicate_key_edge_case0(self): self.assert_syntax_error(""" match ...: @@ -3008,6 +3044,7 @@ class TestSyntaxErrors(unittest.TestCase): pass """) + @disable # validation will be added when class patterns are added def test_mapping_pattern_duplicate_key_edge_case1(self): self.assert_syntax_error(""" match ...: @@ -3015,6 +3052,7 @@ class TestSyntaxErrors(unittest.TestCase): pass """) + @disable # validation will be added when class patterns are added def test_mapping_pattern_duplicate_key_edge_case2(self): self.assert_syntax_error(""" match ...: @@ -3022,6 +3060,7 @@ class TestSyntaxErrors(unittest.TestCase): pass """) + @disable # validation will be added when class patterns are added def test_mapping_pattern_duplicate_key_edge_case3(self): self.assert_syntax_error(""" match ...: |