diff --git a/.travis.yml b/.travis.yml index 8da004eb..83134951 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,22 +49,62 @@ jobs: python: 'pypy3' - env: TOXENV=pypy3-pytest46-xdist27-coverage45 python: 'pypy3' + - env: TOXENV=py27-pytest310-xdist27-coverage50 + python: '2.7' + - env: TOXENV=py27-pytest46-xdist27-coverage50 + python: '2.7' + - env: TOXENV=py35-pytest310-xdist27-coverage50 + python: '3.5' + - env: TOXENV=py35-pytest46-xdist27-coverage50 + python: '3.5' + - env: TOXENV=py36-pytest310-xdist27-coverage50 + python: '3.6' + - env: TOXENV=py36-pytest46-xdist27-coverage50 + python: '3.6' + - env: TOXENV=py37-pytest310-xdist27-coverage50 + python: '3.7' + - env: TOXENV=py37-pytest46-xdist27-coverage50 + python: '3.7' + - env: TOXENV=pypy-pytest310-xdist27-coverage50 + python: 'pypy' + - env: TOXENV=pypy-pytest46-xdist27-coverage50 + python: 'pypy' + - env: TOXENV=pypy3-pytest310-xdist27-coverage50 + python: 'pypy3' + - env: TOXENV=pypy3-pytest46-xdist27-coverage50 + python: 'pypy3' - env: TOXENV=py36-pytest46-xdist29-coverage45 python: '3.6' + - env: TOXENV=py36-pytest46-xdist29-coverage50 + python: '3.6' - env: TOXENV=py36-pytest51-xdist29-coverage45 python: '3.6' + - env: TOXENV=py36-pytest51-xdist29-coverage50 + python: '3.6' - env: TOXENV=py37-pytest46-xdist29-coverage45 python: '3.7' + - env: TOXENV=py37-pytest46-xdist29-coverage50 + python: '3.7' - env: TOXENV=py37-pytest51-xdist29-coverage45 python: '3.7' + - env: TOXENV=py37-pytest51-xdist29-coverage50 + python: '3.7' - env: TOXENV=py38-pytest46-xdist29-coverage45 python: '3.8-dev' + - env: TOXENV=py38-pytest46-xdist29-coverage50 + python: '3.8-dev' - env: TOXENV=py38-pytest51-xdist29-coverage45 python: '3.8-dev' + - env: TOXENV=py38-pytest51-xdist29-coverage50 + python: '3.8-dev' - env: TOXENV=pypy3-pytest46-xdist29-coverage45 python: 'pypy3' + - env: TOXENV=pypy3-pytest46-xdist29-coverage50 + python: 'pypy3' - env: TOXENV=pypy3-pytest51-xdist29-coverage45 python: 'pypy3' + - env: TOXENV=pypy3-pytest51-xdist29-coverage50 + python: 'pypy3' - stage: examples python: '3.6' diff --git a/appveyor.yml b/appveyor.yml index cdfd7a5d..b414a642 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,12 +4,12 @@ build: off environment: matrix: - TOXENV: check - - TOXENV: 'py27-pytest310-xdist27-coverage45,py27-pytest46-xdist27-coverage45' + - TOXENV: 'py27-pytest310-xdist27-coverage45,py27-pytest46-xdist27-coverage45,py27-pytest310-xdist27-coverage50,py27-pytest46-xdist27-coverage50' - TOXENV: 'py34-pytest310-xdist27-coverage45,py34-pytest46-xdist27-coverage45' - - TOXENV: 'py35-pytest310-xdist27-coverage45,py35-pytest46-xdist27-coverage45' - - TOXENV: 'py36-pytest310-xdist27-coverage45,py36-pytest46-xdist27-coverage45,py36-pytest46-xdist29-coverage45,py36-pytest51-xdist29-coverage45' - - TOXENV: 'py37-pytest310-xdist27-coverage45,py37-pytest46-xdist27-coverage45,py37-pytest46-xdist29-coverage45,py37-pytest51-xdist29-coverage45' - - TOXENV: 'pypy-pytest310-xdist27-coverage45,pypy-pytest46-xdist27-coverage45' + - TOXENV: 'py35-pytest310-xdist27-coverage45,py35-pytest46-xdist27-coverage45,py35-pytest310-xdist27-coverage50,py35-pytest46-xdist27-coverage50' + - TOXENV: 'py36-pytest310-xdist27-coverage45,py36-pytest46-xdist27-coverage45,py36-pytest310-xdist27-coverage50,py36-pytest46-xdist27-coverage50,py36-pytest46-xdist29-coverage45,py36-pytest46-xdist29-coverage50,py36-pytest51-xdist29-coverage45,py36-pytest51-xdist29-coverage50' + - TOXENV: 'py37-pytest310-xdist27-coverage45,py37-pytest46-xdist27-coverage45,py37-pytest310-xdist27-coverage50,py37-pytest46-xdist27-coverage50,py37-pytest46-xdist29-coverage45,py37-pytest46-xdist29-coverage50,py37-pytest51-xdist29-coverage45,py37-pytest51-xdist29-coverage50' + - TOXENV: 'pypy-pytest310-xdist27-coverage45,pypy-pytest46-xdist27-coverage45,pypy-pytest310-xdist27-coverage50,pypy-pytest46-xdist27-coverage50' init: - ps: echo $env:TOXENV diff --git a/src/pytest_cov/engine.py b/src/pytest_cov/engine.py index 3d4cc265..d228d5b5 100644 --- a/src/pytest_cov/engine.py +++ b/src/pytest_cov/engine.py @@ -114,6 +114,14 @@ def summary(self, stream): for node_desc in sorted(self.node_descs): self.sep(stream, ' ', '%s' % node_desc) + # Report on any failed workers. + if self.failed_workers: + self.sep(stream, '-', 'coverage: failed workers') + stream.write('The following workers failed to return coverage data, ' + 'ensure that pytest-cov is installed on these workers.\n') + for node in self.failed_workers: + stream.write('%s\n' % node.gateway.id) + # Produce terminal report if wanted. if any(x in self.cov_report for x in ['term', 'term-missing']): options = { @@ -157,14 +165,6 @@ def summary(self, stream): self.cov.xml_report(ignore_errors=True, outfile=output) stream.write('Coverage XML written to file %s\n' % (self.cov.config.xml_output if output is None else output)) - # Report on any failed workers. - if self.failed_workers: - self.sep(stream, '-', 'coverage: failed workers') - stream.write('The following workers failed to return coverage data, ' - 'ensure that pytest-cov is installed on these workers.\n') - for node in self.failed_workers: - stream.write('%s\n' % node.gateway.id) - return total @@ -263,9 +263,14 @@ def testnodedown(self, node, error): data_suffix=data_suffix, config_file=self.cov_config) cov.start() - data = CoverageData() - data.read_fileobj(StringIO(output['cov_worker_data'])) - cov.data.update(data) + if coverage.version_info < (5, 0): + data = CoverageData() + data.read_fileobj(StringIO(output['cov_worker_data'])) + cov.data.update(data) + else: + data = CoverageData(no_disk=True) + data.loads(output['cov_worker_data']) + cov.get_data().update(data) cov.stop() cov.save() path = output['cov_worker_path'] @@ -312,10 +317,6 @@ def start(self): branch=self.cov_branch, data_suffix=True, config_file=self.cov_config) - if self.cov_append: - self.cov.load() - else: - self.cov.erase() self.cov.start() self.set_env() @@ -341,12 +342,17 @@ def finish(self): # it on the master node. # Send all the data to the master over the channel. - buff = StringIO() - self.cov.data.write_fileobj(buff) + if coverage.version_info < (5, 0): + buff = StringIO() + self.cov.data.write_fileobj(buff) + data = buff.getvalue() + else: + data = self.cov.get_data().dumps() + workeroutput(self.config).update({ 'cov_worker_path': self.topdir, 'cov_worker_node_id': self.nodeid, - 'cov_worker_data': buff.getvalue(), + 'cov_worker_data': data, }) def summary(self, stream): diff --git a/tests/test_pytest_cov.py b/tests/test_pytest_cov.py index 3905a9ea..6d0e7e78 100644 --- a/tests/test_pytest_cov.py +++ b/tests/test_pytest_cov.py @@ -248,6 +248,25 @@ def test_annotate_output_dir(testdir): assert result.ret == 0 +def test_html(testdir): + script = testdir.makepyfile(SCRIPT) + + result = testdir.runpytest('-v', + '--cov=%s' % script.dirpath(), + '--cov-report=html', + script) + + result.stdout.fnmatch_lines([ + '*- coverage: platform *, python * -*', + 'Coverage HTML written to dir htmlcov', + '*10 passed*', + ]) + dest_dir = testdir.tmpdir.join('htmlcov') + assert dest_dir.check(dir=True) + assert dest_dir.join("index.html").check() + assert result.ret == 0 + + def test_html_output_dir(testdir): script = testdir.makepyfile(SCRIPT) @@ -288,6 +307,28 @@ def test_term_report_does_not_interact_with_html_output(testdir): assert result.ret == 0 +def test_html_configured_output_dir(testdir): + script = testdir.makepyfile(SCRIPT) + testdir.tmpdir.join('.coveragerc').write(""" +[html] +directory = somewhere +""") + result = testdir.runpytest('-v', + '--cov=%s' % script.dirpath(), + '--cov-report=html', + script) + + result.stdout.fnmatch_lines([ + '*- coverage: platform *, python * -*', + 'Coverage HTML written to dir somewhere', + '*10 passed*', + ]) + dest_dir = testdir.tmpdir.join('somewhere') + assert dest_dir.check(dir=True) + assert dest_dir.join("index.html").check() + assert result.ret == 0 + + def test_xml_output_dir(testdir): script = testdir.makepyfile(SCRIPT) diff --git a/tox.ini b/tox.ini index cf7fc42c..a546659d 100644 --- a/tox.ini +++ b/tox.ini @@ -3,8 +3,9 @@ [tox] envlist = check - py{27,34,35,36,37,py,py3}-pytest{310,46}-xdist27-{coverage45} - py{36,37,38,py3}-pytest{46,51}-xdist29-{coverage45} + py{27,34,35,36,37,py,py3}-pytest{310,46}-xdist27-coverage45 + py{27,35,36,37,py,py3}-pytest{310,46}-xdist27-coverage50 + py{36,37,38,py3}-pytest{46,51}-xdist29-coverage{45,50} docs [testenv] @@ -27,8 +28,8 @@ setenv = xdist28: _DEP_PYTESTXDIST=pytest-xdist==1.28.0 xdist29: _DEP_PYTESTXDIST=pytest-xdist==1.29.0 - coverage44: _DEP_COVERAGE=coverage==4.4.2 coverage45: _DEP_COVERAGE=coverage==4.5.4 + coverage50: _DEP_COVERAGE=coverage==5.0a7 passenv = *