> On Feb 17, 2005, at 9:52 AM, Davide Rossetti wrote: > > I remember I read on this mlist about a testing tool. a script or > > something which took a source file in input and tried to swap lines > > and compile it, then reported results... can't google it exacly.. any > > help ??
Here's something vaguely related: a quick hack for shrinking testcases, when you're looking for a cutdown that still exhibits some still-mysterious failure. Its stupidity makes it slow. But you can run it while you're asleep. #! /usr/bin/env python """ thinloop.py <infile> <tester> <successfile> Expects infile is C source. Loops, writing successively "thinned" version of infile to tmpfiles. After each tmpfile is written, does system("<tester> <tmpfile>"), with a 15 second timeout. If that doesn't time out, examines <successfile>. If it's zero length, assumes the thinned version was a failure, and tries a different version. If it's nonzero, assumes the thinned version was a success, and bases the next thinning on that version. Runs forever, or until 100 fails in a row. Prints "+" or "_" (success or fail) on each iteration. The most recent successful output is kept as file "<infile>.keep". The most recent file that hung the tester is file "<infile>.hung". Thinning algorithm: Deletes one randomly chosen source line, under the rules: 1) doesn't delete lines containing "{" or "}" 2) finds a text line containing ";" 3) deletes that line, and all preceding lines up-to the preceding candidate line (as defined by rules 1 and 2). """ from __future__ import nested_scopes import sys,os import os.path import random import tempfile import copy import signal pid = 0 #------------- def handlerfunc( signum, obj ): """Post this as the signal handler. Expects pid is valid. """ global pid signal.alarm( 0 ) if signum == signal.SIGALRM: # Caught a timeout signal, so kill the pid. os.kill( pid, signal.SIGKILL ) signal.signal( signal.SIGCHLD, handlerfunc) signal.signal( signal.SIGALRM, handlerfunc) #------------- def tag_of( line ): """Given a text lines, returns: 0 - preserve (contains '{' or '}' 1 - target (contains ';') 2 - freefire (not either of above) """ if '{' in line: return 0 if '}' in line: return 0 if ';' in line: return 1 return 2 #------------- def slim_list( line_list): """ Returns a slimmed copy of line_list""" # Get a shallow copy (ie same strings, but new ptrs) line_list = copy.copy( line_list ) # Get a random in the range 0..N-1 target = random.choice(xrange(len(line_list))) try: # If we run off the end of arrays, just punt, # and make no change. # Search forward from random startpoint for a semicolon while ';' not in line_list[target]: target += 1 # Search backward for all freefire's leading up to target freefire = target while tag_of( line_list[freefire-1]) == 2: freefire -= 1 # delete all lines freefire upthu target # (Note each del renumbers them.) while freefire <= target: del line_list[freefire] target -= 1 except: pass return line_list #------------- def main( infile_name, tester, success_file ): global pid line_list = open(infile_name).readlines() fail_count = 0; while 1: # Get a shortened file short_list = slim_list( line_list ) # Emit the remaining lines to a tmpfile outfile_name = tempfile.mktemp(".c") outfile = open( outfile_name, "w") outfile.writelines(short_list) outfile.close() # Invoke the tester, after setting timeout signal.alarm( 15 ) pid = os.spawnv( os.P_NOWAIT, tester, [tester,outfile_name] ) # Wait for the tester to finish, turning any error from a KILL # into a bool. See handlerfunc, who expects we've set the pid. ok = 1 try: os.wait() except OSError: ok = 0 # Check the tester's success criteria, maybe keep the change if ok and os.path.getsize( success_file ) != 0: # Success: the change was good. line_list = short_list os.system( "/bin/cp -f %s %s.keep" % ( outfile_name, infile_name)) sys.stderr.write("+") fail_count = 0 else: if not ok: # Can't use rename, won't cross disks os.system( "/bin/cp -f %s %s.hung" % ( outfile_name, infile_name )) sys.stderr.write("_") fail_count += 1 if fail_count >= 100: sys.exit("Making no headway, stopping.") os.remove( outfile_name ) #------------- if __name__ == '__main__': if len(sys.argv) != 4: sys.exit("TRY: thinloop.py <infile> <tester> <successfile>" ) infile_name = sys.argv[1] tester = sys.argv[2] success_file = sys.argv[3] main( infile_name, tester, success_file )