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

Side by Side Diff: tools/telemetry/third_party/coverage/tests/test_plugins.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 plugins."""
5
6 import os.path
7
8 import coverage
9 from coverage import env
10 from coverage.backward import StringIO
11 from coverage.control import Plugins
12 from coverage.misc import CoverageException
13
14 import coverage.plugin
15
16 from tests.coveragetest import CoverageTest
17 from tests.helpers import CheckUniqueFilenames
18
19
20 class FakeConfig(object):
21 """A fake config for use in tests."""
22
23 def __init__(self, plugin, options):
24 self.plugin = plugin
25 self.options = options
26 self.asked_for = []
27
28 def get_plugin_options(self, module):
29 """Just return the options for `module` if this is the right module."""
30 self.asked_for.append(module)
31 if module == self.plugin:
32 return self.options
33 else:
34 return {}
35
36
37 class LoadPluginsTest(CoverageTest):
38 """Test Plugins.load_plugins directly."""
39
40 def test_implicit_boolean(self):
41 self.make_file("plugin1.py", """\
42 from coverage import CoveragePlugin
43
44 class Plugin(CoveragePlugin):
45 pass
46
47 def coverage_init(reg, options):
48 reg.add_file_tracer(Plugin())
49 """)
50
51 config = FakeConfig("plugin1", {})
52 plugins = Plugins.load_plugins([], config)
53 self.assertFalse(plugins)
54
55 plugins = Plugins.load_plugins(["plugin1"], config)
56 self.assertTrue(plugins)
57
58 def test_importing_and_configuring(self):
59 self.make_file("plugin1.py", """\
60 from coverage import CoveragePlugin
61
62 class Plugin(CoveragePlugin):
63 def __init__(self, options):
64 self.options = options
65 self.this_is = "me"
66
67 def coverage_init(reg, options):
68 reg.add_file_tracer(Plugin(options))
69 """)
70
71 config = FakeConfig("plugin1", {'a': 'hello'})
72 plugins = list(Plugins.load_plugins(["plugin1"], config))
73
74 self.assertEqual(len(plugins), 1)
75 self.assertEqual(plugins[0].this_is, "me")
76 self.assertEqual(plugins[0].options, {'a': 'hello'})
77 self.assertEqual(config.asked_for, ['plugin1'])
78
79 def test_importing_and_configuring_more_than_one(self):
80 self.make_file("plugin1.py", """\
81 from coverage import CoveragePlugin
82
83 class Plugin(CoveragePlugin):
84 def __init__(self, options):
85 self.options = options
86 self.this_is = "me"
87
88 def coverage_init(reg, options):
89 reg.add_file_tracer(Plugin(options))
90 """)
91 self.make_file("plugin2.py", """\
92 from coverage import CoveragePlugin
93
94 class Plugin(CoveragePlugin):
95 def __init__(self, options):
96 self.options = options
97
98 def coverage_init(reg, options):
99 reg.add_file_tracer(Plugin(options))
100 """)
101
102 config = FakeConfig("plugin1", {'a': 'hello'})
103 plugins = list(Plugins.load_plugins(["plugin1", "plugin2"], config))
104
105 self.assertEqual(len(plugins), 2)
106 self.assertEqual(plugins[0].this_is, "me")
107 self.assertEqual(plugins[0].options, {'a': 'hello'})
108 self.assertEqual(plugins[1].options, {})
109 self.assertEqual(config.asked_for, ['plugin1', 'plugin2'])
110
111 # The order matters...
112 config = FakeConfig("plugin1", {'a': 'second'})
113 plugins = list(Plugins.load_plugins(["plugin2", "plugin1"], config))
114
115 self.assertEqual(len(plugins), 2)
116 self.assertEqual(plugins[0].options, {})
117 self.assertEqual(plugins[1].this_is, "me")
118 self.assertEqual(plugins[1].options, {'a': 'second'})
119
120 def test_cant_import(self):
121 with self.assertRaises(ImportError):
122 _ = Plugins.load_plugins(["plugin_not_there"], None)
123
124 def test_plugin_must_define_coverage_init(self):
125 self.make_file("no_plugin.py", """\
126 from coverage import CoveragePlugin
127 Nothing = 0
128 """)
129 msg_pat = "Plugin module 'no_plugin' didn't define a coverage_init funct ion"
130 with self.assertRaisesRegex(CoverageException, msg_pat):
131 list(Plugins.load_plugins(["no_plugin"], None))
132
133
134 class PluginTest(CoverageTest):
135 """Test plugins through the Coverage class."""
136
137 def test_plugin_imported(self):
138 # Prove that a plugin will be imported.
139 self.make_file("my_plugin.py", """\
140 from coverage import CoveragePlugin
141 class Plugin(CoveragePlugin):
142 pass
143 def coverage_init(reg, options):
144 reg.add_noop(Plugin())
145 with open("evidence.out", "w") as f:
146 f.write("we are here!")
147 """)
148
149 self.assert_doesnt_exist("evidence.out")
150 cov = coverage.Coverage()
151 cov.set_option("run:plugins", ["my_plugin"])
152 cov.start()
153 cov.stop() # pragma: nested
154
155 with open("evidence.out") as f:
156 self.assertEqual(f.read(), "we are here!")
157
158 def test_missing_plugin_raises_import_error(self):
159 # Prove that a missing plugin will raise an ImportError.
160 with self.assertRaises(ImportError):
161 cov = coverage.Coverage()
162 cov.set_option("run:plugins", ["does_not_exist_woijwoicweo"])
163 cov.start()
164 cov.stop()
165
166 def test_bad_plugin_isnt_hidden(self):
167 # Prove that a plugin with an error in it will raise the error.
168 self.make_file("plugin_over_zero.py", """\
169 1/0
170 """)
171 with self.assertRaises(ZeroDivisionError):
172 cov = coverage.Coverage()
173 cov.set_option("run:plugins", ["plugin_over_zero"])
174 cov.start()
175 cov.stop()
176
177 def test_plugin_sys_info(self):
178 self.make_file("plugin_sys_info.py", """\
179 import coverage
180
181 class Plugin(coverage.CoveragePlugin):
182 def sys_info(self):
183 return [("hello", "world")]
184
185 def coverage_init(reg, options):
186 reg.add_noop(Plugin())
187 """)
188 debug_out = StringIO()
189 cov = coverage.Coverage(debug=["sys"])
190 cov._debug_file = debug_out
191 cov.set_option("run:plugins", ["plugin_sys_info"])
192 cov.load()
193
194 out_lines = debug_out.getvalue().splitlines()
195 expected_end = [
196 "-- sys: plugin_sys_info.Plugin -------------------------------",
197 " hello: world",
198 "-- end -------------------------------------------------------",
199 ]
200 self.assertEqual(expected_end, out_lines[-len(expected_end):])
201
202 def test_plugin_with_no_sys_info(self):
203 self.make_file("plugin_no_sys_info.py", """\
204 import coverage
205
206 class Plugin(coverage.CoveragePlugin):
207 pass
208
209 def coverage_init(reg, options):
210 reg.add_noop(Plugin())
211 """)
212 debug_out = StringIO()
213 cov = coverage.Coverage(debug=["sys"])
214 cov._debug_file = debug_out
215 cov.set_option("run:plugins", ["plugin_no_sys_info"])
216 cov.load()
217
218 out_lines = debug_out.getvalue().splitlines()
219 expected_end = [
220 "-- sys: plugin_no_sys_info.Plugin ----------------------------",
221 "-- end -------------------------------------------------------",
222 ]
223 self.assertEqual(expected_end, out_lines[-len(expected_end):])
224
225 def test_local_files_are_importable(self):
226 self.make_file("importing_plugin.py", """\
227 from coverage import CoveragePlugin
228 import local_module
229 class MyPlugin(CoveragePlugin):
230 pass
231 def coverage_init(reg, options):
232 reg.add_noop(MyPlugin())
233 """)
234 self.make_file("local_module.py", "CONST = 1")
235 self.make_file(".coveragerc", """\
236 [run]
237 plugins = importing_plugin
238 """)
239 self.make_file("main_file.py", "print('MAIN')")
240
241 out = self.run_command("coverage run main_file.py")
242 self.assertEqual(out, "MAIN\n")
243 out = self.run_command("coverage html")
244 self.assertEqual(out, "")
245
246
247 class PluginWarningOnPyTracer(CoverageTest):
248 """Test that we get a controlled exception with plugins on PyTracer."""
249 def test_exception_if_plugins_on_pytracer(self):
250 if env.C_TRACER:
251 self.skip("This test is only about PyTracer.")
252
253 self.make_file("simple.py", """a = 1""")
254
255 cov = coverage.Coverage()
256 cov.set_option("run:plugins", ["tests.plugin1"])
257
258 warnings = []
259 def capture_warning(msg):
260 """A fake implementation of Coverage._warn, to capture warnings."""
261 warnings.append(msg)
262 cov._warn = capture_warning
263
264 self.start_import_stop(cov, "simple")
265 self.assertIn(
266 "Plugin file tracers (tests.plugin1.Plugin) aren't supported with Py Tracer",
267 warnings
268 )
269
270
271 class FileTracerTest(CoverageTest):
272 """Tests of plugins that implement file_tracer."""
273
274 def setUp(self):
275 super(FileTracerTest, self).setUp()
276 if not env.C_TRACER:
277 self.skip("Plugins are only supported with the C tracer.")
278
279
280 class GoodPluginTest(FileTracerTest):
281 """Tests of plugin happy paths."""
282
283 def test_plugin1(self):
284 self.make_file("simple.py", """\
285 import try_xyz
286 a = 1
287 b = 2
288 """)
289 self.make_file("try_xyz.py", """\
290 c = 3
291 d = 4
292 """)
293
294 cov = coverage.Coverage()
295 CheckUniqueFilenames.hook(cov, '_should_trace')
296 CheckUniqueFilenames.hook(cov, '_check_include_omit_etc')
297 cov.set_option("run:plugins", ["tests.plugin1"])
298
299 # Import the Python file, executing it.
300 self.start_import_stop(cov, "simple")
301
302 _, statements, missing, _ = cov.analysis("simple.py")
303 self.assertEqual(statements, [1, 2, 3])
304 self.assertEqual(missing, [])
305 zzfile = os.path.abspath(os.path.join("/src", "try_ABC.zz"))
306 _, statements, _, _ = cov.analysis(zzfile)
307 self.assertEqual(statements, [105, 106, 107, 205, 206, 207])
308
309 def make_render_and_caller(self):
310 """Make the render.py and caller.py files we need."""
311 # plugin2 emulates a dynamic tracing plugin: the caller's locals
312 # are examined to determine the source file and line number.
313 # The plugin is in tests/plugin2.py.
314 self.make_file("render.py", """\
315 def render(filename, linenum):
316 # This function emulates a template renderer. The plugin
317 # will examine the `filename` and `linenum` locals to
318 # determine the source file and line number.
319 fiddle_around = 1 # not used, just chaff.
320 return "[{0} @ {1}]".format(filename, linenum)
321
322 def helper(x):
323 # This function is here just to show that not all code in
324 # this file will be part of the dynamic tracing.
325 return x+1
326 """)
327 self.make_file("caller.py", """\
328 import sys
329 from render import helper, render
330
331 assert render("foo_7.html", 4) == "[foo_7.html @ 4]"
332 # Render foo_7.html again to try the CheckUniqueFilenames asserts.
333 render("foo_7.html", 4)
334
335 assert helper(42) == 43
336 assert render("bar_4.html", 2) == "[bar_4.html @ 2]"
337 assert helper(76) == 77
338
339 # quux_5.html will be omitted from the results.
340 assert render("quux_5.html", 3) == "[quux_5.html @ 3]"
341
342 # In Python 2, either kind of string should be OK.
343 if sys.version_info[0] == 2:
344 assert render(u"uni_3.html", 2) == "[uni_3.html @ 2]"
345 """)
346
347 # will try to read the actual source files, so make some
348 # source files.
349 def lines(n):
350 """Make a string with n lines of text."""
351 return "".join("line %d\n" % i for i in range(n))
352
353 self.make_file("bar_4.html", lines(4))
354 self.make_file("foo_7.html", lines(7))
355
356 def test_plugin2(self):
357 self.make_render_and_caller()
358
359 cov = coverage.Coverage(omit=["*quux*"])
360 CheckUniqueFilenames.hook(cov, '_should_trace')
361 CheckUniqueFilenames.hook(cov, '_check_include_omit_etc')
362 cov.set_option("run:plugins", ["tests.plugin2"])
363
364 self.start_import_stop(cov, "caller")
365
366 # The way plugin2 works, a file named foo_7.html will be claimed to
367 # have 7 lines in it. If render() was called with line number 4,
368 # then the plugin will claim that lines 4 and 5 were executed.
369 _, statements, missing, _ = cov.analysis("foo_7.html")
370 self.assertEqual(statements, [1, 2, 3, 4, 5, 6, 7])
371 self.assertEqual(missing, [1, 2, 3, 6, 7])
372 self.assertIn("foo_7.html", cov.data.line_counts())
373
374 _, statements, missing, _ = cov.analysis("bar_4.html")
375 self.assertEqual(statements, [1, 2, 3, 4])
376 self.assertEqual(missing, [1, 4])
377 self.assertIn("bar_4.html", cov.data.line_counts())
378
379 self.assertNotIn("quux_5.html", cov.data.line_counts())
380
381 if env.PY2:
382 _, statements, missing, _ = cov.analysis("uni_3.html")
383 self.assertEqual(statements, [1, 2, 3])
384 self.assertEqual(missing, [1])
385 self.assertIn("uni_3.html", cov.data.line_counts())
386
387 def test_plugin2_with_branch(self):
388 self.make_render_and_caller()
389
390 cov = coverage.Coverage(branch=True, omit=["*quux*"])
391 CheckUniqueFilenames.hook(cov, '_should_trace')
392 CheckUniqueFilenames.hook(cov, '_check_include_omit_etc')
393 cov.set_option("run:plugins", ["tests.plugin2"])
394
395 self.start_import_stop(cov, "caller")
396
397 # The way plugin2 works, a file named foo_7.html will be claimed to
398 # have 7 lines in it. If render() was called with line number 4,
399 # then the plugin will claim that lines 4 and 5 were executed.
400 analysis = cov._analyze("foo_7.html")
401 self.assertEqual(analysis.statements, set([1, 2, 3, 4, 5, 6, 7]))
402 # Plugins don't do branch coverage yet.
403 self.assertEqual(analysis.has_arcs(), True)
404 self.assertEqual(analysis.arc_possibilities(), [])
405
406 self.assertEqual(analysis.missing, set([1, 2, 3, 6, 7]))
407
408 def test_plugin2_with_text_report(self):
409 self.make_render_and_caller()
410
411 cov = coverage.Coverage(branch=True, omit=["*quux*"])
412 cov.set_option("run:plugins", ["tests.plugin2"])
413
414 self.start_import_stop(cov, "caller")
415
416 repout = StringIO()
417 total = cov.report(file=repout, include=["*.html"], omit=["uni*.html"])
418 report = repout.getvalue().splitlines()
419 expected = [
420 'Name Stmts Miss Branch BrPart Cover Missing',
421 '--------------------------------------------------------',
422 'bar_4.html 4 2 0 0 50% 1, 4',
423 'foo_7.html 7 5 0 0 29% 1-3, 6-7',
424 '--------------------------------------------------------',
425 'TOTAL 11 7 0 0 36% ',
426 ]
427 self.assertEqual(report, expected)
428 self.assertAlmostEqual(total, 36.36, places=2)
429
430 def test_plugin2_with_html_report(self):
431 self.make_render_and_caller()
432
433 cov = coverage.Coverage(branch=True, omit=["*quux*"])
434 cov.set_option("run:plugins", ["tests.plugin2"])
435
436 self.start_import_stop(cov, "caller")
437
438 total = cov.html_report(include=["*.html"], omit=["uni*.html"])
439 self.assertAlmostEqual(total, 36.36, places=2)
440
441 self.assert_exists("htmlcov/index.html")
442 self.assert_exists("htmlcov/bar_4_html.html")
443 self.assert_exists("htmlcov/foo_7_html.html")
444
445 def test_plugin2_with_xml_report(self):
446 self.make_render_and_caller()
447
448 cov = coverage.Coverage(branch=True, omit=["*quux*"])
449 cov.set_option("run:plugins", ["tests.plugin2"])
450
451 self.start_import_stop(cov, "caller")
452
453 total = cov.xml_report(include=["*.html"], omit=["uni*.html"])
454 self.assertAlmostEqual(total, 36.36, places=2)
455
456 with open("coverage.xml") as fxml:
457 xml = fxml.read()
458
459 for snip in [
460 'filename="bar_4.html" line-rate="0.5" name="bar_4.html"',
461 'filename="foo_7.html" line-rate="0.2857" name="foo_7.html"',
462 ]:
463 self.assertIn(snip, xml)
464
465 def test_defer_to_python(self):
466 # A plugin that measures, but then wants built-in python reporting.
467 self.make_file("fairly_odd_plugin.py", """\
468 # A plugin that claims all the odd lines are executed, and none of
469 # the even lines, and then punts reporting off to the built-in
470 # Python reporting.
471 import coverage.plugin
472 class Plugin(coverage.CoveragePlugin):
473 def file_tracer(self, filename):
474 return OddTracer(filename)
475 def file_reporter(self, filename):
476 return "python"
477
478 class OddTracer(coverage.plugin.FileTracer):
479 def __init__(self, filename):
480 self.filename = filename
481 def source_filename(self):
482 return self.filename
483 def line_number_range(self, frame):
484 lineno = frame.f_lineno
485 if lineno % 2:
486 return (lineno, lineno)
487 else:
488 return (-1, -1)
489
490 def coverage_init(reg, options):
491 reg.add_file_tracer(Plugin())
492 """)
493 self.make_file("unsuspecting.py", """\
494 a = 1
495 b = 2
496 c = 3
497 d = 4
498 e = 5
499 f = 6
500 """)
501 cov = coverage.Coverage(include=["unsuspecting.py"])
502 cov.set_option("run:plugins", ["fairly_odd_plugin"])
503 self.start_import_stop(cov, "unsuspecting")
504
505 repout = StringIO()
506 total = cov.report(file=repout)
507 report = repout.getvalue().splitlines()
508 expected = [
509 'Name Stmts Miss Cover Missing',
510 '-----------------------------------------------',
511 'unsuspecting.py 6 3 50% 2, 4, 6',
512 ]
513 self.assertEqual(report, expected)
514 self.assertEqual(total, 50)
515
516
517 class BadPluginTest(FileTracerTest):
518 """Test error handling around plugins."""
519
520 def run_plugin(self, module_name):
521 """Run a plugin with the given module_name.
522
523 Uses a few fixed Python files.
524
525 Returns the Coverage object.
526
527 """
528 self.make_file("simple.py", """\
529 import other, another
530 a = other.f(2)
531 b = other.f(3)
532 c = another.g(4)
533 d = another.g(5)
534 """)
535 # The names of these files are important: some plugins apply themselves
536 # to "*other.py".
537 self.make_file("other.py", """\
538 def f(x):
539 return x+1
540 """)
541 self.make_file("another.py", """\
542 def g(x):
543 return x-1
544 """)
545
546 cov = coverage.Coverage()
547 cov.set_option("run:plugins", [module_name])
548 self.start_import_stop(cov, "simple")
549 return cov
550
551 def run_bad_plugin(self, module_name, plugin_name, our_error=True, excmsg=No ne):
552 """Run a file, and see that the plugin failed.
553
554 `module_name` and `plugin_name` is the module and name of the plugin to
555 use.
556
557 `our_error` is True if the error reported to the user will be an
558 explicit error in our test code, marked with an '# Oh noes!' comment.
559
560 `excmsg`, if provided, is text that should appear in the stderr.
561
562 The plugin will be disabled, and we check that a warning is output
563 explaining why.
564
565 """
566 self.run_plugin(module_name)
567
568 stderr = self.stderr()
569 print(stderr) # for diagnosing test failures.
570
571 if our_error:
572 errors = stderr.count("# Oh noes!")
573 # The exception we're causing should only appear once.
574 self.assertEqual(errors, 1)
575
576 # There should be a warning explaining what's happening, but only one.
577 # The message can be in two forms:
578 # Disabling plugin '...' due to previous exception
579 # or:
580 # Disabling plugin '...' due to an exception:
581 msg = "Disabling plugin '%s.%s' due to " % (module_name, plugin_name)
582 warnings = stderr.count(msg)
583 self.assertEqual(warnings, 1)
584
585 if excmsg:
586 self.assertIn(excmsg, stderr)
587
588 def test_file_tracer_has_no_file_tracer_method(self):
589 self.make_file("bad_plugin.py", """\
590 class Plugin(object):
591 pass
592
593 def coverage_init(reg, options):
594 reg.add_file_tracer(Plugin())
595 """)
596 self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
597
598 def test_file_tracer_has_inherited_sourcefilename_method(self):
599 self.make_file("bad_plugin.py", """\
600 import coverage
601 class Plugin(coverage.CoveragePlugin):
602 def file_tracer(self, filename):
603 # Just grab everything.
604 return FileTracer()
605
606 class FileTracer(coverage.FileTracer):
607 pass
608
609 def coverage_init(reg, options):
610 reg.add_file_tracer(Plugin())
611 """)
612 self.run_bad_plugin(
613 "bad_plugin", "Plugin", our_error=False,
614 excmsg="Class 'bad_plugin.FileTracer' needs to implement source_file name()",
615 )
616
617 def test_plugin_has_inherited_filereporter_method(self):
618 self.make_file("bad_plugin.py", """\
619 import coverage
620 class Plugin(coverage.CoveragePlugin):
621 def file_tracer(self, filename):
622 # Just grab everything.
623 return FileTracer()
624
625 class FileTracer(coverage.FileTracer):
626 def source_filename(self):
627 return "foo.xxx"
628
629 def coverage_init(reg, options):
630 reg.add_file_tracer(Plugin())
631 """)
632 cov = self.run_plugin("bad_plugin")
633 expected_msg = "Plugin 'bad_plugin.Plugin' needs to implement file_repor ter()"
634 with self.assertRaisesRegex(NotImplementedError, expected_msg):
635 cov.report()
636
637 def test_file_tracer_fails(self):
638 self.make_file("bad_plugin.py", """\
639 import coverage.plugin
640 class Plugin(coverage.plugin.CoveragePlugin):
641 def file_tracer(self, filename):
642 17/0 # Oh noes!
643
644 def coverage_init(reg, options):
645 reg.add_file_tracer(Plugin())
646 """)
647 self.run_bad_plugin("bad_plugin", "Plugin")
648
649 def test_file_tracer_returns_wrong(self):
650 self.make_file("bad_plugin.py", """\
651 import coverage.plugin
652 class Plugin(coverage.plugin.CoveragePlugin):
653 def file_tracer(self, filename):
654 return 3.14159
655
656 def coverage_init(reg, options):
657 reg.add_file_tracer(Plugin())
658 """)
659 self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
660
661 def test_has_dynamic_source_filename_fails(self):
662 self.make_file("bad_plugin.py", """\
663 import coverage.plugin
664 class Plugin(coverage.plugin.CoveragePlugin):
665 def file_tracer(self, filename):
666 return BadFileTracer()
667
668 class BadFileTracer(coverage.plugin.FileTracer):
669 def has_dynamic_source_filename(self):
670 23/0 # Oh noes!
671
672 def coverage_init(reg, options):
673 reg.add_file_tracer(Plugin())
674 """)
675 self.run_bad_plugin("bad_plugin", "Plugin")
676
677 def test_source_filename_fails(self):
678 self.make_file("bad_plugin.py", """\
679 import coverage.plugin
680 class Plugin(coverage.plugin.CoveragePlugin):
681 def file_tracer(self, filename):
682 return BadFileTracer()
683
684 class BadFileTracer(coverage.plugin.FileTracer):
685 def source_filename(self):
686 42/0 # Oh noes!
687
688 def coverage_init(reg, options):
689 reg.add_file_tracer(Plugin())
690 """)
691 self.run_bad_plugin("bad_plugin", "Plugin")
692
693 def test_source_filename_returns_wrong(self):
694 self.make_file("bad_plugin.py", """\
695 import coverage.plugin
696 class Plugin(coverage.plugin.CoveragePlugin):
697 def file_tracer(self, filename):
698 return BadFileTracer()
699
700 class BadFileTracer(coverage.plugin.FileTracer):
701 def source_filename(self):
702 return 17.3
703
704 def coverage_init(reg, options):
705 reg.add_file_tracer(Plugin())
706 """)
707 self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
708
709 def test_dynamic_source_filename_fails(self):
710 self.make_file("bad_plugin.py", """\
711 import coverage.plugin
712 class Plugin(coverage.plugin.CoveragePlugin):
713 def file_tracer(self, filename):
714 if filename.endswith("other.py"):
715 return BadFileTracer()
716
717 class BadFileTracer(coverage.plugin.FileTracer):
718 def has_dynamic_source_filename(self):
719 return True
720 def dynamic_source_filename(self, filename, frame):
721 101/0 # Oh noes!
722
723 def coverage_init(reg, options):
724 reg.add_file_tracer(Plugin())
725 """)
726 self.run_bad_plugin("bad_plugin", "Plugin")
727
728 def test_line_number_range_returns_non_tuple(self):
729 self.make_file("bad_plugin.py", """\
730 import coverage.plugin
731 class Plugin(coverage.plugin.CoveragePlugin):
732 def file_tracer(self, filename):
733 if filename.endswith("other.py"):
734 return BadFileTracer()
735
736 class BadFileTracer(coverage.plugin.FileTracer):
737 def source_filename(self):
738 return "something.foo"
739
740 def line_number_range(self, frame):
741 return 42.23
742
743 def coverage_init(reg, options):
744 reg.add_file_tracer(Plugin())
745 """)
746 self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
747
748 def test_line_number_range_returns_triple(self):
749 self.make_file("bad_plugin.py", """\
750 import coverage.plugin
751 class Plugin(coverage.plugin.CoveragePlugin):
752 def file_tracer(self, filename):
753 if filename.endswith("other.py"):
754 return BadFileTracer()
755
756 class BadFileTracer(coverage.plugin.FileTracer):
757 def source_filename(self):
758 return "something.foo"
759
760 def line_number_range(self, frame):
761 return (1, 2, 3)
762
763 def coverage_init(reg, options):
764 reg.add_file_tracer(Plugin())
765 """)
766 self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
767
768 def test_line_number_range_returns_pair_of_strings(self):
769 self.make_file("bad_plugin.py", """\
770 import coverage.plugin
771 class Plugin(coverage.plugin.CoveragePlugin):
772 def file_tracer(self, filename):
773 if filename.endswith("other.py"):
774 return BadFileTracer()
775
776 class BadFileTracer(coverage.plugin.FileTracer):
777 def source_filename(self):
778 return "something.foo"
779
780 def line_number_range(self, frame):
781 return ("5", "7")
782
783 def coverage_init(reg, options):
784 reg.add_file_tracer(Plugin())
785 """)
786 self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698