test_asdl_parser.py 3.92 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
"""Tests for the asdl parser in Parser/asdl.py"""

import importlib.machinery
import os
from os.path import dirname
import sys
import sysconfig
import unittest


# This test is only relevant for from-source builds of Python.
if not sysconfig.is_python_build():
    raise unittest.SkipTest('test irrelevant for an installed Python')

src_base = dirname(dirname(dirname(__file__)))
parser_dir = os.path.join(src_base, 'Parser')


class TestAsdlParser(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        # Loads the asdl module dynamically, since it's not in a real importable
        # package.
24
        # Parses Python.asdl into an ast.Module and run the check on it.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
        # There's no need to do this for each test method, hence setUpClass.
        sys.path.insert(0, parser_dir)
        loader = importlib.machinery.SourceFileLoader(
                'asdl', os.path.join(parser_dir, 'asdl.py'))
        cls.asdl = loader.load_module()
        cls.mod = cls.asdl.parse(os.path.join(parser_dir, 'Python.asdl'))
        cls.assertTrue(cls.asdl.check(cls.mod), 'Module validation failed')

    @classmethod
    def tearDownClass(cls):
        del sys.path[0]

    def setUp(self):
        # alias stuff from the class, for convenience
        self.asdl = TestAsdlParser.asdl
        self.mod = TestAsdlParser.mod
        self.types = self.mod.types

    def test_module(self):
        self.assertEqual(self.mod.name, 'Python')
        self.assertIn('stmt', self.types)
        self.assertIn('expr', self.types)
        self.assertIn('mod', self.types)

    def test_definitions(self):
        defs = self.mod.dfns
        self.assertIsInstance(defs[0], self.asdl.Type)
        self.assertIsInstance(defs[0].value, self.asdl.Sum)

        self.assertIsInstance(self.types['withitem'], self.asdl.Product)
        self.assertIsInstance(self.types['alias'], self.asdl.Product)

    def test_product(self):
        alias = self.types['alias']
        self.assertEqual(
            str(alias),
            'Product([Field(identifier, name), Field(identifier, asname, opt=True)])')

    def test_attributes(self):
        stmt = self.types['stmt']
        self.assertEqual(len(stmt.attributes), 2)
        self.assertEqual(str(stmt.attributes[0]), 'Field(int, lineno)')
        self.assertEqual(str(stmt.attributes[1]), 'Field(int, col_offset)')

    def test_constructor_fields(self):
        ehandler = self.types['excepthandler']
        self.assertEqual(len(ehandler.types), 1)
        self.assertEqual(len(ehandler.attributes), 2)

        cons = ehandler.types[0]
        self.assertIsInstance(cons, self.asdl.Constructor)
        self.assertEqual(len(cons.fields), 3)

        f0 = cons.fields[0]
        self.assertEqual(f0.type, 'expr')
        self.assertEqual(f0.name, 'type')
        self.assertTrue(f0.opt)

        f1 = cons.fields[1]
        self.assertEqual(f1.type, 'identifier')
        self.assertEqual(f1.name, 'name')
        self.assertTrue(f1.opt)

        f2 = cons.fields[2]
        self.assertEqual(f2.type, 'stmt')
        self.assertEqual(f2.name, 'body')
        self.assertFalse(f2.opt)
        self.assertTrue(f2.seq)

    def test_visitor(self):
        class CustomVisitor(self.asdl.VisitorBase):
            def __init__(self):
                super().__init__()
                self.names_with_seq = []

            def visitModule(self, mod):
                for dfn in mod.dfns:
                    self.visit(dfn)

            def visitType(self, type):
                self.visit(type.value)

            def visitSum(self, sum):
                for t in sum.types:
                    self.visit(t)

            def visitConstructor(self, cons):
                for f in cons.fields:
                    if f.seq:
                        self.names_with_seq.append(cons.name)

        v = CustomVisitor()
        v.visit(self.types['mod'])
        self.assertEqual(v.names_with_seq, ['Module', 'Interactive', 'Suite'])


if __name__ == '__main__':
    unittest.main()