#!/usr/bin/python """Extract test cases information from Cppcheck test file""" import sys import re class Extract: """Read Cppcheck test file and create data representation""" # array that stores all the test cases nodes = [] def parseFile(self,filename): """parse test file and add info to the nodes variable""" name = '[0-9a-zA-Z_]+' string = '\\"(.+)\\"' testclass = None functionName = None fin = open(filename, 'r') for line in fin: # testclass starts res = re.match('class ('+name+')', line) if res != None: testclass = res.group(1) # end of testclass if re.match('};', line) != None: testclass = None # function start res = re.match('\\s+void ('+name+')\\(\\)', line) if res != None: functionName = res.group(1) elif re.match('\\s+}', line) != None: functionName = None if functionName == None: continue # check res = re.match('\s+check\('+string, line) if res != None: code = res.group(1) # code.. res = re.match('\\s+'+string, line) if res != None: code = code + res.group(1) # assert res = re.match('\\s+ASSERT_EQUALS\\(\\"(.*)\\"', line) if res != None and len(code) > 10: node = { 'testclass':testclass, 'functionName':functionName, 'code':code, 'expected':res.group(1) } self.nodes.append(node) code = '' # close test file fin.close() def strtoxml(s): """Convert string to xml/html format""" return s.replace('&','&').replace('"', '"').replace('<','<').replace('>','>') def trimname(name): """Trim test name. Trailing underscore and digits are removed""" while name[-1].isdigit(): name = name[:-1] if name[-1] == '_': name = name[:-1] return name def writeHtmlFile(nodes, functionName, filename, errorsOnly): """Write html file for a function name""" fout = open(filename, 'w') fout.write('\n') fout.write('\n') fout.write(' \n') fout.write('\n') fout.write('\n') fout.write('Home -- ') if errorsOnly: fout.write('All test cases') else: fout.write('Error test cases') fout.write('

') testclass = None num = 0 for node in nodes: if errorsOnly and node['expected']=='': continue if trimname(node['functionName']) == functionName: num = num + 1 if not testclass: testclass = node['testclass'] fout.write('

' + node['testclass'] + '::' + functionName + '

') fout.write('\n') fout.write(' \n') fout.write(' ') fout.write('') fout.write('') fout.write('\n') if testclass != None: fout.write('
NrCodeExpected
' + str(num) + '
' + strtoxml(node['code']).replace('\\n', '\n') + '
' + strtoxml(node['expected']).replace('\\n', '
') + '
\n'); fout.write('\n') fout.close() if len(sys.argv) <= 1 or '--help' in sys.argv: print 'Extract test cases from test file' print 'Syntax: extracttests.py [--html=folder] [--xml] [--code=folder] path/testfile.cpp' sys.exit(0) # parse command line xml = False filename = None htmldir = None codedir = None for arg in sys.argv[1:]: if arg == '--xml': xml = True elif arg.startswith('--html='): htmldir = arg[7:] elif arg.startswith('--code='): codedir = arg[7:] elif arg.endswith('.cpp'): filename = arg else: print 'Invalid option: ' + arg sys.exit(1) # extract test cases if filename != None: # parse test file e = Extract() e.parseFile(filename) # generate output if xml: print '' print '' count = 0 for node in e.nodes: s = ' ' elif htmldir != None: if not htmldir.endswith('/'): htmldir += '/' findex = open(htmldir + 'index.htm', 'w') findex.write('\n') findex.write('\n') findex.write(' \n') findex.write('\n') findex.write('\n') findex.write('

' + filename + '

\n') functionNames = [] for node in e.nodes: functionname = trimname(node['functionName']) if not functionname in functionNames: functionNames.append(functionname) functionNames.sort() findex.write('\n') findex.write(' \n') for functionname in functionNames: findex.write(' ') numall = 0 numerr = 0 for node in e.nodes: if trimname(node['functionName']) == functionname: numall = numall + 1 if node['expected'] != '': numerr = numerr + 1 if numerr == 0: findex.write('') else: findex.write('') findex.write('') findex.write('\n') findex.write('
NameErrorsAll
'+functionname+'
0
' + str(numerr) + '
' + str(numall) + '
\n') findex.write('') findex.close() # create files for each functionName for functionName in functionNames: writeHtmlFile(e.nodes, functionName, htmldir + 'errors-' + functionName + '.htm', True) writeHtmlFile(e.nodes, functionName, htmldir + 'all-' + functionName + '.htm', False) elif codedir: testnum = 0 if not codedir.endswith('/'): codedir = codedir + '/' errors = open(codedir+'errors.txt', 'w') for node in e.nodes: testnum = testnum + 1 functionName = node['functionName'] code = node['code'] code = code.replace('\\n', '\n') code = code.replace('\\"', '"') expected = node['expected'] filename = '0000' + str(testnum) + '-' filename = filename[-4:] filename += functionName + '.cpp' # source code fout = open(codedir+filename,'w') fout.write(code) fout.close() # write 'expected' to errors.txt expected = expected.replace('\\n', '\n') expected = expected.replace('\\"', '"') if expected.startswith('[test.cpp:'): expected='['+filename+expected[9:] elif expected.startswith('[test.c:'): expected='['+filename+expected[8:] if expected != '': errors.write(expected) errors.close() else: for node in e.nodes: print node['functionName']