def setUp(self): if self.run_in_temp_dir: # Create a temporary directory. self.noise = str(random.random())[2:] self.temp_root = os.path.join(tempfile.gettempdir(), 'test_cover') self.temp_dir = os.path.join(self.temp_root, self.noise) os.makedirs(self.temp_dir) self.old_dir = os.getcwd() os.chdir(self.temp_dir) # Modules should be importable from this temp directory. self.old_syspath = sys.path[:] sys.path.insert(0, '') # Keep a counter to make every call to check_coverage unique. self.n = 0 # Record environment variables that we changed with set_environ. self.environ_undos = {} # Capture stdout and stderr so we can examine them in tests. # nose keeps stdout from littering the screen, so we can safely Tee it, # but it doesn't capture stderr, so we don't want to Tee stderr to the # real stderr, since it will interfere with our nice field of dots. self.old_stdout = sys.stdout self.captured_stdout = StringIO() sys.stdout = Tee(sys.stdout, self.captured_stdout) self.old_stderr = sys.stderr self.captured_stderr = StringIO() sys.stderr = self.captured_stderr # Record sys.modules here so we can restore it in tearDown. self.old_modules = dict(sys.modules)
def setUp(self): super(CoverageTest, self).setUp() if _TEST_NAME_FILE: f = open(_TEST_NAME_FILE, "w") f.write("%s_%s" % (self.__class__.__name__, self._testMethodName)) f.close() # Tell newer unittest implementations to print long helpful messages. self.longMessage = True # tearDown will restore the original sys.path self.old_syspath = sys.path[:] if self.run_in_temp_dir: # Create a temporary directory. self.noise = str(random.random())[2:] self.temp_root = os.path.join(tempfile.gettempdir(), 'test_cover') self.temp_dir = os.path.join(self.temp_root, self.noise) os.makedirs(self.temp_dir) self.old_dir = os.getcwd() os.chdir(self.temp_dir) # Modules should be importable from this temp directory. We don't # use '' because we make lots of different temp directories and # nose's caching importer can get confused. The full path prevents # problems. sys.path.insert(0, os.getcwd()) # Keep a counter to make every call to check_coverage unique. self.n = 0 # Record environment variables that we changed with set_environ. self.environ_undos = {} # Capture stdout and stderr so we can examine them in tests. # nose keeps stdout from littering the screen, so we can safely Tee it, # but it doesn't capture stderr, so we don't want to Tee stderr to the # real stderr, since it will interfere with our nice field of dots. self.old_stdout = sys.stdout self.captured_stdout = StringIO() sys.stdout = Tee(sys.stdout, self.captured_stdout) self.old_stderr = sys.stderr self.captured_stderr = StringIO() sys.stderr = self.captured_stderr # Record sys.modules here so we can restore it in tearDown. self.old_modules = dict(sys.modules) class_behavior = self.class_behavior() class_behavior.tests += 1 class_behavior.test_method_made_any_files = False class_behavior.temp_dir = self.run_in_temp_dir
def setUp(self): super(StdStreamCapturingMixin, self).setUp() # Capture stdout and stderr so we can examine them in tests. # nose keeps stdout from littering the screen, so we can safely Tee it, # but it doesn't capture stderr, so we don't want to Tee stderr to the # real stderr, since it will interfere with our nice field of dots. self.old_stdout = sys.stdout self.captured_stdout = StringIO() sys.stdout = Tee(sys.stdout, self.captured_stdout) self.old_stderr = sys.stderr self.captured_stderr = StringIO() sys.stderr = self.captured_stderr self.addCleanup(self.cleanup_std_streams)
def test_plugin_sys_info(self): self.make_file( "plugin_sys_info.py", """\ import coverage class Plugin(coverage.CoveragePlugin): def sys_info(self): return [("hello", "world")] def coverage_init(reg, options): reg.add_noop(Plugin()) """) debug_out = StringIO() cov = coverage.Coverage(debug=["sys"]) cov._debug_file = debug_out cov.set_option("run:plugins", ["plugin_sys_info"]) cov.load() out_lines = debug_out.getvalue().splitlines() expected_end = [ "-- sys: plugin_sys_info.Plugin -------------------------------", " hello: world", "-- end -------------------------------------------------------", ] self.assertEqual(expected_end, out_lines[-len(expected_end):])
def source_token_lines(source): ws_tokens = [token.INDENT, token.DEDENT, token.NEWLINE, tokenize.NL] line = [] col = 0 source = source.expandtabs(8).replace('\r\n', '\n') tokgen = tokenize.generate_tokens(StringIO(source).readline) for ttype, ttext, (_, scol), (_, ecol), _ in phys_tokens(tokgen): mark_start = True for part in re.split('(\n)', ttext): if part == '\n': yield line line = [] col = 0 mark_end = False elif part == '': mark_end = False elif ttype in ws_tokens: mark_end = False else: if mark_start and scol > col: line.append(('ws', ' ' * (scol - col))) mark_start = False tok_class = tokenize.tok_name.get(ttype, 'xx').lower()[:3] if ttype == token.NAME and keyword.iskeyword(ttext): tok_class = 'key' line.append((tok_class, part)) mark_end = True scol = 0 if mark_end: col = ecol if line: yield line
def test_plugin_sys_info(self): self.make_file("plugin_sys_info.py", """\ import coverage class Plugin(coverage.CoveragePlugin): def sys_info(self): return [("hello", "world")] def coverage_init(reg, options): reg.add_file_tracer(Plugin()) """) debug_out = StringIO() cov = coverage.Coverage(debug=["sys"]) cov._debug_file = debug_out cov.set_option("run:plugins", ["plugin_sys_info"]) cov.start() cov.stop() # pragma: nested out_lines = [line.strip() for line in debug_out.getvalue().splitlines()] if env.C_TRACER: assert 'plugins.file_tracers: plugin_sys_info.Plugin' in out_lines else: assert 'plugins.file_tracers: plugin_sys_info.Plugin (disabled)' in out_lines assert 'plugins.configurers: -none-' in out_lines expected_end = [ "-- sys: plugin_sys_info.Plugin -------------------------------", "hello: world", "-- end -------------------------------------------------------", ] assert expected_end == out_lines[-len(expected_end):]
def pretend_to_be_pytestcov(self, append): """Act like pytest-cov.""" self.make_file("prog.py", """\ a = 1 b = 2 if b == 1: c = 4 """) self.make_file(".coveragerc", """\ [run] parallel = True source = . """) cov = coverage.Coverage(source=None, branch=None, config_file='.coveragerc') if append: cov.load() else: cov.erase() self.start_import_stop(cov, "prog") cov.combine() cov.save() report = StringIO() cov.report(show_missing=None, ignore_errors=True, file=report, skip_covered=None, skip_empty=None) assert report.getvalue() == textwrap.dedent("""\ Name Stmts Miss Cover ----------------------------- prog.py 4 1 75% ----------------------------- TOTAL 4 1 75% """) self.assert_file_count(".coverage", 0) self.assert_file_count(".coverage.*", 1)
def source_file(self): if os.path.exists(self.filename): return open_source(self.filename) source = self.file_locator.get_zip_data(self.filename) if source is not None: return StringIO(source) raise CoverageException("No source for code '%s'." % self.filename)
def test_plugin_with_no_sys_info(self): self.make_file("plugin_no_sys_info.py", """\ import coverage class Plugin(coverage.CoveragePlugin): pass def coverage_init(reg, options): reg.add_configurer(Plugin()) """) debug_out = StringIO() cov = coverage.Coverage(debug=["sys"]) cov._debug_file = debug_out cov.set_option("run:plugins", ["plugin_no_sys_info"]) cov.start() cov.stop() # pragma: nested out_lines = [line.strip() for line in debug_out.getvalue().splitlines()] self.assertIn('plugins.file_tracers: -none-', out_lines) self.assertIn('plugins.configurers: plugin_no_sys_info.Plugin', out_lines) expected_end = [ "-- sys: plugin_no_sys_info.Plugin ----------------------------", "-- end -------------------------------------------------------", ] self.assertEqual(expected_end, out_lines[-len(expected_end):])
def test_plugin_init(self): self.make_file('coveragerc_test_config', '') debug_out = StringIO() cov = Coverage(config_file='coveragerc_test_config', debug=['sys']) cov._debug_file = debug_out cov.set_option('run:plugins', ['coverage_config_reload_plugin']) cov.start() cov.stop() out_lines = [ line.strip() for line in debug_out.getvalue().splitlines() ] self.assertIn('plugins.file_tracers: -none-', out_lines) expected_end = [ '-- sys: coverage_config_reload_plugin.ConfigReloadPlugin -----', 'configreload: True', '-- end -------------------------------------------------------', ] self.assertEqual(expected_end, out_lines[-len(expected_end):]) if LooseVersion(coverage_version) >= LooseVersion('4.6'): self.assertIn( 'plugins.configurers: coverage_config_reload_plugin.ConfigReloadPlugin', out_lines)
def _check_config(self, filename, own_rc): section = 'report' if own_rc else 'coverage:report' # Force own rc for pre 4.4.1 if LooseVersion(coverage_version) < LooseVersion('4.4.1'): self.make_file( filename, """\ [report] ignore_errors = true """) else: self.make_file( filename, """\ [{}] ignore_errors = true """.format(section)) debug_out = StringIO() cov = Coverage(config_file=filename, debug=['sys']) assert cov.config.get_option('report:ignore_errors') is True cov._debug_file = debug_out self.make_file( filename, """\ [{}] ignore_errors = off """.format(section)) cov.set_option('run:plugins', ['coverage_config_reload_plugin']) cov.start() cov.stop() assert cov.config.get_option('report:ignore_errors') is False
def get_report(self, cov): """Get the report from `cov`, and canonicalize it.""" repout = StringIO() cov.report(file=repout, show_missing=False) report = repout.getvalue().replace('\\', '/') report = re.sub(r" +", " ", report) return report
def source_file(self): """Return an open file for reading the source of the code unit.""" if os.path.exists(self.filename): return open_source(self.filename) source = self.file_locator.get_zip_data(self.filename) if source is not None: return StringIO(source) raise CoverageException("No source for code '%s'." % self.filename)
def generate_tokens(self, text): """A stand-in for `tokenize.generate_tokens`.""" if text != self.last_text: self.last_text = text self.last_tokens = list( tokenize.generate_tokens(StringIO(text).readline) ) return self.last_tokens
def coverage_usepkgs(self, **kwargs): """Try coverage.report().""" cov = coverage.Coverage() cov.start() import usepkgs # pragma: nested # pylint: disable=import-error, unused-variable cov.stop() # pragma: nested report = StringIO() cov.report(file=report, **kwargs) return report.getvalue()
def coverage_usepkgs(self, **kwargs): """Try coverage.report().""" cov = coverage.coverage() cov.start() import usepkgs # pragma: nested # pylint: disable=F0401,W0612 cov.stop() # pragma: nested report = StringIO() cov.report(file=report, **kwargs) return report.getvalue()
def test_read_and_write_are_opposites(self): covdata1 = CoverageData() covdata1.add_arcs(ARCS_3) stringio = StringIO() covdata1.write_fileobj(stringio) stringio.seek(0) covdata2 = CoverageData() covdata2.read_fileobj(stringio) self.assert_arcs3_data(covdata2)
def get_summary_text(self, coverage_data, options): """Get text output from the SummaryReporter.""" cov = Coverage() cov.start() cov.stop() # pragma: nested cov.data = coverage_data printer = SummaryReporter(cov, options) destination = StringIO() printer.report([], destination) return destination.getvalue()
def test_defer_to_python(self): # A plugin that measures, but then wants built-in python reporting. self.make_file( "fairly_odd_plugin.py", """\ # A plugin that claims all the odd lines are executed, and none of # the even lines, and then punts reporting off to the built-in # Python reporting. import coverage.plugin class Plugin(coverage.CoveragePlugin): def file_tracer(self, filename): return OddTracer(filename) def file_reporter(self, filename): return "python" class OddTracer(coverage.plugin.FileTracer): def __init__(self, filename): self.filename = filename def source_filename(self): return self.filename def line_number_range(self, frame): lineno = frame.f_lineno if lineno % 2: return (lineno, lineno) else: return (-1, -1) def coverage_init(reg, options): reg.add_file_tracer(Plugin()) """) self.make_file( "unsuspecting.py", """\ a = 1 b = 2 c = 3 d = 4 e = 5 f = 6 """) cov = coverage.Coverage(include=["unsuspecting.py"]) cov.set_option("run:plugins", ["fairly_odd_plugin"]) self.start_import_stop(cov, "unsuspecting") repout = StringIO() total = cov.report(file=repout, show_missing=True) report = repout.getvalue().splitlines() expected = [ 'Name Stmts Miss Cover Missing', '-----------------------------------------------', 'unsuspecting.py 6 3 50% 2, 4, 6', '-----------------------------------------------', 'TOTAL 6 3 50%', ] assert expected == report assert total == 50
def test_report_file(self): # The file= argument of coverage.report makes the report go there. self.do_report_work("mycode3") fout = StringIO() coverage.report(["mycode3.py"], file=fout) self.assertEqual(self.stdout(), "") self.assertEqual(fout.getvalue(), textwrap.dedent("""\ Name Stmts Miss Cover Missing --------------------------------------- mycode3 7 3 57% 4-6 """))
def source_file(self): """Return an open file for reading the source of the code unit.""" if os.path.exists(self.filename): # A regular text file: open it. return open_source(self.filename) # Maybe it's in a zip file? source = self.file_locator.get_zip_data(self.filename) if source is not None: return StringIO(source) # Couldn't find source. raise CoverageException("No source for code %r." % self.filename)
def source_token_lines(source): """Generate a series of lines, one for each line in `source`. Each line is a list of pairs, each pair is a token:: [('key', 'def'), ('ws', ' '), ('nam', 'hello'), ('op', '('), ... ] Each pair has a token class, and the token text. If you concatenate all the token texts, and then join them with newlines, you should have your original `source` back, with two differences: trailing whitespace is not preserved, and a final line with no newline is indistinguishable from a final line with a newline. """ ws_tokens = [token.INDENT, token.DEDENT, token.NEWLINE, tokenize.NL] line = [] col = 0 source = source.expandtabs(8).replace('\r\n', '\n') tokgen = tokenize.generate_tokens(StringIO(source).readline) for ttype, ttext, (_, scol), (_, ecol), _ in phys_tokens(tokgen): mark_start = True for part in re.split('(\n)', ttext): if part == '\n': yield line line = [] col = 0 mark_end = False elif part == '': mark_end = False elif ttype in ws_tokens: mark_end = False else: if mark_start and scol > col: line.append(('ws', ' ' * (scol - col))) mark_start = False tok_class = tokenize.tok_name.get(ttype, 'xx').lower()[:3] if ttype == token.NAME and keyword.iskeyword(ttext): tok_class = 'key' line.append((tok_class, part)) mark_end = True scol = 0 if mark_end: col = ecol if line: yield line
def _raw_parse(self): """Parse the source to find the interesting facts about its lines. A handful of member fields are updated. """ if self.exclude: self.excluded = self.lines_matching(self.exclude) indent = 0 exclude_indent = 0 excluding = False prev_toktype = token.INDENT first_line = None empty = True tokgen = tokenize.generate_tokens(StringIO(self.text).readline) for toktype, ttext, (slineno, _), (elineno, _), ltext in tokgen: if self.show_tokens: print '%10s %5s %-20r %r' % (tokenize.tok_name.get( toktype, toktype), nice_pair( (slineno, elineno)), ttext, ltext) if toktype == token.INDENT: indent += 1 elif toktype == token.DEDENT: indent -= 1 elif toktype == token.NAME and ttext == 'class': self.classdefs.add(slineno) elif toktype == token.OP and ttext == ':': if not excluding and elineno in self.excluded: exclude_indent = indent excluding = True elif toktype == token.STRING and prev_toktype == token.INDENT: self.docstrings.update(range(slineno, elineno + 1)) elif toktype == token.NEWLINE: if first_line is not None and elineno != first_line: rng = (first_line, elineno) for l in range(first_line, elineno + 1): self.multiline[l] = rng first_line = None if ttext.strip() and toktype != tokenize.COMMENT: empty = False if first_line is None: first_line = slineno if excluding and indent <= exclude_indent: excluding = False if excluding: self.excluded.add(elineno) prev_toktype = toktype if not empty: self.statement_starts.update(self.byte_parser._find_statements())
def test_empty_files(self): # Shows that empty files like __init__.py are listed as having zero # statements, not one statement. cov = coverage.Coverage(branch=True) cov.start() import usepkgs # pragma: nested # pylint: disable=import-error, unused-variable cov.stop() # pragma: nested repout = StringIO() cov.report(file=repout, show_missing=False) report = repout.getvalue().replace('\\', '/') report = re.sub(r"\s+", " ", report) self.assertIn("tests/modules/pkg1/__init__.py 2 0 0 0 100%", report) self.assertIn("tests/modules/pkg2/__init__.py 0 0 0 0 100%", report)
def test_empty_files(self): # Shows that empty files like __init__.py are listed as having zero # statements, not one statement. cov = coverage.coverage() cov.start() import usepkgs # pylint: disable=F0401,W0612 cov.stop() repout = StringIO() cov.report(file=repout, show_missing=False) report = repout.getvalue().replace('\\', '/') report = re.sub(r"\s+", " ", report) self.assert_("test/modules/pkg1/__init__ 1 0 100%" in report) self.assert_("test/modules/pkg2/__init__ 0 0 100%" in report)
def get_summary_text(self, options): """Get text output from the SummaryReporter.""" self.make_rigged_file("file1.py", 339, 155) self.make_rigged_file("file2.py", 13, 3) self.make_rigged_file("file3.py", 234, 228) self.make_file("doit.py", "import file1, file2, file3") cov = Coverage(source=["."], omit=["doit.py"]) cov.start() import doit # pragma: nested # pylint: disable=import-error, unused-import cov.stop() # pragma: nested printer = SummaryReporter(cov, options) destination = StringIO() printer.report([], destination) return destination.getvalue()
def test_should_trace_cache(self): # The tracers should only invoke should_trace once for each file name. # TODO: Might be better to do this with a mocked _should_trace, # rather than by examining debug output. # Make some files that invoke each other. self.make_file( "f1.py", """\ def f1(x, f): return f(x) """) self.make_file( "f2.py", """\ import f1 def func(x): return f1.f1(x, otherfunc) def otherfunc(x): return x*x for i in range(10): func(i) """) # Trace one file, but not the other, and get the debug output. debug_out = StringIO() cov = coverage.coverage(include=["f1.py"], debug=['trace'], debug_file=debug_out) # Import the python file, executing it. self.start_import_stop(cov, "f2") # Grab all the filenames mentioned in debug output, there should be no # duplicates. trace_lines = [ l for l in debug_out.getvalue().splitlines() if l.startswith("Tracing ") or l.startswith("Not tracing ") ] filenames = [re.search(r"'[^']+'", l).group() for l in trace_lines] self.assertEqual(len(filenames), len(set(filenames))) # Double-check that the tracing messages are in there somewhere. self.assertGreater(len(filenames), 5)
def f1_debug_output(self, debug): """Runs some code with `debug` option, returns the debug output.""" # Make code to run. self.make_file("f1.py", """\ def f1(x): return x+1 for i in range(5): f1(i) """) debug_out = StringIO() cov = coverage.coverage(debug=debug, debug_file=debug_out) self.start_import_stop(cov, "f1") out_lines = debug_out.getvalue().splitlines() return out_lines
def test_reload_plugin_init(self): self._reset_env() self.make_file( '.coveragerc', """\ [run] plugins = coverage_env_plugin, coverage_config_reload_plugin [coverage_env_plugin] markers = True [report] exclude_lines = pragma ${OS_NAME}: no cover """) debug_out = StringIO() cov = Coverage(config_file='.coveragerc', debug=['sys']) cov._debug_file = debug_out cov.set_option( 'run:plugins', ['coverage_env_plugin', 'coverage_config_reload_plugin']) cov.start() cov.stop() assert cov.config.get_option('coverage_env_plugin:markers') == 'True' out_lines = [ line.strip() for line in debug_out.getvalue().splitlines() ] self.assertIn('plugins.file_tracers: -none-', out_lines) if LooseVersion(config_reload_version) >= LooseVersion('0.3.0'): expected_end = [ '-- sys: coverage_config_reload_plugin.ConfigReloadPlugin -----', 'configreload: True', '-- end -------------------------------------------------------', ] self.assertEqual(expected_end, out_lines[-len(expected_end):]) if LooseVersion(coverage_version) >= LooseVersion('4.6'): self.assertIn( 'plugins.configurers: coverage_config_reload_plugin.ConfigReloadPlugin', out_lines)
def test_plugin_with_no_sys_info(self): self.make_file( "plugin_no_sys_info.py", """\ import coverage class Plugin(coverage.CoveragePlugin): pass """) debug_out = StringIO() cov = coverage.Coverage(debug=["sys"]) cov._debug_file = debug_out cov.config["run:plugins"] = ["plugin_no_sys_info"] cov.load() out_lines = debug_out.getvalue().splitlines() expected_end = [ "-- sys: plugin_no_sys_info -----------------------------------", "-- end -------------------------------------------------------", ] self.assertEqual(expected_end, out_lines[-len(expected_end):])