##// END OF EJS Templates
Don't run tests with dots in their name (e.g. test-foo.orig)
Thomas Arendsen Hein -
r2408:6ed46bad default
parent child Browse files
Show More
@@ -1,271 +1,269 b''
1 1 #!/usr/bin/env python
2 2 #
3 3 # run-tests.py - Run a set of tests on Mercurial
4 4 #
5 5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms
8 8 # of the GNU General Public License, incorporated herein by reference.
9 9
10 10 import os, sys, shutil, re
11 11 import tempfile
12 12 import difflib
13 13 import popen2
14 14 from optparse import OptionParser
15 15
16 16 required_tools = ["python", "diff", "grep", "unzip", "gunzip", "bunzip2", "sed"]
17 17
18 18 parser = OptionParser("%prog [options] [tests]")
19 19 parser.add_option("-v", "--verbose", action="store_true",
20 20 help="output verbose messages")
21 21 parser.add_option("-c", "--cover", action="store_true",
22 22 help="print a test coverage report")
23 23 parser.add_option("-s", "--cover_stdlib", action="store_true",
24 24 help="print a test coverage report inc. standard libraries")
25 25 parser.add_option("-C", "--annotate", action="store_true",
26 26 help="output files annotated with coverage")
27 27 (options, args) = parser.parse_args()
28 28 verbose = options.verbose
29 29 coverage = options.cover or options.cover_stdlib or options.annotate
30 30
31 31 def vlog(*msg):
32 32 if verbose:
33 33 for m in msg:
34 34 print m,
35 35 print
36 36
37 37 def splitnewlines(text):
38 38 '''like str.splitlines, but only split on newlines.
39 39 keep line endings.'''
40 40 i = 0
41 41 lines = []
42 42 while True:
43 43 n = text.find('\n', i)
44 44 if n == -1:
45 45 last = text[i:]
46 46 if last:
47 47 lines.append(last)
48 48 return lines
49 49 lines.append(text[i:n+1])
50 50 i = n + 1
51 51
52 52 def show_diff(expected, output):
53 53 for line in difflib.unified_diff(expected, output,
54 54 "Expected output", "Test output", lineterm=''):
55 55 sys.stdout.write(line)
56 56
57 57 def find_program(program):
58 58 """Search PATH for a executable program"""
59 59 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
60 60 name = os.path.join(p, program)
61 61 if os.access(name, os.X_OK):
62 62 return name
63 63 return None
64 64
65 65 def check_required_tools():
66 66 # Before we go any further, check for pre-requisite tools
67 67 # stuff from coreutils (cat, rm, etc) are not tested
68 68 for p in required_tools:
69 69 if os.name == 'nt':
70 70 p += '.exe'
71 71 found = find_program(p)
72 72 if found:
73 73 vlog("# Found prerequisite", p, "at", found)
74 74 else:
75 75 print "WARNING: Did not find prerequisite tool: "+p
76 76
77 77 def cleanup_exit():
78 78 if verbose:
79 79 print "# Cleaning up HGTMP", HGTMP
80 80 shutil.rmtree(HGTMP, True)
81 81
82 82 def install_hg():
83 83 vlog("# Performing temporary installation of HG")
84 84 installerrs = os.path.join("tests", "install.err")
85 85
86 86 os.chdir("..") # Get back to hg root
87 87 cmd = ('%s setup.py clean --all'
88 88 ' install --force --home="%s" --install-lib="%s" >%s 2>&1'
89 89 % (sys.executable, INST, PYTHONDIR, installerrs))
90 90 vlog("# Running", cmd)
91 91 if os.system(cmd) == 0:
92 92 if not verbose:
93 93 os.remove(installerrs)
94 94 else:
95 95 f = open(installerrs)
96 96 for line in f:
97 97 print line,
98 98 f.close()
99 99 sys.exit(1)
100 100 os.chdir(TESTDIR)
101 101
102 102 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
103 103 os.environ["PYTHONPATH"] = PYTHONDIR
104 104
105 105 if coverage:
106 106 vlog("# Installing coverage wrapper")
107 107 os.environ['COVERAGE_FILE'] = COVERAGE_FILE
108 108 if os.path.exists(COVERAGE_FILE):
109 109 os.unlink(COVERAGE_FILE)
110 110 # Create a wrapper script to invoke hg via coverage.py
111 111 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py"))
112 112 f = open(os.path.join(BINDIR, 'hg'), 'w')
113 113 f.write('#!' + sys.executable + '\n')
114 114 f.write('import sys, os; os.execv(sys.executable, [sys.executable, '+ \
115 115 '"%s", "-x", "%s"] + sys.argv[1:])\n' % (
116 116 os.path.join(TESTDIR, 'coverage.py'),
117 117 os.path.join(BINDIR, '_hg.py')))
118 118 f.close()
119 119 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
120 120
121 121 def output_coverage():
122 122 vlog("# Producing coverage report")
123 123 omit = [BINDIR, TESTDIR, PYTHONDIR]
124 124 if not options.cover_stdlib:
125 125 # Exclude as system paths (ignoring empty strings seen on win)
126 126 omit += [x for x in sys.path if x != '']
127 127 omit = ','.join(omit)
128 128 os.chdir(PYTHONDIR)
129 129 cmd = '"%s" "%s" -r "--omit=%s"' % (
130 130 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
131 131 vlog("# Running: "+cmd)
132 132 os.system(cmd)
133 133 if options.annotate:
134 134 adir = os.path.join(TESTDIR, 'annotated')
135 135 if not os.path.isdir(adir):
136 136 os.mkdir(adir)
137 137 cmd = '"%s" "%s" -a "--directory=%s" "--omit=%s"' % (
138 138 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
139 139 adir, omit)
140 140 vlog("# Running: "+cmd)
141 141 os.system(cmd)
142 142
143 143 def run(cmd):
144 144 """Run command in a sub-process, capturing the output (stdout and stderr).
145 145 Return the exist code, and output."""
146 146 # TODO: Use subprocess.Popen if we're running on Python 2.4
147 147 if os.name == 'nt':
148 148 tochild, fromchild = os.popen4(cmd)
149 149 tochild.close()
150 150 output = fromchild.read()
151 151 ret = fromchild.close()
152 152 if ret == None:
153 153 ret = 0
154 154 else:
155 155 proc = popen2.Popen4(cmd)
156 156 proc.tochild.close()
157 157 output = proc.fromchild.read()
158 158 ret = proc.wait()
159 159 return ret, splitnewlines(output)
160 160
161 161 def run_one(test):
162 162 vlog("# Test", test)
163 163 if not verbose:
164 164 sys.stdout.write('.')
165 165 sys.stdout.flush()
166 166
167 167 err = os.path.join(TESTDIR, test+".err")
168 168 ref = os.path.join(TESTDIR, test+".out")
169 169
170 170 if os.path.exists(err):
171 171 os.remove(err) # Remove any previous output files
172 172
173 173 # Make a tmp subdirectory to work in
174 174 tmpd = os.path.join(HGTMP, test)
175 175 os.mkdir(tmpd)
176 176 os.chdir(tmpd)
177 177
178 178 if test.endswith(".py"):
179 179 cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
180 180 else:
181 181 cmd = '"%s"' % (os.path.join(TESTDIR, test))
182 182
183 183 # To reliably get the error code from batch files on WinXP,
184 184 # the "cmd /c call" prefix is needed. Grrr
185 185 if os.name == 'nt' and test.endswith(".bat"):
186 186 cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
187 187
188 188 vlog("# Running", cmd)
189 189 ret, out = run(cmd)
190 190 vlog("# Ret was:", ret)
191 191
192 192 diffret = 0
193 193 # If reference output file exists, check test output against it
194 194 if os.path.exists(ref):
195 195 f = open(ref, "r")
196 196 ref_out = splitnewlines(f.read())
197 197 f.close()
198 198 else:
199 199 ref_out = ['']
200 200 if out != ref_out:
201 201 diffret = 1
202 202 print "\nERROR: %s output changed" % (test)
203 203 show_diff(ref_out, out)
204 204 if ret:
205 205 print "\nERROR: %s failed with error code %d" % (test, ret)
206 206 elif diffret:
207 207 ret = diffret
208 208
209 209 if ret != 0: # Save errors to a file for diagnosis
210 210 f = open(err, "wb")
211 211 for line in out:
212 212 f.write(line)
213 213 f.close()
214 214
215 215 os.chdir(TESTDIR)
216 216 shutil.rmtree(tmpd, True)
217 217 return ret == 0
218 218
219 219
220 220 os.umask(022)
221 221
222 222 check_required_tools()
223 223
224 224 # Reset some environment variables to well-known values so that
225 225 # the tests produce repeatable output.
226 226 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
227 227 os.environ['TZ'] = 'GMT'
228 228
229 229 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
230 230 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
231 231 os.environ["HGUSER"] = "test"
232 232 os.environ["HGRCPATH"] = ""
233 233
234 234 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
235 235 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
236 236 vlog("# Using TESTDIR", TESTDIR)
237 237 vlog("# Using HGTMP", HGTMP)
238 238
239 239 INST = os.path.join(HGTMP, "install")
240 240 BINDIR = os.path.join(INST, "bin")
241 241 PYTHONDIR = os.path.join(INST, "lib", "python")
242 242 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
243 243
244 244 try:
245 245 try:
246 246 install_hg()
247 247
248 248 tests = 0
249 249 failed = 0
250 250
251 251 if len(args) == 0:
252 252 args = os.listdir(".")
253 253 for test in args:
254 if test.startswith("test-"):
255 if '~' in test or re.search(r'\.(out|err)$', test):
256 continue
254 if test.startswith("test-") and not '~' in test and not '.' in test:
257 255 if not run_one(test):
258 256 failed += 1
259 257 tests += 1
260 258
261 259 print "\n# Ran %d tests, %d failed." % (tests, failed)
262 260 if coverage:
263 261 output_coverage()
264 262 except KeyboardInterrupt:
265 263 failed = True
266 264 print "\ninterrupted!"
267 265 finally:
268 266 cleanup_exit()
269 267
270 268 if failed:
271 269 sys.exit(1)
General Comments 0
You need to be logged in to leave comments. Login now