Mercurial > hg > mercurial-crew-with-dirclash
comparison tests/run-tests.py @ 2110:25a8d116ab6a
Add a pure python version of run-tests.
If this works well for most people, it should replace the shell version
of run-test.
author | Stephen Darnell <stephen@darnell.plus.com> |
---|---|
date | Fri, 21 Apr 2006 18:47:55 +0200 |
parents | |
children | 4334be196f8d |
comparison
equal
deleted
inserted
replaced
2106:b03de24ee2ec | 2110:25a8d116ab6a |
---|---|
1 #!/usr/bin/env python | |
2 # | |
3 # run-tests.py - Run a set of tests on Mercurial | |
4 # | |
5 # Copyright 2006 Matt Mackall <mpm@selenic.com> | |
6 # | |
7 # This software may be used and distributed according to the terms | |
8 # of the GNU General Public License, incorporated herein by reference. | |
9 | |
10 import os, sys, shutil, re | |
11 import tempfile | |
12 import difflib | |
13 import popen2 | |
14 from optparse import OptionParser | |
15 | |
16 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"] | |
17 | |
18 parser = OptionParser() | |
19 parser.add_option("-v", "--verbose", action="store_true", dest="verbose", | |
20 default=False, help="output verbose messages") | |
21 (options, args) = parser.parse_args() | |
22 verbose = options.verbose | |
23 | |
24 def vlog(*msg): | |
25 if verbose: | |
26 for m in msg: | |
27 print m, | |
28 print | |
29 | |
30 def show_diff(expected, output): | |
31 for line in difflib.unified_diff(expected, output, | |
32 "Expected output", "Test output", lineterm=''): | |
33 print line | |
34 | |
35 def find_program(program): | |
36 """Search PATH for a executable program""" | |
37 for p in os.environ.get('PATH', os.defpath).split(os.pathsep): | |
38 name = os.path.join(p, program) | |
39 if os.access(name, os.X_OK): | |
40 return name | |
41 return None | |
42 | |
43 # Before we go any further, check for pre-requisite tools | |
44 # stuff from coreutils (cat, rm, etc) are not tested | |
45 for p in required_tools: | |
46 if os.name == 'nt': | |
47 p += '.exe' | |
48 found = find_program(p) | |
49 if found: | |
50 vlog("# Found prerequisite", p, "at", found) | |
51 else: | |
52 print "WARNING: Did not find prerequisite tool: "+p | |
53 | |
54 # Reset some environment variables to well-known values | |
55 os.environ['LANG'] = os.environ['LC_ALL'] = 'C' | |
56 os.environ['TZ'] = 'GMT' | |
57 | |
58 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"' | |
59 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"' | |
60 os.environ["HGUSER"] = "test" | |
61 os.environ["HGRCPATH"] = "" | |
62 | |
63 TESTDIR = os.environ["TESTDIR"] = os.getcwd() | |
64 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.") | |
65 | |
66 def cleanup_exit(): | |
67 if verbose: | |
68 print "# Cleaning up HGTMP", HGTMP | |
69 shutil.rmtree(HGTMP, True) | |
70 | |
71 vlog("# Using TESTDIR", TESTDIR) | |
72 vlog("# Using HGTMP", HGTMP) | |
73 | |
74 os.umask(022) | |
75 | |
76 vlog("# Performing temporary installation of HG") | |
77 INST = os.path.join(HGTMP, "install") | |
78 BINDIR = os.path.join(INST, "bin") | |
79 PYTHONDIR = os.path.join(INST, "lib", "python") | |
80 installerrs = os.path.join("tests", "install.err") | |
81 | |
82 os.chdir("..") # Get back to hg root | |
83 cmd = '%s setup.py install --home="%s" --install-lib="%s" >%s 2>&1' % \ | |
84 (sys.executable, INST, PYTHONDIR, installerrs) | |
85 vlog("# Running", cmd) | |
86 if os.system(cmd) == 0: | |
87 if not verbose: | |
88 os.remove(installerrs) | |
89 else: | |
90 f = open(installerrs) | |
91 for line in f: | |
92 print line, | |
93 f.close() | |
94 cleanup_exit() | |
95 sys.exit(1) | |
96 os.chdir(TESTDIR) | |
97 | |
98 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"]) | |
99 os.environ["PYTHONPATH"] = PYTHONDIR | |
100 | |
101 tests = 0 | |
102 failed = 0 | |
103 | |
104 def run(cmd, split_lines=True): | |
105 """Run command in a sub-process, capturing the output (stdout and stderr). | |
106 Return the exist code, and output.""" | |
107 # TODO: Use subprocess.Popen if we're running on Python 2.4 | |
108 if os.name == 'nt': | |
109 tochild, fromchild = os.popen4(cmd) | |
110 tochild.close() | |
111 output = fromchild.read() | |
112 ret = fromchild.close() | |
113 if ret == None: | |
114 ret = 0 | |
115 else: | |
116 proc = popen2.Popen4(cmd) | |
117 proc.tochild.close() | |
118 output = proc.fromchild.read() | |
119 ret = proc.wait() | |
120 if split_lines: | |
121 output = output.splitlines() | |
122 return ret, output | |
123 | |
124 def run_one(test): | |
125 vlog("# Test", test) | |
126 if not verbose: | |
127 sys.stdout.write('.') | |
128 sys.stdout.flush() | |
129 | |
130 err = os.path.join(TESTDIR, test+".err") | |
131 ref = os.path.join(TESTDIR, test+".out") | |
132 | |
133 if os.path.exists(err): | |
134 os.remove(err) # Remove any previous output files | |
135 | |
136 # Make a tmp subdirectory to work in | |
137 tmpd = os.path.join(HGTMP, test) | |
138 os.mkdir(tmpd) | |
139 os.chdir(tmpd) | |
140 | |
141 if test.endswith(".py"): | |
142 cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test)) | |
143 else: | |
144 cmd = '"%s"' % (os.path.join(TESTDIR, test)) | |
145 | |
146 # To reliably get the error code from batch files on WinXP, | |
147 # the "cmd /c call" prefix is needed. Grrr | |
148 if os.name == 'nt' and test.endswith(".bat"): | |
149 cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test)) | |
150 | |
151 vlog("# Running", cmd) | |
152 ret, out = run(cmd) | |
153 vlog("# Ret was:", ret) | |
154 | |
155 if ret == 0: | |
156 # If reference output file exists, check test output against it | |
157 if os.path.exists(ref): | |
158 f = open(ref, "r") | |
159 ref_out = f.read().splitlines() | |
160 f.close() | |
161 if out != ref_out: | |
162 ret = 1 | |
163 print "\nERROR: %s output changed" % (test) | |
164 show_diff(ref_out, out) | |
165 else: | |
166 print "\nERROR: %s failed with error code %d" % (test, ret) | |
167 | |
168 if ret != 0: # Save errors to a file for diagnosis | |
169 f = open(err, "w") | |
170 for line in out: | |
171 f.write(line) | |
172 f.write("\n") | |
173 f.close() | |
174 | |
175 os.chdir(TESTDIR) | |
176 shutil.rmtree(tmpd, True) | |
177 return ret == 0 | |
178 | |
179 for test in os.listdir("."): | |
180 if test.startswith("test-"): | |
181 if '~' in test or re.search(r'\.(out|err)$', test): | |
182 continue | |
183 if not run_one(test): | |
184 failed += 1 | |
185 tests += 1 | |
186 | |
187 print "# Ran %d tests, %d failed." % (tests, failed) | |
188 | |
189 cleanup_exit() | |
190 | |
191 if failed: | |
192 sys.exit(1) |