/* 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 #include #include #include #include #include #include "thread_wrapper.h" UA_Server *server; UA_Boolean running; UA_ServerNetworkLayer nl; THREAD_HANDLE server_thread; UA_Client *client; #define CUSTOM_NS "http://open62541.org/ns/test" #define CUSTOM_NS_UPPER "http://open62541.org/ns/Test" THREAD_CALLBACK(serverloop) { while (running) UA_Server_run_iterate(server, true); return 0; } static void setup(void) { running = true; server = UA_Server_new(); UA_ServerConfig_setDefault(UA_Server_getConfig(server)); ck_assert_uint_eq(2, UA_Server_addNamespace(server, CUSTOM_NS)); UA_Server_run_startup(server); THREAD_CREATE(server_thread, serverloop); client = UA_Client_new(); UA_ClientConfig_setDefault(UA_Client_getConfig(client)); UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840"); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } static void teardown(void) { UA_Client_disconnect(client); UA_Client_delete(client); running = false; THREAD_JOIN(server_thread); UA_Server_run_shutdown(server); UA_Server_delete(server); } START_TEST(Misc_State) { UA_ClientState state = UA_Client_getState(client); ck_assert_uint_eq(state, UA_CLIENTSTATE_SESSION); } END_TEST START_TEST(Misc_NamespaceGetIndex) { UA_UInt16 idx; UA_String ns = UA_STRING(CUSTOM_NS); UA_StatusCode retval = UA_Client_NamespaceGetIndex(client, &ns, &idx); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_uint_eq(idx, 2); // namespace uri is case sensitive ns = UA_STRING(CUSTOM_NS_UPPER); retval = UA_Client_NamespaceGetIndex(client, &ns, &idx); ck_assert_uint_eq(retval, UA_STATUSCODE_BADNOTFOUND); } END_TEST UA_NodeId newReferenceTypeId; UA_NodeId newObjectTypeId; UA_NodeId newDataTypeId; UA_NodeId newVariableTypeId; UA_NodeId newObjectId; UA_NodeId newVariableId; UA_NodeId newMethodId; UA_NodeId newViewId; #ifdef UA_ENABLE_NODEMANAGEMENT START_TEST(Node_Add) { UA_StatusCode retval; // Create custom reference type 'HasSubSubType' as child of HasSubtype { UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Some HasSubSubType"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "HasSubSubType"); retval = UA_Client_addReferenceTypeNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_QUALIFIEDNAME(1, "HasSubSubType"), attr, &newReferenceTypeId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // Create TestObjectType SubType within BaseObjectType { UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Some TestObjectType"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "TestObjectType"); retval = UA_Client_addObjectTypeNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_QUALIFIEDNAME(1, "TestObjectType"), attr, &newObjectTypeId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } /* Minimal nodeset does not contain UA_NS0ID_INTEGER node */ #ifdef UA_GENERATED_NAMESPACE_ZERO // Create Int128 DataType within Integer Datatype { UA_DataTypeAttributes attr = UA_DataTypeAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Some Int128"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "Int128"); retval = UA_Client_addDataTypeNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_INTEGER), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_QUALIFIEDNAME(1, "Int128"), attr, &newDataTypeId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } #endif // Create PointType VariableType within BaseDataVariableType { UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default; attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId; attr.valueRank = UA_VALUERANK_ONE_DIMENSION; UA_UInt32 arrayDims[1] = {2}; attr.arrayDimensions = arrayDims; attr.arrayDimensionsSize = 1; attr.displayName = UA_LOCALIZEDTEXT("en-US", "PointType"); /* a matching default value is required */ UA_Double zero[2] = {0.0, 0.0}; UA_Variant_setArray(&attr.value, zero, 2, &UA_TYPES[UA_TYPES_INT32]); retval = UA_Client_addVariableTypeNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_QUALIFIEDNAME(1, "PointType"), attr, &newVariableTypeId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // create Coordinates Object within ObjectsFolder { UA_ObjectAttributes attr = UA_ObjectAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Some Coordinates"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "Coordinates"); retval = UA_Client_addObjectNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Coordinates"), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), attr, &newObjectId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // create Variable 'Top' within Coordinates Object { UA_VariableAttributes attr = UA_VariableAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Top Coordinate"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "Top"); UA_Int32 values[2] = {10, 20}; UA_Variant_setArray(&attr.value, values, 2, &UA_TYPES[UA_TYPES_INT32]); attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId; attr.valueRank = UA_VALUERANK_ONE_DIMENSION; UA_UInt32 arrayDims[1] = {2}; attr.arrayDimensions = arrayDims; attr.arrayDimensionsSize = 1; retval = UA_Client_addVariableNode(client, UA_NODEID_NULL, newObjectId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), UA_QUALIFIEDNAME(1, "Top"), newVariableTypeId, attr, &newVariableId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // create Method 'Dummy' within Coordinates Object. { UA_MethodAttributes attr = UA_MethodAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Dummy method"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "Dummy"); attr.executable = true; attr.userExecutable = true; retval = UA_Client_addMethodNode(client, UA_NODEID_NULL, newObjectId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT), UA_QUALIFIEDNAME(1, "Dummy"), attr, &newMethodId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // create View 'AllTopCoordinates' whithin Views Folder { UA_ViewAttributes attr = UA_ViewAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "List of all top coordinates"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "AllTopCoordinates"); retval = UA_Client_addViewNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "AllTopCoordinates"), attr, &newViewId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } UA_ExpandedNodeId target = UA_EXPANDEDNODEID_NULL; target.nodeId = newObjectId; // Add 'Top' to view retval = UA_Client_addReference(client, newViewId, UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_TRUE, UA_STRING_NULL, target, UA_NODECLASS_VARIABLE); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); // Delete 'Top' from view retval = UA_Client_deleteReference(client, newViewId, UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), true, target, true); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); // Delete 'AllTopCoordinates' view retval = UA_Client_deleteNode(client, newViewId, UA_TRUE); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } END_TEST unsigned int iteratedNodeCount = 0; UA_NodeId iteratedNodes[4]; static UA_StatusCode nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle) { if (isInverse || (referenceTypeId.identifierType == UA_NODEIDTYPE_NUMERIC && referenceTypeId.identifier.numeric == UA_NS0ID_HASTYPEDEFINITION)) return UA_STATUSCODE_GOOD; if (iteratedNodeCount >= 4) return UA_STATUSCODE_BADINDEXRANGEINVALID; UA_NodeId_copy(&childId, &iteratedNodes[iteratedNodeCount]); iteratedNodeCount++; return UA_STATUSCODE_GOOD; } #endif START_TEST(Node_Browse) { // Browse node in server folder UA_BrowseRequest bReq; UA_BrowseRequest_init(&bReq); // normally is set to 0, to get all the nodes, but we want to test browse next bReq.requestedMaxReferencesPerNode = 1; bReq.nodesToBrowse = UA_BrowseDescription_new(); bReq.nodesToBrowseSize = 1; bReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER); bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq); ck_assert_uint_eq(bResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD); ck_assert_uint_eq(bResp.resultsSize, 1); ck_assert_uint_eq(bResp.results[0].statusCode, UA_STATUSCODE_GOOD); ck_assert_uint_eq(bResp.results[0].referencesSize, 1); /* References might have a different order in generated nodesets */ /* UA_ReferenceDescription *ref = &(bResp.results[0].references[0]); */ /* ck_assert_uint_eq(ref->nodeId.nodeId.identifier.numeric, UA_NS0ID_SERVERTYPE); */ // browse next UA_BrowseNextRequest bNextReq; UA_BrowseNextRequest_init(&bNextReq); // normally is set to 0, to get all the nodes, but we want to test browse next bNextReq.releaseContinuationPoints = UA_FALSE; bNextReq.continuationPoints = &bResp.results[0].continuationPoint; bNextReq.continuationPointsSize = 1; UA_BrowseNextResponse bNextResp = UA_Client_Service_browseNext(client, bNextReq); ck_assert_uint_eq(bNextResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD); ck_assert_uint_eq(bNextResp.resultsSize, 1); ck_assert_uint_eq(bNextResp.results[0].statusCode, UA_STATUSCODE_GOOD); ck_assert_uint_eq(bNextResp.results[0].referencesSize, 1); /* ref = &(bNextResp.results[0].references[0]); */ /* ck_assert_uint_eq(ref->nodeId.nodeId.identifier.numeric, UA_NS0ID_SERVER_NAMESPACEARRAY); */ UA_BrowseNextResponse_deleteMembers(&bNextResp); bNextResp = UA_Client_Service_browseNext(client, bNextReq); ck_assert_uint_eq(bNextResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD); ck_assert_uint_eq(bNextResp.resultsSize, 1); ck_assert_uint_eq(bNextResp.results[0].statusCode, UA_STATUSCODE_GOOD); ck_assert_uint_eq(bNextResp.results[0].referencesSize, 1); /* ref = &(bNextResp.results[0].references[0]); */ /* ck_assert_uint_eq(ref->nodeId.nodeId.identifier.numeric, UA_NS0ID_SERVER_SERVERARRAY); */ UA_BrowseNextResponse_deleteMembers(&bNextResp); // release continuation point. Result is then empty bNextReq.releaseContinuationPoints = UA_TRUE; bNextResp = UA_Client_Service_browseNext(client, bNextReq); UA_BrowseNextResponse_deleteMembers(&bNextResp); ck_assert_uint_eq(bNextResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD); ck_assert_uint_eq(bNextResp.resultsSize, 0); UA_BrowseRequest_deleteMembers(&bReq); UA_BrowseResponse_deleteMembers(&bResp); // already deleted by browse request bNextReq.continuationPoints = NULL; bNextReq.continuationPointsSize = 0; UA_BrowseNextRequest_deleteMembers(&bNextReq); } END_TEST START_TEST(Node_Register) { UA_RegisterNodesRequest req; UA_RegisterNodesRequest_init(&req); req.nodesToRegister = UA_NodeId_new(); req.nodesToRegister[0] = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME); req.nodesToRegisterSize = 1; UA_RegisterNodesResponse res = UA_Client_Service_registerNodes(client, req); ck_assert_uint_eq(res.responseHeader.serviceResult, UA_STATUSCODE_GOOD); ck_assert_uint_eq(res.registeredNodeIdsSize, 1); UA_UnregisterNodesRequest reqUn; UA_UnregisterNodesRequest_init(&reqUn); reqUn.nodesToUnregister = UA_NodeId_new(); reqUn.nodesToUnregister[0] = res.registeredNodeIds[0]; reqUn.nodesToUnregisterSize = 1; UA_UnregisterNodesResponse resUn = UA_Client_Service_unregisterNodes(client, reqUn); ck_assert_uint_eq(resUn.responseHeader.serviceResult, UA_STATUSCODE_GOOD); UA_UnregisterNodesRequest_deleteMembers(&reqUn); UA_UnregisterNodesResponse_deleteMembers(&resUn); UA_RegisterNodesRequest_deleteMembers(&req); UA_RegisterNodesResponse_deleteMembers(&res); } END_TEST // NodeIds for ReadWrite testing UA_NodeId nodeReadWriteUnitTest; UA_NodeId nodeReadWriteArray; UA_NodeId nodeReadWriteInt; UA_NodeId nodeReadWriteGeneric; UA_NodeId nodeReadWriteTestObjectType; UA_NodeId nodeReadWriteTestHasSubSubType; UA_NodeId nodeReadWriteView; UA_NodeId nodeReadWriteMethod; #ifdef UA_ENABLE_NODEMANAGEMENT START_TEST(Node_AddReadWriteNodes) { UA_StatusCode retval; // Create a folder with two variables for testing // create Coordinates Object within ObjectsFolder { UA_ObjectAttributes attr = UA_ObjectAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "UnitTest"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "UnitTest"); retval = UA_Client_addObjectNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "UnitTest"), UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), attr, &nodeReadWriteUnitTest); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // create Variable 'Top' within UnitTest Object { UA_VariableAttributes attr = UA_VariableAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Array"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "Array"); attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; attr.writeMask = UA_WRITEMASK_ARRRAYDIMENSIONS; UA_Int32 values[2]; values[0] = 10; values[1] = 20; UA_Variant_setArray(&attr.value, values, 2, &UA_TYPES[UA_TYPES_INT32]); attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId; attr.valueRank = UA_VALUERANK_ONE_DIMENSION; UA_UInt32 arrayDims[1] = {2}; attr.arrayDimensions = arrayDims; attr.arrayDimensionsSize = 1; retval = UA_Client_addVariableNode(client, UA_NODEID_NULL, nodeReadWriteUnitTest, UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Array"), UA_NODEID_NULL, attr, &nodeReadWriteArray); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // create Variable 'Int' within UnitTest Object { UA_VariableAttributes attr = UA_VariableAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Int"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "Int"); attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; attr.writeMask = 0xFFFFFFFF; UA_Int32 int_value = 5678; UA_Variant_setScalar(&attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]); attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId; retval = UA_Client_addVariableNode(client, UA_NODEID_NULL, nodeReadWriteUnitTest, UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Int"), UA_NODEID_NULL, attr, &nodeReadWriteInt); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // create Variable 'Generic' within UnitTest Object { UA_VariableAttributes attr = UA_VariableAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Generic"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "Generic"); attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE; attr.writeMask = 0xFFFFFFFF; // generic datatype attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE); retval = UA_Client_addVariableNode(client, UA_NODEID_NULL, nodeReadWriteUnitTest, UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "Generic"), UA_NODEID_NULL, attr, &nodeReadWriteGeneric); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // create Method 'Dummy' within Coordinates Object. { UA_MethodAttributes attr = UA_MethodAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Dummy method"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "Dummy"); attr.executable = true; attr.userExecutable = true; attr.writeMask = 0xFFFFFFFF; retval = UA_Client_addMethodNode(client, UA_NODEID_NULL, nodeReadWriteUnitTest, UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT), UA_QUALIFIEDNAME(1, "Dummy"), attr, &nodeReadWriteMethod); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // Create TestObjectType SubType within BaseObjectType { UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Some TestObjectType"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "TestObjectType"); attr.writeMask = 0xFFFFFFFF; retval = UA_Client_addObjectTypeNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_QUALIFIEDNAME(1, "TestObjectType"), attr, &nodeReadWriteTestObjectType); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // Create custom reference type 'HasSubSubType' as child of HasSubtype { UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "Some HasSubSubType"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "HasSubSubType"); attr.inverseName = UA_LOCALIZEDTEXT("en-US", "HasParentParentType"); attr.writeMask = 0xFFFFFFFF; retval = UA_Client_addReferenceTypeNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE), UA_QUALIFIEDNAME(1, "HasSubSubType"), attr, &nodeReadWriteTestHasSubSubType); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // create View 'AllTopCoordinates' whithin Views Folder { UA_ViewAttributes attr = UA_ViewAttributes_default; attr.description = UA_LOCALIZEDTEXT("en-US", "List of all top coordinates"); attr.displayName = UA_LOCALIZEDTEXT("en-US", "AllTopCoordinates"); attr.writeMask = 0xFFFFFFFF; retval = UA_Client_addViewNode(client, UA_NODEID_NULL, UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER), UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), UA_QUALIFIEDNAME(1, "AllTopCoordinates"), attr, &nodeReadWriteView); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } // iterate over children retval = UA_Client_forEachChildNodeCall(client, nodeReadWriteUnitTest, nodeIter, NULL); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(UA_NodeId_equal(&nodeReadWriteArray, &iteratedNodes[0])); ck_assert(UA_NodeId_equal(&nodeReadWriteInt, &iteratedNodes[1])); } END_TEST START_TEST(Node_ReadWrite_Id) { UA_NodeId newNodeId; // read to check if node id was changed UA_StatusCode retval = UA_Client_readNodeIdAttribute(client, nodeReadWriteInt, &newNodeId); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(UA_NodeId_equal(&newNodeId, &nodeReadWriteInt)); newNodeId.identifier.numeric = 900; retval = UA_Client_writeNodeIdAttribute(client, nodeReadWriteInt, &newNodeId); ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED); } END_TEST static void checkNodeClass(UA_Client *clientNc, const UA_NodeId nodeId, const UA_NodeClass expectedClass) { UA_NodeClass nodeClass = UA_NODECLASS_UNSPECIFIED; UA_StatusCode retval = UA_Client_readNodeClassAttribute(clientNc, nodeId, &nodeClass); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(nodeClass, expectedClass); } START_TEST(Node_ReadWrite_Class) { checkNodeClass(client, nodeReadWriteInt, UA_NODECLASS_VARIABLE); checkNodeClass(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), UA_NODECLASS_OBJECT); /* Minimal nodeset does not contain UA_NS0ID_SERVER_GETMONITOREDITEMS node */ #if defined(UA_ENABLE_METHODCALLS) && defined(UA_GENERATED_NAMESPACE_ZERO) checkNodeClass(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), UA_NODECLASS_METHOD); #endif UA_NodeClass newClass = UA_NODECLASS_METHOD; UA_StatusCode retval = UA_Client_writeNodeClassAttribute(client, nodeReadWriteInt, &newClass); ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED); } END_TEST START_TEST(Node_ReadWrite_BrowseName) { UA_QualifiedName browseName; UA_StatusCode retval = UA_Client_readBrowseNameAttribute(client, nodeReadWriteInt, &browseName); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_QualifiedName orig = UA_QUALIFIEDNAME(1, "Int"); ck_assert_int_eq(browseName.namespaceIndex, orig.namespaceIndex); ck_assert(UA_String_equal(&browseName.name, &orig.name)); UA_QualifiedName_deleteMembers(&browseName); browseName = UA_QUALIFIEDNAME(1,"Int-Changed"); retval = UA_Client_writeBrowseNameAttribute(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &browseName); ck_assert_uint_eq(retval, UA_STATUSCODE_BADUSERACCESSDENIED); retval = UA_Client_writeBrowseNameAttribute(client, nodeReadWriteInt, &browseName); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_QualifiedName browseNameChangedRead; retval = UA_Client_readBrowseNameAttribute(client, nodeReadWriteInt, &browseNameChangedRead); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(browseName.namespaceIndex, browseNameChangedRead.namespaceIndex); ck_assert(UA_String_equal(&browseName.name, &browseNameChangedRead.name)); UA_QualifiedName_deleteMembers(&browseNameChangedRead); } END_TEST START_TEST(Node_ReadWrite_DisplayName) { UA_LocalizedText displayName; UA_StatusCode retval = UA_Client_readDisplayNameAttribute(client, nodeReadWriteInt, &displayName); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_LocalizedText orig = UA_LOCALIZEDTEXT("en-US", "Int"); ck_assert(UA_String_equal(&displayName.locale, &orig.locale)); ck_assert(UA_String_equal(&displayName.text, &orig.text)); UA_LocalizedText_deleteMembers(&displayName); UA_LocalizedText newLocale = UA_LOCALIZEDTEXT("en-US", "Int-Changed"); retval = UA_Client_writeDisplayNameAttribute(client, nodeReadWriteInt, &newLocale); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_LocalizedText displayNameChangedRead; retval = UA_Client_readDisplayNameAttribute(client, nodeReadWriteInt, &displayNameChangedRead); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(UA_String_equal(&newLocale.locale, &displayNameChangedRead.locale)); ck_assert(UA_String_equal(&newLocale.text, &displayNameChangedRead.text)); UA_LocalizedText_deleteMembers(&displayNameChangedRead); } END_TEST START_TEST(Node_ReadWrite_Description) { UA_LocalizedText description; UA_StatusCode retval = UA_Client_readDescriptionAttribute(client, nodeReadWriteInt, &description); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_LocalizedText orig = UA_LOCALIZEDTEXT("en-US", "Int"); ck_assert(UA_String_equal(&description.locale, &orig.locale)); ck_assert(UA_String_equal(&description.text, &orig.text)); UA_LocalizedText_deleteMembers(&description); UA_LocalizedText newLocale = UA_LOCALIZEDTEXT("en-US", "Int-Changed"); retval = UA_Client_writeDescriptionAttribute(client, nodeReadWriteInt, &newLocale); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_LocalizedText descriptionChangedRead; retval = UA_Client_readDescriptionAttribute(client, nodeReadWriteInt, &descriptionChangedRead); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(UA_String_equal(&newLocale.locale, &descriptionChangedRead.locale)); ck_assert(UA_String_equal(&newLocale.text, &descriptionChangedRead.text)); UA_LocalizedText_deleteMembers(&descriptionChangedRead); } END_TEST START_TEST(Node_ReadWrite_WriteMask) { UA_UInt32 writeMask; UA_StatusCode retval = UA_Client_readWriteMaskAttribute(client, nodeReadWriteInt, &writeMask); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(writeMask, 0xFFFFFFFF); // Disable a random write mask bit UA_UInt32 newMask = 0xFFFFFFFF & ~UA_WRITEMASK_BROWSENAME; retval = UA_Client_writeWriteMaskAttribute(client, nodeReadWriteInt, &newMask); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_UInt32 writeMaskChangedRead; retval = UA_Client_readWriteMaskAttribute(client, nodeReadWriteInt, &writeMaskChangedRead); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(writeMaskChangedRead, newMask); } END_TEST START_TEST(Node_ReadWrite_UserWriteMask) { UA_UInt32 userWriteMask; UA_StatusCode retval = UA_Client_readUserWriteMaskAttribute(client, nodeReadWriteInt, &userWriteMask); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(userWriteMask, 0xFFFFFFFF & ~UA_WRITEMASK_BROWSENAME); // Disable a random write mask bit UA_UInt32 newMask = 0xFFFFFFFF & ~UA_WRITEMASK_DISPLAYNAME; retval = UA_Client_writeUserWriteMaskAttribute(client, nodeReadWriteInt, &newMask); ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED); } END_TEST START_TEST(Node_ReadWrite_IsAbstract) { UA_Boolean isAbstract; UA_StatusCode retval = UA_Client_readIsAbstractAttribute(client, nodeReadWriteInt, &isAbstract); ck_assert_uint_eq(retval, UA_STATUSCODE_BADATTRIBUTEIDINVALID); retval = UA_Client_readIsAbstractAttribute(client, nodeReadWriteTestObjectType, &isAbstract); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(isAbstract, UA_FALSE); UA_Boolean newIsAbstract = UA_TRUE; retval = UA_Client_writeIsAbstractAttribute(client, nodeReadWriteTestObjectType, &newIsAbstract); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readIsAbstractAttribute(client, nodeReadWriteTestObjectType, &isAbstract); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(isAbstract, newIsAbstract); } END_TEST START_TEST(Node_ReadWrite_Symmetric) { UA_Boolean symmetric; UA_StatusCode retval = UA_Client_readSymmetricAttribute(client, nodeReadWriteInt, &symmetric); ck_assert_uint_eq(retval, UA_STATUSCODE_BADATTRIBUTEIDINVALID); retval = UA_Client_readSymmetricAttribute(client, nodeReadWriteTestHasSubSubType, &symmetric); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(symmetric, UA_FALSE); UA_Boolean newSymmetric = UA_TRUE; retval = UA_Client_writeSymmetricAttribute(client, nodeReadWriteTestHasSubSubType, &newSymmetric); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readSymmetricAttribute(client, nodeReadWriteTestHasSubSubType, &symmetric); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(symmetric, newSymmetric); } END_TEST START_TEST(Node_ReadWrite_InverseName) { UA_LocalizedText inverseName; UA_StatusCode retval = UA_Client_readInverseNameAttribute(client, nodeReadWriteTestHasSubSubType, &inverseName); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_LocalizedText orig = UA_LOCALIZEDTEXT("en-US", "HasParentParentType"); ck_assert(UA_String_equal(&inverseName.locale, &orig.locale)); ck_assert(UA_String_equal(&inverseName.text, &orig.text)); UA_LocalizedText_deleteMembers(&inverseName); UA_LocalizedText newLocale = UA_LOCALIZEDTEXT("en-US", "HasParentParentType-Changed"); retval = UA_Client_writeInverseNameAttribute(client, nodeReadWriteTestHasSubSubType, &newLocale); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_LocalizedText inverseNameChangedRead; retval = UA_Client_readInverseNameAttribute(client, nodeReadWriteTestHasSubSubType, &inverseNameChangedRead); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(UA_String_equal(&newLocale.locale, &inverseNameChangedRead.locale)); ck_assert(UA_String_equal(&newLocale.text, &inverseNameChangedRead.text)); UA_LocalizedText_deleteMembers(&inverseNameChangedRead); } END_TEST START_TEST(Node_ReadWrite_ContainsNoLoops) { UA_Boolean containsNoLoops; UA_StatusCode retval = UA_Client_readContainsNoLoopsAttribute(client, nodeReadWriteTestHasSubSubType, &containsNoLoops); ck_assert_uint_eq(retval, UA_STATUSCODE_BADATTRIBUTEIDINVALID); retval = UA_Client_readContainsNoLoopsAttribute(client, nodeReadWriteView, &containsNoLoops); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(containsNoLoops, UA_FALSE); UA_Boolean newContainsNoLoops = UA_TRUE; retval = UA_Client_writeContainsNoLoopsAttribute(client, nodeReadWriteView, &newContainsNoLoops); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readContainsNoLoopsAttribute(client, nodeReadWriteView, &containsNoLoops); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(containsNoLoops, newContainsNoLoops); } END_TEST START_TEST(Node_ReadWrite_EventNotifier) { UA_Byte eventNotifier = 0; UA_StatusCode retval = UA_Client_readEventNotifierAttribute(client, nodeReadWriteTestHasSubSubType, &eventNotifier); ck_assert_uint_eq(retval, UA_STATUSCODE_BADATTRIBUTEIDINVALID); retval = UA_Client_readEventNotifierAttribute(client, nodeReadWriteView, &eventNotifier); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(eventNotifier, 0); UA_Byte newEventNotifier = 1; retval = UA_Client_writeEventNotifierAttribute(client, nodeReadWriteView, &newEventNotifier); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readEventNotifierAttribute(client, nodeReadWriteView, &eventNotifier); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(eventNotifier, newEventNotifier); } END_TEST START_TEST(Node_ReadWrite_Value) { UA_Int32 value = 0; UA_Variant *val = UA_Variant_new(); UA_StatusCode retval = UA_Client_readValueAttribute(client, nodeReadWriteInt, val); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(UA_Variant_isScalar(val) && val->type == &UA_TYPES[UA_TYPES_INT32]); value = *(UA_Int32*)val->data; ck_assert_int_eq(value, 5678); UA_Variant_delete(val); /* Write attribute */ value++; val = UA_Variant_new(); UA_Variant_setScalarCopy(val, &value, &UA_TYPES[UA_TYPES_INT32]); retval = UA_Client_writeValueAttribute(client, nodeReadWriteInt, val); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_Variant_delete(val); /* Read again to check value */ val = UA_Variant_new(); retval = UA_Client_readValueAttribute(client, nodeReadWriteInt, val); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(UA_Variant_isScalar(val) && val->type == &UA_TYPES[UA_TYPES_INT32]); value = *(UA_Int32*)val->data; ck_assert_int_eq(value, 5679); UA_Variant_delete(val); } END_TEST START_TEST(Node_ReadWrite_DataType) { UA_NodeId dataType; // read to check if node id was changed UA_StatusCode retval = UA_Client_readDataTypeAttribute(client, nodeReadWriteInt, &dataType); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(UA_NodeId_equal(&dataType, &UA_TYPES[UA_TYPES_INT32].typeId)); UA_NodeId newDataType = UA_TYPES[UA_TYPES_VARIANT].typeId; retval = UA_Client_writeDataTypeAttribute(client, nodeReadWriteGeneric, &newDataType); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readDataTypeAttribute(client, nodeReadWriteGeneric, &dataType); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(UA_NodeId_equal(&dataType, &newDataType)); } END_TEST START_TEST(Node_ReadWrite_ValueRank) { UA_Int32 valueRank = UA_VALUERANK_ONE_OR_MORE_DIMENSIONS; UA_StatusCode retval = UA_Client_readValueRankAttribute(client, nodeReadWriteGeneric, &valueRank); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(valueRank, UA_VALUERANK_ANY); // set the value to a scalar UA_Double val = 0.0; UA_Variant value; UA_Variant_setScalar(&value, &val, &UA_TYPES[UA_TYPES_DOUBLE]); retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); // we want an array UA_Int32 newValueRank = UA_VALUERANK_ONE_DIMENSION; // shall fail when the value is not compatible retval = UA_Client_writeValueRankAttribute(client, nodeReadWriteGeneric, &newValueRank); ck_assert(retval != UA_STATUSCODE_GOOD); // set the value to an array UA_Double vec[3] = {0.0, 0.0, 0.0}; UA_Variant_setArray(&value, vec, 3, &UA_TYPES[UA_TYPES_DOUBLE]); retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); // try again retval = UA_Client_writeValueRankAttribute(client, nodeReadWriteGeneric, &newValueRank); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readValueRankAttribute(client, nodeReadWriteGeneric, &valueRank); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(valueRank, newValueRank); // set the value to no array UA_Variant_init(&value); retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); } END_TEST START_TEST(Node_ReadWrite_ArrayDimensions) { UA_UInt32 *arrayDimsRead; size_t arrayDimsReadSize; UA_StatusCode retval = UA_Client_readArrayDimensionsAttribute(client, nodeReadWriteGeneric, &arrayDimsReadSize, &arrayDimsRead); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(arrayDimsReadSize, 0); // Set a vector of size 1 as the value UA_Double vec2[2] = {0.0, 0.0}; UA_Variant value; UA_Variant_setArray(&value, vec2, 2, &UA_TYPES[UA_TYPES_DOUBLE]); retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); // writing the array dimensions shall fail at first // because the current value is not conformant UA_UInt32 arrayDimsNew[] = {1}; retval = UA_Client_writeArrayDimensionsAttribute(client, nodeReadWriteGeneric, 1, arrayDimsNew); ck_assert(retval != UA_STATUSCODE_GOOD); // Set a vector of size 1 as the value UA_Double vec1[1] = {0.0}; UA_Variant_setArray(&value, vec1, 1, &UA_TYPES[UA_TYPES_DOUBLE]); retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); // Now we can set matching array-dimensions retval = UA_Client_writeArrayDimensionsAttribute(client, nodeReadWriteGeneric, 1, arrayDimsNew); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readArrayDimensionsAttribute(client, nodeReadWriteGeneric, &arrayDimsReadSize, &arrayDimsRead); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(arrayDimsReadSize, 1); ck_assert_int_eq(arrayDimsRead[0], 1); UA_Array_delete(arrayDimsRead, arrayDimsReadSize, &UA_TYPES[UA_TYPES_UINT32]); } END_TEST START_TEST(Node_ReadWrite_AccessLevel) { UA_Byte accessLevel; UA_StatusCode retval = UA_Client_readAccessLevelAttribute(client, nodeReadWriteInt, &accessLevel); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(accessLevel, UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE); UA_Byte newMask = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD; retval = UA_Client_writeAccessLevelAttribute(client, nodeReadWriteInt, &newMask); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); UA_Byte accessLevelChangedRead; retval = UA_Client_readAccessLevelAttribute(client, nodeReadWriteInt, &accessLevelChangedRead); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(accessLevelChangedRead, newMask); } END_TEST START_TEST(Node_ReadWrite_UserAccessLevel) { UA_Byte userAccessLevel; UA_StatusCode retval = UA_Client_readUserAccessLevelAttribute(client, nodeReadWriteInt, &userAccessLevel); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(userAccessLevel, UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD); UA_Byte newMask = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD; retval = UA_Client_writeUserAccessLevelAttribute(client, nodeReadWriteInt, &newMask); ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED); } END_TEST START_TEST(Node_ReadWrite_MinimumSamplingInterval) { UA_Double minimumSamplingInterval = 0; UA_StatusCode retval = UA_Client_readMinimumSamplingIntervalAttribute(client, nodeReadWriteGeneric, &minimumSamplingInterval); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(minimumSamplingInterval == 0); // we want an array UA_Double newMinimumSamplingInterval = 1; retval = UA_Client_writeMinimumSamplingIntervalAttribute(client, nodeReadWriteGeneric, &newMinimumSamplingInterval); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readMinimumSamplingIntervalAttribute(client, nodeReadWriteGeneric, &minimumSamplingInterval); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert(minimumSamplingInterval == newMinimumSamplingInterval); } END_TEST START_TEST(Node_ReadWrite_Historizing) { UA_Boolean historizing; UA_StatusCode retval = UA_Client_readHistorizingAttribute(client, nodeReadWriteInt, &historizing); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(historizing, UA_FALSE); UA_Boolean newHistorizing = UA_TRUE; retval = UA_Client_writeHistorizingAttribute(client, nodeReadWriteInt, &newHistorizing); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readHistorizingAttribute(client, nodeReadWriteInt, &historizing); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(historizing, newHistorizing); } END_TEST START_TEST(Node_ReadWrite_Executable) { UA_Boolean executable; UA_StatusCode retval = UA_Client_readExecutableAttribute(client, nodeReadWriteMethod, &executable); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(executable, UA_TRUE); UA_Boolean newExecutable = UA_FALSE; retval = UA_Client_writeExecutableAttribute(client, nodeReadWriteMethod, &newExecutable); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); retval = UA_Client_readExecutableAttribute(client, nodeReadWriteMethod, &executable); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(executable, newExecutable); } END_TEST START_TEST(Node_ReadWrite_UserExecutable) { UA_Boolean userExecutable; UA_StatusCode retval = UA_Client_readUserExecutableAttribute(client, nodeReadWriteMethod, &userExecutable); ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD); ck_assert_int_eq(userExecutable, UA_FALSE); UA_Boolean newUserExecutable = UA_TRUE; retval = UA_Client_writeUserExecutableAttribute(client, nodeReadWriteMethod, &newUserExecutable); ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED); } END_TEST #endif static Suite *testSuite_Client(void) { Suite *s = suite_create("Client Highlevel"); TCase *tc_misc = tcase_create("Client Highlevel Misc"); tcase_add_checked_fixture(tc_misc, setup, teardown); tcase_add_test(tc_misc, Misc_State); tcase_add_test(tc_misc, Misc_NamespaceGetIndex); suite_add_tcase(s, tc_misc); TCase *tc_nodes = tcase_create("Client Highlevel Node Management"); tcase_add_checked_fixture(tc_nodes, setup, teardown); #ifdef UA_ENABLE_NODEMANAGEMENT tcase_add_test(tc_nodes, Node_Add); #endif tcase_add_test(tc_nodes, Node_Browse); tcase_add_test(tc_nodes, Node_Register); suite_add_tcase(s, tc_nodes); #ifdef UA_ENABLE_NODEMANAGEMENT TCase *tc_readwrite = tcase_create("Client Highlevel Read/Write"); tcase_add_unchecked_fixture(tc_readwrite, setup, teardown); // first add some nodes where we test on tcase_add_test(tc_readwrite, Node_AddReadWriteNodes); // Now run all the read write tests tcase_add_test(tc_readwrite, Node_ReadWrite_Id); tcase_add_test(tc_readwrite, Node_ReadWrite_Class); tcase_add_test(tc_readwrite, Node_ReadWrite_BrowseName); tcase_add_test(tc_readwrite, Node_ReadWrite_DisplayName); tcase_add_test(tc_readwrite, Node_ReadWrite_Description); tcase_add_test(tc_readwrite, Node_ReadWrite_WriteMask); tcase_add_test(tc_readwrite, Node_ReadWrite_UserWriteMask); tcase_add_test(tc_readwrite, Node_ReadWrite_IsAbstract); tcase_add_test(tc_readwrite, Node_ReadWrite_Symmetric); tcase_add_test(tc_readwrite, Node_ReadWrite_InverseName); tcase_add_test(tc_readwrite, Node_ReadWrite_ContainsNoLoops); tcase_add_test(tc_readwrite, Node_ReadWrite_EventNotifier); tcase_add_test(tc_readwrite, Node_ReadWrite_Value); tcase_add_test(tc_readwrite, Node_ReadWrite_DataType); tcase_add_test(tc_readwrite, Node_ReadWrite_ValueRank); tcase_add_test(tc_readwrite, Node_ReadWrite_ArrayDimensions); tcase_add_test(tc_readwrite, Node_ReadWrite_AccessLevel); tcase_add_test(tc_readwrite, Node_ReadWrite_UserAccessLevel); tcase_add_test(tc_readwrite, Node_ReadWrite_MinimumSamplingInterval); tcase_add_test(tc_readwrite, Node_ReadWrite_Historizing); tcase_add_test(tc_readwrite, Node_ReadWrite_Executable); tcase_add_test(tc_readwrite, Node_ReadWrite_UserExecutable); suite_add_tcase(s, tc_readwrite); #endif 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; }