/build/pymake/tests/parsertests.py

http://github.com/zpao/v8monkey · Python · 314 lines · 262 code · 29 blank · 23 comment · 17 complexity · 55fb45866bf25b66d93181841d6dddca MD5 · raw file

  1. import pymake.data, pymake.parser, pymake.parserdata, pymake.functions
  2. import unittest
  3. import logging
  4. from cStringIO import StringIO
  5. def multitest(cls):
  6. for name in cls.testdata.iterkeys():
  7. def m(self, name=name):
  8. return self.runSingle(*self.testdata[name])
  9. setattr(cls, 'test_%s' % name, m)
  10. return cls
  11. class TestBase(unittest.TestCase):
  12. def assertEqual(self, a, b, msg=""):
  13. """Actually print the values which weren't equal, if things don't work out!"""
  14. unittest.TestCase.assertEqual(self, a, b, "%s got %r expected %r" % (msg, a, b))
  15. class DataTest(TestBase):
  16. testdata = {
  17. 'oneline':
  18. ("He\tllo", "f", 1, 0,
  19. ((0, "f", 1, 0), (2, "f", 1, 2), (3, "f", 1, 4))),
  20. 'twoline':
  21. ("line1 \n\tl\tine2", "f", 1, 4,
  22. ((0, "f", 1, 4), (5, "f", 1, 9), (6, "f", 1, 10), (7, "f", 2, 0), (8, "f", 2, 4), (10, "f", 2, 8), (13, "f", 2, 11))),
  23. }
  24. def runSingle(self, data, filename, line, col, results):
  25. d = pymake.parser.Data(data, 0, len(data), pymake.parserdata.Location(filename, line, col))
  26. for pos, file, lineno, col in results:
  27. loc = d.getloc(pos)
  28. self.assertEqual(loc.path, file, "data file offset %i" % pos)
  29. self.assertEqual(loc.line, lineno, "data line offset %i" % pos)
  30. self.assertEqual(loc.column, col, "data col offset %i" % pos)
  31. multitest(DataTest)
  32. class LineEnumeratorTest(TestBase):
  33. testdata = {
  34. 'simple': (
  35. 'Hello, world', [
  36. ('Hello, world', 1),
  37. ]
  38. ),
  39. 'multi': (
  40. 'Hello\nhappy \n\nworld\n', [
  41. ('Hello', 1),
  42. ('happy ', 2),
  43. ('', 3),
  44. ('world', 4),
  45. ('', 5),
  46. ]
  47. ),
  48. 'continuation': (
  49. 'Hello, \\\n world\nJellybeans!', [
  50. ('Hello, \\\n world', 1),
  51. ('Jellybeans!', 3),
  52. ]
  53. ),
  54. 'multislash': (
  55. 'Hello, \\\\\n world', [
  56. ('Hello, \\\\', 1),
  57. (' world', 2),
  58. ]
  59. )
  60. }
  61. def runSingle(self, s, lines):
  62. gotlines = [(d.s[d.lstart:d.lend], d.loc.line) for d in pymake.parser.enumeratelines(s, 'path')]
  63. self.assertEqual(gotlines, lines)
  64. multitest(LineEnumeratorTest)
  65. class IterTest(TestBase):
  66. testdata = {
  67. 'plaindata': (
  68. pymake.parser.iterdata,
  69. "plaindata # test\n",
  70. "plaindata # test\n"
  71. ),
  72. 'makecomment': (
  73. pymake.parser.itermakefilechars,
  74. "VAR = val # comment",
  75. "VAR = val "
  76. ),
  77. 'makeescapedcomment': (
  78. pymake.parser.itermakefilechars,
  79. "VAR = val \# escaped hash",
  80. "VAR = val # escaped hash"
  81. ),
  82. 'makeescapedslash': (
  83. pymake.parser.itermakefilechars,
  84. "VAR = val\\\\",
  85. "VAR = val\\\\",
  86. ),
  87. 'makecontinuation': (
  88. pymake.parser.itermakefilechars,
  89. "VAR = VAL \\\n continuation # comment \\\n continuation",
  90. "VAR = VAL continuation "
  91. ),
  92. 'makecontinuation2': (
  93. pymake.parser.itermakefilechars,
  94. "VAR = VAL \\ \\\n continuation",
  95. "VAR = VAL \\ continuation"
  96. ),
  97. 'makeawful': (
  98. pymake.parser.itermakefilechars,
  99. "VAR = VAL \\\\# comment\n",
  100. "VAR = VAL \\"
  101. ),
  102. 'command': (
  103. pymake.parser.itercommandchars,
  104. "echo boo # comment",
  105. "echo boo # comment",
  106. ),
  107. 'commandcomment': (
  108. pymake.parser.itercommandchars,
  109. "echo boo \# comment",
  110. "echo boo \# comment",
  111. ),
  112. 'commandcontinue': (
  113. pymake.parser.itercommandchars,
  114. "echo boo # \\\n\t command 2",
  115. "echo boo # \\\n command 2"
  116. ),
  117. }
  118. def runSingle(self, ifunc, idata, expected):
  119. d = pymake.parser.Data.fromstring(idata, 'IterTest data')
  120. it = pymake.parser._alltokens.finditer(d.s, 0, d.lend)
  121. actual = ''.join( [c for c, t, o, oo in ifunc(d, 0, ('dummy-token',), it)] )
  122. self.assertEqual(actual, expected)
  123. if ifunc == pymake.parser.itermakefilechars:
  124. print "testing %r" % expected
  125. self.assertEqual(pymake.parser.flattenmakesyntax(d, 0), expected)
  126. multitest(IterTest)
  127. # 'define': (
  128. # pymake.parser.iterdefinechars,
  129. # "endef",
  130. # ""
  131. # ),
  132. # 'definenesting': (
  133. # pymake.parser.iterdefinechars,
  134. # """define BAR # comment
  135. #random text
  136. #endef not what you think!
  137. #endef # comment is ok\n""",
  138. # """define BAR # comment
  139. #random text
  140. #endef not what you think!"""
  141. # ),
  142. # 'defineescaped': (
  143. # pymake.parser.iterdefinechars,
  144. # """value \\
  145. #endef
  146. #endef\n""",
  147. # "value endef"
  148. # ),
  149. class MakeSyntaxTest(TestBase):
  150. # (string, startat, stopat, stopoffset, expansion
  151. testdata = {
  152. 'text': ('hello world', 0, (), None, ['hello world']),
  153. 'singlechar': ('hello $W', 0, (), None,
  154. ['hello ',
  155. {'type': 'VariableRef',
  156. '.vname': ['W']}
  157. ]),
  158. 'stopat': ('hello: world', 0, (':', '='), 6, ['hello']),
  159. 'funccall': ('h $(flavor FOO)', 0, (), None,
  160. ['h ',
  161. {'type': 'FlavorFunction',
  162. '[0]': ['FOO']}
  163. ]),
  164. 'escapedollar': ('hello$$world', 0, (), None, ['hello$world']),
  165. 'varref': ('echo $(VAR)', 0, (), None,
  166. ['echo ',
  167. {'type': 'VariableRef',
  168. '.vname': ['VAR']}
  169. ]),
  170. 'dynamicvarname': ('echo $($(VARNAME):.c=.o)', 0, (':',), None,
  171. ['echo ',
  172. {'type': 'SubstitutionRef',
  173. '.vname': [{'type': 'VariableRef',
  174. '.vname': ['VARNAME']}
  175. ],
  176. '.substfrom': ['.c'],
  177. '.substto': ['.o']}
  178. ]),
  179. 'substref': (' $(VAR:VAL) := $(VAL)', 0, (':=', '+=', '=', ':'), 15,
  180. [' ',
  181. {'type': 'VariableRef',
  182. '.vname': ['VAR:VAL']},
  183. ' ']),
  184. 'vadsubstref': (' $(VAR:VAL) = $(VAL)', 15, (), None,
  185. [{'type': 'VariableRef',
  186. '.vname': ['VAL']},
  187. ]),
  188. }
  189. def compareRecursive(self, actual, expected, path):
  190. self.assertEqual(len(actual), len(expected),
  191. "compareRecursive: %s %r" % (path, actual))
  192. for i in xrange(0, len(actual)):
  193. ipath = path + [i]
  194. a, isfunc = actual[i]
  195. e = expected[i]
  196. if isinstance(e, str):
  197. self.assertEqual(a, e, "compareRecursive: %s" % (ipath,))
  198. else:
  199. self.assertEqual(type(a), getattr(pymake.functions, e['type']),
  200. "compareRecursive: %s" % (ipath,))
  201. for k, v in e.iteritems():
  202. if k == 'type':
  203. pass
  204. elif k[0] == '[':
  205. item = int(k[1:-1])
  206. proppath = ipath + [item]
  207. self.compareRecursive(a[item], v, proppath)
  208. elif k[0] == '.':
  209. item = k[1:]
  210. proppath = ipath + [item]
  211. self.compareRecursive(getattr(a, item), v, proppath)
  212. else:
  213. raise Exception("Unexpected property at %s: %s" % (ipath, k))
  214. def runSingle(self, s, startat, stopat, stopoffset, expansion):
  215. d = pymake.parser.Data.fromstring(s, pymake.parserdata.Location('testdata', 1, 0))
  216. a, t, offset = pymake.parser.parsemakesyntax(d, startat, stopat, pymake.parser.itermakefilechars)
  217. self.compareRecursive(a, expansion, [])
  218. self.assertEqual(offset, stopoffset)
  219. multitest(MakeSyntaxTest)
  220. class VariableTest(TestBase):
  221. testdata = """
  222. VAR = value
  223. VARNAME = TESTVAR
  224. $(VARNAME) = testvalue
  225. $(VARNAME:VAR=VAL) = moretesting
  226. IMM := $(VARNAME) # this is a comment
  227. MULTIVAR = val1 \\
  228. val2
  229. VARNAME = newname
  230. """
  231. expected = {'VAR': 'value',
  232. 'VARNAME': 'newname',
  233. 'TESTVAR': 'testvalue',
  234. 'TESTVAL': 'moretesting',
  235. 'IMM': 'TESTVAR ',
  236. 'MULTIVAR': 'val1 val2',
  237. 'UNDEF': None}
  238. def runTest(self):
  239. stmts = pymake.parser.parsestring(self.testdata, 'VariableTest')
  240. m = pymake.data.Makefile()
  241. stmts.execute(m)
  242. for k, v in self.expected.iteritems():
  243. flavor, source, val = m.variables.get(k)
  244. if val is None:
  245. self.assertEqual(val, v, 'variable named %s' % k)
  246. else:
  247. self.assertEqual(val.resolvestr(m, m.variables), v, 'variable named %s' % k)
  248. class SimpleRuleTest(TestBase):
  249. testdata = """
  250. VAR = value
  251. TSPEC = dummy
  252. all: TSPEC = myrule
  253. all:: test test2 $(VAR)
  254. echo "Hello, $(TSPEC)"
  255. %.o: %.c
  256. $(CC) -o $@ $<
  257. """
  258. def runTest(self):
  259. stmts = pymake.parser.parsestring(self.testdata, 'SimpleRuleTest')
  260. m = pymake.data.Makefile()
  261. stmts.execute(m)
  262. self.assertEqual(m.defaulttarget, 'all', "Default target")
  263. self.assertTrue(m.hastarget('all'), "Has 'all' target")
  264. target = m.gettarget('all')
  265. rules = target.rules
  266. self.assertEqual(len(rules), 1, "Number of rules")
  267. prereqs = rules[0].prerequisites
  268. self.assertEqual(prereqs, ['test', 'test2', 'value'], "Prerequisites")
  269. commands = rules[0].commands
  270. self.assertEqual(len(commands), 1, "Number of commands")
  271. expanded = commands[0].resolvestr(m, target.variables)
  272. self.assertEqual(expanded, 'echo "Hello, myrule"')
  273. irules = m.implicitrules
  274. self.assertEqual(len(irules), 1, "Number of implicit rules")
  275. irule = irules[0]
  276. self.assertEqual(len(irule.targetpatterns), 1, "%.o target pattern count")
  277. self.assertEqual(len(irule.prerequisites), 1, "%.o prerequisite count")
  278. self.assertEqual(irule.targetpatterns[0].match('foo.o'), 'foo', "%.o stem")
  279. if __name__ == '__main__':
  280. logging.basicConfig(level=logging.DEBUG)
  281. unittest.main()