Skip to content
OpenCppCoverage edited this page May 21, 2020 · 20 revisions

How to specify argument for my program?

if you run the following command you will have a parsing error: unrecognised option '--arg1'.

OpenCppCoverage.exe --sources C:\Dev\MyProject YourProgram.exe --arg1

The parser need a way to know that --arg1 is a flag of YourProgram.exe and not for OpenCppCoverage.exe. You need to add ‘--‘ before your executable name in the same way as many Unix command does.

OpenCppCoverage.exe --sources C:\Dev\MyProject -- YourProgram.exe --arg1

Coverage report is empty

If you have an empty coverage report, the first thing to try is to run OpenCppCoverage without --modules, --excluded_modules, --sources and --excluded_sources:

I cannot see my module in the code coverage report.

Run OpenCppCoverage with --verbose and check LastCoverageResults.log file generated in the current directory.

In LastCoverageResults.log look for the filename of the missing module:

  • If you find something like [debug] Module: YOUR_MODULE.dll is skipped because it matches no selected patterns at least one of the value of --modules or --excluded_modules is wrong.
  • If you find something like [info] Module: YOUR_MODULE.dll is selected because it matches selected pattern: Check the line [debug] Try to load pdb from YOUR_MODULE.pdb: XXXX. If XXXX is Failed PDB files are out of date or missing. If XXXX is Success, then your module was recognized correctly but no files are found for this module. See I cannot see my file in the code coverage report.
  • If you do not find your module: OpenCppCoverage discovers modules by inspecting which dynamic loaded libraries (dll) are loaded by your program. Make sure your module is loaded by your program. You can force it with LoadLibrary.

I cannot see my file in the code coverage report.

Run OpenCppCoverage with --verbose and check LastCoverageResults.log file generated in the current directory.

In LastCoverageResults.log look for the filename of the missing file:

  • If you find something like [debug] Filename: YOUR_FILE is skipped because it matches no selected patterns at least one of the value of --sources or --excluded_sources is wrong.
  • If you find something like [debug] Filename: YOUR_FILE is selected because it matches selected pattern: Please open an issue and provide coverage report and LastCoverageResults.log file.
  • If you do not find your file: Either the file does not belong to any loaded module (See I cannot see my module in the code coverage report.) or your PDB files are out of date.

Is Windows XP supported?

Windows XP is currently not supported.

Why there is an uncovered line at the end of my class declaration with Visual Studio 2013?

You can have an uncovered line at the end of the class like in following code:

You will have this behavior if your class have all the following requirements:

  • At least one default method
  • Is exported with __declspec(dllexport)
  • Has only basic types (int, bool) but no std::string, std::vector or any user class.

Even if you call the methods marked with = default, this line will be remained uncovered.

This is not a bug because there is code generated for the method marked with = default that is never called.

To avoid this problem you can see here or do the following things:

  • Remove = default from the method declaration (in the header)
  • Implement your method with = default in your source file (in .cpp)

For example, for a default copy constructor of the class MyClass, you should define in your source file (.cpp)

MyClass::MyClass(const MyClass&) = default;

Coverage and throw

Consider the following output of OpenCppCoverage where line 6 is marked as uncovered.

The assembly code looks like:

     5: 	throw std::runtime_error("error");
00D43918  push        offset string "error" (0DE0E88h)  
00D4391D  lea         ecx,[ebp-0D0h]  
00D43923  call        std::runtime_error::runtime_error (0D3E0B8h)  
00D43928  push        offset __CT??_R0?AVruntime_error@std@@@8??0runtime_error@std@@QAE@ABV01@@Z12 (0E04034h)  
00D4392D  lea         eax,[ebp-0D0h]  
00D43933  push        eax  
00D43934  call        __CxxThrowException@8 (0D401E7h)  
     6: }
00D43939  pop         edi  
00D4393A  pop         esi  
00D4393B  pop         ebx  
00D4393C  add         esp,0D4h  
00D43942  cmp         ebp,esp  
00D43944  call        __RTC_CheckEsp (0D3EFB8h)  
00D43949  mov         esp,ebp  
00D4394B  pop         ebp  
00D4394C  ret  

The code line 6 is not executed as the exception is thrown line 5.

See "else" or "}" is not marked as covered for a workaround.

Network path special considerations

Consider a Visual Studio project shared at \YOUR-COMPUTER\Shared\ConsoleApplication and Z:\ConsoleApplication (Z: is a network drive that maps \YOUR-COMPUTER\Shared).

The following methods for running the program are equivalent:

