Script to list not covered API functions (#8254)
authorGereon Kremer <gereon.kremer@cs.rwth-aachen.de>
Tue, 8 Mar 2022 02:13:43 +0000 (03:13 +0100)
committerGitHub <noreply@github.com>
Tue, 8 Mar 2022 02:13:43 +0000 (02:13 +0000)
Adds a script that lists all functions from the cpp API not covered by the current coverage information.

cmake/CodeCoverage.cmake
contrib/uncovered-api-functions.py [new file with mode: 0755]

index 9027b21b32e7fc810f67ed6bd3ae7deac4ed66a4..c003d2cef2d9a613dff7bb475e7edf68a16c4fc3 100644 (file)
@@ -57,10 +57,12 @@ function(setup_code_coverage_fastcov)
   add_custom_target(${COVERAGE_NAME}
     COMMAND
       ${FASTCOV_BINARY}
-          -d ${COVERAGE_PATH} --lcov ${EXCLUDES} -o coverage.info
-          -j${FASTCOV_PARALLEL_JOBS}
+          -d ${COVERAGE_PATH} ${EXCLUDES} -o coverage.json
+          -j${FASTCOV_PARALLEL_JOBS} -X
+    COMMAND
+      ${FASTCOV_BINARY} -C coverage.json --lcov -o coverage.info
     COMMAND
-      ${GENHTML_BINARY} --no-prefix -o coverage coverage.info
+      ${GENHTML_BINARY} --demangle-cpp --no-prefix -o coverage coverage.info
     DEPENDS
       ${COVERAGE_DEPENDENCIES}
     COMMENT
diff --git a/contrib/uncovered-api-functions.py b/contrib/uncovered-api-functions.py
new file mode 100755 (executable)
index 0000000..17659fc
--- /dev/null
@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+
+import json
+import re
+import subprocess
+
+
+def demangle(name):
+    """Demangle a C++ symbol using c++filt."""
+    pipe = subprocess.Popen(['c++filt', name],
+                            stdin=subprocess.PIPE,
+                            stdout=subprocess.PIPE)
+    stdout, _ = pipe.communicate()
+    return stdout.decode().strip()
+
+
+def get_uncovered(data, file_patterns):
+    """Collect all uncovered functions from files matching the given patterns.
+       Returns a list of dicts with filename, function and startline."""
+    notcovered = []
+
+    for file, fdata in data['sources'].items():
+        if all([re.search(f, file) == None for f in file_patterns]):
+            continue
+        for function, funcdata in fdata['']['functions'].items():
+            if funcdata['execution_count'] == 0:
+                notcovered.append({
+                    'filename': file,
+                    'startline': funcdata['start_line'],
+                    'function': demangle(function),
+                })
+
+    notcovered.sort(key=lambda s: (s['filename'], s['startline']))
+    return notcovered
+
+
+if __name__ == "__main__":
+    patterns = ['src/api/cpp/cvc5.*']
+    data = json.load(open('coverage.json', 'r'))
+    notcovered = get_uncovered(data, patterns)
+    for nc in notcovered:
+        print('starting in {filename}:{startline}'.format(**nc))
+        print('function {function}'.format(**nc))
+        print('')