6689.1.1
by Holger Rapp
First unfinished version of a regression test suite. |
1 |
#!/usr/bin/env python
|
2 |
# encoding: utf-8
|
|
3 |
||
6689.1.4
by Holger Rapp
All tests now run and pass on my system. |
4 |
from glob import glob |
5 |
import argparse |
|
6 |
import os |
|
7 |
import re |
|
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
8 |
import shutil |
9 |
import subprocess |
|
6803
by Holger Rapp
regression_test.py returns an error to the system on failure. |
10 |
import sys |
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
11 |
import tempfile |
6689.1.2
by Holger Rapp
Brought back original content of regression_test.py. |
12 |
import unittest |
6849
by Tino
allow regression test on windows |
13 |
import platform |
6689.1.4
by Holger Rapp
All tests now run and pass on my system. |
14 |
|
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
15 |
def out(string): |
16 |
sys.stdout.write(string) |
|
17 |
sys.stdout.flush() |
|
18 |
||
19 |
class WidelandsTestCase(unittest.TestCase): |
|
20 |
do_use_random_directory = True |
|
21 |
path_to_widelands_binary = None |
|
22 |
keep_output_around = False |
|
23 |
||
24 |
def __init__(self, test_script, **wlargs): |
|
25 |
unittest.TestCase.__init__(self) |
|
26 |
self._test_script = test_script |
|
27 |
self._wlargs = wlargs |
|
28 |
||
29 |
def __str__(self): |
|
30 |
return self._test_script |
|
31 |
||
32 |
def setUp(self): |
|
33 |
if self.do_use_random_directory: |
|
34 |
self.run_dir = tempfile.mkdtemp(prefix="widelands_regression_test") |
|
35 |
else: |
|
36 |
self.run_dir = os.path.join(tempfile.gettempdir(), "widelands_regression_test", self.__class__.__name__) |
|
37 |
if os.path.exists(self.run_dir): |
|
38 |
if not self.keep_output_around: |
|
39 |
shutil.rmtree(self.run_dir) |
|
6812.1.18
by Holger Rapp
No more multiple inheritance in scripting layer. All clearer now. |
40 |
os.makedirs(self.run_dir) |
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
41 |
else: |
42 |
os.makedirs(self.run_dir) |
|
43 |
self.widelands_returncode = 0 |
|
44 |
||
45 |
def run(self, result=None): |
|
46 |
self.currentResult = result # remember result for use in tearDown |
|
47 |
unittest.TestCase.run(self, result) |
|
48 |
||
49 |
def tearDown(self): |
|
50 |
if self.currentResult.wasSuccessful() and not self.keep_output_around: |
|
51 |
shutil.rmtree(self.run_dir) |
|
52 |
||
6820.2.10
by Holger Rapp
Fixed a bug in the test runner and added a new test case. |
53 |
def run_widelands(self, wlargs, which_time): |
54 |
"""Run Widelands with the given 'wlargs'. 'which_time' is an integer
|
|
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
55 |
defining the number of times Widelands has been run this test case
|
56 |
(i.e. because we might load a saved game from an earlier run. This will
|
|
57 |
impact the filenames for stdout.txt.
|
|
58 |
||
59 |
Returns the stdout filename."""
|
|
60 |
stdout_filename = os.path.join(self.run_dir, "stdout_%02i.txt" % which_time) |
|
61 |
if (os.path.exists(stdout_filename)): |
|
62 |
os.unlink(stdout_filename) |
|
63 |
||
64 |
with open(stdout_filename, 'a') as stdout_file: |
|
65 |
args = [self.path_to_widelands_binary, '--verbose=true', |
|
7000
by Jens Beyer (Qcumber-some)
force standard english as language for test; use predictable datadir |
66 |
'--datadir=%s' % os.path.dirname(__file__), '--homedir=%s' % self.run_dir, |
67 |
'--disable_fx=true', '--disable_music=true', '--language=en_US' ] |
|
6820.2.10
by Holger Rapp
Fixed a bug in the test runner and added a new test case. |
68 |
args += [ "--%s=%s" % (key, value) for key, value in wlargs.iteritems() ] |
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
69 |
|
70 |
widelands = subprocess.Popen( |
|
71 |
args, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) |
|
72 |
while 1: |
|
73 |
line = widelands.stdout.readline() |
|
74 |
if not line: |
|
75 |
break
|
|
76 |
stdout_file.write(line) |
|
77 |
stdout_file.flush() |
|
78 |
widelands.communicate() |
|
6849
by Tino
allow regression test on windows |
79 |
if platform.system() == "Windows": |
80 |
win_stdout = self.path_to_widelands_binary.replace("widelands.exe","stdout.txt") |
|
81 |
win_stderr = self.path_to_widelands_binary.replace("widelands.exe","stderr.txt") |
|
82 |
with open(win_stdout,"r") as f: |
|
83 |
for line in f: |
|
84 |
stdout_file.write(line) |
|
85 |
stdout_file.flush() |
|
86 |
if (os.path.exists(win_stderr)): |
|
87 |
with open(win_stderr,"r") as f: |
|
88 |
for line in f: |
|
89 |
stdout_file.write(line) |
|
90 |
stdout_file.flush() |
|
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
91 |
|
92 |
self.widelands_returncode = widelands.returncode |
|
93 |
return stdout_filename |
|
94 |
||
95 |
def runTest(self): |
|
96 |
out("\n Running Widelands ... ") |
|
97 |
stdout_filename = self.run_widelands(self._wlargs, 0) |
|
98 |
stdout = open(stdout_filename, "r").read() |
|
99 |
self.verify_success(stdout, stdout_filename) |
|
100 |
||
101 |
find_saves = lambda stdout: re.findall("Script requests save to: (\w+)$", stdout, re.M) |
|
102 |
savegame_done = { fn: False for fn in find_saves(stdout) } |
|
103 |
which_time = 1 |
|
104 |
while not all(savegame_done.values()): |
|
6820.2.11
by Holger Rapp
Added two more test that remove the ship when a ware should be transported. |
105 |
for savegame in sorted(savegame_done): |
106 |
if not savegame_done[savegame]: break |
|
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
107 |
out(" Loading savegame: %s ... " % savegame) |
108 |
stdout_filename = self.run_widelands({ "loadgame": os.path.join( |
|
109 |
self.run_dir, "save", "%s.wgf" % savegame) }, which_time) |
|
110 |
which_time += 1 |
|
111 |
stdout = open(stdout_filename, "r").read() |
|
112 |
for new_save in find_saves(stdout): |
|
113 |
if new_save not in savegame_done: |
|
114 |
savegame_done[new_save] = False |
|
115 |
savegame_done[savegame] = True |
|
116 |
self.verify_success(stdout, stdout_filename) |
|
117 |
||
118 |
def verify_success(self, stdout, stdout_filename): |
|
119 |
common_msg = "Analyze the files in %s to see why this test case failed. Stdout is\n %s\n" % ( |
|
120 |
self.run_dir, stdout_filename) |
|
121 |
self.assertTrue(self.widelands_returncode == 0, |
|
122 |
"Widelands exited abnormally. %s" % common_msg |
|
123 |
)
|
|
124 |
self.assertTrue("All Tests passed" in stdout, |
|
125 |
"Not all tests pass. %s." % common_msg |
|
126 |
)
|
|
127 |
out("done.\n") |
|
128 |
if self.keep_output_around: |
|
129 |
out(" stdout: %s\n" % stdout_filename) |
|
6689.1.4
by Holger Rapp
All tests now run and pass on my system. |
130 |
|
131 |
def parse_args(): |
|
132 |
p = argparse.ArgumentParser(description= |
|
133 |
"Run the regression tests suite."
|
|
134 |
)
|
|
135 |
||
136 |
p.add_argument("-r", "--regexp", type=str, |
|
137 |
help = "Run only the tests from the files which filename matches." |
|
138 |
)
|
|
139 |
p.add_argument("-n", "--nonrandom", action="store_true", default = False, |
|
140 |
help = "Do not randomize the directories for the tests. This is useful " |
|
141 |
"if you want to run a test more often than once and not reopen stdout.txt "
|
|
142 |
"in your editor."
|
|
143 |
)
|
|
6801
by Holger Rapp
Fix more bugs around seafaring, especially related to persistence. |
144 |
p.add_argument("-k", "--keep-around", action="store_true", default = False, |
145 |
help = "Keep the output files around even when a test terminates successfully." |
|
146 |
)
|
|
6689.1.6
by Holger Rapp
Let the caller specify the widelands binary to use for regression testing. |
147 |
p.add_argument("-b", "--binary", type=str, |
148 |
help = "Run this binary as Widelands. Otherwise some default paths are searched." |
|
149 |
)
|
|
150 |
||
151 |
args = p.parse_args() |
|
152 |
||
153 |
if args.binary is None: |
|
154 |
potential_binaries = ( |
|
155 |
glob("widelands") + |
|
156 |
glob("src/widelands") + |
|
157 |
glob("../*/src/widelands") |
|
158 |
)
|
|
159 |
if not potential_binaries: |
|
160 |
p.error("No widelands binary found. Please specify with -b.") |
|
161 |
args.binary = potential_binaries[0] |
|
162 |
return args |
|
163 |
||
6689.1.2
by Holger Rapp
Brought back original content of regression_test.py. |
164 |
|
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
165 |
def discover_loadgame_tests(regexp, suite): |
166 |
"""Add all tests using --loadgame to the 'suite'."""
|
|
167 |
for fixture in glob(os.path.join("test", "save", "*")): |
|
168 |
if not os.path.isdir(fixture): |
|
169 |
continue
|
|
170 |
savegame = glob(os.path.join(fixture, "*.wgf"))[0] |
|
171 |
for test_script in glob(os.path.join(fixture, "test*.lua")): |
|
172 |
if regexp is not None and not re.search(regexp, test_script): |
|
173 |
continue
|
|
174 |
suite.addTest( |
|
175 |
WidelandsTestCase(test_script, |
|
176 |
loadgame=savegame, script=test_script)) |
|
177 |
||
178 |
def discover_scenario_tests(regexp, suite): |
|
179 |
"""Add all tests using --scenario to the 'suite'."""
|
|
180 |
for wlmap in glob(os.path.join("test", "maps", "*")): |
|
181 |
if not os.path.isdir(wlmap): |
|
182 |
continue
|
|
183 |
for test_script in glob(os.path.join(wlmap, "scripting", "test*.lua")): |
|
184 |
if regexp is not None and not re.search(regexp, test_script): |
|
185 |
continue
|
|
186 |
suite.addTest( |
|
187 |
WidelandsTestCase(test_script, |
|
188 |
scenario=wlmap, script=test_script)) |
|
189 |
||
190 |
def discover_editor_tests(regexp, suite): |
|
191 |
"""Add all tests needing --editor to the 'suite'."""
|
|
192 |
for wlmap in glob(os.path.join("test", "maps", "*")): |
|
193 |
if not os.path.isdir(wlmap): |
|
194 |
continue
|
|
195 |
for test_script in glob(os.path.join(wlmap, "scripting", "editor_test*.lua")): |
|
196 |
if regexp is not None and not re.search(regexp, test_script): |
|
197 |
continue
|
|
198 |
suite.addTest( |
|
199 |
WidelandsTestCase(test_script, |
|
200 |
editor=wlmap, script=test_script)) |
|
201 |
||
6689.1.2
by Holger Rapp
Brought back original content of regression_test.py. |
202 |
def main(): |
6689.1.4
by Holger Rapp
All tests now run and pass on my system. |
203 |
args = parse_args() |
204 |
||
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
205 |
WidelandsTestCase.path_to_widelands_binary = args.binary |
6689.1.6
by Holger Rapp
Let the caller specify the widelands binary to use for regression testing. |
206 |
print "Using '%s' binary." % args.binary |
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
207 |
WidelandsTestCase.do_use_random_directory = not args.nonrandom |
208 |
WidelandsTestCase.keep_output_around = args.keep_around |
|
6689.1.4
by Holger Rapp
All tests now run and pass on my system. |
209 |
|
210 |
all_files = [os.path.basename(filename) for filename in glob("test/test_*.py") ] |
|
211 |
if args.regexp: |
|
212 |
all_files = [filename for filename in all_files if re.search(args.regexp, filename) ] |
|
213 |
||
214 |
all_modules = [ "test.%s" % filename[:-3] for filename in all_files ] |
|
215 |
||
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
216 |
suite = unittest.TestSuite() |
217 |
discover_loadgame_tests(args.regexp, suite) |
|
218 |
discover_scenario_tests(args.regexp, suite) |
|
219 |
discover_editor_tests(args.regexp, suite) |
|
6689.1.2
by Holger Rapp
Brought back original content of regression_test.py. |
220 |
|
6820.2.7
by Holger Rapp
Finally found a better way to define tests that do not need all the redundant python files. |
221 |
return unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful() |
6689.1.2
by Holger Rapp
Brought back original content of regression_test.py. |
222 |
|
223 |
if __name__ == '__main__': |
|
6803
by Holger Rapp
regression_test.py returns an error to the system on failure. |
224 |
sys.exit(0 if main() else 1) |