bpo-31908: Fix output of cover files for trace module command-line tool. (GH-4205)
Previously emitted cover files only when --missing option was used.
This commit is contained in:
parent
fb7e7992be
commit
47ab15470d
|
@ -2,6 +2,7 @@ import os
|
||||||
import sys
|
import sys
|
||||||
from test.support import TESTFN, rmtree, unlink, captured_stdout
|
from test.support import TESTFN, rmtree, unlink, captured_stdout
|
||||||
from test.support.script_helper import assert_python_ok, assert_python_failure
|
from test.support.script_helper import assert_python_ok, assert_python_failure
|
||||||
|
import textwrap
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import trace
|
import trace
|
||||||
|
@ -365,6 +366,46 @@ class Test_Ignore(unittest.TestCase):
|
||||||
# Matched before.
|
# Matched before.
|
||||||
self.assertTrue(ignore.names(jn('bar', 'baz.py'), 'baz'))
|
self.assertTrue(ignore.names(jn('bar', 'baz.py'), 'baz'))
|
||||||
|
|
||||||
|
# Created for Issue 31908 -- CLI utility not writing cover files
|
||||||
|
class TestCoverageCommandLineOutput(unittest.TestCase):
|
||||||
|
|
||||||
|
codefile = 'tmp.py'
|
||||||
|
coverfile = 'tmp.cover'
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
with open(self.codefile, 'w') as f:
|
||||||
|
f.write(textwrap.dedent('''\
|
||||||
|
x = 42
|
||||||
|
if []:
|
||||||
|
print('unreachable')
|
||||||
|
'''))
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
unlink(self.codefile)
|
||||||
|
unlink(self.coverfile)
|
||||||
|
|
||||||
|
def test_cover_files_written_no_highlight(self):
|
||||||
|
argv = '-m trace --count'.split() + [self.codefile]
|
||||||
|
status, stdout, stderr = assert_python_ok(*argv)
|
||||||
|
self.assertTrue(os.path.exists(self.coverfile))
|
||||||
|
with open(self.coverfile) as f:
|
||||||
|
self.assertEqual(f.read(),
|
||||||
|
" 1: x = 42\n"
|
||||||
|
" 1: if []:\n"
|
||||||
|
" print('unreachable')\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_cover_files_written_with_highlight(self):
|
||||||
|
argv = '-m trace --count --missing'.split() + [self.codefile]
|
||||||
|
status, stdout, stderr = assert_python_ok(*argv)
|
||||||
|
self.assertTrue(os.path.exists(self.coverfile))
|
||||||
|
with open(self.coverfile) as f:
|
||||||
|
self.assertEqual(f.read(), textwrap.dedent('''\
|
||||||
|
1: x = 42
|
||||||
|
1: if []:
|
||||||
|
>>>>>> print('unreachable')
|
||||||
|
'''))
|
||||||
|
|
||||||
class TestCommandLine(unittest.TestCase):
|
class TestCommandLine(unittest.TestCase):
|
||||||
|
|
||||||
def test_failures(self):
|
def test_failures(self):
|
||||||
|
|
39
Lib/trace.py
39
Lib/trace.py
|
@ -73,9 +73,6 @@ def _unsettrace():
|
||||||
|
|
||||||
PRAGMA_NOCOVER = "#pragma NO COVER"
|
PRAGMA_NOCOVER = "#pragma NO COVER"
|
||||||
|
|
||||||
# Simple rx to find lines with no code.
|
|
||||||
rx_blank = re.compile(r'^\s*(#.*)?$')
|
|
||||||
|
|
||||||
class _Ignore:
|
class _Ignore:
|
||||||
def __init__(self, modules=None, dirs=None):
|
def __init__(self, modules=None, dirs=None):
|
||||||
self._mods = set() if not modules else set(modules)
|
self._mods = set() if not modules else set(modules)
|
||||||
|
@ -278,16 +275,15 @@ class CoverageResults:
|
||||||
lnotab = _find_executable_linenos(filename)
|
lnotab = _find_executable_linenos(filename)
|
||||||
else:
|
else:
|
||||||
lnotab = {}
|
lnotab = {}
|
||||||
if lnotab:
|
source = linecache.getlines(filename)
|
||||||
source = linecache.getlines(filename)
|
coverpath = os.path.join(dir, modulename + ".cover")
|
||||||
coverpath = os.path.join(dir, modulename + ".cover")
|
with open(filename, 'rb') as fp:
|
||||||
with open(filename, 'rb') as fp:
|
encoding, _ = tokenize.detect_encoding(fp.readline)
|
||||||
encoding, _ = tokenize.detect_encoding(fp.readline)
|
n_hits, n_lines = self.write_results_file(coverpath, source,
|
||||||
n_hits, n_lines = self.write_results_file(coverpath, source,
|
lnotab, count, encoding)
|
||||||
lnotab, count, encoding)
|
if summary and n_lines:
|
||||||
if summary and n_lines:
|
percent = int(100 * n_hits / n_lines)
|
||||||
percent = int(100 * n_hits / n_lines)
|
sums[modulename] = n_lines, percent, modulename, filename
|
||||||
sums[modulename] = n_lines, percent, modulename, filename
|
|
||||||
|
|
||||||
|
|
||||||
if summary and sums:
|
if summary and sums:
|
||||||
|
@ -306,6 +302,7 @@ class CoverageResults:
|
||||||
|
|
||||||
def write_results_file(self, path, lines, lnotab, lines_hit, encoding=None):
|
def write_results_file(self, path, lines, lnotab, lines_hit, encoding=None):
|
||||||
"""Return a coverage results file in path."""
|
"""Return a coverage results file in path."""
|
||||||
|
# ``lnotab`` is a dict of executable lines, or a line number "table"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
outfile = open(path, "w", encoding=encoding)
|
outfile = open(path, "w", encoding=encoding)
|
||||||
|
@ -324,17 +321,13 @@ class CoverageResults:
|
||||||
outfile.write("%5d: " % lines_hit[lineno])
|
outfile.write("%5d: " % lines_hit[lineno])
|
||||||
n_hits += 1
|
n_hits += 1
|
||||||
n_lines += 1
|
n_lines += 1
|
||||||
elif rx_blank.match(line):
|
elif lineno in lnotab and not PRAGMA_NOCOVER in line:
|
||||||
outfile.write(" ")
|
# Highlight never-executed lines, unless the line contains
|
||||||
else:
|
|
||||||
# lines preceded by no marks weren't hit
|
|
||||||
# Highlight them if so indicated, unless the line contains
|
|
||||||
# #pragma: NO COVER
|
# #pragma: NO COVER
|
||||||
if lineno in lnotab and not PRAGMA_NOCOVER in line:
|
outfile.write(">>>>>> ")
|
||||||
outfile.write(">>>>>> ")
|
n_lines += 1
|
||||||
n_lines += 1
|
else:
|
||||||
else:
|
outfile.write(" ")
|
||||||
outfile.write(" ")
|
|
||||||
outfile.write(line.expandtabs(8))
|
outfile.write(line.expandtabs(8))
|
||||||
|
|
||||||
return n_hits, n_lines
|
return n_hits, n_lines
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Fix output of cover files for ``trace`` module command-line tool.
|
||||||
|
Previously emitted cover files only when ``--missing`` option was used.
|
||||||
|
Patch by Michael Selik.
|
Loading…
Reference in New Issue