diff options
-rw-r--r-- | CHANGES.txt | 5 | ||||
-rw-r--r-- | coverage/parser.py | 15 | ||||
-rw-r--r-- | lab/cmd-opts.txt | 8 | ||||
-rw-r--r-- | test/test_arcs.py | 27 |
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.""" |