Ver código fonte

Merge remote-tracking branch 'origin/master' into connection_secureChannel

FlorianPalm 10 anos atrás
pai
commit
e997507535
9 arquivos alterados com 415 adições e 131 exclusões
  1. 5 63
      include/ua_basictypes.h
  2. 1 1
      include/ua_list.h
  3. 66 0
      include/ua_types.h
  4. 3 2
      src/ua_namespace.c
  5. 129 62
      src/ua_xml.c
  6. 8 0
      src/ua_xml.h
  7. 1 1
      tests/Makefile.am
  8. 20 2
      tests/check_namespace.c
  9. 182 0
      tests/check_xml.c

+ 5 - 63
include/ua_basictypes.h

@@ -1,68 +1,8 @@
 #ifndef OPCUA_BASICTYPES_H_
 #define OPCUA_BASICTYPES_H_
 
-#include <stdint.h>
-
-#define DBG_VERBOSE(expression) // omit debug code
-#define DBG_ERR(expression) // omit debug code
-#define DBG(expression) // omit debug code
-#if defined(DEBUG) 		// --enable-debug=(yes|verbose)
-# undef DBG
-# define DBG(expression) expression
-# undef DBG_ERR
-# define DBG_ERR(expression) expression
-# if defined(VERBOSE) 	// --enable-debug=verbose
-#  undef DBG_VERBOSE
-#  define DBG_VERBOSE(expression) expression
-# endif
-#endif
-
-/* Basic types */
-typedef _Bool UA_Boolean;
-typedef uint8_t UA_Byte;
-typedef int8_t UA_SByte;
-typedef int16_t UA_Int16;
-typedef uint16_t UA_UInt16;
-typedef int32_t UA_Int32;
-typedef uint32_t UA_UInt32;
-typedef int64_t UA_Int64;
-typedef uint64_t UA_UInt64;
-typedef float UA_Float;
-typedef double UA_Double;
-
-/* ByteString - Part: 6, Chapter: 5.2.2.7, Page: 17 */
-typedef struct UA_ByteString {
-	UA_Int32 	length;
-	UA_Byte*	data;
-} UA_ByteString;
-
-/* Function return values */
-#define UA_SUCCESS 0
-#define UA_NO_ERROR UA_SUCCESS
-#define UA_ERROR (0x01 << 31)
-#define UA_ERR_INCONSISTENT  (UA_ERROR | (0x01 << 1))
-#define UA_ERR_INVALID_VALUE (UA_ERROR | (0x01 << 2))
-#define UA_ERR_NO_MEMORY     (UA_ERROR | (0x01 << 3))
-#define UA_ERR_NOT_IMPLEMENTED (UA_ERROR | (0x01 << 4))
-
-/* Boolean values and null */
-#define UA_TRUE (42==42)
-#define TRUE UA_TRUE
-#define UA_FALSE (!UA_TRUE)
-#define FALSE UA_FALSE
-
-/* Compare values */
-#define UA_EQUAL 0
-#define UA_NOT_EQUAL (!UA_EQUAL)
-
-/* heap memory functions */
-#define UA_NULL ((void*)0)
-extern void const * UA_alloc_lastptr;
-#define UA_free(ptr) _UA_free(ptr,#ptr,__FILE__,__LINE__)
-UA_Int32 _UA_free(void * ptr,char*,char*,int);
-UA_Int32 UA_memcpy(void *dst, void const *src, int size);
-#define UA_alloc(ptr,size) _UA_alloc(ptr,size,#ptr,#size,__FILE__,__LINE__)
-UA_Int32 _UA_alloc(void ** dst, int size,char*,char*,char*,int);
+#include "ua_types.h"
+#include "ua_list.h"
 
 /* Stop decoding at the first failure. Free members that were already allocated.
    It is assumed that retval is already defined. */
@@ -82,7 +22,7 @@ UA_Int32 UA_Array_init(void **p,UA_Int32 noElements, UA_Int32 type);
 UA_Int32 UA_Array_new(void ***p,UA_Int32 noElements, UA_Int32 type);
 UA_Int32 UA_Array_copy(void const * const *src,UA_Int32 noElements, UA_Int32 type, void ***dst);
 
-/* XML prelimiaries */
+/* XML preliminaries */
 struct XML_Stack;
 typedef char const * const XML_Attr;
 typedef char const * cstring;
