]> granicus.if.org Git - graphviz/commitdiff
enable lcov branch coverage
authorMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Mon, 19 Apr 2021 15:35:07 +0000 (17:35 +0200)
committerMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Sun, 11 Jul 2021 05:04:20 +0000 (07:04 +0200)
.gitlab-ci.yml
CMakeLists.txt
ci/test_coverage.py [new file with mode: 0755]

index 2b7ccf842104dd1f50b743bd65f918a827b4e8c5..277bb6c4ac07c6a914380c124864c30d9eb4b84b 100644 (file)
@@ -236,6 +236,7 @@ portable-source:
         - ci/install-packages.sh
         - export GV_VERSION=$( cat VERSION )
         - export OS_ID=$( cat OS_ID )
+        - ci/test_coverage.py --init
         - pushd build
         # FIXME: remove detect_odr_violation=0 when https://gitlab.com/graphviz/graphviz/-/issues/2096 has been fixed
         - export ASAN_OPTIONS=detect_odr_violation=0
@@ -245,7 +246,10 @@ portable-source:
         # memory leak detections. Disable those for now.
         - export ASAN_OPTIONS=detect_leaks=0
         - python3 -m pytest --verbose --junitxml=report.xml ci/tests.py tests rtest
+        - ci/test_coverage.py --analyze
     artifacts:
+        paths:
+            - coverage/**
         reports:
             junit: ./report.xml
     except:
@@ -490,7 +494,7 @@ ubuntu21-04-cmake-ASan-build-for-ctest:
         # fail on any compiler warnings
         - export CFLAGS=-Werror
         - export CXXFLAGS=-Werror
-        - export CMAKE_OPTIONS="-Duse_sanitizers=ON -Dwith_cxx_tests=ON "
+        - export CMAKE_OPTIONS="-Duse_sanitizers=ON -Duse_coverage=ON -Dwith_cxx_tests=ON "
         - echo experimental > COLLECTION
     # override the deb_build_definition artifacts since we need more
     # files from the build directory when running ctest in the test
@@ -507,6 +511,8 @@ ubuntu21-04-cmake-ASan-build-for-ctest:
             # them.
             - build/lib/**/lib*.so.*
             - build/plugin/**/lib*.so.*
+            # the coverage analysis needs the .gcno files
+            - build/**/*.gcno
             # the packages need to be installed for the post-install tests
             - Packages/*/*/*/*/*/*deb
             - Metadata/*/*/*/configure.log
index 1df011e2fb4b9a12e57d70c40d399e598839c901..ab611fcfe522d763059d731115a66ae486acceb2 100644 (file)
@@ -11,6 +11,7 @@ option(with_ortho      "ORTHO features in neato layout engine." ON )
 option(with_sfdp       "sfdp layout engine." ON )
 option(with_smyrna     "SMYRNA large graph viewer (disabled by default - experimental)" OFF)
 option(use_sanitizers  "enables using address and undefined behavior sanitizer" OFF)
+option(use_coverage    "enables analyzing code coverage" OFF)
 option(with_cxx_tests  "enables building the C++ tests" OFF)
 
 if (enable_ltdl)
@@ -220,6 +221,15 @@ if (use_sanitizers)
     endif()
 endif()
 
+if (use_coverage)
+    add_compile_options("-coverage")
+    if (${CMAKE_VERSION} VERSION_LESS "3.16.0")
+        link_libraries("-coverage")
+    else()
+        add_link_options("-coverage")
+    endif()
+endif()
+
 # ============================ Packaging information ===========================
 include(InstallRequiredSystemLibraries)
 include(package_info)
diff --git a/ci/test_coverage.py b/ci/test_coverage.py
new file mode 100755 (executable)
index 0000000..74c3b02
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+
+"""Graphviz test coverage analysis script"""
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+from typing import List
+
+# logging output stream, setup in main()
+log = None
+
+
+def main(args: List[str]) -> int:  # pylint: disable=C0116
+  # setup logging to print to stderr
+  global log
+  ch = logging.StreamHandler()
+  log = logging.getLogger("test_coverage.py")
+  log.addHandler(ch)
+
+  # parse command line arguments
+  parser = argparse.ArgumentParser(
+      description="Graphviz test coverage analysis script")
+  parser.add_argument("--init", action="store_true",
+                      help="Capture initial zero coverage data before running any test")
+  parser.add_argument("--analyze", action="store_true",
+                      help="Analyze test coverage after running tests")
+  options = parser.parse_args(args[1:])
+
+  if not options.init and not options.analyze:
+    log.error(
+        "Must specify --init or --analyze; refusing to run")
+    return -1
+
+  cwd = os.getcwd()
+
+  generated_files = [
+      f"{cwd}/build/cmd/tools/gmlparse.c",
+      f"{cwd}/build/cmd/tools/gmlscan.c",
+      f"{cwd}/build/lib/cgraph/grammar.c",
+      f"{cwd}/build/lib/cgraph/scan.c",
+      f"{cwd}/build/lib/common/htmlparse.c",
+      f"{cwd}/build/lib/expr/y.tab.c",
+      ]
+
+  excluded_files = generated_files
+
+  exclude_options = [arg for exclude_option in [
+      ["--exclude", f] for f in excluded_files] for arg in exclude_option]
+
+  if options.init:
+    subprocess.check_call(
+        ["lcov", "--capture", "--initial", "--directory", ".", "--rc",
+         "lcov_branch_coverage=1", "--no-external"] + exclude_options +
+        ["--output-file",  "app_base.info"])
+
+    return 0
+
+  if options.analyze:
+    # capture test coverage data
+    subprocess.check_call(
+        ["lcov", "--capture", "--directory", ".", "--rc", "lcov_branch_coverage=1",
+         "--no-external"] + exclude_options + ["--output-file",  "app_test.info"])
+    # combine baseline and test coverage data
+    subprocess.check_call(
+        ["lcov", "--rc", "lcov_branch_coverage=1", "--add-tracefile",
+         "app_base.info", "-add-tracefile", "app_test.info", "--output-file", "app_total.info"])
+    # generate coverage html pages using lcov which are nicer than gcovr's
+    os.makedirs("coverage/lcov", exist_ok=True)
+    subprocess.check_call(
+        ["genhtml", "--prefix", cwd, "--rc", "lcov_branch_coverage=1",
+         "--output-directory", "coverage/lcov", "--show-details", "app_total.info"])
+
+  return 0
+
+
+if __name__ == "__main__":
+  sys.exit(main(sys.argv))