summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt9
-rw-r--r--coverage/bytecode.py16
-rw-r--r--lab/show_pyc.py2
-rw-r--r--tests/coveragetest.py12
-rw-r--r--tests/test_arcs.py21
5 files changed, 51 insertions, 9 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index f96db6e..cab00a9 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -3,6 +3,15 @@ Change history for Coverage.py
------------------------------
+Latest
+------
+
+- Branch coverage couldn't properly handle certain extremely long files. This
+ is now fixed (`issue 359`_).
+
+.. _issue 359: https://bitbucket.org/ned/coveragepy/issue/359/xml-report-chunk-error
+
+
Version 4.0a5 --- 16 February 2015
----------------------------------
diff --git a/coverage/bytecode.py b/coverage/bytecode.py
index 3f62dfa..d730493 100644
--- a/coverage/bytecode.py
+++ b/coverage/bytecode.py
@@ -1,9 +1,11 @@
"""Bytecode manipulation for coverage.py"""
-import opcode, types
+import opcode
+import types
from coverage.backward import byte_to_int
+
class ByteCode(object):
"""A single bytecode."""
def __init__(self):
@@ -26,6 +28,9 @@ class ByteCode(object):
class ByteCodes(object):
"""Iterator over byte codes in `code`.
+ This handles the logic of EXTENDED_ARG byte codes internally. Those byte
+ codes are not returned by this iterator.
+
Returns `ByteCode` objects.
"""
@@ -37,6 +42,7 @@ class ByteCodes(object):
def __iter__(self):
offset = 0
+ ext_arg = 0
while offset < len(self.code):
bc = ByteCode()
bc.op = self[offset]
@@ -44,7 +50,7 @@ class ByteCodes(object):
next_offset = offset+1
if bc.op >= opcode.HAVE_ARGUMENT:
- bc.arg = self[offset+1] + 256*self[offset+2]
+ bc.arg = ext_arg + self[offset+1] + 256*self[offset+2]
next_offset += 2
label = -1
@@ -55,7 +61,11 @@ class ByteCodes(object):
bc.jump_to = label
bc.next_offset = offset = next_offset
- yield bc
+ if bc.op == opcode.EXTENDED_ARG:
+ ext_arg = bc.arg * 256*256
+ else:
+ ext_arg = 0
+ yield bc
class CodeObjects(object):
diff --git a/lab/show_pyc.py b/lab/show_pyc.py
index b2cbb34..d6bbd92 100644
--- a/lab/show_pyc.py
+++ b/lab/show_pyc.py
@@ -4,7 +4,7 @@ def show_pyc_file(fname):
f = open(fname, "rb")
magic = f.read(4)
moddate = f.read(4)
- modtime = time.asctime(time.localtime(struct.unpack('L', moddate)[0]))
+ modtime = time.asctime(time.localtime(struct.unpack('<L', moddate)[0]))
print "magic %s" % (magic.encode('hex'))
print "moddate %s (%s)" % (moddate.encode('hex'), modtime)
code = marshal.load(f)
diff --git a/tests/coveragetest.py b/tests/coveragetest.py
index d673f6d..cf3d247 100644
--- a/tests/coveragetest.py
+++ b/tests/coveragetest.py
@@ -149,7 +149,8 @@ class CoverageTest(
def check_coverage(
self, text, lines=None, missing="", report="",
excludes=None, partials="",
- arcz=None, arcz_missing="", arcz_unpredicted=""
+ arcz=None, arcz_missing=None, arcz_unpredicted=None,
+ arcs=None, arcs_missing=None, arcs_unpredicted=None,
):
"""Check the coverage measurement of `text`.
@@ -172,11 +173,12 @@ class CoverageTest(
self.make_file(modname+".py", text)
- arcs = arcs_missing = arcs_unpredicted = None
- if arcz is not None:
+ if arcs is None and arcz is not None:
arcs = self.arcz_to_arcs(arcz)
- arcs_missing = self.arcz_to_arcs(arcz_missing or "")
- arcs_unpredicted = self.arcz_to_arcs(arcz_unpredicted or "")
+ if arcs_missing is None and arcz_missing is not None:
+ arcs_missing = self.arcz_to_arcs(arcz_missing)
+ if arcs_unpredicted is None and arcz_unpredicted is not None:
+ arcs_unpredicted = self.arcz_to_arcs(arcz_unpredicted)
# Start up Coverage.
cov = coverage.coverage(branch=(arcs_missing is not None))
diff --git a/tests/test_arcs.py b/tests/test_arcs.py
index d3717a8..42e1051 100644
--- a/tests/test_arcs.py
+++ b/tests/test_arcs.py
@@ -575,6 +575,27 @@ class MiscArcTest(CoverageTest):
""",
arcz=".1 19 9.")
+ def test_pathologically_long_code_object(self):
+ # https://bitbucket.org/ned/coveragepy/issue/359
+ # The structure of this file is such that an EXTENDED_ARG byte code is
+ # needed to encode the jump at the end. We weren't interpreting those
+ # opcodes.
+ code = """\
+ data = [
+ """ + "".join("""\
+ [{i}, {i}, {i}, {i}, {i}, {i}, {i}, {i}, {i}, {i}],
+ """.format(i=i) for i in range(2000)
+ ) + """\
+ ]
+
+ if __name__ == "__main__":
+ print(len(data))
+ """
+ self.check_coverage(
+ code,
+ arcs=[(-1, 1), (1, 2004), (2004, -2), (2004, 2005), (2005, -2)],
+ )
+
class ExcludeTest(CoverageTest):
"""Tests of exclusions to indicate known partial branches."""