@@ -388,6 +328,8 @@ typedef struct XML_Parent {
 	int textAttribIdx; // -1 - not set
 	cstring textAttrib;
 	int activeChild; // -1 - no active child
+	int totalGatherLength;
+	UA_list_List textGatherList;
 	int len; // -1 - empty set
 	XML_child children[XML_STACK_MAX_CHILDREN];
 } XML_Parent;

+ 1 - 1
include/ua_list.h

@@ -1,7 +1,7 @@
 #ifndef UA_LIST_H_
 #define UA_LIST_H_
 
-#include "opcua.h"
+#include "ua_types.h"
 #include <stddef.h> /* Needed for sys/queue.h */
 #include <sys/queue.h>
 

+ 66 - 0
include/ua_types.h

@@ -0,0 +1,66 @@
+#ifndef OPCUA_TYPES_H_
+#define OPCUA_TYPES_H_
+
+#include <stdint.h>
+
+#define DBG_VERBOSE(expression) // omit debug code
+#define DBG_ERR(expression) // omit debug code
+#define DBG(expression) // omit debug code
+#if defined(DEBUG) 		// --enable-debug=(yes|verbose)
+# undef DBG
+# define DBG(expression) expression
+# undef DBG_ERR
+# define DBG_ERR(expression) expression
+# if defined(VERBOSE) 	// --enable-debug=verbose
+#  undef DBG_VERBOSE
+#  define DBG_VERBOSE(expression) expression
+# endif
+#endif
+
+/* Basic types */
+typedef _Bool UA_Boolean;
+typedef uint8_t UA_Byte;
+typedef int8_t UA_SByte;
+typedef int16_t UA_Int16;
+typedef uint16_t UA_UInt16;
+typedef int32_t UA_Int32;
+typedef uint32_t UA_UInt32;
+typedef int64_t UA_Int64;
+typedef uint64_t UA_UInt64;
+typedef float UA_Float;
+typedef double UA_Double;
+
+/* ByteString - Part: 6, Chapter: 5.2.2.7, Page: 17 */
+typedef struct UA_ByteString {
+	UA_Int32 	length;
+	UA_Byte*	data;
+} UA_ByteString;
+
+/* Function return values */
+#define UA_SUCCESS 0
+#define UA_NO_ERROR UA_SUCCESS
+#define UA_ERROR (0x01 << 31)
+#define UA_ERR_INCONSISTENT  (UA_ERROR | (0x01 << 1))
+#define UA_ERR_INVALID_VALUE (UA_ERROR | (0x01 << 2))
+#define UA_ERR_NO_MEMORY     (UA_ERROR | (0x01 << 3))
+#define UA_ERR_NOT_IMPLEMENTED (UA_ERROR | (0x01 << 4))
+
+/* Boolean values and null */
+#define UA_TRUE (42==42)
+#define TRUE UA_TRUE
+#define UA_FALSE (!UA_TRUE)
+#define FALSE UA_FALSE
+
+/* Compare values */
+#define UA_EQUAL 0
+#define UA_NOT_EQUAL (!UA_EQUAL)
+
+/* heap memory functions */
+#define UA_NULL ((void*)0)
+extern void const * UA_alloc_lastptr;
+#define UA_free(ptr) _UA_free(ptr,#ptr,__FILE__,__LINE__)
+UA_Int32 _UA_free(void * ptr,char*,char*,int);
+UA_Int32 UA_memcpy(void *dst, void const *src, int size);
+#define UA_alloc(ptr,size) _UA_alloc(ptr,size,#ptr,#size,__FILE__,__LINE__)
+UA_Int32 _UA_alloc(void ** dst, int size,char*,char*,char*,int);
+#endif

+ 3 - 2
src/ua_namespace.c

@@ -188,7 +188,8 @@ static inline hash_t mod(hash_t h, const Namespace * ns) {
 }
 
 static inline hash_t mod_m2(hash_t h, const Namespace * ns) {
-	const struct prime_ent *p = &prime_tab[ns->sizePrimeIndex];
+	const struct prime_ent *p = &prime_tab[ns->sizePrimeIndex];	// eventually return the namespace object that has been allocated in UA_NodeSet_init
+
 	return 1 + mod_1(h, p->prime - 2, p->inv_m2, p->shift);
 }
 
