]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | """Test suite for 2to3's parser and grammar files.\r |
2 | \r | |
3 | This is the place to add tests for changes to 2to3's grammar, such as those\r | |
4 | merging the grammars for Python 2 and 3. In addition to specific tests for\r | |
5 | parts of the grammar we've changed, we also make sure we can parse the\r | |
6 | test_grammar.py files from both Python 2 and Python 3.\r | |
7 | """\r | |
8 | \r | |
9 | from __future__ import with_statement\r | |
10 | \r | |
11 | # Testing imports\r | |
12 | from . import support\r | |
13 | from .support import driver, test_dir\r | |
14 | \r | |
15 | # Python imports\r | |
16 | import os\r | |
17 | import sys\r | |
18 | \r | |
19 | # Local imports\r | |
20 | from lib2to3.pgen2 import tokenize\r | |
21 | from ..pgen2.parse import ParseError\r | |
22 | from lib2to3.pygram import python_symbols as syms\r | |
23 | \r | |
24 | \r | |
25 | class TestDriver(support.TestCase):\r | |
26 | \r | |
27 | def test_formfeed(self):\r | |
28 | s = """print 1\n\x0Cprint 2\n"""\r | |
29 | t = driver.parse_string(s)\r | |
30 | self.assertEqual(t.children[0].children[0].type, syms.print_stmt)\r | |
31 | self.assertEqual(t.children[1].children[0].type, syms.print_stmt)\r | |
32 | \r | |
33 | \r | |
34 | class GrammarTest(support.TestCase):\r | |
35 | def validate(self, code):\r | |
36 | support.parse_string(code)\r | |
37 | \r | |
38 | def invalid_syntax(self, code):\r | |
39 | try:\r | |
40 | self.validate(code)\r | |
41 | except ParseError:\r | |
42 | pass\r | |
43 | else:\r | |
44 | raise AssertionError("Syntax shouldn't have been valid")\r | |
45 | \r | |
46 | \r | |
47 | class TestRaiseChanges(GrammarTest):\r | |
48 | def test_2x_style_1(self):\r | |
49 | self.validate("raise")\r | |
50 | \r | |
51 | def test_2x_style_2(self):\r | |
52 | self.validate("raise E, V")\r | |
53 | \r | |
54 | def test_2x_style_3(self):\r | |
55 | self.validate("raise E, V, T")\r | |
56 | \r | |
57 | def test_2x_style_invalid_1(self):\r | |
58 | self.invalid_syntax("raise E, V, T, Z")\r | |
59 | \r | |
60 | def test_3x_style(self):\r | |
61 | self.validate("raise E1 from E2")\r | |
62 | \r | |
63 | def test_3x_style_invalid_1(self):\r | |
64 | self.invalid_syntax("raise E, V from E1")\r | |
65 | \r | |
66 | def test_3x_style_invalid_2(self):\r | |
67 | self.invalid_syntax("raise E from E1, E2")\r | |
68 | \r | |
69 | def test_3x_style_invalid_3(self):\r | |
70 | self.invalid_syntax("raise from E1, E2")\r | |
71 | \r | |
72 | def test_3x_style_invalid_4(self):\r | |
73 | self.invalid_syntax("raise E from")\r | |
74 | \r | |
75 | \r | |
76 | # Adapated from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef\r | |
77 | class TestFunctionAnnotations(GrammarTest):\r | |
78 | def test_1(self):\r | |
79 | self.validate("""def f(x) -> list: pass""")\r | |
80 | \r | |
81 | def test_2(self):\r | |
82 | self.validate("""def f(x:int): pass""")\r | |
83 | \r | |
84 | def test_3(self):\r | |
85 | self.validate("""def f(*x:str): pass""")\r | |
86 | \r | |
87 | def test_4(self):\r | |
88 | self.validate("""def f(**x:float): pass""")\r | |
89 | \r | |
90 | def test_5(self):\r | |
91 | self.validate("""def f(x, y:1+2): pass""")\r | |
92 | \r | |
93 | def test_6(self):\r | |
94 | self.validate("""def f(a, (b:1, c:2, d)): pass""")\r | |
95 | \r | |
96 | def test_7(self):\r | |
97 | self.validate("""def f(a, (b:1, c:2, d), e:3=4, f=5, *g:6): pass""")\r | |
98 | \r | |
99 | def test_8(self):\r | |
100 | s = """def f(a, (b:1, c:2, d), e:3=4, f=5,\r | |
101 | *g:6, h:7, i=8, j:9=10, **k:11) -> 12: pass"""\r | |
102 | self.validate(s)\r | |
103 | \r | |
104 | \r | |
105 | class TestExcept(GrammarTest):\r | |
106 | def test_new(self):\r | |
107 | s = """\r | |
108 | try:\r | |
109 | x\r | |
110 | except E as N:\r | |
111 | y"""\r | |
112 | self.validate(s)\r | |
113 | \r | |
114 | def test_old(self):\r | |
115 | s = """\r | |
116 | try:\r | |
117 | x\r | |
118 | except E, N:\r | |
119 | y"""\r | |
120 | self.validate(s)\r | |
121 | \r | |
122 | \r | |
123 | # Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.testAtoms\r | |
124 | class TestSetLiteral(GrammarTest):\r | |
125 | def test_1(self):\r | |
126 | self.validate("""x = {'one'}""")\r | |
127 | \r | |
128 | def test_2(self):\r | |
129 | self.validate("""x = {'one', 1,}""")\r | |
130 | \r | |
131 | def test_3(self):\r | |
132 | self.validate("""x = {'one', 'two', 'three'}""")\r | |
133 | \r | |
134 | def test_4(self):\r | |
135 | self.validate("""x = {2, 3, 4,}""")\r | |
136 | \r | |
137 | \r | |
138 | class TestNumericLiterals(GrammarTest):\r | |
139 | def test_new_octal_notation(self):\r | |
140 | self.validate("""0o7777777777777""")\r | |
141 | self.invalid_syntax("""0o7324528887""")\r | |
142 | \r | |
143 | def test_new_binary_notation(self):\r | |
144 | self.validate("""0b101010""")\r | |
145 | self.invalid_syntax("""0b0101021""")\r | |
146 | \r | |
147 | \r | |
148 | class TestClassDef(GrammarTest):\r | |
149 | def test_new_syntax(self):\r | |
150 | self.validate("class B(t=7): pass")\r | |
151 | self.validate("class B(t, *args): pass")\r | |
152 | self.validate("class B(t, **kwargs): pass")\r | |
153 | self.validate("class B(t, *args, **kwargs): pass")\r | |
154 | self.validate("class B(t, y=9, *args, **kwargs): pass")\r | |
155 | \r | |
156 | \r | |
157 | class TestParserIdempotency(support.TestCase):\r | |
158 | \r | |
159 | """A cut-down version of pytree_idempotency.py."""\r | |
160 | \r | |
161 | def test_all_project_files(self):\r | |
162 | if sys.platform.startswith("win"):\r | |
163 | # XXX something with newlines goes wrong on Windows.\r | |
164 | return\r | |
165 | for filepath in support.all_project_files():\r | |
166 | with open(filepath, "rb") as fp:\r | |
167 | encoding = tokenize.detect_encoding(fp.readline)[0]\r | |
168 | self.assertTrue(encoding is not None,\r | |
169 | "can't detect encoding for %s" % filepath)\r | |
170 | with open(filepath, "r") as fp:\r | |
171 | source = fp.read()\r | |
172 | source = source.decode(encoding)\r | |
173 | tree = driver.parse_string(source)\r | |
174 | new = unicode(tree)\r | |
175 | if diff(filepath, new, encoding):\r | |
176 | self.fail("Idempotency failed: %s" % filepath)\r | |
177 | \r | |
178 | def test_extended_unpacking(self):\r | |
179 | driver.parse_string("a, *b, c = x\n")\r | |
180 | driver.parse_string("[*a, b] = x\n")\r | |
181 | driver.parse_string("(z, *y, w) = m\n")\r | |
182 | driver.parse_string("for *z, m in d: pass\n")\r | |
183 | \r | |
184 | class TestLiterals(GrammarTest):\r | |
185 | \r | |
186 | def validate(self, s):\r | |
187 | driver.parse_string(support.dedent(s) + "\n\n")\r | |
188 | \r | |
189 | def test_multiline_bytes_literals(self):\r | |
190 | s = """\r | |
191 | md5test(b"\xaa" * 80,\r | |
192 | (b"Test Using Larger Than Block-Size Key "\r | |
193 | b"and Larger Than One Block-Size Data"),\r | |
194 | "6f630fad67cda0ee1fb1f562db3aa53e")\r | |
195 | """\r | |
196 | self.validate(s)\r | |
197 | \r | |
198 | def test_multiline_bytes_tripquote_literals(self):\r | |
199 | s = '''\r | |
200 | b"""\r | |
201 | <?xml version="1.0" encoding="UTF-8"?>\r | |
202 | <!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN">\r | |
203 | """\r | |
204 | '''\r | |
205 | self.validate(s)\r | |
206 | \r | |
207 | def test_multiline_str_literals(self):\r | |
208 | s = """\r | |
209 | md5test("\xaa" * 80,\r | |
210 | ("Test Using Larger Than Block-Size Key "\r | |
211 | "and Larger Than One Block-Size Data"),\r | |
212 | "6f630fad67cda0ee1fb1f562db3aa53e")\r | |
213 | """\r | |
214 | self.validate(s)\r | |
215 | \r | |
216 | \r | |
217 | def diff(fn, result, encoding):\r | |
218 | f = open("@", "w")\r | |
219 | try:\r | |
220 | f.write(result.encode(encoding))\r | |
221 | finally:\r | |
222 | f.close()\r | |
223 | try:\r | |
224 | fn = fn.replace('"', '\\"')\r | |
225 | return os.system('diff -u "%s" @' % fn)\r | |
226 | finally:\r | |
227 | os.remove("@")\r |