1#!/usr/bin/env python 2# Copyright (c) 2013 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import glob 7import os 8import unittest 9 10from idl_lexer import IDLLexer 11from idl_parser import IDLParser, ParseFile 12 13 14def ParseCommentTest(comment): 15 comment = comment.strip() 16 comments = comment.split(None, 1) 17 return comments[0], comments[1] 18 19 20class WebIDLParser(unittest.TestCase): 21 22 def setUp(self): 23 self.parser = IDLParser(IDLLexer(), mute_error=True) 24 test_dir = os.path.abspath( 25 os.path.join(os.path.dirname(__file__), 'test_parser')) 26 self.filenames = glob.glob('%s/*_web.idl' % test_dir) 27 28 def _TestNode(self, node, filepath): 29 comments = node.GetListOf('SpecialComment') 30 for comment in comments: 31 check, value = ParseCommentTest(comment.GetName()) 32 if check == 'ERROR': 33 msg = node.GetLogLine('Expecting\n\t%s\nbut found \n\t%s\n' % ( 34 value, str(node))) 35 self.assertEqual(value, node.GetName() ,msg) 36 37 if check == 'TREE': 38 quick = '\n'.join(node.Tree()) 39 lineno = node.GetProperty('LINENO') 40 msg = 'Mismatched tree at line %d in %s:' % (lineno, filepath) 41 msg += '\n\n[EXPECTED]\n%s\n\n[ACTUAL]\n%s\n' % (value, quick) 42 self.assertEqual(value, quick, msg) 43 44 def testExpectedNodes(self): 45 for filename in self.filenames: 46 filenode = ParseFile(self.parser, filename) 47 children = filenode.GetChildren() 48 self.assertTrue(len(children) > 2, 'Expecting children in %s.' % 49 filename) 50 51 for node in filenode.GetChildren(): 52 self._TestNode(node, filename) 53 54 55class TestIncludes(unittest.TestCase): 56 57 def setUp(self): 58 self.parser = IDLParser(IDLLexer(), mute_error=True) 59 60 def _ParseIncludes(self, idl_text): 61 filenode = self.parser.ParseText(filename='', data=idl_text) 62 self.assertEqual(1, len(filenode.GetChildren())) 63 return filenode.GetChildren()[0] 64 65 def testAIncludesB(self): 66 idl_text = 'A includes B;' 67 includes_node = self._ParseIncludes(idl_text) 68 self.assertEqual('Includes(A)', str(includes_node)) 69 reference_node = includes_node.GetProperty('REFERENCE') 70 self.assertEqual('B', str(reference_node)) 71 72 def testBIncludesC(self): 73 idl_text = 'B includes C;' 74 includes_node = self._ParseIncludes(idl_text) 75 self.assertEqual('Includes(B)', str(includes_node)) 76 reference_node = includes_node.GetProperty('REFERENCE') 77 self.assertEqual('C', str(reference_node)) 78 79 def testUnexpectedSemicolon(self): 80 idl_text = 'A includes;' 81 node = self._ParseIncludes(idl_text) 82 self.assertEqual('Error', node.GetClass()) 83 error_message = node.GetName() 84 self.assertEqual('Unexpected ";" after keyword "includes".', 85 error_message) 86 87 def testUnexpectedIncludes(self): 88 idl_text = 'includes C;' 89 node = self._ParseIncludes(idl_text) 90 self.assertEqual('Error', node.GetClass()) 91 error_message = node.GetName() 92 self.assertEqual('Unexpected includes.', 93 error_message) 94 95 def testUnexpectedIncludesAfterBracket(self): 96 idl_text = '[foo] includes B;' 97 node = self._ParseIncludes(idl_text) 98 self.assertEqual('Error', node.GetClass()) 99 error_message = node.GetName() 100 self.assertEqual('Unexpected keyword "includes" after "]".', 101 error_message) 102 103 104class TestEnums(unittest.TestCase): 105 106 def setUp(self): 107 self.parser = IDLParser(IDLLexer(), mute_error=True) 108 109 def _ParseEnums(self, idl_text): 110 filenode = self.parser.ParseText(filename='', data=idl_text) 111 self.assertEqual(1, len(filenode.GetChildren())) 112 return filenode.GetChildren()[0] 113 114 def testBasic(self): 115 idl_text = 'enum MealType {"rice","noodles","other"};' 116 node = self._ParseEnums(idl_text) 117 children = node.GetChildren() 118 self.assertEqual('Enum', node.GetClass()) 119 self.assertEqual(3, len(children)) 120 self.assertEqual('EnumItem', children[0].GetClass()) 121 self.assertEqual('rice', children[0].GetName()) 122 self.assertEqual('EnumItem', children[1].GetClass()) 123 self.assertEqual('noodles', children[1].GetName()) 124 self.assertEqual('EnumItem', children[2].GetClass()) 125 self.assertEqual('other', children[2].GetName()) 126 127 def testErrorMissingName(self): 128 idl_text = 'enum {"rice","noodles","other"};' 129 node = self._ParseEnums(idl_text) 130 self.assertEqual('Error', node.GetClass()) 131 error_message = node.GetName() 132 self.assertEqual('Enum missing name.', error_message) 133 134 def testTrailingCommaIsAllowed(self): 135 idl_text = 'enum TrailingComma {"rice","noodles","other",};' 136 node = self._ParseEnums(idl_text) 137 children = node.GetChildren() 138 self.assertEqual('Enum', node.GetClass()) 139 self.assertEqual(3, len(children)) 140 self.assertEqual('EnumItem', children[0].GetClass()) 141 self.assertEqual('rice', children[0].GetName()) 142 self.assertEqual('EnumItem', children[1].GetClass()) 143 self.assertEqual('noodles', children[1].GetName()) 144 self.assertEqual('EnumItem', children[2].GetClass()) 145 self.assertEqual('other', children[2].GetName()) 146 147 def testErrorMissingCommaBetweenIdentifiers(self): 148 idl_text = 'enum MissingComma {"rice" "noodles","other"};' 149 node = self._ParseEnums(idl_text) 150 self.assertEqual('Error', node.GetClass()) 151 error_message = node.GetName() 152 self.assertEqual('Unexpected string "noodles" after string "rice".', 153 error_message) 154 155 def testErrorExtraCommaBetweenIdentifiers(self): 156 idl_text = 'enum ExtraComma {"rice","noodles",,"other"};' 157 node = self._ParseEnums(idl_text) 158 self.assertEqual('Error', node.GetClass()) 159 error_message = node.GetName() 160 self.assertEqual('Unexpected "," after ",".', error_message) 161 162 def testErrorUnexpectedKeyword(self): 163 idl_text = 'enum TestEnum {interface,"noodles","other"};' 164 node = self._ParseEnums(idl_text) 165 self.assertEqual('Error', node.GetClass()) 166 error_message = node.GetName() 167 self.assertEqual('Unexpected keyword "interface" after "{".', 168 error_message) 169 170 def testErrorUnexpectedIdentifier(self): 171 idl_text = 'enum TestEnum {somename,"noodles","other"};' 172 node = self._ParseEnums(idl_text) 173 self.assertEqual('Error', node.GetClass()) 174 error_message = node.GetName() 175 self.assertEqual('Unexpected identifier "somename" after "{".', 176 error_message) 177 178class TestExtendedAttribute(unittest.TestCase): 179 def setUp(self): 180 self.parser = IDLParser(IDLLexer(), mute_error=True) 181 182 def _ParseIdlWithExtendedAttributes(self, extended_attribute_text): 183 idl_text = extended_attribute_text + ' enum MealType {"rice"};' 184 filenode = self.parser.ParseText(filename='', data=idl_text) 185 self.assertEqual(1, len(filenode.GetChildren())) 186 node = filenode.GetChildren()[0] 187 self.assertEqual('Enum', node.GetClass()) 188 children = node.GetChildren() 189 self.assertEqual(2, len(children)) 190 self.assertEqual('EnumItem', children[0].GetClass()) 191 self.assertEqual('rice', children[0].GetName()) 192 return children[1] 193 194 def testNoArguments(self): 195 extended_attribute_text = '[Replacable]' 196 attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) 197 self.assertEqual('ExtAttributes', attributes.GetClass()) 198 self.assertEqual(1, len(attributes.GetChildren()) ) 199 attribute = attributes.GetChildren()[0] 200 self.assertEqual('ExtAttribute', attribute.GetClass()) 201 self.assertEqual('Replacable', attribute.GetName()) 202 203 def testArgumentList(self): 204 extended_attribute_text = '[Constructor(double x, double y)]' 205 attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) 206 self.assertEqual('ExtAttributes', attributes.GetClass()) 207 self.assertEqual(1, len(attributes.GetChildren())) 208 attribute = attributes.GetChildren()[0] 209 self.assertEqual('ExtAttribute', attribute.GetClass()) 210 self.assertEqual('Constructor', attribute.GetName()) 211 self.assertEqual('Arguments', attribute.GetChildren()[0].GetClass()) 212 arguments = attributes.GetChildren()[0].GetChildren()[0] 213 self.assertEqual(2, len(arguments.GetChildren())) 214 self.assertEqual('Argument', arguments.GetChildren()[0].GetClass()) 215 self.assertEqual('x', arguments.GetChildren()[0].GetName()) 216 self.assertEqual('Argument', arguments.GetChildren()[1].GetClass()) 217 self.assertEqual('y', arguments.GetChildren()[1].GetName()) 218 219 def testNamedArgumentList(self): 220 extended_attribute_text = '[NamedConstructor=Image(DOMString src)]' 221 attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) 222 self.assertEqual('ExtAttributes', attributes.GetClass()) 223 self.assertEqual(1, len(attributes.GetChildren())) 224 attribute = attributes.GetChildren()[0] 225 self.assertEqual('ExtAttribute', attribute.GetClass()) 226 self.assertEqual('NamedConstructor',attribute.GetName()) 227 self.assertEqual(1, len(attribute.GetChildren())) 228 self.assertEqual('Call', attribute.GetChildren()[0].GetClass()) 229 self.assertEqual('Image', attribute.GetChildren()[0].GetName()) 230 arguments = attribute.GetChildren()[0].GetChildren()[0] 231 self.assertEqual('Arguments', arguments.GetClass()) 232 self.assertEqual(1, len(arguments.GetChildren())) 233 self.assertEqual('Argument', arguments.GetChildren()[0].GetClass()) 234 self.assertEqual('src', arguments.GetChildren()[0].GetName()) 235 argument = arguments.GetChildren()[0] 236 self.assertEqual(1, len(argument.GetChildren())) 237 self.assertEqual('Type', argument.GetChildren()[0].GetClass()) 238 arg = argument.GetChildren()[0] 239 self.assertEqual(1, len(arg.GetChildren())) 240 argType = arg.GetChildren()[0] 241 self.assertEqual('StringType', argType.GetClass()) 242 self.assertEqual('DOMString', argType.GetName()) 243 244 def testIdentifier(self): 245 extended_attribute_text = '[PutForwards=name]' 246 attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) 247 self.assertEqual('ExtAttributes', attributes.GetClass()) 248 self.assertEqual(1, len(attributes.GetChildren())) 249 attribute = attributes.GetChildren()[0] 250 self.assertEqual('ExtAttribute', attribute.GetClass()) 251 self.assertEqual('PutForwards', attribute.GetName()) 252 identifier = attribute.GetProperty('VALUE') 253 self.assertEqual('name', identifier) 254 255 def testIdentifierList(self): 256 extended_attribute_text = '[Exposed=(Window,Worker)]' 257 attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) 258 self.assertEqual('ExtAttributes', attributes.GetClass()) 259 self.assertEqual(1, len(attributes.GetChildren())) 260 attribute = attributes.GetChildren()[0] 261 self.assertEqual('ExtAttribute', attribute.GetClass()) 262 self.assertEqual('Exposed', attribute.GetName()) 263 identifierList = attribute.GetProperty('VALUE') 264 self.assertEqual(2, len(identifierList)) 265 self.assertEqual('Window', identifierList[0]) 266 self.assertEqual('Worker', identifierList[1]) 267 268 def testCombinationOfExtendedAttributes(self): 269 extended_attribute_text = '[Replacable, Exposed=(Window,Worker)]' 270 attributes = self._ParseIdlWithExtendedAttributes(extended_attribute_text) 271 self.assertEqual('ExtAttributes', attributes.GetClass()) 272 self.assertEqual(2, len(attributes.GetChildren())) 273 attribute0 = attributes.GetChildren()[0] 274 self.assertEqual('ExtAttribute', attribute0.GetClass()) 275 self.assertEqual('Replacable', attribute0.GetName()) 276 attribute1 = attributes.GetChildren()[1] 277 self.assertEqual('ExtAttribute', attribute1.GetClass()) 278 self.assertEqual('Exposed', attribute1.GetName()) 279 identifierList = attribute1.GetProperty('VALUE') 280 self.assertEqual(2, len(identifierList)) 281 self.assertEqual('Window', identifierList[0]) 282 self.assertEqual('Worker', identifierList[1]) 283 284 def testErrorTrailingComma(self): 285 extended_attribute_text = '[Replacable, Exposed=(Window,Worker),]' 286 error = self._ParseIdlWithExtendedAttributes(extended_attribute_text) 287 self.assertEqual('Error', error.GetClass()) 288 error_message = error.GetName() 289 self.assertEqual('Unexpected "]" after ",".', error_message) 290 self.assertEqual('ExtendedAttributeList', error.GetProperty('PROD')) 291 292 def testErrorMultipleExtendedAttributes(self): 293 extended_attribute_text = '[Attribute1][Attribute2]' 294 idl_text = extended_attribute_text + ' enum MealType {"rice"};' 295 filenode = self.parser.ParseText(filename='', data=idl_text) 296 self.assertEqual(1, len(filenode.GetChildren())) 297 node = filenode.GetChildren()[0] 298 self.assertEqual('Error', node.GetClass()) 299 self.assertEqual('Unexpected "[" after "]".', node.GetName()) 300 self.assertEqual('Definition', node.GetProperty('PROD')) 301 children = node.GetChildren() 302 self.assertEqual(1, len(children)) 303 attributes = children[0] 304 self.assertEqual('ExtAttributes', attributes.GetClass()) 305 self.assertEqual(1, len(attributes.GetChildren())) 306 attribute = attributes.GetChildren()[0] 307 self.assertEqual('ExtAttribute', attribute.GetClass()) 308 self.assertEqual('Attribute1', attribute.GetName()) 309 310 311class TestDefaultValue(unittest.TestCase): 312 def setUp(self): 313 self.parser = IDLParser(IDLLexer(), mute_error=True) 314 315 def _ParseDefaultValue(self, default_value_text): 316 idl_text = 'interface I { void hello(' + default_value_text + '); };' 317 filenode = self.parser.ParseText(filename='', data=idl_text) 318 self.assertEqual(1, len(filenode.GetChildren())) 319 node = filenode.GetChildren()[0] 320 self.assertEqual('Interface', node.GetClass()) 321 self.assertEqual('I', node.GetName()) 322 children = node.GetChildren() 323 self.assertEqual(1, len(children)) 324 operation = children[0] 325 self.assertEqual('Operation', operation.GetClass()) 326 self.assertEqual('hello', operation.GetName()) 327 self.assertEqual(2, len(operation.GetChildren())) 328 arguments = operation.GetChildren()[0] 329 self.assertEqual('Arguments', arguments.GetClass()) 330 self.assertEqual(1, len(arguments.GetChildren())) 331 argument = arguments.GetChildren()[0] 332 return_type = operation.GetChildren()[1] 333 self._CheckTypeNode(return_type, 'PrimitiveType', 'void') 334 return argument 335 336 def _CheckTypeNode(self, type_node, expected_class, expected_name): 337 self.assertEqual('Type', type_node.GetClass()) 338 self.assertEqual(1, len(type_node.GetChildren())) 339 type_detail = type_node.GetChildren()[0] 340 class_name = type_detail.GetClass() 341 name = type_detail.GetName() 342 self.assertEqual(expected_class, class_name) 343 self.assertEqual(expected_name, name) 344 345 def _CheckArgumentNode(self, argument, expected_class, expected_name): 346 class_name = argument.GetClass() 347 name = argument.GetName() 348 self.assertEqual(expected_class, class_name) 349 self.assertEqual(expected_name, name) 350 351 def _CheckDefaultValue(self, default_value, expected_type, expected_value): 352 self.assertEqual('Default', default_value.GetClass()) 353 self.assertEqual(expected_type, default_value.GetProperty('TYPE')) 354 self.assertEqual(expected_value, default_value.GetProperty('VALUE')) 355 356 def testDefaultValueDOMString(self): 357 default_value_text = 'optional DOMString arg = "foo"' 358 argument = self._ParseDefaultValue(default_value_text) 359 self._CheckArgumentNode(argument, 'Argument', 'arg') 360 argument_type = argument.GetChildren()[0] 361 self._CheckTypeNode(argument_type, 'StringType', 'DOMString') 362 default_value = argument.GetChildren()[1] 363 self._CheckDefaultValue(default_value, 'DOMString', 'foo') 364 365 def testDefaultValueInteger(self): 366 default_value_text = 'optional long arg = 10' 367 argument = self._ParseDefaultValue(default_value_text) 368 self._CheckArgumentNode(argument, 'Argument', 'arg') 369 argument_type = argument.GetChildren()[0] 370 self._CheckTypeNode(argument_type, 'PrimitiveType', 'long') 371 default_value = argument.GetChildren()[1] 372 self._CheckDefaultValue(default_value, 'integer', '10') 373 374 def testDefaultValueFloat(self): 375 default_value_text = 'optional float arg = 1.5' 376 argument = self._ParseDefaultValue(default_value_text) 377 self._CheckArgumentNode(argument, 'Argument', 'arg') 378 argument_type = argument.GetChildren()[0] 379 self._CheckTypeNode(argument_type, 'PrimitiveType', 'float') 380 default_value = argument.GetChildren()[1] 381 self._CheckDefaultValue(default_value, 'float', '1.5') 382 383 def testDefaultValueBoolean(self): 384 default_value_text = 'optional boolean arg = true' 385 argument = self._ParseDefaultValue(default_value_text) 386 self._CheckArgumentNode(argument, 'Argument', 'arg') 387 argument_type = argument.GetChildren()[0] 388 self._CheckTypeNode(argument_type, 'PrimitiveType', 'boolean') 389 default_value = argument.GetChildren()[1] 390 self._CheckDefaultValue(default_value, 'boolean', True) 391 392 def testDefaultValueNull(self): 393 # Node is a nullable type 394 default_value_text = 'optional Node arg = null' 395 argument = self._ParseDefaultValue(default_value_text) 396 self._CheckArgumentNode(argument, 'Argument', 'arg') 397 argument_type = argument.GetChildren()[0] 398 self._CheckTypeNode(argument_type, 'Typeref', 'Node') 399 default_value = argument.GetChildren()[1] 400 self._CheckDefaultValue(default_value, 'NULL', 'NULL') 401 402if __name__ == '__main__': 403 unittest.main(verbosity=2) 404