Test Functions Containing Complex Data Types Using Python API for Polyspace
R2026bYou can author graphical tests for your C/C++ code base entirely at the command line by using the Python® API for Polyspace®. This example demonstrates how to write tests using the API for functions that take in the following datatypes as input:
Structures
Enumerations
Unions
Pointers
Classes
Before writing tests using the Python API, you can familiarize yourself with the testing structure using the Polyspace Platform user interface. For an introduction to writing tests in the user interface, see Write C/C++ Unit Tests in Polyspace Platform User Interface. For an overview of how to add tests for various data types in the user interface, see Specify Test Inputs in Polyspace Platform User Interface.
For more information on customizing tests for simple functions using the Python API, see Author Graphical Tests Using Python API for Polyspace.
Prerequisites
Make sure you are using a supported Python version and you are able to import the polyspace.project
and polyspace.test
Python modules without errors. For more information, see Set Up Python API for Polyspace. The examples
below use source files that are available with a Polyspace installation.
Add Files and Parse Code
Import the modules polyspace.project and
polyspace.test, create a project, and add the source files in the
folders
<polyspaceroot>\polyspace\examples\doc_pstest\complex_types\src
and
<polyspaceroot>\polyspace\examples\doc_pstest\cpp_tabular_tests\src.
To allow for source files written in C and C++, set the build configuration language to
"C_CPP". Then, use the polyspace.project.parseCode
function to parse the source code and create a test suite for the project.
# Import the required modules.
import polyspace.project
import polyspace.test
import os
# Create project, add files, and set the build configuration language.
proj = polyspace.project.Project("newProject")
c_examples_path = os.path.join(polyspace.__install_path__, "polyspace", "examples", "doc_pstest", "complex_types", "src")
cpp_examples_path = os.path.join(polyspace.__install_path__, "polyspace", "examples", "doc_pstest", "cpp_tabular_tests", "src")
proj.Code.Files.add(os.path.join(c_examples_path, "allTypes.c"))
proj.Code.Files.add(os.path.join(cpp_examples_path, "GridPosition.cpp"))
proj.IncludePaths.add(c_examples_path)
proj.IncludePaths.add(cpp_examples_path)
# Set the build configuration language to C/C++ and parse the source code.
proj.ActiveBuildConfiguration.Language = "C_CPP"
codeInfo = polyspace.project.parseCode(proj)
# Create a test suite for the project.
suite = proj.TestSuites.create("AllTypesTestSuite")The polyspace.project.parseCode function returns an instance of the
polyspace.project.CodeInfo class that contains information about functions,
types, and globals in the source code. You can use the methods of this class to retrieve
this information and use them to author your test cases.
Add Simple Test for Function with Enumeration Input
Create a test case and test step for the colorValue function. Assign
the input and assessment values.
# Create a test case and test step for the colorValue function.
enumCase = suite.TestCases.create("ColorValueTest")
functionColorValue = codeInfo.getFunctionBySignature("int colorValue(MyEnum n)")
enumStep = enumCase.TestSteps.createTabular("ColorValueStep",functionColorValue)
# Set the input value of the enum to "RED" and set the assessment value to 0.
enumStep.Inputs["n"].Value = "RED"
enumStep.Assessments["pst_call_out"].Value = "0"Note
You can only assign strings to the Value property of an input,
assessment, parameter, test data, or observable. Therefore, put quotes around the values
you want to assign. For example:
To specify the integer
42, assign the string"42"to theValueproperty.To specify the double
3.14, assign the string"3.14"to theValueproperty.To specify the string
"My String", assign the string'"My String"'to theValueproperty.To specify the address of a variable
var, assign the string"&var"to theValueproperty.
When generating code for your tests, Polyspace Test™ uses the content of the string to reconstruct the value of the input, assessment, parameter, test data, or observable.
Add Simple Test for Function with Structure Input
Create a simple test for the negateStruct function which takes in a
structure passed by value as input and returns a structure with negated member values. When
attaching inputs and assessments to a test using the Polyspace Python API, we access fields by indexing into arrays, where the parameters and
field names act as indices. Attach an input structure with fields x=1.0
and y=2.0 to the test by indexing into the Inputs
property. Check the output against the assessment values x=-1.0 and
y=-2.0.
# Create a test case and test step for the negateStruct function.
structCase = suite.TestCases.create("NegateStructTest")
functionNegateStruct = codeInfo.getFunctionBySignature("MyStruct negateStruct(MyStruct s)")
structStep = structCase.TestSteps.createTabular("NegateStructStep",functionNegateStruct)
# Update the input value for the structure s to have values x=1.0 and y=2.0
structStep.Inputs["s"]["x"].Value = "1.0"
structStep.Inputs["s"]["y"].Value = "2.0"
# Update the assessment which is automatically created.
structStep.Assessments["pst_call_out"]["x"].Value = "-1.0"
structStep.Assessments["pst_call_out"]["y"].Value = "-2.0"Add Simple Test for Function with Union Input
Unions are similar to structures, but all its members share a single memory location.
When writing Polyspace tests for a function that takes in a union, you can only specify the value of
one member of the union at a time. To set the value of one of the members of the input union
MyUnion, index into the Inputs
property.
# Create a test case and test step for the doubleVal function.
unionCase = suite.TestCases.create("DoubleValTest")
functionDoubleVal = codeInfo.getFunctionBySignature("int doubleVal(MyUnion u, int useFloat)")
unionStep = unionCase.TestSteps.createTabular("DoubleValStep",functionDoubleVal)
# Set the intValue input of the union u by indexing into the union. Set the useFloat parameter to 0.
unionStep.Inputs["u"]["intValue"].Value = "5"
unionStep.Inputs["useFloat"].Value = "0"
# Set the assessment value to be the expected return value.
unionStep.Assessments["pst_call_out"].Value = "10"Add Simple Test for Function with Pointer Input
Create a simple test for the moveCoord function which takes in a
pointer to a structure. To add an input or assessment for the pointer c,
you must first create a test data object. Set the values in your pointer target by indexing
into the test data object.
# Create a test case and test step for the moveCoord function.
pointerCase = suite.TestCases.create("MoveCoordTest")
functionMoveCoord = codeInfo.getFunctionBySignature("void moveCoord(MyStruct *c)")
pointerStep = pointerCase.TestSteps.createTabular("MoveCoordStep",functionMoveCoord)
# Create a test data object for the inputs and set the type to be an array of length 1 of the Coord structure.
inputData = pointerCase.TestData.create("moveInputData",codeInfo.getType("MyStruct[1]"))
# Assign the input values of the structure by indexing into the test data object.
inputData[0]["x"].Value = "1.0"
inputData[0]["y"].Value = "2.0"
# Set the value of the pointer target c to the test data object.
pointerStep.Inputs["c"].Value = inputData
# Create a test data object for the assessments and assign their values.
expectedData = pointerCase.TestData.create("moveExpectedData",codeInfo.getType("MyStruct[1]"))
expectedData[0]["x"].Value = "1.5"
expectedData[0]["y"].Value = "2.3"
pointerStep.Assessments["c"].Value = expectedDataAdd Simple Test for Class Member Function
In a simple test for a C++ member function, you can create a class instance using a
constructor call and then invoke the member function. Create a test case and test step for
the GridPosition::getX() member function. Set the input value of
pst_obj to GridPosition(2,1). Assessments are
automatically added for pst_obj and pst_call_out.
Delete the assessment for pst_obj and set the expected value of the
pst_call_out assessment to 2.
# Create a test case and test step for the member function GridPosition::getX().
classCase = suite.TestCases.create("getXTest")
functionGetX = codeInfo.getFunctionBySignature("int32_t GridPosition::getX()")
classStep = classCase.TestSteps.createTabular("getXStep", functionGetX)
# Update inputs and assessments.
classStep.Inputs["pst_obj"].Value = "GridPosition(2,1)"
classStep.Assessments["pst_call_out"].Value = "2"
classStep.Assessments.pop("pst_obj")Create Multistep Test for Class Member Functions
When testing a C++ class, you might have to invoke several member functions on the same object in a multistep test. To reuse the same object across multiple steps, create a test data object for your test case and refer to this test data object in each test step.
In this example you will write a multistep test that will do the following: Set the data
members x and y to (1,1) using the member function
GridPosition::setPosition(int32_t, int32_t). Shift both data members by
1 using the member function GridPosition::shiftPosition(int32_t,
int32_t). Check that the new data member values correspond to (2,2) using the
member functions GridPosition::getX() and
GridPosition::getY().
Create a test case which will have several test steps and add a test data object to the test case. Then add the following test steps:
Create a test step for the member function
GridPosition::setPosition(int32_t, int32_t)and set the inputs ofxPosandyPosto 1. Set the input value ofpst_objto the test data object and remove the automatically generated assessment forpst_obj.Create a test step for the member function
GridPosition::shiftPosition(int32_t, int32_t)and set both the inputsxShiftandyShiftto 1. Set the input value ofpst_objto the test data object and remove the automatically generated assessment forpst_obj.Create a test step for the member function
GridPosition::getX(). Set the input value ofpst_objto the test data object. Set the value of thepst_call_outassessment to 2 and remove the automatically generated assessment forpst_obj.Create a test step for the member function
GridPosition::getY(). Set the input value ofpst_objto the test data object. Set the value of thepst_call_outassessment to 2 and remove the automatically generated assessment forpst_obj.
# Create a test case. Add a test data object to the test case and set the type to the GridPosition class.
classCase = suite.TestCases.create("MultistepTest")
testData = classCase.TestData.create("data_pst_obj", codeInfo.getType("GridPosition"))
# Create a test step for the member function GridPosition::setPosition(int32_t, int32_t).
functionSetPosition = codeInfo.getFunctionBySignature("GridPosition::setPosition(int32_t, int32_t)")
setPositionStep = classCase.TestSteps.createTabular("Step1", functionSetPosition)
# Set both the inputs xPos and yPos to 1. Set the input value of pst_obj to the test data object and remove the assessment for pst_obj.
setPositionStep.Inputs["xPos"].Value = "1"
setPositionStep.Inputs["yPos"].Value = "1"
setPositionStep.Inputs["pst_obj"].Value = testData
setPositionStep.Assessments.pop("pst_obj")
# Create a new test step for the member function GridPosition::shiftPosition(int32_t, int32_t).
functionShiftPosition = codeInfo.getFunctionBySignature("GridPosition::shiftPosition(int32_t, int32_t)")
shiftPositionStep = classCase.TestSteps.createTabular("Step2", functionShiftPosition)
# Set both the inputs xShift and yShift to 1. Set the value of the pst_obj input to the test data object and remove the assessment for pst_obj.
shiftPositionStep.Inputs["xShift"].Value = "1"
shiftPositionStep.Inputs["yShift"].Value = "1"
shiftPositionStep.Inputs["pst_obj"].Value = testData
shiftPositionStep.Assessments.pop("pst_obj")
# Create a new test step for the member function GridPosition::getX().
functionGetX = codeInfo.getFunctionBySignature("int32_t GridPosition::getX()")
getXStep = classCase.TestSteps.createTabular("Step3", functionGetX)
# Set the input value of pst_obj to the test data object. Set the value of the pst_call_out assessment to 2 and remove the assessment for pst_obj.
getXStep.Inputs["pst_obj"].Value = testData
getXStep.Assessments["pst_call_out"].Value = "2"
getXStep.Assessments.pop("pst_obj")
# Create a new test step for the member function GridPosition::getY().
functionGetY = codeInfo.getFunctionBySignature("int32_t GridPosition::getY()")
getYStep = classCase.TestSteps.createTabular("Step4", functionGetY)
# Set the input value of pst_obj to the test data object. Set the value of the pst_call_out assessment to 2 and remove the assessment for pst_obj.
getYStep.Inputs["pst_obj"].Value = testData
getYStep.Assessments["pst_call_out"].Value = "2"
getYStep.Assessments.pop("pst_obj")Build and Run Tests
Run the tests added to the project.
res = polyspace.test.run(proj)See Also
polyspace.test.run | polyspace.test.build | polyspace.project.Project | polyspace.test.TestResults | polyspace.project.CodeInfo | polyspace.project.ScriptedTestStep | polyspace.project.TestCase | polyspace.project.TabularTestStep