diff options
Diffstat (limited to 'tests/test_plugins.py')
-rw-r--r-- | tests/test_plugins.py | 178 |
1 files changed, 149 insertions, 29 deletions
diff --git a/tests/test_plugins.py b/tests/test_plugins.py index 69e7b42b..558c0436 100644 --- a/tests/test_plugins.py +++ b/tests/test_plugins.py @@ -1,3 +1,6 @@ +# 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 @@ -40,6 +43,9 @@ class LoadPluginsTest(CoverageTest): class Plugin(CoveragePlugin): pass + + def coverage_init(reg, options): + reg.add_file_tracer(Plugin()) """) config = FakeConfig("plugin1", {}) @@ -55,8 +61,11 @@ class LoadPluginsTest(CoverageTest): class Plugin(CoveragePlugin): def __init__(self, options): - super(Plugin, self).__init__(options) + self.options = options self.this_is = "me" + + def coverage_init(reg, options): + reg.add_file_tracer(Plugin(options)) """) config = FakeConfig("plugin1", {'a': 'hello'}) @@ -73,14 +82,21 @@ class LoadPluginsTest(CoverageTest): class Plugin(CoveragePlugin): def __init__(self, options): - super(Plugin, self).__init__(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): - pass + def __init__(self, options): + self.options = options + + def coverage_init(reg, options): + reg.add_file_tracer(Plugin(options)) """) config = FakeConfig("plugin1", {'a': 'hello'}) @@ -105,12 +121,12 @@ class LoadPluginsTest(CoverageTest): with self.assertRaises(ImportError): _ = Plugins.load_plugins(["plugin_not_there"], None) - def test_plugin_must_define_plugin_class(self): + 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 Plugin class" + 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)) @@ -124,6 +140,8 @@ class PluginTest(CoverageTest): 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!") """) @@ -163,6 +181,9 @@ class PluginTest(CoverageTest): 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"]) @@ -172,7 +193,7 @@ class PluginTest(CoverageTest): out_lines = debug_out.getvalue().splitlines() expected_end = [ - "-- sys: plugin_sys_info --------------------------------------", + "-- sys: plugin_sys_info.Plugin -------------------------------", " hello: world", "-- end -------------------------------------------------------", ] @@ -184,6 +205,9 @@ class PluginTest(CoverageTest): class Plugin(coverage.CoveragePlugin): pass + + def coverage_init(reg, options): + reg.add_noop(Plugin()) """) debug_out = StringIO() cov = coverage.Coverage(debug=["sys"]) @@ -193,7 +217,7 @@ class PluginTest(CoverageTest): out_lines = debug_out.getvalue().splitlines() expected_end = [ - "-- sys: plugin_no_sys_info -----------------------------------", + "-- sys: plugin_no_sys_info.Plugin ----------------------------", "-- end -------------------------------------------------------", ] self.assertEqual(expected_end, out_lines[-len(expected_end):]) @@ -202,8 +226,10 @@ class PluginTest(CoverageTest): self.make_file("importing_plugin.py", """\ from coverage import CoveragePlugin import local_module - class Plugin(CoveragePlugin): + 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", """\ @@ -220,12 +246,10 @@ class PluginTest(CoverageTest): class PluginWarningOnPyTracer(CoverageTest): """Test that we get a controlled exception with plugins on PyTracer.""" - def setUp(self): - super(PluginWarningOnPyTracer, self).setUp() + def test_exception_if_plugins_on_pytracer(self): if env.C_TRACER: self.skip("This test is only about PyTracer.") - def test_exception_if_plugins_on_pytracer(self): self.make_file("simple.py", """a = 1""") cov = coverage.Coverage() @@ -233,13 +257,13 @@ class PluginWarningOnPyTracer(CoverageTest): 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) " - "aren't supported with PyTracer", + "Plugin file tracers (tests.plugin1.Plugin) aren't supported with PyTracer", warnings ) @@ -283,6 +307,7 @@ class GoodPluginTest(FileTracerTest): 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. @@ -344,20 +369,20 @@ class GoodPluginTest(FileTracerTest): _, 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.summary()) + 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.summary()) + self.assertIn("bar_4.html", cov.data.line_counts()) - self.assertNotIn("quux_5.html", cov.data.summary()) + 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.summary()) + self.assertIn("uni_3.html", cov.data.line_counts()) def test_plugin2_with_branch(self): self.make_render_and_caller() @@ -437,11 +462,62 @@ class GoodPluginTest(FileTracerTest): ]: 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.config["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_bad_plugin(self, plugin_name, our_error=True): + def run_bad_plugin(self, module_name, plugin_name, our_error=True): """Run a file, and see that the plugin failed. `plugin_name` is the name of the plugin to use. @@ -449,6 +525,9 @@ class BadPluginTest(FileTracerTest): `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. + The plugin will be disabled, and we check that a warning is output + explaining why. + """ self.make_file("simple.py", """\ import other, another @@ -469,7 +548,7 @@ class BadPluginTest(FileTracerTest): """) cov = coverage.Coverage() - cov.config["run:plugins"] = [plugin_name] + cov.config["run:plugins"] = [module_name] self.start_import_stop(cov, "simple") stderr = self.stderr() @@ -481,18 +560,35 @@ class BadPluginTest(FileTracerTest): self.assertEqual(errors, 1) # There should be a warning explaining what's happening, but only one. - msg = "Disabling plugin %r due to an exception:" % plugin_name + # 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) + 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_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") + self.run_bad_plugin("bad_plugin", "Plugin") def test_file_tracer_returns_wrong(self): self.make_file("bad_plugin.py", """\ @@ -500,8 +596,11 @@ class BadPluginTest(FileTracerTest): 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", our_error=False) + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False) def test_has_dynamic_source_filename_fails(self): self.make_file("bad_plugin.py", """\ @@ -513,8 +612,11 @@ class BadPluginTest(FileTracerTest): 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") + self.run_bad_plugin("bad_plugin", "Plugin") def test_source_filename_fails(self): self.make_file("bad_plugin.py", """\ @@ -526,8 +628,11 @@ class BadPluginTest(FileTracerTest): 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") + self.run_bad_plugin("bad_plugin", "Plugin") def test_source_filename_returns_wrong(self): self.make_file("bad_plugin.py", """\ @@ -539,8 +644,11 @@ class BadPluginTest(FileTracerTest): 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", our_error=False) + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False) def test_dynamic_source_filename_fails(self): self.make_file("bad_plugin.py", """\ @@ -555,8 +663,11 @@ class BadPluginTest(FileTracerTest): 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") + self.run_bad_plugin("bad_plugin", "Plugin") def test_line_number_range_returns_non_tuple(self): self.make_file("bad_plugin.py", """\ @@ -572,8 +683,11 @@ class BadPluginTest(FileTracerTest): 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", our_error=False) + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False) def test_line_number_range_returns_triple(self): self.make_file("bad_plugin.py", """\ @@ -589,8 +703,11 @@ class BadPluginTest(FileTracerTest): 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", our_error=False) + 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", """\ @@ -606,5 +723,8 @@ class BadPluginTest(FileTracerTest): 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", our_error=False) + self.run_bad_plugin("bad_plugin", "Plugin", our_error=False) |