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