summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNed Batchelder <ned@nedbatchelder.com>2009-12-20 11:03:33 -0500
committerNed Batchelder <ned@nedbatchelder.com>2009-12-20 11:03:33 -0500
commit30c191f13fe5d397d1b624b4894f2c6bd841a389 (patch)
tree70fc7cc600eecfd84697c4be10556dcb3ac7263c
parentd17aeb10e55585a23702737087afc60a35d3123c (diff)
downloadpython-coveragepy-git-30c191f13fe5d397d1b624b4894f2c6bd841a389.tar.gz
Jumps to jumps could make loops look like they go places they really don't, so start new chunks for every absolute jump. Fixes issue #39.
-rw-r--r--CHANGES.txt5
-rw-r--r--coverage/parser.py15
-rw-r--r--lab/cmd-opts.txt8
-rw-r--r--test/test_arcs.py27
4 files changed, 50 insertions, 5 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index adff817b..cdb76a40 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -8,8 +8,13 @@ Version 3.3
- Settings are now read from a .coveragerc file.
+- Fixed a problem with nested loops having their branch possibilities
+ mischaracterized: `issue 39`_.
+
- Added an AUTHORS.txt file.
+.. _issue 39: http://bitbucket.org/ned/coveragepy/issue/39
+
Version 3.2, 5 December 2009
----------------------------
diff --git a/coverage/parser.py b/coverage/parser.py
index cf462181..aea05f3d 100644
--- a/coverage/parser.py
+++ b/coverage/parser.py
@@ -256,6 +256,11 @@ OPS_CHUNK_END = _opcode_set(
'BREAK_LOOP', 'CONTINUE_LOOP',
)
+# Opcodes that unconditionally begin a new code chunk. By starting new chunks
+# with unconditional jump instructions, we neatly deal with jumps to jumps
+# properly.
+OPS_CHUNK_BEGIN = _opcode_set('JUMP_ABSOLUTE', 'JUMP_FORWARD')
+
# Opcodes that push a block on the block stack.
OPS_PUSH_BLOCK = _opcode_set('SETUP_LOOP', 'SETUP_EXCEPT', 'SETUP_FINALLY')
@@ -399,12 +404,20 @@ class ByteParser(object):
ult = penult = None
for bc in ByteCodes(self.code.co_code):
- # Maybe have to start a new block
+ # Maybe have to start a new chunk
if bc.offset in bytes_lines_map:
+ # Start a new chunk for each source line number.
if chunk:
chunk.exits.add(bc.offset)
chunk = Chunk(bc.offset, bytes_lines_map[bc.offset])
chunks.append(chunk)
+ elif bc.op in OPS_CHUNK_BEGIN:
+ # Jumps deserve their own unnumbered chunk. This fixes
+ # problems with jumps to jumps getting confused.
+ if chunk:
+ chunk.exits.add(bc.offset)
+ chunk = Chunk(bc.offset)
+ chunks.append(chunk)
if not chunk:
chunk = Chunk(bc.offset)
diff --git a/lab/cmd-opts.txt b/lab/cmd-opts.txt
index fed7b0f1..5b1f78e2 100644
--- a/lab/cmd-opts.txt
+++ b/lab/cmd-opts.txt
@@ -46,10 +46,10 @@ commands:
--timid bool [run].timid
- --include=directory [run].include
- --include=filename
- --include=module
- --exclude=directory [run].exclude
+ --include=directory * [run].include
+ --include=filename *
+ --include=module *
+ --exclude=directory * [run].exclude
diff --git a/test/test_arcs.py b/test/test_arcs.py
index cbd7645d..f93e1f55 100644
--- a/test/test_arcs.py
+++ b/test/test_arcs.py
@@ -229,6 +229,33 @@ class LoopArcTest(CoverageTest):
arcz_missing="27" # while loop never exits naturally.
)
+ def test_for_if_else_for(self):
+ self.check_coverage("""\
+ def branches_2(l):
+ if l:
+ for e in l:
+ a = 4
+ else:
+ a = 6
+
+ def branches_3(l):
+ for x in l:
+ if x:
+ for e in l:
+ a = 12
+ else:
+ a = 14
+
+ branches_2([0,1])
+ branches_3([0,1])
+ """,
+ arcz=
+ ".1 18 8G GH H. "
+ ".2 23 34 43 26 3. 6. "
+ ".9 9A 9. AB BC CB B9 AE E9",
+ arcz_missing="26 6."
+ )
+
class ExceptionArcTest(CoverageTest):
"""Arc-measuring tests involving exception handling."""