1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
|
"""Base test case class for coverage testing."""
import imp, os, random, shutil, sys, tempfile, textwrap, unittest
from cStringIO import StringIO
import coverage
class Tee(object):
"""A file-like that writes to all the file-likes it was constructed with."""
def __init__(self, *files):
self.files = files
def write(self, data):
for f in self.files:
f.write(data)
class CoverageTest(unittest.TestCase):
def setUp(self):
# Create a temporary directory.
self.noise = str(random.random())[2:]
self.temp_root = os.path.join(tempfile.gettempdir(), 'test_coverage')
self.temp_dir = os.path.join(self.temp_root, self.noise)
os.makedirs(self.temp_dir)
self.old_dir = os.getcwd()
os.chdir(self.temp_dir)
# Modules should be importable from this temp directory.
self.old_syspath = sys.path[:]
sys.path.insert(0, '')
# Keep a counter to make every call to checkCoverage unique.
self.n = 0
# Use a Tee to capture stdout.
self.old_stdout = sys.stdout
self.captured_stdout = StringIO()
sys.stdout = Tee(sys.stdout, self.captured_stdout)
def tearDown(self):
# Restore the original sys.path
sys.path = self.old_syspath
# Get rid of the temporary directory.
os.chdir(self.old_dir)
shutil.rmtree(self.temp_root)
# Restore stdout.
sys.stdout = self.old_stdout
def stdout(self):
"""Return the data written to stdout during the test."""
return self.captured_stdout.getvalue()
def makeFile(self, modname, text):
""" Create a temp file with modname as the module name, and text as the
contents.
"""
text = textwrap.dedent(text)
# Create the python file.
f = open(modname + '.py', 'w')
f.write(text)
f.close()
def importModule(self, modname):
""" Import the module named modname, and return the module object.
"""
modfile = modname + '.py'
f = open(modfile, 'r')
for suff in imp.get_suffixes():
if suff[0] == '.py':
break
try:
# pylint: disable-msg=W0631
# (Using possibly undefined loop variable 'suff')
mod = imp.load_module(modname, f, modfile, suff)
finally:
f.close()
return mod
def getModuleName(self):
# We append self.n because otherwise two calls in one test will use the
# same filename and whether the test works or not depends on the
# timestamps in the .pyc file, so it becomes random whether the second
# call will use the compiled version of the first call's code or not!
modname = 'coverage_test_' + self.noise + str(self.n)
self.n += 1
return modname
def checkCoverage(self, text, lines, missing="", excludes=None, report=""):
# We write the code into a file so that we can import it.
# coverage.py wants to deal with things as modules with file names.
modname = self.getModuleName()
self.makeFile(modname, text)
# Start up coverage.py
cov = coverage.coverage()
cov.erase()
for exc in excludes or []:
cov.exclude(exc)
cov.start()
# Import the python file, executing it.
mod = self.importModule(modname)
# Stop coverage.py
cov.stop()
# Clean up our side effects
del sys.modules[modname]
# Get the analysis results, and check that they are right.
_, clines, _, cmissing = cov.analysis(mod)
if lines is not None:
if type(lines[0]) == type(1):
self.assertEqual(clines, lines)
else:
for line_list in lines:
if clines == line_list:
break
else:
self.fail("None of the lines choices matched %r" % clines)
if missing is not None:
if type(missing) == type(""):
self.assertEqual(cmissing, missing)
else:
for missing_list in missing:
if cmissing == missing_list:
break
else:
self.fail(
"None of the missing choices matched %r" % cmissing
)
if report:
frep = StringIO()
cov.report(mod, file=frep)
rep = " ".join(frep.getvalue().split("\n")[2].split()[1:])
self.assertEqual(report, rep)
def assertRaisesMsg(self, excClass, msg, callableObj, *args, **kwargs):
""" Just like unittest.TestCase.assertRaises,
but checks that the message is right too.
"""
try:
callableObj(*args, **kwargs)
except excClass, exc:
excMsg = str(exc)
if not msg:
# No message provided: it passes.
return #pragma: no cover
elif excMsg == msg:
# Message provided, and we got the right message: it passes.
return
else: #pragma: no cover
# Message provided, and it didn't match: fail!
raise self.failureException(
"Right exception, wrong message: got '%s' expected '%s'" %
(excMsg, msg)
)
# No need to catch other exceptions: They'll fail the test all by
# themselves!
else: #pragma: no cover
if hasattr(excClass,'__name__'):
excName = excClass.__name__
else:
excName = str(excClass)
raise self.failureException(
"Expected to raise %s, didn't get an exception at all" % excName
)
def nice_file(self, *fparts):
"""Canonicalize the filename composed of the parts in `fparts`."""
fname = os.path.join(*fparts)
return os.path.normcase(os.path.abspath(os.path.realpath(fname)))
def run_command(self, cmd):
""" Run the command-line `cmd`, print its output.
"""
# Add our test modules directory to PYTHONPATH. I'm sure there's too
# much path munging here, but...
here = os.path.dirname(self.nice_file(coverage.__file__, ".."))
testmods = self.nice_file(here, 'test/modules')
zipfile = self.nice_file(here, 'test/zipmods.zip')
pypath = os.environ['PYTHONPATH']
if pypath:
pypath += os.pathsep
pypath += testmods + os.pathsep + zipfile
os.environ['PYTHONPATH'] = pypath
stdin_unused, stdouterr = os.popen4(cmd)
output = stdouterr.read()
print output
return output
|