| Index: tools/telemetry/third_party/coverage/tests/test_plugins.py
|
| diff --git a/tools/telemetry/third_party/coverage/tests/test_plugins.py b/tools/telemetry/third_party/coverage/tests/test_plugins.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..06e3788ddb1ec1c38f2e2dbb1b5445b63fbce4ea
|
| --- /dev/null
|
| +++ b/tools/telemetry/third_party/coverage/tests/test_plugins.py
|
| @@ -0,0 +1,786 @@
|
| +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
|
| +# For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt
|
| +
|
| +"""Tests for plugins."""
|
| +
|
| +import os.path
|
| +
|
| +import coverage
|
| +from coverage import env
|
| +from coverage.backward import StringIO
|
| +from coverage.control import Plugins
|
| +from coverage.misc import CoverageException
|
| +
|
| +import coverage.plugin
|
| +
|
| +from tests.coveragetest import CoverageTest
|
| +from tests.helpers import CheckUniqueFilenames
|
| +
|
| +
|
| +class FakeConfig(object):
|
| + """A fake config for use in tests."""
|
| +
|
| + def __init__(self, plugin, options):
|
| + self.plugin = plugin
|
| + self.options = options
|
| + self.asked_for = []
|
| +
|
| + def get_plugin_options(self, module):
|
| + """Just return the options for `module` if this is the right module."""
|
| + self.asked_for.append(module)
|
| + if module == self.plugin:
|
| + return self.options
|
| + else:
|
| + return {}
|
| +
|
| +
|
| +class LoadPluginsTest(CoverageTest):
|
| + """Test Plugins.load_plugins directly."""
|
| +
|
| + def test_implicit_boolean(self):
|
| + self.make_file("plugin1.py", """\
|
| + from coverage import CoveragePlugin
|
| +
|
| + class Plugin(CoveragePlugin):
|
| + pass
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| +
|
| + config = FakeConfig("plugin1", {})
|
| + plugins = Plugins.load_plugins([], config)
|
| + self.assertFalse(plugins)
|
| +
|
| + plugins = Plugins.load_plugins(["plugin1"], config)
|
| + self.assertTrue(plugins)
|
| +
|
| + def test_importing_and_configuring(self):
|
| + self.make_file("plugin1.py", """\
|
| + from coverage import CoveragePlugin
|
| +
|
| + class Plugin(CoveragePlugin):
|
| + def __init__(self, options):
|
| + self.options = options
|
| + self.this_is = "me"
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin(options))
|
| + """)
|
| +
|
| + config = FakeConfig("plugin1", {'a': 'hello'})
|
| + plugins = list(Plugins.load_plugins(["plugin1"], config))
|
| +
|
| + self.assertEqual(len(plugins), 1)
|
| + self.assertEqual(plugins[0].this_is, "me")
|
| + self.assertEqual(plugins[0].options, {'a': 'hello'})
|
| + self.assertEqual(config.asked_for, ['plugin1'])
|
| +
|
| + def test_importing_and_configuring_more_than_one(self):
|
| + self.make_file("plugin1.py", """\
|
| + from coverage import CoveragePlugin
|
| +
|
| + class Plugin(CoveragePlugin):
|
| + def __init__(self, options):
|
| + self.options = options
|
| + self.this_is = "me"
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin(options))
|
| + """)
|
| + self.make_file("plugin2.py", """\
|
| + from coverage import CoveragePlugin
|
| +
|
| + class Plugin(CoveragePlugin):
|
| + def __init__(self, options):
|
| + self.options = options
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin(options))
|
| + """)
|
| +
|
| + config = FakeConfig("plugin1", {'a': 'hello'})
|
| + plugins = list(Plugins.load_plugins(["plugin1", "plugin2"], config))
|
| +
|
| + self.assertEqual(len(plugins), 2)
|
| + self.assertEqual(plugins[0].this_is, "me")
|
| + self.assertEqual(plugins[0].options, {'a': 'hello'})
|
| + self.assertEqual(plugins[1].options, {})
|
| + self.assertEqual(config.asked_for, ['plugin1', 'plugin2'])
|
| +
|
| + # The order matters...
|
| + config = FakeConfig("plugin1", {'a': 'second'})
|
| + plugins = list(Plugins.load_plugins(["plugin2", "plugin1"], config))
|
| +
|
| + self.assertEqual(len(plugins), 2)
|
| + self.assertEqual(plugins[0].options, {})
|
| + self.assertEqual(plugins[1].this_is, "me")
|
| + self.assertEqual(plugins[1].options, {'a': 'second'})
|
| +
|
| + def test_cant_import(self):
|
| + with self.assertRaises(ImportError):
|
| + _ = Plugins.load_plugins(["plugin_not_there"], None)
|
| +
|
| + def test_plugin_must_define_coverage_init(self):
|
| + self.make_file("no_plugin.py", """\
|
| + from coverage import CoveragePlugin
|
| + Nothing = 0
|
| + """)
|
| + msg_pat = "Plugin module 'no_plugin' didn't define a coverage_init function"
|
| + with self.assertRaisesRegex(CoverageException, msg_pat):
|
| + list(Plugins.load_plugins(["no_plugin"], None))
|
| +
|
| +
|
| +class PluginTest(CoverageTest):
|
| + """Test plugins through the Coverage class."""
|
| +
|
| + def test_plugin_imported(self):
|
| + # Prove that a plugin will be imported.
|
| + self.make_file("my_plugin.py", """\
|
| + from coverage import CoveragePlugin
|
| + class Plugin(CoveragePlugin):
|
| + pass
|
| + def coverage_init(reg, options):
|
| + reg.add_noop(Plugin())
|
| + with open("evidence.out", "w") as f:
|
| + f.write("we are here!")
|
| + """)
|
| +
|
| + self.assert_doesnt_exist("evidence.out")
|
| + cov = coverage.Coverage()
|
| + cov.set_option("run:plugins", ["my_plugin"])
|
| + cov.start()
|
| + cov.stop() # pragma: nested
|
| +
|
| + with open("evidence.out") as f:
|
| + self.assertEqual(f.read(), "we are here!")
|
| +
|
| + def test_missing_plugin_raises_import_error(self):
|
| + # Prove that a missing plugin will raise an ImportError.
|
| + with self.assertRaises(ImportError):
|
| + cov = coverage.Coverage()
|
| + cov.set_option("run:plugins", ["does_not_exist_woijwoicweo"])
|
| + cov.start()
|
| + cov.stop()
|
| +
|
| + def test_bad_plugin_isnt_hidden(self):
|
| + # Prove that a plugin with an error in it will raise the error.
|
| + self.make_file("plugin_over_zero.py", """\
|
| + 1/0
|
| + """)
|
| + with self.assertRaises(ZeroDivisionError):
|
| + cov = coverage.Coverage()
|
| + cov.set_option("run:plugins", ["plugin_over_zero"])
|
| + cov.start()
|
| + cov.stop()
|
| +
|
| + def test_plugin_sys_info(self):
|
| + self.make_file("plugin_sys_info.py", """\
|
| + import coverage
|
| +
|
| + class Plugin(coverage.CoveragePlugin):
|
| + def sys_info(self):
|
| + return [("hello", "world")]
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_noop(Plugin())
|
| + """)
|
| + debug_out = StringIO()
|
| + cov = coverage.Coverage(debug=["sys"])
|
| + cov._debug_file = debug_out
|
| + cov.set_option("run:plugins", ["plugin_sys_info"])
|
| + cov.load()
|
| +
|
| + out_lines = debug_out.getvalue().splitlines()
|
| + expected_end = [
|
| + "-- sys: plugin_sys_info.Plugin -------------------------------",
|
| + " hello: world",
|
| + "-- end -------------------------------------------------------",
|
| + ]
|
| + self.assertEqual(expected_end, out_lines[-len(expected_end):])
|
| +
|
| + def test_plugin_with_no_sys_info(self):
|
| + self.make_file("plugin_no_sys_info.py", """\
|
| + import coverage
|
| +
|
| + class Plugin(coverage.CoveragePlugin):
|
| + pass
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_noop(Plugin())
|
| + """)
|
| + debug_out = StringIO()
|
| + cov = coverage.Coverage(debug=["sys"])
|
| + cov._debug_file = debug_out
|
| + cov.set_option("run:plugins", ["plugin_no_sys_info"])
|
| + cov.load()
|
| +
|
| + out_lines = debug_out.getvalue().splitlines()
|
| + expected_end = [
|
| + "-- sys: plugin_no_sys_info.Plugin ----------------------------",
|
| + "-- end -------------------------------------------------------",
|
| + ]
|
| + self.assertEqual(expected_end, out_lines[-len(expected_end):])
|
| +
|
| + def test_local_files_are_importable(self):
|
| + self.make_file("importing_plugin.py", """\
|
| + from coverage import CoveragePlugin
|
| + import local_module
|
| + class MyPlugin(CoveragePlugin):
|
| + pass
|
| + def coverage_init(reg, options):
|
| + reg.add_noop(MyPlugin())
|
| + """)
|
| + self.make_file("local_module.py", "CONST = 1")
|
| + self.make_file(".coveragerc", """\
|
| + [run]
|
| + plugins = importing_plugin
|
| + """)
|
| + self.make_file("main_file.py", "print('MAIN')")
|
| +
|
| + out = self.run_command("coverage run main_file.py")
|
| + self.assertEqual(out, "MAIN\n")
|
| + out = self.run_command("coverage html")
|
| + self.assertEqual(out, "")
|
| +
|
| +
|
| +class PluginWarningOnPyTracer(CoverageTest):
|
| + """Test that we get a controlled exception with plugins on PyTracer."""
|
| + def test_exception_if_plugins_on_pytracer(self):
|
| + if env.C_TRACER:
|
| + self.skip("This test is only about PyTracer.")
|
| +
|
| + self.make_file("simple.py", """a = 1""")
|
| +
|
| + cov = coverage.Coverage()
|
| + cov.set_option("run:plugins", ["tests.plugin1"])
|
| +
|
| + warnings = []
|
| + def capture_warning(msg):
|
| + """A fake implementation of Coverage._warn, to capture warnings."""
|
| + warnings.append(msg)
|
| + cov._warn = capture_warning
|
| +
|
| + self.start_import_stop(cov, "simple")
|
| + self.assertIn(
|
| + "Plugin file tracers (tests.plugin1.Plugin) aren't supported with PyTracer",
|
| + warnings
|
| + )
|
| +
|
| +
|
| +class FileTracerTest(CoverageTest):
|
| + """Tests of plugins that implement file_tracer."""
|
| +
|
| + def setUp(self):
|
| + super(FileTracerTest, self).setUp()
|
| + if not env.C_TRACER:
|
| + self.skip("Plugins are only supported with the C tracer.")
|
| +
|
| +
|
| +class GoodPluginTest(FileTracerTest):
|
| + """Tests of plugin happy paths."""
|
| +
|
| + def test_plugin1(self):
|
| + self.make_file("simple.py", """\
|
| + import try_xyz
|
| + a = 1
|
| + b = 2
|
| + """)
|
| + self.make_file("try_xyz.py", """\
|
| + c = 3
|
| + d = 4
|
| + """)
|
| +
|
| + cov = coverage.Coverage()
|
| + CheckUniqueFilenames.hook(cov, '_should_trace')
|
| + CheckUniqueFilenames.hook(cov, '_check_include_omit_etc')
|
| + cov.set_option("run:plugins", ["tests.plugin1"])
|
| +
|
| + # Import the Python file, executing it.
|
| + self.start_import_stop(cov, "simple")
|
| +
|
| + _, statements, missing, _ = cov.analysis("simple.py")
|
| + self.assertEqual(statements, [1, 2, 3])
|
| + self.assertEqual(missing, [])
|
| + zzfile = os.path.abspath(os.path.join("/src", "try_ABC.zz"))
|
| + _, statements, _, _ = cov.analysis(zzfile)
|
| + self.assertEqual(statements, [105, 106, 107, 205, 206, 207])
|
| +
|
| + def make_render_and_caller(self):
|
| + """Make the render.py and caller.py files we need."""
|
| + # plugin2 emulates a dynamic tracing plugin: the caller's locals
|
| + # are examined to determine the source file and line number.
|
| + # The plugin is in tests/plugin2.py.
|
| + self.make_file("render.py", """\
|
| + def render(filename, linenum):
|
| + # This function emulates a template renderer. The plugin
|
| + # will examine the `filename` and `linenum` locals to
|
| + # determine the source file and line number.
|
| + fiddle_around = 1 # not used, just chaff.
|
| + return "[{0} @ {1}]".format(filename, linenum)
|
| +
|
| + def helper(x):
|
| + # This function is here just to show that not all code in
|
| + # this file will be part of the dynamic tracing.
|
| + return x+1
|
| + """)
|
| + self.make_file("caller.py", """\
|
| + import sys
|
| + from render import helper, render
|
| +
|
| + assert render("foo_7.html", 4) == "[foo_7.html @ 4]"
|
| + # Render foo_7.html again to try the CheckUniqueFilenames asserts.
|
| + render("foo_7.html", 4)
|
| +
|
| + assert helper(42) == 43
|
| + assert render("bar_4.html", 2) == "[bar_4.html @ 2]"
|
| + assert helper(76) == 77
|
| +
|
| + # quux_5.html will be omitted from the results.
|
| + assert render("quux_5.html", 3) == "[quux_5.html @ 3]"
|
| +
|
| + # In Python 2, either kind of string should be OK.
|
| + if sys.version_info[0] == 2:
|
| + assert render(u"uni_3.html", 2) == "[uni_3.html @ 2]"
|
| + """)
|
| +
|
| + # will try to read the actual source files, so make some
|
| + # source files.
|
| + def lines(n):
|
| + """Make a string with n lines of text."""
|
| + return "".join("line %d\n" % i for i in range(n))
|
| +
|
| + self.make_file("bar_4.html", lines(4))
|
| + self.make_file("foo_7.html", lines(7))
|
| +
|
| + def test_plugin2(self):
|
| + self.make_render_and_caller()
|
| +
|
| + cov = coverage.Coverage(omit=["*quux*"])
|
| + CheckUniqueFilenames.hook(cov, '_should_trace')
|
| + CheckUniqueFilenames.hook(cov, '_check_include_omit_etc')
|
| + cov.set_option("run:plugins", ["tests.plugin2"])
|
| +
|
| + self.start_import_stop(cov, "caller")
|
| +
|
| + # The way plugin2 works, a file named foo_7.html will be claimed to
|
| + # have 7 lines in it. If render() was called with line number 4,
|
| + # then the plugin will claim that lines 4 and 5 were executed.
|
| + _, statements, missing, _ = cov.analysis("foo_7.html")
|
| + self.assertEqual(statements, [1, 2, 3, 4, 5, 6, 7])
|
| + self.assertEqual(missing, [1, 2, 3, 6, 7])
|
| + self.assertIn("foo_7.html", cov.data.line_counts())
|
| +
|
| + _, statements, missing, _ = cov.analysis("bar_4.html")
|
| + self.assertEqual(statements, [1, 2, 3, 4])
|
| + self.assertEqual(missing, [1, 4])
|
| + self.assertIn("bar_4.html", cov.data.line_counts())
|
| +
|
| + self.assertNotIn("quux_5.html", cov.data.line_counts())
|
| +
|
| + if env.PY2:
|
| + _, statements, missing, _ = cov.analysis("uni_3.html")
|
| + self.assertEqual(statements, [1, 2, 3])
|
| + self.assertEqual(missing, [1])
|
| + self.assertIn("uni_3.html", cov.data.line_counts())
|
| +
|
| + def test_plugin2_with_branch(self):
|
| + self.make_render_and_caller()
|
| +
|
| + cov = coverage.Coverage(branch=True, omit=["*quux*"])
|
| + CheckUniqueFilenames.hook(cov, '_should_trace')
|
| + CheckUniqueFilenames.hook(cov, '_check_include_omit_etc')
|
| + cov.set_option("run:plugins", ["tests.plugin2"])
|
| +
|
| + self.start_import_stop(cov, "caller")
|
| +
|
| + # The way plugin2 works, a file named foo_7.html will be claimed to
|
| + # have 7 lines in it. If render() was called with line number 4,
|
| + # then the plugin will claim that lines 4 and 5 were executed.
|
| + analysis = cov._analyze("foo_7.html")
|
| + self.assertEqual(analysis.statements, set([1, 2, 3, 4, 5, 6, 7]))
|
| + # Plugins don't do branch coverage yet.
|
| + self.assertEqual(analysis.has_arcs(), True)
|
| + self.assertEqual(analysis.arc_possibilities(), [])
|
| +
|
| + self.assertEqual(analysis.missing, set([1, 2, 3, 6, 7]))
|
| +
|
| + def test_plugin2_with_text_report(self):
|
| + self.make_render_and_caller()
|
| +
|
| + cov = coverage.Coverage(branch=True, omit=["*quux*"])
|
| + cov.set_option("run:plugins", ["tests.plugin2"])
|
| +
|
| + self.start_import_stop(cov, "caller")
|
| +
|
| + repout = StringIO()
|
| + total = cov.report(file=repout, include=["*.html"], omit=["uni*.html"])
|
| + report = repout.getvalue().splitlines()
|
| + expected = [
|
| + 'Name Stmts Miss Branch BrPart Cover Missing',
|
| + '--------------------------------------------------------',
|
| + 'bar_4.html 4 2 0 0 50% 1, 4',
|
| + 'foo_7.html 7 5 0 0 29% 1-3, 6-7',
|
| + '--------------------------------------------------------',
|
| + 'TOTAL 11 7 0 0 36% ',
|
| + ]
|
| + self.assertEqual(report, expected)
|
| + self.assertAlmostEqual(total, 36.36, places=2)
|
| +
|
| + def test_plugin2_with_html_report(self):
|
| + self.make_render_and_caller()
|
| +
|
| + cov = coverage.Coverage(branch=True, omit=["*quux*"])
|
| + cov.set_option("run:plugins", ["tests.plugin2"])
|
| +
|
| + self.start_import_stop(cov, "caller")
|
| +
|
| + total = cov.html_report(include=["*.html"], omit=["uni*.html"])
|
| + self.assertAlmostEqual(total, 36.36, places=2)
|
| +
|
| + self.assert_exists("htmlcov/index.html")
|
| + self.assert_exists("htmlcov/bar_4_html.html")
|
| + self.assert_exists("htmlcov/foo_7_html.html")
|
| +
|
| + def test_plugin2_with_xml_report(self):
|
| + self.make_render_and_caller()
|
| +
|
| + cov = coverage.Coverage(branch=True, omit=["*quux*"])
|
| + cov.set_option("run:plugins", ["tests.plugin2"])
|
| +
|
| + self.start_import_stop(cov, "caller")
|
| +
|
| + total = cov.xml_report(include=["*.html"], omit=["uni*.html"])
|
| + self.assertAlmostEqual(total, 36.36, places=2)
|
| +
|
| + with open("coverage.xml") as fxml:
|
| + xml = fxml.read()
|
| +
|
| + for snip in [
|
| + 'filename="bar_4.html" line-rate="0.5" name="bar_4.html"',
|
| + 'filename="foo_7.html" line-rate="0.2857" name="foo_7.html"',
|
| + ]:
|
| + self.assertIn(snip, xml)
|
| +
|
| + def test_defer_to_python(self):
|
| + # A plugin that measures, but then wants built-in python reporting.
|
| + self.make_file("fairly_odd_plugin.py", """\
|
| + # A plugin that claims all the odd lines are executed, and none of
|
| + # the even lines, and then punts reporting off to the built-in
|
| + # Python reporting.
|
| + import coverage.plugin
|
| + class Plugin(coverage.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + return OddTracer(filename)
|
| + def file_reporter(self, filename):
|
| + return "python"
|
| +
|
| + class OddTracer(coverage.plugin.FileTracer):
|
| + def __init__(self, filename):
|
| + self.filename = filename
|
| + def source_filename(self):
|
| + return self.filename
|
| + def line_number_range(self, frame):
|
| + lineno = frame.f_lineno
|
| + if lineno % 2:
|
| + return (lineno, lineno)
|
| + else:
|
| + return (-1, -1)
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.make_file("unsuspecting.py", """\
|
| + a = 1
|
| + b = 2
|
| + c = 3
|
| + d = 4
|
| + e = 5
|
| + f = 6
|
| + """)
|
| + cov = coverage.Coverage(include=["unsuspecting.py"])
|
| + cov.set_option("run:plugins", ["fairly_odd_plugin"])
|
| + self.start_import_stop(cov, "unsuspecting")
|
| +
|
| + repout = StringIO()
|
| + total = cov.report(file=repout)
|
| + report = repout.getvalue().splitlines()
|
| + expected = [
|
| + 'Name Stmts Miss Cover Missing',
|
| + '-----------------------------------------------',
|
| + 'unsuspecting.py 6 3 50% 2, 4, 6',
|
| + ]
|
| + self.assertEqual(report, expected)
|
| + self.assertEqual(total, 50)
|
| +
|
| +
|
| +class BadPluginTest(FileTracerTest):
|
| + """Test error handling around plugins."""
|
| +
|
| + def run_plugin(self, module_name):
|
| + """Run a plugin with the given module_name.
|
| +
|
| + Uses a few fixed Python files.
|
| +
|
| + Returns the Coverage object.
|
| +
|
| + """
|
| + self.make_file("simple.py", """\
|
| + import other, another
|
| + a = other.f(2)
|
| + b = other.f(3)
|
| + c = another.g(4)
|
| + d = another.g(5)
|
| + """)
|
| + # The names of these files are important: some plugins apply themselves
|
| + # to "*other.py".
|
| + self.make_file("other.py", """\
|
| + def f(x):
|
| + return x+1
|
| + """)
|
| + self.make_file("another.py", """\
|
| + def g(x):
|
| + return x-1
|
| + """)
|
| +
|
| + cov = coverage.Coverage()
|
| + cov.set_option("run:plugins", [module_name])
|
| + self.start_import_stop(cov, "simple")
|
| + return cov
|
| +
|
| + def run_bad_plugin(self, module_name, plugin_name, our_error=True, excmsg=None):
|
| + """Run a file, and see that the plugin failed.
|
| +
|
| + `module_name` and `plugin_name` is the module and name of the plugin to
|
| + use.
|
| +
|
| + `our_error` is True if the error reported to the user will be an
|
| + explicit error in our test code, marked with an '# Oh noes!' comment.
|
| +
|
| + `excmsg`, if provided, is text that should appear in the stderr.
|
| +
|
| + The plugin will be disabled, and we check that a warning is output
|
| + explaining why.
|
| +
|
| + """
|
| + self.run_plugin(module_name)
|
| +
|
| + stderr = self.stderr()
|
| + print(stderr) # for diagnosing test failures.
|
| +
|
| + if our_error:
|
| + errors = stderr.count("# Oh noes!")
|
| + # The exception we're causing should only appear once.
|
| + self.assertEqual(errors, 1)
|
| +
|
| + # There should be a warning explaining what's happening, but only one.
|
| + # The message can be in two forms:
|
| + # Disabling plugin '...' due to previous exception
|
| + # or:
|
| + # Disabling plugin '...' due to an exception:
|
| + msg = "Disabling plugin '%s.%s' due to " % (module_name, plugin_name)
|
| + warnings = stderr.count(msg)
|
| + self.assertEqual(warnings, 1)
|
| +
|
| + if excmsg:
|
| + self.assertIn(excmsg, stderr)
|
| +
|
| + def test_file_tracer_has_no_file_tracer_method(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + class Plugin(object):
|
| + pass
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
|
| +
|
| + def test_file_tracer_has_inherited_sourcefilename_method(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage
|
| + class Plugin(coverage.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + # Just grab everything.
|
| + return FileTracer()
|
| +
|
| + class FileTracer(coverage.FileTracer):
|
| + pass
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin(
|
| + "bad_plugin", "Plugin", our_error=False,
|
| + excmsg="Class 'bad_plugin.FileTracer' needs to implement source_filename()",
|
| + )
|
| +
|
| + def test_plugin_has_inherited_filereporter_method(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage
|
| + class Plugin(coverage.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + # Just grab everything.
|
| + return FileTracer()
|
| +
|
| + class FileTracer(coverage.FileTracer):
|
| + def source_filename(self):
|
| + return "foo.xxx"
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + cov = self.run_plugin("bad_plugin")
|
| + expected_msg = "Plugin 'bad_plugin.Plugin' needs to implement file_reporter()"
|
| + with self.assertRaisesRegex(NotImplementedError, expected_msg):
|
| + cov.report()
|
| +
|
| + def test_file_tracer_fails(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage.plugin
|
| + class Plugin(coverage.plugin.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + 17/0 # Oh noes!
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin")
|
| +
|
| + def test_file_tracer_returns_wrong(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage.plugin
|
| + class Plugin(coverage.plugin.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + return 3.14159
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
|
| +
|
| + def test_has_dynamic_source_filename_fails(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage.plugin
|
| + class Plugin(coverage.plugin.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + return BadFileTracer()
|
| +
|
| + class BadFileTracer(coverage.plugin.FileTracer):
|
| + def has_dynamic_source_filename(self):
|
| + 23/0 # Oh noes!
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin")
|
| +
|
| + def test_source_filename_fails(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage.plugin
|
| + class Plugin(coverage.plugin.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + return BadFileTracer()
|
| +
|
| + class BadFileTracer(coverage.plugin.FileTracer):
|
| + def source_filename(self):
|
| + 42/0 # Oh noes!
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin")
|
| +
|
| + def test_source_filename_returns_wrong(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage.plugin
|
| + class Plugin(coverage.plugin.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + return BadFileTracer()
|
| +
|
| + class BadFileTracer(coverage.plugin.FileTracer):
|
| + def source_filename(self):
|
| + return 17.3
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
|
| +
|
| + def test_dynamic_source_filename_fails(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage.plugin
|
| + class Plugin(coverage.plugin.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + if filename.endswith("other.py"):
|
| + return BadFileTracer()
|
| +
|
| + class BadFileTracer(coverage.plugin.FileTracer):
|
| + def has_dynamic_source_filename(self):
|
| + return True
|
| + def dynamic_source_filename(self, filename, frame):
|
| + 101/0 # Oh noes!
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin")
|
| +
|
| + def test_line_number_range_returns_non_tuple(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage.plugin
|
| + class Plugin(coverage.plugin.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + if filename.endswith("other.py"):
|
| + return BadFileTracer()
|
| +
|
| + class BadFileTracer(coverage.plugin.FileTracer):
|
| + def source_filename(self):
|
| + return "something.foo"
|
| +
|
| + def line_number_range(self, frame):
|
| + return 42.23
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
|
| +
|
| + def test_line_number_range_returns_triple(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage.plugin
|
| + class Plugin(coverage.plugin.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + if filename.endswith("other.py"):
|
| + return BadFileTracer()
|
| +
|
| + class BadFileTracer(coverage.plugin.FileTracer):
|
| + def source_filename(self):
|
| + return "something.foo"
|
| +
|
| + def line_number_range(self, frame):
|
| + return (1, 2, 3)
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
|
| +
|
| + def test_line_number_range_returns_pair_of_strings(self):
|
| + self.make_file("bad_plugin.py", """\
|
| + import coverage.plugin
|
| + class Plugin(coverage.plugin.CoveragePlugin):
|
| + def file_tracer(self, filename):
|
| + if filename.endswith("other.py"):
|
| + return BadFileTracer()
|
| +
|
| + class BadFileTracer(coverage.plugin.FileTracer):
|
| + def source_filename(self):
|
| + return "something.foo"
|
| +
|
| + def line_number_range(self, frame):
|
| + return ("5", "7")
|
| +
|
| + def coverage_init(reg, options):
|
| + reg.add_file_tracer(Plugin())
|
| + """)
|
| + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False)
|
|
|