1 from HTMLgen import TemplateDocument
2 import sys, re, tempfile, os
4 """See InstanceGenerator for a description of this file"""
7 # Directory that the generated files should be placed into
10 # Start of the test function table definition
11 testfuntableheader = """
12 static TESTFUNP _tests[] = {
16 # End of the test function table definition
17 testfuntablefooter = """\tNULL
21 # Code to generate the suite function
38 """Removes all white space from the start and the end of a string.
39 Like java.lang.String.trim"""
40 ret = chomp(re.sub(r'^\s+', '', a))
44 """Removes all white space from the end of a string.
46 return re.sub(r'\s+$', '', a)
49 """Creates a directory if it doesn't exist"""
50 if not os.path.isdir(path):
53 class InstanceGenerator:
54 """Test case iteration generator.
55 Takes the template given as the first argument, pulls out all the meta
56 iteration information, and generates an instance for each combination
57 of the names and types.
59 See doc/test_suite_spec.tex for more information on the template file
62 def __init__(self, inname):
64 # Initalise the replacements hash.
65 # Map of name to values.
66 self.replacements = { }
67 # Initalise the function list hash.
69 # Emit the suite wrapper into a temporary file
70 self.tmpname = tempfile.mktemp()
71 (self.basename, self.ext) = re.split(r'\.', self.inname)
72 self.ext = '.' + self.ext
74 def permute(self, basepath, keys, trans = {}):
75 """Permutes across all of the names. For each value, recursivly creates
76 a mangled form of the name, this value, and all the combinations of
77 the remaining values. At the tail of the recursion when one full
78 combination is built, generates an instance of the test case from
81 # End of the recursion.
82 # Set the runtime substitutions.
83 trans['testcase'] = basepath
84 # Create the instance from the template
85 T = TemplateDocument(self.tmpname)
86 T.substitutions = trans
87 T.write(basepath + self.ext)
89 # Pull off this key, then recursivly iterate through the rest.
91 for part in self.replacements[key]:
93 # Turn a empty string into something decent for a filename
96 # Remove any bad characters from the filename.
97 part = re.sub(r'\s+', r'_', part)
98 # The slice operator (keys[1:]) creates a copy of the list missing the
100 # Can't use '-' as a seperator due to the mcs51 assembler.
101 self.permute(basepath + '_' + key + '_' + part, keys[1:], trans)
103 def writetemplate(self):
104 """Given a template file and a temporary name writes out a verbatim copy
105 of the source file and adds the suite table and functions."""
106 fout = open(self.tmpname, 'w')
108 for line in self.lines:
111 # Emmit the suite table
112 fout.write(testfuntableheader)
114 for fun in self.functions:
115 # Turn the function definition into a pointer
116 fun = re.sub(r'\(\w+\)', '', fun)
117 fout.write("\t" + fun + ",\n")
119 fout.write(testfuntablefooter)
120 fout.write(testfunsuite);
125 """Read in all of the input file."""
126 fin = open(self.inname)
127 self.lines = fin.readlines()
131 # Start off in the header.
134 # Iterate over the source file and pull out the meta data.
135 for line in self.lines:
138 # If we are still in the header, see if this is a substitution line
140 # A substitution line has a ':' in it
141 if re.search(r':', line) != None:
142 # Split out the name from the values
143 (name, rawvalues) = re.split(r':', line)
144 # Split the values at the commas
145 values = re.split(r',', rawvalues)
149 # Trim all the values
150 values = map(trim, values)
152 self.replacements[name] = values
153 elif re.search(r'\*/', line) != None:
154 # Hit the end of the comments
160 # Pull out any test function names
161 if re.search(r'^test\w+\(\w+\)', line) != None:
162 self.functions.append(line)
165 """Main function. Generates all of the instances."""
170 # Create the output directory if it doesn't exist
174 self.permute(os.path.join(outdir, os.path.basename(self.basename)), self.replacements.keys())
176 # Remove the temporary file
177 os.remove(self.tmpname)
179 # Check and parse the command line arguments
180 if len(sys.argv) < 3:
181 # PENDING: How to throw an error?
182 print "usage: generate-cases.py template.c outdir"
184 # Input name is the first arg.
186 s = InstanceGenerator(sys.argv[1])