Skip to content

--cov-contexts support #342

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/pytest_cov/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ def summary(self, stream):
'file': stream,
}
skip_covered = isinstance(self.cov_report, dict) and 'skip-covered' in self.cov_report.values()
if hasattr(coverage, 'version_info') and coverage.version_info[0] >= 4:
options.update({'skip_covered': skip_covered or None})
options.update({'skip_covered': skip_covered or None})
with _backup(self.cov, "config"):
total = self.cov.report(**options)

Expand Down
35 changes: 35 additions & 0 deletions src/pytest_cov/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import warnings

import pytest
import coverage
from coverage.misc import CoverageException

from . import compat
Expand Down Expand Up @@ -48,6 +49,16 @@ def validate_fail_under(num_str):
return float(num_str)


def validate_contexts(arg):
if coverage.version_info <= (5, 0):
msg = 'Contexts are only supported with coverage.py >= 5.x'
raise argparse.ArgumentTypeError(msg)
if arg != "test":
msg = '--cov-contexts=test is the only supported value'
raise argparse.ArgumentTypeError(msg)
return arg


class StoreReport(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
report_type, file = values
Expand Down Expand Up @@ -88,6 +99,9 @@ def pytest_addoption(parser):
'Default: False')
group.addoption('--cov-branch', action='store_true', default=None,
help='Enable branch coverage.')
group.addoption('--cov-contexts', action='store', metavar='CONTEXT',
type=validate_contexts,
help='Dynamic contexts to use. "test" for now.')


def _prepare_cov_source(cov_source):
Expand Down Expand Up @@ -151,6 +165,9 @@ def __init__(self, options, pluginmanager, start=True):
elif start:
self.start(engine.Central)

if getattr(options, 'cov_contexts', None) == 'test':
pluginmanager.register(TestContextPlugin(self.cov_controller.cov), '_cov_contexts')

# worker is started in pytest hook

def start(self, controller_cls, config=None, nodeid=None):
Expand Down Expand Up @@ -308,6 +325,24 @@ def pytest_runtest_call(self, item):
yield


class TestContextPlugin(object):
def __init__(self, cov):
self.cov = cov

def pytest_runtest_setup(self, item):
self.switch_context(item, 'setup')

def pytest_runtest_teardown(self, item):
self.switch_context(item, 'teardown')

def pytest_runtest_call(self, item):
self.switch_context(item, 'run')

def switch_context(self, item, when):
context = "{item.nodeid}|{when}".format(item=item, when=when)
self.cov.switch_context(context)


@pytest.fixture
def no_cover():
"""A pytest fixture to disable coverage."""
Expand Down
63 changes: 58 additions & 5 deletions tests/test_pytest_cov.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import glob
import os
import platform
import sqlite3
import subprocess
import sys
from distutils.version import StrictVersion
from itertools import chain

import coverage
Expand All @@ -25,7 +25,7 @@
import pytest_cov.plugin
from pytest_cov import compat

coverage, platform, StrictVersion # required for skipif mark on test_cov_min_from_coveragerc
coverage, platform # required for skipif mark on test_cov_min_from_coveragerc

max_worker_restart_0 = "--max-" + compat.worker + "-restart=0"

Expand Down Expand Up @@ -468,7 +468,6 @@ def test_central_nonspecific(testdir, prop):
assert result.ret == 0


@pytest.mark.skipif('StrictVersion(coverage.__version__) <= StrictVersion("3.8")')
def test_cov_min_from_coveragerc(testdir):
script = testdir.makepyfile(SCRIPT)
testdir.tmpdir.join('.coveragerc').write("""
Expand Down Expand Up @@ -1636,7 +1635,6 @@ def test_basic():
SKIP_COVERED_RESULT = '1 file skipped due to complete coverage.'


@pytest.mark.skipif('StrictVersion(coverage.__version__) < StrictVersion("4.0")')
@pytest.mark.parametrize('report_option', [
'term-missing:skip-covered',
'term:skip-covered'])
Expand All @@ -1651,7 +1649,6 @@ def test_skip_covered_cli(testdir, report_option):
result.stdout.fnmatch_lines([SKIP_COVERED_RESULT])


@pytest.mark.skipif('StrictVersion(coverage.__version__) < StrictVersion("4.0")')
def test_skip_covered_coveragerc_config(testdir):
testdir.makefile('', coveragerc=SKIP_COVERED_COVERAGERC)
script = testdir.makepyfile(SKIP_COVERED_TEST)
Expand Down Expand Up @@ -1932,3 +1929,59 @@ def test_cov_and_no_cov(testdir):
script)

assert result.ret == 0


CONTEXTFUL_TESTS = '''\
import unittest

def test_one():
assert 1 == 1

def test_two():
assert 2 == 2

class OldStyleTests(unittest.TestCase):
def setUp(self):
self.three = 3
def tearDown(self):
self.three = None
def test_three(self):
assert self.three == 3
'''

@pytest.mark.skipif("coverage.version_info < (5, 0)")
@xdist_params
def test_contexts(testdir, opts):
script = testdir.makepyfile(CONTEXTFUL_TESTS)
result = testdir.runpytest('-v',
'--cov=%s' % script.dirpath(),
'--cov-contexts=test',
script,
*opts.split()
)
result.stdout.fnmatch_lines([
'test_contexts* 100%*',
])
con = sqlite3.connect(".coverage")
cur = con.cursor()
contexts = set(r[0] for r in cur.execute("select context from context"))
assert contexts == {
'',
'test_contexts.py::test_two|run',
'test_contexts.py::test_one|run',
'test_contexts.py::OldStyleTests::test_three|run',
}


@pytest.mark.skipif("coverage.version_info >= (5, 0)")
def test_contexts_not_supported(testdir):
script = testdir.makepyfile(CONTEXTFUL_TESTS)
result = testdir.runpytest('-v',
'--cov=%s' % script.dirpath(),
'--cov-contexts=test',
script,
)
result.stderr.fnmatch_lines([
'*argument --cov-contexts: Contexts are only supported with coverage.py >= 5.x',
])
assert result.ret != 0