| OLD | NEW |
| (Empty) |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 # Use of this source code is governed by a BSD-style license that can be | |
| 3 # found in the LICENSE file. | |
| 4 | |
| 5 import imp | |
| 6 import os.path | |
| 7 import sys | |
| 8 import unittest | |
| 9 | |
| 10 def _GetDirAbove(dirname): | |
| 11 """Returns the directory "above" this file containing |dirname| (which must | |
| 12 also be "above" this file).""" | |
| 13 path = os.path.abspath(__file__) | |
| 14 while True: | |
| 15 path, tail = os.path.split(path) | |
| 16 assert tail | |
| 17 if tail == dirname: | |
| 18 return path | |
| 19 | |
| 20 try: | |
| 21 imp.find_module("ply") | |
| 22 except ImportError: | |
| 23 sys.path.append(os.path.join(_GetDirAbove("public"), "public/third_party")) | |
| 24 from ply import lex | |
| 25 | |
| 26 try: | |
| 27 imp.find_module("mojom") | |
| 28 except ImportError: | |
| 29 sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib")) | |
| 30 import mojom.parse.lexer | |
| 31 | |
| 32 | |
| 33 # This (monkey-patching LexToken to make comparison value-based) is evil, but | |
| 34 # we'll do it anyway. (I'm pretty sure ply's lexer never cares about comparing | |
| 35 # for object identity.) | |
| 36 def _LexTokenEq(self, other): | |
| 37 return self.type == other.type and self.value == other.value and \ | |
| 38 self.lineno == other.lineno and self.lexpos == other.lexpos | |
| 39 setattr(lex.LexToken, '__eq__', _LexTokenEq) | |
| 40 | |
| 41 | |
| 42 def _MakeLexToken(token_type, value, lineno=1, lexpos=0): | |
| 43 """Makes a LexToken with the given parameters. (Note that lineno is 1-based, | |
| 44 but lexpos is 0-based.)""" | |
| 45 rv = lex.LexToken() | |
| 46 rv.type, rv.value, rv.lineno, rv.lexpos = token_type, value, lineno, lexpos | |
| 47 return rv | |
| 48 | |
| 49 | |
| 50 def _MakeLexTokenForKeyword(keyword, **kwargs): | |
| 51 """Makes a LexToken for the given keyword.""" | |
| 52 return _MakeLexToken(keyword.upper(), keyword.lower(), **kwargs) | |
| 53 | |
| 54 | |
| 55 class LexerTest(unittest.TestCase): | |
| 56 """Tests |mojom.parse.lexer.Lexer|.""" | |
| 57 | |
| 58 def __init__(self, *args, **kwargs): | |
| 59 unittest.TestCase.__init__(self, *args, **kwargs) | |
| 60 # Clone all lexer instances from this one, since making a lexer is slow. | |
| 61 self._zygote_lexer = lex.lex(mojom.parse.lexer.Lexer("my_file.mojom")) | |
| 62 | |
| 63 def testValidKeywords(self): | |
| 64 """Tests valid keywords.""" | |
| 65 self.assertEquals(self._SingleTokenForInput("handle"), | |
| 66 _MakeLexTokenForKeyword("handle")) | |
| 67 self.assertEquals(self._SingleTokenForInput("import"), | |
| 68 _MakeLexTokenForKeyword("import")) | |
| 69 self.assertEquals(self._SingleTokenForInput("module"), | |
| 70 _MakeLexTokenForKeyword("module")) | |
| 71 self.assertEquals(self._SingleTokenForInput("struct"), | |
| 72 _MakeLexTokenForKeyword("struct")) | |
| 73 self.assertEquals(self._SingleTokenForInput("union"), | |
| 74 _MakeLexTokenForKeyword("union")) | |
| 75 self.assertEquals(self._SingleTokenForInput("interface"), | |
| 76 _MakeLexTokenForKeyword("interface")) | |
| 77 self.assertEquals(self._SingleTokenForInput("enum"), | |
| 78 _MakeLexTokenForKeyword("enum")) | |
| 79 self.assertEquals(self._SingleTokenForInput("const"), | |
| 80 _MakeLexTokenForKeyword("const")) | |
| 81 self.assertEquals(self._SingleTokenForInput("true"), | |
| 82 _MakeLexTokenForKeyword("true")) | |
| 83 self.assertEquals(self._SingleTokenForInput("false"), | |
| 84 _MakeLexTokenForKeyword("false")) | |
| 85 self.assertEquals(self._SingleTokenForInput("default"), | |
| 86 _MakeLexTokenForKeyword("default")) | |
| 87 self.assertEquals(self._SingleTokenForInput("array"), | |
| 88 _MakeLexTokenForKeyword("array")) | |
| 89 self.assertEquals(self._SingleTokenForInput("map"), | |
| 90 _MakeLexTokenForKeyword("map")) | |
| 91 | |
| 92 def testValidIdentifiers(self): | |
| 93 """Tests identifiers.""" | |
| 94 self.assertEquals(self._SingleTokenForInput("abcd"), | |
| 95 _MakeLexToken("NAME", "abcd")) | |
| 96 self.assertEquals(self._SingleTokenForInput("AbC_d012_"), | |
| 97 _MakeLexToken("NAME", "AbC_d012_")) | |
| 98 self.assertEquals(self._SingleTokenForInput("_0123"), | |
| 99 _MakeLexToken("NAME", "_0123")) | |
| 100 | |
| 101 def testInvalidIdentifiers(self): | |
| 102 with self.assertRaisesRegexp( | |
| 103 mojom.parse.lexer.LexError, | |
| 104 r"^my_file\.mojom:1: Error: Illegal character '\$'$"): | |
| 105 self._TokensForInput("$abc") | |
| 106 with self.assertRaisesRegexp( | |
| 107 mojom.parse.lexer.LexError, | |
| 108 r"^my_file\.mojom:1: Error: Illegal character '\$'$"): | |
| 109 self._TokensForInput("a$bc") | |
| 110 | |
| 111 def testDecimalIntegerConstants(self): | |
| 112 self.assertEquals(self._SingleTokenForInput("0"), | |
| 113 _MakeLexToken("INT_CONST_DEC", "0")) | |
| 114 self.assertEquals(self._SingleTokenForInput("1"), | |
| 115 _MakeLexToken("INT_CONST_DEC", "1")) | |
| 116 self.assertEquals(self._SingleTokenForInput("123"), | |
| 117 _MakeLexToken("INT_CONST_DEC", "123")) | |
| 118 self.assertEquals(self._SingleTokenForInput("10"), | |
| 119 _MakeLexToken("INT_CONST_DEC", "10")) | |
| 120 | |
| 121 def testValidTokens(self): | |
| 122 """Tests valid tokens (which aren't tested elsewhere).""" | |
| 123 # Keywords tested in |testValidKeywords|. | |
| 124 # NAME tested in |testValidIdentifiers|. | |
| 125 self.assertEquals(self._SingleTokenForInput("@123"), | |
| 126 _MakeLexToken("ORDINAL", "@123")) | |
| 127 self.assertEquals(self._SingleTokenForInput("456"), | |
| 128 _MakeLexToken("INT_CONST_DEC", "456")) | |
| 129 self.assertEquals(self._SingleTokenForInput("0x01aB2eF3"), | |
| 130 _MakeLexToken("INT_CONST_HEX", "0x01aB2eF3")) | |
| 131 self.assertEquals(self._SingleTokenForInput("123.456"), | |
| 132 _MakeLexToken("FLOAT_CONST", "123.456")) | |
| 133 self.assertEquals(self._SingleTokenForInput("\"hello\""), | |
| 134 _MakeLexToken("STRING_LITERAL", "\"hello\"")) | |
| 135 self.assertEquals(self._SingleTokenForInput("+"), | |
| 136 _MakeLexToken("PLUS", "+")) | |
| 137 self.assertEquals(self._SingleTokenForInput("-"), | |
| 138 _MakeLexToken("MINUS", "-")) | |
| 139 self.assertEquals(self._SingleTokenForInput("&"), | |
| 140 _MakeLexToken("AMP", "&")) | |
| 141 self.assertEquals(self._SingleTokenForInput("?"), | |
| 142 _MakeLexToken("QSTN", "?")) | |
| 143 self.assertEquals(self._SingleTokenForInput("="), | |
| 144 _MakeLexToken("EQUALS", "=")) | |
| 145 self.assertEquals(self._SingleTokenForInput("=>"), | |
| 146 _MakeLexToken("RESPONSE", "=>")) | |
| 147 self.assertEquals(self._SingleTokenForInput("("), | |
| 148 _MakeLexToken("LPAREN", "(")) | |
| 149 self.assertEquals(self._SingleTokenForInput(")"), | |
| 150 _MakeLexToken("RPAREN", ")")) | |
| 151 self.assertEquals(self._SingleTokenForInput("["), | |
| 152 _MakeLexToken("LBRACKET", "[")) | |
| 153 self.assertEquals(self._SingleTokenForInput("]"), | |
| 154 _MakeLexToken("RBRACKET", "]")) | |
| 155 self.assertEquals(self._SingleTokenForInput("{"), | |
| 156 _MakeLexToken("LBRACE", "{")) | |
| 157 self.assertEquals(self._SingleTokenForInput("}"), | |
| 158 _MakeLexToken("RBRACE", "}")) | |
| 159 self.assertEquals(self._SingleTokenForInput("<"), | |
| 160 _MakeLexToken("LANGLE", "<")) | |
| 161 self.assertEquals(self._SingleTokenForInput(">"), | |
| 162 _MakeLexToken("RANGLE", ">")) | |
| 163 self.assertEquals(self._SingleTokenForInput(";"), | |
| 164 _MakeLexToken("SEMI", ";")) | |
| 165 self.assertEquals(self._SingleTokenForInput(","), | |
| 166 _MakeLexToken("COMMA", ",")) | |
| 167 self.assertEquals(self._SingleTokenForInput("."), | |
| 168 _MakeLexToken("DOT", ".")) | |
| 169 | |
| 170 def _TokensForInput(self, input_string): | |
| 171 """Gets a list of tokens for the given input string.""" | |
| 172 lexer = self._zygote_lexer.clone() | |
| 173 lexer.input(input_string) | |
| 174 rv = [] | |
| 175 while True: | |
| 176 tok = lexer.token() | |
| 177 if not tok: | |
| 178 return rv | |
| 179 rv.append(tok) | |
| 180 | |
| 181 def _SingleTokenForInput(self, input_string): | |
| 182 """Gets the single token for the given input string. (Raises an exception if | |
| 183 the input string does not result in exactly one token.)""" | |
| 184 toks = self._TokensForInput(input_string) | |
| 185 assert len(toks) == 1 | |
| 186 return toks[0] | |
| 187 | |
| 188 | |
| 189 if __name__ == "__main__": | |
| 190 unittest.main() | |
| OLD | NEW |