From a14e746d1bbb89763a3c1717d3fc4f6f394a2449 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ionel=20Cristian=20M=C4=83rie=C8=99?= Date: Fri, 2 Oct 2015 01:31:33 +0300 Subject: [PATCH] Fix handling when tests change working directory. Use absolute paths for coverage config file and sources. Add a new internal variable "COV_CORE_DATAFILE" to workaround the misplacement of .coverage.foobar.123 files. Because needs to be an absolute path COV_CORE_CONFIG we need to do some special things: coverage treats config_file='.coveragerc' as if it was config_file=True. We need to keep that behavior. Closes #94. Closes #77. --- src/pytest_cov/embed.py | 16 +++++++++---- src/pytest_cov/engine.py | 11 +++++++-- tests/test_pytest_cov.py | 50 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/pytest_cov/embed.py b/src/pytest_cov/embed.py index a707b34f..f281445a 100644 --- a/src/pytest_cov/embed.py +++ b/src/pytest_cov/embed.py @@ -41,7 +41,8 @@ def init(): cov_source = os.environ.get('COV_CORE_SOURCE') cov_config = os.environ.get('COV_CORE_CONFIG') - if cov_config: + cov_datafile = os.environ.get('COV_CORE_DATAFILE') + if cov_datafile: # Import what we need to activate coverage. import coverage @@ -50,12 +51,17 @@ def init(): cov_source = None else: cov_source = cov_source.split(os.pathsep) + if not cov_config: + cov_config = True # Activate coverage for this process. - cov = coverage.coverage(source=cov_source, - data_suffix=True, - config_file=cov_config, - auto_data=True) + cov = coverage.coverage( + source=cov_source, + data_suffix=True, + config_file=cov_config, + auto_data=True, + data_file=cov_datafile + ) cov.load() cov.start() cov._warn_no_data = False diff --git a/src/pytest_cov/engine.py b/src/pytest_cov/engine.py index 38cd1f2b..e470d5b7 100644 --- a/src/pytest_cov/engine.py +++ b/src/pytest_cov/engine.py @@ -34,14 +34,21 @@ def set_env(self): if self.cov_source is None: os.environ['COV_CORE_SOURCE'] = '' else: - os.environ['COV_CORE_SOURCE'] = os.pathsep.join(self.cov_source) - os.environ['COV_CORE_CONFIG'] = self.cov_config + os.environ['COV_CORE_SOURCE'] = os.pathsep.join( + os.path.abspath(p) for p in self.cov_source) + config_file = os.path.abspath(self.cov_config) + if os.path.exists(config_file): + os.environ['COV_CORE_CONFIG'] = config_file + else: + os.environ['COV_CORE_CONFIG'] = '' + os.environ['COV_CORE_DATAFILE'] = os.path.abspath('.coverage') @staticmethod def unset_env(): """Remove coverage info from env.""" os.environ.pop('COV_CORE_SOURCE', None) os.environ.pop('COV_CORE_CONFIG', None) + os.environ.pop('COV_CORE_DATAFILE', None) @staticmethod def get_node_desc(platform, version_info): diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 9672b552..32e95de5 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -7,11 +7,11 @@ import coverage import py import pytest - import virtualenv from process_tests import TestProcess from process_tests import dump_on_error from process_tests import wait_for_strings + import pytest_cov.plugin coverage, StrictVersion # required for skipif mark on test_cov_min_from_coveragerc @@ -75,6 +75,30 @@ def test_foo(idx): pass ''' +SCRIPT_PARENT_CHANGE_CWD = ''' +import subprocess +import sys +import os + +def pytest_generate_tests(metafunc): + for i in range(2): + metafunc.addcall(funcargs=dict(idx=i)) + +def test_foo(idx): + os.mkdir("foobar") + os.chdir("foobar") + + subprocess.check_call([ + sys.executable, + os.path.join(os.path.dirname(__file__), 'child_script.py'), + str(idx) + ]) + +# there is a issue in coverage.py with multiline statements at +# end of file: https://bitbucket.org/ned/coveragepy/issue/293 +pass +''' + SCRIPT_FUNCARG = ''' import coverage @@ -350,6 +374,30 @@ def test_central_subprocess(testdir): assert result.ret == 0 +def test_central_subprocess_change_cwd(testdir): + scripts = testdir.makepyfile(parent_script=SCRIPT_PARENT_CHANGE_CWD, + child_script=SCRIPT_CHILD) + parent_script = scripts.dirpath().join('parent_script.py') + testdir.makefile('', coveragerc=""" +[run] +branch = true +parallel = true +""") + + result = testdir.runpytest('-v', '--tb=short', + '--cov=%s' % scripts.dirpath(), + '--cov-config=coveragerc', + '--cov-report=term-missing', + parent_script) + + result.stdout.fnmatch_lines([ + '*- coverage: platform *, python * -*', + 'child_script* %s *' % CHILD_SCRIPT_RESULT, + 'parent_script* 100% *', + ]) + assert result.ret == 0 + + def test_central_subprocess_no_subscript(testdir): script = testdir.makepyfile(""" import subprocess, sys