blob: 592a1c7e9f504ec17541b3822899579d2d343c2c [file] [log] [blame]
"""This module calculates the incremental coverage of a git commit using
information from `git diff` and LCOV's ".info" file.
"""
from typing import Tuple, Text, List, Dict
import changed_lines
import lcov_parser
import os
import re
import sys
Lines = Dict[int, bool]
class CurrDirectoryError(Exception):
"""CurrDirectoryError is raised when the current working directory
cannot be found at the beginning of the absolute paths of the files
listed in the ".info" file.
"""
pass
def coverage(updated_lines: Dict[Text, List[int]],
covered_lines: Dict[Text, Lines],
curr_dir: Text) -> float:
"""Computes the the proportion of lines covered in updated_lines, ignoring
those that are not instrumented (e.g. like comments or macros).
Args:
updated_lines: a dict mapping files to a list of its updated lines
covered_lines: a dict mapping files to another dict mapping lines to
whether they've been covered or not
curr_dir: name of the current directory, to be removed from beginning of
absolute file paths in covered_lines
Raises:
CurrDirectoryError: if there is an issue removing the current directory from the
beginning of the absolute paths of the files listed in the ".info" file.
"""
num_covered_lines = 0
total_lines = 0
for (file_name, covered) in covered_lines.items():
# remove the prefix to the absolute path in the files
if not file_name.startswith(curr_dir):
raise CurrDirectoryError('Error removing "' + curr_dir + \
'" from beginning of "' + file_name + '".')
trimmed_filename = file_name[len(curr_dir) + 1:]
if trimmed_filename in updated_lines:
for updated_line in updated_lines[trimmed_filename]:
if updated_line in covered:
total_lines += 1
if covered[updated_line]:
num_covered_lines += 1
# some files may not have any instrumented code, e.g. header files with
# only macros
if total_lines == 0:
return None
return float(num_covered_lines) / total_lines
def main(lcov_file_name: Text):
"""Takes in the name of an LCOV ".info" file and calculates the incremental
coverage results of the current git commit.
Raises:
GitDiffSyntaxError if there are formatting issues parsing file name in `file_diff`.
"""
_, covered_lines = lcov_parser.parse(open(lcov_file_name, 'r'))
git_diff = os.popen('git diff HEAD~').read()
updated_lines = changed_lines.from_diff(git_diff)
perc = coverage(updated_lines, covered_lines, os.getcwd())
if perc == None:
print("None")
return
# prints the coverage as a percentage
print(round(perc*100, 2))
if __name__ == '__main__':
main(sys.argv[1])