##// END OF EJS Templates
make indentation of coverage code in run-tests.py nicer.
Vadim Gelfer -
r2145:5bb3cb9e default
parent child Browse files
Show More
@@ -1,250 +1,250 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 show_diff(expected, output):
38 38 for line in difflib.unified_diff(expected, output,
39 39 "Expected output", "Test output", lineterm=''):
40 40 print line
41 41
42 42 def find_program(program):
43 43 """Search PATH for a executable program"""
44 44 for p in os.environ.get('PATH', os.defpath).split(os.pathsep):
45 45 name = os.path.join(p, program)
46 46 if os.access(name, os.X_OK):
47 47 return name
48 48 return None
49 49
50 50 def check_required_tools():
51 51 # Before we go any further, check for pre-requisite tools
52 52 # stuff from coreutils (cat, rm, etc) are not tested
53 53 for p in required_tools:
54 54 if os.name == 'nt':
55 55 p += '.exe'
56 56 found = find_program(p)
57 57 if found:
58 58 vlog("# Found prerequisite", p, "at", found)
59 59 else:
60 60 print "WARNING: Did not find prerequisite tool: "+p
61 61
62 62 def cleanup_exit():
63 63 if verbose:
64 64 print "# Cleaning up HGTMP", HGTMP
65 65 shutil.rmtree(HGTMP, True)
66 66
67 67 def install_hg():
68 68 vlog("# Performing temporary installation of HG")
69 69 installerrs = os.path.join("tests", "install.err")
70 70
71 71 os.chdir("..") # Get back to hg root
72 72 cmd = '%s setup.py install --home="%s" --install-lib="%s" >%s 2>&1' % \
73 73 (sys.executable, INST, PYTHONDIR, installerrs)
74 74 vlog("# Running", cmd)
75 75 if os.system(cmd) == 0:
76 76 if not verbose:
77 77 os.remove(installerrs)
78 78 else:
79 79 f = open(installerrs)
80 80 for line in f:
81 81 print line,
82 82 f.close()
83 83 sys.exit(1)
84 84 os.chdir(TESTDIR)
85 85
86 86 os.environ["PATH"] = "%s%s%s" % (BINDIR, os.pathsep, os.environ["PATH"])
87 87 os.environ["PYTHONPATH"] = PYTHONDIR
88 88
89 89 if coverage:
90 90 vlog("# Installing coverage wrapper")
91 91 os.environ['COVERAGE_FILE'] = COVERAGE_FILE
92 92 if os.path.exists(COVERAGE_FILE):
93 93 os.unlink(COVERAGE_FILE)
94 94 # Create a wrapper script to invoke hg via coverage.py
95 95 os.rename(os.path.join(BINDIR, "hg"), os.path.join(BINDIR, "_hg.py"))
96 96 f = open(os.path.join(BINDIR, 'hg'), 'w')
97 97 f.write('#!' + sys.executable + '\n')
98 98 f.write('import sys, os; os.execv(sys.executable, [sys.executable, '+ \
99 99 '"%s", "-x", "%s"] + sys.argv[1:])\n' % (
100 100 os.path.join(TESTDIR, 'coverage.py'),
101 101 os.path.join(BINDIR, '_hg.py')))
102 102 f.close()
103 103 os.chmod(os.path.join(BINDIR, 'hg'), 0700)
104 104
105 105 def output_coverage():
106 if coverage:
107 vlog("# Producing coverage report")
108 omit = [BINDIR, TESTDIR, PYTHONDIR]
109 if not options.cover_stdlib:
110 # Exclude as system paths (ignoring empty strings seen on win)
111 omit += [x for x in sys.path if x != '']
112 omit = ','.join(omit)
113 os.chdir(PYTHONDIR)
114 cmd = '"%s" "%s" -r "--omit=%s"' % (
115 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
106 vlog("# Producing coverage report")
107 omit = [BINDIR, TESTDIR, PYTHONDIR]
108 if not options.cover_stdlib:
109 # Exclude as system paths (ignoring empty strings seen on win)
110 omit += [x for x in sys.path if x != '']
111 omit = ','.join(omit)
112 os.chdir(PYTHONDIR)
113 cmd = '"%s" "%s" -r "--omit=%s"' % (
114 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
115 vlog("# Running: "+cmd)
116 os.system(cmd)
117 if options.annotate:
118 adir = os.path.join(TESTDIR, 'annotated')
119 if not os.path.isdir(adir):
120 os.mkdir(adir)
121 cmd = '"%s" "%s" -a "--directory=%s" "--omit=%s"' % (
122 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
123 adir, omit)
116 124 vlog("# Running: "+cmd)
117 125 os.system(cmd)
118 if options.annotate:
119 adir = os.path.join(TESTDIR, 'annotated')
120 if not os.path.isdir(adir):
121 os.mkdir(adir)
122 cmd = '"%s" "%s" -a "--directory=%s" "--omit=%s"' % (
123 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
124 adir, omit)
125 vlog("# Running: "+cmd)
126 os.system(cmd)
127 126
128 127 def run(cmd, split_lines=True):
129 128 """Run command in a sub-process, capturing the output (stdout and stderr).
130 129 Return the exist code, and output."""
131 130 # TODO: Use subprocess.Popen if we're running on Python 2.4
132 131 if os.name == 'nt':
133 132 tochild, fromchild = os.popen4(cmd)
134 133 tochild.close()
135 134 output = fromchild.read()
136 135 ret = fromchild.close()
137 136 if ret == None:
138 137 ret = 0
139 138 else:
140 139 proc = popen2.Popen4(cmd)
141 140 proc.tochild.close()
142 141 output = proc.fromchild.read()
143 142 ret = proc.wait()
144 143 if split_lines:
145 144 output = output.splitlines()
146 145 return ret, output
147 146
148 147 def run_one(test):
149 148 vlog("# Test", test)
150 149 if not verbose:
151 150 sys.stdout.write('.')
152 151 sys.stdout.flush()
153 152
154 153 err = os.path.join(TESTDIR, test+".err")
155 154 ref = os.path.join(TESTDIR, test+".out")
156 155
157 156 if os.path.exists(err):
158 157 os.remove(err) # Remove any previous output files
159 158
160 159 # Make a tmp subdirectory to work in
161 160 tmpd = os.path.join(HGTMP, test)
162 161 os.mkdir(tmpd)
163 162 os.chdir(tmpd)
164 163
165 164 if test.endswith(".py"):
166 165 cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
167 166 else:
168 167 cmd = '"%s"' % (os.path.join(TESTDIR, test))
169 168
170 169 # To reliably get the error code from batch files on WinXP,
171 170 # the "cmd /c call" prefix is needed. Grrr
172 171 if os.name == 'nt' and test.endswith(".bat"):
173 172 cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
174 173
175 174 vlog("# Running", cmd)
176 175 ret, out = run(cmd)
177 176 vlog("# Ret was:", ret)
178 177
179 178 if ret == 0:
180 179 # If reference output file exists, check test output against it
181 180 if os.path.exists(ref):
182 181 f = open(ref, "r")
183 182 ref_out = f.read().splitlines()
184 183 f.close()
185 184 if out != ref_out:
186 185 ret = 1
187 186 print "\nERROR: %s output changed" % (test)
188 187 show_diff(ref_out, out)
189 188 else:
190 189 print "\nERROR: %s failed with error code %d" % (test, ret)
191 190
192 191 if ret != 0: # Save errors to a file for diagnosis
193 192 f = open(err, "w")
194 193 for line in out:
195 194 f.write(line)
196 195 f.write("\n")
197 196 f.close()
198 197
199 198 os.chdir(TESTDIR)
200 199 shutil.rmtree(tmpd, True)
201 200 return ret == 0
202 201
203 202
204 203 os.umask(022)
205 204
206 205 check_required_tools()
207 206
208 207 # Reset some environment variables to well-known values so that
209 208 # the tests produce repeatable output.
210 209 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
211 210 os.environ['TZ'] = 'GMT'
212 211
213 212 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
214 213 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
215 214 os.environ["HGUSER"] = "test"
216 215 os.environ["HGRCPATH"] = ""
217 216
218 217 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
219 218 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
220 219 vlog("# Using TESTDIR", TESTDIR)
221 220 vlog("# Using HGTMP", HGTMP)
222 221
223 222 INST = os.path.join(HGTMP, "install")
224 223 BINDIR = os.path.join(INST, "bin")
225 224 PYTHONDIR = os.path.join(INST, "lib", "python")
226 225 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
227 226
228 227 try:
229 228 install_hg()
230 229
231 230 tests = 0
232 231 failed = 0
233 232
234 233 if len(args) == 0:
235 234 args = os.listdir(".")
236 235 for test in args:
237 236 if test.startswith("test-"):
238 237 if '~' in test or re.search(r'\.(out|err)$', test):
239 238 continue
240 239 if not run_one(test):
241 240 failed += 1
242 241 tests += 1
243 242
244 243 print "\n# Ran %d tests, %d failed." % (tests, failed)
245 output_coverage()
244 if coverage:
245 output_coverage()
246 246 finally:
247 247 cleanup_exit()
248 248
249 249 if failed:
250 250 sys.exit(1)
General Comments 0
You need to be logged in to leave comments. Login now