##// END OF EJS Templates
run-tests.py: remove trailing white space
Vadim Gelfer -
r2146:eb1ed410 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 vlog("# Producing coverage report")
106 vlog("# Producing coverage report")
107 omit = [BINDIR, TESTDIR, PYTHONDIR]
107 omit = [BINDIR, TESTDIR, PYTHONDIR]
108 if not options.cover_stdlib:
108 if not options.cover_stdlib:
109 # Exclude as system paths (ignoring empty strings seen on win)
109 # Exclude as system paths (ignoring empty strings seen on win)
110 omit += [x for x in sys.path if x != '']
110 omit += [x for x in sys.path if x != '']
111 omit = ','.join(omit)
111 omit = ','.join(omit)
112 os.chdir(PYTHONDIR)
112 os.chdir(PYTHONDIR)
113 cmd = '"%s" "%s" -r "--omit=%s"' % (
113 cmd = '"%s" "%s" -r "--omit=%s"' % (
114 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
114 sys.executable, os.path.join(TESTDIR, 'coverage.py'), omit)
115 vlog("# Running: "+cmd)
115 vlog("# Running: "+cmd)
116 os.system(cmd)
116 os.system(cmd)
117 if options.annotate:
117 if options.annotate:
118 adir = os.path.join(TESTDIR, 'annotated')
118 adir = os.path.join(TESTDIR, 'annotated')
119 if not os.path.isdir(adir):
119 if not os.path.isdir(adir):
120 os.mkdir(adir)
120 os.mkdir(adir)
121 cmd = '"%s" "%s" -a "--directory=%s" "--omit=%s"' % (
121 cmd = '"%s" "%s" -a "--directory=%s" "--omit=%s"' % (
122 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
122 sys.executable, os.path.join(TESTDIR, 'coverage.py'),
123 adir, omit)
123 adir, omit)
124 vlog("# Running: "+cmd)
124 vlog("# Running: "+cmd)
125 os.system(cmd)
125 os.system(cmd)
126
126
127 def run(cmd, split_lines=True):
127 def run(cmd, split_lines=True):
128 """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).
129 Return the exist code, and output."""
129 Return the exist code, and output."""
130 # 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
131 if os.name == 'nt':
131 if os.name == 'nt':
132 tochild, fromchild = os.popen4(cmd)
132 tochild, fromchild = os.popen4(cmd)
133 tochild.close()
133 tochild.close()
134 output = fromchild.read()
134 output = fromchild.read()
135 ret = fromchild.close()
135 ret = fromchild.close()
136 if ret == None:
136 if ret == None:
137 ret = 0
137 ret = 0
138 else:
138 else:
139 proc = popen2.Popen4(cmd)
139 proc = popen2.Popen4(cmd)
140 proc.tochild.close()
140 proc.tochild.close()
141 output = proc.fromchild.read()
141 output = proc.fromchild.read()
142 ret = proc.wait()
142 ret = proc.wait()
143 if split_lines:
143 if split_lines:
144 output = output.splitlines()
144 output = output.splitlines()
145 return ret, output
145 return ret, output
146
146
147 def run_one(test):
147 def run_one(test):
148 vlog("# Test", test)
148 vlog("# Test", test)
149 if not verbose:
149 if not verbose:
150 sys.stdout.write('.')
150 sys.stdout.write('.')
151 sys.stdout.flush()
151 sys.stdout.flush()
152
152
153 err = os.path.join(TESTDIR, test+".err")
153 err = os.path.join(TESTDIR, test+".err")
154 ref = os.path.join(TESTDIR, test+".out")
154 ref = os.path.join(TESTDIR, test+".out")
155
155
156 if os.path.exists(err):
156 if os.path.exists(err):
157 os.remove(err) # Remove any previous output files
157 os.remove(err) # Remove any previous output files
158
158
159 # Make a tmp subdirectory to work in
159 # Make a tmp subdirectory to work in
160 tmpd = os.path.join(HGTMP, test)
160 tmpd = os.path.join(HGTMP, test)
161 os.mkdir(tmpd)
161 os.mkdir(tmpd)
162 os.chdir(tmpd)
162 os.chdir(tmpd)
163
163
164 if test.endswith(".py"):
164 if test.endswith(".py"):
165 cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
165 cmd = '%s "%s"' % (sys.executable, os.path.join(TESTDIR, test))
166 else:
166 else:
167 cmd = '"%s"' % (os.path.join(TESTDIR, test))
167 cmd = '"%s"' % (os.path.join(TESTDIR, test))
168
168
169 # To reliably get the error code from batch files on WinXP,
169 # To reliably get the error code from batch files on WinXP,
170 # the "cmd /c call" prefix is needed. Grrr
170 # the "cmd /c call" prefix is needed. Grrr
171 if os.name == 'nt' and test.endswith(".bat"):
171 if os.name == 'nt' and test.endswith(".bat"):
172 cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
172 cmd = 'cmd /c call "%s"' % (os.path.join(TESTDIR, test))
173
173
174 vlog("# Running", cmd)
174 vlog("# Running", cmd)
175 ret, out = run(cmd)
175 ret, out = run(cmd)
176 vlog("# Ret was:", ret)
176 vlog("# Ret was:", ret)
177
177
178 if ret == 0:
178 if ret == 0:
179 # If reference output file exists, check test output against it
179 # If reference output file exists, check test output against it
180 if os.path.exists(ref):
180 if os.path.exists(ref):
181 f = open(ref, "r")
181 f = open(ref, "r")
182 ref_out = f.read().splitlines()
182 ref_out = f.read().splitlines()
183 f.close()
183 f.close()
184 if out != ref_out:
184 if out != ref_out:
185 ret = 1
185 ret = 1
186 print "\nERROR: %s output changed" % (test)
186 print "\nERROR: %s output changed" % (test)
187 show_diff(ref_out, out)
187 show_diff(ref_out, out)
188 else:
188 else:
189 print "\nERROR: %s failed with error code %d" % (test, ret)
189 print "\nERROR: %s failed with error code %d" % (test, ret)
190
190
191 if ret != 0: # Save errors to a file for diagnosis
191 if ret != 0: # Save errors to a file for diagnosis
192 f = open(err, "w")
192 f = open(err, "w")
193 for line in out:
193 for line in out:
194 f.write(line)
194 f.write(line)
195 f.write("\n")
195 f.write("\n")
196 f.close()
196 f.close()
197
197
198 os.chdir(TESTDIR)
198 os.chdir(TESTDIR)
199 shutil.rmtree(tmpd, True)
199 shutil.rmtree(tmpd, True)
200 return ret == 0
200 return ret == 0
201
201
202
202
203 os.umask(022)
203 os.umask(022)
204
204
205 check_required_tools()
205 check_required_tools()
206
206
207 # Reset some environment variables to well-known values so that
207 # Reset some environment variables to well-known values so that
208 # the tests produce repeatable output.
208 # the tests produce repeatable output.
209 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
209 os.environ['LANG'] = os.environ['LC_ALL'] = 'C'
210 os.environ['TZ'] = 'GMT'
210 os.environ['TZ'] = 'GMT'
211
211
212 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
212 os.environ["HGEDITOR"] = sys.executable + ' -c "import sys; sys.exit(0)"'
213 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
213 os.environ["HGMERGE"] = sys.executable + ' -c "import sys; sys.exit(0)"'
214 os.environ["HGUSER"] = "test"
214 os.environ["HGUSER"] = "test"
215 os.environ["HGRCPATH"] = ""
215 os.environ["HGRCPATH"] = ""
216
216
217 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
217 TESTDIR = os.environ["TESTDIR"] = os.getcwd()
218 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
218 HGTMP = os.environ["HGTMP"] = tempfile.mkdtemp("", "hgtests.")
219 vlog("# Using TESTDIR", TESTDIR)
219 vlog("# Using TESTDIR", TESTDIR)
220 vlog("# Using HGTMP", HGTMP)
220 vlog("# Using HGTMP", HGTMP)
221
221
222 INST = os.path.join(HGTMP, "install")
222 INST = os.path.join(HGTMP, "install")
223 BINDIR = os.path.join(INST, "bin")
223 BINDIR = os.path.join(INST, "bin")
224 PYTHONDIR = os.path.join(INST, "lib", "python")
224 PYTHONDIR = os.path.join(INST, "lib", "python")
225 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
225 COVERAGE_FILE = os.path.join(TESTDIR, ".coverage")
226
226
227 try:
227 try:
228 install_hg()
228 install_hg()
229
229
230 tests = 0
230 tests = 0
231 failed = 0
231 failed = 0
232
232
233 if len(args) == 0:
233 if len(args) == 0:
234 args = os.listdir(".")
234 args = os.listdir(".")
235 for test in args:
235 for test in args:
236 if test.startswith("test-"):
236 if test.startswith("test-"):
237 if '~' in test or re.search(r'\.(out|err)$', test):
237 if '~' in test or re.search(r'\.(out|err)$', test):
238 continue
238 continue
239 if not run_one(test):
239 if not run_one(test):
240 failed += 1
240 failed += 1
241 tests += 1
241 tests += 1
242
242
243 print "\n# Ran %d tests, %d failed." % (tests, failed)
243 print "\n# Ran %d tests, %d failed." % (tests, failed)
244 if coverage:
244 if coverage:
245 output_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