OpenCppCoverage --sources ConsoleApplication -- Z:\ConsoleApplication\Debug\ConsoleApplication.exe

OpenCppCoverage --sources ConsoleApplication -- \\YOUR-COMPUTER\Shared\ConsoleApplication\Debug\ConsoleApplication.exe

For module filtering (--modules and --excluded_modules), you need to always use the network style that is \YOUR-COMPUTER\Shared\ConsoleApplication.

For source filtering (--sources and --excluded_sources), thing are little more complex because it depends on how the project was compiled and not how the program is run:

  • If you open Visual Studio solution using Z:\ConsoleApplication\ConsoleApplication.sln and then compile, you should use Z:\ConsoleApplication style for filtering.
  • If you open instead \YOUR-COMPUTER\Shared\ConsoleApplication\ConsoleApplication.sln and then compile, you should use \YOUR-COMPUTER\Shared\ConsoleApplication style for filtering.

It is highly recommended to run OpenCppCoverage in verbose mode when settings filters.

How do I customize the HTML report?

The HTML report is generated using HTML template files located in "Template" folder inside OpenCppCoverage installation folder.

During the report generation, OpenCppCoverage replaces tags like {{TITLE}} by the proper value.

There are two kinds of template:

  • MainTemplate.html: template for index.html and for all HTML files located in "Module" folder.
  • SourceTemplate.html: template for all source files.

The syntax highlighting is performed by the library code-pretiffy. The getting started page explains how to configure it.

If you want to change the color of the comment for example, you can update the theme defined in prettify-CppCoverage.css located in Template\third-party\google-code-prettify. prettify-CppCoverage.css is a minified version of the default theme and you can find examples of theme here.

"else" or "}" is not marked as covered

OpenCppCoverage uses PDB content to detect which line need a coverage.

int foo(bool v)
{
	if (v)
		return 0;
	else
		return 1;
}

int main(int argc, char** argv)
{
	foo(true);
	foo(false);
	return 0;
}

In the previous example, the line containing "else" will never be executed and OpenCppCoverage will report it as not covered. This is because Visual Studio generates an instruction for "else". Indeed, generated code are not the same with and without "else". You can have a similar issue with “throw” (see here for more detail) and for a closing parenthesis (see here for more detail).

To solve this problem, you can use --excluded_line_regex "\s*else.*" and --excluded_line_regex "\s*\}.*" to exclude respectively else or }. You can also introduce a special comment like // @NOCOVERAGE and use --excluded_line_regex ".*@NOCOVERAGE.*".

How to run OpenCppCoverage with vstest.console.exe?

You just need to run vstest.console.exe with OpenCppCoverage:

OpenCppCoverage --sources YOUR_SOURCE -- "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe" debug/UnitTests.dll

For x64, you need to add --cover_children flag:

OpenCppCoverage --cover_children --sources YOUR_SOURCE -- "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\CommonExtensions\Microsoft\TestWindow\vstest.console.exe" /Platform:x64 x64/debug/UnitTests.dll

Avoid using a static library

vstest.console.exe loads and unloads several times (17 times in my case) the dynamic library containing the unit tests.

Let's consider your unit tests are located in UnitTests.dll. If you link MyStaticLibrary.lib with UnitTests.dll, UnitTests.dll contains all the code from MyStaticLibrary.lib. As vstest.console.exe loads several times UnitTests.dll, OpenCppCoverage instruments all your code several times and it is very slow!

vstest.console.exe loads dynamic library dependencies only once during the last load. If you transform MyStaticLibrary.lib into a dynamic library, it solves this problem.

You should avoid using a static library with vstest.console.exe and OpenCppCoverage.

Error: "OpenCppCoverage cannot find the name of the module."

Docker is not yet supported. See here for more information.

This error happens when CREATE_PROCESS_DEBUG_INFO::hFile or LOAD_DLL_DEBUG_INFO::hFile is null. The exact steps to reproduce this issue remain unknown. I had twice this issue and restarting Windows solved the problem. You can also try to copy your program to a different folder.

More report formats

OpenCppCoverage provides an HTML report format. If you want more report formats, you can create your code coverage as a Cobertura file and then use ReportGenerator.

Create a code coverage in Cobertura format:

OpenCppCoverage.exe --sources YOUR_SOURCE_FILTER_PATTERN --export_type cobertura:coverage.xml -- YOUR_PROGRAM.EXE

Create a report in the folder CoverageReport:

ReportGenerator.exe --reports:coverage.xml -targetdir:CoverageReport

See ReportGenerator documentation for additional options.

