summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/backunittest.py41
-rw-r--r--tests/coveragetest.py256
-rw-r--r--tests/modules/plugins/__init__.py0
-rw-r--r--tests/modules/plugins/a_plugin.py6
-rw-r--r--tests/modules/plugins/another.py6
-rw-r--r--tests/test_backward.py4
-rw-r--r--tests/test_config.py24
-rw-r--r--tests/test_coroutine.py48
-rw-r--r--tests/test_plugins.py217
-rw-r--r--tests/test_testing.py32
10 files changed, 315 insertions, 319 deletions
diff --git a/tests/backunittest.py b/tests/backunittest.py
deleted file mode 100644
index 6498397f..00000000
--- a/tests/backunittest.py
+++ /dev/null
@@ -1,41 +0,0 @@
-"""Implementations of unittest features from the future."""
-
-# Use unittest2 if it's available, otherwise unittest. This gives us
-# backported features for 2.6.
-try:
- import unittest2 as unittest # pylint: disable=F0401
-except ImportError:
- import unittest
-
-
-def unittest_has(method):
- """Does `unitttest.TestCase` have `method` defined?"""
- return hasattr(unittest.TestCase, method)
-
-
-class TestCase(unittest.TestCase):
- """Just like unittest.TestCase, but with assert methods added.
-
- Designed to be compatible with 3.1 unittest. Methods are only defined if
- `unittest` doesn't have them.
-
- """
- # pylint: disable=missing-docstring
-
- if not unittest_has('assertCountEqual'):
- if unittest_has('assertSameElements'):
- def assertCountEqual(self, *args, **kwargs):
- # pylint: disable=no-member
- return self.assertSameElements(*args, **kwargs)
- else:
- def assertCountEqual(self, s1, s2):
- """Assert these have the same elements, regardless of order."""
- self.assertEqual(set(s1), set(s2))
-
- if not unittest_has('assertRaisesRegex'):
- def assertRaisesRegex(self, *args, **kwargs):
- return self.assertRaisesRegexp(*args, **kwargs)
-
- if not unittest_has('assertRegex'):
- def assertRegex(self, *args, **kwargs):
- return self.assertRegexpMatches(*args, **kwargs)
diff --git a/tests/coveragetest.py b/tests/coveragetest.py
index 1eedad39..4053059f 100644
--- a/tests/coveragetest.py
+++ b/tests/coveragetest.py
@@ -1,48 +1,39 @@
"""Base test case class for coverage testing."""
-import glob, os, random, re, shlex, shutil, sys, tempfile, textwrap
-import atexit, collections
+import glob, os, random, re, shlex, shutil, sys
import coverage
-from coverage.backward import StringIO, to_bytes, import_local_file
+from coverage.backunittest import TestCase
+from coverage.backward import StringIO, import_local_file
from coverage.backward import importlib # pylint: disable=unused-import
from coverage.control import _TEST_NAME_FILE
-from tests.backtest import run_command
-from tests.backunittest import TestCase
-
-class Tee(object):
- """A file-like that writes to all the file-likes it has."""
-
- def __init__(self, *files):
- """Make a Tee that writes to all the files in `files.`"""
- self._files = files
- if hasattr(files[0], "encoding"):
- self.encoding = files[0].encoding
-
- def write(self, data):
- """Write `data` to all the files."""
- for f in self._files:
- f.write(data)
+from coverage.test_helpers import (
+ ModuleAwareMixin, SysPathAwareMixin, EnvironmentAwareMixin,
+ StdStreamCapturingMixin, TempDirMixin,
+)
- if 0:
- # Use this if you need to use a debugger, though it makes some tests
- # fail, I'm not sure why...
- def __getattr__(self, name):
- return getattr(self._files[0], name)
+from tests.backtest import run_command
# Status returns for the command line.
OK, ERR = 0, 1
-class CoverageTest(TestCase):
+class CoverageTest(
+ ModuleAwareMixin,
+ SysPathAwareMixin,
+ EnvironmentAwareMixin,
+ StdStreamCapturingMixin,
+ TempDirMixin,
+ TestCase
+):
"""A base class for Coverage test cases."""
- # Our own setting: most CoverageTests run in their own temp directory.
- run_in_temp_dir = True
-
# Standard unittest setting: show me diffs even if they are very long.
maxDiff = None
+ # Tell newer unittest implementations to print long helpful messages.
+ longMessage = True
+
def setUp(self):
super(CoverageTest, self).setUp()
@@ -51,153 +42,6 @@ class CoverageTest(TestCase):
f.write("%s_%s" % (self.__class__.__name__, self._testMethodName))
f.close()
- # Tell newer unittest implementations to print long helpful messages.
- self.longMessage = True
-
- # tearDown will restore the original sys.path
- self.old_syspath = sys.path[:]
-
- if self.run_in_temp_dir:
- # Create a temporary directory.
- self.noise = str(random.random())[2:]
- self.temp_root = os.path.join(tempfile.gettempdir(), 'test_cover')
- self.temp_dir = os.path.join(self.temp_root, self.noise)
- os.makedirs(self.temp_dir)
- self.old_dir = os.getcwd()
- os.chdir(self.temp_dir)
-
- # Modules should be importable from this temp directory. We don't
- # use '' because we make lots of different temp directories and
- # nose's caching importer can get confused. The full path prevents
- # problems.
- sys.path.insert(0, os.getcwd())
-
- # Keep a counter to make every call to check_coverage unique.
- self.n = 0
-
- # Record environment variables that we changed with set_environ.
- self.environ_undos = {}
-
- # Capture stdout and stderr so we can examine them in tests.
- # nose keeps stdout from littering the screen, so we can safely Tee it,
- # but it doesn't capture stderr, so we don't want to Tee stderr to the
- # real stderr, since it will interfere with our nice field of dots.
- self.old_stdout = sys.stdout
- self.captured_stdout = StringIO()
- sys.stdout = Tee(sys.stdout, self.captured_stdout)
- self.old_stderr = sys.stderr
- self.captured_stderr = StringIO()
- sys.stderr = self.captured_stderr
-
- # Record sys.modules here so we can restore it in tearDown.
- self.old_modules = dict(sys.modules)
-
- class_behavior = self.class_behavior()
- class_behavior.tests += 1
- class_behavior.test_method_made_any_files = False
- class_behavior.temp_dir = self.run_in_temp_dir
-
- def tearDown(self):
- super(CoverageTest, self).tearDown()
-
- # Restore the original sys.path.
- sys.path = self.old_syspath
-
- if self.run_in_temp_dir:
- # Get rid of the temporary directory.
- os.chdir(self.old_dir)
- shutil.rmtree(self.temp_root)
-
- # Restore the environment.
- self.undo_environ()
-
- # Restore stdout and stderr
- sys.stdout = self.old_stdout
- sys.stderr = self.old_stderr
-
- self.clean_modules()
-
- class_behavior = self.class_behavior()
- if class_behavior.test_method_made_any_files:
- class_behavior.tests_making_files += 1
-
- def clean_modules(self):
- """Remove any new modules imported during the test run.
-
- This lets us import the same source files for more than one test.
-
- """
- for m in [m for m in sys.modules if m not in self.old_modules]:
- del sys.modules[m]
-
- def set_environ(self, name, value):
- """Set an environment variable `name` to be `value`.
-
- The environment variable is set, and record is kept that it was set,
- so that `tearDown` can restore its original value.
-
- """
- if name not in self.environ_undos:
- self.environ_undos[name] = os.environ.get(name)
- os.environ[name] = value
-
- def original_environ(self, name, if_missing=None):
- """The environment variable `name` from when the test started."""
- if name in self.environ_undos:
- ret = self.environ_undos[name]
- else:
- ret = os.environ.get(name)
- if ret is None:
- ret = if_missing
- return ret
-
- def undo_environ(self):
- """Undo all the changes made by `set_environ`."""
- for name, value in self.environ_undos.items():
- if value is None:
- del os.environ[name]
- else:
- os.environ[name] = value
-
- def stdout(self):
- """Return the data written to stdout during the test."""
- return self.captured_stdout.getvalue()
-
- def stderr(self):
- """Return the data written to stderr during the test."""
- return self.captured_stderr.getvalue()
-
- def make_file(self, filename, text="", newline=None):
- """Create a file for testing.
-
- `filename` is the relative path to the file, including directories if
- desired, which will be created if need be. `text` is the content to
- create in the file. If `newline` is provided, it is a string that will
- be used as the line endings in the created file, otherwise the line
- endings are as provided in `text`.
-
- Returns `filename`.
-
- """
- # Tests that call `make_file` should be run in a temp environment.
- assert self.run_in_temp_dir
- self.class_behavior().test_method_made_any_files = True
-
- text = textwrap.dedent(text)
- if newline:
- text = text.replace("\n", newline)
-
- # Make sure the directories are available.
- dirs, _ = os.path.split(filename)
- if dirs and not os.path.exists(dirs):
- os.makedirs(dirs)
-
- # Create the file.
- with open(filename, 'wb') as f:
- f.write(to_bytes(text))
-
- return filename
-
def clean_local_file_imports(self):
"""Clean up the results of calls to `import_local_file`.
@@ -206,7 +50,7 @@ class CoverageTest(TestCase):
"""
# So that we can re-import files, clean them out first.
- self.clean_modules()
+ self.cleanup_modules()
# Also have to clean out the .pyc file, since the timestamp
# resolution is only one second, a changed file might not be
# picked up.
@@ -244,13 +88,7 @@ class CoverageTest(TestCase):
def get_module_name(self):
"""Return the module name to use for this test run."""
- # We append self.n because otherwise two calls in one test will use the
- # same filename and whether the test works or not depends on the
- # timestamps in the .pyc file, so it becomes random whether the second
- # call will use the compiled version of the first call's code or not!
- modname = 'coverage_test_' + self.noise + str(self.n)
- self.n += 1
- return modname
+ return 'coverage_test_' + str(random.random())[2:]
# Map chars to numbers for arcz_to_arcs
_arcz_map = {'.': -1}
@@ -507,55 +345,3 @@ class CoverageTest(TestCase):
def last_line_squeezed(self, report):
"""Return the last line of `report` with the spaces squeezed down."""
return self.squeezed_lines(report)[-1]
-
- # We run some tests in temporary directories, because they may need to make
- # files for the tests. But this is expensive, so we can change per-class
- # whether a temp dir is used or not. It's easy to forget to set that
- # option properly, so we track information about what the tests did, and
- # then report at the end of the process on test classes that were set
- # wrong.
-
- class ClassBehavior(object):
- """A value object to store per-class in CoverageTest."""
- def __init__(self):
- self.tests = 0
- self.temp_dir = True
- self.tests_making_files = 0
- self.test_method_made_any_files = False
-
- # Map from class to info about how it ran.
- class_behaviors = collections.defaultdict(ClassBehavior)
-
- @classmethod
- def report_on_class_behavior(cls):
- """Called at process exit to report on class behavior."""
- for test_class, behavior in cls.class_behaviors.items():
- if behavior.temp_dir and behavior.tests_making_files == 0:
- bad = "Inefficient"
- elif not behavior.temp_dir and behavior.tests_making_files > 0:
- bad = "Unsafe"
- else:
- bad = ""
-
- if bad:
- if behavior.temp_dir:
- where = "in a temp directory"
- else:
- where = "without a temp directory"
- print(
- "%s: %s ran %d tests, %d made files %s" % (
- bad,
- test_class.__name__,
- behavior.tests,
- behavior.tests_making_files,
- where,
- )
- )
-
- def class_behavior(self):
- """Get the ClassBehavior instance for this test."""
- return self.class_behaviors[self.__class__]
-
-
-# When the process ends, find out about bad classes.
-atexit.register(CoverageTest.report_on_class_behavior)
diff --git a/tests/modules/plugins/__init__.py b/tests/modules/plugins/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/modules/plugins/__init__.py
diff --git a/tests/modules/plugins/a_plugin.py b/tests/modules/plugins/a_plugin.py
new file mode 100644
index 00000000..2ff84dac
--- /dev/null
+++ b/tests/modules/plugins/a_plugin.py
@@ -0,0 +1,6 @@
+"""A plugin for tests to reference."""
+
+from coverage import CoveragePlugin
+
+class Plugin(CoveragePlugin):
+ pass
diff --git a/tests/modules/plugins/another.py b/tests/modules/plugins/another.py
new file mode 100644
index 00000000..2ff84dac
--- /dev/null
+++ b/tests/modules/plugins/another.py
@@ -0,0 +1,6 @@
+"""A plugin for tests to reference."""
+
+from coverage import CoveragePlugin
+
+class Plugin(CoveragePlugin):
+ pass
diff --git a/tests/test_backward.py b/tests/test_backward.py
index 2c688edd..09803ba7 100644
--- a/tests/test_backward.py
+++ b/tests/test_backward.py
@@ -1,14 +1,12 @@
"""Tests that our version shims in backward.py are working."""
+from coverage.backunittest import TestCase
from coverage.backward import iitems, binary_bytes, byte_to_int, bytes_to_ints
-from tests.backunittest import TestCase
class BackwardTest(TestCase):
"""Tests of things from backward.py."""
- run_in_temp_dir = False
-
def test_iitems(self):
d = {'a': 1, 'b': 2, 'c': 3}
items = [('a', 1), ('b', 2), ('c', 3)]
diff --git a/tests/test_config.py b/tests/test_config.py
index 7409f4aa..bf84423d 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
"""Test the config file handling for coverage.py"""
+import sys, os
+
import coverage
from coverage.misc import CoverageException
@@ -125,6 +127,12 @@ class ConfigTest(CoverageTest):
class ConfigFileTest(CoverageTest):
"""Tests of the config file settings in particular."""
+ def setUp(self):
+ super(ConfigFileTest, self).setUp()
+ # Parent class saves and restores sys.path, we can just modify it.
+ # Add modules to the path so we can import plugins.
+ sys.path.append(self.nice_file(os.path.dirname(__file__), 'modules'))
+
# This sample file tries to use lots of variation of syntax...
# The {section} placeholder lets us nest these settings in another file.
LOTSA_SETTINGS = """\
@@ -136,6 +144,9 @@ class ConfigFileTest(CoverageTest):
cover_pylib = TRUE
parallel = on
include = a/ , b/
+ plugins =
+ plugins.a_plugin
+ plugins.another
[{section}report]
; these settings affect reporting.
@@ -174,6 +185,10 @@ class ConfigFileTest(CoverageTest):
other = other, /home/ned/other, c:\\Ned\\etc
+ [{section}plugins.a_plugin]
+ hello = world
+ ; comments still work.
+ names = Jane/John/Jenny
"""
# Just some sample setup.cfg text from the docs.
@@ -212,6 +227,9 @@ class ConfigFileTest(CoverageTest):
self.assertEqual(cov.config.partial_always_list,
["if 0:", "while True:"]
)
+ self.assertEqual(cov.config.plugins,
+ ["plugins.a_plugin", "plugins.another"]
+ )
self.assertTrue(cov.config.show_missing)
self.assertEqual(cov.config.html_dir, r"c:\tricky\dir.somewhere")
self.assertEqual(cov.config.extra_css, "something/extra.css")
@@ -224,6 +242,12 @@ class ConfigFileTest(CoverageTest):
'other': ['other', '/home/ned/other', 'c:\\Ned\\etc']
})
+ self.assertEqual(cov.config.get_plugin_options("plugins.a_plugin"), {
+ 'hello': 'world',
+ 'names': 'Jane/John/Jenny',
+ })
+ self.assertEqual(cov.config.get_plugin_options("plugins.another"), {})
+
def test_config_file_settings(self):
self.make_file(".coveragerc", self.LOTSA_SETTINGS.format(section=""))
cov = coverage.coverage()
diff --git a/tests/test_coroutine.py b/tests/test_coroutine.py
index 38de7a3d..9ad1f31f 100644
--- a/tests/test_coroutine.py
+++ b/tests/test_coroutine.py
@@ -2,7 +2,6 @@
import os.path, sys
-from nose.plugins.skip import SkipTest
import coverage
from tests.coveragetest import CoverageTest
@@ -32,7 +31,7 @@ def line_count(s):
class CoroutineTest(CoverageTest):
"""Tests of the coroutine support in coverage.py."""
- LIMIT = 3 # Should be 1000, but this gives me a reasonable amount of output.
+ LIMIT = 1000
# The code common to all the concurrency models.
COMMON = """
@@ -96,6 +95,15 @@ class CoroutineTest(CoverageTest):
import gevent.queue as queue
""" + COMMON
+ # Uncomplicated code that doesn't use any of the coroutining stuff, to test
+ # the simple case under each of the regimes.
+ SIMPLE = """\
+ total = 0
+ for i in range({LIMIT}):
+ total += i
+ print(total)
+ """.format(LIMIT=LIMIT)
+
def try_some_code(self, code, args):
"""Run some coroutine testing code and see that it was all covered."""
@@ -122,35 +130,25 @@ class CoroutineTest(CoverageTest):
def test_threads(self):
self.try_some_code(self.THREAD, "")
- def test_eventlet(self):
- if eventlet is None:
- raise SkipTest("No eventlet available")
-
- self.try_some_code(self.EVENTLET, "--coroutine=eventlet")
-
- def test_gevent(self):
- #raise SkipTest("Still not sure why gevent isn't working...")
+ def test_threads_simple_code(self):
+ self.try_some_code(self.SIMPLE, "")
- if gevent is None:
- raise SkipTest("No gevent available")
+ if eventlet is not None:
+ def test_eventlet(self):
+ self.try_some_code(self.EVENTLET, "--coroutine=eventlet")
- self.try_some_code(self.GEVENT, "--coroutine=gevent")
+ def test_eventlet_simple_code(self):
+ self.try_some_code(self.SIMPLE, "--coroutine=eventlet")
- def test_gevent_badly(self):
- # This test shouldn't pass. It should fail because we are running
- # gevent code without the --coroutine=gevent flag. It's here so I can
- # see how gevent code looks when it isn't measured properly. The C
- # extension implementation of coroutining is currently acting precisely
- # as if no coroutine support is available (demonstrated by this test),
- # and I don't know why. This test is part of me debugging that
- # problem.
- if gevent is None:
- raise SkipTest("No gevent available")
+ if gevent is not None:
+ def test_gevent(self):
+ self.try_some_code(self.GEVENT, "--coroutine=gevent")
- self.try_some_code(self.GEVENT, "")
+ def test_gevent_simple_code(self):
+ self.try_some_code(self.SIMPLE, "--coroutine=gevent")
def print_simple_annotation(code, linenos):
"""Print the lines in `code` with X for each line number in `linenos`."""
for lineno, line in enumerate(code.splitlines(), start=1):
- print(" {0:s} {1}".format("X" if lineno in linenos else " ", line))
+ print(" {0} {1}".format("X" if lineno in linenos else " ", line))
diff --git a/tests/test_plugins.py b/tests/test_plugins.py
new file mode 100644
index 00000000..d60ce77b
--- /dev/null
+++ b/tests/test_plugins.py
@@ -0,0 +1,217 @@
+"""Tests for plugins."""
+
+import os.path
+
+import coverage
+from coverage.codeunit import CodeUnit
+from coverage.parser import CodeParser
+from coverage.plugin import Plugins, overrides
+
+from tests.coveragetest import CoverageTest
+
+
+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 PluginUnitTest(CoverageTest):
+ """Test Plugins.load_plugins directly."""
+
+ def test_importing_and_configuring(self):
+ self.make_file("plugin1.py", """\
+ from coverage import CoveragePlugin
+
+ class Plugin(CoveragePlugin):
+ def __init__(self, options):
+ super(Plugin, self).__init__(options)
+ self.this_is = "me"
+ """)
+
+ 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):
+ super(Plugin, self).__init__(options)
+ self.this_is = "me"
+ """)
+ self.make_file("plugin2.py", """\
+ from coverage import CoveragePlugin
+
+ class Plugin(CoveragePlugin):
+ pass
+ """)
+
+ 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'])
+
+ def test_cant_import(self):
+ with self.assertRaises(ImportError):
+ _ = Plugins.load_plugins(["plugin_not_there"], None)
+
+ def test_ok_to_not_define_plugin(self):
+ self.make_file("plugin2.py", """\
+ from coverage import CoveragePlugin
+
+ Nothing = 0
+ """)
+ plugins = list(Plugins.load_plugins(["plugin2"], None))
+ self.assertEqual(plugins, [])
+
+
+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", """\
+ with open("evidence.out", "w") as f:
+ f.write("we are here!")
+ """)
+
+ self.assert_doesnt_exist("evidence.out")
+ _ = coverage.Coverage(plugins=["my_plugin"])
+
+ 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(plugins=["foo"])
+ cov.start()
+
+ 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):
+ _ = coverage.Coverage(plugins=["plugin_over_zero"])
+
+ def test_importing_myself(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(plugins=["tests.test_plugins"])
+
+ # 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, [])
+ _, statements, _, _ = cov.analysis("/src/try_ABC.zz")
+ self.assertEqual(statements, [105, 106, 107, 205, 206, 207])
+
+
+class Plugin(coverage.CoveragePlugin):
+ def trace_judge(self, disp):
+ if "xyz.py" in disp.original_filename:
+ disp.trace = True
+ disp.source_filename = os.path.join(
+ "/src",
+ os.path.basename(
+ disp.original_filename.replace("xyz.py", "ABC.zz")
+ )
+ )
+
+ def line_number_range(self, frame):
+ lineno = frame.f_lineno
+ return lineno*100+5, lineno*100+7
+
+ def code_unit_class(self, filename):
+ return PluginCodeUnit
+
+class PluginCodeUnit(CodeUnit):
+ def get_parser(self, exclude=None):
+ return PluginParser()
+
+class PluginParser(CodeParser):
+ def parse_source(self):
+ return set([105, 106, 107, 205, 206, 207]), set([])
+
+
+class OverridesTest(CoverageTest):
+ """Test plugins.py:overrides."""
+
+ run_in_temp_dir = False
+
+ def test_overrides(self):
+ class SomeBase(object):
+ """Base class, two base methods."""
+ def method1(self):
+ pass
+
+ def method2(self):
+ pass
+
+ class Derived1(SomeBase):
+ """Simple single inheritance."""
+ def method1(self):
+ pass
+
+ self.assertTrue(overrides(Derived1(), "method1", SomeBase))
+ self.assertFalse(overrides(Derived1(), "method2", SomeBase))
+
+ class FurtherDerived1(Derived1):
+ """Derive again from Derived1, inherit its method1."""
+ pass
+
+ self.assertTrue(overrides(FurtherDerived1(), "method1", SomeBase))
+ self.assertFalse(overrides(FurtherDerived1(), "method2", SomeBase))
+
+ class FurtherDerived2(Derived1):
+ """Override the overridden method."""
+ def method1(self):
+ pass
+
+ self.assertTrue(overrides(FurtherDerived2(), "method1", SomeBase))
+ self.assertFalse(overrides(FurtherDerived2(), "method2", SomeBase))
+
+ class Mixin(object):
+ """A mixin that overrides method1."""
+ def method1(self):
+ pass
+
+ class Derived2(Mixin, SomeBase):
+ """A class that gets the method from the mixin."""
+ pass
+
+ self.assertTrue(overrides(Derived2(), "method1", SomeBase))
+ self.assertFalse(overrides(Derived2(), "method2", SomeBase))
diff --git a/tests/test_testing.py b/tests/test_testing.py
index 049a1982..4a19098f 100644
--- a/tests/test_testing.py
+++ b/tests/test_testing.py
@@ -2,16 +2,14 @@
"""Tests that our test infrastructure is really working!"""
import os, sys
+from coverage.backunittest import TestCase
from coverage.backward import to_bytes
-from tests.backunittest import TestCase
-from tests.coveragetest import CoverageTest
+from tests.coveragetest import TempDirMixin, CoverageTest
class TestingTest(TestCase):
"""Tests of helper methods on `backunittest.TestCase`."""
- run_in_temp_dir = False
-
def test_assert_count_equal(self):
self.assertCountEqual(set(), set())
self.assertCountEqual(set([1,2,3]), set([3,1,2]))
@@ -21,26 +19,27 @@ class TestingTest(TestCase):
self.assertCountEqual(set([1,2,3]), set([4,5,6]))
-class CoverageTestTest(CoverageTest):
- """Test the methods in `CoverageTest`."""
+class TempDirMixinTest(TempDirMixin, TestCase):
+ """Test the methods in TempDirMixin."""
def file_text(self, fname):
"""Return the text read from a file."""
- return open(fname, "rb").read().decode('ascii')
+ with open(fname, "rb") as f:
+ return f.read().decode('ascii')
def test_make_file(self):
# A simple file.
self.make_file("fooey.boo", "Hello there")
- self.assertEqual(open("fooey.boo").read(), "Hello there")
+ self.assertEqual(self.file_text("fooey.boo"), "Hello there")
# A file in a sub-directory
self.make_file("sub/another.txt", "Another")
- self.assertEqual(open("sub/another.txt").read(), "Another")
+ self.assertEqual(self.file_text("sub/another.txt"), "Another")
# A second file in that sub-directory
self.make_file("sub/second.txt", "Second")
- self.assertEqual(open("sub/second.txt").read(), "Second")
+ self.assertEqual(self.file_text("sub/second.txt"), "Second")
# A deeper directory
self.make_file("sub/deeper/evenmore/third.txt")
- self.assertEqual(open("sub/deeper/evenmore/third.txt").read(), "")
+ self.assertEqual(self.file_text("sub/deeper/evenmore/third.txt"), "")
def test_make_file_newline(self):
self.make_file("unix.txt", "Hello\n")
@@ -52,10 +51,13 @@ class CoverageTestTest(CoverageTest):
def test_make_file_non_ascii(self):
self.make_file("unicode.txt", "tabblo: «ταБЬℓσ»")
- self.assertEqual(
- open("unicode.txt", "rb").read(),
- to_bytes("tabblo: «ταБЬℓσ»")
- )
+ with open("unicode.txt", "rb") as f:
+ text = f.read()
+ self.assertEqual(text, to_bytes("tabblo: «ταБЬℓσ»"))
+
+
+class CoverageTestTest(CoverageTest):
+ """Test the methods in `CoverageTest`."""
def test_file_exists(self):
self.make_file("whoville.txt", "We are here!")