Rss Feed
Tweeter button
Facebook button
Technorati button
Reddit button
Myspace button
Linkedin button
Webonews button
Delicious button
Digg button
Flickr button
Stumbleupon button
Newsvine button

Getting code coverage for a child process?

By , May 31, 2017 5:43 pm

In this blog post I’m going to explain how to collect code coverage for a process that is launched by another process. We’ll be using C++ Coverage Validator to collect the code coverage.

For example you may have a control process that launches helper programs to do specific jobs and you wish to collect code coverage data for one of the helper programs. I’m first going to show how you do this with the GUI, then I’ll show you how to do this with the command line.

For the purposes of this blog post I’m going to use a test program called testAppFromOtherProcess.exe as the child program and testAppOtherProcessCpp.exe as the parent process. Once I’ve explained this for C++, I’ll also provide examples for programs launched from Java and for programs launched from Python.

The test program

The test program is simple. It takes two numbers and calculates the sum of all the products. If less than two arguments are supplied they default to 10.

int _tmain(int argc, _TCHAR* argv[])
{
	int	nx, ny;
	int	x, y;
	int	v;

	nx = 10;
	ny = 10;
	v = 0;

	if (argc == 2)
	{
		nx = _tcstol(argv[1], NULL, 10);
	}
	else if (argc >= 3)
	{
		nx = _tcstol(argv[1], NULL, 10);
		ny = _tcstol(argv[2], NULL, 10);
	}

	for(y = 0; y < ny; y++)
	{
		for(x = 0; x < nx; x++)
		{
			v += (x + 1) * (y + 1);
		}
	}

	return v;
}

The parent C++ program

The parent C++ program is a simple MFC dialog that collects two values and launches the test program. The code for launching the child process looks like this:

void CtestAppOtherProcessCppDlg::OnBnClickedOk()
{
	// get data values

	CString	str1, str2;
	DWORD	v = 0;

	GetDlgItemText(IDC_EDIT_COUNT1, str1);
	GetDlgItemText(IDC_EDIT_COUNT2, str2);

	// create command line

	CString	commandline;

	commandline += _T("testAppFromOtherProcess.exe");
	commandline += _T(" ");
	commandline += str1;
	commandline += _T(" ");
	commandline += str2;

	// run child process

	STARTUPINFO         stStartInfo;
	PROCESS_INFORMATION stProcessInfo;

	memset(&stStartInfo, 0, sizeof(STARTUPINFO));
	memset(&stProcessInfo, 0, sizeof(PROCESS_INFORMATION));

	stStartInfo.cb = sizeof(STARTUPINFO);
	stStartInfo.dwFlags = STARTF_USESHOWWINDOW;
	stStartInfo.wShowWindow = SW_HIDE;

	int	bRet;

	bRet = CreateProcess(NULL,
			(TCHAR *)(const TCHAR *)commandline,
			NULL,
			NULL,
			FALSE,
			0,
			NULL,
			NULL,
			&stStartInfo,
			&stProcessInfo);
	if (bRet)
	{
		// wait until complete then get exit code

		WaitForSingleObject(stProcessInfo.hProcess, INFINITE);

		GetExitCodeProcess(stProcessInfo.hProcess, &v);

		// tidy up

		CloseHandle(stProcessInfo.hProcess);
		CloseHandle(stProcessInfo.hThread);
	}

	// display result

	SetDlgItemInt(IDC_STATIC_VALUE, v, FALSE);
}

Configuring the target C++ program

Before we can collect code coverage we need to tell C++ Coverage Validator about the target program and the program that is going to launch it. We do this from the launch dialog (or launch wizard). From the launch dialog, select the program to launch using the Browse... button and selecting the file with the File dialog. Once a file has been chosen a default value will be selected for the Application to Monitor. This is the same program as you just selected with the File dialog.

CVLaunchDialogApplicationToMonitor

To allow us to monitor other programs we need to edit the list of applications we can monitor. Click the Edit... button to the right of the Application to monitor combo box. The Applications To Monitor dialog is displayed.

CVApplicationsToMonitorDialog

We need to add our target program to the list of programs to monitor. Click Add.... The Application To Monitor dialog is displayed. Choose our launch program testAppOtherProcessCpp.exe using Browse.... C++ Coverage Validator will identify any other executables in the same folder and add these to the list of target programs you may want to monitor. You can remove any programs you don't want to monitor with the Remove and Remove All buttons. Your dialog should look like the one shown below.

CVApplicationToMonitorDialog

Click OK to close the Application To Monitor dialog.

Click OK to close the Applications To Monitor dialog.

