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
= """
17 # End of the test function table definition
18 testfuntablefooter
= """}
21 # Code to generate the suite function
32 """Creates a directory if it doesn't exist"""
33 if not os
.path
.isdir(path
):
36 class InstanceGenerator
:
37 """Test case iteration generator.
38 Takes the template given as the first argument, pulls out all the meta
39 iteration information, and generates an instance for each combination
40 of the names and types.
42 See doc/test_suite_spec.tex for more information on the template file
45 def __init__(self
, inname
):
47 # Initalise the replacements hash.
48 # Map of name to values.
49 self
.replacements
= []
50 # Initalise the function list hash.
52 # Emit the suite wrapper into a temporary file
53 self
.tmpname
= tempfile
.mktemp()
54 (self
.dirname
, self
.filename
) = os
.path
.split(self
.inname
)
55 (self
.basename
, self
.ext
) = os
.path
.splitext (self
.filename
)
57 (self
.basename
, self
.ext
) = os
.path
.splitext (self
.filename
[:-3])
59 def permute(self
, basename
, repl
, trans
= {}):
60 """Permutes across all of the names. For each value, recursively creates
61 a mangled form of the name, this value, and all the combinations of
62 the remaining values. At the tail of the recursion when one full
63 combination is built, generates an instance of the test case from
65 basepath
= os
.path
.join(outdir
, basename
)
67 # End of the recursion.
68 # Set the runtime substitutions.
69 trans
['testcase'] = re
.sub(r
'\\', r
'\\\\', basename
)
70 # Create the instance from the template
71 T
= TemplateDocument(self
.tmpname
)
72 T
.substitutions
= trans
73 T
.write(basepath
+ self
.ext
)
75 # Pull off this key, then recursively iterate through the rest.
77 for part
in repl
[0][1]:
79 # Turn a empty string into something decent for a filename
82 # Remove any bad characters from the filename.
83 part
= re
.sub(r
'\s+', r
'_', part
)
84 # The slice operator (_[1:]) creates a copy of the list missing the
86 # Can't use '-' as a seperator due to the mcs51 assembler.
87 self
.permute(basename
+ '_' + key
+ '_' + part
, repl
[1:], trans
)
89 def writetemplate(self
):
90 """Given a template file and a temporary name writes out a verbatim copy
91 of the source file and adds the suite table and functions."""
92 if sys
.version_info
[0]<3:
93 fout
= open(self
.tmpname
, 'w')
95 fout
= open(self
.tmpname
, 'w', encoding
="latin-1")
97 for line
in self
.lines
:
100 # Emmit the suite table
101 fout
.write(testfuntableheader
)
104 for fun
in self
.functions
:
105 # Turn the function definition into a function call
106 fout
.write(" __prints(\"Running " + fun
+ "\\n\");\n");
107 fout
.write(' ' + fun
+ "();\n")
110 fout
.write(testfuntablefooter
)
111 fout
.write("\nconst int __numCases = " + str(n
) + ";\n")
112 fout
.write(testfunsuite
);
118 """Read in all of the input file."""
119 if sys
.version_info
[0]<3:
120 fin
= open(self
.inname
)
122 fin
= open(self
.inname
, encoding
="latin-1")
123 self
.lines
= fin
.readlines()
127 # Start off in the header.
130 # Iterate over the source file and pull out the meta data.
131 for line
in self
.lines
:
134 # If we are still in the header, see if this is a substitution line
136 # A substitution line has a ':' in it
137 if re
.search(r
':', line
) != None:
138 # Split out the name from the values
139 (name
, rawvalues
) = re
.split(r
':', line
)
140 # Split the values at the commas
141 values
= re
.split(r
',', rawvalues
)
145 # Trim all the values
146 values
= [value
.strip() for value
in values
]
148 self
.replacements
.append((name
, values
))
149 elif re
.search(r
'\*/', line
) != None:
150 # Hit the end of the comments
156 # Pull out any test function names
157 m
= re
.match(r
'^(?:\W*void\W+)?\W*(test\w*)\W*\(\W*void\W*\)', line
)
159 self
.functions
.append(m
.group(1))
162 """Main function. Generates all of the instances."""
165 if self
.writetemplate() == 0:
166 sys
.stderr
.write("Empty function list in " + self
.inname
+ "!\n")
168 # Create the output directory if it doesn't exist
172 self
.permute(self
.basename
, self
.replacements
)
174 # Remove the temporary file
175 os
.remove(self
.tmpname
)
178 # Check and parse the command line arguments
179 if len(sys
.argv
) < 3:
180 print("usage: generate-cases.py template.c outdir")
183 # Input name is the first arg.
185 s
= InstanceGenerator(sys
.argv
[1])
188 if __name__
== '__main__':