2 #---------------------------------------------------------------------------
3 # valdiag.py - Validate diagnostic messages from SDCC/GCC
4 # Written By - Erik Petrich . epetrich@users.sourceforge.net (2003)
6 # This program is free software; you can redistribute it and/or modify it
7 # under the terms of the GNU General Public License as published by the
8 # Free Software Foundation; either version 2, or (at your option) any
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 # In other words, you are welcome to use, share and improve this program.
21 # You are forbidden to forbid anyone else to use, share and improve
22 # what you give them. Help stamp out software-hoarding!
23 #---------------------------------------------------------------------------
25 import sys, string, os, popen2, re
42 "CC":"../../bin/sdcc",
43 "CCFLAGS":"-c -m{port}",
52 "code not generated.*due to previous errors",
53 "unreferenced function argument"
72 "flags":"--model-large",
74 "SDCC_MODEL_LARGE":"1"
80 "flags":"--stack-auto",
112 def evalQualifier(expr):
114 tokens = re.split("([^0-9A-Za-z_])", expr)
115 for tokenindex in range(len(tokens)):
116 token = tokens[tokenindex]
117 if token in macrodefs:
118 tokens[tokenindex] = macrodefs[token]
119 elif token == "defined":
120 tokens[tokenindex] = ""
121 if tokens[tokenindex+2] in macrodefs:
122 tokens[tokenindex+2] = "1"
124 tokens[tokenindex+2] = "0"
126 if token[0]=="_" or token[0] in string.ascii_letters:
127 tokens[tokenindex] = "0"
128 expr = string.join(tokens,"")
129 expr = string.replace(expr,"&&"," and ");
130 expr = string.replace(expr,"||"," or ");
131 expr = string.replace(expr,"!"," not ");
134 def expandPyExpr(expr):
135 tokens = re.split("({|})", expr)
136 for tokenindex in range(1,len(tokens)):
137 if tokens[tokenindex-1]=="{":
138 tokens[tokenindex]=eval(tokens[tokenindex])
139 tokens[tokenindex-1]=""
140 tokens[tokenindex+1]=""
141 expandedExpr = string.join(tokens,"")
144 def addDefines(deflist):
145 for define in deflist.keys():
146 expandeddef = expandPyExpr(define)
147 macrodefs[expandeddef] = expandPyExpr(deflist[define])
149 def parseInputfile(inputfilename):
150 inputfile = open(inputfilename, "r")
155 # Find the test cases and tests in this file
156 for line in inputfile.readlines():
158 # See if a new testcase is being defined
159 p = string.find(line, "TEST")
161 testname = string.split(line[p:])[0]
162 if not testcases.has_key(testname):
163 testcases[testname] = {}
165 # See if a new test is being defined
166 for testtype in ["ERROR", "WARNING", "IGNORE"]:
167 p = string.find(line, testtype);
169 # Found a test definition
170 qualifier = string.strip(line[p+len(testtype):])
171 p = string.find(qualifier, "*/")
173 qualifier = string.strip(qualifier[:p])
174 if len(qualifier)==0:
176 qualifier = evalQualifier(qualifier)
178 if not linenumber in testcases[testname]:
179 testcases[testname][linenumber]=[]
180 testcases[testname][linenumber].append(testtype)
182 linenumber = linenumber + 1
187 def parseResults(output):
192 if string.count(line, "SIGSEG"):
193 results[0] = ["FAULT", string.strip(line)]
196 # look for something of the form:
197 # filename:line:message
198 msg = string.split(line,":",2)
199 if len(msg)<3: continue
200 if msg[0]!=inputfilename: continue
201 if len(msg[1])==0: continue
202 if not msg[1][0] in string.digits: continue
204 # it's in the right form; parse it
205 linenumber = int(msg[1])
207 uppermsg = string.upper(msg[2])
208 if string.count(uppermsg,"ERROR"):
210 if string.count(uppermsg,"WARNING"):
212 msgtext = string.strip(msg[2])
214 for ignoreExpr in ignoreExprList:
215 if re.search(ignoreExpr,msgtext)!=None:
218 results[linenumber]=[msgtype,string.strip(msg[2])]
222 print "Usage: test testmode cfile [objectfile]"
223 print "Choices for testmode are:"
224 for testmodename in testmodes.keys():
225 print " %s" % testmodename
232 testmodename = sys.argv[1]
233 if not testmodename in testmodes:
234 print "Unknown test mode '%s'" % testmodename
237 testmode = testmodes[testmodename]
238 compilermode = testmode["compiler"]
239 port = expandPyExpr(testmode["port"])
240 cc = expandPyExpr(compilermode["CC"])
241 ccflags = expandPyExpr(compilermode["CCFLAGS"])
242 if "flags" in testmode:
243 ccflags = string.join([ccflags,expandPyExpr(testmode["flags"])])
245 if "CCOUTPUT" in compilermode:
246 ccflags = string.join([ccflags,expandPyExpr(compilermode["CCOUTPUT"]),sys.argv[3]])
247 if "defined" in compilermode:
248 addDefines(compilermode["defined"])
249 if "defined" in testmode:
250 addDefines(testmode["defined"])
251 if "ignoremsg" in compilermode:
252 ignoreExprList = compilermode["ignoremsg"]
256 inputfilename = sys.argv[2]
258 testcases = parseInputfile(inputfilename)
260 print "Unable to read file '%s'" % inputfilename
263 casecount = len(testcases.keys())
267 for testname in testcases.keys():
268 ccdef = compilermode["CCDEF"]+testname
269 cmd = string.join([cc,ccflags,ccdef,inputfilename])
272 spawn = popen2.Popen4(cmd)
274 output = spawn.fromchild.readlines()
276 results = parseResults(output)
278 if len(testcases[testname])==0:
279 testcount = testcount + 1 #implicit test for no errors
281 # Go through the tests of this case and make sure
282 # the compiler gave a diagnostic
283 for checkline in testcases[testname].keys():
284 testcount = testcount + 1
285 if checkline in results:
286 if "IGNORE" in testcases[testname][checkline]:
287 testcount = testcount - 1 #this isn't really a test
288 del results[checkline]
290 for wanted in testcases[testname][checkline]:
291 if not wanted=="IGNORE":
292 print "--- FAIL: expected %s" % wanted,
293 print "at %s:%d" % (inputfilename, checkline)
294 failurecount = failurecount + 1
296 # Output any unexpected diagnostics
297 for checkline in results.keys():
298 print '--- FAIL: unexpected message "%s" ' % results[checkline][1],
299 print "at %s:%d" % (inputfilename, checkline)
300 failurecount = failurecount + 1
303 print "--- Summary: %d/%d/%d: " % (failurecount, testcount, casecount),
304 print "%d failed of %d tests in %d cases." % (failurecount, testcount, casecount)