summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2014-09-15 21:35:07 -0400
committerNed Batchelder <ned@nedbatchelder.com>2014-09-15 21:35:07 -0400
commitf5da86062ed852cbe6bcf57cc23b1228f15de922 (patch)
tree3fa354093088521c2e072e4db5f1f87df966e6e9
parentf0b43b13fa9e1775e8b69ff894372db883965645 (diff)
downloadpython-coveragepy-git-f5da86062ed852cbe6bcf57cc23b1228f15de922.tar.gz
Move test helpers into the coverage package so others can use them
--HG-- rename : tests/backunittest.py => coverage/backunittest.py
-rw-r--r--coverage/backunittest.py (renamed from tests/backunittest.py)0
-rw-r--r--tests/coveragetest.py266
-rw-r--r--tests/test_backward.py4
-rw-r--r--tests/test_testing.py4
4 files changed, 10 insertions, 264 deletions
diff --git a/tests/backunittest.py b/coverage/backunittest.py
index 6498397f..6498397f 100644
--- a/tests/backunittest.py
+++ b/coverage/backunittest.py
diff --git a/tests/coveragetest.py b/tests/coveragetest.py
index a6632404..4053059f 100644
--- a/tests/coveragetest.py
+++ b/tests/coveragetest.py
@@ -1,273 +1,23 @@
"""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 ModuleAwareMixin(TestCase):
- """A test case mixin that isolates changes to sys.modules."""
-
- def setUp(self):
- super(ModuleAwareMixin, self).setUp()
-
- # Record sys.modules here so we can restore it in tearDown.
- self.old_modules = dict(sys.modules)
- self.addCleanup(self.cleanup_modules)
-
- def cleanup_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]
-
-
-class SysPathAwareMixin(TestCase):
- """A test case mixin that isolates changes to sys.path."""
-
- def setUp(self):
- super(SysPathAwareMixin, self).setUp()
-
- self.old_syspath = sys.path[:]
- self.addCleanup(self.cleanup_syspath)
-
- def cleanup_syspath(self):
- """Restore the original sys.path."""
- sys.path = self.old_syspath
-
-
-class EnvironmentAwareMixin(TestCase):
- """A test case mixin that isolates changes to the environment."""
-
- def setUp(self):
- super(EnvironmentAwareMixin, self).setUp()
-
- # Record environment variables that we changed with set_environ.
- self.environ_undos = {}
-
- self.addCleanup(self.cleanup_environ)
-
- 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 cleanup_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
-
-
-class StdStreamCapturingMixin(TestCase):
- """A test case mixin that captures stdout and stderr."""
-
- def setUp(self):
- super(StdStreamCapturingMixin, self).setUp()
-
- # 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
-
- self.addCleanup(self.cleanup_std_streams)
-
- def cleanup_std_streams(self):
- """Restore stdout and stderr."""
- sys.stdout = self.old_stdout
- sys.stderr = self.old_stderr
-
- 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()
-
-
-class TempDirMixin(TestCase):
- """A test case mixin that creates a temp directory and files in it."""
-
- # Our own setting: most of these tests run in their own temp directory.
- run_in_temp_dir = True
-
- def setUp(self):
- super(TempDirMixin, self).setUp()
-
- if self.run_in_temp_dir:
- # Create a temporary directory.
- noise = str(random.random())[2:]
- self.temp_root = os.path.join(tempfile.gettempdir(), 'test_cover')
- self.temp_dir = os.path.join(self.temp_root, 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())
-
- 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
-
- self.addCleanup(self.cleanup_temp_dir)
-
- def cleanup_temp_dir(self):
- """Clean up the temp directories we made."""
-
- if self.run_in_temp_dir:
- # Get rid of the temporary directory.
- os.chdir(self.old_dir)
- shutil.rmtree(self.temp_root)
-
- class_behavior = self.class_behavior()
- if class_behavior.test_method_made_any_files:
- class_behavior.tests_making_files += 1
-
- 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
-
- # 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."""
- 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(TempDirMixin.report_on_class_behavior)
-
-
class CoverageTest(
ModuleAwareMixin,
SysPathAwareMixin,
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_testing.py b/tests/test_testing.py
index ddda4b00..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 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]))