The Application to monitor combo will now have additional entries in it. Select testAppFromOtherProcess.exe in the Application to monitor combo. Leave the launch count set to 1. The first time testAppFromOtherProcess.exe is launched it will be monitored. Click Go! to start the parent process.

CVApplicationToMonitorParentProcess

You will notice that C++ Coverage Validator is not collecting data. Now click on the Launch Child Process button. The child process is launched, C++ Coverage Validator recognises the parent process is launching a child process that is configured to be monitored and has the correct launch count (this is the first time it is being launched and the launch count is set to "1") - the child process is instrumented for code coverage. You can see the instrumentation progress in the title bar and pretty soon code coverage statistics are being displayed by C++ Coverage Validator.

CVCodeCoverageResults

Command Line, example for C++

OK, that's wonderful, we can collect code coverage using the GUI to launch one program and collect data from a child process. All without any coding. Super. So how do we do that from the command line? Glad you asked!

"c:\C++ Coverage Validator\coverageValidator.exe" 
-program "e:\test\release\testAppOtherProcessCpp.exe"
-directory "e:\test\release" 
-programToMonitor "e:\test\release\testAppFromOtherProcess.exe" 

How does this work?

  • -directory. Specify the startup directory.
  • -program. Specify the program to launch.
  • -programToMonitor. Specify the program to that will be monitored for code coverage.

Very straightforward and simple. Paths must have quotes if they contain spaces. If in doubt always use quotes. Note also that where you've installed C++ Coverage Validator will be different, most likely in C:\Program Files (x86)\Software Verification. We shortened it for the example to make it fit the page.

Java

The parent program in Java is very simple. It takes any arguments passed to it and passes them to the target program.

import java.io.IOException;
import java.lang.ProcessBuilder;
import java.util.ArrayList;

public class testAppFromOtherProcessJava 
{
    public static void main(String[] args) throws IOException, InterruptedException
	{
		String			target = "e:\\om\\c\\testApps\\testAppFromOtherProcess\\Release\\testAppFromOtherProcess.exe";
        	ProcessBuilder	p = new ProcessBuilder();

		// add the args to be passed to the target program, unlike C/C++, args[0] is not the program name

		ArrayList	targetArgs;

		targetArgs = new ArrayList();
		targetArgs.add(target);
		for(int i = 0; i < args.length; i++)
		{
			targetArgs.add(args[i]);
		}

		p.command(targetArgs);

		// run the process, wait for it to complete and report the value calculated

		Process			proc;

	        proc = p.start();
		proc.waitFor();

		System.out.println("Result: " + proc.exitValue()); 
    }
}

You can compile this program with this simple command line. This assumes you have a Java Development Kit installed and javac.exe on the command line.

javac testAppFromOtherProcessJava.java

Configuring the target Java program

As with the C++ target program we need to tell C++ Coverage Validator about the target program and the program that is going to launch it. We're running a Java program so the executable to launch is the Java runtime. Click the Browse... button and select the Java runtime you are using.

CVLaunchDialogJava

The launch directory is automatically configured to be the same as the launch program. In the case of a Java program, that is almost certainly incorrect. We're going to choose the directory where our Java class is located. Click the Dir... button and choose that directory.

CVLaunchDialogJavaDirectory

We also need to tell the Java runtime what class to execute. This is provided as an argument to the program being run (the Java rutnime). In the arguments field, type the name of the class. In this case testAppFromOtherProcessJava (without the .class extension).

CVLaunchDialogJavaArguments

To allow us to monitor other programs we need to edit the list of applications we can monitor. Click the Edit... button to the right of the Application to monitor combo box. The Applications To Monitor dialog is displayed.

CVApplicationsToMonitorDialog

We need to add our target program to the list of programs to monitor. Click Add.... The Application To Monitor dialog is displayed. Choose the Java runtime java.exe using Browse.... C++ Coverage Validator will identify any other executables in the same folder and add these to the list of target programs you may want to monitor. You can remove any programs you don't want to monitor with the Remove and Remove All buttons. We now need to add the target program to the list of programs we want to monitor. Click Add... and select testAppFromOtherProcess.exe. Your dialog should look like the one shown below.

CVApplicationToMonitorDialogJava

Select testAppFromOtherProcess.exe in the Application to monitor combo. Leave the launch count set to 1. The first time testAppFromOtherProcess.exe is launched it will be monitored. Click Go! to start the parent process.

CVLaunchDialogApplicationToMonitorJava

The Java process launches testAppFromOtherProcess.exe immediately. As such you will notice that C++ Coverage Validator starts collecting code coverage almost instantly because it has recognised the Java process is launching a child process that is configured to be monitored and has the correct launch count.

CVCodeCoverageResultsJava

Command Line, example for Java

