# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 # For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt """Test json-based summary reporting for coverage.py""" from __future__ import annotations import json import os from datetime import datetime from typing import Any, Dict import coverage from coverage import Coverage from tests.coveragetest import UsingModulesMixin, CoverageTest class JsonReportTest(UsingModulesMixin, CoverageTest): """Tests of the JSON reports from coverage.py.""" def _assert_expected_json_report( self, cov: Coverage, expected_result: Dict[str, Any], ) -> None: """ Helper for tests that handles the common ceremony so the tests can be clearly show the consequences of setting various arguments. """ self.make_file("a.py", """\ a = {'b': 1} if a.get('a'): b = 1 elif a.get('b'): b = 2 else: b = 3 if not a: b = 4 """) a = self.start_import_stop(cov, "a") output_path = os.path.join(self.temp_dir, "a.json") cov.json_report(a, outfile=output_path) with open(output_path) as result_file: parsed_result = json.load(result_file) self.assert_recent_datetime( datetime.strptime(parsed_result['meta']['timestamp'], "%Y-%m-%dT%H:%M:%S.%f") ) del (parsed_result['meta']['timestamp']) assert parsed_result == expected_result def test_branch_coverage(self) -> None: cov = coverage.Coverage(branch=True) expected_result = { 'meta': { "version": coverage.__version__, "branch_coverage": True, "show_contexts": False, }, 'files': { 'a.py': { 'executed_lines': [1, 2, 4, 5, 8], 'missing_lines': [3, 7, 9], 'excluded_lines': [], 'executed_branches': [ [2, 4], [4, 5], [8, -1], ], 'missing_branches': [ [2, 3], [4, 7], [8, 9], ], 'summary': { 'missing_lines': 3, 'covered_lines': 5, 'num_statements': 8, 'num_branches': 6, 'excluded_lines': 0, 'num_partial_branches': 3, 'covered_branches': 3, 'missing_branches': 3, 'percent_covered': 57.142857142857146, 'percent_covered_display': '57', }, }, }, 'totals': { 'missing_lines': 3, 'covered_lines': 5, 'num_statements': 8, 'num_branches': 6, 'excluded_lines': 0, 'num_partial_branches': 3, 'percent_covered': 57.142857142857146, 'percent_covered_display': '57', 'covered_branches': 3, 'missing_branches': 3, }, } self._assert_expected_json_report(cov, expected_result) def test_simple_line_coverage(self) -> None: cov = coverage.Coverage() expected_result = { 'meta': { "version": coverage.__version__, "branch_coverage": False, "show_contexts": False, }, 'files': { 'a.py': { 'executed_lines': [1, 2, 4, 5, 8], 'missing_lines': [3, 7, 9], 'excluded_lines': [], 'summary': { 'excluded_lines': 0, 'missing_lines': 3, 'covered_lines': 5, 'num_statements': 8, 'percent_covered': 62.5, 'percent_covered_display': '62', }, }, }, 'totals': { 'excluded_lines': 0, 'missing_lines': 3, 'covered_lines': 5, 'num_statements': 8, 'percent_covered': 62.5, 'percent_covered_display': '62', }, } self._assert_expected_json_report(cov, expected_result) def run_context_test(self, relative_files: bool) -> None: """A helper for two tests below.""" self.make_file("config", """\ [run] relative_files = {} [report] precision = 2 [json] show_contexts = True """.format(relative_files)) cov = coverage.Coverage(context="cool_test", config_file="config") expected_result = { 'meta': { "version": coverage.__version__, "branch_coverage": False, "show_contexts": True, }, 'files': { 'a.py': { 'executed_lines': [1, 2, 4, 5, 8], 'missing_lines': [3, 7, 9], 'excluded_lines': [], "contexts": { "1": [ "cool_test" ], "2": [ "cool_test" ], "4": [ "cool_test" ], "5": [ "cool_test" ], "8": [ "cool_test" ], }, 'summary': { 'excluded_lines': 0, 'missing_lines': 3, 'covered_lines': 5, 'num_statements': 8, 'percent_covered': 62.5, 'percent_covered_display': '62.50', }, }, }, 'totals': { 'excluded_lines': 0, 'missing_lines': 3, 'covered_lines': 5, 'num_statements': 8, 'percent_covered': 62.5, 'percent_covered_display': '62.50', }, } self._assert_expected_json_report(cov, expected_result) def test_context_non_relative(self) -> None: self.run_context_test(relative_files=False) def test_context_relative(self) -> None: self.run_context_test(relative_files=True)