summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2010-06-13 21:46:35 -0400
committerNed Batchelder <ned@nedbatchelder.com>2010-06-13 21:46:35 -0400
commitcf7fa58279cf644c47864485260a7139d9608b2d (patch)
treeb568ddf59350961a2c4e137a4321ce12093d685e
parentf198d9d2c0df551ce79d97eb448a62f8bdb0cf26 (diff)
downloadpython-coveragepy-git-cf7fa58279cf644c47864485260a7139d9608b2d.tar.gz
The 'source' option is a list of directories or packages to limit coverage's attention.
-rw-r--r--TODO.txt5
-rw-r--r--coverage/cmdline.py16
-rw-r--r--coverage/config.py3
-rw-r--r--coverage/control.py129
-rw-r--r--coverage/files.py36
-rw-r--r--coverage/runners/plugin.py6
-rw-r--r--test/coveragetest.py6
-rw-r--r--test/test_cmdline.py40
-rw-r--r--test/test_files.py39
-rw-r--r--test/test_testing.py4
-rw-r--r--test/test_testplugin.py2
11 files changed, 221 insertions, 65 deletions
diff --git a/TODO.txt b/TODO.txt
index adef82df..b45c2c87 100644
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,5 +1,10 @@
Coverage TODO
+* Cleanups discovered while doing --source:
+ - PyTracer doesn't use should_trace_cache!!
+ - optparse recommends using make_option, not Option constructor
+
+
* plugin work
+ add --cover-include.
+ add --cover-rcfile.
diff --git a/coverage/cmdline.py b/coverage/cmdline.py
index d8738db7..8bf90e21 100644
--- a/coverage/cmdline.py
+++ b/coverage/cmdline.py
@@ -75,6 +75,10 @@ class Opts(object):
'', '--rcfile', action='store',
help="Specify configuration file. Defaults to '.coveragerc'"
)
+ source = optparse.Option(
+ '', '--source', action='store', metavar="SRC1,SRC2,...",
+ help="A list of packages or directories of code to be measured."
+ )
timid = optparse.Option(
'', '--timid', action='store_true',
help="Use a simpler but slower trace method. Try this if you get "
@@ -110,6 +114,7 @@ class CoverageOptionParser(optparse.OptionParser, object):
pylib=None,
rcfile=True,
show_missing=None,
+ source=None,
timid=None,
erase_first=None,
version=None,
@@ -290,6 +295,7 @@ CMDS = {
Opts.pylib,
Opts.parallel_mode,
Opts.timid,
+ Opts.source,
Opts.omit,
Opts.include,
] + GLOBAL_ARGS,
@@ -440,8 +446,9 @@ class CoverageScript(object):
return ERR
# Listify the list options.
- omit = pattern_list(options.omit)
- include = pattern_list(options.include)
+ source = unshell_list(options.source)
+ omit = unshell_list(options.omit)
+ include = unshell_list(options.include)
# Do something.
self.coverage = self.covpkg.coverage(
@@ -450,6 +457,7 @@ class CoverageScript(object):
timid = options.timid,
branch = options.branch,
config_file = options.rcfile,
+ source = source,
omit = omit,
include = include,
)
@@ -528,8 +536,8 @@ class CoverageScript(object):
return OK
-def pattern_list(s):
- """Turn an argument into a list of patterns."""
+def unshell_list(s):
+ """Turn a command-line argument into a list."""
if not s:
return None
if sys.platform == 'win32':
diff --git a/coverage/config.py b/coverage/config.py
index 9f52ecb1..7c22f64b 100644
--- a/coverage/config.py
+++ b/coverage/config.py
@@ -20,6 +20,7 @@ class CoverageConfig(object):
self.data_file = ".coverage"
self.parallel = False
self.timid = False
+ self.source = None
# Defaults for [report]
self.exclude_list = ['(?i)# *pragma[: ]*no *cover']
@@ -68,6 +69,8 @@ class CoverageConfig(object):
self.parallel = cp.getboolean('run', 'parallel')
if cp.has_option('run', 'timid'):
self.timid = cp.getboolean('run', 'timid')
+ if cp.has_option('run', 'source'):
+ self.source = self.get_list(cp, 'run', 'source')
if cp.has_option('run', 'omit'):
self.omit = self.get_list(cp, 'run', 'omit')
if cp.has_option('run', 'include'):
diff --git a/coverage/control.py b/coverage/control.py
index 432a7c27..dafd4930 100644
--- a/coverage/control.py
+++ b/coverage/control.py
@@ -1,6 +1,6 @@
"""Core control stuff for Coverage."""
-import atexit, fnmatch, os, random, socket, sys
+import atexit, os, random, socket, sys
from coverage.annotate import AnnotateReporter
from coverage.backward import string_class
@@ -8,7 +8,7 @@ from coverage.codeunit import code_unit_factory, CodeUnit
from coverage.collector import Collector
from coverage.config import CoverageConfig
from coverage.data import CoverageData
-from coverage.files import FileLocator
+from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher
from coverage.html import HtmlReporter
from coverage.misc import bool_or_none
from coverage.results import Analysis
@@ -32,7 +32,7 @@ class coverage(object):
def __init__(self, data_file=None, data_suffix=None, cover_pylib=None,
auto_data=False, timid=None, branch=None, config_file=True,
- omit=None, include=None):
+ source=None, omit=None, include=None):
"""
`data_file` is the base name of the data file to use, defaulting to
".coverage". `data_suffix` is appended (with a dot) to `data_file` to
@@ -59,6 +59,10 @@ class coverage(object):
standard file is read (".coveragerc"). If it is False, then no file is
read.
+ `source` is a list of file paths or package names. Only code located
+ in the trees indicated by the file paths or package names will be
+ measured.
+
`include` and `omit` are lists of filename patterns. Files that match
`include` will be measured, files that match `omit` will not.
@@ -85,7 +89,7 @@ class coverage(object):
self.config.from_args(
data_file=data_file, cover_pylib=cover_pylib, timid=timid,
branch=branch, parallel=bool_or_none(data_suffix),
- omit=omit, include=include
+ source=source, omit=omit, include=include
)
self.auto_data = auto_data
@@ -96,6 +100,15 @@ class coverage(object):
self.file_locator = FileLocator()
+ # The source argument can be directories or package names.
+ self.source = []
+ self.source_pkgs = []
+ for src in self.config.source or []:
+ if os.path.exists(src):
+ self.source.append(self.file_locator.canonical_filename(src))
+ else:
+ self.source_pkgs.append(src)
+
self.omit = self._abs_files(self.config.omit)
self.include = self._abs_files(self.config.include)
@@ -126,11 +139,12 @@ class coverage(object):
)
# The dirs for files considered "installed with the interpreter".
+ self.pylib_dirs = []
if not self.config.cover_pylib:
# Look at where the "os" module is located. That's the indication
# for "installed with the interpreter".
os_dir = self.canonical_dir(os.__file__)
- self.pylib_dirs = [os_dir]
+ self.pylib_dirs.append(os_dir)
# In a virtualenv, there're actually two lib directories. Find the
# other one. This is kind of ad-hoc, but it works.
@@ -142,10 +156,22 @@ class coverage(object):
# where we are.
self.cover_dir = self.canonical_dir(__file__)
+ # The matchers for _should_trace, created when tracing starts.
+ self.source_match = None
+ self.pylib_match = self.cover_match = None
+ self.include_match = self.omit_match = None
+
def canonical_dir(self, f):
"""Return the canonical directory of the file `f`."""
return os.path.split(self.file_locator.canonical_filename(f))[0]
+ def _source_for_file(self, filename):
+ """Return the source file for `filename`."""
+ if not filename.endswith(".py"):
+ if filename[-4:-1] == ".py":
+ filename = filename[:-1]
+ return filename
+
def _should_trace(self, filename, frame):
"""Decide whether to trace execution in `filename`
@@ -156,13 +182,15 @@ class coverage(object):
should not.
"""
- if filename[0] == '<':
+ if filename.startswith('<'):
# Lots of non-file execution is represented with artificial
# filenames like "<string>", "<doctest readme.txt[0]>", or
# "<exec_function>". Don't ever trace these executions, since we
# can't do anything with the data later anyway.
return False
+ self._check_for_packages()
+
# Compiled Python files have two filenames: frame.f_code.co_filename is
# the filename at the time the .pyc was compiled. The second name
# is __file__, which is where the .pyc was actually loaded from. Since
@@ -171,35 +199,31 @@ class coverage(object):
# co_filename value.
dunder_file = frame.f_globals.get('__file__')
if dunder_file:
- if not dunder_file.endswith(".py"):
- if dunder_file[-4:-1] == ".py":
- dunder_file = dunder_file[:-1]
- filename = dunder_file
-
+ filename = self._source_for_file(dunder_file)
canonical = self.file_locator.canonical_filename(filename)
- canon_dir = os.path.split(canonical)[0]
- # If we aren't supposed to trace installed code, then check if this is
- # near the Python standard library and skip it if so.
- if not self.config.cover_pylib:
- if canon_dir in self.pylib_dirs:
+ # If the user specified source, then that's authoritative about what to
+ # measure. If they didn't, then we have to exclude the stdlib and
+ # coverage.py directories.
+ if self.source_match:
+ if not self.source_match.match(canonical):
+ return False
+ else:
+ # If we aren't supposed to trace installed code, then check if this
+ # is near the Python standard library and skip it if so.
+ if self.pylib_match and self.pylib_match.match(canonical):
return False
- # We exclude the coverage code itself, since a little of it will be
- # measured otherwise.
- if canon_dir == self.cover_dir:
- return False
+ # We exclude the coverage code itself, since a little of it will be
+ # measured otherwise.
+ if self.cover_match and self.cover_match.match(canonical):
+ return False
# Check the file against the include and omit patterns.
- if self.include:
- for pattern in self.include:
- if fnmatch.fnmatch(canonical, pattern):
- break
- else:
- return False
- for pattern in self.omit:
- if fnmatch.fnmatch(canonical, pattern):
- return False
+ if self.include_match and not self.include_match.match(canonical):
+ return False
+ if self.omit_match and self.omit_match.match(canonical):
+ return False
return canonical
@@ -217,6 +241,39 @@ class coverage(object):
files = files or []
return [self.file_locator.abs_file(f) for f in files]
+ def _check_for_packages(self):
+ """Update the source_match matcher with latest imported packages."""
+ # Our self.source_pkgs attribute is a list of package names we want to
+ # measure. Each time through here, we see if we've imported any of
+ # them yet. If so, we add its file to source_match, and we don't have
+ # to look for that package any more.
+ if self.source_pkgs:
+ found = []
+ for pkg in self.source_pkgs:
+ try:
+ mod = sys.modules[pkg]
+ except KeyError:
+ continue
+
+ found.append(pkg)
+
+ try:
+ pkg_file = mod.__file__
+ except AttributeError:
+ print "WHOA! No file for module %s" % pkg
+ else:
+ d, f = os.path.split(pkg_file)
+ if f.startswith('__init__.'):
+ # This is actually a package, return the directory.
+ pkg_file = d
+ else:
+ pkg_file = self._source_for_file(pkg_file)
+ pkg_file = self.file_locator.canonical_filename(pkg_file)
+ self.source_match.add(pkg_file)
+
+ for pkg in found:
+ self.source_pkgs.remove(pkg)
+
def use_cache(self, usecache):
"""Control the use of a data file (incorrectly called a cache).
@@ -242,6 +299,20 @@ class coverage(object):
if not self.atexit_registered:
atexit.register(self.save)
self.atexit_registered = True
+
+ # Create the matchers we need for _should_trace
+ if self.source or self.source_pkgs:
+ self.source_match = TreeMatcher(self.source)
+ else:
+ if self.cover_dir:
+ self.cover_match = TreeMatcher([self.cover_dir])
+ if self.pylib_dirs:
+ self.pylib_match = TreeMatcher(self.pylib_dirs)
+ if self.include:
+ self.include_match = FnmatchMatcher(self.include)
+ if self.omit:
+ self.omit_match = FnmatchMatcher(self.omit)
+
self.collector.start()
def stop(self):
diff --git a/coverage/files.py b/coverage/files.py
index 5690679f..d74b4d79 100644
--- a/coverage/files.py
+++ b/coverage/files.py
@@ -1,6 +1,6 @@
"""File wrangling."""
-import os, sys
+import fnmatch, os, sys
class FileLocator(object):
"""Understand how filenames work."""
@@ -76,3 +76,37 @@ class FileLocator(object):
data = data.decode('utf8') # TODO: How to do this properly?
return data
return None
+
+
+class TreeMatcher(object):
+ """A matcher for files in a tree."""
+ def __init__(self, directories):
+ self.dirs = directories[:]
+
+ def add(self, directory):
+ """Add another directory to the list we match for."""
+ self.dirs.append(directory)
+
+ def match(self, fpath):
+ """Does `fpath` indicate a file in one of our trees?"""
+ for d in self.dirs:
+ if fpath.startswith(d):
+ if fpath == d:
+ # This is the same file!
+ return True
+ if fpath[len(d)] == os.sep:
+ # This is a file in the directory
+ return True
+ return False
+
+class FnmatchMatcher(object):
+ """A matcher for files by filename pattern."""
+ def __init__(self, pats):
+ self.pats = pats[:]
+
+ def match(self, fpath):
+ """Does `fpath` match one of our filename patterns?"""
+ for pat in self.pats:
+ if fnmatch.fnmatch(fpath, pat):
+ return True
+ return False
diff --git a/coverage/runners/plugin.py b/coverage/runners/plugin.py
index fd2a3a62..cf059c57 100644
--- a/coverage/runners/plugin.py
+++ b/coverage/runners/plugin.py
@@ -2,7 +2,7 @@
import optparse, sys
import coverage
-from coverage.cmdline import pattern_list
+from coverage.cmdline import unshell_list
class CoverageTestWrapper(object):
@@ -34,8 +34,8 @@ class CoverageTestWrapper(object):
def start(self):
"""Start coverage before the test suite."""
# cover_omit is a ',' separated list if provided
- self.omit = pattern_list(self.options.cover_omit)
- self.include = pattern_list(self.options.cover_omit)
+ self.omit = unshell_list(self.options.cover_omit)
+ self.include = unshell_list(self.options.cover_omit)
self.coverage = self.covpkg.coverage(
config_file = self.options.cover_rcfile,
diff --git a/test/coveragetest.py b/test/coveragetest.py
index 9b85b034..f09afc1f 100644
--- a/test/coveragetest.py
+++ b/test/coveragetest.py
@@ -121,12 +121,14 @@ class CoverageTest(TestCase):
"""Return the data written to stderr during the test."""
return self.captured_stderr.getvalue()
- def make_file(self, filename, text):
+ def make_file(self, filename, text=""):
"""Create a temp file.
`filename` is the path to the file, including directories if desired,
and `text` is the content.
+ Returns the path to the file.
+
"""
# Tests that call `make_file` should be run in a temp environment.
assert self.run_in_temp_dir
@@ -142,6 +144,8 @@ class CoverageTest(TestCase):
f.write(text)
f.close()
+ return filename
+
def import_module(self, modname):
"""Import the module named modname, and return the module object."""
modfile = modname + '.py'
diff --git a/test/test_cmdline.py b/test/test_cmdline.py
index cf20ba7f..9c0e1154 100644
--- a/test/test_cmdline.py
+++ b/test/test_cmdline.py
@@ -16,7 +16,7 @@ class CmdLineTest(CoverageTest):
run_in_temp_dir = False
INIT_LOAD = """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=None)
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=None)
.load()\n"""
def model_object(self):
@@ -96,7 +96,7 @@ class ClassicCmdLineTest(CmdLineTest):
def testErase(self):
# coverage -e
self.cmd_executes("-e", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=None)
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=None)
.erase()
""")
self.cmd_executes_same("-e", "--erase")
@@ -106,7 +106,7 @@ class ClassicCmdLineTest(CmdLineTest):
# -x calls coverage.load first.
self.cmd_executes("-x foo.py", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=None)
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=None)
.load()
.start()
.run_python_file('foo.py', ['foo.py'])
@@ -115,7 +115,7 @@ class ClassicCmdLineTest(CmdLineTest):
""")
# -e -x calls coverage.erase first.
self.cmd_executes("-e -x foo.py", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=None)
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=None)
.erase()
.start()
.run_python_file('foo.py', ['foo.py'])
@@ -124,7 +124,7 @@ class ClassicCmdLineTest(CmdLineTest):
""")
# --timid sets a flag, and program arguments get passed through.
self.cmd_executes("-x --timid foo.py abc 123", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=True, branch=None, config_file=True, include=None, omit=None)
+ .coverage(cover_pylib=None, data_suffix=None, timid=True, branch=None, config_file=True, source=None, include=None, omit=None)
.load()
.start()
.run_python_file('foo.py', ['foo.py', 'abc', '123'])
@@ -133,7 +133,7 @@ class ClassicCmdLineTest(CmdLineTest):
""")
# -L sets a flag, and flags for the program don't confuse us.
self.cmd_executes("-x -p -L foo.py -a -b", """\
- .coverage(cover_pylib=True, data_suffix=True, timid=None, branch=None, config_file=True, include=None, omit=None)
+ .coverage(cover_pylib=True, data_suffix=True, timid=None, branch=None, config_file=True, source=None, include=None, omit=None)
.load()
.start()
.run_python_file('foo.py', ['foo.py', '-a', '-b'])
@@ -150,7 +150,7 @@ class ClassicCmdLineTest(CmdLineTest):
def testCombine(self):
# coverage -c
self.cmd_executes("-c", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=None)
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=None)
.load()
.combine()
.save()
@@ -172,13 +172,13 @@ class ClassicCmdLineTest(CmdLineTest):
show_missing=True)
""")
self.cmd_executes("-r -o fooey", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=["fooey"])
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey"])
.load()
.report(ignore_errors=None, omit=["fooey"], include=None,
morfs=[], show_missing=None)
""")
self.cmd_executes("-r -o fooey,booey", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=["fooey", "booey"])
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey", "booey"])
.load()
.report(ignore_errors=None, omit=["fooey", "booey"], include=None,
morfs=[], show_missing=None)
@@ -217,13 +217,13 @@ class ClassicCmdLineTest(CmdLineTest):
omit=None, include=None, morfs=[])
""")
self.cmd_executes("-a -o fooey", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=["fooey"])
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey"])
.load()
.annotate(directory=None, ignore_errors=None,
omit=["fooey"], include=None, morfs=[])
""")
self.cmd_executes("-a -o fooey,booey", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=["fooey", "booey"])
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey", "booey"])
.load()
.annotate(directory=None, ignore_errors=None,
omit=["fooey", "booey"], include=None, morfs=[])
@@ -262,13 +262,13 @@ class ClassicCmdLineTest(CmdLineTest):
omit=None, include=None, morfs=[])
""")
self.cmd_executes("-b -o fooey", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=["fooey"])
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey"])
.load()
.html_report(directory=None, ignore_errors=None,
omit=["fooey"], include=None, morfs=[])
""")
self.cmd_executes("-b -o fooey,booey", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=["fooey", "booey"])
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey", "booey"])
.load()
.html_report(directory=None, ignore_errors=None,
omit=["fooey", "booey"], include=None, morfs=[])
@@ -465,7 +465,7 @@ class NewCmdLineTest(CmdLineTest):
self.cmd_executes_same("run --timid f.py", "-e -x --timid f.py")
self.cmd_executes_same("run", "-x")
self.cmd_executes("run --branch foo.py", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=True, config_file=True, include=None, omit=None)
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=True, config_file=True, source=None, include=None, omit=None)
.erase()
.start()
.run_python_file('foo.py', ['foo.py'])
@@ -473,7 +473,7 @@ class NewCmdLineTest(CmdLineTest):
.save()
""")
self.cmd_executes("run --rcfile=myrc.rc foo.py", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file="myrc.rc", include=None, omit=None)
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file="myrc.rc", source=None, include=None, omit=None)
.erase()
.start()
.run_python_file('foo.py', ['foo.py'])
@@ -481,7 +481,7 @@ class NewCmdLineTest(CmdLineTest):
.save()
""")
self.cmd_executes("run --include=pre1,pre2 foo.py", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=["pre1", "pre2"], omit=None)
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=["pre1", "pre2"], omit=None)
.erase()
.start()
.run_python_file('foo.py', ['foo.py'])
@@ -489,7 +489,7 @@ class NewCmdLineTest(CmdLineTest):
.save()
""")
self.cmd_executes("run --omit=opre1,opre2 foo.py", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=["opre1", "opre2"])
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["opre1", "opre2"])
.erase()
.start()
.run_python_file('foo.py', ['foo.py'])
@@ -499,7 +499,7 @@ class NewCmdLineTest(CmdLineTest):
self.cmd_executes("run --include=pre1,pre2 --omit=opre1,opre2 foo.py",
"""\
.coverage(cover_pylib=None, data_suffix=None, timid=None,
- branch=None, config_file=True,
+ branch=None, config_file=True, source=None,
include=["pre1", "pre2"],
omit=["opre1", "opre2"])
.erase()
@@ -528,13 +528,13 @@ class NewCmdLineTest(CmdLineTest):
outfile="-")
""")
self.cmd_executes("xml --omit fooey", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=["fooey"])
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey"])
.load()
.xml_report(ignore_errors=None, omit=["fooey"], include=None, morfs=[],
outfile="coverage.xml")
""")
self.cmd_executes("xml --omit fooey,booey", """\
- .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, include=None, omit=["fooey", "booey"])
+ .coverage(cover_pylib=None, data_suffix=None, timid=None, branch=None, config_file=True, source=None, include=None, omit=["fooey", "booey"])
.load()
.xml_report(ignore_errors=None, omit=["fooey", "booey"], include=None,
morfs=[], outfile="coverage.xml")
diff --git a/test/test_files.py b/test/test_files.py
index ca9b4e0d..db835e5e 100644
--- a/test/test_files.py
+++ b/test/test_files.py
@@ -2,7 +2,7 @@
import os, sys
-from coverage.files import FileLocator
+from coverage.files import FileLocator, TreeMatcher, FnmatchMatcher
sys.path.insert(0, os.path.split(__file__)[0]) # Force relative import for Py3k
from coveragetest import CoverageTest
@@ -16,7 +16,7 @@ class FileLocatorTest(CoverageTest):
return os.path.join(os.getcwd(), os.path.normpath(p))
def test_simple(self):
- self.make_file("hello.py", "#hello")
+ self.make_file("hello.py")
fl = FileLocator()
self.assertEqual(fl.relative_filename("hello.py"), "hello.py")
a = self.abs_path("hello.py")
@@ -24,8 +24,8 @@ class FileLocatorTest(CoverageTest):
self.assertEqual(fl.relative_filename(a), "hello.py")
def test_peer_directories(self):
- self.make_file("sub/proj1/file1.py", "file1")
- self.make_file("sub/proj2/file2.py", "file2")
+ self.make_file("sub/proj1/file1.py")
+ self.make_file("sub/proj2/file2.py")
a1 = self.abs_path("sub/proj1/file1.py")
a2 = self.abs_path("sub/proj2/file2.py")
d = os.path.normpath("sub/proj1")
@@ -33,3 +33,34 @@ class FileLocatorTest(CoverageTest):
fl = FileLocator()
self.assertEqual(fl.relative_filename(a1), "file1.py")
self.assertEqual(fl.relative_filename(a2), a2)
+
+ def test_tree_matcher(self):
+ file1 = self.make_file("sub/file1.py")
+ file2 = self.make_file("sub/file2.c")
+ file3 = self.make_file("sub2/file3.h")
+ file4 = self.make_file("sub3/file4.py")
+ file5 = self.make_file("sub3/file5.c")
+ fl = FileLocator()
+ tm = TreeMatcher([
+ fl.canonical_filename("sub"),
+ fl.canonical_filename(file4),
+ ])
+ self.assertTrue(tm.match(fl.canonical_filename(file1)))
+ self.assertTrue(tm.match(fl.canonical_filename(file2)))
+ self.assertFalse(tm.match(fl.canonical_filename(file3)))
+ self.assertTrue(tm.match(fl.canonical_filename(file4)))
+ self.assertFalse(tm.match(fl.canonical_filename(file5)))
+
+ def test_fnmatch_matcher(self):
+ file1 = self.make_file("sub/file1.py")
+ file2 = self.make_file("sub/file2.c")
+ file3 = self.make_file("sub2/file3.h")
+ file4 = self.make_file("sub3/file4.py")
+ file5 = self.make_file("sub3/file5.c")
+ fl = FileLocator()
+ fnm = FnmatchMatcher(["*.py", "*/sub2/*"])
+ self.assertTrue(fnm.match(fl.canonical_filename(file1)))
+ self.assertFalse(fnm.match(fl.canonical_filename(file2)))
+ self.assertTrue(fnm.match(fl.canonical_filename(file3)))
+ self.assertTrue(fnm.match(fl.canonical_filename(file4)))
+ self.assertFalse(fnm.match(fl.canonical_filename(file5)))
diff --git a/test/test_testing.py b/test/test_testing.py
index 9bbb7cca..1cae9310 100644
--- a/test/test_testing.py
+++ b/test/test_testing.py
@@ -107,5 +107,5 @@ class CoverageTestTest(CoverageTest):
self.make_file("sub/second.txt", "Second")
self.assertEqual(open("sub/second.txt").read(), "Second")
# A deeper directory
- self.make_file("sub/deeper/evenmore/third.txt", "Third")
- self.assertEqual(open("sub/deeper/evenmore/third.txt").read(), "Third")
+ self.make_file("sub/deeper/evenmore/third.txt")
+ self.assertEqual(open("sub/deeper/evenmore/third.txt").read(), "")
diff --git a/test/test_testplugin.py b/test/test_testplugin.py
index c5bcca01..b012ca6a 100644
--- a/test/test_testplugin.py
+++ b/test/test_testplugin.py
@@ -14,7 +14,7 @@ class TestCoverage(PluginTester, unittest.TestCase):
@py.test.mark.skipif(True) # "requires nose test runner"
def test_output(self):
- assert "Processing Coverage..." in self.output, (
+ assert "Processing coverage..." in self.output, (
"got: %s" % self.output)
def makeSuite(self):
class TC(unittest.TestCase):