Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: tools/telemetry/third_party/coverage/tests/test_api.py

Issue 1366913004: Add coverage Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
3
4 """Tests for coverage.py's API."""
5
6 import fnmatch
7 import os
8 import sys
9 import textwrap
10
11 import coverage
12 from coverage.backward import StringIO
13 from coverage.misc import CoverageException
14
15 from tests.coveragetest import CoverageTest
16
17
18 class ApiTest(CoverageTest):
19 """Api-oriented tests for coverage.py."""
20
21 def clean_files(self, files, pats):
22 """Remove names matching `pats` from `files`, a list of file names."""
23 good = []
24 for f in files:
25 for pat in pats:
26 if fnmatch.fnmatch(f, pat):
27 break
28 else:
29 good.append(f)
30 return good
31
32 def assertFiles(self, files):
33 """Assert that the files here are `files`, ignoring the usual junk."""
34 here = os.listdir(".")
35 here = self.clean_files(here, ["*.pyc", "__pycache__"])
36 self.assertCountEqual(here, files)
37
38 def test_unexecuted_file(self):
39 cov = coverage.Coverage()
40
41 self.make_file("mycode.py", """\
42 a = 1
43 b = 2
44 if b == 3:
45 c = 4
46 d = 5
47 """)
48
49 self.make_file("not_run.py", """\
50 fooey = 17
51 """)
52
53 # Import the Python file, executing it.
54 self.start_import_stop(cov, "mycode")
55
56 _, statements, missing, _ = cov.analysis("not_run.py")
57 self.assertEqual(statements, [1])
58 self.assertEqual(missing, [1])
59
60 def test_filenames(self):
61
62 self.make_file("mymain.py", """\
63 import mymod
64 a = 1
65 """)
66
67 self.make_file("mymod.py", """\
68 fooey = 17
69 """)
70
71 # Import the Python file, executing it.
72 cov = coverage.Coverage()
73 self.start_import_stop(cov, "mymain")
74
75 filename, _, _, _ = cov.analysis("mymain.py")
76 self.assertEqual(os.path.basename(filename), "mymain.py")
77 filename, _, _, _ = cov.analysis("mymod.py")
78 self.assertEqual(os.path.basename(filename), "mymod.py")
79
80 filename, _, _, _ = cov.analysis(sys.modules["mymain"])
81 self.assertEqual(os.path.basename(filename), "mymain.py")
82 filename, _, _, _ = cov.analysis(sys.modules["mymod"])
83 self.assertEqual(os.path.basename(filename), "mymod.py")
84
85 # Import the Python file, executing it again, once it's been compiled
86 # already.
87 cov = coverage.Coverage()
88 self.start_import_stop(cov, "mymain")
89
90 filename, _, _, _ = cov.analysis("mymain.py")
91 self.assertEqual(os.path.basename(filename), "mymain.py")
92 filename, _, _, _ = cov.analysis("mymod.py")
93 self.assertEqual(os.path.basename(filename), "mymod.py")
94
95 filename, _, _, _ = cov.analysis(sys.modules["mymain"])
96 self.assertEqual(os.path.basename(filename), "mymain.py")
97 filename, _, _, _ = cov.analysis(sys.modules["mymod"])
98 self.assertEqual(os.path.basename(filename), "mymod.py")
99
100 def test_ignore_stdlib(self):
101 self.make_file("mymain.py", """\
102 import colorsys
103 a = 1
104 hls = colorsys.rgb_to_hls(1.0, 0.5, 0.0)
105 """)
106
107 # Measure without the stdlib.
108 cov1 = coverage.Coverage()
109 self.assertEqual(cov1.config.cover_pylib, False)
110 self.start_import_stop(cov1, "mymain")
111
112 # some statements were marked executed in mymain.py
113 _, statements, missing, _ = cov1.analysis("mymain.py")
114 self.assertNotEqual(statements, missing)
115 # but none were in colorsys.py
116 _, statements, missing, _ = cov1.analysis("colorsys.py")
117 self.assertEqual(statements, missing)
118
119 # Measure with the stdlib.
120 cov2 = coverage.Coverage(cover_pylib=True)
121 self.start_import_stop(cov2, "mymain")
122
123 # some statements were marked executed in mymain.py
124 _, statements, missing, _ = cov2.analysis("mymain.py")
125 self.assertNotEqual(statements, missing)
126 # and some were marked executed in colorsys.py
127 _, statements, missing, _ = cov2.analysis("colorsys.py")
128 self.assertNotEqual(statements, missing)
129
130 def test_include_can_measure_stdlib(self):
131 self.make_file("mymain.py", """\
132 import colorsys, random
133 a = 1
134 r, g, b = [random.random() for _ in range(3)]
135 hls = colorsys.rgb_to_hls(r, g, b)
136 """)
137
138 # Measure without the stdlib, but include colorsys.
139 cov1 = coverage.Coverage(cover_pylib=False, include=["*/colorsys.py"])
140 self.start_import_stop(cov1, "mymain")
141
142 # some statements were marked executed in colorsys.py
143 _, statements, missing, _ = cov1.analysis("colorsys.py")
144 self.assertNotEqual(statements, missing)
145 # but none were in random.py
146 _, statements, missing, _ = cov1.analysis("random.py")
147 self.assertEqual(statements, missing)
148
149 def test_exclude_list(self):
150 cov = coverage.Coverage()
151 cov.clear_exclude()
152 self.assertEqual(cov.get_exclude_list(), [])
153 cov.exclude("foo")
154 self.assertEqual(cov.get_exclude_list(), ["foo"])
155 cov.exclude("bar")
156 self.assertEqual(cov.get_exclude_list(), ["foo", "bar"])
157 self.assertEqual(cov._exclude_regex('exclude'), "(?:foo)|(?:bar)")
158 cov.clear_exclude()
159 self.assertEqual(cov.get_exclude_list(), [])
160
161 def test_exclude_partial_list(self):
162 cov = coverage.Coverage()
163 cov.clear_exclude(which='partial')
164 self.assertEqual(cov.get_exclude_list(which='partial'), [])
165 cov.exclude("foo", which='partial')
166 self.assertEqual(cov.get_exclude_list(which='partial'), ["foo"])
167 cov.exclude("bar", which='partial')
168 self.assertEqual(cov.get_exclude_list(which='partial'), ["foo", "bar"])
169 self.assertEqual(
170 cov._exclude_regex(which='partial'), "(?:foo)|(?:bar)"
171 )
172 cov.clear_exclude(which='partial')
173 self.assertEqual(cov.get_exclude_list(which='partial'), [])
174
175 def test_exclude_and_partial_are_separate_lists(self):
176 cov = coverage.Coverage()
177 cov.clear_exclude(which='partial')
178 cov.clear_exclude(which='exclude')
179 cov.exclude("foo", which='partial')
180 self.assertEqual(cov.get_exclude_list(which='partial'), ['foo'])
181 self.assertEqual(cov.get_exclude_list(which='exclude'), [])
182 cov.exclude("bar", which='exclude')
183 self.assertEqual(cov.get_exclude_list(which='partial'), ['foo'])
184 self.assertEqual(cov.get_exclude_list(which='exclude'), ['bar'])
185 cov.exclude("p2", which='partial')
186 cov.exclude("e2", which='exclude')
187 self.assertEqual(cov.get_exclude_list(which='partial'), ['foo', 'p2'])
188 self.assertEqual(cov.get_exclude_list(which='exclude'), ['bar', 'e2'])
189 cov.clear_exclude(which='partial')
190 self.assertEqual(cov.get_exclude_list(which='partial'), [])
191 self.assertEqual(cov.get_exclude_list(which='exclude'), ['bar', 'e2'])
192 cov.clear_exclude(which='exclude')
193 self.assertEqual(cov.get_exclude_list(which='partial'), [])
194 self.assertEqual(cov.get_exclude_list(which='exclude'), [])
195
196 def test_datafile_default(self):
197 # Default data file behavior: it's .coverage
198 self.make_file("datatest1.py", """\
199 fooey = 17
200 """)
201
202 self.assertFiles(["datatest1.py"])
203 cov = coverage.Coverage()
204 self.start_import_stop(cov, "datatest1")
205 cov.save()
206 self.assertFiles(["datatest1.py", ".coverage"])
207
208 def test_datafile_specified(self):
209 # You can specify the data file name.
210 self.make_file("datatest2.py", """\
211 fooey = 17
212 """)
213
214 self.assertFiles(["datatest2.py"])
215 cov = coverage.Coverage(data_file="cov.data")
216 self.start_import_stop(cov, "datatest2")
217 cov.save()
218 self.assertFiles(["datatest2.py", "cov.data"])
219
220 def test_datafile_and_suffix_specified(self):
221 # You can specify the data file name and suffix.
222 self.make_file("datatest3.py", """\
223 fooey = 17
224 """)
225
226 self.assertFiles(["datatest3.py"])
227 cov = coverage.Coverage(data_file="cov.data", data_suffix="14")
228 self.start_import_stop(cov, "datatest3")
229 cov.save()
230 self.assertFiles(["datatest3.py", "cov.data.14"])
231
232 def test_datafile_from_rcfile(self):
233 # You can specify the data file name in the .coveragerc file
234 self.make_file("datatest4.py", """\
235 fooey = 17
236 """)
237 self.make_file(".coveragerc", """\
238 [run]
239 data_file = mydata.dat
240 """)
241
242 self.assertFiles(["datatest4.py", ".coveragerc"])
243 cov = coverage.Coverage()
244 self.start_import_stop(cov, "datatest4")
245 cov.save()
246 self.assertFiles(["datatest4.py", ".coveragerc", "mydata.dat"])
247
248 def test_empty_reporting(self):
249 # empty summary reports raise exception, just like the xml report
250 cov = coverage.Coverage()
251 cov.erase()
252 self.assertRaises(CoverageException, cov.report)
253
254 def test_start_stop_start_stop(self):
255 self.make_file("code1.py", """\
256 code1 = 1
257 """)
258 self.make_file("code2.py", """\
259 code2 = 1
260 code2 = 2
261 """)
262 cov = coverage.Coverage()
263 self.start_import_stop(cov, "code1")
264 cov.save()
265 self.start_import_stop(cov, "code2")
266 _, statements, missing, _ = cov.analysis("code1.py")
267 self.assertEqual(statements, [1])
268 self.assertEqual(missing, [])
269 _, statements, missing, _ = cov.analysis("code2.py")
270 self.assertEqual(statements, [1, 2])
271 self.assertEqual(missing, [])
272
273 if 0: # expected failure
274 # for https://bitbucket.org/ned/coveragepy/issue/79
275 def test_start_save_stop(self):
276 self.make_file("code1.py", """\
277 code1 = 1
278 """)
279 self.make_file("code2.py", """\
280 code2 = 1
281 code2 = 2
282 """)
283 cov = coverage.Coverage()
284 cov.start()
285 self.import_local_file("code1")
286 cov.save()
287 self.import_local_file("code2")
288 cov.stop()
289
290 _, statements, missing, _ = cov.analysis("code1.py")
291 self.assertEqual(statements, [1])
292 self.assertEqual(missing, [])
293 _, statements, missing, _ = cov.analysis("code2.py")
294 self.assertEqual(statements, [1, 2])
295 self.assertEqual(missing, [])
296
297
298
299 class UsingModulesMixin(object):
300 """A mixin for importing modules from test/modules and test/moremodules."""
301
302 run_in_temp_dir = False
303
304 def setUp(self):
305 super(UsingModulesMixin, self).setUp()
306
307 old_dir = os.getcwd()
308 os.chdir(self.nice_file(os.path.dirname(__file__), 'modules'))
309 self.addCleanup(os.chdir, old_dir)
310
311 # Parent class saves and restores sys.path, we can just modify it.
312 sys.path.append(".")
313 sys.path.append("../moremodules")
314
315
316 class OmitIncludeTestsMixin(UsingModulesMixin):
317 """Test methods for coverage methods taking include and omit."""
318
319 def filenames_in(self, summary, filenames):
320 """Assert the `filenames` are in the keys of `summary`."""
321 for filename in filenames.split():
322 self.assertIn(filename, summary)
323
324 def filenames_not_in(self, summary, filenames):
325 """Assert the `filenames` are not in the keys of `summary`."""
326 for filename in filenames.split():
327 self.assertNotIn(filename, summary)
328
329 def test_nothing_specified(self):
330 result = self.coverage_usepkgs()
331 self.filenames_in(result, "p1a p1b p2a p2b othera otherb osa osb")
332 self.filenames_not_in(result, "p1c")
333 # Because there was no source= specified, we don't search for
334 # unexecuted files.
335
336 def test_include(self):
337 result = self.coverage_usepkgs(include=["*/p1a.py"])
338 self.filenames_in(result, "p1a")
339 self.filenames_not_in(result, "p1b p1c p2a p2b othera otherb osa osb")
340
341 def test_include_2(self):
342 result = self.coverage_usepkgs(include=["*a.py"])
343 self.filenames_in(result, "p1a p2a othera osa")
344 self.filenames_not_in(result, "p1b p1c p2b otherb osb")
345
346 def test_include_as_string(self):
347 result = self.coverage_usepkgs(include="*a.py")
348 self.filenames_in(result, "p1a p2a othera osa")
349 self.filenames_not_in(result, "p1b p1c p2b otherb osb")
350
351 def test_omit(self):
352 result = self.coverage_usepkgs(omit=["*/p1a.py"])
353 self.filenames_in(result, "p1b p2a p2b")
354 self.filenames_not_in(result, "p1a p1c")
355
356 def test_omit_2(self):
357 result = self.coverage_usepkgs(omit=["*a.py"])
358 self.filenames_in(result, "p1b p2b otherb osb")
359 self.filenames_not_in(result, "p1a p1c p2a othera osa")
360
361 def test_omit_as_string(self):
362 result = self.coverage_usepkgs(omit="*a.py")
363 self.filenames_in(result, "p1b p2b otherb osb")
364 self.filenames_not_in(result, "p1a p1c p2a othera osa")
365
366 def test_omit_and_include(self):
367 result = self.coverage_usepkgs(include=["*/p1*"], omit=["*/p1a.py"])
368 self.filenames_in(result, "p1b")
369 self.filenames_not_in(result, "p1a p1c p2a p2b")
370
371
372 class SourceOmitIncludeTest(OmitIncludeTestsMixin, CoverageTest):
373 """Test using `source`, `omit` and `include` when measuring code."""
374
375 def coverage_usepkgs(self, **kwargs):
376 """Run coverage on usepkgs and return the line summary.
377
378 Arguments are passed to the `coverage.Coverage` constructor.
379
380 """
381 cov = coverage.Coverage(**kwargs)
382 cov.start()
383 import usepkgs # pragma: nested # pylint: disable=import-error,unused -variable
384 cov.stop() # pragma: nested
385 data = cov.get_data()
386 summary = data.line_counts()
387 for k, v in list(summary.items()):
388 assert k.endswith(".py")
389 summary[k[:-3]] = v
390 return summary
391
392 def test_source_package(self):
393 lines = self.coverage_usepkgs(source=["pkg1"])
394 self.filenames_in(lines, "p1a p1b")
395 self.filenames_not_in(lines, "p2a p2b othera otherb osa osb")
396 # Because source= was specified, we do search for unexecuted files.
397 self.assertEqual(lines['p1c'], 0)
398
399 def test_source_package_dotted(self):
400 lines = self.coverage_usepkgs(source=["pkg1.p1b"])
401 self.filenames_in(lines, "p1b")
402 self.filenames_not_in(lines, "p1a p1c p2a p2b othera otherb osa osb")
403
404 def test_source_package_part_omitted(self):
405 # https://bitbucket.org/ned/coveragepy/issue/218
406 # Used to be if you omitted something executed and inside the source,
407 # then after it was executed but not recorded, it would be found in
408 # the search for unexecuted files, and given a score of 0%.
409 lines = self.coverage_usepkgs(source=["pkg1"], omit=["pkg1/p1b.py"])
410 self.filenames_in(lines, "p1a")
411 self.filenames_not_in(lines, "p1b")
412 self.assertEqual(lines['p1c'], 0)
413
414
415 class ReportIncludeOmitTest(OmitIncludeTestsMixin, CoverageTest):
416 """Tests of the report include/omit functionality."""
417
418 def coverage_usepkgs(self, **kwargs):
419 """Try coverage.report()."""
420 cov = coverage.Coverage()
421 cov.start()
422 import usepkgs # pragma: nested # pylint: disable=import-error,unused -variable
423 cov.stop() # pragma: nested
424 report = StringIO()
425 cov.report(file=report, **kwargs)
426 return report.getvalue()
427
428
429 class XmlIncludeOmitTest(OmitIncludeTestsMixin, CoverageTest):
430 """Tests of the XML include/omit functionality.
431
432 This also takes care of the HTML and annotate include/omit, by virtue
433 of the structure of the code.
434
435 """
436
437 def coverage_usepkgs(self, **kwargs):
438 """Try coverage.xml_report()."""
439 cov = coverage.Coverage()
440 cov.start()
441 import usepkgs # pragma: nested # pylint: disable=import-error,unused -variable
442 cov.stop() # pragma: nested
443 cov.xml_report(outfile="-", **kwargs)
444 return self.stdout()
445
446
447 class AnalysisTest(CoverageTest):
448 """Test the numerical analysis of results."""
449 def test_many_missing_branches(self):
450 cov = coverage.Coverage(branch=True)
451
452 self.make_file("missing.py", """\
453 def fun1(x):
454 if x == 1:
455 print("one")
456 else:
457 print("not one")
458 print("done") # pragma: nocover
459
460 def fun2(x):
461 print("x")
462
463 fun2(3)
464 """)
465
466 # Import the Python file, executing it.
467 self.start_import_stop(cov, "missing")
468
469 nums = cov._analyze("missing.py").numbers
470 self.assertEqual(nums.n_files, 1)
471 self.assertEqual(nums.n_statements, 7)
472 self.assertEqual(nums.n_excluded, 1)
473 self.assertEqual(nums.n_missing, 3)
474 self.assertEqual(nums.n_branches, 2)
475 self.assertEqual(nums.n_partial_branches, 0)
476 self.assertEqual(nums.n_missing_branches, 2)
477
478
479 class PluginTest(CoverageTest):
480 """Test that the API works properly the way the plugins call it.
481
482 We don't actually use the plugins, but these tests call the API the same
483 way they do.
484
485 """
486 def pretend_to_be_nose_with_cover(self, erase):
487 """This is what the nose --with-cover plugin does."""
488 cov = coverage.Coverage()
489
490 self.make_file("no_biggie.py", """\
491 a = 1
492 b = 2
493 if b == 1:
494 c = 4
495 """)
496
497 if erase:
498 cov.combine()
499 cov.erase()
500 cov.load()
501 self.start_import_stop(cov, "no_biggie")
502 cov.combine()
503 cov.save()
504 cov.report(["no_biggie.py"])
505 self.assertEqual(self.stdout(), textwrap.dedent("""\
506 Name Stmts Miss Cover Missing
507 --------------------------------------------
508 no_biggie.py 4 1 75% 4
509 """))
510
511 def test_nose_plugin(self):
512 self.pretend_to_be_nose_with_cover(erase=False)
513
514 def test_nose_plugin_with_erase(self):
515 self.pretend_to_be_nose_with_cover(erase=True)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698