FAQ
- How to specify argument for my program?
- Coverage report is empty
- I cannot see my module in the code coverage report.
- I cannot see my file in the code coverage report.
- Is Windows XP supported?
- Why there is an uncovered line at the end of my class declaration with Visual Studio 2013?
- Coverage and throw
- Network path special considerations
- How do I customize the HTML report?
- "else" or "}" is not marked as covered
- How to run OpenCppCoverage with vstest.console.exe?
- Error: "OpenCppCoverage cannot find the name of the module."
- More report formats
- Merging code coverage from different source locations
- Windows service support
- Your application has thrown an unhandled exception. Code: 3221225477: EXCEPTION_ACCESS_VIOLATION
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
If you have an empty coverage report, the first thing to try is to run OpenCppCoverage without --modules
, --excluded_modules
, --sources
and --excluded_sources
:
- If the coverage become not empty, check the value of
--modules
,--excluded_modules
,--sources
and--excluded_sources
and read carefully the meaning of these flags. - If the coverage is still empty, please check I cannot see my module in the code coverage report and 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 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 isFailed
PDB files are out of date or missing. If XXXX isSuccess
, 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.
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 andLastCoverageResults.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.
Windows XP is currently not supported.
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;
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.
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.
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.
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.*"
.
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
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.
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.
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.
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
(notC:\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
(notD:\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.
There are two ways to run OpenCppCoverage on a service.
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 insideServiceProject
. -
ConsoleProject
: A regular console project that call the function ofLibraryProject
.
Consider the example provided at https://docs.microsoft.com/en-us/windows/desktop/services/service-program-tasks.
-
ServiceProject
contains _tmain, SvcMain, ReportSvcStatus and SvcCtrlHandler. -
LibraryProject
contains only SvcInit. -
ConsoleProject
is a console application that call SvcInit.
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!
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.
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 yourmain
function. The code should be similar to:
#pragma comment (lib, "dbghelp.lib")
namespace Tools { void CreateMiniDumpOnUnHandledException(); }
int main(int argc, char** argv)
{
Tools::CreateMiniDumpOnUnHandledException();
// ...
- Run your application.
Tools::CreateMiniDumpOnUnHandledException()
creates the fileOpenCppCoverage.dmp
when an access violation occurs. - Open the dump with Visual Studio 2019.