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

Side by Side Diff: tools/telemetry/third_party/coverage/tests/test_process.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 # coding: utf8
2 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
3 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
4
5 """Tests for process behavior of coverage.py."""
6
7 import glob
8 import os
9 import os.path
10 import re
11 import sys
12 import textwrap
13
14 import coverage
15 from coverage import env, CoverageData
16
17 from tests.coveragetest import CoverageTest
18
19 HERE = os.path.dirname(__file__)
20
21
22 class ProcessTest(CoverageTest):
23 """Tests of the per-process behavior of coverage.py."""
24
25 def number_of_data_files(self):
26 """Return the number of coverage data files in this directory."""
27 num = 0
28 for f in os.listdir('.'):
29 if f.startswith('.coverage.') or f == '.coverage':
30 num += 1
31 return num
32
33 def test_save_on_exit(self):
34 self.make_file("mycode.py", """\
35 h = "Hello"
36 w = "world"
37 """)
38
39 self.assert_doesnt_exist(".coverage")
40 self.run_command("coverage run mycode.py")
41 self.assert_exists(".coverage")
42
43 def test_environment(self):
44 # Checks that we can import modules from the test directory at all!
45 self.make_file("mycode.py", """\
46 import covmod1
47 import covmodzip1
48 a = 1
49 print('done')
50 """)
51
52 self.assert_doesnt_exist(".coverage")
53 out = self.run_command("coverage run mycode.py")
54 self.assert_exists(".coverage")
55 self.assertEqual(out, 'done\n')
56
57 def make_b_or_c_py(self):
58 """Create b_or_c.py, used in a few of these tests."""
59 self.make_file("b_or_c.py", """\
60 import sys
61 a = 1
62 if sys.argv[1] == 'b':
63 b = 1
64 else:
65 c = 1
66 d = 1
67 print('done')
68 """)
69
70 def test_combine_parallel_data(self):
71 self.make_b_or_c_py()
72 out = self.run_command("coverage run -p b_or_c.py b")
73 self.assertEqual(out, 'done\n')
74 self.assert_doesnt_exist(".coverage")
75 self.assertEqual(self.number_of_data_files(), 1)
76
77 out = self.run_command("coverage run -p b_or_c.py c")
78 self.assertEqual(out, 'done\n')
79 self.assert_doesnt_exist(".coverage")
80
81 # After two -p runs, there should be two .coverage.machine.123 files.
82 self.assertEqual(self.number_of_data_files(), 2)
83
84 # Combine the parallel coverage data files into .coverage .
85 self.run_command("coverage combine")
86 self.assert_exists(".coverage")
87
88 # After combining, there should be only the .coverage file.
89 self.assertEqual(self.number_of_data_files(), 1)
90
91 # Read the coverage file and see that b_or_c.py has all 7 lines
92 # executed.
93 data = coverage.CoverageData()
94 data.read_file(".coverage")
95 self.assertEqual(data.line_counts()['b_or_c.py'], 7)
96
97 def test_combine_parallel_data_in_two_steps(self):
98 self.make_b_or_c_py()
99
100 out = self.run_command("coverage run -p b_or_c.py b")
101 self.assertEqual(out, 'done\n')
102 self.assert_doesnt_exist(".coverage")
103 self.assertEqual(self.number_of_data_files(), 1)
104
105 # Combine the (one) parallel coverage data file into .coverage .
106 self.run_command("coverage combine")
107 self.assert_exists(".coverage")
108 self.assertEqual(self.number_of_data_files(), 1)
109
110 out = self.run_command("coverage run -p b_or_c.py c")
111 self.assertEqual(out, 'done\n')
112 self.assert_exists(".coverage")
113 self.assertEqual(self.number_of_data_files(), 2)
114
115 # Combine the parallel coverage data files into .coverage .
116 self.run_command("coverage combine")
117 self.assert_exists(".coverage")
118
119 # After combining, there should be only the .coverage file.
120 self.assertEqual(self.number_of_data_files(), 1)
121
122 # Read the coverage file and see that b_or_c.py has all 7 lines
123 # executed.
124 data = coverage.CoverageData()
125 data.read_file(".coverage")
126 self.assertEqual(data.line_counts()['b_or_c.py'], 7)
127
128 def test_append_data(self):
129 self.make_b_or_c_py()
130
131 out = self.run_command("coverage run b_or_c.py b")
132 self.assertEqual(out, 'done\n')
133 self.assert_exists(".coverage")
134 self.assertEqual(self.number_of_data_files(), 1)
135
136 out = self.run_command("coverage run --append b_or_c.py c")
137 self.assertEqual(out, 'done\n')
138 self.assert_exists(".coverage")
139 self.assertEqual(self.number_of_data_files(), 1)
140
141 # Read the coverage file and see that b_or_c.py has all 7 lines
142 # executed.
143 data = coverage.CoverageData()
144 data.read_file(".coverage")
145 self.assertEqual(data.line_counts()['b_or_c.py'], 7)
146
147 def test_append_data_with_different_file(self):
148 self.make_b_or_c_py()
149
150 self.make_file(".coveragerc", """\
151 [run]
152 data_file = .mycovdata
153 """)
154
155 out = self.run_command("coverage run b_or_c.py b")
156 self.assertEqual(out, 'done\n')
157 self.assert_doesnt_exist(".coverage")
158 self.assert_exists(".mycovdata")
159
160 out = self.run_command("coverage run --append b_or_c.py c")
161 self.assertEqual(out, 'done\n')
162 self.assert_doesnt_exist(".coverage")
163 self.assert_exists(".mycovdata")
164
165 # Read the coverage file and see that b_or_c.py has all 7 lines
166 # executed.
167 data = coverage.CoverageData()
168 data.read_file(".mycovdata")
169 self.assertEqual(data.line_counts()['b_or_c.py'], 7)
170
171 def test_append_can_create_a_data_file(self):
172 self.make_b_or_c_py()
173
174 out = self.run_command("coverage run --append b_or_c.py b")
175 self.assertEqual(out, 'done\n')
176 self.assert_exists(".coverage")
177 self.assertEqual(self.number_of_data_files(), 1)
178
179 # Read the coverage file and see that b_or_c.py has only 6 lines
180 # executed.
181 data = coverage.CoverageData()
182 data.read_file(".coverage")
183 self.assertEqual(data.line_counts()['b_or_c.py'], 6)
184
185 def test_combine_with_rc(self):
186 self.make_b_or_c_py()
187
188 self.make_file(".coveragerc", """\
189 [run]
190 parallel = true
191 """)
192
193 out = self.run_command("coverage run b_or_c.py b")
194 self.assertEqual(out, 'done\n')
195 self.assert_doesnt_exist(".coverage")
196
197 out = self.run_command("coverage run b_or_c.py c")
198 self.assertEqual(out, 'done\n')
199 self.assert_doesnt_exist(".coverage")
200
201 # After two runs, there should be two .coverage.machine.123 files.
202 self.assertEqual(self.number_of_data_files(), 2)
203
204 # Combine the parallel coverage data files into .coverage .
205 self.run_command("coverage combine")
206 self.assert_exists(".coverage")
207 self.assert_exists(".coveragerc")
208
209 # After combining, there should be only the .coverage file.
210 self.assertEqual(self.number_of_data_files(), 1)
211
212 # Read the coverage file and see that b_or_c.py has all 7 lines
213 # executed.
214 data = coverage.CoverageData()
215 data.read_file(".coverage")
216 self.assertEqual(data.line_counts()['b_or_c.py'], 7)
217
218 # Reporting should still work even with the .rc file
219 out = self.run_command("coverage report")
220 self.assertMultiLineEqual(out, textwrap.dedent("""\
221 Name Stmts Miss Cover
222 -------------------------------
223 b_or_c.py 7 0 100%
224 """))
225
226 def test_combine_with_aliases(self):
227 self.make_file("d1/x.py", """\
228 a = 1
229 b = 2
230 print("%s %s" % (a, b))
231 """)
232
233 self.make_file("d2/x.py", """\
234 # 1
235 # 2
236 # 3
237 c = 4
238 d = 5
239 print("%s %s" % (c, d))
240 """)
241
242 self.make_file(".coveragerc", """\
243 [run]
244 parallel = True
245
246 [paths]
247 source =
248 src
249 */d1
250 */d2
251 """)
252
253 out = self.run_command("coverage run " + os.path.normpath("d1/x.py"))
254 self.assertEqual(out, '1 2\n')
255 out = self.run_command("coverage run " + os.path.normpath("d2/x.py"))
256 self.assertEqual(out, '4 5\n')
257
258 self.assertEqual(self.number_of_data_files(), 2)
259
260 self.run_command("coverage combine")
261 self.assert_exists(".coverage")
262
263 # After combining, there should be only the .coverage file.
264 self.assertEqual(self.number_of_data_files(), 1)
265
266 # Read the coverage data file and see that the two different x.py
267 # files have been combined together.
268 data = coverage.CoverageData()
269 data.read_file(".coverage")
270 summary = data.line_counts(fullpath=True)
271 self.assertEqual(len(summary), 1)
272 actual = os.path.normcase(os.path.abspath(list(summary.keys())[0]))
273 expected = os.path.normcase(os.path.abspath('src/x.py'))
274 self.assertEqual(actual, expected)
275 self.assertEqual(list(summary.values())[0], 6)
276
277 def test_erase_parallel(self):
278 self.make_file(".coveragerc", """\
279 [run]
280 data_file = data.dat
281 parallel = True
282 """)
283 self.make_file("data.dat")
284 self.make_file("data.dat.fooey")
285 self.make_file("data.dat.gooey")
286 self.make_file(".coverage")
287
288 self.run_command("coverage erase")
289 self.assert_doesnt_exist("data.dat")
290 self.assert_doesnt_exist("data.dat.fooey")
291 self.assert_doesnt_exist("data.dat.gooey")
292 self.assert_exists(".coverage")
293
294 def test_missing_source_file(self):
295 # Check what happens if the source is missing when reporting happens.
296 self.make_file("fleeting.py", """\
297 s = 'goodbye, cruel world!'
298 """)
299
300 self.run_command("coverage run fleeting.py")
301 os.remove("fleeting.py")
302 out = self.run_command("coverage html -d htmlcov")
303 self.assertRegex(out, "No source for code: '.*fleeting.py'")
304 self.assertNotIn("Traceback", out)
305
306 # It happens that the code paths are different for *.py and other
307 # files, so try again with no extension.
308 self.make_file("fleeting", """\
309 s = 'goodbye, cruel world!'
310 """)
311
312 self.run_command("coverage run fleeting")
313 os.remove("fleeting")
314 status, out = self.run_command_status("coverage html -d htmlcov")
315 self.assertRegex(out, "No source for code: '.*fleeting'")
316 self.assertNotIn("Traceback", out)
317 self.assertEqual(status, 1)
318
319 def test_running_missing_file(self):
320 status, out = self.run_command_status("coverage run xyzzy.py")
321 self.assertRegex(out, "No file to run: .*xyzzy.py")
322 self.assertNotIn("raceback", out)
323 self.assertNotIn("rror", out)
324 self.assertEqual(status, 1)
325
326 def test_code_throws(self):
327 self.make_file("throw.py", """\
328 def f1():
329 raise Exception("hey!")
330
331 def f2():
332 f1()
333
334 f2()
335 """)
336
337 # The important thing is for "coverage run" and "python" to report the
338 # same traceback.
339 status, out = self.run_command_status("coverage run throw.py")
340 out2 = self.run_command("python throw.py")
341 if env.PYPY:
342 # Pypy has an extra frame in the traceback for some reason
343 lines2 = out2.splitlines()
344 out2 = "".join(l+"\n" for l in lines2 if "toplevel" not in l)
345 self.assertMultiLineEqual(out, out2)
346
347 # But also make sure that the output is what we expect.
348 self.assertIn('File "throw.py", line 5, in f2', out)
349 self.assertIn('raise Exception("hey!")', out)
350 self.assertNotIn('coverage', out)
351 self.assertEqual(status, 1)
352
353 def test_code_exits(self):
354 self.make_file("exit.py", """\
355 import sys
356 def f1():
357 print("about to exit..")
358 sys.exit(17)
359
360 def f2():
361 f1()
362
363 f2()
364 """)
365
366 # The important thing is for "coverage run" and "python" to have the
367 # same output. No traceback.
368 status, out = self.run_command_status("coverage run exit.py")
369 status2, out2 = self.run_command_status("python exit.py")
370 self.assertMultiLineEqual(out, out2)
371 self.assertMultiLineEqual(out, "about to exit..\n")
372 self.assertEqual(status, status2)
373 self.assertEqual(status, 17)
374
375 def test_code_exits_no_arg(self):
376 self.make_file("exit_none.py", """\
377 import sys
378 def f1():
379 print("about to exit quietly..")
380 sys.exit()
381
382 f1()
383 """)
384 status, out = self.run_command_status("coverage run exit_none.py")
385 status2, out2 = self.run_command_status("python exit_none.py")
386 self.assertMultiLineEqual(out, out2)
387 self.assertMultiLineEqual(out, "about to exit quietly..\n")
388 self.assertEqual(status, status2)
389 self.assertEqual(status, 0)
390
391 def test_coverage_run_is_like_python(self):
392 tryfile = os.path.join(HERE, "try_execfile.py")
393 with open(tryfile) as f:
394 self.make_file("run_me.py", f.read())
395 out_cov = self.run_command("coverage run run_me.py")
396 out_py = self.run_command("python run_me.py")
397 self.assertMultiLineEqual(out_cov, out_py)
398
399 def test_coverage_run_dashm_is_like_python_dashm(self):
400 # These -m commands assume the coverage tree is on the path.
401 out_cov = self.run_command("coverage run -m tests.try_execfile")
402 out_py = self.run_command("python -m tests.try_execfile")
403 self.assertMultiLineEqual(out_cov, out_py)
404
405 def test_coverage_run_dir_is_like_python_dir(self):
406 tryfile = os.path.join(HERE, "try_execfile.py")
407 with open(tryfile) as f:
408 self.make_file("with_main/__main__.py", f.read())
409 out_cov = self.run_command("coverage run with_main")
410 out_py = self.run_command("python with_main")
411
412 # The coverage.py results are not identical to the Python results, and
413 # I don't know why. For now, ignore those failures. If someone finds
414 # a real problem with the discrepancies, we can work on it some more.
415 ignored = r"__file__|__loader__|__package__"
416 # PyPy includes the current directory in the path when running a
417 # directory, while CPython and coverage.py do not. Exclude that from
418 # the comparison also...
419 if env.PYPY:
420 ignored += "|"+re.escape(os.getcwd())
421 out_cov = remove_matching_lines(out_cov, ignored)
422 out_py = remove_matching_lines(out_py, ignored)
423 self.assertMultiLineEqual(out_cov, out_py)
424
425 def test_coverage_run_dashm_equal_to_doubledashsource(self):
426 """regression test for #328
427
428 When imported by -m, a module's __name__ is __main__, but we need the
429 --source machinery to know and respect the original name.
430 """
431 # These -m commands assume the coverage tree is on the path.
432 out_cov = self.run_command(
433 "coverage run --source tests.try_execfile -m tests.try_execfile"
434 )
435 out_py = self.run_command("python -m tests.try_execfile")
436 self.assertMultiLineEqual(out_cov, out_py)
437
438 def test_coverage_run_dashm_superset_of_doubledashsource(self):
439 """Edge case: --source foo -m foo.bar"""
440 # These -m commands assume the coverage tree is on the path.
441 out_cov = self.run_command(
442 "coverage run --source tests -m tests.try_execfile"
443 )
444 out_py = self.run_command("python -m tests.try_execfile")
445 self.assertMultiLineEqual(out_cov, out_py)
446
447 st, out = self.run_command_status("coverage report")
448 self.assertEqual(st, 0)
449 self.assertEqual(self.line_count(out), 6, out)
450
451 def test_coverage_run_script_imports_doubledashsource(self):
452 # This file imports try_execfile, which compiles it to .pyc, so the
453 # first run will have __file__ == "try_execfile.py" and the second will
454 # have __file__ == "try_execfile.pyc", which throws off the comparison.
455 # Setting dont_write_bytecode True stops the compilation to .pyc and
456 # keeps the test working.
457 self.make_file("myscript", """\
458 import sys; sys.dont_write_bytecode = True
459 import tests.try_execfile
460 """)
461
462 # These -m commands assume the coverage tree is on the path.
463 out_cov = self.run_command(
464 "coverage run --source tests myscript"
465 )
466 out_py = self.run_command("python myscript")
467 self.assertMultiLineEqual(out_cov, out_py)
468
469 st, out = self.run_command_status("coverage report")
470 self.assertEqual(st, 0)
471 self.assertEqual(self.line_count(out), 6, out)
472
473 def test_coverage_run_dashm_is_like_python_dashm_off_path(self):
474 # https://bitbucket.org/ned/coveragepy/issue/242
475 tryfile = os.path.join(HERE, "try_execfile.py")
476 self.make_file("sub/__init__.py", "")
477 with open(tryfile) as f:
478 self.make_file("sub/run_me.py", f.read())
479 out_cov = self.run_command("coverage run -m sub.run_me")
480 out_py = self.run_command("python -m sub.run_me")
481 self.assertMultiLineEqual(out_cov, out_py)
482
483 def test_coverage_run_dashm_is_like_python_dashm_with__main__207(self):
484 if sys.version_info < (2, 7):
485 # Coverage.py isn't bug-for-bug compatible in the behavior of -m for
486 # Pythons < 2.7
487 self.skip("-m doesn't work the same < Python 2.7")
488 # https://bitbucket.org/ned/coveragepy/issue/207
489 self.make_file("package/__init__.py", "print('init')")
490 self.make_file("package/__main__.py", "print('main')")
491 out_cov = self.run_command("coverage run -m package")
492 out_py = self.run_command("python -m package")
493 self.assertMultiLineEqual(out_cov, out_py)
494
495 def test_fork(self):
496 if not hasattr(os, 'fork'):
497 self.skip("Can't test os.fork since it doesn't exist.")
498
499 self.make_file("fork.py", """\
500 import os
501
502 def child():
503 print('Child!')
504
505 def main():
506 ret = os.fork()
507
508 if ret == 0:
509 child()
510 else:
511 os.waitpid(ret, 0)
512
513 main()
514 """)
515
516 out = self.run_command("coverage run -p fork.py")
517 self.assertEqual(out, 'Child!\n')
518 self.assert_doesnt_exist(".coverage")
519
520 # After running the forking program, there should be two
521 # .coverage.machine.123 files.
522 self.assertEqual(self.number_of_data_files(), 2)
523
524 # Combine the parallel coverage data files into .coverage .
525 self.run_command("coverage combine")
526 self.assert_exists(".coverage")
527
528 # After combining, there should be only the .coverage file.
529 self.assertEqual(self.number_of_data_files(), 1)
530
531 # Read the coverage file and see that b_or_c.py has all 7 lines
532 # executed.
533 data = coverage.CoverageData()
534 data.read_file(".coverage")
535 self.assertEqual(data.line_counts()['fork.py'], 9)
536
537 def test_warnings(self):
538 self.make_file("hello.py", """\
539 import sys, os
540 print("Hello")
541 """)
542 out = self.run_command("coverage run --source=sys,xyzzy,quux hello.py")
543
544 self.assertIn("Hello\n", out)
545 self.assertIn(textwrap.dedent("""\
546 Coverage.py warning: Module sys has no Python source.
547 Coverage.py warning: Module xyzzy was never imported.
548 Coverage.py warning: Module quux was never imported.
549 Coverage.py warning: No data was collected.
550 """), out)
551
552 def test_warnings_during_reporting(self):
553 # While fixing issue #224, the warnings were being printed far too
554 # often. Make sure they're not any more.
555 self.make_file("hello.py", """\
556 import sys, os, the_other
557 print("Hello")
558 """)
559 self.make_file("the_other.py", """\
560 print("What?")
561 """)
562 self.make_file(".coveragerc", """\
563 [run]
564 source =
565 .
566 xyzzy
567 """)
568
569 self.run_command("coverage run hello.py")
570 out = self.run_command("coverage html")
571 self.assertEqual(out.count("Module xyzzy was never imported."), 0)
572
573 def test_warnings_if_never_run(self):
574 out = self.run_command("coverage run i_dont_exist.py")
575 self.assertIn("No file to run: 'i_dont_exist.py'", out)
576 self.assertNotIn("warning", out)
577 self.assertNotIn("Exception", out)
578
579 out = self.run_command("coverage run -m no_such_module")
580 self.assertTrue(
581 ("No module named no_such_module" in out) or
582 ("No module named 'no_such_module'" in out)
583 )
584 self.assertNotIn("warning", out)
585 self.assertNotIn("Exception", out)
586
587 def test_warnings_trace_function_changed_with_threads(self):
588 # https://bitbucket.org/ned/coveragepy/issue/164
589 self.make_file("bug164.py", """\
590 import threading
591 import time
592
593 class MyThread (threading.Thread):
594 def run(self):
595 print("Hello")
596
597 thr = MyThread()
598 thr.start()
599 thr.join()
600 """)
601 out = self.run_command("coverage run --timid bug164.py")
602
603 self.assertIn("Hello\n", out)
604 self.assertNotIn("warning", out)
605
606 def test_warning_trace_function_changed(self):
607 self.make_file("settrace.py", """\
608 import sys
609 print("Hello")
610 sys.settrace(None)
611 print("Goodbye")
612 """)
613 out = self.run_command("coverage run --timid settrace.py")
614 self.assertIn("Hello\n", out)
615 self.assertIn("Goodbye\n", out)
616
617 self.assertIn("Trace function changed", out)
618
619 def test_note(self):
620 self.make_file(".coveragerc", """\
621 [run]
622 data_file = mydata.dat
623 note = These are musical notes: ♫𝅗𝅥♩
624 """)
625 self.make_file("simple.py", """print('hello')""")
626 self.run_command("coverage run simple.py")
627
628 data = CoverageData()
629 data.read_file("mydata.dat")
630 infos = data.run_infos()
631 self.assertEqual(len(infos), 1)
632 self.assertEqual(infos[0]['note'], u"These are musical notes: ♫𝅗𝅥♩")
633
634 def test_fullcoverage(self): # pragma: not covered
635 if env.PY2: # This doesn't work on Python 2.
636 self.skip("fullcoverage doesn't work on Python 2.")
637 # It only works with the C tracer, and if we aren't measuring ourselves.
638 if not env.C_TRACER or env.METACOV:
639 self.skip("fullcoverage only works with the C tracer.")
640
641 # fullcoverage is a trick to get stdlib modules measured from
642 # the very beginning of the process. Here we import os and
643 # then check how many lines are measured.
644 self.make_file("getenv.py", """\
645 import os
646 print("FOOEY == %s" % os.getenv("FOOEY"))
647 """)
648
649 fullcov = os.path.join(
650 os.path.dirname(coverage.__file__), "fullcoverage"
651 )
652 self.set_environ("FOOEY", "BOO")
653 self.set_environ("PYTHONPATH", fullcov)
654 out = self.run_command("python -m coverage run -L getenv.py")
655 self.assertEqual(out, "FOOEY == BOO\n")
656 data = coverage.CoverageData()
657 data.read_file(".coverage")
658 # The actual number of executed lines in os.py when it's
659 # imported is 120 or so. Just running os.getenv executes
660 # about 5.
661 self.assertGreater(data.line_counts()['os.py'], 50)
662
663 def test_deprecation_warnings(self):
664 # Test that coverage doesn't trigger deprecation warnings.
665 # https://bitbucket.org/ned/coveragepy/issue/305/pendingdeprecationwarni ng-the-imp-module
666 self.make_file("allok.py", """\
667 import warnings
668 warnings.simplefilter('default')
669 import coverage
670 print("No warnings!")
671 """)
672 out = self.run_command("python allok.py")
673 self.assertEqual(out, "No warnings!\n")
674
675 def test_run_twice(self):
676 # https://bitbucket.org/ned/coveragepy/issue/353/40a3-introduces-an-unex pected-third-case
677 self.make_file("foo.py", """\
678 def foo():
679 pass
680 """)
681 self.make_file("run_twice.py", """\
682 import coverage
683
684 for _ in [1, 2]:
685 inst = coverage.Coverage(source=['foo'])
686 inst.load()
687 inst.start()
688 import foo
689 inst.stop()
690 inst.combine()
691 inst.save()
692 """)
693 out = self.run_command("python run_twice.py")
694 self.assertEqual(
695 out,
696 "Coverage.py warning: Module foo was previously imported, but not me asured.\n"
697 )
698
699
700 class AliasedCommandTest(CoverageTest):
701 """Tests of the version-specific command aliases."""
702
703 run_in_temp_dir = False
704
705 def test_major_version_works(self):
706 # "coverage2" works on py2
707 cmd = "coverage%d" % sys.version_info[0]
708 out = self.run_command(cmd)
709 self.assertIn("Code coverage for Python", out)
710
711 def test_wrong_alias_doesnt_work(self):
712 # "coverage3" doesn't work on py2
713 badcmd = "coverage%d" % (5 - sys.version_info[0])
714 out = self.run_command(badcmd)
715 self.assertNotIn("Code coverage for Python", out)
716
717 def test_specific_alias_works(self):
718 # "coverage-2.7" works on py2.7
719 cmd = "coverage-%d.%d" % sys.version_info[:2]
720 out = self.run_command(cmd)
721 self.assertIn("Code coverage for Python", out)
722
723
724 class PydocTest(CoverageTest):
725 """Test that pydoc can get our information."""
726
727 run_in_temp_dir = False
728
729 def assert_pydoc_ok(self, name, thing):
730 """Check that pydoc of `name` finds the docstring from `thing`."""
731 # Run pydoc.
732 out = self.run_command("python -m pydoc " + name)
733 # It should say "Help on..", and not have a traceback
734 self.assert_starts_with(out, "Help on ")
735 self.assertNotIn("Traceback", out)
736
737 # All of the lines in the docstring should be there somewhere.
738 for line in thing.__doc__.splitlines():
739 self.assertIn(line.strip(), out)
740
741 def test_pydoc_coverage(self):
742 self.assert_pydoc_ok("coverage", coverage)
743
744 def test_pydoc_coverage_coverage(self):
745 self.assert_pydoc_ok("coverage.Coverage", coverage.Coverage)
746
747
748 class FailUnderTest(CoverageTest):
749 """Tests of the --fail-under switch."""
750
751 def setUp(self):
752 super(FailUnderTest, self).setUp()
753 self.make_file("forty_two_plus.py", """\
754 # I have 42.857% (3/7) coverage!
755 a = 1
756 b = 2
757 if a > 3:
758 b = 4
759 c = 5
760 d = 6
761 e = 7
762 """)
763 st, _ = self.run_command_status("coverage run forty_two_plus.py")
764 self.assertEqual(st, 0)
765 st, out = self.run_command_status("coverage report")
766 self.assertEqual(st, 0)
767 self.assertEqual(
768 self.last_line_squeezed(out),
769 "forty_two_plus.py 7 4 43%"
770 )
771
772 def test_report(self):
773 st, _ = self.run_command_status("coverage report --fail-under=42")
774 self.assertEqual(st, 0)
775 st, _ = self.run_command_status("coverage report --fail-under=43")
776 self.assertEqual(st, 0)
777 st, _ = self.run_command_status("coverage report --fail-under=44")
778 self.assertEqual(st, 2)
779
780 def test_html_report(self):
781 st, _ = self.run_command_status("coverage html --fail-under=42")
782 self.assertEqual(st, 0)
783 st, _ = self.run_command_status("coverage html --fail-under=43")
784 self.assertEqual(st, 0)
785 st, _ = self.run_command_status("coverage html --fail-under=44")
786 self.assertEqual(st, 2)
787
788 def test_xml_report(self):
789 st, _ = self.run_command_status("coverage xml --fail-under=42")
790 self.assertEqual(st, 0)
791 st, _ = self.run_command_status("coverage xml --fail-under=43")
792 self.assertEqual(st, 0)
793 st, _ = self.run_command_status("coverage xml --fail-under=44")
794 self.assertEqual(st, 2)
795
796 def test_fail_under_in_config(self):
797 self.make_file(".coveragerc", "[report]\nfail_under = 43\n")
798 st, _ = self.run_command_status("coverage report")
799 self.assertEqual(st, 0)
800
801 self.make_file(".coveragerc", "[report]\nfail_under = 44\n")
802 st, _ = self.run_command_status("coverage report")
803 self.assertEqual(st, 2)
804
805
806 class FailUnderNoFilesTest(CoverageTest):
807 """Test that nothing to report results in an error exit status."""
808 def setUp(self):
809 super(FailUnderNoFilesTest, self).setUp()
810 self.make_file(".coveragerc", "[report]\nfail_under = 99\n")
811
812 def test_report(self):
813 st, out = self.run_command_status("coverage report")
814 self.assertIn('No data to report.', out)
815 self.assertEqual(st, 1)
816
817 def test_xml(self):
818 st, out = self.run_command_status("coverage xml")
819 self.assertIn('No data to report.', out)
820 self.assertEqual(st, 1)
821
822 def test_html(self):
823 st, out = self.run_command_status("coverage html")
824 self.assertIn('No data to report.', out)
825 self.assertEqual(st, 1)
826
827
828 class FailUnderEmptyFilesTest(CoverageTest):
829 """Test that empty files produce the proper fail_under exit status."""
830 def setUp(self):
831 super(FailUnderEmptyFilesTest, self).setUp()
832
833 self.make_file(".coveragerc", "[report]\nfail_under = 99\n")
834 self.make_file("empty.py", "")
835 st, _ = self.run_command_status("coverage run empty.py")
836 self.assertEqual(st, 0)
837
838 def test_report(self):
839 st, _ = self.run_command_status("coverage report")
840 self.assertEqual(st, 2)
841
842 def test_xml(self):
843 st, _ = self.run_command_status("coverage xml")
844 self.assertEqual(st, 2)
845
846 def test_html(self):
847 st, _ = self.run_command_status("coverage html")
848 self.assertEqual(st, 2)
849
850
851 def possible_pth_dirs():
852 """Produce a sequence of directories for trying to write .pth files."""
853 # First look through sys.path, and we find a .pth file, then it's a good
854 # place to put ours.
855 for d in sys.path:
856 g = glob.glob(os.path.join(d, "*.pth"))
857 if g:
858 yield d
859
860 # If we're still looking, then try the Python library directory.
861 # https://bitbucket.org/ned/coveragepy/issue/339/pth-test-malfunctions
862 import distutils.sysconfig # pylint: disable=import-error
863 yield distutils.sysconfig.get_python_lib()
864
865
866 class ProcessCoverageMixin(object):
867 """Set up a .pth file to coverage-measure all sub-processes."""
868
869 def setUp(self):
870 super(ProcessCoverageMixin, self).setUp()
871 # Find a place to put a .pth file.
872 pth_contents = "import coverage; coverage.process_startup()\n"
873 for pth_dir in possible_pth_dirs(): # pragma: part covered
874 pth_path = os.path.join(pth_dir, "subcover.pth")
875 with open(pth_path, "w") as pth:
876 try:
877 pth.write(pth_contents)
878 self.pth_path = pth_path
879 break
880 except (IOError, OSError): # pragma: not covered
881 pass
882 else: # pragma: not covered
883 raise Exception("Couldn't find a place for the .pth file")
884
885 self.addCleanup(os.remove, self.pth_path)
886
887
888 class ProcessStartupTest(ProcessCoverageMixin, CoverageTest):
889 """Test that we can measure coverage in sub-processes."""
890
891 def test_subprocess_with_pth_files(self): # pragma: not covered
892 if env.METACOV:
893 self.skip("Can't test sub-process pth file suppport during metacover age")
894
895 # Main will run sub.py
896 self.make_file("main.py", """\
897 import os, os.path, sys
898 ex = os.path.basename(sys.executable)
899 os.system(ex + " sub.py")
900 """)
901 # sub.py will write a few lines.
902 self.make_file("sub.py", """\
903 with open("out.txt", "w") as f:
904 f.write("Hello, world!\\n")
905 """)
906 self.make_file("coverage.ini", """\
907 [run]
908 data_file = .mycovdata
909 """)
910 self.set_environ("COVERAGE_PROCESS_START", "coverage.ini")
911 import main # pylint: disable=import-error,unused-variable
912
913 with open("out.txt") as f:
914 self.assertEqual(f.read(), "Hello, world!\n")
915
916 # Read the data from .coverage
917 self.assert_exists(".mycovdata")
918 data = coverage.CoverageData()
919 data.read_file(".mycovdata")
920 self.assertEqual(data.line_counts()['sub.py'], 2)
921
922
923 class ProcessStartupWithSourceTest(ProcessCoverageMixin, CoverageTest):
924 """Show that we can configure {[run]source} during process-level coverage.
925
926 There are three interesting variables, for a total of eight tests:
927
928 1. -m versus a simple script argument (for example, `python myscript`),
929
930 2. filtering for the top-level (main.py) or second-level (sub.py)
931 module, and
932
933 3. whether the files are in a package or not.
934
935 """
936
937 def assert_pth_and_source_work_together(
938 self, dashm, package, source
939 ): # pragma: not covered
940 """Run the test for a particular combination of factors.
941
942 The arguments are all strings:
943
944 * `dashm`: Either "" (run the program as a file) or "-m" (run the
945 program as a module).
946
947 * `package`: Either "" (put the source at the top level) or a
948 package name to use to hold the source.
949
950 * `source`: Either "main" or "sub", which file to use as the
951 ``--source`` argument.
952
953 """
954 if env.METACOV:
955 self.skip("Can't test sub-process pth file suppport during metacover age")
956
957 def fullname(modname):
958 """What is the full module name for `modname` for this test?"""
959 if package and dashm:
960 return '.'.join((package, modname))
961 else:
962 return modname
963
964 def path(basename):
965 """Where should `basename` be created for this test?"""
966 return os.path.join(package, basename)
967
968 # Main will run sub.py.
969 self.make_file(path("main.py"), """\
970 import %s
971 if True: pass
972 """ % fullname('sub'))
973 if package:
974 self.make_file(path("__init__.py"), "")
975 # sub.py will write a few lines.
976 self.make_file(path("sub.py"), """\
977 with open("out.txt", "w") as f:
978 f.write("Hello, world!")
979 """)
980 self.make_file("coverage.ini", """\
981 [run]
982 source = %s
983 """ % fullname(source))
984
985 self.set_environ("COVERAGE_PROCESS_START", "coverage.ini")
986
987 if dashm:
988 cmd = "python -m %s" % fullname('main')
989 else:
990 cmd = "python %s" % path('main.py')
991
992 self.run_command(cmd)
993
994 with open("out.txt") as f:
995 self.assertEqual(f.read(), "Hello, world!")
996
997 # Read the data from .coverage
998 self.assert_exists(".coverage")
999 data = coverage.CoverageData()
1000 data.read_file(".coverage")
1001 summary = data.line_counts()
1002 print(summary)
1003 self.assertEqual(summary[source + '.py'], 2)
1004 self.assertEqual(len(summary), 1)
1005
1006 def test_dashm_main(self):
1007 self.assert_pth_and_source_work_together('-m', '', 'main')
1008
1009 def test_script_main(self):
1010 self.assert_pth_and_source_work_together('', '', 'main')
1011
1012 def test_dashm_sub(self):
1013 self.assert_pth_and_source_work_together('-m', '', 'sub')
1014
1015 def test_script_sub(self):
1016 self.assert_pth_and_source_work_together('', '', 'sub')
1017
1018 def test_dashm_pkg_main(self):
1019 self.assert_pth_and_source_work_together('-m', 'pkg', 'main')
1020
1021 def test_script_pkg_main(self):
1022 self.assert_pth_and_source_work_together('', 'pkg', 'main')
1023
1024 def test_dashm_pkg_sub(self):
1025 self.assert_pth_and_source_work_together('-m', 'pkg', 'sub')
1026
1027 def test_script_pkg_sub(self):
1028 self.assert_pth_and_source_work_together('', 'pkg', 'sub')
1029
1030
1031 def remove_matching_lines(text, pat):
1032 """Return `text` with all lines matching `pat` removed."""
1033 lines = [l for l in text.splitlines(True) if not re.search(pat, l)]
1034 return "".join(lines)
OLDNEW
« no previous file with comments | « tools/telemetry/third_party/coverage/tests/test_plugins.py ('k') | tools/telemetry/third_party/coverage/tests/test_python.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698