As you can see, it's slightly more complicated for Java than for C++, but only because the Java runtime is located in a different folder than the test executable and because we also have to specify a Java class to execute. We still managed to collect code coverage for a child process of a just in time compiled language without any coding.

Of course, you now want to know how to do this for the command line. Is this any more complicated than for the C++ example? No! Just as easy. Here's how you do it:

"c:\C++ Coverage Validator\coverageValidator.exe" 
-program "c:\program files\java\jdk1.8.0_121\bin\java.exe"
-directory "e:\test\release" 
-arg testAppFromOtherProcessJava
-programToMonitor "e:\test\release\testAppFromOtherProcess.exe"

How does this work?

  • -arg. Specify an argument to the program to launch. In this example this specifies the Java class to execute.
  • -directory. Specify the startup directory.
  • -program. Specify the program to launch. In this example this specifies the Java runtime.
  • -programToMonitor. Specify the program to that will be monitored for code coverage.

Use as many -arg options as you need. We only used one because that's all we need for the example.

Python

The parent program in Python is very simple.

import sys
import subprocess

cmdLine = r"E:\om\c\testApps\testAppFromOtherProcess\Release\testAppFromOtherProcess.exe"
for arg in range(1, len(sys.argv)):
  cmdLine += " "
  cmdLine += sys.argv[arg]
  
subprocess.call(cmdLine, stdin=None, stdout=None, stderr=None, shell=False)

Configuring the target Python program

As with the C++ target program we need to tell C++ Coverage Validator about the target program and the program that is going to launch it. We're running a Python program so the executable to launch is the Python interpreter. Click the Browse... button and select the Python interpreter you are using.

CVLaunchDialogPython

The launch directory is automatically configured to be the same as the launch program. In the case of a Python program, that is almost certainly incorrect. We're going to choose the directory where our Python script is located. Click the Dir... button and choose that directory.

CVLaunchDialogPythonDirectory

We also need to tell Python what script to launch. This is provided as an argument to the program being run (the Python interpreter). In the arguments field, type the name of the script. In this case testAppFromOtherProcess.py.

CVLaunchDialogPythonArguments

To allow us to monitor other programs we need to edit the list of applications we can monitor. Click the Edit... button to the right of the Application to monitor combo box. The Applications To Monitor dialog is displayed.

CVApplicationsToMonitorDialog

We need to add our target program to the list of programs to monitor. Click Add.... The Application To Monitor dialog is displayed. Choose the Python interpreter python.exe using Browse.... C++ Coverage Validator will identify any other executables in the same folder and add these to the list of target programs you may want to monitor. You can remove any programs you don't want to monitor with the Remove and Remove All buttons. We now need to add the target program to the list of programs we want to monitor. Click Add... and select testAppFromOtherProcess.exe. Your dialog should look like the one shown below.

CVApplicationToMonitorDialogPython

Select testAppFromOtherProcess.exe in the Application to monitor combo. Leave the launch count set to 1. The first time testAppFromOtherProcess.exe is launched it will be monitored. Click Go! to start the parent process.

CVLaunchDialogPythonAppToMonitor

The Python process launches testAppFromOtherProcess.exe immediately. As such you will notice that C++ Coverage Validator starts collecting code coverage almost instantly because it has recognised the Python process is launching a child process that is configured to be monitored and has the correct launch count.

CVCodeCoverageResultsPython

Command Line, example for Python

As you can see, it's slightly more complicated for Python than for C++, but only because the Python interpreter is located in a different folder than the test executable and because we also have to specify a Python script. We still managed to collect code coverage for a child process of a scripted language without any coding.

Of course, you now want to know how to do this for the command line. Is this any more complicated than for the C++ example? No! Just as easy. Here's how you do it:

"c:\C++ Coverage Validator\coverageValidator.exe" 
-program "c:\python36-32\python.exe"
-directory "e:\test\release" 
-arg testAppFromOtherProcess.py
-programToMonitor "e:\test\release\testAppFromOtherProcess.exe"

How does this work?

  • -arg. Specify an argument to the program to launch. In this example this specifies the Python script to run.
  • -directory. Specify the startup directory.
  • -program. Specify the program to launch. In this example this specifies the Python interpreter.
  • -programToMonitor. Specify the program to that will be monitored for code coverage.

Use as many -arg options as you need. We only used one because that's all we need for the example.

Conclusion

We've demonstrated how to monitor code coverage in a target program launched from C++, Java and Python, using both the GUI and the command line. Each example is slightly different, showing you the changes required for each situation. If you have any questions please email support@softwareverify.com

You can download the C++, Java and Python code used in these examples here.

Share

Leave a Reply

Panorama Theme by Themocracy