testyacc.py (2632:1bb2f91485ea) testyacc.py (6498:e21e9ab5fad0)
1#!/usr/local/bin
2# ----------------------------------------------------------------------
3# testyacc.py
1# testyacc.py
4#
5# Run tests for the yacc module
6# ----------------------------------------------------------------------
7
2
8import sys,os,glob
3import unittest
4try:
5 import StringIO
6except ImportError:
7 import io as StringIO
9
8
10if len(sys.argv) < 2:
11 print "Usage: python testyacc.py directory"
12 raise SystemExit
9import sys
10import os
13
11
14dirname = None
15make = 0
12sys.path.insert(0,"..")
13sys.tracebacklimit = 0
16
14
17for o in sys.argv[1:]:
18 if o == '-make':
19 make = 1
20 else:
21 dirname = o
22 break
15import ply.yacc
23
16
24if not dirname:
25 print "Usage: python testyacc.py [-make] directory"
26 raise SystemExit
17def check_expected(result,expected):
18 resultlines = []
19 for line in result.splitlines():
20 if line.startswith("WARNING: "):
21 line = line[9:]
22 elif line.startswith("ERROR: "):
23 line = line[7:]
24 resultlines.append(line)
27
25
28f = glob.glob("%s/%s" % (dirname,"yacc_*.py"))
26 expectedlines = expected.splitlines()
27 if len(resultlines) != len(expectedlines):
28 return False
29 for rline,eline in zip(resultlines,expectedlines):
30 if not rline.endswith(eline):
31 return False
32 return True
29
33
30print "**** Running tests for yacc ****"
34def run_import(module):
35 code = "import "+module
36 exec(code)
37 del sys.modules[module]
38
39# Tests related to errors and warnings when building parsers
40class YaccErrorWarningTests(unittest.TestCase):
41 def setUp(self):
42 sys.stderr = StringIO.StringIO()
43 sys.stdout = StringIO.StringIO()
44 try:
45 os.remove("parsetab.py")
46 os.remove("parsetab.pyc")
47 except OSError:
48 pass
49
50 def tearDown(self):
51 sys.stderr = sys.__stderr__
52 sys.stdout = sys.__stdout__
53 def test_yacc_badargs(self):
54 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_badargs")
55 result = sys.stderr.getvalue()
56 self.assert_(check_expected(result,
57 "yacc_badargs.py:23: Rule 'p_statement_assign' has too many arguments\n"
58 "yacc_badargs.py:27: Rule 'p_statement_expr' requires an argument\n"
59 ))
60 def test_yacc_badid(self):
61 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_badid")
62 result = sys.stderr.getvalue()
63 self.assert_(check_expected(result,
64 "yacc_badid.py:32: Illegal name 'bad&rule' in rule 'statement'\n"
65 "yacc_badid.py:36: Illegal rule name 'bad&rule'\n"
66 ))
31
67
32for t in f:
33 name = t[:-3]
34 print "Testing %-32s" % name,
35 os.system("rm -f %s/parsetab.*" % dirname)
36 if make:
37 if not os.path.exists("%s.exp" % name):
38 os.system("python %s.py >%s.exp 2>&1" % (name,name))
39 passed = 1
40 else:
41 os.system("python %s.py >%s.out 2>&1" % (name,name))
42 a = os.system("diff %s.out %s.exp >%s.dif" % (name,name,name))
43 if a == 0:
44 passed = 1
45 else:
46 passed = 0
68 def test_yacc_badprec(self):
69 try:
70 run_import("yacc_badprec")
71 except ply.yacc.YaccError:
72 result = sys.stderr.getvalue()
73 self.assert_(check_expected(result,
74 "precedence must be a list or tuple\n"
75 ))
76 def test_yacc_badprec2(self):
77 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_badprec2")
78 result = sys.stderr.getvalue()
79 self.assert_(check_expected(result,
80 "Bad precedence table\n"
81 ))
47
82
48 if passed:
49 print "Passed"
50 else:
51 print "Failed. See %s.dif" % name
83 def test_yacc_badprec3(self):
84 run_import("yacc_badprec3")
85 result = sys.stderr.getvalue()
86 self.assert_(check_expected(result,
87 "Precedence already specified for terminal 'MINUS'\n"
88 "Generating LALR tables\n"
52
89
90 ))
91
92 def test_yacc_badrule(self):
93 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_badrule")
94 result = sys.stderr.getvalue()
95 self.assert_(check_expected(result,
96 "yacc_badrule.py:24: Syntax error. Expected ':'\n"
97 "yacc_badrule.py:28: Syntax error in rule 'statement'\n"
98 "yacc_badrule.py:33: Syntax error. Expected ':'\n"
99 "yacc_badrule.py:42: Syntax error. Expected ':'\n"
100 ))
53
101
102 def test_yacc_badtok(self):
103 try:
104 run_import("yacc_badtok")
105 except ply.yacc.YaccError:
106 result = sys.stderr.getvalue()
107 self.assert_(check_expected(result,
108 "tokens must be a list or tuple\n"))
54
109
110 def test_yacc_dup(self):
111 run_import("yacc_dup")
112 result = sys.stderr.getvalue()
113 self.assert_(check_expected(result,
114 "yacc_dup.py:27: Function p_statement redefined. Previously defined on line 23\n"
115 "Token 'EQUALS' defined, but not used\n"
116 "There is 1 unused token\n"
117 "Generating LALR tables\n"
55
118
119 ))
120 def test_yacc_error1(self):
121 try:
122 run_import("yacc_error1")
123 except ply.yacc.YaccError:
124 result = sys.stderr.getvalue()
125 self.assert_(check_expected(result,
126 "yacc_error1.py:61: p_error() requires 1 argument\n"))
56
127
128 def test_yacc_error2(self):
129 try:
130 run_import("yacc_error2")
131 except ply.yacc.YaccError:
132 result = sys.stderr.getvalue()
133 self.assert_(check_expected(result,
134 "yacc_error2.py:61: p_error() requires 1 argument\n"))
57
135
136 def test_yacc_error3(self):
137 try:
138 run_import("yacc_error3")
139 except ply.yacc.YaccError:
140 e = sys.exc_info()[1]
141 result = sys.stderr.getvalue()
142 self.assert_(check_expected(result,
143 "'p_error' defined, but is not a function or method\n"))
144
145 def test_yacc_error4(self):
146 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_error4")
147 result = sys.stderr.getvalue()
148 self.assert_(check_expected(result,
149 "yacc_error4.py:62: Illegal rule name 'error'. Already defined as a token\n"
150 ))
151
152 def test_yacc_inf(self):
153 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_inf")
154 result = sys.stderr.getvalue()
155 self.assert_(check_expected(result,
156 "Token 'NUMBER' defined, but not used\n"
157 "There is 1 unused token\n"
158 "Infinite recursion detected for symbol 'statement'\n"
159 "Infinite recursion detected for symbol 'expression'\n"
160 ))
161 def test_yacc_literal(self):
162 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_literal")
163 result = sys.stderr.getvalue()
164 self.assert_(check_expected(result,
165 "yacc_literal.py:36: Literal token '**' in rule 'expression' may only be a single character\n"
166 ))
167 def test_yacc_misplaced(self):
168 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_misplaced")
169 result = sys.stderr.getvalue()
170 self.assert_(check_expected(result,
171 "yacc_misplaced.py:32: Misplaced '|'\n"
172 ))
58
173
174 def test_yacc_missing1(self):
175 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_missing1")
176 result = sys.stderr.getvalue()
177 self.assert_(check_expected(result,
178 "yacc_missing1.py:24: Symbol 'location' used, but not defined as a token or a rule\n"
179 ))
180
181 def test_yacc_nested(self):
182 run_import("yacc_nested")
183 result = sys.stdout.getvalue()
184 self.assert_(check_expected(result,
185 "A\n"
186 "A\n"
187 "A\n",
188 ))
189
190 def test_yacc_nodoc(self):
191 run_import("yacc_nodoc")
192 result = sys.stderr.getvalue()
193 self.assert_(check_expected(result,
194 "yacc_nodoc.py:27: No documentation string specified in function 'p_statement_expr' (ignored)\n"
195 "Generating LALR tables\n"
196 ))
197
198 def test_yacc_noerror(self):
199 run_import("yacc_noerror")
200 result = sys.stderr.getvalue()
201 self.assert_(check_expected(result,
202 "no p_error() function is defined\n"
203 "Generating LALR tables\n"
204 ))
205
206 def test_yacc_nop(self):
207 run_import("yacc_nop")
208 result = sys.stderr.getvalue()
209 self.assert_(check_expected(result,
210 "yacc_nop.py:27: Possible grammar rule 'statement_expr' defined without p_ prefix\n"
211 "Generating LALR tables\n"
212 ))
213
214 def test_yacc_notfunc(self):
215 run_import("yacc_notfunc")
216 result = sys.stderr.getvalue()
217 self.assert_(check_expected(result,
218 "'p_statement_assign' not defined as a function\n"
219 "Token 'EQUALS' defined, but not used\n"
220 "There is 1 unused token\n"
221 "Generating LALR tables\n"
222 ))
223 def test_yacc_notok(self):
224 try:
225 run_import("yacc_notok")
226 except ply.yacc.YaccError:
227 result = sys.stderr.getvalue()
228 self.assert_(check_expected(result,
229 "No token list is defined\n"))
230
231 def test_yacc_rr(self):
232 run_import("yacc_rr")
233 result = sys.stderr.getvalue()
234 self.assert_(check_expected(result,
235 "Generating LALR tables\n"
236 "1 reduce/reduce conflict\n"
237 "reduce/reduce conflict in state 15 resolved using rule (statement -> NAME EQUALS NUMBER)\n"
238 "rejected rule (expression -> NUMBER) in state 15\n"
239
240 ))
241
242 def test_yacc_rr_unused(self):
243 run_import("yacc_rr_unused")
244 result = sys.stderr.getvalue()
245 self.assert_(check_expected(result,
246 "no p_error() function is defined\n"
247 "Generating LALR tables\n"
248 "3 reduce/reduce conflicts\n"
249 "reduce/reduce conflict in state 1 resolved using rule (rule3 -> A)\n"
250 "rejected rule (rule4 -> A) in state 1\n"
251 "reduce/reduce conflict in state 1 resolved using rule (rule3 -> A)\n"
252 "rejected rule (rule5 -> A) in state 1\n"
253 "reduce/reduce conflict in state 1 resolved using rule (rule4 -> A)\n"
254 "rejected rule (rule5 -> A) in state 1\n"
255 "Rule (rule5 -> A) is never reduced\n"
256 ))
257
258 def test_yacc_simple(self):
259 run_import("yacc_simple")
260 result = sys.stderr.getvalue()
261 self.assert_(check_expected(result,
262 "Generating LALR tables\n"
263 ))
264 def test_yacc_sr(self):
265 run_import("yacc_sr")
266 result = sys.stderr.getvalue()
267 self.assert_(check_expected(result,
268 "Generating LALR tables\n"
269 "20 shift/reduce conflicts\n"
270 ))
271
272 def test_yacc_term1(self):
273 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_term1")
274 result = sys.stderr.getvalue()
275 self.assert_(check_expected(result,
276 "yacc_term1.py:24: Illegal rule name 'NUMBER'. Already defined as a token\n"
277 ))
278
279 def test_yacc_unused(self):
280 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_unused")
281 result = sys.stderr.getvalue()
282 self.assert_(check_expected(result,
283 "yacc_unused.py:62: Symbol 'COMMA' used, but not defined as a token or a rule\n"
284 "Symbol 'COMMA' is unreachable\n"
285 "Symbol 'exprlist' is unreachable\n"
286 ))
287 def test_yacc_unused_rule(self):
288 run_import("yacc_unused_rule")
289 result = sys.stderr.getvalue()
290 self.assert_(check_expected(result,
291 "yacc_unused_rule.py:62: Rule 'integer' defined, but not used\n"
292 "There is 1 unused rule\n"
293 "Symbol 'integer' is unreachable\n"
294 "Generating LALR tables\n"
295 ))
296
297 def test_yacc_uprec(self):
298 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_uprec")
299 result = sys.stderr.getvalue()
300 print repr(result)
301 self.assert_(check_expected(result,
302 "yacc_uprec.py:37: Nothing known about the precedence of 'UMINUS'\n"
303 ))
304
305 def test_yacc_uprec2(self):
306 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_uprec2")
307 result = sys.stderr.getvalue()
308 self.assert_(check_expected(result,
309 "yacc_uprec2.py:37: Syntax error. Nothing follows %prec\n"
310 ))
311
312 def test_yacc_prec1(self):
313 self.assertRaises(ply.yacc.YaccError,run_import,"yacc_prec1")
314 result = sys.stderr.getvalue()
315 self.assert_(check_expected(result,
316 "Precedence rule 'left' defined for unknown symbol '+'\n"
317 "Precedence rule 'left' defined for unknown symbol '*'\n"
318 "Precedence rule 'left' defined for unknown symbol '-'\n"
319 "Precedence rule 'left' defined for unknown symbol '/'\n"
320 ))
321
322
323
324unittest.main()