1#! /usr/bin/env python
2
3# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
4# This program is distributed with GNU Go, a Go program.        #
5#                                                               #
6# Write gnugo@gnu.org or see http://www.gnu.org/software/gnugo/ #
7# for more information.                                         #
8#                                                               #
9# Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 and 2006   #
10# by the Free Software Foundation.                              #
11#                                                               #
12# This program is free software; you can redistribute it and/or #
13# modify it under the terms of the GNU General Public License   #
14# as published by the Free Software Foundation - version 3      #
15# or (at your option) any later version.                        #
16#                                                               #
17# This program is distributed in the hope that it will be       #
18# useful, but WITHOUT ANY WARRANTY; without even the implied    #
19# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR       #
20# PURPOSE.  See the GNU General Public License in file COPYING  #
21# for more details.                                             #
22#                                                               #
23# You should have received a copy of the GNU General Public     #
24# License along with this program; if not, write to the Free    #
25# Software Foundation, Inc., 51 Franklin Street, Fifth Floor,   #
26# Boston, MA 02111, USA.                                        #
27# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
28
29import string
30import sys, getopt
31import re
32
33help_string = """
34Usage:
35breakage2tst.py [--pike] <BREAKAGE_FILE
36	This creates a command line invoking regress.pike to run all tes
37	cases that appear as unexpected PASS or FAIL in BREAKAGE_FILE.
38breakage2tst.py [--pike] --update <BREAKAGE_FILE
39	This changes all .tst files so that the expected results match
40	the behaviour of the version that produced BREAKAGE_FILE.
41In both cases, it needs to be run from the regression test directory.
42"""
43
44# This prints out the list of tests from testfile in the format
45# <tstfile>:number
46def write_tests(tstfilename, tests):
47	for number, expected in tests:
48		print "%s:%d" % (tstfilename, number),
49
50
51def toggled_result(resultline, expected):
52	if (re.search(r"\]$", resultline)):
53		if (not expected == 0):
54			print "Result line doesn't match 'unexpected FAIL':",
55			print resultline
56			sys.exit(2)
57		return (re.sub(r"\]$", "]*", resultline))
58	elif (re.search(r"\]\*$", resultline)):
59		if (not expected == 1):
60			print "Result line doesn't match 'unexpected PASS':",
61			print resultline
62			sys.exit(2)
63		return (re.sub(r"\]\*$", "]", resultline))
64	else:
65		print "Couldn't parse alleged result line:", resultline
66		sys.exit(2)
67
68
69# This toggles the expected result in the .tst-file "tstfilename" for
70# all tests whose id is listed in "tests"
71def update_tstfile(tstfilename, tests):
72	if len(tests) == 0:
73		print tstfilename, "unchanged."
74		return
75	print "Updating", tstfilename
76	tstfile = open(tstfilename, 'r')
77	tstlines = tstfile.readlines()
78	tstfile.close
79	new_tstfile = ''
80
81	for number, expected in tests:
82		current_line = tstlines.pop(0)
83		command_pattern = re.compile("^%d " % number)
84
85		# Look for the line containing the command with matching id,
86		# while keeping recent commands and comments
87		while (not command_pattern.match(current_line)):
88			new_tstfile = new_tstfile + current_line
89			current_line = tstlines.pop(0)
90
91		# Found match. Now look for the result line:
92		while (not re.match(r"^#\?", current_line)):
93			new_tstfile = new_tstfile + current_line
94			current_line = tstlines.pop(0)
95
96		new_tstfile = new_tstfile + toggled_result(current_line,
97							   expected)
98
99	# Now copy the rest of the file without change.
100	new_tstfile = new_tstfile + string.join(tstlines, '')
101
102	tstfile = open(tstfilename, 'w')
103	tstfile.write(new_tstfile)
104	tstfile.close
105
106def parse_input(do_work):
107	tests = []
108	filename = ''
109	while 1:
110		try:
111			inputline = raw_input()
112		except EOFError:
113			do_work(filename, tests)
114			break
115		else:
116			s = string.split(inputline)
117			if len(s) == 0:
118				continue
119			if (re.search(r"regress\.sh", s[0])
120			    or re.search(r"eval\.sh", s[0])):
121			        if (filename != ''):
122					do_work(filename, tests)
123				filename = re.search(r"[^\s]+\.tst", inputline).group()
124				tests = []
125			elif (re.search("PASS", string.join(s[1:3]))):
126				tests.append([int(s[0]), 1])
127			elif (re.search("FAIL", string.join(s[1:3]))):
128				tests.append([int(s[0]), 0])
129
130def parse_pike_input(do_work):
131	tests = []
132	filename = ''
133	while 1:
134		try:
135			inputline = raw_input()
136		except EOFError:
137			if (filename != ''):
138				do_work(filename, tests)
139			break
140		else:
141			s = string.split(inputline)
142			if (not re.search(r"\:", s[0])):
143				continue
144			new_filename = re.search(r"[^:]+", s[0]).group() \
145				       + ".tst"
146			if (filename != new_filename):
147				if (filename != ''):
148					do_work(filename, tests)
149				filename = new_filename
150				tests = []
151			number = int(re.search(r"[\d]+$", s[0]).group())
152			if (s[1] == "PASS"):
153				tests.append([number, 1])
154			elif (s[1] == "FAIL"):
155				tests.append([number, 0])
156			else:
157				print "Inconsistent input line:", inputline
158				sys.exit(2)
159
160
161def main():
162	mode = 0
163	pike = 0
164	try:
165		opts, args = getopt.getopt(sys.argv[1:], "",
166					   ["update", "help", "pike"])
167	except getopt.GetoptError:
168		print "breakage2tst: Unrecognized option."
169		print help_string
170		sys.exit(2)
171	if (args != []):
172		print "I know nothing about arguments", args
173		print help_string
174		sys.exit(2)
175
176	for o, a in opts:
177		if (o == "--help"):
178			print help_string
179			sys.exit()
180		if (o == "--update"):
181			mode = 1
182		if (o == "--pike"):
183			pike = 1
184
185	if (mode == 0):
186		print "./regress.pike ",
187		do_work = write_tests
188	else:
189		do_work = update_tstfile
190
191
192	if (pike):
193		parse_pike_input(do_work)
194	else:
195		parse_input(do_work)
196
197	if (mode == 0):
198		print
199	else:
200		print "Done."
201
202
203main()
204