1"""Tests for the asdl parser in Parser/asdl.py""" 2 3import importlib.machinery 4import os 5from os.path import dirname 6import sys 7import sysconfig 8import unittest 9 10 11# This test is only relevant for from-source builds of Python. 12if not sysconfig.is_python_build(): 13 raise unittest.SkipTest('test irrelevant for an installed Python') 14 15src_base = dirname(dirname(dirname(__file__))) 16parser_dir = os.path.join(src_base, 'Parser') 17 18 19class TestAsdlParser(unittest.TestCase): 20 @classmethod 21 def setUpClass(cls): 22 # Loads the asdl module dynamically, since it's not in a real importable 23 # package. 24 # Parses Python.asdl into an ast.Module and run the check on it. 25 # There's no need to do this for each test method, hence setUpClass. 26 sys.path.insert(0, parser_dir) 27 loader = importlib.machinery.SourceFileLoader( 28 'asdl', os.path.join(parser_dir, 'asdl.py')) 29 cls.asdl = loader.load_module() 30 cls.mod = cls.asdl.parse(os.path.join(parser_dir, 'Python.asdl')) 31 cls.assertTrue(cls.asdl.check(cls.mod), 'Module validation failed') 32 33 @classmethod 34 def tearDownClass(cls): 35 del sys.path[0] 36 37 def setUp(self): 38 # alias stuff from the class, for convenience 39 self.asdl = TestAsdlParser.asdl 40 self.mod = TestAsdlParser.mod 41 self.types = self.mod.types 42 43 def test_module(self): 44 self.assertEqual(self.mod.name, 'Python') 45 self.assertIn('stmt', self.types) 46 self.assertIn('expr', self.types) 47 self.assertIn('mod', self.types) 48 49 def test_definitions(self): 50 defs = self.mod.dfns 51 self.assertIsInstance(defs[0], self.asdl.Type) 52 self.assertIsInstance(defs[0].value, self.asdl.Sum) 53 54 self.assertIsInstance(self.types['withitem'], self.asdl.Product) 55 self.assertIsInstance(self.types['alias'], self.asdl.Product) 56 57 def test_product(self): 58 alias = self.types['alias'] 59 self.assertEqual( 60 str(alias), 61 'Product([Field(identifier, name), Field(identifier, asname, opt=True)])') 62 63 def test_attributes(self): 64 stmt = self.types['stmt'] 65 self.assertEqual(len(stmt.attributes), 2) 66 self.assertEqual(str(stmt.attributes[0]), 'Field(int, lineno)') 67 self.assertEqual(str(stmt.attributes[1]), 'Field(int, col_offset)') 68 69 def test_constructor_fields(self): 70 ehandler = self.types['excepthandler'] 71 self.assertEqual(len(ehandler.types), 1) 72 self.assertEqual(len(ehandler.attributes), 2) 73 74 cons = ehandler.types[0] 75 self.assertIsInstance(cons, self.asdl.Constructor) 76 self.assertEqual(len(cons.fields), 3) 77 78 f0 = cons.fields[0] 79 self.assertEqual(f0.type, 'expr') 80 self.assertEqual(f0.name, 'type') 81 self.assertTrue(f0.opt) 82 83 f1 = cons.fields[1] 84 self.assertEqual(f1.type, 'identifier') 85 self.assertEqual(f1.name, 'name') 86 self.assertTrue(f1.opt) 87 88 f2 = cons.fields[2] 89 self.assertEqual(f2.type, 'stmt') 90 self.assertEqual(f2.name, 'body') 91 self.assertFalse(f2.opt) 92 self.assertTrue(f2.seq) 93 94 def test_visitor(self): 95 class CustomVisitor(self.asdl.VisitorBase): 96 def __init__(self): 97 super().__init__() 98 self.names_with_seq = [] 99 100 def visitModule(self, mod): 101 for dfn in mod.dfns: 102 self.visit(dfn) 103 104 def visitType(self, type): 105 self.visit(type.value) 106 107 def visitSum(self, sum): 108 for t in sum.types: 109 self.visit(t) 110 111 def visitConstructor(self, cons): 112 for f in cons.fields: 113 if f.seq: 114 self.names_with_seq.append(cons.name) 115 116 v = CustomVisitor() 117 v.visit(self.types['mod']) 118 self.assertEqual(v.names_with_seq, ['Module', 'Interactive', 'Suite']) 119 120 121if __name__ == '__main__': 122 unittest.main() 123