@@ -415,7 +416,7 @@ UA_Int32 Namespace_insertUnique(Namespace * ns, UA_Node * node) {
 
 UA_Int32 Namespace_contains(const Namespace * ns, const UA_NodeId * nodeid) {
 	Namespace_Entry *entry;
-	return find_entry(ns, nodeid, &entry);
+	return (find_entry(ns, nodeid, &entry) == UA_SUCCESS ? UA_TRUE : UA_FALSE);
 }
 
 UA_Int32 Namespace_get(Namespace const *ns, const UA_NodeId * nodeid, const UA_Node **result,

+ 129 - 62
src/ua_xml.c

@@ -78,27 +78,43 @@ UA_Int32 UA_NodeSet_new(UA_NodeSet** p, UA_UInt32 nsid) {
 	UA_NodeSet_init(*p, nsid);
 	return UA_SUCCESS;
 }
-UA_Int32 UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases) {
-	dst->encodingByte = UA_NODEIDTYPE_FOURBYTE;
-	dst->namespace = 0;
-	dst->identifier.numeric = 0;
-	// FIXME: assumes i=nnnn
-	if (src[1] == '=') {
-		dst->identifier.numeric = atoi(&src[2]);
-	} else {
-		UA_Int32 i;
-		for (i = 0; i < aliases->size && dst->identifier.numeric == 0; ++i) {
-			if (0
-					== strncmp((char const*) src, (char const*) aliases->aliases[i]->alias.data,
-							aliases->aliases[i]->alias.length)) {
-				dst->identifier.numeric = atoi((char const*) &(aliases->aliases[i]->value.data[2]));
+
+UA_Int32 _UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases) {
+	UA_Int32 retval = UA_SUCCESS;
+	if (src != UA_NULL && dst != UA_NULL ) {
+		if (src[0] == 'i' && src[1] == '=') { // namespace zero numeric identifier
+			dst->identifier.numeric = atoi(&src[2]);
+		} else if (src[0] == 'n' && src[1] == 's' && src[2] == '=') { // namespace
+			dst->namespace = atoi(&src[3]);
+			src = strchr(&src[3],';');
+			if (src != UA_NULL)
+				retval = _UA_NodeId_copycstring(src+1,dst,aliases);  // +1 to start beyond ;
+			else
+				retval = UA_ERR_INVALID_VALUE;
+		} else if (aliases != UA_NULL ) { // try for aliases
+			UA_Int32 i;
+			for (i = 0; i < aliases->size && dst->identifier.numeric == 0; ++i) {
+				if (0 == strncmp((char const*) src, (char const*) aliases->aliases[i]->alias.data,
+								aliases->aliases[i]->alias.length)) {
+					_UA_NodeId_copycstring((cstring)aliases->aliases[i]->alias.data,dst,UA_NULL); // substitute text of alias
+				}
 			}
+		} else {
+			retval = UA_ERR_NOT_IMPLEMENTED;
 		}
+	} else {
+		retval = UA_ERR_INVALID_VALUE;
 	}
 	DBG_VERBOSE(printf("UA_NodeId_copycstring src=%s,id=%d\n", src, dst->identifier.numeric));
-	return UA_SUCCESS;
+	return retval;
 }
 
+UA_Int32 UA_NodeId_copycstring(cstring src, UA_NodeId* dst, UA_NodeSetAliases* aliases) {
+	dst->encodingByte = UA_NODEIDTYPE_FOURBYTE;
+	dst->namespace = 0;
+	dst->identifier.numeric = 0;
+	return _UA_NodeId_copycstring(src,dst,aliases);
+}
 
 UA_Int32 UA_ReferenceNode_println(cstring label, UA_ReferenceNode *a) {
 	printf("%s{referenceType=%d, target=%d, isInverse=%d}\n",
@@ -127,6 +143,8 @@ void XML_Stack_init(XML_Stack* p, UA_UInt32 nsid, cstring name) {
 		p->parent[i].activeChild = -1;
 		p->parent[i].textAttrib = UA_NULL;
 		p->parent[i].textAttribIdx = -1;
+		p->parent[i].totalGatherLength = -1;
+		UA_list_init(&(p->parent[i].textGatherList));
 		for (j = 0; j < XML_STACK_MAX_CHILDREN; j++) {
 			p->parent[i].children[j].name = UA_NULL;
 			p->parent[i].children[j].length = -1;
@@ -931,11 +949,6 @@ UA_Int32 UA_NodeSetAlias_decodeXML(XML_Stack* s, XML_Attr* attr, UA_NodeSetAlias
 				DBG_ERR(XML_Stack_print(s));DBG_ERR(printf("%s - unknown attribute\n", attr[i]));
 			}
 		}
-	} else {
-		// sub element is ready
-// TODO: It is a design flaw that we need to do this here, isn't it?
-//		DBG_VERBOSE(printf("UA_NodeSetAlias clears %p\n", (void* ) (s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj)));
-//		s->parent[s->depth - 1].children[s->parent[s->depth - 1].activeChild].obj = UA_NULL;
 	}
 	return UA_SUCCESS;
 }
@@ -1050,44 +1063,67 @@ UA_Int32 XML_isSpace(cstring s, int len) {
 	return UA_TRUE;
 }
 
-/* simulates startElement, endElement behaviour */
+/* gather text */
 void XML_Stack_handleText(void * data, const char *txt, int len) {
 	XML_Stack* s = (XML_Stack*) data;
 
 	if (len > 0 && !XML_isSpace(txt, len)) {
-		XML_Parent* cp = &(s->parent[s->depth]);
-		if (cp->textAttribIdx >= 0) {
-			cp->activeChild = cp->textAttribIdx;
-			char* buf; // need to copy txt to add 0 as string terminator
-			UA_alloc((void** )&buf, len + 1);
-			strncpy(buf, txt, len);
-			buf[len] = 0;
-			XML_Attr attr[3] = { cp->textAttrib, buf, UA_NULL };
-			DBG(printf("handleText @ %s calls start elementHandler %s with dst=%p, buf={%s}\n", XML_Stack_path(s),cp->children[cp->activeChild].name, cp->children[cp->activeChild].obj, buf));
-			cp->children[cp->activeChild].elementHandler(s, attr, cp->children[cp->activeChild].obj, TRUE);
-			// FIXME: The indices of this call are simply wrong
-			// DBG_VERBOSE(printf("handleText calls finish elementHandler %s with dst=%p, attr=(nil)\n", cp->children[cp->activeChild].name, cp->children[cp->activeChild].obj));
-			// cp->children[cp->activeChild].elementHandler(s, UA_NULL, cp->children[cp->activeChild].obj, FALSE);
-
-			if (s->parent[s->depth-1].activeChild > 0) {
-				// FIXME: actually we'd like to have something like the following, won't we?
-				// XML_Stack_endElement(data, cp->children[cp->activeChild].name);
-				XML_child* c = &(s->parent[s->depth-1].children[s->parent[s->depth-1].activeChild]);
-				c->elementHandler(s, UA_NULL, c->obj, FALSE);
-			}
-			UA_free(buf);
+		XML_Parent* cp = &(s->parent[s->depth]); // determine current element
+		UA_ByteString src = { len+1, (UA_Byte*) txt };
+		UA_ByteString *dst;
+		UA_ByteString_new(&dst);	// alloc dst
+		UA_ByteString_copy(&src,dst); // alloc dst->data and copy txt
+		dst->data[len] = 0; // add terminating zero to handle single line efficiently
+		UA_list_addPayloadToBack(&(cp->textGatherList), (void*) dst);
+		if (cp->totalGatherLength == -1) {
+			cp->totalGatherLength = len;
 		} else {
-			DBG_VERBOSE(XML_Stack_print(s));
-			DBG_VERBOSE(printf("textData - ignore text data '%.*s'\n", len, txt));
+			cp->totalGatherLength += len;
 		}
 	}
 }
 
+char* theGatherBuffer;
+void textGatherListTotalLength(void* payload) {
+	UA_ByteString* b = (UA_ByteString*) payload;
+	UA_ByteString_printf("\t",b);
+	UA_memcpy(theGatherBuffer,b->data,b->length-1); // remove trailing zero
+	theGatherBuffer += (b->length-1);
+}
 /** if we are an activeChild of a parent we call the child-handler */
 void XML_Stack_endElement(void *data, const char *el) {
 	XML_Stack* s = (XML_Stack*) data;
 
-// the parent of the parent (pop) of the element knows the elementHandler, therefore depth-2!
+	XML_Parent* ce = &(s->parent[s->depth]);
+	if (ce->textAttribIdx >= 0 && ce->totalGatherLength > 0 ) {
+		ce->activeChild = ce->textAttribIdx;
+		char* buf;
+		if (UA_list_getFirst(&(ce->textGatherList)) == UA_list_getLast(&(ce->textGatherList)) ) {
+			buf = (char*) ((UA_ByteString*) UA_list_getFirst(&(ce->textGatherList))->payload)->data;
+		} else {
+			printf("XML_Stack_endElement - more than one text snippet with total length=%d:\n",ce->totalGatherLength);
+			UA_alloc((void**)&theGatherBuffer,ce->totalGatherLength+1);
+			buf = theGatherBuffer;
+			UA_list_iteratePayload(&(ce->textGatherList), textGatherListTotalLength);
+			buf[ce->totalGatherLength] = 0;
+			printf("XML_Stack_endElement - gatherBuffer %s:\n",buf);
+		}
+		XML_Attr attr[3] = { ce->textAttrib, buf, UA_NULL };
+		DBG(printf("handleText @ %s calls start elementHandler %s with dst=%p, buf={%s}\n", XML_Stack_path(s),ce->children[ce->activeChild].name, ce->children[ce->activeChild].obj, buf));
+		ce->children[ce->activeChild].elementHandler(s, attr, ce->children[ce->activeChild].obj, TRUE);
+		if (s->parent[s->depth-1].activeChild > 0) {
+			XML_child* c = &(s->parent[s->depth-1].children[s->parent[s->depth-1].activeChild]);
+			c->elementHandler(s, UA_NULL, c->obj, FALSE);
+		}
+		if (UA_list_getFirst(&(ce->textGatherList)) != UA_list_getLast(&(ce->textGatherList)) ) {
+			UA_free(buf);
+		}
+		UA_list_destroy(&(ce->textGatherList),(UA_list_PayloadVisitor) UA_ByteString_delete);
+		UA_list_init(&(ce->textGatherList)); // don't know if destroy leaves the list in usable state...
+		ce->totalGatherLength = -1;
+	}
+
+	// the parent of the parent (pop) of the element knows the elementHandler, therefore depth-2!
 	if (s->depth > 1) {
 		// inform parents elementHandler that everything is done
 		XML_Parent* cp = &(s->parent[s->depth - 1]);
@@ -1106,14 +1142,12 @@ void XML_Stack_endElement(void *data, const char *el) {
 	s->depth--;
 }
 
-UA_Int32 Namespace_loadFromFile(Namespace **ns,UA_UInt32 nsid,const char* rootName,const char* fileName) {
-	int f;
-	if (fileName == UA_NULL)
-		f = 0; // stdin
-	else if ((f= open(fileName, O_RDONLY)) == -1)
-		return UA_ERR_INVALID_VALUE;
+typedef UA_Int32 (*XML_Stack_Loader) (char* buf, int len);
 
-	char buf[1024];
+#define XML_BUFFER_LEN 1024
+UA_Int32 Namespace_loadXml(Namespace **ns,UA_UInt32 nsid,const char* rootName, XML_Stack_Loader getNextBufferFull) {
+	UA_Int32 retval = UA_SUCCESS;
+	char buf[XML_BUFFER_LEN];
 	int len; /* len is the number of bytes in the current bufferful of data */
 
 	XML_Stack s;
@@ -1121,25 +1155,58 @@ UA_Int32 Namespace_loadFromFile(Namespace **ns,UA_UInt32 nsid,const char* rootNa
 
 	UA_NodeSet n;
 	UA_NodeSet_init(&n, 0);
-	XML_Stack_addChildHandler(&s, "UANodeSet", strlen("UANodeSet"), (XML_decoder) UA_NodeSet_decodeXML, UA_INVALIDTYPE, &n);
+	*ns = n.ns;
 
+	XML_Stack_addChildHandler(&s, "UANodeSet", strlen("UANodeSet"), (XML_decoder) UA_NodeSet_decodeXML, UA_INVALIDTYPE, &n);
 	XML_Parser parser = XML_ParserCreate(NULL);
 	XML_SetUserData(parser, &s);
 	XML_SetElementHandler(parser, XML_Stack_startElement, XML_Stack_endElement);
 	XML_SetCharacterDataHandler(parser, XML_Stack_handleText);
-	while ((len = read(f, buf, 1024)) > 0) {
-		if (!XML_Parse(parser, buf, len, (len < 1024))) {
-			return 1;
+	while ((len = getNextBufferFull(buf, XML_BUFFER_LEN)) > 0) {
+		if (XML_Parse(parser, buf, len, (len < XML_BUFFER_LEN)) == XML_STATUS_ERROR) {
+			retval = UA_ERR_INVALID_VALUE;
+			break;
 		}
 	}
 	XML_ParserFree(parser);
-	close(f);
 
-	DBG_VERBOSE(printf("Namespace_loadFromFile - aliases addr=%p, size=%d\n", (void*) &(n.aliases), n.aliases.size));
-	DBG_VERBOSE(UA_NodeSetAliases_println("Namespace_loadFromFile - elements=", &n.aliases));
+	DBG_VERBOSE(printf("Namespace_loadXml - aliases addr=%p, size=%d\n", (void*) &(n.aliases), n.aliases.size));
+	DBG_VERBOSE(UA_NodeSetAliases_println("Namespace_loadXml - elements=", &n.aliases));
 
-	// eventually return the namespace object that has been allocated in UA_NodeSet_init
-	*ns = n.ns;
-	return UA_SUCCESS;
+	return retval;
+}
+
+static int theFile = 0;
+UA_Int32 readFromTheFile(char*buf,int len) {
+	return read(theFile,buf,len);
 }
 
+UA_Int32 Namespace_loadFromFile(Namespace **ns,UA_UInt32 nsid,const char* rootName,const char* fileName) {
+	if (fileName == UA_NULL)
+		theFile = 0; // stdin
+	else if ((theFile = open(fileName, O_RDONLY)) == -1)
+		return UA_ERR_INVALID_VALUE;
+
+	UA_Int32 retval = Namespace_loadXml(ns,nsid,rootName,readFromTheFile);
+	close(theFile);
+	return retval;
+}
+
+static const char* theBuffer = UA_NULL;
+static const char* theBufferEnd = UA_NULL;
+UA_Int32 readFromTheBuffer(char*buf,int len) {
+	if (len == 0) return 0;
+	if (theBuffer + XML_BUFFER_LEN > theBufferEnd)
+		len = theBufferEnd - theBuffer + 1;
+	else
+		len = XML_BUFFER_LEN;
+	memcpy(buf,theBuffer,len);
+	theBuffer = theBuffer + len;
+	return len;
+}
+
+UA_Int32 Namespace_loadFromString(Namespace **ns,UA_UInt32 nsid,const char* rootName,const char* buffer) {
+	theBuffer = buffer;
+	theBufferEnd = buffer + strlen(buffer) - 1;
+	return Namespace_loadXml(ns,nsid,rootName,readFromTheBuffer);
+}

+ 8 - 0
src/ua_xml.h

@@ -113,5 +113,13 @@ void XML_Stack_endElement(void *data, const char *el);
  */
 UA_Int32 Namespace_loadFromFile(Namespace **ns,UA_UInt32 namespaceId,const char* rootName,const char* fileName);
 
+/** @brief load a namespace from a string
+ *
+ * @param[in/out] ns the address of the namespace ptr
+ * @param[in] namespaceId the numeric id of the namespace
+ * @param[in] rootName the name of the root element of the hierarchy (not used?)
+ * @param[in] buffer the xml string
+ */
+UA_Int32 Namespace_loadFromString(Namespace **ns,UA_UInt32 nsid,const char* rootName,const char* buffer);
 
 #endif // __UA_XML_H__

+ 1 - 1
tests/Makefile.am

@@ -3,7 +3,7 @@ TESTS=
 UNIT_TESTS=
 check_PROGRAMS=
 
-UNIT_TESTS += check_stack check_list check_indexedList check_builtin check_namespace check_memory check_services_view
+UNIT_TESTS += check_stack check_list check_indexedList check_builtin check_namespace check_memory check_services_view check_xml
 TESTS += $(UNIT_TESTS)
 check_PROGRAMS += $(UNIT_TESTS)
 

+ 20 - 2
tests/check_namespace.c

@@ -27,6 +27,21 @@ UA_Int32 createNode(UA_Node** p, UA_Int16 nsid, UA_Int32 id) {
 	return UA_SUCCESS;
 }
 
+START_TEST(confirmExistenceInNamespaceWithSingleEntry) {
+	// given
+	Namespace *ns;
+	Namespace_new(&ns, 512, 0);
+	UA_Node* n1; createNode(&n1,0,2253); Namespace_insert(ns,n1);
+	UA_Int32 retval;
+	// when
+	retval = Namespace_contains(ns,&(n1->nodeId));
+	// then
+	ck_assert_int_eq(retval, UA_TRUE);
+	// finally
+	Namespace_delete(ns);
+}
+END_TEST
+
 START_TEST(findNodeInNamespaceWithSingleEntry) {
 	// given
 	Namespace *ns;
@@ -140,7 +155,8 @@ START_TEST(findNodeInExpandedNamespace) {
 	Namespace *ns;
 	Namespace_new(&ns, 10, 0);
 	UA_Node* n;
-	for (UA_Int32 i=0; i<200; i++) {
+	UA_Int32 i=0;
+	for (; i<200; i++) {
 		createNode(&n,0,i); Namespace_insert(ns,n);
 	}
 	const UA_Node* nr = UA_NULL;
@@ -163,7 +179,8 @@ START_TEST(iterateOverExpandedNamespaceShallNotVisitEmptyNodes) {
 	Namespace *ns;
 	Namespace_new(&ns, 10, 0);
 	UA_Node* n;
-	for (UA_Int32 i=0; i<200; i++) {
+	UA_Int32 i=0;
+	for (; i<200; i++) {
 		createNode(&n,0,i); Namespace_insert(ns,n);
 	}
 	// when
@@ -212,6 +229,7 @@ Suite * namespace_suite (void) {
 	suite_add_tcase (s, tc_cd);
 
 	TCase* tc_find = tcase_create ("Find");
+	tcase_add_test (tc_find, confirmExistenceInNamespaceWithSingleEntry);
 	tcase_add_test (tc_find, findNodeInNamespaceWithSingleEntry);
 	tcase_add_test (tc_find, findNodeInNamespaceWithTwoEntries);
 	tcase_add_test (tc_find, findNodeInNamespaceWithSeveralEntries);

+ 182 - 0
tests/check_xml.c

@@ -0,0 +1,182 @@
+/****************************************************************************
+ Name        : check_xml.c
+ Author      : uleon @ open62541
+ Version     : 0.1
+ Copyright   : Your copyright notice
+ Description : test cases to check different aspects of the
+ xml-processing
+
+
+*****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ua_xml.h"
+
+#include "check.h"
+
+START_TEST(parseNumericNodeIdWithoutNsIdShallYieldNs0NodeId)
+{
+	// given
+	char txt[] = "i=2";
+	UA_NodeId nodeId = { (UA_Byte) 0, (UA_UInt16) 0, { 0 } };
+
+	// when
+	UA_Int32 retval = UA_NodeId_copycstring(txt,&nodeId,UA_NULL);
+
+	// then
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_int_eq(nodeId.encodingByte,UA_NODEIDTYPE_FOURBYTE);
+	ck_assert_int_eq(nodeId.namespace,0);
+	ck_assert_int_eq(nodeId.identifier.numeric,2);
+
+	// finally
+}
+END_TEST
+
+START_TEST(parseNumericNodeIdWithNsShallYieldNodeIdWithNs)
+{
+	// given
+	char txt[] = "ns=1;i=2";
+	UA_NodeId nodeId = { (UA_Byte) 0, (UA_UInt16) 0, { 0 } };
+
+	// when
+	UA_Int32 retval = UA_NodeId_copycstring(txt,&nodeId,UA_NULL);
+
+	// then
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_int_eq(nodeId.encodingByte,UA_NODEIDTYPE_FOURBYTE);
+	ck_assert_int_eq(nodeId.namespace,1);
+	ck_assert_int_eq(nodeId.identifier.numeric,2);
+
+	// finally
+}
+END_TEST
+
+START_TEST(loadUserNamespaceWithSingleProcessVariableShallSucceed)
+{
+	// given
+	char xml[]=
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+"<UANodeSet>"
+	"<UAVariable NodeId=\"ns=1;i=2\" BrowseName=\"X1\" DataType=\"i=6\">"
+		"<DisplayName>Integer Variable</DisplayName>"
+		"<References>"
+			"<Reference ReferenceType=\"i=40\">i=63</Reference>"
+		"</References>"
+	"</UAVariable>"
+"</UANodeSet>";
+	Namespace *ns;
+	UA_NodeId nodeId;
+	UA_Int32 retval;
+
+	// when
+	retval = Namespace_loadFromString(&ns,1,"ROOT",xml);
+
+	// then
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_ptr_ne(ns,UA_NULL);
+
+	UA_NodeId_copycstring("ns=1;i=2",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_TRUE);
+
+	const UA_Node* nr = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
+	retval = Namespace_get(ns,&nodeId,&nr,&nl);
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_ptr_ne(nr,UA_NULL);
+	ck_assert_int_eq(nr->references[0]->referenceTypeId.identifier.numeric,40);
+	ck_assert_int_eq(nr->references[0]->targetId.nodeId.identifier.numeric,63);
+
+
+	UA_NodeId_copycstring("i=2",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_FALSE);
+
+	// finally
+	Namespace_delete(ns);
+}
+END_TEST
+
+START_TEST(loadUserNamespaceWithSingleProcessVariableAndAliasesShallSucceed)
+{
+	// given
+	char xml[]=
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+"<UANodeSet>"
+	"<Aliases>"
+		"<Alias Alias=\"Int32\">i=6</Alias>"
+		"<Alias Alias=\"HasTypeDefinition\">i=40</Alias>"
+	"</Aliases>"
+	"<UAVariable NodeId=\"ns=1;i=4\" BrowseName=\"X1\" DataType=\"Int32\">"
+		"<DisplayName>Integer Variable</DisplayName>"
+		"<References>"
+			"<Reference ReferenceType=\"HasTypeDefinition\">i=63</Reference>"
+		"</References>"
+	"</UAVariable>"
+"</UANodeSet>";
+	Namespace *ns;
+	UA_NodeId nodeId;
+	UA_Int32 retval;
+
+	// when
+	retval = Namespace_loadFromString(&ns,1,"ROOT",xml);
+
+	// then
+	ck_assert_ptr_ne(ns,UA_NULL);
+	ck_assert_int_eq(retval,UA_SUCCESS);
+
+	UA_NodeId_copycstring("ns=1;i=4",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_TRUE);
+
+	const UA_Node* nr = UA_NULL;
+	Namespace_Entry_Lock* nl = UA_NULL;
+	retval = Namespace_get(ns,&nodeId,&nr,&nl);
+	ck_assert_int_eq(retval,UA_SUCCESS);
+	ck_assert_ptr_ne(nr,UA_NULL);
+	ck_assert_int_eq(nr->references[0]->referenceTypeId.identifier.numeric,40);
+	ck_assert_int_eq(nr->references[0]->targetId.nodeId.identifier.numeric,63);
+
+	UA_NodeId_copycstring("ns=1;i=2",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_FALSE);
+
+	UA_NodeId_copycstring("ns=2;i=4",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_FALSE);
+
+	UA_NodeId_copycstring("i=4",&nodeId,UA_NULL);
+	ck_assert_int_eq(Namespace_contains(ns,&nodeId),UA_FALSE);
+
+	// finally
+	Namespace_delete(ns);
+}
+END_TEST
+
+Suite* testSuite()
+{
+	Suite *s = suite_create("XML Test");
+	TCase *tc_core = tcase_create("Core");
+
+	tcase_add_test(tc_core, parseNumericNodeIdWithoutNsIdShallYieldNs0NodeId);
+	tcase_add_test(tc_core, parseNumericNodeIdWithNsShallYieldNodeIdWithNs);
+	tcase_add_test(tc_core, loadUserNamespaceWithSingleProcessVariableShallSucceed);
+	tcase_add_test(tc_core, loadUserNamespaceWithSingleProcessVariableAndAliasesShallSucceed);
+	suite_add_tcase(s,tc_core);
+	return s;
+}
+
+int main (void)
+{
+	int number_failed = 0;
+
+	Suite *s;
+	SRunner *sr;
+
+	s = testSuite();
+	sr = srunner_create(s);
+	srunner_set_fork_status(sr, CK_NOFORK);
+	srunner_run_all(sr,CK_NORMAL);
+	number_failed += srunner_ntests_failed(sr);
+	srunner_free(sr);
+
+	return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}