diff options
author | Ned Batchelder <ned@nedbatchelder.com> | 2009-10-16 07:25:56 -0400 |
---|---|---|
committer | Ned Batchelder <ned@nedbatchelder.com> | 2009-10-16 07:25:56 -0400 |
commit | 9ca8f380e28b3bd315708da4d0c879549f9e3e42 (patch) | |
tree | 8fbc0925eb2bd741a62a829c4cb41dc2414cc105 /coverage | |
parent | 86f2a554175d899a227c726e9a894f8cfcba985e (diff) | |
download | python-coveragepy-9ca8f380e28b3bd315708da4d0c879549f9e3e42.tar.gz |
Start unit testing the arc measurement. In arcs, -1 means enter or exit.
Diffstat (limited to 'coverage')
-rw-r--r-- | coverage/collector.py | 6 | ||||
-rw-r--r-- | coverage/control.py | 35 | ||||
-rw-r--r-- | coverage/data.py | 4 | ||||
-rw-r--r-- | coverage/parser.py | 26 |
4 files changed, 42 insertions, 29 deletions
diff --git a/coverage/collector.py b/coverage/collector.py index aadbab7..bc70027 100644 --- a/coverage/collector.py +++ b/coverage/collector.py @@ -49,7 +49,7 @@ class PyTracer: if frame == self.last_exc_back: # Someone forgot a return event. if self.arcs and self.cur_file_data: - self.cur_file_data[(self.last_line, 0)] = None + self.cur_file_data[(self.last_line, -1)] = None self.cur_file_data, self.last_line = self.data_stack.pop() self.last_exc_back = None @@ -65,7 +65,7 @@ class PyTracer: self.cur_file_data = self.data[tracename] else: self.cur_file_data = None - self.last_line = 0 + self.last_line = -1 elif event == 'line': # Record an executed line. if self.cur_file_data is not None: @@ -76,7 +76,7 @@ class PyTracer: self.last_line = frame.f_lineno elif event == 'return': if self.arcs and self.cur_file_data: - self.cur_file_data[(self.last_line, 0)] = None + self.cur_file_data[(self.last_line, -1)] = None # Leaving this function, pop the filename stack. self.cur_file_data, self.last_line = self.data_stack.pop() elif event == 'exception': diff --git a/coverage/control.py b/coverage/control.py index ce79cd3..952897d 100644 --- a/coverage/control.py +++ b/coverage/control.py @@ -3,7 +3,7 @@ import os, socket from coverage.annotate import AnnotateReporter -from coverage.backward import string_class +from coverage.backward import string_class, sorted # pylint: disable-msg=W0622 from coverage.codeunit import code_unit_factory, CodeUnit from coverage.collector import Collector from coverage.data import CoverageData @@ -330,45 +330,54 @@ class Analysis: """The results of analyzing a code unit.""" def __init__(self, cov, code_unit): + self.coverage = cov self.code_unit = code_unit from coverage.parser import CodeParser - filename = code_unit.filename - ext = os.path.splitext(filename)[1] + self.filename = self.code_unit.filename + ext = os.path.splitext(self.filename)[1] source = None if ext == '.py': - if not os.path.exists(filename): - source = cov.file_locator.get_zip_data(filename) + if not os.path.exists(self.filename): + source = self.coverage.file_locator.get_zip_data(self.filename) if not source: raise CoverageException( - "No source for code '%s'." % code_unit.filename + "No source for code '%s'." % self.filename ) self.parser = CodeParser( - text=source, filename=filename, exclude=cov.exclude_re + text=source, filename=self.filename, exclude=self.coverage.exclude_re ) self.statements, self.excluded, line_map = self.parser.parse_source() # Identify missing statements. self.missing = [] - execed = cov.data.executed_lines(filename) + self.executed = self.coverage.data.executed_lines(self.filename) for line in self.statements: lines = line_map.get(line) if lines: for l in range(lines[0], lines[1]+1): - if l in execed: + if l in self.executed: break else: self.missing.append(line) else: - if line not in execed: + if line not in self.executed: self.missing.append(line) - self.filename = self.code_unit.filename - def missing_formatted(self): return format_lines(self.statements, self.missing) - def arc_info(self): + def arc_possibilities(self): return self.parser.arc_info() + + def arcs_executed(self): + return self.coverage.data.executed_arcs(self.filename) + + def arcs_missing(self): + possible = self.arc_possibilities() + executed = self.arcs_executed() + missing = [p for p in possible if p not in executed] + return sorted(missing) + diff --git a/coverage/data.py b/coverage/data.py index 26dc5aa..0c1fc3a 100644 --- a/coverage/data.py +++ b/coverage/data.py @@ -198,6 +198,10 @@ class CoverageData: """ return self.lines.get(filename) or {} + def executed_arcs(self, filename): + """A map containing all the arcs executed in `filename`.""" + return self.arcs.get(filename) or {} + def summary(self, fullpath=False): """Return a dict summarizing the coverage data. diff --git a/coverage/parser.py b/coverage/parser.py index ba28102..9460f08 100644 --- a/coverage/parser.py +++ b/coverage/parser.py @@ -2,7 +2,7 @@ import glob, opcode, os, re, sys, token, tokenize -from coverage.backward import set, StringIO # pylint: disable-msg=W0622 +from coverage.backward import set, sorted, StringIO # pylint: disable-msg=W0622 from coverage.bytecode import ByteCodes, CodeObjects from coverage.misc import nice_pair, CoverageException @@ -148,8 +148,7 @@ class CodeParser: if new_l not in ignore: lset.add(new_l) lines = list(lset) - lines.sort() - return lines + return sorted(lines) def parse_source(self): """Parse source text to find executable lines, excluded lines, etc. @@ -169,7 +168,8 @@ class CodeParser: def arc_info(self): """Get information about the arcs available in the code.""" - return self.byte_parser._all_arcs() + arcs = self.byte_parser._all_arcs() + return sorted(arcs) class ByteParser: @@ -281,7 +281,7 @@ class ByteParser: class Chunk(object): """A sequence of bytecodes with exits to other bytecodes. - An exit of None means the chunk can leave the code block (return). + An exit of -1 means the chunk can leave the code block (return). """ def __init__(self, byte, line=0): @@ -313,7 +313,7 @@ class ByteParser: chunk.exits.add(bc.jump_to) if bc.op in self._code_enders: - chunk.exits.add(None) + chunk.exits.add(-1) if bc.op in self._chunk_enders: chunk = None @@ -332,12 +332,12 @@ class ByteParser: byte_chunks = dict([(c.byte, c) for c in chunks]) # Build a map from byte offsets to actual lines reached. - byte_lines = {None:[None]} + byte_lines = {-1:[-1]} bytes_to_add = set([c.byte for c in chunks]) while bytes_to_add: byte_to_add = bytes_to_add.pop() - if byte_to_add in byte_lines or byte_to_add is None: + if byte_to_add in byte_lines or byte_to_add == -1: continue # Which lines does this chunk lead to? @@ -365,8 +365,8 @@ class ByteParser: lines.add(ch.line) else: for ex in ch.exits: - if ex is None: - lines.add(None) + if ex == -1: + lines.add(-1) elif ex not in bytes_considered: bytes_to_consider.append(ex) @@ -382,7 +382,7 @@ class ByteParser: for exit_line in byte_lines[ex]: arcs.add((chunk.line, exit_line)) for line in byte_lines[0]: - arcs.add((None, line)) + arcs.add((-1, line)) return arcs @@ -472,9 +472,9 @@ class AdHocMain(object): arc_chars = {} if options.chunks: for lfrom, lto in sorted(arcs): - if lfrom is None: + if lfrom == -1: arc_chars[lto] = arc_chars.get(lto, '') + 'v' - elif lto is None: + elif lto == -1: arc_chars[lfrom] = arc_chars.get(lfrom, '') + '^' else: if lfrom == lto-1: |