check_types_custom.c 7.1 KB

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