You can also write your own export format. Explanations are provided here.

Merging code coverage from different source locations

Imaging you would like to compute code coverage in the following use case:

  • Your code is located in the folder C:\Dev\MyProject on computer A.
  • The same code is located in a different folder D:\Dev\MyProject on another computer B.

Run on computer A:

OpenCppCoverage --sources=MyProject --export=binary:a.cov -- C:\Dev\MyProject\Debug\MyProject.exe

Run on computer B:

OpenCppCoverage --sources=MyProject --export=binary:b.cov -- D:\Dev\MyProject\Debug\MyProject.exe

Merge the result:

OpenCppCoverage --input_coverage=a.cov --input_coverage=b.cov 

The code is duplicated as C:\Dev\MyProject\MyProject\myProject.cpp is not the same as D:\Dev\MyProject\MyProject\myProject.cpp.

To solve this issue, we can use the subst command. In this example, we are using Z: drive letter but it can be any drive letter available on both computers.

On computer A:

  • Run subst Z: C:\Dev\MyProject
  • Open with Visual Studio the solution Z:\MyProject.sln (not C:\Dev\MyProject\MyProject.sln) and rebuild your code. This step is mandatory, please see here for more information.
  • Run OpenCppCoverage --sources=MyProject --export=binary:a.cov -- Z:\Debug\MyProject.exe

On computer B:

  • Run subst Z: D:\Dev\MyProject
  • Open with Visual Studio the solution Z:\MyProject.sln (not D:\Dev\MyProject\MyProject.sln) and rebuild your code. This step is mandatory, please see here for more information.
  • Run OpenCppCoverage --sources=MyProject --export=binary:b.cov -- Z:\Debug\MyProject.exe

You can now merge your code coverage without duplicated files:

OpenCppCoverage --input_coverage=a.cov --input_coverage=b.cov 

Please note that executable path is still duplicated but source code is merged.

Windows service support

There are two ways to run OpenCppCoverage on a service.

Isolate service specific code

OpenCppCoverage cannot compute the code coverage for a Windows service directly as a service is run by the system.

From https://msdn.microsoft.com/en-us/en-en/library/d56de412%28v=vs.110%29.aspx "you cannot immediately run a service or step into its code. Instead, you must install and start your service, and then attach a debugger to the service's process"

OpenCppCoverage cannot be attached to a running process, and even if it would be possible, it would not be convenient. Indeed, your service would need to display its process id and wait until you run OpenCppCoverage from the command line.

A workaround is to split your code into three projects:

  • ServiceProject: A service project containing only the code specific to the service. It should be as small as possible.
  • LibraryProject: A library project containing all your code except what is inside ServiceProject.
  • ConsoleProject: A regular console project that call the function of LibraryProject.

Consider the example provided at https://docs.microsoft.com/en-us/windows/desktop/services/service-program-tasks.

Using ConsoleProject, OpenCppCoverage can report now the code coverage. As a bonus, you can debug your program easily as you do not need to attached manually your debugger!

Using registry

Follow the procedure described on the third bullet point here. Do not forget to check Allow Service to Interact with Desktop.

For Debugger value enter "C:\Program Files\OpenCppCoverage\OpenCppCoverage.exe" --sources MySource -- where MySource is your source filter. You can enter additional argument if needed.

Unfortunately, the coverage report is generated inside the folder C:\Windows\System32\CoverageReport-YYYY-MM-DD-HHhMMmSSs and using --working_dir does not help.

This method was tested successfully on a small service but a user report an issue using this method.

Your application has thrown an unhandled exception. Code: 3221225477: EXCEPTION_ACCESS_VIOLATION

If the application run by OpenCppCoverage raises an access violation exception, OpenCppCoverage displays Your application has thrown an unhandled exception. Code: 3221225477: EXCEPTION_ACCESS_VIOLATION. If the application was built with optimization enabled, make sure using --optimized_build.

You should try running your application under a debugger without OpenCppCoverage. If you can reproduce the problem only when running your program with OpenCppCoverage, creating a minidump file should help:

  • Copy MiniDump.cpp to your project
  • In MiniDump.cpp replace #include "MiniDump.hpp" by #include <Windows.h>.
  • Call Tools::CreateMiniDumpOnUnHandledException(); in your main function. The code should be similar to:
#pragma comment (lib, "dbghelp.lib")
namespace Tools { void CreateMiniDumpOnUnHandledException(); }

int main(int argc, char** argv)
{
	Tools::CreateMiniDumpOnUnHandledException();
        // ...