forked from duckdb/duckdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
check_coverage.py
129 lines (103 loc) · 4.06 KB
/
check_coverage.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import argparse
import os
import math
import re
parser = argparse.ArgumentParser(description='Check code coverage results')
parser.add_argument(
'--uncovered_files',
action='store',
help='Set of files that are not 100% covered',
default=os.path.join(".github", "config", "uncovered_files.csv"),
)
parser.add_argument('--directory', help='Directory of generated HTML files', action='store', default='coverage_html')
parser.add_argument('--fix', help='Fill up the uncovered_files.csv with all files', action='store_true', default=False)
args = parser.parse_args()
if not os.path.exists(args.directory):
print(f"The provided directory ({args.directory}) does not exist, please create it first")
exit(1)
covered_regex = (
r'<a name="(\d+)">[ \t\n]*<span class="lineNum">[ \t\n0-9]+</span><span class="{COVERED_CLASS}">[ \t\n0-9]+:([^<]+)'
)
def get_original_path(path):
return (
path.replace('.gcov.html', '')
.replace(os.getcwd(), '')
.replace('coverage_html' + os.path.sep, '')
.replace('home/runner/work/duckdb/duckdb/', '')
)
def cleanup_line(line):
return line.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"')
partial_coverage_dict = {}
with open(args.uncovered_files, 'r') as f:
for line in f.readlines():
splits = line.split('\t')
partial_coverage_dict[splits[0]] = int(splits[1].strip())
if args.fix:
uncovered_file = open(args.uncovered_files, 'w+')
DASH_COUNT = 80
total_difference = 0
allowed_difference = 0
def check_file(path, partial_coverage_dict):
global any_failed
global total_difference
if not '.cpp' in path and not '.hpp' in path:
# files are named [path].[ch]pp
return
if not '.html' in path:
return
with open(path, 'r') as f:
text = f.read()
original_path = get_original_path(path)
uncovered_lines = re.findall(covered_regex.replace('{COVERED_CLASS}', 'lineNoCov'), text)
covered_lines = re.findall(covered_regex.replace('{COVERED_CLASS}', 'lineCov'), text)
total_lines = len(uncovered_lines) + len(covered_lines)
if total_lines == 0:
# no lines to cover - skip
return
coverage_percentage = round(len(covered_lines) / (total_lines) * 100, 2)
expected_uncovered_lines = 0
if original_path in partial_coverage_dict:
expected_uncovered_lines = partial_coverage_dict[original_path]
if args.fix:
if expected_uncovered_lines == 0 and len(uncovered_lines) == 0:
return
expected_uncovered = max(expected_uncovered_lines, len(uncovered_lines) + 1)
uncovered_file.write(f'{original_path}\t{expected_uncovered}\n')
return
if len(uncovered_lines) > expected_uncovered_lines:
total_difference += len(uncovered_lines) - expected_uncovered_lines
print("-" * DASH_COUNT)
print(f"Coverage failure in file {original_path}")
print("-" * DASH_COUNT)
print(f"Coverage percentage: {coverage_percentage}%")
print(f"Uncovered lines: {len(uncovered_lines)}")
print(f"Covered lines: {len(covered_lines)}")
print("-" * DASH_COUNT)
print(f"Expected uncovered lines: {expected_uncovered_lines}")
print("-" * DASH_COUNT)
print("Uncovered lines")
print("-" * DASH_COUNT)
for e in uncovered_lines:
print(e[0] + ' ' * 8 + cleanup_line(e[1]))
def scan_directory(path):
file_list = []
if os.path.isfile(path):
file_list.append(path)
else:
files = os.listdir(path)
for file in files:
file_list += scan_directory(os.path.join(path, file))
return file_list
files = scan_directory(args.directory)
files.sort()
for file in files:
check_file(file, partial_coverage_dict)
if args.fix:
uncovered_file.close()
if total_difference > allowed_difference:
exit(1)
elif total_difference > 0:
print("-" * DASH_COUNT)
print("SUCCESS-ish")
print("-" * DASH_COUNT)
print(f"{total_difference} lines were uncovered but this falls within the margin of {allowed_difference}")