Imported Upstream version 2.9.0
[debian/cc1111] / support / regression / generate-cases.py
1 from HTMLgen import TemplateDocument
2 import sys, re, tempfile, os
3
4 """See InstanceGenerator for a description of this file"""
5
6 # Globals
7 # Directory that the generated files should be placed into
8 outdir = sys.argv[2]
9
10 # Start of the test function table definition
11 testfuntableheader = """
12 void
13 __runSuite(void)
14 {
15 """
16
17 # End of the test function table definition
18 testfuntablefooter = """}
19 """
20
21 # Code to generate the suite function
22 testfunsuite = """
23 code const char *
24 __getSuiteName(void)
25 {
26   return "{testcase}";
27 }
28 """ 
29
30 # Utility functions
31 def trim(a):
32     """Removes all white space from the start and the end of a string.
33     Like java.lang.String.trim"""
34     ret = chomp(re.sub(r'^\s+', '', a))
35     return ret
36     
37 def chomp(a):
38     """Removes all white space from the end of a string.
39     Like perl's chomp"""
40     return re.sub(r'\s+$', '', a)
41
42 def createdir(path):
43     """Creates a directory if it doesn't exist"""
44     if not os.path.isdir(path):
45         os.mkdir(path)
46
47 class InstanceGenerator:
48     """Test case iteration generator.
49     Takes the template given as the first argument, pulls out all the meta
50     iteration information, and generates an instance for each combination
51     of the names and types.
52
53     See doc/test_suite_spec.tex for more information on the template file
54     format."""
55
56     def __init__(self, inname):
57         self.inname = inname
58         # Initalise the replacements hash.
59         # Map of name to values.
60         self.replacements = { }
61         # Initalise the function list hash.
62         self.functions = []
63         # Emit the suite wrapper into a temporary file
64         self.tmpname = tempfile.mktemp()
65         (self.dirname, self.filename) = os.path.split(self.inname)
66         (self.basename, self.ext) = os.path.splitext (self.filename)
67
68     def permute(self, basepath, keys, trans = {}):
69         """Permutes across all of the names.  For each value, recursivly creates
70         a mangled form of the name, this value, and all the combinations of
71         the remaining values.  At the tail of the recursion when one full
72         combination is built, generates an instance of the test case from
73         the template."""
74         if len(keys) == 0:
75             # End of the recursion.
76             # Set the runtime substitutions.
77             trans['testcase'] = re.sub(r'\\', r'\\\\', basepath)
78             # Create the instance from the template
79             T = TemplateDocument(self.tmpname)
80             T.substitutions = trans
81             T.write(basepath + self.ext)
82         else:
83             # Pull off this key, then recursivly iterate through the rest.
84             key = keys[0]
85             for part in self.replacements[key]:
86                 trans[key] = part
87                 # Turn a empty string into something decent for a filename
88                 if not part:
89                     part = 'none'
90                 # Remove any bad characters from the filename.
91                 part = re.sub(r'\s+', r'_', part)
92                 # The slice operator (keys[1:]) creates a copy of the list missing the
93                 # first element.
94                 # Can't use '-' as a seperator due to the mcs51 assembler.
95                 self.permute(basepath + '_' + key + '_' + part, keys[1:], trans) 
96
97     def writetemplate(self):
98         """Given a template file and a temporary name writes out a verbatim copy
99         of the source file and adds the suite table and functions."""
100         fout = open(self.tmpname, 'w')
101
102         for line in self.lines:
103             fout.write(line)
104
105         # Emmit the suite table
106         fout.write(testfuntableheader)
107
108         n = 0;
109         for fun in self.functions:
110             # Turn the function definition into a function call
111             fout.write("  __prints(\"Running " + fun + "\\n\");\n");
112             fout.write('  ' + fun + "();\n")
113             n += 1;
114
115         fout.write(testfuntablefooter)
116         fout.write("\nconst int __numCases = " + str(n) + ";\n")
117         fout.write(testfunsuite);
118         
119         fout.close()
120         return n
121
122     def readfile(self):
123         """Read in all of the input file."""
124         fin = open(self.inname)
125         self.lines = fin.readlines()
126         fin.close()
127
128     def parse(self):
129         # Start off in the header.
130         inheader = 1;
131
132         # Iterate over the source file and pull out the meta data.
133         for line in self.lines:
134             line = trim(line)
135
136             # If we are still in the header, see if this is a substitution line
137             if inheader:
138                 # A substitution line has a ':' in it
139                 if re.search(r':', line) != None:
140                     # Split out the name from the values
141                     (name, rawvalues) = re.split(r':', line)
142                     # Split the values at the commas
143                     values = re.split(r',', rawvalues)
144                     
145                     # Trim the name
146                     name = trim(name)
147                     # Trim all the values
148                     values = map(trim, values)
149                     
150                     self.replacements[name] = values
151                 elif re.search(r'\*/', line) != None:
152                     # Hit the end of the comments
153                     inheader = 0;
154                 else:
155                     # Do nothing.
156                     None
157             else:
158                 # Pull out any test function names
159                 m = re.match(r'^(?:\W*void\W+)?\W*(test\w*)\W*\(\W*void\W*\)', line)
160                 if m != None:
161                     self.functions.append(m.group(1))
162
163     def generate(self):
164         """Main function.  Generates all of the instances."""
165         self.readfile()
166         self.parse()
167         if self.writetemplate() == 0:
168             sys.stderr.write("Empty function list in " + self.inname + "!\n")
169
170         # Create the output directory if it doesn't exist
171         createdir(outdir)
172
173         # Generate
174         self.permute(os.path.join(outdir, self.basename), self.replacements.keys())
175
176         # Remove the temporary file
177         os.remove(self.tmpname)
178
179 def main():
180     # Check and parse the command line arguments
181     if len(sys.argv) < 3:
182         print "usage: generate-cases.py template.c outdir"
183         sys.exit(-1)
184         
185     # Input name is the first arg.
186
187     s = InstanceGenerator(sys.argv[1])
188     s.generate()
189
190 if __name__ == '__main__':
191     main()