summaryrefslogtreecommitdiff
path: root/tests/goldtest.py
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2018-11-18 11:18:39 -0500
committerNed Batchelder <ned@nedbatchelder.com>2018-11-18 12:23:05 -0500
commit2fb113e60c2733e640f92d737278431a1f670052 (patch)
tree3b197a57ddd85846b3791f55facb58373a144721 /tests/goldtest.py
parent701f4ed56639325dcb9fa0aecf06df303ee6a761 (diff)
downloadpython-coveragepy-git-2fb113e60c2733e640f92d737278431a1f670052.tar.gz
Remove test_farm.py
Diffstat (limited to 'tests/goldtest.py')
-rw-r--r--tests/goldtest.py158
1 files changed, 154 insertions, 4 deletions
diff --git a/tests/goldtest.py b/tests/goldtest.py
index 48842f0c..975db615 100644
--- a/tests/goldtest.py
+++ b/tests/goldtest.py
@@ -3,16 +3,166 @@
"""A test base class for tests based on gold file comparison."""
+import difflib
+import filecmp
+import fnmatch
import os
+import os.path
+import re
+import sys
from unittest_mixins import change_dir # pylint: disable=unused-import
+from coverage import env
+
from tests.coveragetest import TESTS_DIR
-# Import helpers, eventually test_farm.py will go away.
-from tests.test_farm import ( # pylint: disable=unused-import
- compare, contains, doesnt_contain, contains_any,
-)
+
def gold_path(path):
"""Get a path to a gold file for comparison."""
return os.path.join(TESTS_DIR, "farm", path)
+
+
+# "rU" was deprecated in 3.4
+READ_MODE = "rU" if env.PYVERSION < (3, 4) else "r"
+
+
+def versioned_directory(d):
+ """Find a subdirectory of d specific to the Python version.
+ For example, on Python 3.6.4 rc 1, it returns the first of these
+ directories that exists::
+ d/3.6.4.candidate.1
+ d/3.6.4.candidate
+ d/3.6.4
+ d/3.6
+ d/3
+ d
+ Returns: a string, the path to an existing directory.
+ """
+ ver_parts = list(map(str, sys.version_info))
+ for nparts in range(len(ver_parts), -1, -1):
+ version = ".".join(ver_parts[:nparts])
+ subdir = os.path.join(d, version)
+ if os.path.exists(subdir):
+ return subdir
+ raise Exception("Directory missing: {}".format(d)) # pragma: only failure
+
+
+def compare(
+ expected_dir, actual_dir, file_pattern=None,
+ actual_extra=False, scrubs=None,
+ ):
+ """Compare files matching `file_pattern` in `expected_dir` and `actual_dir`.
+
+ A version-specific subdirectory of `expected_dir` will be used if
+ it exists.
+
+ `actual_extra` true means `actual_dir` can have extra files in it
+ without triggering an assertion.
+
+ `scrubs` is a list of pairs: regexes to find and replace to scrub the
+ files of unimportant differences.
+
+ An assertion will be raised if the directories fail one of their
+ matches.
+
+ """
+ expected_dir = versioned_directory(expected_dir)
+
+ dc = filecmp.dircmp(expected_dir, actual_dir)
+ diff_files = fnmatch_list(dc.diff_files, file_pattern)
+ expected_only = fnmatch_list(dc.left_only, file_pattern)
+ actual_only = fnmatch_list(dc.right_only, file_pattern)
+
+ # filecmp only compares in binary mode, but we want text mode. So
+ # look through the list of different files, and compare them
+ # ourselves.
+ text_diff = []
+ for f in diff_files:
+ expected_file = os.path.join(expected_dir, f)
+ actual_file = os.path.join(actual_dir, f)
+ with open(expected_file, READ_MODE) as fobj:
+ expected = fobj.read()
+ with open(actual_file, READ_MODE) as fobj:
+ actual = fobj.read()
+ if scrubs:
+ expected = scrub(expected, scrubs)
+ actual = scrub(actual, scrubs)
+ if expected != actual: # pragma: only failure
+ text_diff.append('%s != %s' % (expected_file, actual_file))
+ expected = expected.splitlines()
+ actual = actual.splitlines()
+ print(":::: diff {!r} and {!r}".format(expected_file, actual_file))
+ print("\n".join(difflib.Differ().compare(expected, actual)))
+ print(":::: end diff {!r} and {!r}".format(expected_file, actual_file))
+ assert not text_diff, "Files differ: %s" % '\n'.join(text_diff)
+
+ assert not expected_only, "Files in %s only: %s" % (expected_dir, expected_only)
+ if not actual_extra:
+ assert not actual_only, "Files in %s only: %s" % (actual_dir, actual_only)
+
+
+def contains(filename, *strlist):
+ """Check that the file contains all of a list of strings.
+
+ An assert will be raised if one of the arguments in `strlist` is
+ missing in `filename`.
+
+ """
+ with open(filename, "r") as fobj:
+ text = fobj.read()
+ for s in strlist:
+ assert s in text, "Missing content in %s: %r" % (filename, s)
+
+
+def contains_any(filename, *strlist):
+ """Check that the file contains at least one of a list of strings.
+
+ An assert will be raised if none of the arguments in `strlist` is in
+ `filename`.
+
+ """
+ with open(filename, "r") as fobj:
+ text = fobj.read()
+ for s in strlist:
+ if s in text:
+ return
+
+ assert False, ( # pragma: only failure
+ "Missing content in %s: %r [1 of %d]" % (filename, strlist[0], len(strlist),)
+ )
+
+
+def doesnt_contain(filename, *strlist):
+ """Check that the file contains none of a list of strings.
+
+ An assert will be raised if any of the strings in `strlist` appears in
+ `filename`.
+
+ """
+ with open(filename, "r") as fobj:
+ text = fobj.read()
+ for s in strlist:
+ assert s not in text, "Forbidden content in %s: %r" % (filename, s)
+
+
+# Helpers
+
+def fnmatch_list(files, file_pattern):
+ """Filter the list of `files` to only those that match `file_pattern`.
+ If `file_pattern` is None, then return the entire list of files.
+ Returns a list of the filtered files.
+ """
+ if file_pattern:
+ files = [f for f in files if fnmatch.fnmatch(f, file_pattern)]
+ return files
+
+
+def scrub(strdata, scrubs):
+ """Scrub uninteresting data from the payload in `strdata`.
+ `scrubs` is a list of (find, replace) pairs of regexes that are used on
+ `strdata`. A string is returned.
+ """
+ for rgx_find, rgx_replace in scrubs:
+ strdata = re.sub(rgx_find, rgx_replace, strdata)
+ return strdata