diff options
-rw-r--r-- | CHANGES.txt | 9 | ||||
-rw-r--r-- | coverage/bytecode.py | 16 | ||||
-rw-r--r-- | lab/show_pyc.py | 2 | ||||
-rw-r--r-- | tests/coveragetest.py | 12 | ||||
-rw-r--r-- | tests/test_arcs.py | 21 |
5 files changed, 51 insertions, 9 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index f96db6e5..cab00a94 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 3f62dfaf..d7304936 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 b2cbb342..d6bbd921 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 d673f6d6..cf3d2474 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 d3717a88..42e10510 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.""" |