| #!/usr/bin/env python3 |
| # Copyright 2013 The Chromium Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import glob |
| import os |
| import unittest |
| |
| from idl_lexer import IDLLexer |
| from idl_parser import IDLParser, ParseFile |
| |
| |
| def ParseCommentTest(comment): |
| comment = comment.strip() |
| comments = comment.split(None, 1) |
| return comments[0], comments[1] |
| |
| |
| class WebIDLParser(unittest.TestCase): |
| |
| def setUp(self): |
| self.parser = IDLParser(IDLLexer(), mute_error=True) |
| test_dir = os.path.abspath( |
| os.path.join(os.path.dirname(__file__), 'test_parser')) |
| self.filenames = glob.glob('%s/*_web.idl' % test_dir) |
| |
| def _TestNode(self, node, filepath): |
| comments = node.GetListOf('SpecialComment') |
| for comment in comments: |
| check, value = ParseCommentTest(comment.GetName()) |
| if check == 'ERROR': |
| msg = node.GetLogLine('Expecting\n\t%s\nbut found \n\t%s\n' % ( |
| value, str(node))) |
| self.assertEqual(value, node.GetName() ,msg) |
| |
| if check == 'TREE': |
| quick = '\n'.join(node.Tree()) |
| lineno = node.GetProperty('LINENO') |
| msg = 'Mismatched tree at line %d in %s:' % (lineno, filepath) |
| msg += '\n\n[EXPECTED]\n%s\n\n[ACTUAL]\n%s\n' % (value, quick) |
| self.assertEqual(value, quick, msg) |
| |
| def testExpectedNodes(self): |
| for filename in self.filenames: |
| filenode = ParseFile(self.parser, filename) |
| children = filenode.GetChildren() |
| self.assertTrue(len(children) > 2, 'Expecting children in %s.' % |
| filename) |
| |
| for node in filenode.GetChildren(): |
| self._TestNode(node, filename) |
| |
| |
| class TestIncludes(unittest.TestCase): |
| |
| def setUp(self): |
| self.parser = IDLParser(IDLLexer(), mute_error=True) |
| |
| def _ParseIncludes(self, idl_text): |
| filenode = self.parser.ParseText(filename='', data=idl_text) |
| self.assertEqual(1, len(filenode.GetChildren())) |
| return filenode.GetChildren()[0] |
| |
| def testAIncludesB(self): |
| idl_text = 'A includes B;' |
| includes_node = self._ParseIncludes(idl_text) |
| self.assertEqual('Includes(A)', str(includes_node)) |
| reference_node = includes_node.GetProperty('REFERENCE') |
| self.assertEqual('B', str(reference_node)) |
| |
| def testBIncludesC(self): |
| idl_text = 'B includes C;' |
| includes_node = self._ParseIncludes(idl_text) |
| self.assertEqual('Includes(B)', str(includes_node)) |
| reference_node = includes_node.GetProperty('REFERENCE') |
| self.assertEqual('C', str(reference_node)) |
| |
| def testUnexpectedSemicolon(self): |
| idl_text = 'A includes;' |
| node = self._ParseIncludes(idl_text) |
| self.assertEqual('Error', node.GetClass()) |
| error_message = node.GetName() |
| self.assertEqual('Unexpected ";" after keyword "includes".', |
| error_message) |
| |
| def testUnexpectedIncludes(self): |
| idl_text = 'includes C;' |
| node = self._ParseIncludes(idl_text) |
| self.assertEqual('Error', node.GetClass()) |
| error_message = node.GetName() |
| self.assertEqual('Unexpected includes.', |
| error_message) |
| |
| def testUnexpectedIncludesAfterBracket(self): |
| idl_text = '[foo] includes B;' |
| node = self._ParseIncludes(idl_text) |
| self.assertEqual('Error', node.GetClass()) |
| error_message = node.GetName() |
| self.assertEqual('Unexpected keyword "includes" after "]".', |
| error_message) |
| |
| |
| class TestEnums(unittest.TestCase): |
| |
| def setUp(self): |
| self.parser = IDLParser(IDLLexer(), mute_error=True) |
| |
| def _ParseEnums(self, idl_text): |
| filenode = self.parser.ParseText(filename='', data=idl_text) |
| self.assertEqual(1, len(filenode.GetChildren())) |
| return filenode.GetChildren()[0] |
| |
| def testBasic(self): |
| idl_text = 'enum MealType {"rice","noodles","other"};' |
| node = self._ParseEnums(idl_text) |
| children = node.GetChildren() |
| self.assertEqual('Enum', node.GetClass()) |
| self.assertEqual(3, len(children)) |
| self.assertEqual('EnumItem', children[0].GetClass()) |
| self.assertEqual('rice', children[0].GetName()) |
| self.assertEqual('EnumItem', children[1].GetClass()) |
| self.assertEqual('noodles', children[1].GetName()) |
| self.assertEqual('EnumItem', children[2].GetClass()) |
| self.assertEqual('other', children[2].GetName()) |
| |
| def testErrorMissingName(self): |
| idl_text = 'enum {"rice","noodles","other"};' |
| node = self._ParseEnums(idl_text) |
| self.assertEqual('Error', node.GetClass()) |
| error_message = node.GetName() |
| self.assertEqual('Enum missing name.', error_message) |
| |
| def testTrailingCommaIsAllowed(self): |
| idl_text = 'enum TrailingComma {"rice","noodles","other",};' |
| node = self._ParseEnums(idl_text) |
| children = node.GetChildren() |
| self.assertEqual('Enum', node.GetClass()) |
| self.assertEqual(3, len(children)) |
| self.assertEqual('EnumItem', children[0].GetClass()) |
| self.assertEqual('rice', children[0].GetName()) |
| self.assertEqual('EnumItem', children[1].GetClass()) |
| self.assertEqual('noodles', children[1].GetName()) |
| self.assertEqual('EnumItem', children[2].GetClass()) |
| self.assertEqual('other', children[2].GetName()) |
| |
| def testErrorMissingCommaBetweenIdentifiers(self): |
| idl_text = 'enum MissingComma {"rice" "noodles","other"};' |
| node = self._ParseEnums(idl_text) |
| self.assertEqual('Error', node.GetClass()) |
| error_message = node.GetName() |
| self.assertEqual('Unexpected string "noodles" after string "rice".', |
| error_message) |
| |
| def testErrorExtraCommaBetweenIdentifiers(self): |
| idl_text = 'enum ExtraComma {"rice","noodles",,"other"};' |
| node = self._ParseEnums(idl_text) |
| self.assertEqual('Error', node.GetClass()) |
| error_message = node.GetName() |
| self.assertEqual('Unexpected "," after ",".', error_message) |
| |
| def testErrorUnexpectedKeyword(self): |
| idl_text = 'enum TestEnum {interface,"noodles","other"};' |
| node = self._ParseEnums(idl_text) |
| self.assertEqual('Error', node.GetClass()) |
| error_message = node.GetName() |
| self.assertEqual('Unexpected keyword "interface" after "{".', |
| error_message) |
| |
| def testErrorUnexpectedIdentifier(self): |
| idl_text = 'enum TestEnum {somename,"noodles","other"};' |
| node = self._ParseEnums(idl_text) |
| self.assertEqual('Error', node.GetClass()) |
| error_message = node.GetName() |
| self.assertEqual('Unexpected identifier "somename" after "{".', |
| error_message) |
| |
| class TestExtendedAttribute(unittest.TestCase): |
| def setUp(self): |
| self.parser = IDLParser(IDLLexer(), mute_error=True) |
| |
| def _ParseIdlWithExtendedAttributes(self, extended_attribute_text): |
| idl_text = extended_attribute_text + ' enum MealType {"rice"};' |
| filenode = self.parser.ParseText(filename='', data=idl_text) |
| self.assertEqual(1, len(filenode.GetChildren())) |
| node = filenode.GetChildren()[0] |
| self.assertEqual('Enum', node.GetClass()) |
| children = node.GetChildren() |
| self.assertEqual(2, len(children)) |
| self.assertEqual('EnumItem', children[0].GetClass()) |
| self.assertEqual('rice', children[0].GetName()) |
| return children[1] |
| |
| def testNoArguments(self): |
| extended_attribute_text = '[Replacable]' |
| attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) |
| self.assertEqual('ExtAttributes', attributes.GetClass()) |
| self.assertEqual(1, len(attributes.GetChildren()) ) |
| attribute = attributes.GetChildren()[0] |
| self.assertEqual('ExtAttribute', attribute.GetClass()) |
| self.assertEqual('Replacable', attribute.GetName()) |
| |
| def testArgumentList(self): |
| extended_attribute_text = '[Constructor(double x, double y)]' |
| attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) |
| self.assertEqual('ExtAttributes', attributes.GetClass()) |
| self.assertEqual(1, len(attributes.GetChildren())) |
| attribute = attributes.GetChildren()[0] |
| self.assertEqual('ExtAttribute', attribute.GetClass()) |
| self.assertEqual('Constructor', attribute.GetName()) |
| self.assertEqual('Arguments', attribute.GetChildren()[0].GetClass()) |
| arguments = attributes.GetChildren()[0].GetChildren()[0] |
| self.assertEqual(2, len(arguments.GetChildren())) |
| self.assertEqual('Argument', arguments.GetChildren()[0].GetClass()) |
| self.assertEqual('x', arguments.GetChildren()[0].GetName()) |
| self.assertEqual('Argument', arguments.GetChildren()[1].GetClass()) |
| self.assertEqual('y', arguments.GetChildren()[1].GetName()) |
| |
| def testNamedArgumentList(self): |
| extended_attribute_text = '[NamedConstructor=Image(DOMString src)]' |
| attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) |
| self.assertEqual('ExtAttributes', attributes.GetClass()) |
| self.assertEqual(1, len(attributes.GetChildren())) |
| attribute = attributes.GetChildren()[0] |
| self.assertEqual('ExtAttribute', attribute.GetClass()) |
| self.assertEqual('NamedConstructor',attribute.GetName()) |
| self.assertEqual(1, len(attribute.GetChildren())) |
| self.assertEqual('Call', attribute.GetChildren()[0].GetClass()) |
| self.assertEqual('Image', attribute.GetChildren()[0].GetName()) |
| arguments = attribute.GetChildren()[0].GetChildren()[0] |
| self.assertEqual('Arguments', arguments.GetClass()) |
| self.assertEqual(1, len(arguments.GetChildren())) |
| self.assertEqual('Argument', arguments.GetChildren()[0].GetClass()) |
| self.assertEqual('src', arguments.GetChildren()[0].GetName()) |
| argument = arguments.GetChildren()[0] |
| self.assertEqual(1, len(argument.GetChildren())) |
| self.assertEqual('Type', argument.GetChildren()[0].GetClass()) |
| arg = argument.GetChildren()[0] |
| self.assertEqual(1, len(arg.GetChildren())) |
| argType = arg.GetChildren()[0] |
| self.assertEqual('StringType', argType.GetClass()) |
| self.assertEqual('DOMString', argType.GetName()) |
| |
| def testIdentifier(self): |
| extended_attribute_text = '[PutForwards=name]' |
| attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) |
| self.assertEqual('ExtAttributes', attributes.GetClass()) |
| self.assertEqual(1, len(attributes.GetChildren())) |
| attribute = attributes.GetChildren()[0] |
| self.assertEqual('ExtAttribute', attribute.GetClass()) |
| self.assertEqual('PutForwards', attribute.GetName()) |
| identifier = attribute.GetProperty('VALUE') |
| self.assertEqual('name', identifier) |
| |
| def testIdentifierList(self): |
| extended_attribute_text = '[Exposed=(Window,Worker)]' |
| attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) |
| self.assertEqual('ExtAttributes', attributes.GetClass()) |
| self.assertEqual(1, len(attributes.GetChildren())) |
| attribute = attributes.GetChildren()[0] |
| self.assertEqual('ExtAttribute', attribute.GetClass()) |
| self.assertEqual('Exposed', attribute.GetName()) |
| identifierList = attribute.GetProperty('VALUE') |
| self.assertEqual(2, len(identifierList)) |
| self.assertEqual('Window', identifierList[0]) |
| self.assertEqual('Worker', identifierList[1]) |
| |
| def testCombinationOfExtendedAttributes(self): |
| extended_attribute_text = '[Replacable, Exposed=(Window,Worker)]' |
| attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) |
| self.assertEqual('ExtAttributes', attributes.GetClass()) |
| self.assertEqual(2, len(attributes.GetChildren())) |
| attribute0 = attributes.GetChildren()[0] |
| self.assertEqual('ExtAttribute', attribute0.GetClass()) |
| self.assertEqual('Replacable', attribute0.GetName()) |
| attribute1 = attributes.GetChildren()[1] |
| self.assertEqual('ExtAttribute', attribute1.GetClass()) |
| self.assertEqual('Exposed', attribute1.GetName()) |
| identifierList = attribute1.GetProperty('VALUE') |
| self.assertEqual(2, len(identifierList)) |
| self.assertEqual('Window', identifierList[0]) |
| self.assertEqual('Worker', identifierList[1]) |
| |
| def testErrorTrailingComma(self): |
| extended_attribute_text = '[Replacable, Exposed=(Window,Worker),]' |
| error = self._ParseIdlWithExtendedAttributes(extended_attribute_text) |
| self.assertEqual('Error', error.GetClass()) |
| error_message = error.GetName() |
| self.assertEqual('Unexpected "]" after ",".', error_message) |
| self.assertEqual('ExtendedAttributeList', error.GetProperty('PROD')) |
| |
| def testErrorMultipleExtendedAttributes(self): |
| extended_attribute_text = '[Attribute1][Attribute2]' |
| idl_text = extended_attribute_text + ' enum MealType {"rice"};' |
| filenode = self.parser.ParseText(filename='', data=idl_text) |
| self.assertEqual(1, len(filenode.GetChildren())) |
| node = filenode.GetChildren()[0] |
| self.assertEqual('Error', node.GetClass()) |
| self.assertEqual('Unexpected "[" after "]".', node.GetName()) |
| self.assertEqual('Definition', node.GetProperty('PROD')) |
| children = node.GetChildren() |
| self.assertEqual(1, len(children)) |
| attributes = children[0] |
| self.assertEqual('ExtAttributes', attributes.GetClass()) |
| self.assertEqual(1, len(attributes.GetChildren())) |
| attribute = attributes.GetChildren()[0] |
| self.assertEqual('ExtAttribute', attribute.GetClass()) |
| self.assertEqual('Attribute1', attribute.GetName()) |
| |
| |
| class TestDefaultValue(unittest.TestCase): |
| def setUp(self): |
| self.parser = IDLParser(IDLLexer(), mute_error=True) |
| |
| def _ParseDefaultValue(self, default_value_text): |
| idl_text = 'interface I { void hello(' + default_value_text + '); };' |
| filenode = self.parser.ParseText(filename='', data=idl_text) |
| self.assertEqual(1, len(filenode.GetChildren())) |
| node = filenode.GetChildren()[0] |
| self.assertEqual('Interface', node.GetClass()) |
| self.assertEqual('I', node.GetName()) |
| children = node.GetChildren() |
| self.assertEqual(1, len(children)) |
| operation = children[0] |
| self.assertEqual('Operation', operation.GetClass()) |
| self.assertEqual('hello', operation.GetName()) |
| self.assertEqual(2, len(operation.GetChildren())) |
| arguments = operation.GetChildren()[0] |
| self.assertEqual('Arguments', arguments.GetClass()) |
| self.assertEqual(1, len(arguments.GetChildren())) |
| argument = arguments.GetChildren()[0] |
| return_type = operation.GetChildren()[1] |
| self._CheckTypeNode(return_type, 'PrimitiveType', 'void') |
| return argument |
| |
| def _CheckTypeNode(self, type_node, expected_class, expected_name): |
| self.assertEqual('Type', type_node.GetClass()) |
| self.assertEqual(1, len(type_node.GetChildren())) |
| type_detail = type_node.GetChildren()[0] |
| class_name = type_detail.GetClass() |
| name = type_detail.GetName() |
| self.assertEqual(expected_class, class_name) |
| self.assertEqual(expected_name, name) |
| |
| def _CheckArgumentNode(self, argument, expected_class, expected_name): |
| class_name = argument.GetClass() |
| name = argument.GetName() |
| self.assertEqual(expected_class, class_name) |
| self.assertEqual(expected_name, name) |
| |
| def _CheckDefaultValue(self, default_value, expected_type, expected_value): |
| self.assertEqual('Default', default_value.GetClass()) |
| self.assertEqual(expected_type, default_value.GetProperty('TYPE')) |
| self.assertEqual(expected_value, default_value.GetProperty('VALUE')) |
| |
| def testDefaultValueDOMString(self): |
| default_value_text = 'optional DOMString arg = "foo"' |
| argument = self._ParseDefaultValue(default_value_text) |
| self._CheckArgumentNode(argument, 'Argument', 'arg') |
| argument_type = argument.GetChildren()[0] |
| self._CheckTypeNode(argument_type, 'StringType', 'DOMString') |
| default_value = argument.GetChildren()[1] |
| self._CheckDefaultValue(default_value, 'DOMString', 'foo') |
| |
| def testDefaultValueInteger(self): |
| default_value_text = 'optional long arg = 10' |
| argument = self._ParseDefaultValue(default_value_text) |
| self._CheckArgumentNode(argument, 'Argument', 'arg') |
| argument_type = argument.GetChildren()[0] |
| self._CheckTypeNode(argument_type, 'PrimitiveType', 'long') |
| default_value = argument.GetChildren()[1] |
| self._CheckDefaultValue(default_value, 'integer', '10') |
| |
| def testDefaultValueFloat(self): |
| default_value_text = 'optional float arg = 1.5' |
| argument = self._ParseDefaultValue(default_value_text) |
| self._CheckArgumentNode(argument, 'Argument', 'arg') |
| argument_type = argument.GetChildren()[0] |
| self._CheckTypeNode(argument_type, 'PrimitiveType', 'float') |
| default_value = argument.GetChildren()[1] |
| self._CheckDefaultValue(default_value, 'float', '1.5') |
| |
| def testDefaultValueBoolean(self): |
| default_value_text = 'optional boolean arg = true' |
| argument = self._ParseDefaultValue(default_value_text) |
| self._CheckArgumentNode(argument, 'Argument', 'arg') |
| argument_type = argument.GetChildren()[0] |
| self._CheckTypeNode(argument_type, 'PrimitiveType', 'boolean') |
| default_value = argument.GetChildren()[1] |
| self._CheckDefaultValue(default_value, 'boolean', True) |
| |
| def testDefaultValueNull(self): |
| # Node is a nullable type |
| default_value_text = 'optional Node arg = null' |
| argument = self._ParseDefaultValue(default_value_text) |
| self._CheckArgumentNode(argument, 'Argument', 'arg') |
| argument_type = argument.GetChildren()[0] |
| self._CheckTypeNode(argument_type, 'Typeref', 'Node') |
| default_value = argument.GetChildren()[1] |
| self._CheckDefaultValue(default_value, 'NULL', 'NULL') |
| |
| if __name__ == '__main__': |
| unittest.main(verbosity=2) |