xref: /llvm-project/clang/utils/FuzzTest (revision 8b0f3e05251562404adde606941dc4e0cc2ca15f)
1ef261ba5SDaniel Dunbar#!/usr/bin/env python
2ef261ba5SDaniel Dunbar
3ef261ba5SDaniel Dunbar"""
4ef261ba5SDaniel DunbarThis is a generic fuzz testing tool, see --help for more information.
5ef261ba5SDaniel Dunbar"""
6ef261ba5SDaniel Dunbar
7ef261ba5SDaniel Dunbarimport os
8ef261ba5SDaniel Dunbarimport sys
9ef261ba5SDaniel Dunbarimport random
10ef261ba5SDaniel Dunbarimport subprocess
11ef261ba5SDaniel Dunbarimport itertools
12ef261ba5SDaniel Dunbar
13ef261ba5SDaniel Dunbarclass TestGenerator:
14ef261ba5SDaniel Dunbar    def __init__(self, inputs, delete, insert, replace,
15ef261ba5SDaniel Dunbar                 insert_strings, pick_input):
16ef261ba5SDaniel Dunbar        self.inputs = [(s, open(s).read()) for s in inputs]
17ef261ba5SDaniel Dunbar
18ef261ba5SDaniel Dunbar        self.delete = bool(delete)
19ef261ba5SDaniel Dunbar        self.insert = bool(insert)
20ef261ba5SDaniel Dunbar        self.replace = bool(replace)
21ef261ba5SDaniel Dunbar        self.pick_input = bool(pick_input)
22ef261ba5SDaniel Dunbar        self.insert_strings = list(insert_strings)
23ef261ba5SDaniel Dunbar
24ef261ba5SDaniel Dunbar        self.num_positions = sum([len(d) for _,d in self.inputs])
25ef261ba5SDaniel Dunbar        self.num_insert_strings = len(insert_strings)
26ef261ba5SDaniel Dunbar        self.num_tests = ((delete + (insert + replace)*self.num_insert_strings)
27ef261ba5SDaniel Dunbar                          * self.num_positions)
28ef261ba5SDaniel Dunbar        self.num_tests += 1
29ef261ba5SDaniel Dunbar
30ef261ba5SDaniel Dunbar        if self.pick_input:
31ef261ba5SDaniel Dunbar            self.num_tests *= self.num_positions
32ef261ba5SDaniel Dunbar
33ef261ba5SDaniel Dunbar    def position_to_source_index(self, position):
34ef261ba5SDaniel Dunbar        for i,(s,d) in enumerate(self.inputs):
35ef261ba5SDaniel Dunbar            n = len(d)
36ef261ba5SDaniel Dunbar            if position < n:
37ef261ba5SDaniel Dunbar                return (i,position)
38ef261ba5SDaniel Dunbar            position -= n
39ef261ba5SDaniel Dunbar        raise ValueError,'Invalid position.'
40ef261ba5SDaniel Dunbar
41ef261ba5SDaniel Dunbar    def get_test(self, index):
42ef261ba5SDaniel Dunbar        assert 0 <= index < self.num_tests
43ef261ba5SDaniel Dunbar
44ef261ba5SDaniel Dunbar        picked_position = None
45ef261ba5SDaniel Dunbar        if self.pick_input:
46ef261ba5SDaniel Dunbar            index,picked_position = divmod(index, self.num_positions)
47ef261ba5SDaniel Dunbar            picked_position = self.position_to_source_index(picked_position)
48ef261ba5SDaniel Dunbar
49ef261ba5SDaniel Dunbar        if index == 0:
50ef261ba5SDaniel Dunbar            return ('nothing', None, None, picked_position)
51ef261ba5SDaniel Dunbar
52ef261ba5SDaniel Dunbar        index -= 1
53ef261ba5SDaniel Dunbar        index,position = divmod(index, self.num_positions)
54ef261ba5SDaniel Dunbar        position = self.position_to_source_index(position)
55ef261ba5SDaniel Dunbar        if self.delete:
56ef261ba5SDaniel Dunbar            if index == 0:
57ef261ba5SDaniel Dunbar                return ('delete', position, None, picked_position)
58ef261ba5SDaniel Dunbar            index -= 1
59ef261ba5SDaniel Dunbar
60ef261ba5SDaniel Dunbar        index,insert_index = divmod(index, self.num_insert_strings)
61ef261ba5SDaniel Dunbar        insert_str = self.insert_strings[insert_index]
62ef261ba5SDaniel Dunbar        if self.insert:
63ef261ba5SDaniel Dunbar            if index == 0:
64ef261ba5SDaniel Dunbar                return ('insert', position, insert_str, picked_position)
65ef261ba5SDaniel Dunbar            index -= 1
66ef261ba5SDaniel Dunbar
67ef261ba5SDaniel Dunbar        assert self.replace
68ef261ba5SDaniel Dunbar        assert index == 0
69ef261ba5SDaniel Dunbar        return ('replace', position, insert_str, picked_position)
70ef261ba5SDaniel Dunbar
71ef261ba5SDaniel Dunbarclass TestApplication:
72ef261ba5SDaniel Dunbar    def __init__(self, tg, test):
73ef261ba5SDaniel Dunbar        self.tg = tg
74ef261ba5SDaniel Dunbar        self.test = test
75ef261ba5SDaniel Dunbar
76ef261ba5SDaniel Dunbar    def apply(self):
77ef261ba5SDaniel Dunbar        if self.test[0] == 'nothing':
78ef261ba5SDaniel Dunbar            pass
79ef261ba5SDaniel Dunbar        else:
80ef261ba5SDaniel Dunbar            i,j = self.test[1]
81ef261ba5SDaniel Dunbar            name,data = self.tg.inputs[i]
82ef261ba5SDaniel Dunbar            if self.test[0] == 'delete':
83ef261ba5SDaniel Dunbar                data = data[:j] + data[j+1:]
84ef261ba5SDaniel Dunbar            elif self.test[0] == 'insert':
85ef261ba5SDaniel Dunbar                data = data[:j] + self.test[2] + data[j:]
86ef261ba5SDaniel Dunbar            elif self.test[0] == 'replace':
87ef261ba5SDaniel Dunbar                data = data[:j] + self.test[2] + data[j+1:]
88ef261ba5SDaniel Dunbar            else:
89ef261ba5SDaniel Dunbar                raise ValueError,'Invalid test %r' % self.test
90ef261ba5SDaniel Dunbar            open(name,'wb').write(data)
91ef261ba5SDaniel Dunbar
92ef261ba5SDaniel Dunbar    def revert(self):
93ef261ba5SDaniel Dunbar        if self.test[0] != 'nothing':
94ef261ba5SDaniel Dunbar            i,j = self.test[1]
95ef261ba5SDaniel Dunbar            name,data = self.tg.inputs[i]
96ef261ba5SDaniel Dunbar            open(name,'wb').write(data)
97ef261ba5SDaniel Dunbar
98ef261ba5SDaniel Dunbardef quote(str):
99ef261ba5SDaniel Dunbar    return '"' + str + '"'
100ef261ba5SDaniel Dunbar
101ef261ba5SDaniel Dunbardef run_one_test(test_application, index, input_files, args):
102ef261ba5SDaniel Dunbar    test = test_application.test
103ef261ba5SDaniel Dunbar
104ef261ba5SDaniel Dunbar    # Interpolate arguments.
105ef261ba5SDaniel Dunbar    options = { 'index' : index,
106ef261ba5SDaniel Dunbar                'inputs' : ' '.join(quote(f) for f in input_files) }
107ef261ba5SDaniel Dunbar
108ef261ba5SDaniel Dunbar    # Add picked input interpolation arguments, if used.
109ef261ba5SDaniel Dunbar    if test[3] is not None:
110ef261ba5SDaniel Dunbar        pos = test[3][1]
111ef261ba5SDaniel Dunbar        options['picked_input'] = input_files[test[3][0]]
112ef261ba5SDaniel Dunbar        options['picked_input_pos'] = pos
113ef261ba5SDaniel Dunbar        # Compute the line and column.
114ef261ba5SDaniel Dunbar        file_data = test_application.tg.inputs[test[3][0]][1]
115ef261ba5SDaniel Dunbar        line = column = 1
116ef261ba5SDaniel Dunbar        for i in range(pos):
117ef261ba5SDaniel Dunbar            c = file_data[i]
118ef261ba5SDaniel Dunbar            if c == '\n':
119ef261ba5SDaniel Dunbar                line += 1
120ef261ba5SDaniel Dunbar                column = 1
121ef261ba5SDaniel Dunbar            else:
122ef261ba5SDaniel Dunbar                column += 1
123ef261ba5SDaniel Dunbar        options['picked_input_line'] = line
124ef261ba5SDaniel Dunbar        options['picked_input_col'] = column
125ef261ba5SDaniel Dunbar
126ef261ba5SDaniel Dunbar    test_args = [a % options for a in args]
127ef261ba5SDaniel Dunbar    if opts.verbose:
128ef261ba5SDaniel Dunbar        print '%s: note: executing %r' % (sys.argv[0], test_args)
129ef261ba5SDaniel Dunbar
130ef261ba5SDaniel Dunbar    stdout = None
131ef261ba5SDaniel Dunbar    stderr = None
132ef261ba5SDaniel Dunbar    if opts.log_dir:
133ef261ba5SDaniel Dunbar        stdout_log_path = os.path.join(opts.log_dir, '%s.out' % index)
134ef261ba5SDaniel Dunbar        stderr_log_path = os.path.join(opts.log_dir, '%s.err' % index)
135ef261ba5SDaniel Dunbar        stdout = open(stdout_log_path, 'wb')
136ef261ba5SDaniel Dunbar        stderr = open(stderr_log_path, 'wb')
137ef261ba5SDaniel Dunbar    else:
138ef261ba5SDaniel Dunbar        sys.stdout.flush()
139ef261ba5SDaniel Dunbar    p = subprocess.Popen(test_args, stdout=stdout, stderr=stderr)
140ef261ba5SDaniel Dunbar    p.communicate()
141ef261ba5SDaniel Dunbar    exit_code = p.wait()
142ef261ba5SDaniel Dunbar
143ef261ba5SDaniel Dunbar    test_result = (exit_code == opts.expected_exit_code or
144ef261ba5SDaniel Dunbar                   exit_code in opts.extra_exit_codes)
145ef261ba5SDaniel Dunbar
146ef261ba5SDaniel Dunbar    if stdout is not None:
147ef261ba5SDaniel Dunbar        stdout.close()
148ef261ba5SDaniel Dunbar        stderr.close()
149ef261ba5SDaniel Dunbar
150ef261ba5SDaniel Dunbar        # Remove the logs for passes, unless logging all results.
151ef261ba5SDaniel Dunbar        if not opts.log_all and test_result:
152ef261ba5SDaniel Dunbar            os.remove(stdout_log_path)
153ef261ba5SDaniel Dunbar            os.remove(stderr_log_path)
154ef261ba5SDaniel Dunbar
155ef261ba5SDaniel Dunbar    if not test_result:
156ef261ba5SDaniel Dunbar        print 'FAIL: %d' % index
157ef261ba5SDaniel Dunbar    elif not opts.succinct:
158ef261ba5SDaniel Dunbar        print 'PASS: %d' % index
159*8b0f3e05SArgyrios Kyrtzidis    return test_result
160ef261ba5SDaniel Dunbar
161ef261ba5SDaniel Dunbardef main():
162ef261ba5SDaniel Dunbar    global opts
163ef261ba5SDaniel Dunbar    from optparse import OptionParser, OptionGroup
164ef261ba5SDaniel Dunbar    parser = OptionParser("""%prog [options] ... test command args ...
165ef261ba5SDaniel Dunbar
166ef261ba5SDaniel Dunbar%prog is a tool for fuzzing inputs and testing them.
167ef261ba5SDaniel Dunbar
168ef261ba5SDaniel DunbarThe most basic usage is something like:
169ef261ba5SDaniel Dunbar
170ef261ba5SDaniel Dunbar  $ %prog --file foo.txt ./test.sh
171ef261ba5SDaniel Dunbar
172ef261ba5SDaniel Dunbarwhich will run a default list of fuzzing strategies on the input. For each
173ef261ba5SDaniel Dunbarfuzzed input, it will overwrite the input files (in place), run the test script,
174ef261ba5SDaniel Dunbarthen restore the files back to their original contents.
175ef261ba5SDaniel Dunbar
176ef261ba5SDaniel DunbarNOTE: You should make sure you have a backup copy of your inputs, in case
177ef261ba5SDaniel Dunbarsomething goes wrong!!!
178ef261ba5SDaniel Dunbar
179ef261ba5SDaniel DunbarYou can cause the fuzzing to not restore the original files with
180ef261ba5SDaniel Dunbar'--no-revert'. Generally this is used with '--test <index>' to run one failing
181ef261ba5SDaniel Dunbartest and then leave the fuzzed inputs in place to examine the failure.
182ef261ba5SDaniel Dunbar
183ef261ba5SDaniel DunbarFor each fuzzed input, %prog will run the test command given on the command
184ef261ba5SDaniel Dunbarline. Each argument in the command is subject to string interpolation before
185ef261ba5SDaniel Dunbarbeing executed. The syntax is "%(VARIABLE)FORMAT" where FORMAT is a standard
1861c66a0e1SDaniel Dunbarprintf format, and VARIABLE is one of:
187ef261ba5SDaniel Dunbar
188ef261ba5SDaniel Dunbar  'index' - the test index being run
189ef261ba5SDaniel Dunbar  'inputs' - the full list of test inputs
190ef261ba5SDaniel Dunbar  'picked_input'      - (with --pick-input) the selected input file
191ef261ba5SDaniel Dunbar  'picked_input_pos'  - (with --pick-input) the selected input position
192ef261ba5SDaniel Dunbar  'picked_input_line' - (with --pick-input) the selected input line
193ef261ba5SDaniel Dunbar  'picked_input_col'  - (with --pick-input) the selected input column
194ef261ba5SDaniel Dunbar
195ef261ba5SDaniel DunbarBy default, the script will run forever continually picking new tests to
196ef261ba5SDaniel Dunbarrun. You can limit the number of tests that are run with '--max-tests <number>',
197ef261ba5SDaniel Dunbarand you can run a particular test with '--test <index>'.
198*8b0f3e05SArgyrios Kyrtzidis
199*8b0f3e05SArgyrios KyrtzidisYou can specify '--stop-on-fail' to stop the script on the first failure
200*8b0f3e05SArgyrios Kyrtzidiswithout reverting the changes.
201*8b0f3e05SArgyrios Kyrtzidis
202ef261ba5SDaniel Dunbar""")
203ef261ba5SDaniel Dunbar    parser.add_option("-v", "--verbose", help="Show more output",
204ef261ba5SDaniel Dunbar                      action='store_true', dest="verbose", default=False)
205ef261ba5SDaniel Dunbar    parser.add_option("-s", "--succinct",  help="Reduce amount of output",
206ef261ba5SDaniel Dunbar                      action="store_true", dest="succinct", default=False)
207ef261ba5SDaniel Dunbar
208ef261ba5SDaniel Dunbar    group = OptionGroup(parser, "Test Execution")
209ef261ba5SDaniel Dunbar    group.add_option("", "--expected-exit-code", help="Set expected exit code",
210ef261ba5SDaniel Dunbar                     type=int, dest="expected_exit_code",
211ef261ba5SDaniel Dunbar                     default=0)
212ef261ba5SDaniel Dunbar    group.add_option("", "--extra-exit-code",
213ef261ba5SDaniel Dunbar                     help="Set additional expected exit code",
214ef261ba5SDaniel Dunbar                     type=int, action="append", dest="extra_exit_codes",
215ef261ba5SDaniel Dunbar                     default=[])
216ef261ba5SDaniel Dunbar    group.add_option("", "--log-dir",
217ef261ba5SDaniel Dunbar                     help="Capture test logs to an output directory",
218ef261ba5SDaniel Dunbar                     type=str, dest="log_dir",
219ef261ba5SDaniel Dunbar                     default=None)
220ef261ba5SDaniel Dunbar    group.add_option("", "--log-all",
221ef261ba5SDaniel Dunbar                     help="Log all outputs (not just failures)",
222ef261ba5SDaniel Dunbar                     action="store_true", dest="log_all", default=False)
223ef261ba5SDaniel Dunbar    parser.add_option_group(group)
224ef261ba5SDaniel Dunbar
225ef261ba5SDaniel Dunbar    group = OptionGroup(parser, "Input Files")
226ef261ba5SDaniel Dunbar    group.add_option("", "--file", metavar="PATH",
227ef261ba5SDaniel Dunbar                     help="Add an input file to fuzz",
228ef261ba5SDaniel Dunbar                     type=str, action="append", dest="input_files", default=[])
229ef261ba5SDaniel Dunbar    group.add_option("", "--filelist", metavar="LIST",
230ef261ba5SDaniel Dunbar                     help="Add a list of inputs files to fuzz (one per line)",
23105d2212dSArgyrios Kyrtzidis                     type=str, action="append", dest="filelists", default=[])
232ef261ba5SDaniel Dunbar    parser.add_option_group(group)
233ef261ba5SDaniel Dunbar
234ef261ba5SDaniel Dunbar    group = OptionGroup(parser, "Fuzz Options")
235ef261ba5SDaniel Dunbar    group.add_option("", "--replacement-chars", dest="replacement_chars",
236ef261ba5SDaniel Dunbar                     help="Characters to insert/replace",
237ef261ba5SDaniel Dunbar                     default="0{}[]<>\;@#$^%& ")
238ef261ba5SDaniel Dunbar    group.add_option("", "--replacement-string", dest="replacement_strings",
239ef261ba5SDaniel Dunbar                     action="append", help="Add a replacement string to use",
240ef261ba5SDaniel Dunbar                     default=[])
2413dbd7b51SDaniel Dunbar    group.add_option("", "--replacement-list", dest="replacement_lists",
2423dbd7b51SDaniel Dunbar                     help="Add a list of replacement strings (one per line)",
2433dbd7b51SDaniel Dunbar                     action="append", default=[])
244ef261ba5SDaniel Dunbar    group.add_option("", "--no-delete", help="Don't delete characters",
245ef261ba5SDaniel Dunbar                     action='store_false', dest="enable_delete", default=True)
246ef261ba5SDaniel Dunbar    group.add_option("", "--no-insert", help="Don't insert strings",
247ef261ba5SDaniel Dunbar                     action='store_false', dest="enable_insert", default=True)
248ef261ba5SDaniel Dunbar    group.add_option("", "--no-replace", help="Don't replace strings",
249ef261ba5SDaniel Dunbar                     action='store_false', dest="enable_replace", default=True)
250ef261ba5SDaniel Dunbar    group.add_option("", "--no-revert", help="Don't revert changes",
251ef261ba5SDaniel Dunbar                     action='store_false', dest="revert", default=True)
252*8b0f3e05SArgyrios Kyrtzidis    group.add_option("", "--stop-on-fail", help="Stop on first failure",
253*8b0f3e05SArgyrios Kyrtzidis                     action='store_true', dest="stop_on_fail", default=False)
254ef261ba5SDaniel Dunbar    parser.add_option_group(group)
255ef261ba5SDaniel Dunbar
256ef261ba5SDaniel Dunbar    group = OptionGroup(parser, "Test Selection")
257ef261ba5SDaniel Dunbar    group.add_option("", "--test", help="Run a particular test",
258ef261ba5SDaniel Dunbar                     type=int, dest="test", default=None, metavar="INDEX")
259ef261ba5SDaniel Dunbar    group.add_option("", "--max-tests", help="Maximum number of tests",
260941d0929SArgyrios Kyrtzidis                     type=int, dest="max_tests", default=None, metavar="COUNT")
261ef261ba5SDaniel Dunbar    group.add_option("", "--pick-input",
262ef261ba5SDaniel Dunbar                     help="Randomly select an input byte as well as fuzzing",
263ef261ba5SDaniel Dunbar                     action='store_true', dest="pick_input", default=False)
264ef261ba5SDaniel Dunbar    parser.add_option_group(group)
265ef261ba5SDaniel Dunbar
266ef261ba5SDaniel Dunbar    parser.disable_interspersed_args()
267ef261ba5SDaniel Dunbar
268ef261ba5SDaniel Dunbar    (opts, args) = parser.parse_args()
269ef261ba5SDaniel Dunbar
270ef261ba5SDaniel Dunbar    if not args:
271ef261ba5SDaniel Dunbar        parser.error("Invalid number of arguments")
272ef261ba5SDaniel Dunbar
273ef261ba5SDaniel Dunbar    # Collect the list of inputs.
274ef261ba5SDaniel Dunbar    input_files = list(opts.input_files)
275ef261ba5SDaniel Dunbar    for filelist in opts.filelists:
276ef261ba5SDaniel Dunbar        f = open(filelist)
277ef261ba5SDaniel Dunbar        try:
278ef261ba5SDaniel Dunbar            for ln in f:
279ef261ba5SDaniel Dunbar                ln = ln.strip()
280ef261ba5SDaniel Dunbar                if ln:
281ef261ba5SDaniel Dunbar                    input_files.append(ln)
282ef261ba5SDaniel Dunbar        finally:
283ef261ba5SDaniel Dunbar            f.close()
284ef261ba5SDaniel Dunbar    input_files.sort()
285ef261ba5SDaniel Dunbar
286ef261ba5SDaniel Dunbar    if not input_files:
287ef261ba5SDaniel Dunbar        parser.error("No input files!")
288ef261ba5SDaniel Dunbar
289ef261ba5SDaniel Dunbar    print '%s: note: fuzzing %d files.' % (sys.argv[0], len(input_files))
290ef261ba5SDaniel Dunbar
291ef261ba5SDaniel Dunbar    # Make sure the log directory exists if used.
292ef261ba5SDaniel Dunbar    if opts.log_dir:
293ef261ba5SDaniel Dunbar        if not os.path.exists(opts.log_dir):
294ef261ba5SDaniel Dunbar            try:
295ef261ba5SDaniel Dunbar                os.mkdir(opts.log_dir)
296ef261ba5SDaniel Dunbar            except OSError:
297ef261ba5SDaniel Dunbar                print "%s: error: log directory couldn't be created!" % (
298ef261ba5SDaniel Dunbar                    sys.argv[0],)
299ef261ba5SDaniel Dunbar                raise SystemExit,1
300ef261ba5SDaniel Dunbar
301ef261ba5SDaniel Dunbar    # Get the list if insert/replacement strings.
302ef261ba5SDaniel Dunbar    replacements = list(opts.replacement_chars)
303ef261ba5SDaniel Dunbar    replacements.extend(opts.replacement_strings)
3043dbd7b51SDaniel Dunbar    for replacement_list in opts.replacement_lists:
3053dbd7b51SDaniel Dunbar        f = open(replacement_list)
3063dbd7b51SDaniel Dunbar        try:
3073dbd7b51SDaniel Dunbar            for ln in f:
3083dbd7b51SDaniel Dunbar                ln = ln[:-1]
3093dbd7b51SDaniel Dunbar                if ln:
3103dbd7b51SDaniel Dunbar                    replacements.append(ln)
3113dbd7b51SDaniel Dunbar        finally:
3123dbd7b51SDaniel Dunbar            f.close()
3133dbd7b51SDaniel Dunbar
3143dbd7b51SDaniel Dunbar    # Unique and order the replacement list.
3153dbd7b51SDaniel Dunbar    replacements = list(set(replacements))
3163dbd7b51SDaniel Dunbar    replacements.sort()
317ef261ba5SDaniel Dunbar
318ef261ba5SDaniel Dunbar    # Create the test generator.
319ef261ba5SDaniel Dunbar    tg = TestGenerator(input_files, opts.enable_delete, opts.enable_insert,
320ef261ba5SDaniel Dunbar                       opts.enable_replace, replacements, opts.pick_input)
321ef261ba5SDaniel Dunbar
322ef261ba5SDaniel Dunbar    print '%s: note: %d input bytes.' % (sys.argv[0], tg.num_positions)
323ef261ba5SDaniel Dunbar    print '%s: note: %d total tests.' % (sys.argv[0], tg.num_tests)
324ef261ba5SDaniel Dunbar    if opts.test is not None:
325ef261ba5SDaniel Dunbar        it = [opts.test]
326ef261ba5SDaniel Dunbar    elif opts.max_tests is not None:
327ef261ba5SDaniel Dunbar        it = itertools.imap(random.randrange,
328ef261ba5SDaniel Dunbar                            itertools.repeat(tg.num_tests, opts.max_tests))
329ef261ba5SDaniel Dunbar    else:
330ef261ba5SDaniel Dunbar        it = itertools.imap(random.randrange, itertools.repeat(tg.num_tests))
331ef261ba5SDaniel Dunbar    for test in it:
332ef261ba5SDaniel Dunbar        t = tg.get_test(test)
333ef261ba5SDaniel Dunbar
334ef261ba5SDaniel Dunbar        if opts.verbose:
335ef261ba5SDaniel Dunbar            print '%s: note: running test %d: %r' % (sys.argv[0], test, t)
336ef261ba5SDaniel Dunbar        ta = TestApplication(tg, t)
337ef261ba5SDaniel Dunbar        try:
338ef261ba5SDaniel Dunbar            ta.apply()
339*8b0f3e05SArgyrios Kyrtzidis            test_result = run_one_test(ta, test, input_files, args)
340*8b0f3e05SArgyrios Kyrtzidis            if not test_result and opts.stop_on_fail:
341*8b0f3e05SArgyrios Kyrtzidis                opts.revert = False
342*8b0f3e05SArgyrios Kyrtzidis                sys.exit(1)
343ef261ba5SDaniel Dunbar        finally:
344ef261ba5SDaniel Dunbar            if opts.revert:
345ef261ba5SDaniel Dunbar                ta.revert()
346ef261ba5SDaniel Dunbar
347ef261ba5SDaniel Dunbar        sys.stdout.flush()
348ef261ba5SDaniel Dunbar
349ef261ba5SDaniel Dunbarif __name__ == '__main__':
350ef261ba5SDaniel Dunbar    main()
351