213 lines
6.3 KiB
Python
213 lines
6.3 KiB
Python
#!/usr/bin/python
|
|
|
|
import re
|
|
import os
|
|
import sys
|
|
import glob
|
|
import argparse
|
|
|
|
class tpp:
|
|
|
|
def __init__(self, fname):
|
|
self.data = {'name':'', 'ifdef':'', 'main':'', 'body':'', 'num':''}
|
|
self.info = []
|
|
self.c_file = None
|
|
self.line_num = 0
|
|
self.fname = fname
|
|
|
|
def c_write(self, line):
|
|
if not self.c_file: self.c_write(line)
|
|
else: self.c_file.write(line + '\n')
|
|
|
|
def test_hdr(self, line):
|
|
self.c_write(line);
|
|
|
|
def test_test(self, name):
|
|
self.data['name'] = name
|
|
|
|
def test_if(self, line):
|
|
if self.data['name']: self.test_body(line)
|
|
elif self.data['ifdef']:
|
|
sys.stderr.write('ERROR: nested ifdef not allowed in file %s at line %d\n' % (self.fname, self.line_num))
|
|
sys.exit(1);
|
|
else: self.data['ifdef'] = line.strip()
|
|
|
|
def test_endif(self, line):
|
|
if self.data['name']: self.test_body(line)
|
|
|
|
def test_open_brace(self):
|
|
self.data['body'] = ''
|
|
|
|
def test_main(self, main):
|
|
self.data['main'] = main
|
|
self.c_write('''
|
|
extern void %(main)s(TestInfo*);
|
|
#define %(main)s_NUMB 0
|
|
static const char %(main)s_NAME [] = "%(main)s";
|
|
''' % self.data)
|
|
self.data['name'] = ''
|
|
self.data['ifdef'] = ''
|
|
self.data['body'] = ''
|
|
self.data['num'] = ''
|
|
|
|
def test_close_brace(self):
|
|
if not self.data['name']: return
|
|
self.c_write('')
|
|
if self.data['ifdef']: self.c_write(self.data['ifdef'])
|
|
self.data['num'] = str(len(re.findall(r'^\s+ASSERT', self.data['body'], flags=re.MULTILINE)))
|
|
self.c_write('''#define %(name)s_NUMB %(num)s
|
|
static const char %(name)s_NAME [] = "%(name)s";
|
|
static void %(name)s()
|
|
{
|
|
noteTestMain(__FILE__, __LINE__, %(name)s_NAME);
|
|
{
|
|
%(body)s\t}
|
|
breakOnSubDone(__FILE__, __LINE__, %(name)s_NAME);
|
|
}''' % self.data)
|
|
|
|
if self.data['ifdef']: self.c_write('#endif /* %(ifdef)s */\n' % self.data)
|
|
self.info += [(self.data['name'], self.data['ifdef'])]
|
|
|
|
# clear this test
|
|
self.data['name'] = ''
|
|
self.data['ifdef'] = ''
|
|
self.data['body'] = ''
|
|
|
|
def test_body(self, line):
|
|
if self.data['name']:
|
|
# add an indentation
|
|
if line[0] == '\t': line = '\t' + line
|
|
self.data['body'] += line
|
|
else:
|
|
self.c_write(line)
|
|
|
|
def test_fi(self):
|
|
self.c_write('static FunctionInfo fi[] = {')
|
|
|
|
if self.data['main']: self.c_write('\t{ %(main)s_NAME, (testFuncPtr) &%(main)s, %(main)s_NUMB },' % self.data)
|
|
|
|
for (e, f) in self.info:
|
|
if f: self.c_write(f)
|
|
self.c_write('\t{ %s_NAME, (testFuncPtr) &%s, %s_NUMB },' % (e, e, e))
|
|
if f: self.c_write('#endif /* %s */' % f)
|
|
|
|
self.c_write('\t{ 0, 0, 0 }')
|
|
self.c_write('};')
|
|
|
|
# This is boilerplate, supplying the main, etc
|
|
|
|
def test_boilerplate(self):
|
|
self.c_write('''
|
|
static GroupInfo Info = {
|
|
{\'a\', \'B\', \'c\', \'D\', \'e\', \'f\', \'G\', \'h\'},
|
|
fi
|
|
};
|
|
|
|
/* Function exists to make sure that the GroupInfo structure does not
|
|
* get optimized away.
|
|
**/
|
|
|
|
GroupInfo *%(main)s_Force() {
|
|
return &Info;
|
|
}
|
|
|
|
void %(main)s(TestInfo* not_used) {
|
|
i4 i = 0;
|
|
int numTest = 0;
|
|
|
|
TestInfo_reset();
|
|
|
|
for (i = 1; Info.funcTable[i].name; i++) Info.funcTable[i].func();
|
|
|
|
breakOnDone(__FILE__, __LINE__, %(main)s_NAME);
|
|
}''' % self.data)
|
|
|
|
def match(self, rexp, line):
|
|
self.m = re.match(rexp, line)
|
|
return self.m
|
|
|
|
# parse the test file
|
|
|
|
def parse(self):
|
|
|
|
if not self.fname.endswith('.test'):
|
|
sys.stderr.write('ERROR: filename %s must end with .test\n' % self.fname)
|
|
sys.exit(1);
|
|
|
|
self.c_file = open(re.sub('[.]test', '.c', self.fname), "w")
|
|
|
|
self.line_num = 0
|
|
for line in open(self.fname):
|
|
self.line_num += 1
|
|
if self.match(r'TEST\s+(\w*).*', line):
|
|
self.test_test(self.m.group(1))
|
|
elif self.match(r'(?:#include)\s+.*', line):
|
|
self.test_hdr(line)
|
|
elif self.match(r'(?:#if|#ifdef)\s+.*', line):
|
|
self.test_if(line)
|
|
elif self.match(r'#endif.*', line):
|
|
self.test_endif(line)
|
|
elif self.match(r'{\s*(.*)', line):
|
|
self.test_open_brace()
|
|
elif self.match(r'MAIN\s+(\w*).*', line):
|
|
self.test_main(self.m.group(1))
|
|
elif self.match(r'}.*', line):
|
|
self.test_close_brace()
|
|
else:
|
|
self.test_body(line)
|
|
|
|
self.test_fi()
|
|
self.test_boilerplate()
|
|
self.c_file.close()
|
|
self.c_file = False
|
|
|
|
# the ENTRY function will contain a call to all of the MAIN
|
|
# functions found in .test files in the current directory
|
|
|
|
def create_entry(self):
|
|
if os.path.exists(self.fname):
|
|
sys.stderr.write('WARNING: entry filename %s exists\n' % self.fname)
|
|
return;
|
|
|
|
extern_lines = []
|
|
main_lines = []
|
|
for tname in glob.glob(re.sub(r'[^/]*$', '*.test', self.fname)):
|
|
with open(tname) as tfile:
|
|
for line in tfile:
|
|
if self.match(r'MAIN\s+(\w*).*', line):
|
|
extern_lines.append('\textern void %s(TestInfo* not_used);' % self.m.group(1))
|
|
main_lines.append('\t%s(&info);' % self.m.group(1))
|
|
self.c_file = open(self.fname, "w")
|
|
self.c_write('#include "pcode_test.h"')
|
|
self.c_write('')
|
|
#for l in extern_lines:
|
|
# self.c_write(l)
|
|
self.c_write('void main(void) {')
|
|
self.c_write('\tTestInfo info;')
|
|
#for l in main_lines:
|
|
# self.c_write(l)
|
|
self.c_write('#ifdef BUILD_EXE')
|
|
self.c_write('\texit(0);')
|
|
self.c_write('#endif')
|
|
self.c_write('}')
|
|
self.c_file.close()
|
|
self.c_file = False
|
|
|
|
|
|
parser = argparse.ArgumentParser(description='Precompile test file',
|
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
|
|
|
parser.add_argument('test_file', nargs='*', help='Test file to preprocess, must end with .test')
|
|
parser.add_argument('--entry', default='', help='Create file ENTRY contianing a main function that calls all MAIN functions')
|
|
|
|
sys.argv.pop(0)
|
|
args = parser.parse_args(sys.argv)
|
|
|
|
if args.test_file:
|
|
for test_file in args.test_file:
|
|
tpp(test_file).parse()
|
|
|
|
if args.entry:
|
|
tpp(args.entry).create_entry()
|
|
|