Compare and Display Values for Complex C/C++ Data Types Using Polyspace Test xUnit API
The Polyspace®
Test™ xUnit API provides predefined assessment macros to compare and display values for all fundamental data types. For example, to check for equality of two integers, you can use the macro PST_VERIFY_EQ_INT. For the full list of predefined macros, see Assessment Macros in Polyspace Test API for C/C++ Code.
For more complex data types, you have to write your own comparison and display functions to compare and display values. You can then provide these function names to a Polyspace Test xUnit API macro that supports custom functions and write tests for complex data types in a manner similar to fundamental data types.
This example shows how to define your own assessment macros for complex data types.
Prerequisites
To compile tests authored using the Polyspace Test xUnit API, you are required to know some file paths in advance. For your convenience, you can define environment variables to stand for the file paths, or otherwise include the file paths in your build. For more information, see Set Up C/C++ Testing and Code Profiling Using Self-Managed Builds.
Workflow
How to Define Assessments with Custom Comparison and Display Functions
To compare two integers, and actualValue, you perform an assessment such as:expectedValue
PST_VERIFY_EQ_INT(actualValue, expectedValue)
actualValue if the comparison fails.Suppose that your code contains a structured data type such as:
typedef struct Point {
int x;
int y;
} Point;Point:
Write your own comparison function,
, to check for equality of twofuncCompPointobjects, and your own display function,, to display their values.funcDispProvide these function names to the
PST_VERIFY_EQ_CUSTOMmacro and define your own assessment macroMY_VERIFY_EQ_Pointthat works exclusively on variables of typePoint:#define MY_VERIFY_EQ_Point(actualValue, expectedValue) \ PST_VERIFY_EQ_CUSTOM(actualValue, expectedValue, funcComp, funcDisp);Defining a new macro such as
MY_VERIFY_EQ_Pointis optional. You could have directly invoked the macroPST_VERIFY_EQ_CUSTOMfor comparing twoPointobjects. Defining a new macro saves you from having to specify the comparison and display functions each time you want to perform assessments onPointobjects.
Just like PST_VERIFY_EQ_INT can compare two integers for equality, you can now use the assessment macro MY_VERIFY_EQ_Point to compare equality of two Point objects.
Format of Comparison and Display Functions
The comparison and display functions must follow a strict format:
A function
that compares two objects must have this signature:funcCompThe function must behave like theint funcComp (const void *objLeft, const void *objRight);
strcmpfunction in C/C++ and return 0 if the comparison succeeds.A function
that displays an object value must have this signature:funcDispSee also Custom Test Result Display Functions for Complex C/C++ Data Types.void funcDisp (char *buffer, const pst_size_t bufferSize, const void* objToDisplay);
Since both functions take const void* pointers to accept the objects to compare or display, before using the pointers, cast them back to the correct object pointer type. The Polyspace
Test xUnit API provides the macro PST_STATIC_CAST to cast from one type to another. For example, in a comparison function that takes two objects of type Point, you can convert the function parameters from const void* to Point*:
int funcComp (const void* lhs, const void* rhs) {
const Point* lhs_Point = PST_STATIC_CAST(const Point*, lhs);
const Point* rhs_Point = PST_STATIC_CAST(const Point*, rhs);
...
}Example
Example Files
Copy code from steps 1 and 2 into .c files.
Alternatively, find the files for this tutorial in the folder . Copy these files to a writable location and continue the tutorial. Here, polyspaceroot\polyspace\examples\doc_pstest\complex_assessments is the Polyspace installation folder, for example, polyspacerootC:\Program Files\Polyspace\R2026a.
Inspect Function Under Test and Requirements
The function setOrigin initializes the value of a global structure origin of type Point, and the function shiftOrigin modifies this structure.
#include "example.h"
Point origin;
void setOrigin(void) {
origin.x = 0;
origin.y = 0;
}
void shiftOrigin(int shift) {
origin.x = shift;
}
example.c.A header file, example.h, defines the structured data type.
typedef struct Point {
int x;
int y;
}Point;
extern Point origin;Suppose you have to test that the two functions when executed one after another result in the correct value of the global structure. You can write a custom comparison function to compare two Point objects in an assessment and a custom display function to display their values if the assessment fails.
Write Test
The following test defines a custom comparison function, verifyXCoord, to compare two Point objects and a custom display function, displayPoint, to display their values if the assessment fails:
The comparison function
verifyXCoordcompares only the fieldxof twoPointobjects. If the comparison succeeds, the function returns 0.The display function
displayPointdisplays the value of aPointobject in a specific format. For example, if the object value is{0 , 0}, you see:x:0, y:0
The macro MY_VERIFY_EQ_Point compares two objects by using this custom comparison and display function. Users of this macro do not need to look up the appropriate comparison and display functions, and can simply provide the objects to compare.
#include <pstunit.h>
#include "example.h"
/* Function returns 0 if x-coordinate of lhs is equal to x-coordinate of rhs*/
int verifyXCoord (const void* lhs, const void* rhs) {
const Point* lhs_Point = PST_STATIC_CAST(const Point*, lhs);
const Point* rhs_Point = PST_STATIC_CAST(const Point*, rhs);
return !(lhs_Point->x == rhs_Point->x);
}
void displayPoint(char* buff, const pst_size_t buff_size, const void* val) {
const Point* val_Point = PST_STATIC_CAST(const Point*, val);
pst_format(buff, buff_size, "x:%d, y:%d", val_Point->x, val_Point->y);
}
#define MY_VERIFY_EQ_Point(lhs, rhs) \
PST_VERIFY_EQ_CUSTOM(lhs, rhs, verifyXCoord, displayPoint);
/* Tested functions */
Point setOrigin(void);
Point shiftOrigin(int);
PST_SIMPLE_TEST_CONFIG(test_origin_xShift) {
}
PST_SIMPLE_TEST_BODY(test_origin_xShift) {
int xShift;
xShift = 2;
Point expectedValue = {2,0};
Point expectedValueIncorrect = {3,0};
setOrigin();
shiftOrigin(xShift);
/* Assessments. */
PST_ASSESSMENT_ID("1");
MY_VERIFY_EQ_Point(origin, expectedValue);
PST_ASSESSMENT_ID("2");
MY_VERIFY_EQ_Point(origin, expectedValueIncorrect);
}
PST_REGFCN(myRegFcn) {
PST_ADD_SIMPLE_TEST(test_origin_xShift);
}
#ifndef PSTEST_BUILD
int main(int argc, char *argv[]) {
PST_REGFCN_CALL(myRegFcn);
return PST_MAIN(argc, argv);
}
#endifSave this code in a file test.c.
The test consists of these macros from the Polyspace Test xUnit API:
PST_SIMPLE_TEST_CONFIG– This macro defines the test configuration for the test casetest_origin_xShift.PST_SIMPLE_TEST_BODY– This macro defines the test body fortest_origin_xShiftand contains the call to the function under test.PST_VERIFY_EQ_Custom– This macro checks for the equality of two objects using a custom comparison function. If the comparison fails, a custom display function is used to display the object values.
The remaining macros, PST_REGFCN, PST_ADD_SIMPLE_TEST and PST_REGFCN_CALL, register the test.
Execute Test and Inspect Results
Compile the files example.c and test.c along with files that ship with Polyspace
Test. Here, the file example.h must be in the same folder as the source example.c.
gcc example.c test.c <PSTUNIT_SOURCE> -I . -I <PSTUNIT_INCLUDE> -o testrunner
<PSTUNIT_SOURCE> and <PSTUNIT_INCLUDE>, see Set Up C/C++ Testing and Code Profiling Using Self-Managed Builds.Run the test executable:
testrunner.exe
./testrunner in Linux®).The test contains two uses of the PST_VERIFY_EQ_Point to perform two comparisons. The first comparison succeeds and the second fails, leading to an overall test failure. The Polyspace
Test xUnit API reports the failing values in a custom display format.
| Running tests | | |-----------------|------------| | Running | suite | pst_default_suite |-----------------|------------| | Running | test | test_origin_xShift | VERIFY FAIL | | custom_assessment.c:51: Verify failed: '2' Expression 'verifyXCoord(&(origin), &(expectedValueIncorrect)) == 0' evaluated to false lhs="x:2, y:0" rhs="x:3, y:0" | FAIL | test | test_origin_xShift |-----------------|------------| | FAIL | suite | pst_default_suite | | Total | Passed | Failed | Incomplete |--------|--------|--------|--------|------------ | Suites | 1 | 0 | 1 | 0 | Tests | 1 | 0 | 1 | 0