check_types_custom.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include <open62541/types.h>
  5. #include <open62541/types_generated_handling.h>
  6. #include "ua_types_encoding_binary.h"
  7. #include "check.h"
  8. #ifdef __clang__
  9. //required for ck_assert_ptr_eq and const casting
  10. #pragma clang diagnostic push
  11. #pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
  12. #endif
  13. /* The standard-defined datatypes are stored in the global array UA_TYPES. User
  14. * can create their own UA_CUSTOM_TYPES array (the name doesn't matter) and
  15. * provide it to the server / client. The type will be automatically decoded if
  16. * possible.
  17. */
  18. /* The custom datatype for describing a 3d position */
  19. typedef struct {
  20. UA_Float x;
  21. UA_Float y;
  22. UA_Float z;
  23. } Point;
  24. /* The datatype description for the Point datatype */
  25. #define padding_y offsetof(Point,y) - offsetof(Point,x) - sizeof(UA_Float)
  26. #define padding_z offsetof(Point,z) - offsetof(Point,y) - sizeof(UA_Float)
  27. static UA_DataTypeMember members[3] = {
  28. /* x */
  29. {
  30. UA_TYPENAME("x") /* .memberName */
  31. UA_TYPES_FLOAT, /* .memberTypeIndex, points into UA_TYPES since
  32. .namespaceZero is true */
  33. 0, /* .padding */
  34. true, /* .namespaceZero, see .memberTypeIndex */
  35. false /* .isArray */
  36. },
  37. /* y */
  38. {
  39. UA_TYPENAME("y")
  40. UA_TYPES_FLOAT, padding_y, true, false
  41. },
  42. /* z */
  43. {
  44. UA_TYPENAME("y")
  45. UA_TYPES_FLOAT, padding_z, true, false
  46. }
  47. };
  48. static const UA_DataType PointType = {
  49. UA_TYPENAME("Point") /* .typeName */
  50. {1, UA_NODEIDTYPE_NUMERIC, {1}}, /* .typeId */
  51. sizeof(Point), /* .memSize */
  52. 0, /* .typeIndex, in the array of custom types */
  53. UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
  54. true, /* .pointerFree */
  55. false, /* .overlayable (depends on endianness and
  56. the absence of padding) */
  57. 3, /* .membersSize */
  58. 0, /* .binaryEncodingId, the numeric
  59. identifier used on the wire (the
  60. namespaceindex is from .typeId) */
  61. members
  62. };
  63. const UA_DataTypeArray customDataTypes = {NULL, 1, &PointType};
  64. START_TEST(parseCustomScalar) {
  65. Point p;
  66. p.x = 1.0;
  67. p.y = 2.0;
  68. p.z = 3.0;
  69. UA_Variant var;
  70. UA_Variant_init(&var);
  71. UA_Variant_setScalar(&var, &p, &PointType);
  72. size_t buflen = UA_calcSizeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT]);
  73. UA_ByteString buf;
  74. UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, buflen);
  75. ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
  76. UA_Byte *pos = buf.data;
  77. const UA_Byte *end = &buf.data[buf.length];
  78. retval = UA_encodeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT],
  79. &pos, &end, NULL, NULL);
  80. ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
  81. UA_Variant var2;
  82. size_t offset = 0;
  83. retval = UA_decodeBinary(&buf, &offset, &var2, &UA_TYPES[UA_TYPES_VARIANT], &customDataTypes);
  84. ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
  85. ck_assert(var2.type == &PointType);
  86. Point *p2 = (Point*)var2.data;
  87. ck_assert(p.x == p2->x);
  88. UA_Variant_deleteMembers(&var2);
  89. UA_ByteString_deleteMembers(&buf);
  90. } END_TEST
  91. START_TEST(parseCustomScalarExtensionObject) {
  92. Point p;
  93. p.x = 1.0;
  94. p.y = 2.0;
  95. p.z = 3.0;
  96. UA_ExtensionObject eo;
  97. UA_ExtensionObject_init(&eo);
  98. eo.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
  99. eo.content.decoded.data = &p;
  100. eo.content.decoded.type = &PointType;
  101. size_t buflen = UA_calcSizeBinary(&eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
  102. UA_ByteString buf;
  103. UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, buflen);
  104. ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
  105. UA_Byte *bufPos = buf.data;
  106. const UA_Byte *bufEnd = &buf.data[buf.length];
  107. retval = UA_encodeBinary(&eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], &bufPos, &bufEnd, NULL, NULL);
  108. ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
  109. UA_ExtensionObject eo2;
  110. size_t offset = 0;
  111. retval = UA_decodeBinary(&buf, &offset, &eo2, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], &customDataTypes);
  112. ck_assert_int_eq(offset, (uintptr_t)(bufPos - buf.data));
  113. ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
  114. ck_assert_int_eq(eo2.encoding, UA_EXTENSIONOBJECT_DECODED);
  115. ck_assert(eo2.content.decoded.type == &PointType);
  116. Point *p2 = (Point*)eo2.content.decoded.data;
  117. ck_assert(p.x == p2->x);
  118. UA_ExtensionObject_deleteMembers(&eo2);
  119. UA_ByteString_deleteMembers(&buf);
  120. } END_TEST
  121. START_TEST(parseCustomArray) {
  122. Point ps[10];
  123. for(size_t i = 0; i < 10; ++i) {
  124. ps[i].x = (UA_Float)(1*i);
  125. ps[i].y = (UA_Float)(2*i);
  126. ps[i].z = (UA_Float)(3*i);
  127. }
  128. UA_Variant var;
  129. UA_Variant_init(&var);
  130. UA_Variant_setArray(&var, (void*)ps, 10, &PointType);
  131. size_t buflen = UA_calcSizeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT]);
  132. UA_ByteString buf;
  133. UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, buflen);
  134. ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
  135. UA_Byte *pos = buf.data;
  136. const UA_Byte *end = &buf.data[buf.length];
  137. retval = UA_encodeBinary(&var, &UA_TYPES[UA_TYPES_VARIANT],
  138. &pos, &end, NULL, NULL);
  139. ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
  140. UA_Variant var2;
  141. size_t offset = 0;
  142. retval = UA_decodeBinary(&buf, &offset, &var2, &UA_TYPES[UA_TYPES_VARIANT], &customDataTypes);
  143. ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
  144. ck_assert(var2.type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
  145. ck_assert_int_eq(var2.arrayLength, 10);
  146. for (size_t i = 0; i < 10; i++) {
  147. UA_ExtensionObject *eo = &((UA_ExtensionObject*)var2.data)[i];
  148. ck_assert_int_eq(eo->encoding, UA_EXTENSIONOBJECT_DECODED);
  149. ck_assert(eo->content.decoded.type == &PointType);
  150. Point *p2 = (Point*)eo->content.decoded.data;
  151. // we need to cast floats to int to avoid comparison of floats
  152. // which may result into false results
  153. ck_assert((int)p2->x == (int)ps[i].x);
  154. ck_assert((int)p2->y == (int)ps[i].y);
  155. ck_assert((int)p2->z == (int)ps[i].z);
  156. }
  157. UA_Variant_deleteMembers(&var2);
  158. UA_ByteString_deleteMembers(&buf);
  159. } END_TEST
  160. int main(void) {
  161. Suite *s = suite_create("Test Custom DataType Encoding");
  162. TCase *tc = tcase_create("test cases");
  163. tcase_add_test(tc, parseCustomScalar);
  164. tcase_add_test(tc, parseCustomScalarExtensionObject);
  165. tcase_add_test(tc, parseCustomArray);
  166. suite_add_tcase(s, tc);
  167. SRunner *sr = srunner_create(s);
  168. srunner_set_fork_status(sr, CK_NOFORK);
  169. srunner_run_all (sr, CK_NORMAL);
  170. int number_failed = srunner_ntests_failed(sr);
  171. srunner_free(sr);
  172. return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  173. }
  174. #ifdef __clang__
  175. #pragma clang diagnostic pop
  176. #endif