Using the MC/DC Testing Tool

The MC/DC checker analyzes C/C++ code and assesses whether decisions in the code are formulated in a way that enables gcov to show MC/DC coverage.

What does the MC/DC checker tool do?

The MC/DC checker does not actually assess test coverage itself. On a higher level, the tool is supposed be invoked before running coverage tools:

  1. Run MC/DC checker.

  2. Make code changes based on solutions recommended by the MC/DC checker.

  3. Run coverage tool to get MC/DC coverage.

Here is an overview of what the MC/DC checker does:

  1. Runs clang to preprocess the file - generates AST (Abstract Syntax Tree).

  2. Walks the AST to find decisions.

  3. Builds Binary Decision Diagram (BDD) from decisions.

  4. Checks to see if BDD is tree-like. For tree-like BDD, it is proven Object Branch Coverage (OBC) implies MC/DC.

  5. If BDD is non-tree-like, attempts to reorder the BDD.

  6. After checking all files, it outputs to console a summary of all non-BDD decisions in files

  7. Generates BDD .dot files showing before and after reordering.

How to run the MC/DC checker

The recommended way of running the check is to use the upstream docker image as it requires Clang 19 or newer.

Pull their docker image:

docker pull registry.gitlab.com/gtd-gmbh/mcdc-checker/mcdc-checker

Launch the docker container and mount your source code that you would like to run MC/DC check on:

cd <some_library>
docker run -it -v $(pwd):/code registry.gitlab.com/gtd-gmbh/mcdc-checker/mcdc-checker -a

The -a flag tells the check to run recursively on all files in this directory. You should see the script start processing the source code and generating output. See notes below for more info about possible error messages.

Notes about the MC/DC checker

  • When running the mcdc_checker script, you may encounter error messages about include files not found.

    The checker invokes clang to preprocess the input files. If include files are not found, it will not be able to do #include file expansion. Underneath the hood, the checker runs:

    clang input_file.c -E > output
    

    where -E means run preprocesor only.

    You can pass include directories as arguments to the mcdc_checker tool, e.g

    mcdc_checker -a -I/usr/include -I<some_other_dir>
    
  • Some non-tree BDDs do not have solutions

    Looking at the console output produced by the mcdc_checker tool, the bdd_is_not_tree_like occurred in: section lists issues with non-tree BDDs. However, it is possible that not all of them contain solutions.

How to get coverage data for a specific ROS package

Here are instructions for generating coverage data with the gcov and lcov coverage tools, using the rcpputils package as an example.

In your colcon workspace, build the package:

colcon build --packages-select rcpputils --cmake-args -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="--coverage"

Run the tests

colcon test --event-handlers console_direct+ --packages-select rcpputils

You should now see gcov .gcna and .gcno data files generated in the build directory

Use lcov to capture coverage data

lcov --capture --directory build/rcpputils/ --output-file rcpputils_report.info

Generate html report

genhtml rcpputils_report.info --output-directory rcpputils_coverage_report

Open rcpputils_coverage_report/index.html to see coverage data for the rcpputils pacakge