> 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
Expects infile is C source.
Loops, writing successively "thinned" version of infile to tmpfiles.
After each tmpfile is written, does system(" "),
with a 15 second timeout. If that doesn't time out, examines
. 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 ".keep".
The most recent file that hung the tester is file ".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: