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

Side by Side Diff: tools/telemetry/third_party/coverage/tests/test_cmdline.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 """Test cmdline.py for coverage.py."""
5
6 import pprint
7 import re
8 import shlex
9 import sys
10 import textwrap
11
12 import mock
13
14 import coverage
15 import coverage.cmdline
16 from coverage.config import CoverageConfig
17 from coverage.data import CoverageData, CoverageDataFiles
18 from coverage.misc import ExceptionDuringRun
19
20 from tests.coveragetest import CoverageTest, OK, ERR
21
22
23 class BaseCmdLineTest(CoverageTest):
24 """Tests of execution paths through the command line interpreter."""
25
26 run_in_temp_dir = False
27
28 # Make a dict mapping function names to the default values that cmdline.py
29 # uses when calling the function.
30 defaults = mock.Mock()
31 defaults.coverage(
32 cover_pylib=None, data_suffix=None, timid=None, branch=None,
33 config_file=True, source=None, include=None, omit=None, debug=None,
34 concurrency=None,
35 )
36 defaults.annotate(
37 directory=None, ignore_errors=None, include=None, omit=None, morfs=[],
38 )
39 defaults.html_report(
40 directory=None, ignore_errors=None, include=None, omit=None, morfs=[],
41 title=None,
42 )
43 defaults.report(
44 ignore_errors=None, include=None, omit=None, morfs=[],
45 show_missing=None, skip_covered=None
46 )
47 defaults.xml_report(
48 ignore_errors=None, include=None, omit=None, morfs=[], outfile=None,
49 )
50
51 DEFAULT_KWARGS = dict((name, kw) for name, _, kw in defaults.mock_calls)
52
53 def model_object(self):
54 """Return a Mock suitable for use in CoverageScript."""
55 mk = mock.Mock()
56 # We'll invoke .coverage as the constructor, and then keep using the
57 # same object as the resulting coverage object.
58 mk.coverage.return_value = mk
59
60 # The mock needs to get options, but shouldn't need to set them.
61 config = CoverageConfig()
62 mk.get_option = config.get_option
63
64 return mk
65
66 def mock_command_line(self, args, path_exists=None):
67 """Run `args` through the command line, with a Mock.
68
69 Returns the Mock it used and the status code returned.
70
71 """
72 m = self.model_object()
73 m.path_exists.return_value = path_exists
74
75 ret = coverage.cmdline.CoverageScript(
76 _covpkg=m, _run_python_file=m.run_python_file,
77 _run_python_module=m.run_python_module, _help_fn=m.help_fn,
78 _path_exists=m.path_exists,
79 ).command_line(shlex.split(args))
80
81 return m, ret
82
83 def cmd_executes(self, args, code, ret=OK, path_exists=None):
84 """Assert that the `args` end up executing the sequence in `code`."""
85 m1, r1 = self.mock_command_line(args, path_exists=path_exists)
86 self.assertEqual(r1, ret, "Wrong status: got %r, wanted %r" % (r1, ret))
87
88 # Remove all indentation, and change ".foo()" to "m2.foo()".
89 code = re.sub(r"(?m)^\s+", "", code)
90 code = re.sub(r"(?m)^\.", "m2.", code)
91 m2 = self.model_object()
92 m2.path_exists.return_value = path_exists
93 code_obj = compile(code, "<code>", "exec")
94 eval(code_obj, globals(), { 'm2': m2 }) # pylint: disable=eval-used
95
96 # Many of our functions take a lot of arguments, and cmdline.py
97 # calls them with many. But most of them are just the defaults, which
98 # we don't want to have to repeat in all tests. For each call, apply
99 # the defaults. This lets the tests just mention the interesting ones.
100 for name, args, kwargs in m2.method_calls:
101 for k, v in self.DEFAULT_KWARGS.get(name, {}).items():
102 if k not in kwargs:
103 kwargs[k] = v
104 self.assert_same_method_calls(m1, m2)
105
106 def cmd_executes_same(self, args1, args2):
107 """Assert that the `args1` executes the same as `args2`."""
108 m1, r1 = self.mock_command_line(args1)
109 m2, r2 = self.mock_command_line(args2)
110 self.assertEqual(r1, r2)
111 self.assert_same_method_calls(m1, m2)
112
113 def assert_same_method_calls(self, m1, m2):
114 """Assert that `m1.method_calls` and `m2.method_calls` are the same."""
115 # Use a real equality comparison, but if it fails, use a nicer assert
116 # so we can tell what's going on. We have to use the real == first due
117 # to CmdOptionParser.__eq__
118 if m1.method_calls != m2.method_calls:
119 pp1 = pprint.pformat(m1.method_calls)
120 pp2 = pprint.pformat(m2.method_calls)
121 self.assertMultiLineEqual(pp1+'\n', pp2+'\n')
122
123 def cmd_help(self, args, help_msg=None, topic=None, ret=ERR):
124 """Run a command line, and check that it prints the right help.
125
126 Only the last function call in the mock is checked, which should be the
127 help message that we want to see.
128
129 """
130 m, r = self.mock_command_line(args)
131 self.assertEqual(r, ret,
132 "Wrong status: got %s, wanted %s" % (r, ret)
133 )
134 if help_msg:
135 self.assertEqual(m.method_calls[-1],
136 ('help_fn', (help_msg,), {})
137 )
138 else:
139 self.assertEqual(m.method_calls[-1],
140 ('help_fn', (), {'topic':topic})
141 )
142
143
144 class BaseCmdLineTestTest(BaseCmdLineTest):
145 """Tests that our BaseCmdLineTest helpers work."""
146 def test_assert_same_method_calls(self):
147 # All the other tests here use self.cmd_executes_same in successful
148 # ways, so here we just check that it fails.
149 with self.assertRaises(AssertionError):
150 self.cmd_executes_same("run", "debug")
151
152
153 class CmdLineTest(BaseCmdLineTest):
154 """Tests of the coverage.py command line."""
155
156 def test_annotate(self):
157 # coverage annotate [-d DIR] [-i] [--omit DIR,...] [FILE1 FILE2 ...]
158 self.cmd_executes("annotate", """\
159 .coverage()
160 .load()
161 .annotate()
162 """)
163 self.cmd_executes("annotate -d dir1", """\
164 .coverage()
165 .load()
166 .annotate(directory="dir1")
167 """)
168 self.cmd_executes("annotate -i", """\
169 .coverage()
170 .load()
171 .annotate(ignore_errors=True)
172 """)
173 self.cmd_executes("annotate --omit fooey", """\
174 .coverage(omit=["fooey"])
175 .load()
176 .annotate(omit=["fooey"])
177 """)
178 self.cmd_executes("annotate --omit fooey,booey", """\
179 .coverage(omit=["fooey", "booey"])
180 .load()
181 .annotate(omit=["fooey", "booey"])
182 """)
183 self.cmd_executes("annotate mod1", """\
184 .coverage()
185 .load()
186 .annotate(morfs=["mod1"])
187 """)
188 self.cmd_executes("annotate mod1 mod2 mod3", """\
189 .coverage()
190 .load()
191 .annotate(morfs=["mod1", "mod2", "mod3"])
192 """)
193
194 def test_combine(self):
195 # coverage combine with args
196 self.cmd_executes("combine datadir1", """\
197 .coverage()
198 .load()
199 .combine(["datadir1"])
200 .save()
201 """)
202 # coverage combine without args
203 self.cmd_executes("combine", """\
204 .coverage()
205 .load()
206 .combine(None)
207 .save()
208 """)
209
210 def test_combine_doesnt_confuse_options_with_args(self):
211 # https://bitbucket.org/ned/coveragepy/issues/385/coverage-combine-doesn t-work-with-rcfile
212 self.cmd_executes("combine --rcfile cov.ini", """\
213 .coverage(config_file='cov.ini')
214 .load()
215 .combine(None)
216 .save()
217 """)
218 self.cmd_executes("combine --rcfile cov.ini data1 data2/more", """\
219 .coverage(config_file='cov.ini')
220 .load()
221 .combine(["data1", "data2/more"])
222 .save()
223 """)
224
225 def test_debug(self):
226 self.cmd_help("debug", "What information would you like: data, sys?")
227 self.cmd_help("debug foo", "Don't know what you mean by 'foo'")
228
229 def test_debug_sys(self):
230 self.command_line("debug sys")
231 out = self.stdout()
232 self.assertIn("version:", out)
233 self.assertIn("data_path:", out)
234
235 def test_erase(self):
236 # coverage erase
237 self.cmd_executes("erase", """\
238 .coverage()
239 .erase()
240 """)
241
242 def test_version(self):
243 # coverage --version
244 self.cmd_help("--version", topic="version", ret=OK)
245
246 def test_help_option(self):
247 # coverage -h
248 self.cmd_help("-h", topic="help", ret=OK)
249 self.cmd_help("--help", topic="help", ret=OK)
250
251 def test_help_command(self):
252 self.cmd_executes("help", ".help_fn(topic='help')")
253
254 def test_cmd_help(self):
255 self.cmd_executes("run --help",
256 ".help_fn(parser='<CmdOptionParser:run>')")
257 self.cmd_executes_same("help run", "run --help")
258
259 def test_html(self):
260 # coverage html -d DIR [-i] [--omit DIR,...] [FILE1 FILE2 ...]
261 self.cmd_executes("html", """\
262 .coverage()
263 .load()
264 .html_report()
265 """)
266 self.cmd_executes("html -d dir1", """\
267 .coverage()
268 .load()
269 .html_report(directory="dir1")
270 """)
271 self.cmd_executes("html -i", """\
272 .coverage()
273 .load()
274 .html_report(ignore_errors=True)
275 """)
276 self.cmd_executes("html --omit fooey", """\
277 .coverage(omit=["fooey"])
278 .load()
279 .html_report(omit=["fooey"])
280 """)
281 self.cmd_executes("html --omit fooey,booey", """\
282 .coverage(omit=["fooey", "booey"])
283 .load()
284 .html_report(omit=["fooey", "booey"])
285 """)
286 self.cmd_executes("html mod1", """\
287 .coverage()
288 .load()
289 .html_report(morfs=["mod1"])
290 """)
291 self.cmd_executes("html mod1 mod2 mod3", """\
292 .coverage()
293 .load()
294 .html_report(morfs=["mod1", "mod2", "mod3"])
295 """)
296 self.cmd_executes("html --title=Hello_there", """\
297 .coverage()
298 .load()
299 .html_report(title='Hello_there')
300 """)
301
302 def test_report(self):
303 # coverage report [-m] [-i] [-o DIR,...] [FILE1 FILE2 ...]
304 self.cmd_executes("report", """\
305 .coverage()
306 .load()
307 .report(show_missing=None)
308 """)
309 self.cmd_executes("report -i", """\
310 .coverage()
311 .load()
312 .report(ignore_errors=True)
313 """)
314 self.cmd_executes("report -m", """\
315 .coverage()
316 .load()
317 .report(show_missing=True)
318 """)
319 self.cmd_executes("report --omit fooey", """\
320 .coverage(omit=["fooey"])
321 .load()
322 .report(omit=["fooey"])
323 """)
324 self.cmd_executes("report --omit fooey,booey", """\
325 .coverage(omit=["fooey", "booey"])
326 .load()
327 .report(omit=["fooey", "booey"])
328 """)
329 self.cmd_executes("report mod1", """\
330 .coverage()
331 .load()
332 .report(morfs=["mod1"])
333 """)
334 self.cmd_executes("report mod1 mod2 mod3", """\
335 .coverage()
336 .load()
337 .report(morfs=["mod1", "mod2", "mod3"])
338 """)
339 self.cmd_executes("report --skip-covered", """\
340 .coverage()
341 .load()
342 .report(skip_covered=True)
343 """)
344
345 def test_run(self):
346 # coverage run [-p] [-L] [--timid] MODULE.py [ARG1 ARG2 ...]
347
348 # run calls coverage.erase first.
349 self.cmd_executes("run foo.py", """\
350 .coverage()
351 .erase()
352 .start()
353 .run_python_file('foo.py', ['foo.py'])
354 .stop()
355 .save()
356 """)
357 # run -a combines with an existing data file before saving.
358 self.cmd_executes("run -a foo.py", """\
359 .coverage()
360 .start()
361 .run_python_file('foo.py', ['foo.py'])
362 .stop()
363 .path_exists('.coverage')
364 .combine(data_paths=['.coverage'])
365 .save()
366 """, path_exists=True)
367 # run -a doesn't combine anything if the data file doesn't exist.
368 self.cmd_executes("run -a foo.py", """\
369 .coverage()
370 .start()
371 .run_python_file('foo.py', ['foo.py'])
372 .stop()
373 .path_exists('.coverage')
374 .save()
375 """, path_exists=False)
376 # --timid sets a flag, and program arguments get passed through.
377 self.cmd_executes("run --timid foo.py abc 123", """\
378 .coverage(timid=True)
379 .erase()
380 .start()
381 .run_python_file('foo.py', ['foo.py', 'abc', '123'])
382 .stop()
383 .save()
384 """)
385 # -L sets a flag, and flags for the program don't confuse us.
386 self.cmd_executes("run -p -L foo.py -a -b", """\
387 .coverage(cover_pylib=True, data_suffix=True)
388 .erase()
389 .start()
390 .run_python_file('foo.py', ['foo.py', '-a', '-b'])
391 .stop()
392 .save()
393 """)
394 self.cmd_executes("run --branch foo.py", """\
395 .coverage(branch=True)
396 .erase()
397 .start()
398 .run_python_file('foo.py', ['foo.py'])
399 .stop()
400 .save()
401 """)
402 self.cmd_executes("run --rcfile=myrc.rc foo.py", """\
403 .coverage(config_file="myrc.rc")
404 .erase()
405 .start()
406 .run_python_file('foo.py', ['foo.py'])
407 .stop()
408 .save()
409 """)
410 self.cmd_executes("run --include=pre1,pre2 foo.py", """\
411 .coverage(include=["pre1", "pre2"])
412 .erase()
413 .start()
414 .run_python_file('foo.py', ['foo.py'])
415 .stop()
416 .save()
417 """)
418 self.cmd_executes("run --omit=opre1,opre2 foo.py", """\
419 .coverage(omit=["opre1", "opre2"])
420 .erase()
421 .start()
422 .run_python_file('foo.py', ['foo.py'])
423 .stop()
424 .save()
425 """)
426 self.cmd_executes("run --include=pre1,pre2 --omit=opre1,opre2 foo.py",
427 """\
428 .coverage(include=["pre1", "pre2"], omit=["opre1", "opre2"])
429 .erase()
430 .start()
431 .run_python_file('foo.py', ['foo.py'])
432 .stop()
433 .save()
434 """)
435 self.cmd_executes("run --source=quux,hi.there,/home/bar foo.py", """\
436 .coverage(source=["quux", "hi.there", "/home/bar"])
437 .erase()
438 .start()
439 .run_python_file('foo.py', ['foo.py'])
440 .stop()
441 .save()
442 """)
443 self.cmd_executes("run --concurrency=gevent foo.py", """\
444 .coverage(concurrency='gevent')
445 .erase()
446 .start()
447 .run_python_file('foo.py', ['foo.py'])
448 .stop()
449 .save()
450 """)
451
452 def test_bad_concurrency(self):
453 self.command_line("run --concurrency=nothing", ret=ERR)
454 out = self.stdout()
455 self.assertIn("option --concurrency: invalid choice: 'nothing'", out)
456
457 def test_run_debug(self):
458 self.cmd_executes("run --debug=opt1 foo.py", """\
459 .coverage(debug=["opt1"])
460 .erase()
461 .start()
462 .run_python_file('foo.py', ['foo.py'])
463 .stop()
464 .save()
465 """)
466 self.cmd_executes("run --debug=opt1,opt2 foo.py", """\
467 .coverage(debug=["opt1","opt2"])
468 .erase()
469 .start()
470 .run_python_file('foo.py', ['foo.py'])
471 .stop()
472 .save()
473 """)
474
475 def test_run_module(self):
476 self.cmd_executes("run -m mymodule", """\
477 .coverage()
478 .erase()
479 .start()
480 .run_python_module('mymodule', ['mymodule'])
481 .stop()
482 .save()
483 """)
484 self.cmd_executes("run -m mymodule -qq arg1 arg2", """\
485 .coverage()
486 .erase()
487 .start()
488 .run_python_module('mymodule', ['mymodule', '-qq', 'arg1', 'arg2'])
489 .stop()
490 .save()
491 """)
492 self.cmd_executes("run --branch -m mymodule", """\
493 .coverage(branch=True)
494 .erase()
495 .start()
496 .run_python_module('mymodule', ['mymodule'])
497 .stop()
498 .save()
499 """)
500 self.cmd_executes_same("run -m mymodule", "run --module mymodule")
501
502 def test_run_nothing(self):
503 self.command_line("run", ret=ERR)
504 self.assertIn("Nothing to do", self.stdout())
505
506 def test_cant_append_parallel(self):
507 self.command_line("run --append --parallel-mode foo.py", ret=ERR)
508 self.assertIn("Can't append to data files in parallel mode.", self.stdou t())
509
510 def test_xml(self):
511 # coverage xml [-i] [--omit DIR,...] [FILE1 FILE2 ...]
512 self.cmd_executes("xml", """\
513 .coverage()
514 .load()
515 .xml_report()
516 """)
517 self.cmd_executes("xml -i", """\
518 .coverage()
519 .load()
520 .xml_report(ignore_errors=True)
521 """)
522 self.cmd_executes("xml -o myxml.foo", """\
523 .coverage()
524 .load()
525 .xml_report(outfile="myxml.foo")
526 """)
527 self.cmd_executes("xml -o -", """\
528 .coverage()
529 .load()
530 .xml_report(outfile="-")
531 """)
532 self.cmd_executes("xml --omit fooey", """\
533 .coverage(omit=["fooey"])
534 .load()
535 .xml_report(omit=["fooey"])
536 """)
537 self.cmd_executes("xml --omit fooey,booey", """\
538 .coverage(omit=["fooey", "booey"])
539 .load()
540 .xml_report(omit=["fooey", "booey"])
541 """)
542 self.cmd_executes("xml mod1", """\
543 .coverage()
544 .load()
545 .xml_report(morfs=["mod1"])
546 """)
547 self.cmd_executes("xml mod1 mod2 mod3", """\
548 .coverage()
549 .load()
550 .xml_report(morfs=["mod1", "mod2", "mod3"])
551 """)
552
553 def test_no_arguments_at_all(self):
554 self.cmd_help("", topic="minimum_help", ret=OK)
555
556 def test_bad_command(self):
557 self.cmd_help("xyzzy", "Unknown command: 'xyzzy'")
558
559
560 class CmdLineWithFilesTest(BaseCmdLineTest):
561 """Test the command line in ways that need temp files."""
562
563 run_in_temp_dir = True
564 no_files_in_temp_dir = True
565
566 def test_debug_data(self):
567 data = CoverageData()
568 data.add_lines({
569 "file1.py": dict.fromkeys(range(1, 18)),
570 "file2.py": dict.fromkeys(range(1, 24)),
571 })
572 data.add_file_tracers({"file1.py": "a_plugin"})
573 data_files = CoverageDataFiles()
574 data_files.write(data)
575
576 self.command_line("debug data")
577 self.assertMultiLineEqual(self.stdout(), textwrap.dedent("""\
578 -- data ------------------------------------------------------
579 path: FILENAME
580 has_arcs: False
581
582 2 files:
583 file1.py: 17 lines [a_plugin]
584 file2.py: 23 lines
585 """).replace("FILENAME", data_files.filename))
586
587 def test_debug_data_with_no_data(self):
588 data_files = CoverageDataFiles()
589 self.command_line("debug data")
590 self.assertMultiLineEqual(self.stdout(), textwrap.dedent("""\
591 -- data ------------------------------------------------------
592 path: FILENAME
593 No data collected
594 """).replace("FILENAME", data_files.filename))
595
596
597 class CmdLineStdoutTest(BaseCmdLineTest):
598 """Test the command line with real stdout output."""
599
600 def test_minimum_help(self):
601 self.command_line("")
602 out = self.stdout()
603 self.assertIn("Code coverage for Python.", out)
604 self.assertLess(out.count("\n"), 4)
605
606 def test_version(self):
607 self.command_line("--version")
608 out = self.stdout()
609 self.assertIn("ersion ", out)
610 self.assertLess(out.count("\n"), 4)
611
612 def test_help(self):
613 self.command_line("help")
614 out = self.stdout()
615 self.assertIn("readthedocs.org", out)
616 self.assertGreater(out.count("\n"), 10)
617
618 def test_cmd_help(self):
619 self.command_line("help run")
620 out = self.stdout()
621 self.assertIn("<pyfile>", out)
622 self.assertIn("--timid", out)
623 self.assertGreater(out.count("\n"), 10)
624
625 def test_error(self):
626 self.command_line("fooey kablooey", ret=ERR)
627 out = self.stdout()
628 self.assertIn("fooey", out)
629 self.assertIn("help", out)
630
631
632 class CmdMainTest(CoverageTest):
633 """Tests of coverage.cmdline.main(), using mocking for isolation."""
634
635 run_in_temp_dir = False
636
637 class CoverageScriptStub(object):
638 """A stub for coverage.cmdline.CoverageScript, used by CmdMainTest."""
639
640 def command_line(self, argv):
641 """Stub for command_line, the arg determines what it will do."""
642 if argv[0] == 'hello':
643 print("Hello, world!")
644 elif argv[0] == 'raise':
645 try:
646 raise Exception("oh noes!")
647 except:
648 raise ExceptionDuringRun(*sys.exc_info())
649 elif argv[0] == 'internalraise':
650 raise ValueError("coverage is broken")
651 elif argv[0] == 'exit':
652 sys.exit(23)
653 else:
654 raise AssertionError("Bad CoverageScriptStub: %r"% (argv,))
655 return 0
656
657 def setUp(self):
658 super(CmdMainTest, self).setUp()
659 self.old_CoverageScript = coverage.cmdline.CoverageScript
660 coverage.cmdline.CoverageScript = self.CoverageScriptStub
661 self.addCleanup(self.cleanup_coverage_script)
662
663 def cleanup_coverage_script(self):
664 """Restore CoverageScript when the test is done."""
665 coverage.cmdline.CoverageScript = self.old_CoverageScript
666
667 def test_normal(self):
668 ret = coverage.cmdline.main(['hello'])
669 self.assertEqual(ret, 0)
670 self.assertEqual(self.stdout(), "Hello, world!\n")
671
672 def test_raise(self):
673 ret = coverage.cmdline.main(['raise'])
674 self.assertEqual(ret, 1)
675 self.assertEqual(self.stdout(), "")
676 err = self.stderr().split('\n')
677 self.assertEqual(err[0], 'Traceback (most recent call last):')
678 self.assertEqual(err[-3], ' raise Exception("oh noes!")')
679 self.assertEqual(err[-2], 'Exception: oh noes!')
680
681 def test_internalraise(self):
682 with self.assertRaisesRegex(ValueError, "coverage is broken"):
683 coverage.cmdline.main(['internalraise'])
684
685 def test_exit(self):
686 ret = coverage.cmdline.main(['exit'])
687 self.assertEqual(ret, 23)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698