Files
open62541/tests/server/check_node_inheritance.c
Andreas Ebner 918f2cfd4b fix(docs): typos in comments, docs and messages
Fix misspellings found with codespell across headers, sources, examples,
tests and the documentation, including "propably" in the nodeset
compiler docs. Identifiers, companion spec names and generated code are
left untouched.
2026-09-28 16:20:44 +02:00

479 lines
22 KiB
C

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <open62541/server_config_default.h>
#include "server/ua_server_internal.h"
#include "test_helpers.h"
#include <check.h>
#include <stdlib.h>
UA_Server *server = NULL;
UA_UInt32 valueToBeInherited = 42;
static void setup(void) {
server = UA_Server_newForUnitTest();
ck_assert(server != NULL);
UA_Server_run_startup(server);
}
static void teardown(void) {
UA_Server_run_shutdown(server);
UA_Server_delete(server);
}
#ifdef UA_GENERATED_NAMESPACE_ZERO
/* finds the NodeId of a StateNumber child of a given node id */
static void
findChildId(UA_NodeId parentNode, UA_NodeId referenceType,
const UA_QualifiedName targetName, UA_NodeId *result) {
UA_RelativePathElement rpe;
UA_RelativePathElement_init(&rpe);
rpe.referenceTypeId = referenceType;
rpe.isInverse = false;
rpe.includeSubtypes = false;
rpe.targetName = targetName;
UA_BrowsePath bp;
UA_BrowsePath_init(&bp);
bp.startingNode = parentNode;
bp.relativePath.elementsSize = 1;
bp.relativePath.elements = &rpe; //clion complains but is ok
UA_BrowsePathResult bpr = UA_Server_translateBrowsePathToNodeIds(server, &bp);
ck_assert_uint_eq(bpr.statusCode, UA_STATUSCODE_GOOD);
ck_assert(bpr.targetsSize > 0);
UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, result);
UA_BrowsePathResult_clear(&bpr);
}
#endif
START_TEST(Nodes_createCustomBrowseNameObjectType)
{
/* Create a custom object type "CustomBrowseNameType" which has a
* "DefaultInstanceBrowseName" property. */
/* create new object type node which has a subcomponent of the type StateType */
UA_ObjectTypeAttributes otAttr = UA_ObjectTypeAttributes_default;
otAttr.displayName = UA_LOCALIZEDTEXT("", "CustomBrowseNameType");
otAttr.description = UA_LOCALIZEDTEXT("", "");
UA_StatusCode retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 7010),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "CustomBrowseNameType"),
otAttr, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
// Now add a property "DefaultInstanceBrowseName"
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = UA_VALUERANK_ANY;
attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_QUALIFIEDNAME);
UA_QualifiedName defaultInstanceBrowseName = UA_QUALIFIEDNAME(1, "MyCustomBrowseName");
UA_Variant_setScalar(&attr.value, &defaultInstanceBrowseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
attr.displayName = UA_LOCALIZEDTEXT("", "DefaultInstanceBrowseName");
attr.description = UA_LOCALIZEDTEXT("", "");
attr.writeMask = 0;
attr.userWriteMask = 0;
retval = UA_Server_addVariableNode(server,
UA_NODEID_NUMERIC(1, 7011),
UA_NODEID_NUMERIC(1, 7010),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
UA_QUALIFIEDNAME(0, "DefaultInstanceBrowseName"),
UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE),
attr,
NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(Nodes_checkDefaultInstanceBrowseName) {
/* create an object/instance of the CustomDemoType.
* This should fail if we do not specify a browse name.
* CustomDemoType does not have a DefaultInstanceBrowseName
* */
UA_ObjectAttributes oAttr2 = UA_ObjectAttributes_default;
oAttr2.displayName = UA_LOCALIZEDTEXT("", "DemoCustomBrowseNameFail");
oAttr2.description = UA_LOCALIZEDTEXT("", "");
UA_QualifiedName nullName;
UA_QualifiedName_init(&nullName);
UA_StatusCode retval =
UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 7020),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
nullName, UA_NODEID_NUMERIC(1, 6010),
oAttr2, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_BADBROWSENAMEINVALID);
/* create an object/instance of the CustomBrowseNameType and set the default browse name */
oAttr2 = UA_ObjectAttributes_default;
oAttr2.displayName = UA_LOCALIZEDTEXT("", "DemoCustomBrowseName");
oAttr2.description = UA_LOCALIZEDTEXT("", "");
UA_QualifiedName_init(&nullName);
retval =
UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 7021),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
nullName, UA_NODEID_NUMERIC(1, 7010),
oAttr2, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
UA_QualifiedName receivedBrowseName;
UA_QualifiedName_init(&receivedBrowseName);
UA_QualifiedName defaultInstanceBrowseName = UA_QUALIFIEDNAME(1, "MyCustomBrowseName");
retval = UA_Server_readBrowseName(server, UA_NODEID_NUMERIC(1, 7021), &receivedBrowseName);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
ck_assert(UA_QualifiedName_equal(&receivedBrowseName, &defaultInstanceBrowseName) == true);
UA_QualifiedName_clear(&receivedBrowseName);
/* create an object/instance of the CustomBrowseNameType and set a custom browse name */
oAttr2 = UA_ObjectAttributes_default;
oAttr2.displayName = UA_LOCALIZEDTEXT("", "DemoCustomBrowseName");
oAttr2.description = UA_LOCALIZEDTEXT("", "");
UA_QualifiedName overriddenBrowseName = UA_QUALIFIEDNAME(1, "MyOverriddenBrowseName");
retval =
UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 7022),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
overriddenBrowseName, UA_NODEID_NUMERIC(1, 7010),
oAttr2, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
UA_QualifiedName_init(&receivedBrowseName);
retval = UA_Server_readBrowseName(server, UA_NODEID_NUMERIC(1, 7022), &receivedBrowseName);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
ck_assert(UA_QualifiedName_equal(&receivedBrowseName, &overriddenBrowseName) == true);
UA_QualifiedName_clear(&receivedBrowseName);
}
END_TEST
START_TEST(Nodes_createCustomStateType) {
// Create a type "CustomStateType" with a variable "CustomStateNumber" as property
UA_StatusCode retval = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attrObject = UA_ObjectTypeAttributes_default;
attrObject.displayName = UA_LOCALIZEDTEXT("", "CustomStateType");
attrObject.description = UA_LOCALIZEDTEXT("", "");
attrObject.writeMask = 0;
attrObject.userWriteMask = 0;
retval = UA_Server_addObjectTypeNode(server,
UA_NODEID_NUMERIC(1, 6000),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "CustomStateType"),
attrObject,
NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
// Now add a property "StateNumber"
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = UA_VALUERANK_ANY;
attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_UINT32);
UA_UInt32 val = 0;
UA_Variant_setScalar(&attr.value, &val, &UA_TYPES[UA_TYPES_UINT32]);
attr.displayName = UA_LOCALIZEDTEXT("", "CustomStateNumber");
attr.description = UA_LOCALIZEDTEXT("", "");
attr.writeMask = 0;
attr.userWriteMask = 0;
retval = UA_Server_addVariableNode(server,
UA_NODEID_NUMERIC(1, 6001),
UA_NODEID_NUMERIC(1, 6000),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
UA_QUALIFIEDNAME(1, "CustomStateNumber"),
UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE),
attr,
NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Minimal nodeset does not contain the modelling rule mandatory */
#ifdef UA_GENERATED_NAMESPACE_ZERO
retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(1, 6001),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY),
true);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
#endif
}
END_TEST
START_TEST(Nodes_createCustomObjectType) {
/* Create a custom object type "CustomDemoType" which has a
* "CustomStateType" component */
UA_StatusCode retval = UA_STATUSCODE_GOOD;
/* create new object type node which has a subcomponent of the type StateType */
UA_ObjectTypeAttributes otAttr = UA_ObjectTypeAttributes_default;
otAttr.displayName = UA_LOCALIZEDTEXT("", "CustomDemoType");
otAttr.description = UA_LOCALIZEDTEXT("", "");
retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 6010),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "CustomDemoType"),
otAttr, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
oAttr.displayName = UA_LOCALIZEDTEXT("", "State");
oAttr.description = UA_LOCALIZEDTEXT("", "");
retval = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 6011), UA_NODEID_NUMERIC(1, 6010),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "State"),
UA_NODEID_NUMERIC(1, 6000),
oAttr, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Minimal nodeset does not contain the modelling rule mandatory */
#ifdef UA_GENERATED_NAMESPACE_ZERO
/* modelling rule is mandatory so it will be inherited for the object
* created from CustomDemoType */
retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(1, 6011),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY),
true);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* assign a default value to the attribute "StateNumber" inside the state
* attribute (part of the MyDemoType) */
UA_Variant stateNum;
UA_Variant_init(&stateNum);
UA_Variant_setScalar(&stateNum, &valueToBeInherited, &UA_TYPES[UA_TYPES_UINT32]);
UA_NodeId childID;
findChildId(UA_NODEID_NUMERIC(1, 6011), UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
UA_QUALIFIEDNAME(1, "CustomStateNumber"), &childID);
ck_assert(!UA_NodeId_isNull(&childID));
retval = UA_Server_writeValue(server, childID, stateNum);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
#endif
}
END_TEST
START_TEST(Nodes_createInheritedObject) {
/* create an object/instance of the demo type */
UA_ObjectAttributes oAttr2 = UA_ObjectAttributes_default;
oAttr2.displayName = UA_LOCALIZEDTEXT("", "Demo");
oAttr2.description = UA_LOCALIZEDTEXT("", "");
UA_StatusCode retval =
UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 6020),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "Demo"), UA_NODEID_NUMERIC(1, 6010),
oAttr2, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
}
END_TEST
START_TEST(Nodes_checkInheritedValue) {
/* Minimal nodeset does not contain the modelling rule mandatory, therefore there is no CustomStateNumber */
#ifdef UA_GENERATED_NAMESPACE_ZERO
UA_NodeId childState;
findChildId(UA_NODEID_NUMERIC(1, 6020),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "State"), &childState);
ck_assert(!UA_NodeId_isNull(&childState));
UA_NodeId childNumber;
findChildId(childState, UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
UA_QUALIFIEDNAME(1, "CustomStateNumber"), &childNumber);
ck_assert(!UA_NodeId_isNull(&childNumber));
UA_ReadValueId rvi;
UA_ReadValueId_init(&rvi);
rvi.nodeId = childNumber;
rvi.attributeId = UA_ATTRIBUTEID_VALUE;
UA_DataValue inheritedValue = UA_Server_read(server, &rvi, UA_TIMESTAMPSTORETURN_BOTH);
ck_assert(inheritedValue.value.type == &UA_TYPES[UA_TYPES_UINT32]);
UA_UInt32 *value = (UA_UInt32 *) inheritedValue.value.data;
ck_assert_int_eq(*value, valueToBeInherited);
/* Write a specific timestamp */
UA_WriteValue wValue;
UA_WriteValue_init(&wValue);
wValue.value = inheritedValue;
wValue.value.hasSourceTimestamp = true;
wValue.value.sourceTimestamp = 1337;
wValue.nodeId = childNumber;
wValue.attributeId = UA_ATTRIBUTEID_VALUE;
UA_StatusCode retval = UA_Server_write(server, &wValue);
ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
/* Read the timestamp back out */
UA_DataValue resp = UA_Server_read(server, &rvi, UA_TIMESTAMPSTORETURN_BOTH);
ck_assert(resp.hasSourceTimestamp);
ck_assert_int_eq(resp.sourceTimestamp, 1337);
UA_DataValue_clear(&resp);
UA_DataValue_clear(&inheritedValue);
#endif
}
END_TEST
START_TEST(Nodes_createCustomInterfaceType) {
/* Minimal nodeset does not have the Interface definitions */
#ifdef UA_GENERATED_NAMESPACE_ZERO
/* Create a custom interface type */
UA_ObjectTypeAttributes otAttr = UA_ObjectTypeAttributes_default;
otAttr.displayName = UA_LOCALIZEDTEXT("", "ILocationType");
otAttr.description = UA_LOCALIZEDTEXT("", "");
UA_StatusCode retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 8000),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEINTERFACETYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "ILocationType"),
otAttr, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
oAttr.displayName = UA_LOCALIZEDTEXT("", "InterfaceChild");
oAttr.description = UA_LOCALIZEDTEXT("", "");
retval = UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 8001), UA_NODEID_NUMERIC(1, 8000),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "InterfaceChild"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
oAttr, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(1, 8001),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY),
true);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* create an object type which has the interface */
otAttr = UA_ObjectTypeAttributes_default;
otAttr.displayName = UA_LOCALIZEDTEXT("", "ObjectWithLocation");
otAttr.description = UA_LOCALIZEDTEXT("", "");
retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NUMERIC(1, 8002),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "ObjectWithLocation"),
otAttr, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(1, 8002), UA_NODEID_NUMERIC(0, UA_NS0ID_HASINTERFACE), UA_EXPANDEDNODEID_NUMERIC(1, 8000), true);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
#endif
}
END_TEST
START_TEST(Nodes_createObjectWithInterfaceOnType) {
/* Minimal nodeset does not have the Interface definitions */
#ifdef UA_GENERATED_NAMESPACE_ZERO
/* create an object/instance of the demo type */
UA_ObjectAttributes oAttr2 = UA_ObjectAttributes_default;
oAttr2.displayName = UA_LOCALIZEDTEXT("", "ObjectInstanceOfInterface");
oAttr2.description = UA_LOCALIZEDTEXT("", "");
UA_StatusCode retval =
UA_Server_addObjectNode(server, UA_NODEID_NUMERIC(1, 8020),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "ObjectInstanceOfInterface"), UA_NODEID_NUMERIC(1, 8002),
oAttr2, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Check that object has inherited the interface children */
UA_NodeId childId;
findChildId(UA_NODEID_NUMERIC(1, 8020),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "InterfaceChild"), &childId);
ck_assert(!UA_NodeId_isNull(&childId));
#endif
}
END_TEST
START_TEST(Nodes_createObjectWithInterfaceOnObject) {
/* Minimal nodeset does not have the Interface definitions */
#ifdef UA_GENERATED_NAMESPACE_ZERO
/* create an object of base object type */
UA_ObjectAttributes oAttr2 = UA_ObjectAttributes_default;
oAttr2.displayName = UA_LOCALIZEDTEXT("", "ObjectInstanceWithInterface");
oAttr2.description = UA_LOCALIZEDTEXT("", "");
UA_StatusCode retval =
UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 8021),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "ObjectInstanceWithInterface"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
(const UA_NodeAttributes*)&oAttr2,&UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Add HasInterface to object */
retval = UA_Server_addReference(server, UA_NODEID_NUMERIC(1, 8021), UA_NODEID_NUMERIC(0, UA_NS0ID_HASINTERFACE), UA_EXPANDEDNODEID_NUMERIC(1, 8000), true);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Finish object node creation */
retval = UA_Server_addNode_finish(server,UA_NODEID_NUMERIC(1, 8021));
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Check that object has inherited the interface children */
UA_NodeId childId;
findChildId(UA_NODEID_NUMERIC(1, 8021),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "InterfaceChild"), &childId);
ck_assert(!UA_NodeId_isNull(&childId));
#endif
}
END_TEST
static Suite *testSuite_Client(void) {
Suite *s = suite_create("Node inheritance");
TCase *tc_inherit_subtype = tcase_create("Inherit subtype value");
tcase_add_unchecked_fixture(tc_inherit_subtype, setup, teardown);
tcase_add_test(tc_inherit_subtype, Nodes_createCustomStateType);
tcase_add_test(tc_inherit_subtype, Nodes_createCustomObjectType);
tcase_add_test(tc_inherit_subtype, Nodes_createInheritedObject);
tcase_add_test(tc_inherit_subtype, Nodes_checkInheritedValue);
tcase_add_test(tc_inherit_subtype, Nodes_createCustomBrowseNameObjectType);
tcase_add_test(tc_inherit_subtype, Nodes_checkDefaultInstanceBrowseName);
suite_add_tcase(s, tc_inherit_subtype);
TCase *tc_interface_addin = tcase_create("Interfaces and Addins");
tcase_add_unchecked_fixture(tc_interface_addin, setup, teardown);
tcase_add_test(tc_interface_addin, Nodes_createCustomInterfaceType);
tcase_add_test(tc_interface_addin, Nodes_createObjectWithInterfaceOnType);
tcase_add_test(tc_interface_addin, Nodes_createObjectWithInterfaceOnObject);
suite_add_tcase(s, tc_interface_addin);
return s;
}
int main(void) {
Suite *s = testSuite_Client();
SRunner *sr = srunner_create(s);
srunner_set_fork_status(sr, CK_NOFORK);
srunner_run_all(sr, CK_NORMAL);
int number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}