From 0bb7d5669b94a3254ec85e43ec1d08aa64d17f61 Mon Sep 17 00:00:00 2001 From: Christoph Blessing <33834216+cblessing24@users.noreply.github.com> Date: Thu, 18 Aug 2022 12:58:29 +0200 Subject: [PATCH 1/5] Extend json report test Added more branches to the code whose coverage is checked. --- tests/test_json.py | 76 ++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/tests/test_json.py b/tests/test_json.py index 63713af8c..314b32d66 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -21,6 +21,10 @@ def _assert_expected_json_report(self, cov, expected_result): a = {'b': 1} if a.get('a'): b = 1 + elif a.get('b'): + b = 2 + else: + b = 3 """) a = self.start_import_stop(cov, "a") output_path = os.path.join(self.temp_dir, "a.json") @@ -43,34 +47,34 @@ def test_branch_coverage(self): }, 'files': { 'a.py': { - 'executed_lines': [1, 2], - 'missing_lines': [3], + 'executed_lines': [1, 2, 4, 5], + 'missing_lines': [3, 7], 'excluded_lines': [], 'summary': { - 'missing_lines': 1, - 'covered_lines': 2, - 'num_statements': 3, - 'num_branches': 2, + 'missing_lines': 2, + 'covered_lines': 4, + 'num_statements': 6, + 'num_branches': 4, 'excluded_lines': 0, - 'num_partial_branches': 1, - 'covered_branches': 1, - 'missing_branches': 1, + 'num_partial_branches': 2, + 'covered_branches': 2, + 'missing_branches': 2, 'percent_covered': 60.0, 'percent_covered_display': '60', }, }, }, 'totals': { - 'missing_lines': 1, - 'covered_lines': 2, - 'num_statements': 3, - 'num_branches': 2, + 'missing_lines': 2, + 'covered_lines': 4, + 'num_statements': 6, + 'num_branches': 4, 'excluded_lines': 0, - 'num_partial_branches': 1, + 'num_partial_branches': 2, 'percent_covered': 60.0, 'percent_covered_display': '60', - 'covered_branches': 1, - 'missing_branches': 1, + 'covered_branches': 2, + 'missing_branches': 2, }, } self._assert_expected_json_report(cov, expected_result) @@ -85,14 +89,14 @@ def test_simple_line_coverage(self): }, 'files': { 'a.py': { - 'executed_lines': [1, 2], - 'missing_lines': [3], + 'executed_lines': [1, 2, 4 ,5], + 'missing_lines': [3, 7], 'excluded_lines': [], 'summary': { 'excluded_lines': 0, - 'missing_lines': 1, - 'covered_lines': 2, - 'num_statements': 3, + 'missing_lines': 2, + 'covered_lines': 4, + 'num_statements': 6, 'percent_covered': 66.66666666666667, 'percent_covered_display': '67', }, @@ -100,9 +104,9 @@ def test_simple_line_coverage(self): }, 'totals': { 'excluded_lines': 0, - 'missing_lines': 1, - 'covered_lines': 2, - 'num_statements': 3, + 'missing_lines': 2, + 'covered_lines': 4, + 'num_statements': 6, 'percent_covered': 66.66666666666667, 'percent_covered_display': '67', }, @@ -130,8 +134,8 @@ def run_context_test(self, relative_files): }, 'files': { 'a.py': { - 'executed_lines': [1, 2], - 'missing_lines': [3], + 'executed_lines': [1, 2, 4, 5], + 'missing_lines': [3, 7], 'excluded_lines': [], "contexts": { "1": [ @@ -139,13 +143,19 @@ def run_context_test(self, relative_files): ], "2": [ "cool_test" - ] + ], + "4": [ + "cool_test" + ], + "5": [ + "cool_test" + ], }, 'summary': { 'excluded_lines': 0, - 'missing_lines': 1, - 'covered_lines': 2, - 'num_statements': 3, + 'missing_lines': 2, + 'covered_lines': 4, + 'num_statements': 6, 'percent_covered': 66.66666666666667, 'percent_covered_display': '66.67', }, @@ -153,9 +163,9 @@ def run_context_test(self, relative_files): }, 'totals': { 'excluded_lines': 0, - 'missing_lines': 1, - 'covered_lines': 2, - 'num_statements': 3, + 'missing_lines': 2, + 'covered_lines': 4, + 'num_statements': 6, 'percent_covered': 66.66666666666667, 'percent_covered_display': '66.67', }, From b387359c700933723f51c1c9ab997473f497c32f Mon Sep 17 00:00:00 2001 From: Christoph Blessing <33834216+cblessing24@users.noreply.github.com> Date: Thu, 18 Aug 2022 13:28:34 +0200 Subject: [PATCH 2/5] Add branch details to json report The json report now includes for each branch which branches have been executed, missed and what the percentage of covered branches was. --- coverage/jsonreport.py | 18 ++++++++++++++++++ tests/test_json.py | 12 ++++++++++++ 2 files changed, 30 insertions(+) diff --git a/coverage/jsonreport.py b/coverage/jsonreport.py index 43edc4520..e4e658e59 100644 --- a/coverage/jsonreport.py +++ b/coverage/jsonreport.py @@ -102,4 +102,22 @@ def report_one_file(self, coverage_data, analysis): 'covered_branches': nums.n_executed_branches, 'missing_branches': nums.n_missing_branches, }) + reported_file['branch_details'] = _report_branch_details(analysis) return reported_file + + +def _report_branch_details(analysis): + """Extract branch details for a single file.""" + executed_arcs = analysis.executed_branch_arcs() + missing_arcs = analysis.missing_branch_arcs() + details = {} + for source_lineno in executed_arcs.keys() | missing_arcs.keys(): + target_linenos_executed = executed_arcs.get(source_lineno, []) + target_linenos_missing = missing_arcs.get(source_lineno, []) + n_target_linenos = len(target_linenos_executed) + len(target_linenos_missing) + details[source_lineno] = { + 'executed_branches': target_linenos_executed, + 'missing_branches': target_linenos_missing, + 'percent_covered': len(target_linenos_executed) / n_target_linenos * 100, + } + return details diff --git a/tests/test_json.py b/tests/test_json.py index 314b32d66..d626f1c8c 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -50,6 +50,18 @@ def test_branch_coverage(self): 'executed_lines': [1, 2, 4, 5], 'missing_lines': [3, 7], 'excluded_lines': [], + 'branch_details': { + '2': { + 'executed_branches': [4], + 'missing_branches': [3], + 'percent_covered': 50.0, + }, + '4': { + 'executed_branches': [5], + 'missing_branches': [7], + 'percent_covered': 50.0, + }, + }, 'summary': { 'missing_lines': 2, 'covered_lines': 4, From 99ed2db904fae257ea9042d85d9755e0a2a17ca3 Mon Sep 17 00:00:00 2001 From: Christoph Blessing <33834216+cblessing24@users.noreply.github.com> Date: Fri, 19 Aug 2022 10:28:06 +0200 Subject: [PATCH 3/5] Add exiting branch arc to json report test --- tests/test_json.py | 98 +++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/tests/test_json.py b/tests/test_json.py index d626f1c8c..ceefc5da5 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -25,6 +25,8 @@ def _assert_expected_json_report(self, cov, expected_result): 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") @@ -47,8 +49,8 @@ def test_branch_coverage(self): }, 'files': { 'a.py': { - 'executed_lines': [1, 2, 4, 5], - 'missing_lines': [3, 7], + 'executed_lines': [1, 2, 4, 5, 8], + 'missing_lines': [3, 7, 9], 'excluded_lines': [], 'branch_details': { '2': { @@ -61,32 +63,37 @@ def test_branch_coverage(self): 'missing_branches': [7], 'percent_covered': 50.0, }, + '8': { + 'executed_branches': [-1], + 'missing_branches': [9], + 'percent_covered': 50.0, + } }, 'summary': { - 'missing_lines': 2, - 'covered_lines': 4, - 'num_statements': 6, - 'num_branches': 4, + 'missing_lines': 3, + 'covered_lines': 5, + 'num_statements': 8, + 'num_branches': 6, 'excluded_lines': 0, - 'num_partial_branches': 2, - 'covered_branches': 2, - 'missing_branches': 2, - 'percent_covered': 60.0, - 'percent_covered_display': '60', + 'num_partial_branches': 3, + 'covered_branches': 3, + 'missing_branches': 3, + 'percent_covered': 57.142857142857146, + 'percent_covered_display': '57', }, }, }, 'totals': { - 'missing_lines': 2, - 'covered_lines': 4, - 'num_statements': 6, - 'num_branches': 4, + 'missing_lines': 3, + 'covered_lines': 5, + 'num_statements': 8, + 'num_branches': 6, 'excluded_lines': 0, - 'num_partial_branches': 2, - 'percent_covered': 60.0, - 'percent_covered_display': '60', - 'covered_branches': 2, - 'missing_branches': 2, + '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) @@ -101,26 +108,26 @@ def test_simple_line_coverage(self): }, 'files': { 'a.py': { - 'executed_lines': [1, 2, 4 ,5], - 'missing_lines': [3, 7], + 'executed_lines': [1, 2, 4, 5, 8], + 'missing_lines': [3, 7, 9], 'excluded_lines': [], 'summary': { 'excluded_lines': 0, - 'missing_lines': 2, - 'covered_lines': 4, - 'num_statements': 6, - 'percent_covered': 66.66666666666667, - 'percent_covered_display': '67', + 'missing_lines': 3, + 'covered_lines': 5, + 'num_statements': 8, + 'percent_covered': 62.5, + 'percent_covered_display': '62', }, }, }, 'totals': { 'excluded_lines': 0, - 'missing_lines': 2, - 'covered_lines': 4, - 'num_statements': 6, - 'percent_covered': 66.66666666666667, - 'percent_covered_display': '67', + '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) @@ -146,8 +153,8 @@ def run_context_test(self, relative_files): }, 'files': { 'a.py': { - 'executed_lines': [1, 2, 4, 5], - 'missing_lines': [3, 7], + 'executed_lines': [1, 2, 4, 5, 8], + 'missing_lines': [3, 7, 9], 'excluded_lines': [], "contexts": { "1": [ @@ -162,24 +169,27 @@ def run_context_test(self, relative_files): "5": [ "cool_test" ], + "8": [ + "cool_test" + ], }, 'summary': { 'excluded_lines': 0, - 'missing_lines': 2, - 'covered_lines': 4, - 'num_statements': 6, - 'percent_covered': 66.66666666666667, - 'percent_covered_display': '66.67', + 'missing_lines': 3, + 'covered_lines': 5, + 'num_statements': 8, + 'percent_covered': 62.5, + 'percent_covered_display': '62.50', }, }, }, 'totals': { 'excluded_lines': 0, - 'missing_lines': 2, - 'covered_lines': 4, - 'num_statements': 6, - 'percent_covered': 66.66666666666667, - 'percent_covered_display': '66.67', + '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) From 97b2ac89f3af343d749623aa515347ca328d0a06 Mon Sep 17 00:00:00 2001 From: Christoph Blessing <33834216+cblessing24@users.noreply.github.com> Date: Fri, 19 Aug 2022 10:45:24 +0200 Subject: [PATCH 4/5] Update branch details format Executed and missing branch arcs are stored in the fields named 'executed_branches' and 'missing_branches' respectively. Both fields contain a list of two element lists. The first element represents the source line number and the second one the target line number. Exit branches have their target line number set to 0. --- coverage/jsonreport.py | 22 ++++++---------------- tests/test_json.py | 27 ++++++++++----------------- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/coverage/jsonreport.py b/coverage/jsonreport.py index e4e658e59..394043421 100644 --- a/coverage/jsonreport.py +++ b/coverage/jsonreport.py @@ -102,22 +102,12 @@ def report_one_file(self, coverage_data, analysis): 'covered_branches': nums.n_executed_branches, 'missing_branches': nums.n_missing_branches, }) - reported_file['branch_details'] = _report_branch_details(analysis) + reported_file['executed_branches'] = list(_convert_branch_arcs(analysis.executed_branch_arcs())) + reported_file['missing_branches'] = list(_convert_branch_arcs(analysis.missing_branch_arcs())) return reported_file -def _report_branch_details(analysis): - """Extract branch details for a single file.""" - executed_arcs = analysis.executed_branch_arcs() - missing_arcs = analysis.missing_branch_arcs() - details = {} - for source_lineno in executed_arcs.keys() | missing_arcs.keys(): - target_linenos_executed = executed_arcs.get(source_lineno, []) - target_linenos_missing = missing_arcs.get(source_lineno, []) - n_target_linenos = len(target_linenos_executed) + len(target_linenos_missing) - details[source_lineno] = { - 'executed_branches': target_linenos_executed, - 'missing_branches': target_linenos_missing, - 'percent_covered': len(target_linenos_executed) / n_target_linenos * 100, - } - return details +def _convert_branch_arcs(branch_arcs): + for source, targets in branch_arcs.items(): + for target in targets: + yield source, target if target != -1 else 0 diff --git a/tests/test_json.py b/tests/test_json.py index ceefc5da5..7205c284c 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -52,23 +52,16 @@ def test_branch_coverage(self): 'executed_lines': [1, 2, 4, 5, 8], 'missing_lines': [3, 7, 9], 'excluded_lines': [], - 'branch_details': { - '2': { - 'executed_branches': [4], - 'missing_branches': [3], - 'percent_covered': 50.0, - }, - '4': { - 'executed_branches': [5], - 'missing_branches': [7], - 'percent_covered': 50.0, - }, - '8': { - 'executed_branches': [-1], - 'missing_branches': [9], - 'percent_covered': 50.0, - } - }, + 'executed_branches': [ + [2, 4], + [4, 5], + [8, 0], + ], + 'missing_branches': [ + [2, 3], + [4, 7], + [8, 9], + ], 'summary': { 'missing_lines': 3, 'covered_lines': 5, From d6f9893497615765ed506a6a767b389459ebe5e3 Mon Sep 17 00:00:00 2001 From: Christoph Blessing <33834216+cblessing24@users.noreply.github.com> Date: Fri, 19 Aug 2022 11:14:53 +0200 Subject: [PATCH 5/5] Fix linting errors --- coverage/jsonreport.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/coverage/jsonreport.py b/coverage/jsonreport.py index 394043421..7ca468e32 100644 --- a/coverage/jsonreport.py +++ b/coverage/jsonreport.py @@ -102,12 +102,17 @@ def report_one_file(self, coverage_data, analysis): 'covered_branches': nums.n_executed_branches, 'missing_branches': nums.n_missing_branches, }) - reported_file['executed_branches'] = list(_convert_branch_arcs(analysis.executed_branch_arcs())) - reported_file['missing_branches'] = list(_convert_branch_arcs(analysis.missing_branch_arcs())) + reported_file['executed_branches'] = list( + _convert_branch_arcs(analysis.executed_branch_arcs()) + ) + reported_file['missing_branches'] = list( + _convert_branch_arcs(analysis.missing_branch_arcs()) + ) return reported_file def _convert_branch_arcs(branch_arcs): + """Convert branch arcs to a list of two-element tuples.""" for source, targets in branch_arcs.items(): for target in targets: yield source, target if target != -1 else 0