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