build/pymake/tests/parsertests.py

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

mercurial