diff --git a/gfauto/gfauto/cov_new.py b/gfauto/gfauto/cov_new.py index 75d1ed614..7243c4f64 100644 --- a/gfauto/gfauto/cov_new.py +++ b/gfauto/gfauto/cov_new.py @@ -51,16 +51,36 @@ def main() -> None: with open(b_coverage, mode="rb") as f: b_line_counts: cov_util.LineCounts = pickle.load(f) + newly_covered_total: int = 0 + # We modify b_line_counts so that lines already covered by A are set to 0. # Note that line counts appear to be able to overflow, so we use "!= 0" instead of "> 0". for source_file_path, b_counts in b_line_counts.items(): if source_file_path in a_line_counts: a_counts = a_line_counts[source_file_path] + newly_covered_local: int = 0 for line_number, b_count in b_counts.items(): if b_count != 0: # Defaults to 0 if not present. if a_counts[line_number] != 0: b_counts[line_number] = 0 + else: + newly_covered_local += 1 + newly_covered_total += 1 + if newly_covered_local > 0: + print( + "{:03d}".format(newly_covered_local) + + " line(s) newly covered in " + + source_file_path + ) + + print( + str(newly_covered_total) + + " line(s) newly covered in " + + b_coverage + + " compared with " + + a_coverage + ) with open(output_coverage, mode="wb") as f: pickle.dump(b_line_counts, f, protocol=pickle.HIGHEST_PROTOCOL) diff --git a/gfauto/gfauto/cov_venn.py b/gfauto/gfauto/cov_venn.py new file mode 100644 index 000000000..54e23c17b --- /dev/null +++ b/gfauto/gfauto/cov_venn.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- + +# Copyright 2021 The GraphicsFuzz Project Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Shows how many lines are covered by each component of the Venn diagram associated with A.cov and B.cov. + +Unlike most code in gfauto, we use str instead of pathlib.Path because the increased speed is probably worthwhile. +""" + +import argparse +import pickle +import sys + +from gfauto import cov_util + + +def main() -> None: + + parser = argparse.ArgumentParser( + description="Outputs the components of the Venn diagram associated with A.cov and B.cov.", + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + + parser.add_argument("a_coverage", type=str, help="The A.cov file.") + parser.add_argument("b_coverage", type=str, help="The B.cov file.") + + parsed_args = parser.parse_args(sys.argv[1:]) + + a_coverage: str = parsed_args.a_coverage + b_coverage: str = parsed_args.b_coverage + + with open(a_coverage, mode="rb") as f: + a_line_counts: cov_util.LineCounts = pickle.load(f) + + with open(b_coverage, mode="rb") as f: + b_line_counts: cov_util.LineCounts = pickle.load(f) + + total_lines: int = 0 + count_both: int = 0 + count_neither: int = 0 + count_just_a: int = 0 + count_just_b: int = 0 + + for source_file_path, b_counts in b_line_counts.items(): + if source_file_path not in a_line_counts: + print( + "Warning: file " + + source_file_path + + " present in coverage data for " + + b_coverage + + " but not " + + a_coverage + + "; results may be meaningless." + ) + else: + a_counts = a_line_counts[source_file_path] + for line_number, b_count in b_counts.items(): + total_lines += 1 + a_count = a_counts[line_number] + if a_count == 0 and b_count == 0: + count_neither += 1 + elif a_count != 0 and b_count != 0: + count_both += 1 + elif a_count != 0: + count_just_a += 1 + else: + assert b_count != 0 + count_just_b += 1 + + # Integrity check: make sure that all source files from A.cov are represented in B.cov + for source_file_path, a_counts in a_line_counts.items(): + if source_file_path not in b_line_counts: + print( + "Warning: file " + + source_file_path + + " present in coverage data for " + + a_coverage + + " but not " + + b_coverage + + "; results may be meaningless." + ) + + assert total_lines == count_both + count_neither + count_just_a + count_just_b + print("Total lines: " + "{:06d}".format(total_lines)) + print("Lines covered by both: " + "{:06d}".format(count_both)) + print("Lines covered by neither: " + "{:06d}".format(count_neither)) + print("Lines covered by just A.cov: " + "{:06d}".format(count_just_a)) + print("Lines covered by just B.cov: " + "{:06d}".format(count_just_b)) + + +if __name__ == "__main__": + main() diff --git a/gfauto/setup.py b/gfauto/setup.py index 09bbcec2d..8d614019d 100644 --- a/gfauto/setup.py +++ b/gfauto/setup.py @@ -62,6 +62,7 @@ "gfauto_cov_new = gfauto.cov_new:main", "gfauto_cov_to_source = gfauto.cov_to_source:main", "gfauto_cov_from_gcov = gfauto.cov_from_gcov:main", + "gfauto_cov_venn = gfauto.cov_venn:main", "gfauto_settings_update = gfauto.settings_update:main", "gfauto_reduce_source_dir = gfauto.reduce_source_dir:main", "gfauto_bucket_via_transformations = gfauto.bucket_via_transformations:main",