You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by rl...@apache.org on 2019/08/29 12:16:18 UTC
[celix] branch develop updated: Added avpr parsing and
serialization (#43)
This is an automated email from the ASF dual-hosted git repository.
rlenferink pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/celix.git
The following commit(s) were added to refs/heads/develop by this push:
new 48a8fb5 Added avpr parsing and serialization (#43)
48a8fb5 is described below
commit 48a8fb5be15eef23db3cc989bd6e1ace1970de04
Author: idzardh <id...@live.nl>
AuthorDate: Thu Aug 29 14:16:14 2019 +0200
Added avpr parsing and serialization (#43)
* Added avpr parsing and serialization
* Update cpp test code
* Update json serializer to also handle avpr. Leave descriptor parsing intact.
* Adding all annotations to dyn_type
* Added test case for custom annotation
---
bundles/pubsub/mock/CMakeLists.txt | 6 +-
.../src/pubsub_serializer_impl.c | 307 ++++--
bundles/pubsub/test/CMakeLists.txt | 1 +
.../examples/calculator_api/CMakeLists.txt | 2 +-
.../org.apache.celix.calc.api.Calculator.avpr | 44 +
.../examples/calculator_shell/CMakeLists.txt | 4 +-
.../remote_service_admin_dfi/src/dfi_utils.c | 23 +
.../remote_service_admin_dfi/src/dfi_utils.h | 1 +
.../src/export_registration_dfi.c | 11 +-
.../src/import_registration_dfi.c | 9 +-
.../topology_manager/CMakeLists.txt | 8 +-
.../topology_manager/tms_tst/bundle/CMakeLists.txt | 2 +-
.../bundle/org.apache.celix.test.MyBundle.avpr | 24 +
.../org.apache.celix.test.MyBundle.descriptor | 9 -
.../topology_manager/tms_tst/tms_tests.cpp | 6 +-
libs/CMakeLists.txt | 2 +-
libs/dfi/CMakeLists.txt | 33 +-
libs/dfi/include/dyn_function.h | 5 +
libs/dfi/include/dyn_function_common.h | 55 +
libs/dfi/include/dyn_interface.h | 4 +
.../dfi/include/dyn_interface_common.h | 23 +-
libs/dfi/include/dyn_message.h | 4 +-
libs/dfi/include/dyn_type.h | 19 +
libs/dfi/include/dyn_type_common.h | 64 ++
libs/dfi/src/dyn_avpr_function.c | 352 +++++++
libs/dfi/src/dyn_avpr_interface.c | 290 ++++++
libs/dfi/src/dyn_avpr_type.c | 987 ++++++++++++++++++
libs/dfi/src/dyn_function.c | 29 +-
libs/dfi/src/dyn_interface.c | 16 +-
libs/dfi/src/dyn_type.c | 141 +--
libs/dfi/src/dyn_type_common.c | 81 ++
libs/dfi/src/json_serializer.c | 59 +-
libs/dfi/test/avro_descriptor_translator_tests.cpp | 1 +
libs/dfi/test/dyn_avpr_function_tests.cpp | 620 ++++++++++++
libs/dfi/test/dyn_avpr_interface_tests.cpp | 174 ++++
libs/dfi/test/dyn_avpr_tests.cpp | 514 ++++++++++
libs/dfi/test/dyn_function_tests.cpp | 3 +-
libs/dfi/test/dyn_interface_tests.cpp | 1 +
libs/dfi/test/dyn_message_tests.cpp | 1 +
libs/dfi/test/dyn_type_tests.cpp | 11 +
libs/dfi/test/json_rpc_avpr_tests.cpp | 384 +++++++
libs/dfi/test/json_rpc_tests.cpp | 147 ++-
libs/dfi/test/json_serializer_tests.cpp | 1067 +++++++++++++++++---
libs/framework/CMakeLists.txt | 78 +-
libs/framework/tst/CMakeLists.txt | 2 +
45 files changed, 5111 insertions(+), 513 deletions(-)
diff --git a/bundles/pubsub/mock/CMakeLists.txt b/bundles/pubsub/mock/CMakeLists.txt
index 2a406d0..98be018 100644
--- a/bundles/pubsub/mock/CMakeLists.txt
+++ b/bundles/pubsub/mock/CMakeLists.txt
@@ -23,11 +23,9 @@ if (CPPUTEST_FOUND)
add_library(pubsub_mock STATIC
src/publisher_mock.cc
)
- target_include_directories(pubsub_mock PUBLIC api)
target_link_libraries(pubsub_mock PRIVATE Celix::pubsub_spi ${CPPUTEST_LIBRARY})
- target_include_directories(pubsub_mock SYSTEM PRIVATE
- ${CPPUTEST_INCLUDE_DIR}
- )
+ target_include_directories(pubsub_mock PUBLIC api)
+ target_include_directories(pubsub_mock SYSTEM PRIVATE ${CPPUTEST_INCLUDE_DIR})
if (ENABLE_TESTING)
add_executable(pubsubmock_test
diff --git a/bundles/pubsub/pubsub_serializer_json/src/pubsub_serializer_impl.c b/bundles/pubsub/pubsub_serializer_json/src/pubsub_serializer_impl.c
index 4dc9916..5637937 100644
--- a/bundles/pubsub/pubsub_serializer_json/src/pubsub_serializer_impl.c
+++ b/bundles/pubsub/pubsub_serializer_json/src/pubsub_serializer_impl.c
@@ -37,6 +37,14 @@
#define SYSTEM_BUNDLE_ARCHIVE_PATH "CELIX_FRAMEWORK_EXTENDER_PATH"
#define MAX_PATH_LEN 1024
+typedef enum
+{
+ FIT_INVALID = 0,
+ FIT_DESCRIPTOR = 1,
+ FIT_AVPR = 2
+}
+FILE_INPUT_TYPE;
+
struct pubsub_json_serializer {
bundle_context_pt bundle_context;
log_helper_pt loghelper;
@@ -47,10 +55,12 @@ struct pubsub_json_serializer {
static celix_status_t pubsubMsgSerializer_serialize(void* handle, const void* msg, void** out, size_t *outLen);
static celix_status_t pubsubMsgSerializer_deserialize(void* handle, const void* input, size_t inputLen, void **out);
static void pubsubMsgSerializer_freeMsg(void* handle, void *msg);
-
+static FILE* openFileStream(FILE_INPUT_TYPE file_input_type, const char* filename, const char* root, /*output*/ char* avpr_fqn, /*output*/ char* path);
+static FILE_INPUT_TYPE getFileInputType(const char* filename);
+static bool readPropertiesFile(const char* properties_file_name, const char* root, /*output*/ char* avpr_fqn, /*output*/ char* path);
typedef struct pubsub_json_msg_serializer_impl {
- dyn_message_type *msgType;
+ dyn_type *type;
unsigned int msgId;
const char* msgName;
@@ -61,6 +71,8 @@ static char* pubsubSerializer_getMsgDescriptionDir(bundle_pt bundle);
static void pubsubSerializer_addMsgSerializerFromBundle(const char *root, bundle_pt bundle, hash_map_pt msgTypesMap);
static void pubsubSerializer_fillMsgSerializerMap(hash_map_pt msgTypesMap,bundle_pt bundle);
+static int pubsubMsgSerializer_convert_descriptor(FILE* file_ptr, pubsub_msg_serializer_t* serializer);
+static int pubsubMsgSerializer_convert_avpr(FILE* file_ptr, pubsub_msg_serializer_t* serializer, const char* fqn);
static void dfi_log(void *handle, int level, const char *file, int line, const char *msg, ...) {
va_list ap;
@@ -139,8 +151,7 @@ celix_status_t pubsubSerializer_destroySerializerMap(void* handle __attribute__(
while (hashMapIterator_hasNext(&iter)) {
pubsub_msg_serializer_t* msgSerializer = hashMapIterator_nextValue(&iter);
pubsub_json_msg_serializer_impl_t *impl = msgSerializer->handle;
- dyn_message_type *dynMsg = impl->msgType;
- dynMessage_destroy(dynMsg); //note msgSer->name and msgSer->version owned by dynType
+ dynType_destroy(impl->type);
free(msgSerializer); //also contains the service struct.
free(impl);
}
@@ -157,9 +168,7 @@ celix_status_t pubsubMsgSerializer_serialize(void *handle, const void* msg, void
pubsub_json_msg_serializer_impl_t *impl = handle;
char *jsonOutput = NULL;
- dyn_type* dynType = NULL;
- dyn_message_type *dynMsg = impl->msgType;
- dynMessage_getMessageType(dynMsg, &dynType);
+ dyn_type* dynType = impl->type;
if (jsonSerializer_serialize(dynType, msg, &jsonOutput) != 0) {
status = CELIX_BUNDLE_EXCEPTION;
@@ -177,9 +186,7 @@ celix_status_t pubsubMsgSerializer_deserialize(void* handle, const void* input,
celix_status_t status = CELIX_SUCCESS;
pubsub_json_msg_serializer_impl_t *impl = handle;
void *msg = NULL;
- dyn_type* dynType = NULL;
- dyn_message_type *dynMsg = impl->msgType;
- dynMessage_getMessageType(dynMsg, &dynType);
+ dyn_type* dynType = impl->type;
if (jsonSerializer_deserialize(dynType, (const char*)input, &msg) != 0) {
status = CELIX_BUNDLE_EXCEPTION;
@@ -193,9 +200,7 @@ celix_status_t pubsubMsgSerializer_deserialize(void* handle, const void* input,
void pubsubMsgSerializer_freeMsg(void* handle, void *msg) {
pubsub_json_msg_serializer_impl_t *impl = handle;
- dyn_type* dynType = NULL;
- dyn_message_type *dynMsg = impl->msgType;
- dynMessage_getMessageType(dynMsg, &dynType);
+ dyn_type* dynType = impl->type;
if (dynType != NULL) {
dynType_free(dynType, msg);
}
@@ -249,88 +254,222 @@ static char* pubsubSerializer_getMsgDescriptionDir(bundle_pt bundle)
static void pubsubSerializer_addMsgSerializerFromBundle(const char *root, bundle_pt bundle, hash_map_pt msgSerializers)
{
+ char fqn[MAX_PATH_LEN];
char path[MAX_PATH_LEN];
- struct dirent *entry = NULL;
- DIR *dir = opendir(root);
+ const char* entry_name = NULL;
+ FILE_INPUT_TYPE fileInputType;
+ FILE* stream = NULL;
+ const struct dirent *entry = NULL;
+ DIR* dir = opendir(root);
if (dir) {
entry = readdir(dir);
}
- while (entry != NULL) {
-
- if (strstr(entry->d_name, ".descriptor") != NULL) {
-
- printf("DMU: Parsing entry '%s'\n", entry->d_name);
-
- snprintf(path, MAX_PATH_LEN, "%s/%s", root, entry->d_name);
- FILE *stream = fopen(path,"r");
-
- if (stream != NULL) {
- dyn_message_type* msgType = NULL;
-
- int rc = dynMessage_parse(stream, &msgType);
- if (rc == 0 && msgType != NULL) {
-
- char* msgName = NULL;
- rc += dynMessage_getName(msgType,&msgName);
-
- version_pt msgVersion = NULL;
- rc += dynMessage_getVersion(msgType, &msgVersion);
-
- if (rc == 0 && msgName != NULL && msgVersion != NULL) {
-
- unsigned int msgId = utils_stringHash(msgName);
-
- pubsub_msg_serializer_t *msgSerializer = calloc(1,sizeof(*msgSerializer));
- pubsub_json_msg_serializer_impl_t *impl = calloc(1, sizeof(*impl));
-
- impl->msgType = msgType;
- impl->msgId = msgId;
- impl->msgName = msgName;
- impl->msgVersion = msgVersion;
-
- msgSerializer->handle = impl;
- msgSerializer->msgId = impl->msgId;
- msgSerializer->msgName = impl->msgName;
- msgSerializer->msgVersion = impl->msgVersion;
- msgSerializer->serialize = (void*) pubsubMsgSerializer_serialize;
- msgSerializer->deserialize = (void*) pubsubMsgSerializer_deserialize;
- msgSerializer->freeMsg = (void*) pubsubMsgSerializer_freeMsg;
-
- bool clash = hashMap_containsKey(msgSerializers, (void*)(uintptr_t)msgId);
- if (clash) {
- printf("Cannot add msg %s. clash in msg id %d!!\n", msgName, msgId);
- free(msgSerializer);
- free(impl);
- dynMessage_destroy(msgType);
- } else if (msgId != 0) {
- printf("Adding %u : %s\n", msgId, msgName);
- hashMap_put(msgSerializers, (void*)(uintptr_t)msgId, msgSerializer);
- } else {
- printf("Error creating msg serializer\n");
- free(impl);
- free(msgSerializer);
- dynMessage_destroy(msgType);
- }
-
- } else {
- printf("Cannot retrieve name and/or version from msg\n");
- }
-
- } else {
- printf("DMU: cannot parse message from descriptor %s\n.",path);
- }
- fclose(stream);
- } else {
- printf("DMU: cannot open descriptor file %s\n.",path);
- }
+ for (; entry != NULL; entry = readdir(dir)) {
+ entry_name = entry->d_name;
+ printf("DMU: Parsing entry '%s'\n", entry_name);
+ fileInputType = getFileInputType(entry_name);
+ stream = openFileStream(fileInputType, entry_name, root, /*out*/fqn, /*out*/path);
+ if (!stream) {
+ printf("DMU: Cannot open descriptor file: '%s'.\n", path);
+ continue; // Go to next entry in directory
+ }
+ pubsub_json_msg_serializer_impl_t *impl = calloc(1, sizeof(*impl));
+ pubsub_msg_serializer_t *msgSerializer = calloc(1,sizeof(*msgSerializer));
+ msgSerializer->handle = impl;
+
+ int translation_result = -1;
+ if (fileInputType == FIT_DESCRIPTOR) {
+ translation_result = pubsubMsgSerializer_convert_descriptor(stream, msgSerializer);
+ }
+ else if (fileInputType == FIT_AVPR) {
+ translation_result = pubsubMsgSerializer_convert_avpr(stream, msgSerializer, fqn);
+ }
+ fclose(stream);
+
+ if (translation_result != 0) {
+ printf("DMU: could not create serializer for '%s'\n", entry_name);
+ free(impl);
+ free(msgSerializer);
+ continue;
+ }
+
+ // serializer has been constructed, try to put in the map
+ if (hashMap_containsKey(msgSerializers, (void *) (uintptr_t) msgSerializer->msgId)) {
+ printf("Cannot add msg %s. clash in msg id %d!!\n", msgSerializer->msgName, msgSerializer->msgId);
+ dynType_destroy(impl->type);
+ free(msgSerializer);
+ free(impl);
+ } else if (msgSerializer->msgId == 0) {
+ printf("Cannot add msg %s. clash in msg id %d!!\n", msgSerializer->msgName, msgSerializer->msgId);
+ dynType_destroy(impl->type);
+ free(msgSerializer);
+ free(impl);
+ }
+ else {
+ hashMap_put(msgSerializers, (void *) (uintptr_t) msgSerializer->msgId, msgSerializer);
}
- entry = readdir(dir);
}
if (dir) {
closedir(dir);
}
}
+static FILE* openFileStream(FILE_INPUT_TYPE file_input_type, const char* filename, const char* root, char* avpr_fqn, char* path) {
+ FILE* result = NULL;
+ memset(path, 0, MAX_PATH_LEN);
+ switch (file_input_type) {
+ case FIT_INVALID:
+ snprintf(path, MAX_PATH_LEN, "Because %s is not a valid file", filename);
+ break;
+
+ case FIT_DESCRIPTOR:
+ snprintf(path, MAX_PATH_LEN, "%s/%s", root, filename);
+ result = fopen(path, "r");
+ break;
+
+ case FIT_AVPR:
+ if (readPropertiesFile(filename, root, avpr_fqn, path)) {
+ result = fopen(path, "r");
+ }
+ break;
+
+ default:
+ printf("DMU: Unknown file input type, returning NULL!\n");
+ break;
+ }
+
+ return result;
+}
+
+static FILE_INPUT_TYPE getFileInputType(const char* filename) {
+ if (strstr(filename, ".descriptor")) {
+ return FIT_DESCRIPTOR;
+ }
+ else if (strstr(filename, ".properties")) {
+ return FIT_AVPR;
+ }
+ else {
+ return FIT_INVALID;
+ }
+}
+
+static bool readPropertiesFile(const char* properties_file_name, const char* root, char* avpr_fqn, char* path) {
+ snprintf(path, MAX_PATH_LEN, "%s/%s", root, properties_file_name); // use path to create path to properties file
+ FILE *properties = fopen(path, "r");
+ if (!properties) {
+ printf("DMU: Could not find or open %s as a properties file in %s\n", properties_file_name, root);
+ return false;
+ }
+
+ *avpr_fqn = '\0';
+ *path = '\0'; //re-use path to create path to avpr file
+ char *p_line = malloc(MAX_PATH_LEN);
+ size_t line_len = MAX_PATH_LEN;
+ while (getline(&p_line, &line_len, properties) >= 0) {
+ if (strncmp(p_line, "fqn=", strlen("fqn=")) == 0) {
+ snprintf(avpr_fqn, MAX_PATH_LEN, "%s", (p_line + strlen("fqn=")));
+ avpr_fqn[strcspn(avpr_fqn, "\n")] = 0;
+ }
+ else if (strncmp(p_line, "avpr=", strlen("avpr=")) == 0) {
+ snprintf(path, MAX_PATH_LEN, "%s/%s", root, (p_line + strlen("avpr=")));
+ path[strcspn(path, "\n")] = 0;
+ }
+ }
+ free(p_line);
+ fclose(properties);
+
+ if (*avpr_fqn == '\0') {
+ printf("CMU: File %s does not contain a fully qualified name for the parser\n", properties_file_name);
+ return false;
+ }
+
+ if (*path == '\0') {
+ printf("CMU: File %s does not contain a location for the avpr file\n", properties_file_name);
+ return false;
+ }
+
+ return true;
+}
+
+static int pubsubMsgSerializer_convert_descriptor(FILE* file_ptr, pubsub_msg_serializer_t* serializer) {
+ dyn_message_type* msgType = NULL;
+ int rc = dynMessage_parse(file_ptr, &msgType);
+ if (rc != 0 || msgType == NULL) {
+ printf("DMU: cannot parse message from descriptor.\n");
+ return -1;
+ }
+
+ char* msgName = NULL;
+ rc += dynMessage_getName(msgType, &msgName);
+
+ version_pt msgVersion = NULL;
+ rc += dynMessage_getVersion(msgType, &msgVersion);
+
+ if (rc != 0 || msgName == NULL || msgVersion == NULL) {
+ printf("DMU: cannot retrieve name and/or version from msg\n");
+ return -1;
+ }
+
+ dyn_type * type = NULL;
+ dynMessage_getMessageType(msgType, &type);
+
+ unsigned int msgId = utils_stringHash(msgName);
+ pubsub_json_msg_serializer_impl_t * handle = (pubsub_json_msg_serializer_impl_t*)serializer->handle;
+ handle->type = type;
+ handle->msgId = msgId;
+ handle->msgName = msgName;
+ handle->msgVersion = msgVersion;
+
+ serializer->msgId = handle->msgId;
+ serializer->msgName = handle->msgName;
+ serializer->msgVersion = handle->msgVersion;
+
+ serializer->serialize = (void*) pubsubMsgSerializer_serialize;
+ serializer->deserialize = (void*) pubsubMsgSerializer_deserialize;
+ serializer->freeMsg = (void*) pubsubMsgSerializer_freeMsg;
+
+ return 0;
+}
+
+static int pubsubMsgSerializer_convert_avpr(FILE* file_ptr, pubsub_msg_serializer_t* serializer, const char* fqn) {
+ if (!file_ptr || !fqn || !serializer) return -2;
+ dyn_type* type = dynType_parseAvpr(file_ptr, fqn);
+
+ if (!type) {
+ printf("DMU: cannot parse avpr file for '%s'\n", fqn);
+ return -1;
+ }
+
+ const char* msgName = dynType_getName(type);
+
+ version_pt msgVersion = NULL;
+ celix_status_t s = version_createVersionFromString(dynType_getMetaInfo(type, "version"), &msgVersion);
+
+ if (s != CELIX_SUCCESS || !msgName) {
+ printf("DMU: cannot retrieve name and/or version from msg\n");
+ if (s == CELIX_SUCCESS) {
+ version_destroy(msgVersion);
+ }
+ return -1;
+ }
+
+ unsigned int msgId = utils_stringHash(msgName);
+ pubsub_json_msg_serializer_impl_t * handle = (pubsub_json_msg_serializer_impl_t*) serializer->handle;
+ handle->type = type;
+ handle->msgId = msgId;
+ handle->msgName = msgName;
+ handle->msgVersion = msgVersion;
+
+ serializer->msgId = handle->msgId;
+ serializer->msgName = handle->msgName;
+ serializer->msgVersion = handle->msgVersion;
+
+ serializer->serialize = (void*) pubsubMsgSerializer_serialize;
+ serializer->deserialize = (void*) pubsubMsgSerializer_deserialize;
+ serializer->freeMsg = (void*) pubsubMsgSerializer_freeMsg;
+
+ return 0;
+}
diff --git a/bundles/pubsub/test/CMakeLists.txt b/bundles/pubsub/test/CMakeLists.txt
index 957745b..f2f9374 100644
--- a/bundles/pubsub/test/CMakeLists.txt
+++ b/bundles/pubsub/test/CMakeLists.txt
@@ -207,6 +207,7 @@ if (BUILD_PUBSUB_PSA_ZMQ)
pubsub_sut
pubsub_tst
)
+
target_link_libraries(pubsub_zmq_tests PRIVATE Celix::pubsub_api ${CPPUTEST_LIBRARIES} ${JANSSON_LIBRARIES} Celix::dfi)
target_include_directories(pubsub_zmq_tests PRIVATE ${CPPUTEST_INCLUDE_DIR})
add_test(NAME pubsub_zmq_tests COMMAND pubsub_zmq_tests WORKING_DIRECTORY $<TARGET_PROPERTY:pubsub_zmq_tests,CONTAINER_LOC>)
diff --git a/bundles/remote_services/examples/calculator_api/CMakeLists.txt b/bundles/remote_services/examples/calculator_api/CMakeLists.txt
index 2fb445b..a87945f 100644
--- a/bundles/remote_services/examples/calculator_api/CMakeLists.txt
+++ b/bundles/remote_services/examples/calculator_api/CMakeLists.txt
@@ -19,4 +19,4 @@ add_library(calculator_api INTERFACE)
target_include_directories(calculator_api INTERFACE include)
set_target_properties(calculator_api PROPERTIES
"INTERFACE_CALCULATOR_DESCRIPTOR"
- "${CMAKE_CURRENT_LIST_DIR}/include/org.apache.celix.calc.api.Calculator.descriptor")
+ "${CMAKE_CURRENT_LIST_DIR}/include/org.apache.celix.calc.api.Calculator.avpr")
diff --git a/bundles/remote_services/examples/calculator_api/include/org.apache.celix.calc.api.Calculator.avpr b/bundles/remote_services/examples/calculator_api/include/org.apache.celix.calc.api.Calculator.avpr
new file mode 100644
index 0000000..b20554e
--- /dev/null
+++ b/bundles/remote_services/examples/calculator_api/include/org.apache.celix.calc.api.Calculator.avpr
@@ -0,0 +1,44 @@
+{
+ "protocol" : "Calculator",
+ "namespace" : "org.apache.celix.calc.api",
+ "version" : "1.3.0",
+ "types" : [ {
+ "type" : "fixed",
+ "name" : "Double",
+ "alias": "double",
+ "size" : 8
+ } ] ,
+ "messages" : {
+ "add" : {
+ "index" : 0,
+ "request" : [ {
+ "name" : "arg1",
+ "type" : "Double"
+ } , {
+ "name" : "arg2",
+ "type" : "Double"
+ } ],
+ "response" : "Double"
+ },
+ "sub" : {
+ "index" : 1,
+ "request" : [ {
+ "name" : "arg1",
+ "type" : "Double"
+ } , {
+ "name" : "arg2",
+ "type" : "Double"
+ } ],
+ "response" : "Double"
+ },
+ "sqrt" : {
+ "index" : 2,
+ "request" : [ {
+ "name" : "arg",
+ "type" : "Double"
+ } ],
+ "response" : "Double"
+ }
+ }
+}
+
diff --git a/bundles/remote_services/examples/calculator_shell/CMakeLists.txt b/bundles/remote_services/examples/calculator_shell/CMakeLists.txt
index 5f3e9e2..14087e3 100644
--- a/bundles/remote_services/examples/calculator_shell/CMakeLists.txt
+++ b/bundles/remote_services/examples/calculator_shell/CMakeLists.txt
@@ -28,7 +28,7 @@ target_include_directories(calculator_shell PRIVATE src)
target_link_libraries(calculator_shell PRIVATE Celix::shell_api calculator_api)
celix_bundle_files(calculator_shell
- ../calculator_api/include/org.apache.celix.calc.api.Calculator.descriptor
- #src/org.apache.celix.calc.api.Calculator.descriptor ##Use this descriptor in case you want to try out versioning!
+ ../calculator_api/include/org.apache.celix.calc.api.Calculator.avpr
+ #src/org.apache.celix.calc.api.Calculator2.descriptor ##Use this descriptor in case you want to try out versioning!
DESTINATION .
)
diff --git a/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.c b/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.c
index 631152d..74eb259 100644
--- a/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.c
+++ b/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.c
@@ -106,3 +106,26 @@ celix_status_t dfi_findDescriptor(bundle_context_pt context, bundle_pt bundle, c
return status;
}
+
+celix_status_t dfi_findAvprDescriptor(bundle_context_pt context, bundle_pt bundle, const char *name, FILE **out) {
+ celix_status_t status;
+ char fileName[128];
+
+ snprintf(fileName, 128, "%s.avpr", name);
+
+ long id;
+ status = bundle_getBundleId(bundle, &id);
+
+ if (status == CELIX_SUCCESS) {
+ if (id == 0) {
+ //framework bundle
+ status = dfi_findFileForFramework(context, fileName, out);
+ } else {
+ //normal bundle
+ status = dfi_findFileForBundle(bundle, fileName, out);
+ }
+ }
+
+ return status;
+}
+
diff --git a/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.h b/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.h
index cec8aa1..b3056c4 100644
--- a/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.h
+++ b/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.h
@@ -26,5 +26,6 @@
celix_status_t dfi_findDescriptor(bundle_context_pt context, bundle_pt bundle, const char *name, FILE **out);
+celix_status_t dfi_findAvprDescriptor(bundle_context_pt context, bundle_pt bundle, const char *name, FILE **out);
#endif
diff --git a/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c b/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c
index 59d6276..e5b4f46 100644
--- a/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c
+++ b/bundles/remote_services/remote_service_admin_dfi/src/export_registration_dfi.c
@@ -90,7 +90,7 @@ celix_status_t exportRegistration_create(log_helper_pt helper, service_reference
FILE *descriptor = NULL;
if (status == CELIX_SUCCESS) {
- status = dfi_findDescriptor(context, bundle, exports, &descriptor);
+ status = dfi_findAvprDescriptor(context, bundle, exports, &descriptor);
}
if (status != CELIX_SUCCESS || descriptor == NULL) {
@@ -99,11 +99,12 @@ celix_status_t exportRegistration_create(log_helper_pt helper, service_reference
}
if (status == CELIX_SUCCESS) {
- int rc = dynInterface_parse(descriptor, ®->intf);
+ reg->intf = dynInterface_parseAvpr(descriptor);
+
fclose(descriptor);
- if (rc != 0) {
+ if (!reg->intf) {
status = CELIX_BUNDLE_EXCEPTION;
- logHelper_log(helper, OSGI_LOGSERVICE_WARNING, "RSA: Error parsing service descriptor.");
+ logHelper_log(helper, OSGI_LOGSERVICE_WARNING, "RSA: Error parsing service descriptor for '%s'", exports);
}
else {
/* Add the interface version as a property in the properties_map */
@@ -260,4 +261,4 @@ celix_status_t exportReference_getExportedService(export_reference_pt reference,
celix_status_t status = CELIX_SUCCESS;
*ref = reference->reference;
return status;
-}
\ No newline at end of file
+}
diff --git a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c
index a40a560..f7f6567 100644
--- a/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c
+++ b/bundles/remote_services/remote_service_admin_dfi/src/import_registration_dfi.c
@@ -208,18 +208,19 @@ static celix_status_t importRegistration_createProxy(import_registration_pt impo
dyn_interface_type* intf = NULL;
FILE *descriptor = NULL;
- status = dfi_findDescriptor(import->context, bundle, import->classObject, &descriptor);
+ status = dfi_findAvprDescriptor(import->context, bundle, import->classObject, &descriptor);
if (status != CELIX_SUCCESS || descriptor == NULL) {
//TODO use log helper logHelper_log(helper, OSGI_LOGSERVICE_ERROR, "Cannot find/open descriptor for '%s'", import->classObject);
- fprintf(stderr, "RSA_DFI: Cannot find/open descriptor for '%s'", import->classObject);
+ fprintf(stdout, "RSA_DFI: Cannot find/open descriptor for '%s'", import->classObject);
return CELIX_BUNDLE_EXCEPTION;
}
if (status == CELIX_SUCCESS) {
- int rc = dynInterface_parse(descriptor, &intf);
+ intf = dynInterface_parseAvpr(descriptor);
fclose(descriptor);
- if (rc != 0 || intf==NULL) {
+ if (!intf) {
+ fprintf(stderr, "RSA_DFI: Cannot parse descriptor for '%s'", import->classObject);
return CELIX_BUNDLE_EXCEPTION;
}
}
diff --git a/bundles/remote_services/topology_manager/CMakeLists.txt b/bundles/remote_services/topology_manager/CMakeLists.txt
index 8a4661d..8343d9f 100644
--- a/bundles/remote_services/topology_manager/CMakeLists.txt
+++ b/bundles/remote_services/topology_manager/CMakeLists.txt
@@ -35,10 +35,10 @@ if (RSA_TOPOLOGY_MANAGER)
if (ENABLE_TESTING)
find_package(CppUTest REQUIRED)
find_package(Jansson REQUIRED)
-
- include_directories("${JANSSON_INCLUDE_DIR}")
- include_directories(${CPPUTEST_INCLUDE_DIR})
- include_directories(${CPPUTEST_EXT_INCLUDE_DIR})
+
+ include_directories("${JANSSON_INCLUDE_DIR}")
+ include_directories("${CPPUTEST_INCLUDE_DIR}")
+ include_directories("${CPPUTEST_EXT_INCLUDE_DIR}")
add_subdirectory(tms_tst)
endif (ENABLE_TESTING)
diff --git a/bundles/remote_services/topology_manager/tms_tst/bundle/CMakeLists.txt b/bundles/remote_services/topology_manager/tms_tst/bundle/CMakeLists.txt
index 15536e0..8df8399 100644
--- a/bundles/remote_services/topology_manager/tms_tst/bundle/CMakeLists.txt
+++ b/bundles/remote_services/topology_manager/tms_tst/bundle/CMakeLists.txt
@@ -28,7 +28,7 @@ add_celix_bundle(topology_manager_test_bundle
tst_activator.c
)
celix_bundle_files(topology_manager_test_bundle
- org.apache.celix.test.MyBundle.descriptor
+ org.apache.celix.test.MyBundle.avpr
DESTINATION .
)
diff --git a/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.avpr b/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.avpr
new file mode 100644
index 0000000..3876f6f
--- /dev/null
+++ b/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.avpr
@@ -0,0 +1,24 @@
+{
+ "protocol" : "MyBundle",
+ "namespace" : "org.apache.celix",
+ "version" : "1.0.0",
+ "types" : [ {
+ "type" : "fixed",
+ "name" : "Double",
+ "alias": "double",
+ "size" : 8
+ } ] ,
+ "messages" : {
+ "add" : {
+ "index" : 0,
+ "request" : [ {
+ "name" : "arg1",
+ "type" : "Double"
+ } , {
+ "name" : "arg2",
+ "type" : "Double"
+ } ],
+ "response" : "Double"
+ }
+ }
+}
diff --git a/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.descriptor b/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.descriptor
deleted file mode 100644
index 8f04454..0000000
--- a/bundles/remote_services/topology_manager/tms_tst/bundle/org.apache.celix.test.MyBundle.descriptor
+++ /dev/null
@@ -1,9 +0,0 @@
-:header
-type=interface
-name=MyBundle
-version=1.0.0
-:annotations
-classname=org.apache.celix.MyBundle
-:types
-:methods
-add(DD)D=add(#am=handle;PDD#am=pre;*D)N
diff --git a/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp b/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp
index c0001aa..70bcadb 100644
--- a/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp
+++ b/bundles/remote_services/topology_manager/tms_tst/tms_tests.cpp
@@ -85,7 +85,6 @@ extern "C" {
static service_reference_pt eplRef = NULL;
static endpoint_listener_pt eplService = NULL; // actually this is the topology manager
-
static void setupFm(void) {
int rc = 0;
rc = celixLauncher_launch("config.properties", &framework);
@@ -125,9 +124,12 @@ extern "C" {
rc = bundleContext_getService(context, discRef, (void **)&discMock);
CHECK_EQUAL(CELIX_SUCCESS, rc);
+
+ printf("==> Finished setup.\n");
}
static void teardownFm(void) {
+ printf("==> Starting teardown.\n");
int rc = 0;
rc = bundleContext_ungetService(context, scopeServiceRef, NULL);
@@ -262,7 +264,6 @@ extern "C" {
framework = NULL;
}
-
/// \TEST_CASE_ID{1}
/// \TEST_CASE_TITLE{Test register scope service}
/// \TEST_CASE_REQ{REQ-1}
@@ -661,7 +662,6 @@ extern "C" {
printf("End: %s\n", __func__);
}
-
}
TEST_GROUP(topology_manager_scoped_export) {
diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt
index 5df35a2..8f937e9 100644
--- a/libs/CMakeLists.txt
+++ b/libs/CMakeLists.txt
@@ -28,4 +28,4 @@ add_subdirectory(launcher)
#add_subdirectory(event_admin)# event_admin is unstable
add_subdirectory(dependency_manager)
-add_subdirectory(dependency_manager_cxx)
\ No newline at end of file
+add_subdirectory(dependency_manager_cxx)
diff --git a/libs/dfi/CMakeLists.txt b/libs/dfi/CMakeLists.txt
index 4bf33f0..6b32a54 100644
--- a/libs/dfi/CMakeLists.txt
+++ b/libs/dfi/CMakeLists.txt
@@ -20,9 +20,13 @@ find_package(Jansson REQUIRED)
set(SOURCES
src/dyn_common.c
+ src/dyn_type_common.c
src/dyn_type.c
+ src/dyn_avpr_type.c
src/dyn_function.c
+ src/dyn_avpr_function.c
src/dyn_interface.c
+ src/dyn_avpr_interface.c
src/dyn_message.c
src/json_serializer.c
src/json_rpc.c
@@ -31,8 +35,8 @@ set(SOURCES
add_library(dfi SHARED ${SOURCES})
set_target_properties(dfi PROPERTIES OUTPUT_NAME "celix_dfi")
target_include_directories(dfi PUBLIC
- $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
- $<INSTALL_INTERFACE:include/celix/dfi>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
+ $<INSTALL_INTERFACE:include/celix/dfi>
)
target_include_directories(dfi SYSTEM PRIVATE
@@ -52,21 +56,24 @@ add_library(Celix::dfi ALIAS dfi)
if (ENABLE_TESTING)
find_package(CppUTest REQUIRED)
-
- include_directories(${CPPUTEST_INCLUDE_DIR})
add_executable(test_dfi
- test/dyn_type_tests.cpp
- test/dyn_function_tests.cpp
- test/dyn_closure_tests.cpp
- test/dyn_interface_tests.cpp
- test/dyn_message_tests.cpp
- test/json_serializer_tests.cpp
- test/json_rpc_tests.cpp
+ test/dyn_avpr_tests.cpp
+ test/dyn_type_tests.cpp
+ test/dyn_function_tests.cpp
+ test/dyn_closure_tests.cpp
+ test/dyn_avpr_function_tests.cpp
+ test/dyn_interface_tests.cpp
+ test/dyn_avpr_interface_tests.cpp
+ test/dyn_message_tests.cpp
+ test/json_serializer_tests.cpp
+ test/json_rpc_tests.cpp
+ test/json_rpc_avpr_tests.cpp
test/run_tests.cpp
)
- target_link_libraries(test_dfi PRIVATE Celix::dfi Celix::utils ffi::lib ${CPPUTEST_LIBRARY})
- target_include_directories(test_dfi PRIVATE ffi::lib)
+
+ target_link_libraries(test_dfi PRIVATE Celix::dfi Celix::utils ffi::lib ${JANSSON_LIBRARY} ${CPPUTEST_LIBRARIES})
+ target_include_directories(test_dfi PRIVATE ${JANSSON_INCLUDE_DIRS})
file(COPY ${CMAKE_CURRENT_LIST_DIR}/test/schemas DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
file(COPY ${CMAKE_CURRENT_LIST_DIR}/test/descriptors DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/libs/dfi/include/dyn_function.h b/libs/dfi/include/dyn_function.h
index a73c941..b7f9a7e 100644
--- a/libs/dfi/include/dyn_function.h
+++ b/libs/dfi/include/dyn_function.h
@@ -35,6 +35,7 @@
typedef struct _dyn_function_type dyn_function_type;
DFI_SETUP_LOG_HEADER(dynFunction);
+DFI_SETUP_LOG_HEADER(dynAvprFunction);
enum dyn_function_argument_meta {
DYN_FUNCTION_ARGUMENT_META__STD = 0,
@@ -57,4 +58,8 @@ int dynFunction_call(dyn_function_type *dynFunc, void(*fn)(void), void *returnVa
int dynFunction_createClosure(dyn_function_type *func, void (*bind)(void *, void **, void*), void *userData, void(**fn)(void));
int dynFunction_getFnPointer(dyn_function_type *func, void (**fn)(void));
+// Avpr parsing
+dyn_function_type * dynFunction_parseAvprWithStr(const char * avpr, const char * fqn);
+dyn_function_type * dynFunction_parseAvpr(FILE * avprStream, const char * fqn);
+
#endif
diff --git a/libs/dfi/include/dyn_function_common.h b/libs/dfi/include/dyn_function_common.h
new file mode 100644
index 0000000..8ec705a
--- /dev/null
+++ b/libs/dfi/include/dyn_function_common.h
@@ -0,0 +1,55 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#ifndef _DYN_FUNCTION_COMMON_H_
+#define _DYN_FUNCTION_COMMON_H_
+
+#include "dyn_function.h"
+
+#include <strings.h>
+#include <stdlib.h>
+#include <ffi.h>
+
+#include "dyn_common.h"
+
+struct _dyn_function_type {
+ char *name;
+ struct types_head *refTypes; //NOTE not owned
+ TAILQ_HEAD(,_dyn_function_argument_type) arguments;
+ ffi_type **ffiArguments;
+ dyn_type *funcReturn;
+ ffi_cif cif;
+
+ //closure part
+ ffi_closure *ffiClosure;
+ void (*fn)(void);
+ void *userData;
+ void (*bind)(void *userData, void *args[], void *ret);
+};
+
+typedef struct _dyn_function_argument_type dyn_function_argument_type;
+struct _dyn_function_argument_type {
+ int index;
+ char *name;
+ enum dyn_function_argument_meta argumentMeta;
+ dyn_type *type;
+ TAILQ_ENTRY(_dyn_function_argument_type) entries;
+};
+
+#endif
diff --git a/libs/dfi/include/dyn_interface.h b/libs/dfi/include/dyn_interface.h
index 54bf41c..0aa7e79 100644
--- a/libs/dfi/include/dyn_interface.h
+++ b/libs/dfi/include/dyn_interface.h
@@ -27,6 +27,7 @@
#include "version.h"
DFI_SETUP_LOG_HEADER(dynInterface);
+DFI_SETUP_LOG_HEADER(dynAvprInterface);
/* Description string
*
@@ -62,5 +63,8 @@ int dynInterface_getAnnotationEntry(dyn_interface_type *intf, const char *name,
int dynInterface_methods(dyn_interface_type *intf, struct methods_head **list);
int dynInterface_nrOfMethods(dyn_interface_type *intf);
+// Avpr parsing
+dyn_interface_type * dynInterface_parseAvprWithStr(const char * avpr);
+dyn_interface_type * dynInterface_parseAvpr(FILE * avprStream);
#endif
diff --git a/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.h b/libs/dfi/include/dyn_interface_common.h
similarity index 68%
copy from bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.h
copy to libs/dfi/include/dyn_interface_common.h
index cec8aa1..20b9b6d 100644
--- a/bundles/remote_services/remote_service_admin_dfi/src/dfi_utils.h
+++ b/libs/dfi/include/dyn_interface_common.h
@@ -16,15 +16,24 @@
*specific language governing permissions and limitations
*under the License.
*/
-#ifndef DFI_UTILS_H_
-#define DFI_UTILS_H_
-#include "bundle.h"
-#include "bundle_context.h"
-#include <stdio.h>
-#include "celix_errno.h"
+#ifndef _DYN_INTERFACE_COMMON_H_
+#define _DYN_INTERFACE_COMMON_H_
+#include "dyn_interface.h"
-celix_status_t dfi_findDescriptor(bundle_context_pt context, bundle_pt bundle, const char *name, FILE **out);
+#include <strings.h>
+#include <stdlib.h>
+#include <ffi.h>
+
+#include "dyn_common.h"
+
+struct _dyn_interface_type {
+ struct namvals_head header;
+ struct namvals_head annotations;
+ struct types_head types;
+ struct methods_head methods;
+ version_pt version;
+};
#endif
diff --git a/libs/dfi/include/dyn_message.h b/libs/dfi/include/dyn_message.h
index d1c8dd7..8a75a73 100644
--- a/libs/dfi/include/dyn_message.h
+++ b/libs/dfi/include/dyn_message.h
@@ -51,6 +51,8 @@ int dynMessage_getHeaderEntry(dyn_message_type *msg, const char *name, char **va
int dynMessage_getAnnotationEntry(dyn_message_type *msg, const char *name, char **value);
int dynMessage_getMessageType(dyn_message_type *msg, dyn_type **type);
-
+// avpr parsing
+dyn_message_type * dynMessage_parseAvpr(FILE *avprDescriptorStream, const char *fqn);
+dyn_message_type * dynMessage_parseAvprWithStr(const char *avprDescriptor, const char *fqn);
#endif
diff --git a/libs/dfi/include/dyn_type.h b/libs/dfi/include/dyn_type.h
index 554966a..e17db20 100644
--- a/libs/dfi/include/dyn_type.h
+++ b/libs/dfi/include/dyn_type.h
@@ -58,6 +58,10 @@
* P untyped pointer (void *)
* t char* string
* N native int
+ * E enum (int) + meta infos #EnumName=#EnumValue (e.g. #e1=v1;#e2=v2;E)
+ *
+ * < Array //TODO
+ * <(size)[Type] //TODO
*
* ComplexTypes (Struct)
* {[Type]+ [(Name)(SPACE)]+}
@@ -71,6 +75,7 @@
* TypeDef
* T(Name)=Type;
*
+ * #OMG style sequence. Struct with uint32_t cap, uint32_t len and a <itemtype> buf[] fields.
* SequenceType
* [(Type)
*
@@ -112,8 +117,16 @@ struct complex_type_entry {
TAILQ_ENTRY(complex_type_entry) entries;
};
+TAILQ_HEAD(meta_properties_head, meta_entry);
+struct meta_entry {
+ char *name;
+ char *value;
+ TAILQ_ENTRY(meta_entry) entries;
+};
+
//logging
DFI_SETUP_LOG_HEADER(dynType);
+DFI_SETUP_LOG_HEADER(dynAvprType);
//generic
int dynType_parse(FILE *descriptorStream, const char *name, struct types_head *refTypes, dyn_type **type);
@@ -128,6 +141,8 @@ size_t dynType_size(dyn_type *type);
int dynType_type(dyn_type *type);
int dynType_descriptorType(dyn_type *type);
const char * dynType_getMetaInfo(dyn_type *type, const char *name);
+int dynType_metaEntries(dyn_type *type, struct meta_properties_head **entries);
+const char * dynType_getName(dyn_type *type);
//complexType
int dynType_complex_indexForName(dyn_type *type, const char *name);
@@ -152,4 +167,8 @@ int dynType_text_allocAndInit(dyn_type *type, void *textLoc, const char *value);
//simple
void dynType_simple_setValue(dyn_type *type, void *inst, void *in);
+// avpr parsing
+dyn_type * dynType_parseAvpr(FILE *avprStream, const char *fqn);
+dyn_type * dynType_parseAvprWithStr(const char *avpr, const char *fqn);
+
#endif
diff --git a/libs/dfi/include/dyn_type_common.h b/libs/dfi/include/dyn_type_common.h
new file mode 100644
index 0000000..e19a172
--- /dev/null
+++ b/libs/dfi/include/dyn_type_common.h
@@ -0,0 +1,64 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#ifndef _DYN_TYPE_COMMON_H_
+#define _DYN_TYPE_COMMON_H_
+
+#include "dyn_common.h"
+#include "dyn_type.h"
+
+#include <ffi.h>
+
+#include "dfi_log_util.h"
+
+DFI_SETUP_LOG_HEADER(dynTypeCommon);
+
+struct _dyn_type {
+ char *name;
+ char descriptor;
+ int type;
+ ffi_type *ffiType;
+ dyn_type *parent;
+ struct types_head *referenceTypes; //NOTE: not owned
+ struct types_head nestedTypesHead;
+ struct meta_properties_head metaProperties;
+ union {
+ struct {
+ struct complex_type_entries_head entriesHead;
+ ffi_type structType; //dyn_type.ffiType points to this
+ dyn_type **types; //based on entriesHead for fast access
+ } complex;
+ struct {
+ ffi_type seqType; //dyn_type.ffiType points to this
+ dyn_type *itemType;
+ } sequence;
+ struct {
+ dyn_type *typedType;
+ } typedPointer;
+ struct {
+ dyn_type *ref;
+ } ref;
+ };
+};
+
+dyn_type * dynType_findType(dyn_type *type, char *name);
+ffi_type * dynType_ffiType(dyn_type * type);
+void dynType_prepCif(ffi_type *type);
+
+#endif
diff --git a/libs/dfi/src/dyn_avpr_function.c b/libs/dfi/src/dyn_avpr_function.c
new file mode 100644
index 0000000..5ce62cb
--- /dev/null
+++ b/libs/dfi/src/dyn_avpr_function.c
@@ -0,0 +1,352 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include "dyn_function.h"
+#include "dyn_function_common.h"
+
+#include "jansson.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dyn_common.h"
+#include "dyn_type.h"
+
+DFI_SETUP_LOG(dynAvprFunction)
+
+#define FQN_SIZE 256
+#define ARG_SIZE 32
+
+// Section: static function declarations
+dyn_function_type * dynAvprFunction_parseFromJson(json_t * const root, const char * fqn);
+static json_t const * const dynAvprFunction_findFunc(const char * fqn, json_t * const messagesObject, const char * parentNamespace);
+static bool dynAvprFunction_parseFunc(dyn_function_type * func, json_t const * const jsonFuncObject, json_t * const root, const char * fqn, const char * parentNamespace);
+inline static bool dynAvprFunction_parseArgument(dyn_function_type * func, size_t index, json_t const * entry, json_t * const root, const char * namespace, char * argBuffer, char * typeBuffer);
+inline static bool dynAvprFunction_parseReturn(dyn_function_type * func, size_t index, json_t const * const response_type, json_t * const root, const char * namespace, char * typeBuffer);
+inline static bool dynAvprFunction_createHandle(dyn_function_type * func);
+inline static dyn_function_argument_type * dynAvprFunction_prepareArgumentEntry(const char * name);
+inline static dyn_type * dynAvprFunction_createVoidType();
+inline static dyn_type * dynAvprFunction_createNativeType();
+inline static bool dynAvprFunction_initCif(dyn_function_type * func, size_t nofArguments);
+
+// Section: extern function definitions
+ffi_type * dynType_ffiType(dyn_type *type);
+dyn_type * dynAvprType_parseFromJson(json_t * const root, const char * fqn);
+dyn_type * dynAvprType_createNestedForFunction(dyn_type * store_type, const char* fqn);
+dyn_type * dynAvprType_parseFromTypedJson(json_t * const root, json_t const * const type_entry, const char * namespace);
+void dynAvprType_constructFqn(char* destination, int size, const char * possibleFqn, const char * ns);
+
+// Section: function definitions
+dyn_function_type * dynFunction_parseAvpr(FILE * avprStream, const char * fqn) {
+ json_error_t error;
+ json_t *root = json_loadf(avprStream, JSON_REJECT_DUPLICATES, &error);
+ if (!root) {
+ LOG_ERROR("function_parseAvpr: Error decoding json: line %d: %s", error.line, error.text);
+ return NULL;
+ }
+
+ dyn_function_type * func = dynAvprFunction_parseFromJson(root, fqn);
+ json_decref(root);
+ return func;
+}
+
+dyn_function_type * dynFunction_parseAvprWithStr(const char * avpr, const char * fqn) {
+ FILE *avprStream = fmemopen((char*)avpr, strlen(avpr), "r");
+
+ if (!avprStream) {
+ LOG_ERROR("function_parseAvprWithStr: Error creating mem stream for descriptor string. %s", strerror(errno));
+ return NULL;
+ }
+
+ dyn_function_type *returnValue = dynFunction_parseAvpr(avprStream, fqn);
+ fclose(avprStream);
+ return returnValue;
+}
+
+dyn_function_type * dynAvprFunction_parseFromJson(json_t * const root, const char * fqn) {
+ bool valid = true;
+ dyn_function_type *func = calloc(1, sizeof(*func));
+
+ if (!json_is_object(root)) {
+ LOG_ERROR("ParseFunction: Error decoding json, root should be an object");
+ valid = false;
+ }
+
+ // Get base namespace
+ const char *parentNamespace = json_string_value(json_object_get(root, "namespace"));
+ if (valid && !parentNamespace) {
+ LOG_ERROR("ParseFunction: No namespace found in root, or it is null!");
+ valid = false;
+ }
+
+ // Get messages array
+ json_t * const messagesObject = json_object_get(root, "messages");
+ if (valid && !json_is_object(messagesObject)) {
+ LOG_ERROR("ParseFunction: No messages, or it is not an object");
+ valid = false;
+ }
+
+ if (valid && !dynAvprFunction_parseFunc(func, dynAvprFunction_findFunc(fqn, messagesObject, parentNamespace), root, fqn, parentNamespace)) {
+ LOG_ERROR("parseAvpr: Destroying incorrect result");
+ dynFunction_destroy(func);
+ func = NULL;
+ }
+ else {
+ LOG_DEBUG("ParseFunction: Succesfully parsed \"%s\"", fqn)
+ }
+
+ return func;
+}
+
+static json_t const * const dynAvprFunction_findFunc(const char * fqn, json_t * const messagesObject, const char * parentNamespace) {
+ char nameBuffer[FQN_SIZE];
+ const char * func_name;
+ json_t const * func_entry;
+ json_t const * local_ns;
+ json_object_foreach(messagesObject, func_name, func_entry) {
+ local_ns = json_object_get(func_entry, "namespace");
+ dynAvprType_constructFqn(nameBuffer, FQN_SIZE, func_name, json_is_string(local_ns) ? json_string_value(local_ns) : parentNamespace);
+
+ LOG_DEBUG("FindFunc: Comparing: %s and %s", fqn, nameBuffer);
+ if (strcmp(nameBuffer, fqn) == 0) {
+ LOG_DEBUG("FindFunc: Found function definition for %s", fqn);
+ return func_entry;
+ }
+ }
+ LOG_INFO("FindFunc: Did not find function definition for %s", fqn);
+ return NULL;
+}
+
+static bool dynAvprFunction_parseFunc(dyn_function_type * func, json_t const * const jsonFuncObject, json_t * const root, const char * fqn, const char * parentNamespace) {
+ if (!jsonFuncObject) {
+ LOG_WARNING("ParseFunc: Received NULL, function not found, nothing to parse");
+ return false;
+ }
+
+ func->name = strdup(fqn);
+ if (!func->name) {
+ LOG_ERROR("ParseFunc: Error allocating memory for function name %s", fqn);
+ return false;
+ }
+
+ json_t const * const argument_list = json_object_get(jsonFuncObject, "request");
+ if (!json_is_array(argument_list)) {
+ LOG_ERROR("ParseFunc: Request is not an array");
+ free(func->name);
+ return false;
+ }
+
+ json_t const * const json_function_namespace = json_object_get(jsonFuncObject, "namespace");
+ const char* function_namespace = json_is_string(json_function_namespace) ? json_string_value(json_function_namespace) : parentNamespace;
+
+ // Parse requests argument array
+ TAILQ_INIT(&func->arguments);
+ if (!dynAvprFunction_createHandle(func)) {
+ LOG_ERROR("ParseFunc: Could not creat handle for %s", fqn);
+ free(func->name);
+ return false;
+ }
+ char argBuffer[ARG_SIZE];
+ char typeBuffer[FQN_SIZE];
+ size_t index;
+ json_t const * arg_entry;
+ json_array_foreach(argument_list, index, arg_entry) {
+ if (!dynAvprFunction_parseArgument(func, index+1, arg_entry, root, function_namespace, argBuffer, typeBuffer)) { /* Offset index to account for the handle */
+ LOG_ERROR("ParseFunc: Could not parse argument %d for %s", index, fqn);
+ return false;
+ }
+ LOG_DEBUG("Added argument %d", index+1);
+ }
+ index++;
+
+ json_t const * const response_type = json_object_get(jsonFuncObject, "response");
+ if (!dynAvprFunction_parseReturn(func, index, response_type, root, function_namespace, typeBuffer)) {
+ LOG_ERROR("ParseFunc: Could not parse return type for %s", fqn);
+ free(func->name);
+ return false;
+ }
+ index+=1;
+
+ func->funcReturn = dynAvprFunction_createNativeType();
+ if (!func->funcReturn) {
+ LOG_ERROR("ParseFunc: Could not create error indicator for %s", fqn);
+ return false;
+ }
+
+ if (!dynAvprFunction_initCif(func, index)) {
+ LOG_ERROR("ParseFunc: Could not prepare cif information");
+ return false;
+ }
+
+ // Everything successfull
+ return true;
+}
+
+inline static bool dynAvprFunction_parseArgument(dyn_function_type * func, size_t index, json_t const * entry, json_t * const root, const char * namespace, char * argBuffer, char * typeBuffer) {
+ const char * entry_name = json_string_value(json_object_get(entry, "name"));
+ if (!entry_name) {
+ LOG_INFO("ParseArgument: Could not find argument name for %d, using default", index);
+ snprintf(argBuffer, ARG_SIZE, "arg%04lu", index);
+ entry_name = argBuffer;
+ }
+
+ dyn_type * entry_dyn_type = dynAvprType_parseFromTypedJson(root, json_object_get(entry, "type"), namespace);
+ if (!entry_dyn_type) {
+ LOG_ERROR("ParseArgument: Could not parse type for argument");
+ return false;
+ }
+
+ if (json_is_true(json_object_get(entry, "ptr"))) {
+ entry_dyn_type = dynAvprType_createNestedForFunction(entry_dyn_type, entry_name);
+ if (!entry_dyn_type) {
+ LOG_ERROR("ParseArgument: Could not create pointer argument for %s", entry_name);
+ dynType_destroy(entry_dyn_type);
+ return false;
+ }
+ }
+
+ dyn_function_argument_type *arg = dynAvprFunction_prepareArgumentEntry(entry_name);
+ if (!arg) {
+ dynType_destroy(entry_dyn_type);
+ return false;
+ }
+
+ arg->index = index;
+ arg->type = entry_dyn_type;
+ arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__STD;
+
+ TAILQ_INSERT_TAIL(&func->arguments, arg, entries);
+ return true;
+}
+
+inline static bool dynAvprFunction_parseReturn(dyn_function_type * func, size_t index, json_t const * const response_type, json_t * const root, const char * namespace, char * typeBuffer) {
+ dyn_type * return_dyn_type = dynAvprType_parseFromTypedJson(root, response_type, namespace);
+ if (!return_dyn_type) {
+ LOG_ERROR("ParseReturn: Could not parse return argument");
+ return false;
+ }
+
+ dyn_type * out_dyn_type = dynAvprType_createNestedForFunction(return_dyn_type, "out");
+ if (!out_dyn_type) {
+ LOG_ERROR("ParseReturn: Could not create pointer for return type");
+ dynType_destroy(return_dyn_type);
+ return false;
+ }
+
+ dyn_function_argument_type *arg = dynAvprFunction_prepareArgumentEntry("out");
+ if (!arg) {
+ LOG_ERROR("ParseReturn: Could not create nested type for return type");
+ dynType_destroy(out_dyn_type);
+ return false;
+ }
+
+ arg->index = index;
+
+ // Check descriptor type, if it is a struct ({), sequence ([) or a string (t) an extra level of indirection is needed
+ int descriptor = dynType_descriptorType(return_dyn_type);
+ if (descriptor == '{' || descriptor == '[') {
+ out_dyn_type = dynAvprType_createNestedForFunction(out_dyn_type, "out");
+ if (!out_dyn_type) {
+ LOG_ERROR("ParseReturn: Could not create nested type for return complex type");
+ dynType_destroy(out_dyn_type);
+ return false;
+ }
+ arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__OUTPUT;
+ }
+ else {
+ arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__PRE_ALLOCATED_OUTPUT;
+ }
+
+ arg->type = out_dyn_type;
+ TAILQ_INSERT_TAIL(&func->arguments, arg, entries);
+ return true;
+}
+
+inline static bool dynAvprFunction_createHandle(dyn_function_type * func) {
+ dyn_function_argument_type * arg = dynAvprFunction_prepareArgumentEntry("handle");
+ if (!arg) {
+ return false;
+ }
+
+ arg->index = 0;
+ arg->type = dynAvprFunction_createVoidType();
+ if (!arg->type) {
+ free(arg);
+ return false;
+ }
+
+ arg->argumentMeta = DYN_FUNCTION_ARGUMENT_META__HANDLE;
+ TAILQ_INSERT_TAIL(&func->arguments, arg, entries);
+ return true;
+}
+
+inline static dyn_function_argument_type * dynAvprFunction_prepareArgumentEntry(const char * name) {
+ if (!name) {
+ LOG_ERROR("PrepareArgumentEntry: Need name to create argument entry");
+ return NULL;
+ }
+
+ dyn_function_argument_type *arg = calloc(1, sizeof(*arg));
+ arg->name = strndup(name, ARG_SIZE);
+ return arg;
+}
+
+inline static dyn_type * dynAvprFunction_createVoidType() {
+ const char * entry = "{ \
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"dummy\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"VoidPtr\", \
+ \"alias\" : \"void_ptr\", \
+ \"size\" : 4 \
+ } ] ,\
+ \"messages\" : { }\
+ }";
+ return dynType_parseAvprWithStr(entry, "dummy.VoidPtr");
+}
+
+inline static dyn_type * dynAvprFunction_createNativeType() {
+ const char * entry = "{ \
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"dummy\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"NativeInt\", \
+ \"alias\" : \"native_int\", \
+ \"size\" : 4 \
+ } ] ,\
+ \"messages\" : { }\
+ }";
+ return dynType_parseAvprWithStr(entry, "dummy.NativeInt");
+}
+
+inline static bool dynAvprFunction_initCif(dyn_function_type * func, size_t nofArguments) {
+ func->ffiArguments = calloc(nofArguments, sizeof(ffi_type*));
+ dyn_function_argument_type *entry = NULL;
+ TAILQ_FOREACH(entry, &func->arguments, entries) {
+ func->ffiArguments[entry->index] = dynType_ffiType(entry->type);
+ }
+
+ ffi_type *returnType = dynType_ffiType(func->funcReturn);
+ int ffi_result = ffi_prep_cif(&func->cif, FFI_DEFAULT_ABI, nofArguments, returnType, func->ffiArguments);
+
+ return ffi_result == FFI_OK;
+}
+
diff --git a/libs/dfi/src/dyn_avpr_interface.c b/libs/dfi/src/dyn_avpr_interface.c
new file mode 100644
index 0000000..1424d30
--- /dev/null
+++ b/libs/dfi/src/dyn_avpr_interface.c
@@ -0,0 +1,290 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include "dyn_interface.h"
+#include "dyn_interface_common.h"
+
+#include "jansson.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "dyn_common.h"
+#include "dyn_type.h"
+#include "dyn_function.h"
+
+DFI_SETUP_LOG(dynAvprInterface)
+
+#define STR_LENGTH 1024
+#define FQN_SIZE 256
+#define ARG_SIZE 32
+
+// Section: function definitions
+inline static dyn_interface_type * dynAvprInterface_initializeInterface();
+inline static bool dynAvprInterface_createHeader(dyn_interface_type* intf, json_t * const root);
+inline static bool dynAvprInterface_createAnnotations(dyn_interface_type* intf, json_t * const root);
+inline static bool dynAvprInterface_createTypes(dyn_interface_type* intf, json_t * const root, const char* parent_ns);
+inline static bool dynAvprInterface_createMethods(dyn_interface_type* intf, json_t * const root, const char* parent_ns);
+static bool dynAvprInterface_insertNamValEntry(struct namvals_head *head, const char* name, const char* value);
+static struct namval_entry * dynAvprInterface_createNamValEntry(const char* name, const char* value);
+
+// Section: extern function definitions
+ffi_type * dynType_ffiType(dyn_type *type);
+dyn_type * dynAvprType_parseFromJson(json_t * const root, const char * fqn);
+dyn_function_type * dynAvprFunction_parseFromJson(json_t * const root, const char * fqn);
+int dynInterface_checkInterface(dyn_interface_type *intf);
+void dynAvprType_constructFqn(char * destination, int size, const char * possibleFqn, const char * ns);
+
+// Function definitions
+dyn_interface_type * dynInterface_parseAvprWithStr(const char * avpr) {
+ FILE *avprStream = fmemopen((char*)avpr, strlen(avpr), "r");
+
+ if (!avprStream) {
+ LOG_ERROR("interface_parseAvprWithStr: Error creating mem stream for descriptor string. %s", strerror(errno));
+ return NULL;
+ }
+
+ dyn_interface_type *returnValue = dynInterface_parseAvpr(avprStream);
+ fclose(avprStream);
+ return returnValue;
+}
+
+dyn_interface_type * dynInterface_parseAvpr(FILE * avprStream) {
+ dyn_interface_type *intf = NULL;
+ bool valid = true;
+ json_error_t error;
+ json_t *root = json_loadf(avprStream, JSON_REJECT_DUPLICATES, &error);
+ if (!root) {
+ LOG_ERROR("interface_parseAvpr: Error decoding json: line %d: %s", error.line, error.text);
+ valid = false;
+ }
+
+ if (valid && !json_is_object(root)) {
+ LOG_ERROR("interface_parseAvpr: Error decoding json, root should be an object");
+ valid = false;
+ }
+
+ const char *parent_ns = json_string_value(json_object_get(root, "namespace"));
+ if (valid && !parent_ns) {
+ LOG_ERROR("interface_parseAvpr: No namespace found in root, or it is null!");
+ valid = false;
+ }
+
+ json_t * const messagesObject = json_object_get(root, "messages");
+ if (valid && !json_is_object(messagesObject)) {
+ LOG_ERROR("interface_parseAvpr: No messages, or it is not an object");
+ valid = false;
+ }
+
+ if (valid) {
+ intf = dynAvprInterface_initializeInterface();
+ valid = intf != NULL;
+ }
+
+ valid = valid && dynAvprInterface_createHeader(intf, root);
+ valid = valid && dynAvprInterface_createAnnotations(intf, root);
+ valid = valid && dynAvprInterface_createTypes(intf, root, parent_ns);
+ valid = valid && dynAvprInterface_createMethods(intf, root, parent_ns);
+
+ valid = valid && 0 == dynInterface_checkInterface(intf);
+
+ json_decref(root);
+ if (valid) {
+ LOG_DEBUG("Parsing of avpr interface successful");
+ return intf;
+ }
+ else {
+ LOG_ERROR("Parsing of avpr interface failed");
+ dynInterface_destroy(intf);
+ return NULL;
+ }
+}
+
+inline static dyn_interface_type * dynAvprInterface_initializeInterface() {
+ dyn_interface_type *intf = calloc(1, sizeof(*intf));
+
+ TAILQ_INIT(&intf->header);
+ TAILQ_INIT(&intf->annotations);
+ TAILQ_INIT(&intf->types);
+ TAILQ_INIT(&intf->methods);
+
+ return intf;
+}
+
+inline static bool dynAvprInterface_createHeader(dyn_interface_type* intf, json_t * const root) {
+ // type
+ if (!dynAvprInterface_insertNamValEntry(&intf->header, "type", "interface")) {
+ return false;
+ }
+
+ // name (protocol in avpr-speak)
+ if (!dynAvprInterface_insertNamValEntry(&intf->header, "name", json_string_value(json_object_get(root, "protocol")))) {
+ return false;
+ }
+
+ // version
+ if (!dynAvprInterface_insertNamValEntry(&intf->header, "version", json_string_value(json_object_get(root, "version")))) {
+ return false;
+ }
+
+ // Also parse version in the intf->version for cel
+ char* version = NULL;
+ dynInterface_getVersionString(intf, &version);
+ if (!version) {
+ LOG_ERROR("No version string in header");
+ return false;
+ }
+
+ if (CELIX_SUCCESS != version_createVersionFromString(version, &(intf->version))) {
+ LOG_ERROR("Invalid version (%s) in parsed descriptor\n", version);
+ return false;
+ }
+
+ return true;
+}
+
+inline static bool dynAvprInterface_createAnnotations(dyn_interface_type* intf, json_t * const root) {
+ // namespace
+ if (!dynAvprInterface_insertNamValEntry(&intf->annotations, "namespace", json_string_value(json_object_get(root, "namespace")))) {
+ return false;
+ }
+
+ // TODO: other annotations?
+
+ return true;
+}
+
+inline static bool dynAvprInterface_createTypes(dyn_interface_type* intf, json_t * const root, const char* parent_ns) {
+ json_t const * const types_array = json_object_get(root, "types");
+ if (!types_array || !json_is_array(types_array)) {
+ LOG_ERROR("json: types is not an array or it does not exists!");
+ return false;
+ }
+
+ char name_buffer[FQN_SIZE];
+ json_t const * entry;
+ json_t const * local_ns;
+ char const * name;
+ size_t index;
+ struct type_entry *t_entry = NULL;
+ json_array_foreach(types_array, index, entry) {
+ local_ns = json_object_get(entry, "namespace");
+ name = json_string_value(json_object_get(entry, "name"));
+ if (!name) {
+ LOG_ERROR("Type entry %llu has no name", index);
+ return false;
+ }
+ dynAvprType_constructFqn(name_buffer, FQN_SIZE, name, json_is_string(local_ns) ? json_string_value(local_ns) : parent_ns);
+
+ t_entry = calloc(1, sizeof(*t_entry));
+ t_entry->type = dynAvprType_parseFromJson(root, name_buffer);
+ if (!t_entry->type) {
+ free(t_entry);
+ return false;
+ }
+
+ TAILQ_INSERT_TAIL(&intf->types, t_entry, entries);
+ }
+
+ return true;
+}
+
+inline static bool dynAvprInterface_createMethods(dyn_interface_type* intf, json_t * const root, const char* parent_ns) {
+ json_t * const messages_object = json_object_get(root, "messages");
+ if (!messages_object || !json_is_object(messages_object)) {
+ LOG_ERROR("json: messages is not an object or it does not exist!");
+ return false;
+ }
+
+ char name_buffer[FQN_SIZE];
+ json_t const * func_entry;
+ json_t const * local_ns;
+ json_t const * j_index;
+ char const * func_name;
+ struct method_entry *m_entry = NULL;
+ json_object_foreach(messages_object, func_name, func_entry) {
+ local_ns = json_object_get(func_entry, "namespace");
+ dynAvprType_constructFqn(name_buffer, FQN_SIZE, func_name, json_is_string(local_ns) ? json_string_value(local_ns) : parent_ns);
+
+ m_entry = calloc(1, sizeof(*m_entry));
+ m_entry->dynFunc = dynAvprFunction_parseFromJson(root, name_buffer);
+ if (!m_entry->dynFunc) {
+ free(m_entry);
+ return false;
+ }
+
+ j_index = json_object_get(func_entry, "index");
+ if (!json_is_integer(j_index)) {
+ LOG_ERROR("For parsing an interface annotate all functions with an integer index");
+ dynFunction_destroy(m_entry->dynFunc);
+ free(m_entry);
+ return false;
+ }
+
+ m_entry->index = json_integer_value(j_index);
+ m_entry->id = strndup(func_name, STR_LENGTH);
+ if (!m_entry->id) {
+ LOG_ERROR("Could not allocate memory for method entry name %s", func_name);
+ dynFunction_destroy(m_entry->dynFunc);
+ free(m_entry);
+ return false;
+ }
+
+ m_entry->name = strndup(func_name, STR_LENGTH); // For avpr these are the same
+ if (!m_entry->id) {
+ LOG_ERROR("Could not allocate memory for method entry id %s", func_name);
+ dynFunction_destroy(m_entry->dynFunc);
+ free(m_entry);
+ return false;
+ }
+ TAILQ_INSERT_TAIL(&intf->methods, m_entry, entries);
+ }
+
+ // Parsed all methods
+ return true;
+}
+
+static bool dynAvprInterface_insertNamValEntry(struct namvals_head *head, const char* name, const char* value) {
+ struct namval_entry *entry = dynAvprInterface_createNamValEntry(name, value);
+ if (!entry) {
+ return false;
+ }
+ else {
+ TAILQ_INSERT_TAIL(head, entry, entries);
+ return true;
+ }
+}
+
+static struct namval_entry * dynAvprInterface_createNamValEntry(const char* name, const char* value) {
+ if (!name) {
+ LOG_ERROR("Passed null-ptr to name of name-value entry creation function, unknown what type to create");
+ return NULL;
+ }
+
+ if (!value) {
+ LOG_ERROR("Received a name (%s) but no value, did the look-up for a value fail?", name);
+ return NULL;
+ }
+
+ struct namval_entry *entry = calloc(1, sizeof(*entry));
+ entry->name = strndup(name, STR_LENGTH);
+ entry->value = strndup(value, STR_LENGTH);
+ return entry;
+}
+
diff --git a/libs/dfi/src/dyn_avpr_type.c b/libs/dfi/src/dyn_avpr_type.c
new file mode 100644
index 0000000..fccf610
--- /dev/null
+++ b/libs/dfi/src/dyn_avpr_type.c
@@ -0,0 +1,987 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include "dyn_type.h"
+
+#include "jansson.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <ffi.h>
+
+#include "dyn_type.h"
+#include "dyn_type_common.h"
+#include "version.h"
+
+DFI_SETUP_LOG(dynAvprType)
+
+#define STR_LENGTH 1024
+#define FQN_SIZE 256
+
+enum JsonTypeType {INVALID=0, SIMPLE=1, ARRAY=2, REFERENCE=3, SELF_REFERENCE=4};
+
+dyn_type * dynAvprType_parseFromJson(json_t * const root, const char * fqn);
+dyn_type * dynAvprType_createNestedForFunction(dyn_type * store_type, const char* fqn);
+dyn_type * dynAvprType_parseFromTypedJson(json_t * const root, json_t const * const type_entry, const char * namespace);
+void dynAvprType_constructFqn(char* destination, int size, const char* possibleFqn, const char* ns);
+
+// Any
+static json_t const * dynAvprType_findType(char const * const fqn, json_t const * const array_object, const char * ns);
+static dyn_type * dynAvprType_parseAny(dyn_type * root, dyn_type * parent, json_t const * const jsonObject, json_t const * const array_object, const char * parent_ns);
+static dyn_type * dynAvprType_initializeType(dyn_type * parent);
+
+// Record
+static dyn_type * dynAvprType_parseRecord(dyn_type * root, dyn_type * parent, json_t const * const record_obj, json_t const * const array_object, const char* parent_ns, dyn_type * ref_type);
+static inline dyn_type * dynAvprType_prepareRecord(dyn_type * parent, json_t const ** fields, json_t const * const record_obj);
+static inline bool dynAvprType_finalizeRecord(dyn_type * type, const size_t size);
+static inline struct complex_type_entry* dynAvprType_prepareRecordEntry(dyn_type * parent, json_t const * const entry_object);
+static inline struct complex_type_entry * dynAvprType_parseRecordEntry(dyn_type * root, dyn_type * parent, json_t const * const entry_object, json_t const * const array_object, const char * fqn_parent, const char * parent_ns, const char * record_ns, dyn_type * ref_type);
+static inline enum JsonTypeType dynAvprType_getRecordEntryType(json_t const * const entry_object, const char * fqn_parent, char * name_buffer, const char * namespace);
+
+// Reference
+static dyn_type * dynAvprType_parseReference(dyn_type * root, const char * name_buffer, json_t const * const array_object, const char * parent_ns);
+static dyn_type * dynAvprType_parseSelfReference(dyn_type * root, dyn_type * parent, const char * name_buffer, json_t const * const array_object, const char * parent_ns, dyn_type * ref_type);
+static dyn_type * dynAvprType_initializeReferenceType(dyn_type * type_pointer);
+static inline struct type_entry * dynAvprType_prepareNestedEntry(dyn_type * const parent, const char * fqn, bool allocate);
+
+// Enum
+static dyn_type * dynAvprType_parseEnum(dyn_type * parent, json_t const * const enum_obj, const char * parent_ns);
+static inline struct meta_entry * dynAvprType_createMetaEntry(const char* enum_entry_name);
+static inline bool dynAvprType_metaEntrySetValue(struct meta_entry * meta_entry_ptr, json_t const * const values_array, size_t index);
+static inline void dynAvprType_parseEnumValue(char** enumvalue);
+
+// Array
+static dyn_type * dynAvprType_parseArray(dyn_type * root, dyn_type * parent, json_t const * const array_entry_obj, json_t const * const array_object, char * name_buffer, const char * parent_ns, const char * record_ns);
+
+// Fixed
+static dyn_type * dynAvprType_parseFixed(dyn_type * parent, json_t const * const fixed_object, const char * parent_ns);
+static inline int dynAvprType_fixedTypeToFfi(json_t const * const simple_obj, ffi_type ** output_ffi_type);
+
+// General
+static char * dynAvprType_createFqnFromJson(json_t const * const jsonObject, const char * namespace);
+static inline enum JsonTypeType dynAvprType_getType(json_t const * const json_type);
+static inline void dynAvprType_createVersionMetaEntry(dyn_type * type, json_t const * const root, json_t const * const array_object, const char* parent_ns);
+static inline void dynAvprType_createAnnotationEntries(dyn_type * type, json_t const * const array_object, const char* parent_ns);
+
+// fqn = fully qualified name
+dyn_type * dynType_parseAvpr(FILE* avprStream, const char *fqn) {
+ json_error_t error;
+ json_t *root = json_loadf(avprStream, JSON_REJECT_DUPLICATES, &error);
+ if (!root) {
+ LOG_ERROR("parseAvpr: Error decoding json: line %d: %s", error.line, error.text);
+ return NULL;
+ }
+
+ dyn_type * type = dynAvprType_parseFromJson(root, fqn);
+ json_decref(root);
+ return type;
+}
+
+dyn_type * dynType_parseAvprWithStr(const char* avpr, const char *fqn) {
+ FILE *avprStream = fmemopen((char*)avpr, strlen(avpr), "r");
+
+ if (!avprStream) {
+ LOG_ERROR("parseAvprWithStr: Error creating mem stream for descriptor string. %s", strerror(errno));
+ return NULL;
+ }
+
+ dyn_type *returnValue = dynType_parseAvpr(avprStream, fqn);
+ fclose(avprStream);
+ return returnValue;
+}
+
+// Based on the fqn passed in, try to find an entry in the array_object with that name, the current namespace is defined by the parameter ns
+static json_t const * dynAvprType_findType(char const * const fqn, json_t const * const array_object, const char * ns) {
+ char fqn_buffer[FQN_SIZE];
+ size_t index;
+ json_t const * type_entry;
+
+ json_array_foreach(array_object, index, type_entry) {
+ const char* entry_name = json_string_value(json_object_get(type_entry, "name"));
+ if (entry_name) {
+ const char* entry_ns = json_string_value(json_object_get(type_entry, "namespace"));
+ snprintf(fqn_buffer, FQN_SIZE, "%s.%s", entry_ns ? entry_ns : ns, entry_name);
+ if (strcmp(fqn, fqn_buffer) == 0) {
+ return type_entry; // Found
+ }
+ }
+ else {
+ LOG_INFO("FindType: found a type with no name, check your json configuration, skipping this entry for now...");
+ }
+ }
+ return NULL; // Not found
+}
+
+dyn_type * dynAvprType_parseFromJson(json_t * const root, const char * fqn) {
+ // Initialize type
+ bool valid = true;
+ if (!json_is_object(root)) {
+ LOG_ERROR("parseAvpr: Error decoding json, root should be an object");
+ valid = false;
+ }
+
+ // Get base namespace
+ const char *parent_ns = json_string_value(json_object_get(root, "namespace"));
+ if (valid && !parent_ns) {
+ LOG_ERROR("parseAvpr: No namespace found in root, or it is null!");
+ valid = false;
+ }
+
+ // Get types array
+ json_t* typesArrayObject = json_object_get(root, "types");
+ if (valid && !json_is_array(typesArrayObject)) {
+ LOG_ERROR("parseAvpr: types should be an array!");
+ valid = false;
+ }
+
+ // Try to find the fqn and parse if it is found, if any error occurs during parsing, return NULL
+ dyn_type * type = NULL;
+ if (valid) {
+ type = dynAvprType_parseAny(NULL, NULL, dynAvprType_findType(fqn, typesArrayObject, parent_ns), typesArrayObject, parent_ns);
+ valid = type != NULL;
+ }
+
+ // Add version as a meta entry
+ if (valid) {
+ LOG_DEBUG("parseAvpr: Parsing successful, adding version entry and annotations");
+ dynAvprType_createVersionMetaEntry(type, root, typesArrayObject, parent_ns);
+ // Add any other annotation fields that are not in [type, name, fields, version, alias]
+ dynAvprType_createAnnotationEntries(type, typesArrayObject, parent_ns);
+
+ }
+
+ if (valid) {
+ LOG_DEBUG("Found %s", fqn);
+ }
+ else {
+ LOG_ERROR("Not found %s", fqn);
+ }
+
+ return type;
+}
+
+dyn_type * dynAvprType_createNestedForFunction(dyn_type * store_type, const char* fqn) {
+ if (!store_type) {
+ return NULL;
+ }
+
+ // Created dyn_type for reference argument in function
+ dyn_type * entry_ref_type = dynAvprType_initializeType(NULL);
+ if (!entry_ref_type) {
+ dynType_destroy(store_type);
+ return NULL;
+ }
+
+ // Create pointer type and enter type in nested types
+ struct type_entry *entry = dynAvprType_prepareNestedEntry(entry_ref_type, fqn, false);
+ if (!entry) {
+ free(entry_ref_type);
+ return NULL;
+ }
+
+ entry->type = store_type;
+ entry_ref_type->type = DYN_TYPE_TYPED_POINTER;
+ entry_ref_type->descriptor = '*';
+ entry_ref_type->ffiType = &ffi_type_pointer;
+
+ // Create reference type for the sub type
+ dyn_type * sub_type = dynAvprType_initializeType(entry_ref_type);
+ if (!sub_type) {
+ dynType_destroy(store_type);
+ free(entry_ref_type);
+ free(entry);
+ return NULL;
+ }
+
+ entry_ref_type->typedPointer.typedType = sub_type;
+ sub_type->type = DYN_TYPE_REF;
+ sub_type->descriptor = 'l';
+ sub_type->ref.ref = entry->type;
+
+ return entry_ref_type;
+}
+
+// To be used for dyn_function parsing of return and parameter arrays
+dyn_type * dynAvprType_parseFromTypedJson(json_t * const root, json_t const * const type_entry, const char * namespace) {
+ if (!type_entry) {
+ LOG_ERROR("Need a type entry to parse, but got a NULL pointer");
+ return NULL;
+ }
+
+ dyn_type * ret_type = NULL;
+ enum JsonTypeType elType = dynAvprType_getType(type_entry);
+ char name_buffer[FQN_SIZE];
+ switch (elType) {
+ case SIMPLE:
+ dynAvprType_constructFqn(name_buffer, FQN_SIZE, json_string_value(type_entry), namespace);
+ ret_type = dynAvprType_parseFromJson(root, name_buffer);
+ break;
+
+ case ARRAY:
+ ret_type = dynAvprType_parseArray(ret_type, NULL, type_entry, json_object_get(root, "types"), name_buffer, namespace, namespace);
+ if (!ret_type) {
+ LOG_ERROR("Error allocating memory for type");
+ return NULL;
+ }
+ break;
+
+ case INVALID:
+ /* fall through */
+ case REFERENCE:
+ /* fall through */
+ default:
+ LOG_ERROR("ParseFromTypedJson: Received illegal type : %d", elType);
+ break;
+ }
+
+ return ret_type;
+}
+
+void dynAvprType_constructFqn(char* destination, int size, const char* possibleFqn, const char* ns) {
+ const bool isAlreadyFqn = strchr(possibleFqn, '.') != NULL;
+ snprintf(destination, size, "%s%s%s", isAlreadyFqn ? "" : ns, isAlreadyFqn ? "" : ".", possibleFqn);
+}
+
+static dyn_type * dynAvprType_parseAny(dyn_type * root, dyn_type * parent, json_t const * const jsonObject, json_t const * const array_object, const char * parent_ns) {
+ if (!jsonObject) {
+ LOG_WARNING("Any: Received NULL, type not found, nothing to parse");
+ return NULL;
+ }
+
+ const char* type_name = json_string_value(json_object_get(jsonObject, "type"));
+ if (!type_name) {
+ LOG_ERROR("Any: \"type\" entry is not a string or does not exist");
+ return NULL;
+ }
+
+ dyn_type * type = NULL;
+ LOG_DEBUG("Any: Parsing a %s", type_name);
+ if (strcmp(type_name, "record") == 0) {
+ type = dynAvprType_parseRecord(root, parent, jsonObject, array_object, parent_ns, NULL);
+ }
+ else if (strcmp(type_name, "fixed") == 0) {
+ type = dynAvprType_parseFixed(parent, jsonObject, parent_ns);
+ }
+ else if (strcmp(type_name, "enum") == 0) {
+ type = dynAvprType_parseEnum(parent, jsonObject, parent_ns);
+ }
+ else {
+ LOG_ERROR("Any: Unrecognized type: %s", type_name);
+ }
+
+ return type;
+}
+
+static dyn_type * dynAvprType_initializeType(dyn_type * parent) {
+ dyn_type * type = calloc(1, sizeof(*type));
+ TAILQ_INIT(&type->nestedTypesHead);
+ TAILQ_INIT(&type->metaProperties);
+ type->parent = parent;
+ return type;
+}
+
+static dyn_type * dynAvprType_parseRecord(dyn_type * root, dyn_type * parent, json_t const * const record_obj, json_t const * const array_object, const char * parent_ns, dyn_type * ref_type) {
+ json_t const * fields = NULL;
+ dyn_type * type = dynAvprType_prepareRecord(parent, &fields, record_obj); // also sets fields correctly
+ if (!type) {
+ return NULL;
+ }
+
+ // Check if namespace is present, otherwise set it equal to parent
+ const char* record_ns = json_string_value(json_object_get(record_obj, "namespace"));
+ if (!record_ns) {
+ record_ns = parent_ns;
+ }
+
+ // Create namespace + name for storage in type->name (to preserve namespacing)
+ char fqn_buffer[FQN_SIZE];
+ snprintf(fqn_buffer, FQN_SIZE, "%s.%s", record_ns, json_string_value(json_object_get(record_obj, "name")));
+ type->name = strndup(fqn_buffer, STR_LENGTH);
+ if (!type->name) {
+ LOG_ERROR("Record: failed to allocate memory for type->name");
+ dynType_destroy(type);
+ return NULL;
+ }
+
+ // If root is NULL, this is the root type
+ if (!root) {
+ root = type;
+ }
+
+ // Loop over json_fields and parse each entry
+ size_t counter;
+ json_t *element;
+ json_array_foreach(fields, counter, element) {
+ LOG_DEBUG("Record: parsing field [%s](%s) at %d", json_string_value(json_object_get(element, "type")), json_string_value(json_object_get(element, "name")), counter);
+
+ struct complex_type_entry * entry = dynAvprType_parseRecordEntry(root, type, element, array_object, fqn_buffer, parent_ns, record_ns, ref_type);
+ if (!entry) {
+ LOG_ERROR("Record: Parsing record entry %d failed", counter);
+ dynType_destroy(type);
+ return NULL;
+ }
+
+ TAILQ_INSERT_TAIL(&type->complex.entriesHead, entry, entries);
+ }
+
+ return dynAvprType_finalizeRecord(type, counter) ? type : NULL;
+}
+
+// Initializes the type pointer with the correct information for a record (complex type)
+static inline dyn_type * dynAvprType_prepareRecord(dyn_type * parent, json_t const ** fields, json_t const * const record_obj) {
+ const char * name = json_string_value(json_object_get(record_obj, "name"));
+ if (!name) {
+ LOG_ERROR("Record: \"name\" entry is missing");
+ return NULL;
+ }
+
+ *fields = json_object_get(record_obj, "fields");
+ if (!json_is_array(*fields)) {
+ LOG_WARNING("Record: \"fields\" is not an array or does not exist");
+ return NULL;
+ }
+
+ dyn_type * type = dynAvprType_initializeType(parent);
+ if (!type) {
+ return NULL;
+ }
+
+ type->type = DYN_TYPE_COMPLEX;
+ type->descriptor = '{';
+ type->ffiType = &type->complex.structType;
+ type->complex.structType.type = FFI_TYPE_STRUCT;
+ TAILQ_INIT(&type->complex.entriesHead);
+ return type;
+}
+
+// Create the ffi types for quick access and link the dyn_types
+static inline bool dynAvprType_finalizeRecord(dyn_type * type, const size_t size) {
+ type->complex.structType.elements = calloc(size+1, sizeof(ffi_type*));
+ type->complex.structType.elements[size] = NULL;
+ struct complex_type_entry *entry = NULL;
+ int index = 0;
+ TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) {
+ type->complex.structType.elements[index++] = dynType_ffiType(entry->type);
+ }
+
+ // set types for every element for access
+ index = 0;
+ type->complex.types = calloc(size, sizeof(dyn_type*));
+ TAILQ_FOREACH(entry, &type->complex.entriesHead, entries) {
+ type->complex.types[index++] = entry->type;
+ }
+
+ dynType_prepCif(type->ffiType);
+ return true;
+}
+
+static inline struct complex_type_entry * dynAvprType_parseRecordEntry(dyn_type * root, dyn_type * parent, json_t const * const entry_object, json_t const * const array_object, const char * fqn_parent, const char * parent_ns, const char * record_ns, dyn_type * ref_type) {
+ struct complex_type_entry *entry = dynAvprType_prepareRecordEntry(parent, entry_object);
+ if (!entry) {
+ return NULL;
+ }
+
+ char name_buffer[FQN_SIZE];
+ switch (dynAvprType_getRecordEntryType(entry_object, fqn_parent, name_buffer, record_ns)) {
+ case SIMPLE:
+ LOG_DEBUG("RecordEntry: Looking for type: %s", name_buffer);
+ entry->type = dynAvprType_parseAny(root, parent, dynAvprType_findType(name_buffer, array_object, parent_ns), array_object, parent_ns);
+ break;
+
+ case REFERENCE:
+ LOG_DEBUG("RecordEntry: Found a ptr type, creating a reference %s", name_buffer);
+ entry->type = dynAvprType_parseReference(root, name_buffer, array_object, parent_ns);
+ break;
+
+ case SELF_REFERENCE:
+ LOG_DEBUG("RecordEntry: Creating a self_reference for %s", name_buffer);
+ entry->type = dynAvprType_parseSelfReference(root, parent, name_buffer, array_object, parent_ns, ref_type);
+ break;
+
+ case ARRAY:
+ LOG_DEBUG("RecordEntry: Parsing array: %s", name_buffer);
+ entry->type = dynAvprType_parseArray(root, parent, json_object_get(entry_object, "type"), array_object, name_buffer, parent_ns, record_ns);
+ break;
+
+ case INVALID:
+ /* fall through */
+ default:
+ LOG_ERROR("RecordEntry: Illegal record entry for %s", json_string_value(json_object_get(entry_object, "name")));
+ entry->type = NULL;
+ break;
+ }
+
+ if (entry->type) {
+ return entry;
+ }
+ else {
+ free(entry->name);
+ free(entry);
+ return NULL;
+ }
+}
+
+static inline struct complex_type_entry* dynAvprType_prepareRecordEntry(dyn_type * parent, json_t const * const entry_object) {
+ struct complex_type_entry *entry = NULL;
+
+ const char * entry_name = json_string_value(json_object_get(entry_object, "name"));
+ if (!entry_name) {
+ LOG_ERROR("Could not find name in entry");
+ return NULL;
+ }
+
+ entry = calloc(1, sizeof(*entry));
+ entry->name = strndup(entry_name, STR_LENGTH);
+ return entry;
+}
+
+// Returns correct type and sets the fqn in the buffer if it is a simple type (not for array because arrays can be nested
+static inline enum JsonTypeType dynAvprType_getRecordEntryType(json_t const * const entry_object, const char * fqn_parent, char * name_buffer, const char * namespace) {
+ json_t const * const json_type = json_object_get(entry_object, "type");
+ if (!json_type) {
+ LOG_WARNING("RecordEntry: No type entry");
+ return INVALID;
+ }
+
+ enum JsonTypeType elType = dynAvprType_getType(json_type);
+ if (elType == SIMPLE) {
+ dynAvprType_constructFqn(name_buffer, FQN_SIZE, json_string_value(json_type), namespace);
+ if (strcmp(name_buffer, fqn_parent) == 0) {
+ elType = SELF_REFERENCE;
+ } else if (json_is_true(json_object_get(entry_object, "ptr"))) {
+ elType = REFERENCE;
+ }
+ }
+
+ return elType;
+}
+
+static dyn_type * dynAvprType_parseReference(dyn_type * root, const char * name_buffer, json_t const * const array_object, const char * parent_ns) {
+ dyn_type * type = dynAvprType_initializeType(NULL);
+ if (!type) {
+ return NULL;
+ }
+
+ dyn_type *subType = dynAvprType_initializeReferenceType(type);
+ if (!subType) {
+ free(type);
+ return NULL;
+ }
+
+ // First try to find if it already exists
+ LOG_DEBUG("Reference: looking for %s", name_buffer);
+ dyn_type *ref = dynType_findType(root, (char*) name_buffer);
+ if (ref) {
+ if (ref->type == DYN_TYPE_INVALID) {
+ LOG_ERROR("Reference: found incomplete type");
+ free(type);
+ return NULL;
+ }
+ else {
+ subType->ref.ref = ref;
+ return type;
+ }
+ }
+
+ // if not found, Generate the reference type in root
+ LOG_DEBUG("Reference: looking for %s in array", name_buffer);
+ json_t const * const refType = dynAvprType_findType(name_buffer, array_object, parent_ns);
+ if (!refType) {
+ LOG_ERROR("ParseReference: Could not find %s", name_buffer);
+ free(subType);
+ free(type);
+ return NULL;
+ }
+
+ bool success = true;
+ struct type_entry *entry = dynAvprType_prepareNestedEntry(root, name_buffer, true);
+ dyn_type * tmp = entry->type;
+ if (!entry) {
+ LOG_ERROR("Reference: could not create nested entry");
+ success = false;
+ }
+
+ if (success) {
+ entry->type = dynAvprType_parseAny(root, NULL, refType, array_object, parent_ns);
+ if (!entry->type) {
+ free(entry);
+ success = false;
+ }
+ }
+
+ free(tmp->name);
+ free(tmp);
+
+ if (success) {
+ LOG_DEBUG("Added new type to root:");
+ subType->ref.ref = entry->type;
+ return type;
+ }
+ else {
+ dynType_destroy(subType);
+ dynType_destroy(type);
+ return NULL;
+ }
+}
+
+static dyn_type * dynAvprType_parseSelfReference(dyn_type * root, dyn_type * parent, const char * name_buffer, json_t const * const array_object, const char * parent_ns, dyn_type * ref_type) {
+ dyn_type * type = dynAvprType_initializeType(parent);
+ if (!type) {
+ return NULL;
+ }
+
+ dyn_type * sub_type = dynAvprType_initializeReferenceType(type);
+ if (!sub_type) {
+ free(type);
+ return NULL;
+ }
+
+ sub_type->ref.ref = parent;
+ return type;
+}
+
+// Assumes type_pointer is already present and alloc'd!
+static dyn_type * dynAvprType_initializeReferenceType(dyn_type * type_pointer) {
+ type_pointer->type = DYN_TYPE_TYPED_POINTER;
+ type_pointer->descriptor = '*';
+ type_pointer->ffiType = &ffi_type_pointer;
+
+ dyn_type *sub_type = dynAvprType_initializeType(type_pointer);
+ if (!sub_type) {
+ LOG_ERROR("Could not create reference type");
+ return NULL;
+ }
+
+ type_pointer->typedPointer.typedType = sub_type;
+ sub_type->type = DYN_TYPE_REF;
+ sub_type->descriptor = 'l';
+ return sub_type;
+
+}
+
+static inline struct type_entry * dynAvprType_prepareNestedEntry(dyn_type * const parent, const char * fqn, bool allocate) {
+ struct type_entry *entry = calloc(1, sizeof(*entry));
+ if (allocate) {
+ entry->type = calloc(1, sizeof(*entry->type));
+ entry->type->name = strndup(fqn, STR_LENGTH);
+
+ // Initialize information
+ entry->type->parent = parent;
+ entry->type->type = DYN_TYPE_INVALID;
+ TAILQ_INIT(&entry->type->nestedTypesHead);
+ TAILQ_INIT(&entry->type->metaProperties);
+ }
+
+ TAILQ_INSERT_TAIL(&parent->nestedTypesHead, entry, entries);
+ return entry;
+}
+
+static dyn_type * dynAvprType_parseEnum(dyn_type * parent, json_t const * const enum_obj, const char * parent_ns) {
+ dyn_type * type = dynAvprType_initializeType(parent);
+ if (!type) {
+ return NULL;
+ }
+
+ char * fqn = dynAvprType_createFqnFromJson(enum_obj, parent_ns);
+ if (!fqn) {
+ free(type);
+ return NULL;
+ }
+
+ json_t * symbolArray = json_object_get(enum_obj, "symbols");
+ if (!json_is_array(symbolArray)) {
+ LOG_WARNING("Expected \"symbols\" to be an array for enum %s", fqn);
+ free(fqn);
+ free(type);
+ return NULL;
+ }
+
+ json_t * values_array = json_object_get(enum_obj, "EnumValues");
+ if (json_is_array(values_array) && json_array_size(values_array) != json_array_size(symbolArray)) {
+ LOG_WARNING("Expected \"symbols\" and \"EnumValues\" arrays to be of the same size");
+ free(fqn);
+ free(type);
+ return NULL;
+ }
+
+ const size_t max = json_array_size(symbolArray);
+ bool valid = true;
+ size_t counter = 0;
+ json_t *enumeta_entry_ptr;
+ for (; valid && counter < max && (enumeta_entry_ptr = json_array_get(symbolArray, counter)); counter++) {
+ struct meta_entry * meta_entry_ptr = dynAvprType_createMetaEntry(json_string_value(enumeta_entry_ptr));
+ if (meta_entry_ptr && dynAvprType_metaEntrySetValue(meta_entry_ptr, values_array, counter)) {
+ LOG_DEBUG("Added enum entry with name: %s and value: %s", meta_entry_ptr->name, meta_entry_ptr->value);
+ TAILQ_INSERT_TAIL(&type->metaProperties, meta_entry_ptr, entries);
+ }
+ else {
+ valid = false;
+ }
+ }
+
+ if (valid) {
+ type->name = fqn;
+ type->type = DYN_TYPE_SIMPLE;
+ type->descriptor = 'E';
+ type->ffiType = &ffi_type_sint32;
+ return type;
+ }
+ else {
+ free(fqn);
+ dynType_destroy(type);
+ return NULL;
+ }
+}
+
+static inline struct meta_entry * dynAvprType_createMetaEntry(const char* enum_entry_name) {
+ if (!enum_entry_name) {
+ LOG_ERROR("CreateMetaEntry: passed null pointer, no name present?");
+ return NULL;
+ }
+
+ struct meta_entry *entry = calloc(1, sizeof(*entry));
+ entry->name = strndup(enum_entry_name, STR_LENGTH);
+ return entry;
+}
+
+static inline bool dynAvprType_metaEntrySetValue(struct meta_entry * meta_entry_ptr, json_t const * const values_array, size_t index) {
+ if (!meta_entry_ptr) {
+ return false;
+ }
+
+ if (values_array) {
+ const char* enumValue = json_string_value(json_array_get(values_array, index));
+ if (!enumValue) {
+ LOG_WARNING("MetaEntrySetValue: could not get the enum value from the \"EnumValues\" list at index %lu", index);
+ return false;
+ }
+
+ meta_entry_ptr->value = strndup(enumValue, STR_LENGTH);
+ if (!meta_entry_ptr->value) {
+ LOG_ERROR("MetaEntrySetValue: could not allocate memory for meta_entry->value");
+ return false;
+ }
+ dynAvprType_parseEnumValue(&meta_entry_ptr->value);
+ }
+ else {
+ const int bufsize = sizeof(index) * CHAR_BIT + 1;
+ meta_entry_ptr->value = calloc(bufsize, sizeof(char));
+
+ snprintf(meta_entry_ptr->value, bufsize, "%lu", index);
+ }
+
+ return true;
+}
+
+static inline void dynAvprType_parseEnumValue(char** enumvalue) {
+ char* str = *enumvalue;
+ if (!str) {
+ LOG_ERROR("Do not pass null pointer to this function");
+ return;
+ }
+
+ // Remove whitespace
+ int i, j = 0;
+ for (i = 0; str[i] != '\0'; i++) {
+ if (!isspace((unsigned char) str[i])) {
+ str[j++] = str[i];
+ }
+ }
+ str[j] = '\0';
+
+ //create the substring if an equals sign is found
+ char* equalssign = strrchr(str, '=');
+ if (equalssign) {
+ memmove(str, equalssign+1, strlen(equalssign-1));
+ }
+}
+
+static ffi_type *seq_types[] = {&ffi_type_uint32, &ffi_type_uint32, &ffi_type_pointer, NULL};
+
+static dyn_type * dynAvprType_parseArray(dyn_type * root, dyn_type * parent, json_t const * const array_entry_obj, json_t const * const array_object, char * name_buffer, const char * parent_ns, const char * record_ns) {
+ dyn_type * type = dynAvprType_initializeType(parent);
+ if (!type) {
+ return NULL;
+ }
+
+ type->type = DYN_TYPE_SEQUENCE;
+ type->descriptor = '[';
+
+ type->sequence.seqType.elements = seq_types;
+ type->sequence.seqType.type = FFI_TYPE_STRUCT;
+ type->sequence.seqType.size = 0;
+ type->sequence.seqType.alignment = 0;
+ type->sequence.itemType = NULL;
+
+ json_t const * const itemsEntry = json_object_get(array_entry_obj, "items");
+ if (json_is_object(itemsEntry)) { // is nested?
+ LOG_DEBUG("ParseArray: Found nested array");
+ json_t const * const nested_array_object = json_object_get(array_entry_obj, "items");
+ type->sequence.itemType = dynAvprType_parseArray(root, type, nested_array_object, array_object, name_buffer, parent_ns, record_ns);
+ }
+ else if (json_is_string(itemsEntry)) { // is a named item?
+ LOG_DEBUG("ParseArray: Found type, parsing");
+ dynAvprType_constructFqn(name_buffer, FQN_SIZE, json_string_value(itemsEntry), record_ns);
+ type->sequence.itemType = dynAvprType_parseAny(root, type, dynAvprType_findType(name_buffer, array_object, parent_ns), array_object, parent_ns);
+ }
+ else {
+ LOG_ERROR("ParseArray: Unrecognized array structure: \"items\" is neither a nested array nor a type");
+ }
+
+ if (type->sequence.itemType) {
+ type->ffiType = &type->sequence.seqType;
+ dynType_prepCif(&type->sequence.seqType);
+ }
+ else {
+ free(type);
+ type = NULL;
+ }
+
+ return type;
+}
+
+static dyn_type * dynAvprType_parseFixed(dyn_type * parent, json_t const * const fixed_object, const char * parent_ns) {
+ dyn_type * type = dynAvprType_initializeType(parent);
+ if (!type) {
+ return NULL;
+ }
+
+ ffi_type * ffiType = NULL;
+ int descriptor = dynAvprType_fixedTypeToFfi(fixed_object, &ffiType);
+
+ if (!ffiType || descriptor == '0') {
+ LOG_ERROR("Invalid simple type, received wrong ffi type!");
+ free(type);
+ return NULL;
+ }
+
+ if (!json_is_string(json_object_get(fixed_object, "name"))) {
+ LOG_ERROR("Invalid simple type, need a name");
+ free(type);
+ return NULL;
+ }
+
+ type->name = dynAvprType_createFqnFromJson(fixed_object, parent_ns);
+ if (!type->name) {
+ free(type);
+ return NULL;
+ }
+
+ type->type = (descriptor == 't') ? DYN_TYPE_TEXT : DYN_TYPE_SIMPLE;
+ type->descriptor = descriptor;
+ type->ffiType = ffiType;
+ return type;
+}
+
+static inline int dynAvprType_fixedTypeToFfi(json_t const * const simple_obj, ffi_type ** output_ffi_type) {
+ const int size = json_integer_value(json_object_get(simple_obj, "size"));
+ const bool sign = json_is_true(json_object_get(simple_obj, "signed"));
+ const char * alias = json_string_value(json_object_get(simple_obj, "alias"));
+ const int s_size = sign ? size : -size;
+
+ LOG_DEBUG("Simple fixed type: size = %d, signed = %s, alias = %s", size, sign ? "true" : "false", alias ? alias : "none");
+
+ if (!alias) {
+ switch (s_size) {
+ case 1:
+ *output_ffi_type = &ffi_type_sint8;
+ return 'B';
+ case 2:
+ *output_ffi_type = &ffi_type_sint16;
+ return 'S';
+ case 4:
+ *output_ffi_type = &ffi_type_sint32;
+ return 'I';
+ case 8:
+ *output_ffi_type = &ffi_type_sint64;
+ return 'J';
+ case -1:
+ *output_ffi_type = &ffi_type_uint8;
+ return 'b';
+ case -2:
+ *output_ffi_type = &ffi_type_uint16;
+ return 's';
+ case -4:
+ *output_ffi_type = &ffi_type_uint32;
+ return 'i';
+ case -8:
+ *output_ffi_type = &ffi_type_uint64;
+ return 'j';
+ default:
+ LOG_ERROR("Unrecognized size = %d", size);
+ return '0';
+ }
+
+ }
+ else {
+ if (strcmp(alias, "float") == 0) {
+ *output_ffi_type = &ffi_type_float;
+ return 'F';
+ }
+ else if (strcmp(alias, "double") == 0) {
+ *output_ffi_type = &ffi_type_double;
+ return 'D';
+ }
+ else if (strcmp(alias, "string") == 0) {
+ *output_ffi_type = &ffi_type_pointer;
+ return 't';
+ }
+ else if (strcmp(alias, "boolean") == 0) {
+ *output_ffi_type = &ffi_type_uint8;
+ return 'Z';
+ }
+ else if (strcmp(alias, "void") == 0) {
+ *output_ffi_type = &ffi_type_void;
+ return 'V';
+ }
+ else if (strcmp(alias, "void_ptr") == 0) {
+ *output_ffi_type = &ffi_type_pointer;
+ return 'P';
+ }
+ else if (strcmp(alias, "native_int") == 0) {
+ *output_ffi_type = &ffi_type_sint;
+ return 'N';
+ }
+ else {
+ LOG_ERROR("Unrecognized alias = %s", alias);
+ return '0';
+ }
+ }
+}
+
+static char * dynAvprType_createFqnFromJson(json_t const * const jsonObject, const char * namespace) {
+ const char *name = json_string_value(json_object_get(jsonObject, "name"));
+ if (!name) {
+ LOG_ERROR("This object appears to not have a name!!");
+ return NULL;
+ }
+
+ const bool local_ns = json_is_string(json_object_get(jsonObject, "namespace"));
+ const char *ns = local_ns ? json_string_value(json_object_get(jsonObject, "namespace")) : namespace;
+ if (!ns) {
+ LOG_ERROR("Need a namespace because the jsonObject does not have a namespace!");
+ return NULL;
+ }
+
+ // Create fqn
+ const int length = strlen(ns) + strlen(name) + 2;
+ char * fqn = calloc(length, sizeof(char));
+
+ snprintf(fqn, length, "%s.%s", ns, name);
+ return fqn;
+}
+
+static inline enum JsonTypeType dynAvprType_getType(json_t const * const json_type) {
+ if (json_is_string(json_type)) {
+ return SIMPLE;
+ }
+ else if (json_is_object(json_type) && json_is_string(json_object_get(json_type, "type")) && 0 == strcmp("array", json_string_value(json_object_get(json_type, "type")))) {
+ return ARRAY;
+ }
+ else {
+ return INVALID;
+ }
+}
+
+static inline void dynAvprType_createVersionMetaEntry(dyn_type * type, json_t const * const root, json_t const * const array_object, const char* parent_ns) {
+ struct meta_entry * m_entry = dynAvprType_createMetaEntry("version");
+
+ json_t const * json_type_version = json_object_get(dynAvprType_findType(dynType_getName(type), array_object, parent_ns), "version");
+
+ // If version is not available check root version
+ if (!json_is_string(json_type_version)) {
+ json_type_version = json_object_get(root, "version");
+ }
+
+ // If version is available use it (either from record or root)
+ if (json_is_string(json_type_version)) {
+ const char* version_str = json_string_value(json_type_version);
+ // Check if a valid version was given
+ version_pt v = NULL;
+ celix_status_t status = version_createVersionFromString(version_str, &v);
+ if (CELIX_SUCCESS == status) {
+ m_entry->value = strndup(version_str, STR_LENGTH);
+ version_destroy(v);
+ }
+ else {
+ m_entry->value = strndup("0.0.0", STR_LENGTH);
+ LOG_WARNING("parseAvpr: Did not find valid version, set version to 0.0.0");
+ }
+ }
+ else {
+ // If no version or an invalid version is available, default to 0.0.0
+ m_entry->value = strndup("0.0.0", STR_LENGTH);
+ LOG_WARNING("parseAvpr: Did not find version entry, set version to 0.0.0");
+ }
+
+ // Insert into type
+ TAILQ_INSERT_TAIL(&type->metaProperties, m_entry, entries);
+}
+
+static inline void dynAvprType_createAnnotationEntries(dyn_type * type, json_t const * const array_object, const char* parent_ns) {
+ json_t const * json_type = dynAvprType_findType(dynType_getName(type), array_object, parent_ns);
+ const char* const not_of_interest[5] = {"type", "name", "fields", "version", "alias"};
+ const char* key;
+ json_t const * value;
+ json_object_foreach((json_t*)json_type, key, value) {
+ if (! ( strcmp(key, not_of_interest[0]) == 0
+ || strcmp(key, not_of_interest[1]) == 0
+ || strcmp(key, not_of_interest[2]) == 0
+ || strcmp(key, not_of_interest[3]) == 0
+ || strcmp(key, not_of_interest[4]) == 0))
+ {
+ struct meta_entry * m_entry = dynAvprType_createMetaEntry(key);
+
+ switch (json_typeof(value)) {
+ case JSON_STRING:
+ m_entry->value = strndup(json_string_value(value), STR_LENGTH);
+ break;
+ case JSON_INTEGER:
+ asprintf(&m_entry->value, "%" JSON_INTEGER_FORMAT, json_integer_value(value));
+ break;
+ case JSON_REAL:
+ asprintf(&m_entry->value, "%f", json_real_value(value));
+ break;
+ case JSON_TRUE:
+ m_entry->value = strdup("true");
+ break;
+ case JSON_FALSE:
+ m_entry->value = strdup("false");
+ break;
+ case JSON_NULL:
+ m_entry->value = strdup("null");
+ break;
+ case JSON_OBJECT:
+ /* fall through */
+ case JSON_ARRAY:
+ /* fall through */
+ default:
+ LOG_WARNING("createAnnotationEntries: encountered an annotation of an unknown type : %s", key);
+ free(m_entry->name);
+ free(m_entry);
+ continue; // Do not add the invalid entry as a meta-entry
+ }
+
+ TAILQ_INSERT_TAIL(&type->metaProperties, m_entry, entries);
+ }
+ }
+}
diff --git a/libs/dfi/src/dyn_function.c b/libs/dfi/src/dyn_function.c
index db718f2..b70239b 100644
--- a/libs/dfi/src/dyn_function.c
+++ b/libs/dfi/src/dyn_function.c
@@ -17,37 +17,12 @@
*under the License.
*/
#include "dyn_function.h"
+#include "dyn_function_common.h"
#include <strings.h>
#include <stdlib.h>
#include <ffi.h>
-#include "dyn_common.h"
-
-struct _dyn_function_type {
- char *name;
- struct types_head *refTypes; //NOTE not owned
- TAILQ_HEAD(,_dyn_function_argument_type) arguments;
- ffi_type **ffiArguments;
- dyn_type *funcReturn;
- ffi_cif cif;
-
- //closure part
- ffi_closure *ffiClosure;
- void (*fn)(void);
- void *userData;
- void (*bind)(void *userData, void *args[], void *ret);
-};
-
-typedef struct _dyn_function_argument_type dyn_function_argument_type;
-struct _dyn_function_argument_type {
- int index;
- char *name;
- enum dyn_function_argument_meta argumentMeta;
- dyn_type *type;
- TAILQ_ENTRY(_dyn_function_argument_type) entries;
-};
-
static const int OK = 0;
static const int MEM_ERROR = 1;
static const int PARSE_ERROR = 2;
@@ -59,7 +34,7 @@ static int dynFunction_initCif(dyn_function_type *dynFunc);
static int dynFunction_parseDescriptor(dyn_function_type *dynFunc, FILE *descriptor);
static void dynFunction_ffiBind(ffi_cif *cif, void *ret, void *args[], void *userData);
-extern ffi_type * dynType_ffiType(dyn_type *type);
+ffi_type * dynType_ffiType(dyn_type *type);
int dynFunction_parse(FILE *descriptor, struct types_head *refTypes, dyn_function_type **out) {
int status = OK;
diff --git a/libs/dfi/src/dyn_interface.c b/libs/dfi/src/dyn_interface.c
index abb5345..2e9581a 100644
--- a/libs/dfi/src/dyn_interface.c
+++ b/libs/dfi/src/dyn_interface.c
@@ -23,28 +23,22 @@
#include "dyn_common.h"
#include "dyn_type.h"
-#include "dyn_interface.h"
+#include "dyn_interface_common.h"
DFI_SETUP_LOG(dynInterface);
-struct _dyn_interface_type {
- struct namvals_head header;
- struct namvals_head annotations;
- struct types_head types;
- struct methods_head methods;
- version_pt version;
-};
-
static const int OK = 0;
static const int ERROR = 1;
+// Also export for dyn_avpr_interface
+int dynInterface_checkInterface(dyn_interface_type *intf);
+
static int dynInterface_parseSection(dyn_interface_type *intf, FILE *stream);
static int dynInterface_parseAnnotations(dyn_interface_type *intf, FILE *stream);
static int dynInterface_parseTypes(dyn_interface_type *intf, FILE *stream);
static int dynInterface_parseMethods(dyn_interface_type *intf, FILE *stream);
static int dynInterface_parseHeader(dyn_interface_type *intf, FILE *stream);
static int dynInterface_parseNameValueSection(dyn_interface_type *intf, FILE *stream, struct namvals_head *head);
-static int dynInterface_checkInterface(dyn_interface_type *intf);
static int dynInterface_getEntryForHead(struct namvals_head *head, const char *name, char **value);
int dynInterface_parse(FILE *descriptor, dyn_interface_type **out) {
@@ -99,7 +93,7 @@ int dynInterface_parse(FILE *descriptor, dyn_interface_type **out) {
return status;
}
-static int dynInterface_checkInterface(dyn_interface_type *intf) {
+int dynInterface_checkInterface(dyn_interface_type *intf) {
int status = OK;
//check header section
diff --git a/libs/dfi/src/dyn_type.c b/libs/dfi/src/dyn_type.c
index 4fc79ff..b223ca6 100644
--- a/libs/dfi/src/dyn_type.c
+++ b/libs/dfi/src/dyn_type.c
@@ -24,10 +24,16 @@
#include <errno.h>
#include <ffi.h>
+#include "dyn_type_common.h"
#include "dyn_common.h"
DFI_SETUP_LOG(dynType)
+static const int OK = 0;
+static const int ERROR = 1;
+static const int MEM_ERROR = 2;
+static const int PARSE_ERROR = 3;
+
static int dynType_parseWithStream(FILE *stream, const char *name, dyn_type *parent, struct types_head *refTypes, dyn_type **result);
static void dynType_clear(dyn_type *type);
static void dynType_clearComplex(dyn_type *type);
@@ -38,7 +44,6 @@ ffi_type * dynType_ffiType(dyn_type *type);
static struct type_entry *dynType_allocTypeEntry(void);
static ffi_type * dynType_ffiTypeFor(int c);
-static dyn_type * dynType_findType(dyn_type *type, char *name);
static int dynType_parseAny(FILE *stream, dyn_type *type);
static int dynType_parseComplex(FILE *stream, dyn_type *type);
static int dynType_parseNestedType(FILE *stream, dyn_type *type);
@@ -47,13 +52,13 @@ static int dynType_parseRefByValue(FILE *stream, dyn_type *type);
static int dynType_parseSequence(FILE *stream, dyn_type *type);
static int dynType_parseSimple(int c, dyn_type *type);
static int dynType_parseTypedPointer(FILE *stream, dyn_type *type);
-static void dynType_prepCif(ffi_type *type);
static unsigned short dynType_getOffset(dyn_type *type, int index);
static void dynType_printAny(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printComplex(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printSequence(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printSimple(char *name, dyn_type *type, int depth, FILE *stream);
+static void dynType_printEnum(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printTypedPointer(char *name, dyn_type *type, int depth, FILE *stream);
static void dynType_printDepth(int depth, FILE *stream);
@@ -62,6 +67,7 @@ static void dynType_printComplexType(dyn_type *type, FILE *stream);
static void dynType_printSimpleType(dyn_type *type, FILE *stream);
static int dynType_parseText(FILE *stream, dyn_type *type);
+static int dynType_parseEnum(FILE *stream, dyn_type *type);
void dynType_freeComplexType(dyn_type *type, void *loc);
void dynType_deepFree(dyn_type *type, void *loc, bool alsoDeleteSelf);
void dynType_freeSequenceType(dyn_type *type, void *seqLoc);
@@ -74,47 +80,6 @@ struct generic_sequence {
void *buf;
};
-TAILQ_HEAD(meta_properties_head, meta_entry);
-struct meta_entry {
- char *name;
- char *value;
- TAILQ_ENTRY(meta_entry) entries;
-};
-
-
-struct _dyn_type {
- char *name;
- char descriptor;
- int type;
- ffi_type *ffiType;
- dyn_type *parent;
- struct types_head *referenceTypes; //NOTE: not owned
- struct types_head nestedTypesHead;
- struct meta_properties_head metaProperties;
- union {
- struct {
- struct complex_type_entries_head entriesHead;
- ffi_type structType; //dyn_type.ffiType points to this
- dyn_type **types; //based on entriesHead for fast access
- } complex;
- struct {
- ffi_type seqType; //dyn_type.ffiType points to this
- dyn_type *itemType;
- } sequence;
- struct {
- dyn_type *typedType;
- } typedPointer;
- struct {
- dyn_type *ref;
- } ref;
- };
-};
-
-static const int OK = 0;
-static const int ERROR = 1;
-static const int MEM_ERROR = 2;
-static const int PARSE_ERROR = 3;
-
int dynType_parse(FILE *descriptorStream, const char *name, struct types_head *refTypes, dyn_type **type) {
return dynType_parseWithStream(descriptorStream, name, NULL, refTypes, type);
}
@@ -199,6 +164,9 @@ static int dynType_parseAny(FILE *stream, dyn_type *type) {
case 't' :
status = dynType_parseText(stream, type);
break;
+ case 'E' :
+ status = dynType_parseEnum(stream, type);
+ break;
case '#' :
status = dynType_parseMetaInfo(stream, type);
if (status == OK) {
@@ -261,6 +229,14 @@ static int dynType_parseText(FILE *stream, dyn_type *type) {
return status;
}
+static int dynType_parseEnum(FILE *stream, dyn_type *type) {
+ int status = OK;
+ type->ffiType = &ffi_type_sint32;
+ type->descriptor = 'E';
+ type->type = DYN_TYPE_SIMPLE;
+ return status;
+}
+
static int dynType_parseComplex(FILE *stream, dyn_type *type) {
int status = OK;
type->type = DYN_TYPE_COMPLEX;
@@ -296,7 +272,7 @@ static int dynType_parseComplex(FILE *stream, dyn_type *type) {
c = fgetc(stream);
}
-
+// loop over names
if (status == OK) {
entry = TAILQ_FIRST(&type->complex.entriesHead);
char *name = NULL;
@@ -508,13 +484,6 @@ static int dynType_parseTypedPointer(FILE *stream, dyn_type *type) {
return status;
}
-static void dynType_prepCif(ffi_type *type) {
- ffi_cif cif;
- ffi_type *args[1];
- args[0] = type;
- ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uint, args);
-}
-
void dynType_destroy(dyn_type *type) {
if (type != NULL) {
dynType_clear(type);
@@ -824,7 +793,6 @@ void dynType_simple_setValue(dyn_type *type, void *inst, void *in) {
memcpy(inst, in, size);
}
-
int dynType_descriptorType(dyn_type *type) {
return type->descriptor;
}
@@ -842,15 +810,13 @@ const char * dynType_getMetaInfo(dyn_type *type, const char *name) {
return result;
}
-ffi_type *dynType_ffiType(dyn_type *type) {
- if (type->type == DYN_TYPE_REF) {
- if (type->ref.ref == NULL) {
- LOG_ERROR("Error. Ref for %s is not (yet) initialized", type->name);
- return NULL;
- }
- return type->ref.ref->ffiType;
- }
- return type->ffiType;
+int dynType_metaEntries(dyn_type *type, struct meta_properties_head **entries) {
+ *entries = &type->metaProperties;
+ return OK;
+}
+
+const char * dynType_getName(dyn_type *type) {
+ return type->name;
}
static ffi_type * dynType_ffiTypeFor(int c) {
@@ -887,7 +853,7 @@ static ffi_type * dynType_ffiTypeFor(int c) {
type = &ffi_type_sint64;
break;
case 'j' :
- type = &ffi_type_sint64;
+ type = &ffi_type_uint64;
break;
case 'N' :
type = &ffi_type_sint;
@@ -902,38 +868,6 @@ static ffi_type * dynType_ffiTypeFor(int c) {
return type;
}
-static dyn_type * dynType_findType(dyn_type *type, char *name) {
- dyn_type *result = NULL;
-
- struct type_entry *entry = NULL;
- if (type->referenceTypes != NULL) {
- TAILQ_FOREACH(entry, type->referenceTypes, entries) {
- LOG_DEBUG("checking ref type '%s' with name '%s'", entry->type->name, name);
- if (strcmp(name, entry->type->name) == 0) {
- result = entry->type;
- break;
- }
- }
- }
-
- if (result == NULL) {
- struct type_entry *nEntry = NULL;
- TAILQ_FOREACH(nEntry, &type->nestedTypesHead, entries) {
- LOG_DEBUG("checking nested type '%s' with name '%s'", nEntry->type->name, name);
- if (strcmp(name, nEntry->type->name) == 0) {
- result = nEntry->type;
- break;
- }
- }
- }
-
- if (result == NULL && type->parent != NULL) {
- result = dynType_findType(type->parent, name);
- }
-
- return result;
-}
-
static unsigned short dynType_getOffset(dyn_type *type, int index) {
assert(type->type == DYN_TYPE_COMPLEX);
unsigned short offset = 0;
@@ -1037,7 +971,7 @@ static void dynType_printAny(char *name, dyn_type *type, int depth, FILE *stream
dynType_printTypedPointer(name, toPrint, depth, stream);
break;
default :
- fprintf(stream, "TODO Unsupported type %i\n", toPrint->type);
+ fprintf(stream, "TODO Unsupported type %d\n", toPrint->type);
break;
}
}
@@ -1076,8 +1010,23 @@ static void dynType_printSequence(char *name, dyn_type *type, int depth, FILE *s
}
static void dynType_printSimple(char *name, dyn_type *type, int depth, FILE *stream) {
+ if (type->descriptor != 'E') {
+ dynType_printDepth(depth, stream);
+ fprintf(stream, "%s: simple type, size is %zu, alignment is %i, descriptor is '%c'.\n", name, type->ffiType->size, type->ffiType->alignment, type->descriptor);
+ }
+ else {
+ dynType_printEnum(name, type, depth, stream);
+ }
+}
+
+static void dynType_printEnum(char *name, dyn_type *type, int depth, FILE *stream) {
dynType_printDepth(depth, stream);
- fprintf(stream, "%s: simple type, size is %zu, alignment is %i, descriptor is '%c'.\n", name, type->ffiType->size, type->ffiType->alignment, type->descriptor);
+ fprintf(stream, "%s: enum type, size is %zu, alignment is %i, descriptor is '%c'. values:", name, type->ffiType->size, type->ffiType->alignment, type->descriptor);
+ struct meta_entry * m_entry;
+ TAILQ_FOREACH(m_entry, &type->metaProperties, entries) {
+ fprintf(stream, " (\"%s\":\"%s\")", m_entry->name, m_entry->value);
+ }
+ fprintf(stream, "\n");
}
static void dynType_printTypedPointer(char *name, dyn_type *type, int depth, FILE *stream) {
diff --git a/libs/dfi/src/dyn_type_common.c b/libs/dfi/src/dyn_type_common.c
new file mode 100644
index 0000000..b3ad7c3
--- /dev/null
+++ b/libs/dfi/src/dyn_type_common.c
@@ -0,0 +1,81 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include "dyn_type.h"
+
+#include "dyn_type_common.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <ffi.h>
+
+DFI_SETUP_LOG(dynTypeCommon)
+
+dyn_type * dynType_findType(dyn_type *type, char *name) {
+ dyn_type *result = NULL;
+
+ struct type_entry *entry = NULL;
+ if (type->referenceTypes != NULL) {
+ TAILQ_FOREACH(entry, type->referenceTypes, entries) {
+ LOG_DEBUG("checking ref type '%s' with name '%s'", entry->type->name, name);
+ if (strcmp(name, entry->type->name) == 0) {
+ result = entry->type;
+ break;
+ }
+ }
+ }
+
+ if (result == NULL) {
+ struct type_entry *nEntry = NULL;
+ TAILQ_FOREACH(nEntry, &type->nestedTypesHead, entries) {
+ LOG_DEBUG("checking nested type '%s' with name '%s'", nEntry->type->name, name);
+ if (strcmp(name, nEntry->type->name) == 0) {
+ result = nEntry->type;
+ break;
+ }
+ }
+ }
+
+ if (result == NULL && type->parent != NULL) {
+ result = dynType_findType(type->parent, name);
+ }
+
+ return result;
+}
+
+ffi_type * dynType_ffiType(dyn_type * type) {
+ if (type->type == DYN_TYPE_REF) {
+ if (type->ref.ref == NULL) {
+ LOG_ERROR("Error. Ref for %s is not (yet) initialized", type->name);
+ return NULL;
+ }
+ return type->ref.ref->ffiType;
+ }
+ return type->ffiType;
+}
+
+void dynType_prepCif(ffi_type *type) {
+ ffi_cif cif;
+ ffi_type *args[1];
+ args[0] = type;
+ ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uint, args);
+}
+
diff --git a/libs/dfi/src/json_serializer.c b/libs/dfi/src/json_serializer.c
index 106c745..c3307c4 100644
--- a/libs/dfi/src/json_serializer.c
+++ b/libs/dfi/src/json_serializer.c
@@ -18,6 +18,7 @@
*/
#include "json_serializer.h"
#include "dyn_type.h"
+#include "dyn_type_common.h"
#include "dyn_interface.h"
#include <jansson.h>
@@ -30,12 +31,13 @@ static int jsonSerializer_parseObject(dyn_type *type, json_t *object, void *inst
static int jsonSerializer_parseObjectMember(dyn_type *type, const char *name, json_t *val, void *inst);
static int jsonSerializer_parseSequence(dyn_type *seq, json_t *array, void *seqLoc);
static int jsonSerializer_parseAny(dyn_type *type, void *input, json_t *val);
+static int jsonSerializer_parseEnum(dyn_type *type, const char* enum_name, int32_t *out);
static int jsonSerializer_writeAny(dyn_type *type, void *input, json_t **val);
-
static int jsonSerializer_writeComplex(dyn_type *type, void *input, json_t **val);
-
static int jsonSerializer_writeSequence(dyn_type *type, void *input, json_t **out);
+static int jsonSerializer_writeEnum(dyn_type *type, int32_t enum_value, json_t **out);
+
static int OK = 0;
static int ERROR = 1;
@@ -159,6 +161,7 @@ static int jsonSerializer_parseAny(dyn_type *type, void *loc, json_t *val) {
int *n; //N
int16_t *s; //S
int32_t *i; //I
+ int32_t *E; //E
int64_t *l; //J
uint8_t *ub; //b
uint16_t *us; //s
@@ -214,6 +217,17 @@ static int jsonSerializer_parseAny(dyn_type *type, void *loc, json_t *val) {
ul = loc;
*ul = (uint64_t) json_integer_value(val);
break;
+ case 'E' :
+ if (json_is_null(val)) {
+ //nop
+ } else if (json_is_string(val)){
+ E = loc;
+ status = jsonSerializer_parseEnum(type, json_string_value(val), E);
+ } else {
+ status = ERROR;
+ LOG_ERROR("Expected json string for enum type but got %i", json_typeof(val));
+ }
+ break;
case 't' :
if (json_is_null(val)) {
//nop
@@ -299,6 +313,20 @@ int jsonSerializer_serialize(dyn_type *type, const void* input, char **output) {
return status;
}
+static int jsonSerializer_parseEnum(dyn_type *type, const char* enum_name, int32_t *out) {
+ struct meta_entry * entry;
+
+ TAILQ_FOREACH(entry, &type->metaProperties, entries) {
+ if (0 == strcmp(enum_name, entry->name)) {
+ *out = atoi(entry->value);
+ return OK;
+ }
+ }
+
+ LOG_ERROR("Could not find Enum value %s in enum type", enum_name);
+ return ERROR;
+}
+
int jsonSerializer_serializeJson(dyn_type *type, const void* input, json_t **out) {
return jsonSerializer_writeAny(type, (void*)input /*TODO update static function to take const void**/, out);
}
@@ -317,6 +345,7 @@ static int jsonSerializer_writeAny(dyn_type *type, void* input, json_t **out) {
int *n; //N
int16_t *s; //S
int32_t *i; //I
+ int32_t *e; //E
int64_t *l; //J
uint8_t *ub; //b
uint16_t *us; //s
@@ -375,6 +404,10 @@ static int jsonSerializer_writeAny(dyn_type *type, void* input, json_t **out) {
case 't' :
val = json_string(*(const char **) input);
break;
+ case 'E':
+ e = input;
+ jsonSerializer_writeEnum(type, *e, &val);
+ break;
case '*' :
status = dynType_typedPointer_getTypedType(type, &subType);
if (status == OK) {
@@ -454,11 +487,11 @@ static int jsonSerializer_writeComplex(dyn_type *type, void *input, json_t **out
dyn_type *subType = NULL;
index = dynType_complex_indexForName(type, entry->name);
if (index < 0) {
- LOG_ERROR("Cannot find index for member '%s'", entry->name);
+ LOG_ERROR("Cannot find index for member '%s'", entry->name);
status = ERROR;
}
if(status == OK){
- status = dynType_complex_valLocAt(type, index, input, &subLoc);
+ status = dynType_complex_valLocAt(type, index, input, &subLoc);
}
if (status == OK) {
status = dynType_complex_dynTypeAt(type, index, &subType);
@@ -484,3 +517,21 @@ static int jsonSerializer_writeComplex(dyn_type *type, void *input, json_t **out
return status;
}
+static int jsonSerializer_writeEnum(dyn_type *type, int32_t enum_value, json_t **out) {
+ struct meta_entry * entry;
+
+ // Convert to string
+ char enum_value_str[32];
+ snprintf(enum_value_str, 32, "%d", enum_value);
+
+ // Lookup in meta-information
+ TAILQ_FOREACH(entry, &type->metaProperties, entries) {
+ if (0 == strcmp(enum_value_str, entry->value)) {
+ *out = json_string((const char*)entry->name);
+ return OK;
+ }
+ }
+
+ LOG_ERROR("Could not find Enum value %s in enum type", enum_value_str);
+ return ERROR;
+}
diff --git a/libs/dfi/test/avro_descriptor_translator_tests.cpp b/libs/dfi/test/avro_descriptor_translator_tests.cpp
index 5bab518..23149e1 100644
--- a/libs/dfi/test/avro_descriptor_translator_tests.cpp
+++ b/libs/dfi/test/avro_descriptor_translator_tests.cpp
@@ -178,3 +178,4 @@ TEST(AvroDescTranslatorTest, invalid1) {
TEST(AvroDescTranslatorTest, invalid2) {
invalid("schemas/invalid2.avpr");
}
+
diff --git a/libs/dfi/test/dyn_avpr_function_tests.cpp b/libs/dfi/test/dyn_avpr_function_tests.cpp
new file mode 100644
index 0000000..e9172fd
--- /dev/null
+++ b/libs/dfi/test/dyn_avpr_function_tests.cpp
@@ -0,0 +1,620 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include <CppUTest/TestHarness.h>
+#include "CppUTest/CommandLineTestRunner.h"
+
+extern "C" {
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <stdarg.h>
+
+ #include "dyn_common.h"
+ #include "dyn_function.h"
+
+ static void stdLog(void*, int level, const char *file, int line, const char *msg, ...) {
+ va_list ap;
+ const char *levels[5] = {"NIL", "ERROR", "WARNING", "INFO", "DEBUG"};
+ fprintf(stderr, "%s: FILE:%s, LINE:%i, MSG:",levels[level], file, line);
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ }
+}
+
+const char* theAvprFile = "{ \
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.dt\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Void\", \
+ \"alias\" : \"void\", \
+ \"size\" : 4 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"VoidPtr\", \
+ \"alias\" : \"void_ptr\", \
+ \"size\" : 4 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Sint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"NativeInt\", \
+ \"size\" : 4, \
+ \"alias\" : \"native_int\" \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"String\", \
+ \"alias\" : \"string\", \
+ \"size\" : 8 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Double\", \
+ \"alias\" : \"double\", \
+ \"size\" : 8 \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"StructString\", \
+ \"fields\" : [ { \
+ \"name\" : \"name\", \
+ \"type\" : \"String\" \
+ } , { \
+ \"name\" : \"id\", \
+ \"type\" : \"Sint\" \
+ } ] \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"AStruct\", \
+ \"namespace\" : \"nested.test.dt\", \
+ \"fields\" : [ { \
+ \"name\" : \"val1\", \
+ \"type\" : \"test.dt.Sint\" \
+ } , { \
+ \"name\" : \"val2\", \
+ \"type\" : \"test.dt.Sint\" \
+ } , { \
+ \"name\" : \"val3\", \
+ \"type\" : \"test.dt.Double\" \
+ } ] \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"MArray\", \
+ \"fields\" : [ { \
+ \"name\" : \"array\", \
+ \"type\" : { \
+ \"type\" : \"array\",\
+ \"items\" : \"Double\"\
+ } \
+ } ] \
+ } ] ,\
+ \"messages\" : { \
+ \"simpleFunc\" : {\
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"Sint\" \
+ } , { \
+ \"name\" : \"arg2\", \
+ \"type\" : \"Sint\" \
+ } , { \
+ \"name\" : \"arg3\", \
+ \"type\" : \"Sint\" \
+ } ],\
+ \"response\" : \"Sint\" \
+ }, \
+ \"structFunc\" : {\
+ \"namespace\" : \"nested.test.dt\", \
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"test.dt.Sint\" \
+ } , { \
+ \"name\" : \"arg2\", \
+ \"type\" : \"AStruct\" \
+ } , { \
+ \"name\" : \"arg3\", \
+ \"type\" : \"test.dt.Double\" \
+ } ],\
+ \"response\" : \"test.dt.Double\" \
+ }, \
+ \"accessFunc\" : {\
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"Double\" \
+ } , { \
+ \"name\" : \"arg2\", \
+ \"type\" : \"nested.test.dt.AStruct\" \
+ } , { \
+ \"name\" : \"arg3\", \
+ \"type\" : \"Double\" \
+ } ],\
+ \"response\" : \"test.dt.Void\" \
+ }, \
+ \"outFunc\" : {\
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"VoidPtr\" \
+ } , { \
+ \"name\" : \"arg2\", \
+ \"type\" : \"Double\" \
+ } , { \
+ \"name\" : \"arg3\", \
+ \"type\" : \"Double\", \
+ \"ptr\" : true \
+ } ],\
+ \"response\" : \"NativeInt\" \
+ }, \
+ \"seqFunc\" : {\
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"MArray\" \
+ } ],\
+ \"response\" : \"Void\" \
+ }, \
+ \"infoFunc\" : {\
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"Sint\" \
+ } ],\
+ \"response\" : \"Double\" \
+ }, \
+ \"arrayInFunc\" : {\
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : { \
+ \"type\" : \"array\",\
+ \"items\" : \"Double\" \
+ } \
+ } ],\
+ \"response\" : \"Double\" \
+ }, \
+ \"arrayOutFunc\" : {\
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"Double\" \
+ } ],\
+ \"response\" : { \
+ \"type\" : \"array\",\
+ \"items\" : \"Double\" \
+ } \
+ }, \
+ \"stringOutFunc\" : {\
+ \"request\" : [ ],\
+ \"response\" : \"String\" \
+ }, \
+ \"structStringOutFunc\" : {\
+ \"request\" : [ ],\
+ \"response\" : \"StructString\" \
+ } \
+ }\
+ }";
+
+TEST_GROUP(DynAvprFunctionTests) {
+ void setup() override {
+ int lvl = 1;
+ dynAvprFunction_logSetup(stdLog, nullptr, lvl);
+ dynAvprType_logSetup(stdLog, nullptr, lvl);
+ }
+};
+
+// Test 1, simple function with three arguments and a return type
+static int avpr_example1(__attribute__((unused)) void* handle, int32_t a, int32_t b, int32_t c, int32_t * out) {
+ CHECK_EQUAL(2, a);
+ CHECK_EQUAL(4, b);
+ CHECK_EQUAL(8, c);
+ *out = 1;
+ return 0;
+}
+
+TEST(DynAvprFunctionTests, Example1) {
+ auto fp = (void (*)()) avpr_example1;
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "test.dt.simpleFunc");
+ CHECK(dynFunc != nullptr);
+
+ int handle = 0;
+ int* handle_ptr = &handle;
+ int32_t a = 2;
+ int32_t b = 4;
+ int32_t c = 8;
+ int32_t out = 0;
+ int32_t * p_out = &out;
+ void *values[5];
+ values[0] = &handle_ptr;
+ values[1] = &a;
+ values[2] = &b;
+ values[3] = &c;
+ values[4] = &p_out;
+ int rVal = 1;
+
+ int rc = dynFunction_call(dynFunc, fp, &rVal, values);
+ CHECK_EQUAL(0, rc);
+ CHECK_EQUAL(1, out);
+ CHECK_EQUAL(0, rVal);
+ dynFunction_destroy(dynFunc);
+}
+
+
+// Test 2, function with complex argument
+struct avpr_example2_arg2 {
+ int32_t val1;
+ int32_t val2;
+ double val3;
+};
+
+static int avpr_example2(__attribute__((unused)) void* handle, int32_t arg1, struct avpr_example2_arg2 arg2, double arg3, double* out) {
+ CHECK_EQUAL(2, arg1);
+ CHECK_EQUAL(2, arg2.val1);
+ CHECK_EQUAL(3, arg2.val2);
+ CHECK_EQUAL(4.1, arg2.val3);
+ CHECK_EQUAL(8.1, arg3);
+ *out = 2.2;
+ return 0;
+}
+
+TEST(DynAvprFunctionTests, Example2) {
+ auto fp = (void (*)()) avpr_example2;
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "nested.test.dt.structFunc");
+ CHECK(dynFunc != nullptr);
+
+ int handle = 0;
+ int* handle_ptr = &handle;
+ int32_t a = 2;
+ avpr_example2_arg2 arg2 {2, 3, 4.1};
+
+ double c = 8.1;
+ double out = 0.0;
+ double* p_out = &out;
+ void *values[5];
+ values[0] = &handle_ptr;
+ values[1] = &a;
+ values[2] = &arg2;
+ values[3] = &c;
+ values[4] = &p_out;
+ int rVal = 1;
+
+ int rc = dynFunction_call(dynFunc, fp, &rVal, values);
+ CHECK_EQUAL(0, rc);
+ CHECK_EQUAL(0, rVal);
+ CHECK_EQUAL(2.2, out);
+ dynFunction_destroy(dynFunc);
+}
+
+// Test 3, Test access of functions, see if arguments and result type can be accessed
+TEST(DynAvprFunctionTests, Example3) {
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "test.dt.accessFunc");
+ CHECK(dynFunc != nullptr);
+
+ int nrOfArgs = dynFunction_nrOfArguments(dynFunc);
+ CHECK_EQUAL(3+1+1, nrOfArgs);
+
+ dyn_type *arg1 = dynFunction_argumentTypeForIndex(dynFunc, 2);
+ CHECK(arg1 != nullptr);
+ CHECK_EQUAL('{', (char) dynType_descriptorType(arg1));
+
+ dyn_type *nonExist = dynFunction_argumentTypeForIndex(dynFunc, 10);
+ CHECK(nonExist == nullptr);
+
+ dyn_type *returnType = dynFunction_returnType(dynFunc);
+ CHECK_EQUAL('N', (char) dynType_descriptorType(returnType));
+
+ dynFunction_destroy(dynFunc);
+}
+
+
+// Test 4, with void pointer and native output
+/*
+static int avpr_example4(__attribute__((unused)) void *handle, void *ptr, double a, double *out, int *out_2) {
+ auto b = (double *)ptr;
+ CHECK_EQUAL(2.0, *b);
+ CHECK_EQUAL(2.0, a);
+ *out = *b * a; // => out parameter
+ *out_2 = 3;
+ return 0;
+}
+
+TEST(DynAvprFunctionTests, Example4) {
+ auto fp = (void(*)()) avpr_example4;
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "test.dt.outFunc");
+ CHECK(dynFunc != nullptr);
+
+ int handle = 0;
+ int* handle_ptr = &handle;
+ double result = -1.0;
+ double *input = &result;
+ double a = 2.0;
+ void *ptr = &a;
+ void *args[5];
+ int out = 0;
+ int* out_ptr = &out;
+ args[0] = &handle_ptr;
+ args[1] = &ptr;
+ args[2] = &a;
+ args[3] = &input;
+ args[4] = &out_ptr;
+ int rVal = 1;
+ int rc = dynFunction_call(dynFunc, fp, &rVal, args);
+
+ CHECK_EQUAL(0, rc);
+ CHECK_EQUAL(4.0, result);
+ CHECK_EQUAL(3, out);
+
+ auto inMemResult = (double *)calloc(1, sizeof(double));
+ a = 2.0;
+ ptr = &a;
+ args[1] = &ptr;
+ args[2] = &a;
+ args[3] = &inMemResult;
+ rVal = 0;
+ rc = dynFunction_call(dynFunc, fp, &rVal, args);
+ CHECK_EQUAL(0, rc);
+ CHECK_EQUAL(4.0, result);
+ free(inMemResult);
+ dynFunction_destroy(dynFunc);
+}
+*/
+
+// Test5, testing with sequence as argument
+struct tst_seq {
+ uint32_t cap;
+ uint32_t len;
+ double *buf;
+};
+
+static int avpr_example5(__attribute__((unused)) void* handle, struct tst_seq seq, __attribute__((unused)) void* out) {
+ CHECK_EQUAL(4, seq.cap);
+ CHECK_EQUAL(2, seq.len);
+ CHECK_EQUAL(1.1, seq.buf[0]);
+ CHECK_EQUAL(2.2, seq.buf[1]);
+ return 0;
+}
+
+TEST(DynAvprFunctionTests, Example5) {
+ auto fp = (void(*)()) avpr_example5;
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "test.dt.seqFunc");
+
+ CHECK(dynFunc != nullptr);
+
+ int handle = 0;
+ int* handle_ptr = &handle;
+ double buf[4];
+ buf[0] = 1.1;
+ buf[1] = 2.2;
+ struct tst_seq seq {4, 2, buf};
+ int out = 0;
+ int* out_ptr = &out;
+
+ void *args[3];
+ args[0] = &handle_ptr;
+ args[1] = &seq;
+ args[2] = &out_ptr;
+ int retArg = 1;
+
+ int rc = dynFunction_call(dynFunc, fp, &retArg, args);
+ CHECK_EQUAL(0, rc);
+ CHECK_EQUAL(0, retArg);
+
+ dynFunction_destroy(dynFunc);
+}
+
+// Test 6, Test data accessible with handle
+struct info {
+ char * name;
+ int id;
+};
+
+static int avpr_example6(void *handle, int32_t id_modifier, double* out) {
+ auto fake_this = (struct info *) handle;
+ CHECK(fake_this != nullptr);
+ CHECK(fake_this->name != nullptr);
+ CHECK_EQUAL(0, strcmp(fake_this->name, "test_name"));
+ CHECK_EQUAL(42, fake_this->id);
+ *out = (double)(fake_this->id + id_modifier);
+ return 0;
+}
+
+TEST(DynAvprFunctionTests, Example6) {
+ auto fp = (void(*)()) avpr_example6;
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "test.dt.infoFunc");
+ CHECK(dynFunc != nullptr);
+
+ info handle {strdup("test_name"), 42};
+ CHECK(handle.name != nullptr);
+
+ struct info * handle_ptr = &handle;
+ int32_t argument = 58;
+ double out = 0.0;
+ double * out_ptr = &out;
+
+ void *values[3];
+ values[0] = &handle_ptr;
+ values[1] = &argument;
+ values[2] = &out_ptr;
+ int rVal = 1;
+
+ int rc = dynFunction_call(dynFunc, fp, &rVal, values);
+ CHECK_EQUAL(0, rc);
+ CHECK_EQUAL(100.0, out);
+ CHECK_EQUAL(0, rVal);
+ dynFunction_destroy(dynFunc);
+ free(handle.name);
+}
+
+//Test 7, Test function with array as parameter
+struct double_seq {
+ uint32_t cap;
+ uint32_t len;
+ double *buf;
+};
+
+static int avpr_example7(__attribute__((unused)) void *handle, struct double_seq seq_in, double* out) {
+ CHECK_EQUAL(2, seq_in.cap);
+ CHECK_EQUAL(2, seq_in.len);
+ *out = seq_in.buf[0] + seq_in.buf[1];
+ return 0;
+}
+
+TEST(DynAvprFunctionTests, Example7) {
+ auto fp = (void(*)()) avpr_example7;
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "test.dt.arrayInFunc");
+ CHECK(dynFunc != nullptr);
+
+ int handle = 0;
+ int* handle_ptr = &handle;
+
+ double buf[2];
+ buf[0] = 1.101;
+ buf[1] = 2.202;
+ double_seq s_seq {2, 2, buf};
+
+ double out = 0.0;
+ double *out_ptr = &out;
+
+ void *args[3];
+ args[0] = &handle_ptr;
+ args[1] = &s_seq;
+ args[2] = &out_ptr;
+ int rVal = 0;
+
+ int rc = dynFunction_call(dynFunc, fp, &rVal, args);
+ CHECK_EQUAL(0, rc);
+ DOUBLES_EQUAL(3.303, out, 0.00001);
+
+ dynFunction_destroy(dynFunc);
+}
+
+//Test 8, Test function with array as return value
+static int avpr_example8(__attribute__((unused))void *handle, double arg1, struct double_seq** out) {
+ DOUBLES_EQUAL(2.0, arg1, 0.0001);
+ CHECK_EQUAL(3, (*out)->cap);
+ (*out)->buf[0] = 0.0;
+ (*out)->buf[1] = 1.1;
+ (*out)->buf[2] = 2.2;
+ return 0;
+}
+
+TEST(DynAvprFunctionTests, Example8) {
+ auto fp = (void(*)()) avpr_example8;
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "test.dt.arrayOutFunc");
+ CHECK(dynFunc != nullptr);
+
+ int handle = 0;
+ int* handle_ptr = &handle;
+
+ double arg1 = 2.0;
+
+ double buf[3];
+ buf[0] = -1.1;
+ buf[1] = 0.0;
+ buf[2] = 0.0;
+ double_seq dseq {3, 3, buf};
+ struct double_seq * out_ptr = &dseq;
+ struct double_seq ** out_ptr_ptr = &out_ptr;
+
+ void *args[3];
+ args[0] = &handle_ptr;
+ args[1] = &arg1;
+ args[2] = &out_ptr_ptr;
+ int rVal = 0;
+
+ int rc = dynFunction_call(dynFunc, fp, &rVal, args);
+ CHECK_EQUAL(0, rc);
+ DOUBLES_EQUAL(0.0, buf[0], 0.0001);
+ DOUBLES_EQUAL(1.1, buf[1], 0.0001);
+ DOUBLES_EQUAL(2.2, buf[2], 0.0001);
+
+ dynFunction_destroy(dynFunc);
+}
+
+// Test 9, Test function with string as return value
+static int avpr_example9(__attribute__((unused))void *handle, char** out) {
+ *out = strdup("result_out");
+ CHECK(*out != nullptr);
+ return 0;
+}
+
+TEST(DynAvprFunctionTests, Example9) {
+ auto fp = (void(*)()) avpr_example9;
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "test.dt.stringOutFunc");
+ CHECK(dynFunc != nullptr);
+
+ int handle = 0;
+ int* handle_ptr = &handle;
+
+ char * out = nullptr;
+ char ** out_ptr = &out;
+
+ void *args[2];
+ args[0] = &handle_ptr;
+ args[1] = &out_ptr;
+ int rVal = 1;
+
+ int rc = dynFunction_call(dynFunc, fp, &rVal, args);
+ CHECK_EQUAL(0, rc);
+ STRCMP_EQUAL("result_out", out);
+
+ free(out);
+ dynFunction_destroy(dynFunc);
+}
+
+// Test 10, Test function with object with string as return value
+extern "C" {
+ struct tst_10 {
+ char * name;
+ int32_t id;
+ };
+}
+
+static int avpr_example10(__attribute__((unused))void *handle, struct tst_10 ** out) {
+ (*out)->name = strdup("my_new_char");
+ CHECK((*out)->name != nullptr);
+ (*out)->id = 132;
+ return 0;
+}
+
+TEST(DynAvprFunctionTests, Example10) {
+ auto fp = (void(*)()) avpr_example10;
+ dyn_function_type * dynFunc = dynFunction_parseAvprWithStr(theAvprFile, "test.dt.structStringOutFunc");
+ CHECK(dynFunc != nullptr);
+
+ int handle = 0;
+ int* handle_ptr = &handle;
+
+ tst_10 out {nullptr, 0};
+ struct tst_10 * out_ptr = &out;
+ struct tst_10 ** out_ptr_ptr = &out_ptr;
+
+ void *args[2];
+ args[0] = &handle_ptr;
+ args[1] = &out_ptr_ptr;
+ int rVal = 1;
+
+ int rc = dynFunction_call(dynFunc, fp, &rVal, args);
+ CHECK_EQUAL(0, rc);
+ CHECK_EQUAL(132, out.id);
+ STRCMP_EQUAL("my_new_char", out.name);
+
+ free(out.name);
+ dynFunction_destroy(dynFunc);
+}
diff --git a/libs/dfi/test/dyn_avpr_interface_tests.cpp b/libs/dfi/test/dyn_avpr_interface_tests.cpp
new file mode 100644
index 0000000..5d7d1e5
--- /dev/null
+++ b/libs/dfi/test/dyn_avpr_interface_tests.cpp
@@ -0,0 +1,174 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include <CppUTest/TestHarness.h>
+#include "CppUTest/CommandLineTestRunner.h"
+
+extern "C" {
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <stdarg.h>
+
+ #include "dyn_common.h"
+ #include "dyn_interface.h"
+
+ static void stdLog(void*, int level, const char *file, int line, const char *msg, ...) {
+ va_list ap;
+ const char *levels[5] = {"NIL", "ERROR", "WARNING", "INFO", "DEBUG"};
+ fprintf(stderr, "%s: FILE:%s, LINE:%i, MSG:",levels[level], file, line);
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ }
+}
+
+const char* theInvalidAvprFile = "{ \
+ \"protocol\" : \"the_interface\", \
+ \"namespace\" : \"test.dt\", \
+ \"version\" : \"1.1.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Sint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ } ] ,\
+ \"messages\" : { \
+ \"aFunc\" : {\
+ \"request\" : [ ],\
+ \"response\" : \"Sint\" \
+ } \
+ } \
+ }";
+
+const char* theBigAvprFile = "{ \
+ \"protocol\" : \"the_interface\", \
+ \"namespace\" : \"test.dt\", \
+ \"version\" : \"1.1.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Sint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ } , { \
+ \"type\" : \"fixed\", \
+ \"namespace\" : \"nested\", \
+ \"name\" : \"Double\", \
+ \"alias\": \"double\", \
+ \"size\" : 8 \
+ } ] ,\
+ \"messages\" : { \
+ \"simpleFunc\" : {\
+ \"index\" : 0, \
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"Sint\" \
+ } , { \
+ \"name\" : \"arg2\", \
+ \"type\" : \"Sint\" \
+ } , { \
+ \"name\" : \"arg3\", \
+ \"type\" : \"Sint\", \
+ \"ptr\" : true \
+ } ],\
+ \"response\" : \"Sint\" \
+ }, \
+ \"aFunc\" : {\
+ \"index\" : 1, \
+ \"request\" : [ {\
+ \"name\" : \"m_arg\", \
+ \"type\" : \"Sint\" \
+ } ],\
+ \"response\" : \"Sint\" \
+ } \
+ } \
+ }";
+
+TEST_GROUP(DynAvprInterfaceTests) {
+ void setup() override {
+ int lvl = 1;
+ dynAvprInterface_logSetup(stdLog, nullptr, lvl);
+ dynAvprFunction_logSetup(stdLog, nullptr, lvl);
+ dynAvprType_logSetup(stdLog, nullptr, lvl);
+ }
+};
+
+static void checkInterfaceVersion(dyn_interface_type* dynIntf, const char* v) {
+ int status;
+
+ char *version = nullptr;
+ status = dynInterface_getVersionString(dynIntf, &version);
+ CHECK_EQUAL(0, status);
+ STRCMP_EQUAL(v, version);
+ version_pt msgVersion = nullptr, localMsgVersion = nullptr;
+ int cmpVersion = -1;
+ version_createVersionFromString(version, &localMsgVersion);
+ status = dynInterface_getVersion(dynIntf, &msgVersion);
+ CHECK_EQUAL(0, status);
+ version_compareTo(msgVersion, localMsgVersion, &cmpVersion);
+ CHECK_EQUAL(cmpVersion, 0);
+ version_destroy(localMsgVersion);
+}
+
+// Test 1, simply see if parsing works and if parsed correctly
+TEST(DynAvprInterfaceTests, Example1) {
+ dyn_interface_type *dynIntf = dynInterface_parseAvprWithStr(theBigAvprFile);
+ CHECK(dynIntf != nullptr);
+
+ // Check version
+ checkInterfaceVersion(dynIntf, "1.1.0");
+
+ // Check name
+ char *name = nullptr;
+ dynInterface_getName(dynIntf, &name);
+ CHECK(name != nullptr);
+ STRCMP_EQUAL("the_interface", name);
+
+ // Check annotation (namespace)
+ char *annVal = nullptr;
+ dynInterface_getAnnotationEntry(dynIntf, "namespace", &annVal);
+ CHECK(annVal != nullptr);
+ STRCMP_EQUAL("test.dt", annVal);
+
+ // Check nonexisting
+ char *nonExist = nullptr;
+ dynInterface_getHeaderEntry(dynIntf, "nonExisting", &nonExist);
+ CHECK(nonExist == nullptr);
+
+ // Get lists of methods
+ struct methods_head *list = nullptr;
+ int status = dynInterface_methods(dynIntf, &list);
+ CHECK(status == 0);
+ CHECK(list != nullptr);
+
+ int count = dynInterface_nrOfMethods(dynIntf);
+ CHECK_EQUAL(2, count);
+
+ dynInterface_destroy(dynIntf);
+}
+
+// Invalid tests
+TEST(DynAvprInterfaceTests, InvalidExample) {
+ dyn_interface_type *dynIntf = dynInterface_parseAvprWithStr(theInvalidAvprFile);
+ CHECK(dynIntf == nullptr);
+}
+
diff --git a/libs/dfi/test/dyn_avpr_tests.cpp b/libs/dfi/test/dyn_avpr_tests.cpp
new file mode 100644
index 0000000..69ff3d9
--- /dev/null
+++ b/libs/dfi/test/dyn_avpr_tests.cpp
@@ -0,0 +1,514 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+#include "CppUTest/TestHarness.h"
+#include "CppUTest/CommandLineTestRunner.h"
+
+extern "C" {
+ #include <stdarg.h>
+
+ #include "dyn_common.h"
+ #include "dyn_type.h"
+
+ static void stdLogA(void*, int level, const char *file, int line, const char *msg, ...) {
+ va_list ap;
+ const char *levels[5] = {"NIL", "ERROR", "WARNING", "INFO", "DEBUG"};
+ fprintf(stderr, "%s: FILE:%s, LINE:%i, MSG:",levels[level], file, line);
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ }
+
+ static void runTestA(const char *descriptorStr, const char *exName, int expectedType) {
+ dyn_type *type;
+ type = dynType_parseAvprWithStr(descriptorStr, exName);
+
+ if (type != nullptr) {
+ CHECK_EQUAL(expectedType, dynType_type(type));
+ dynType_destroy(type);
+ } else {
+ CHECK_EQUAL(1, 0);
+ }
+ }
+}
+
+const char* theTestCase = "{ \
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.dt\", \
+ \"version\" : \"1.1.9\", \
+ \"CpfCInclude\" : \"time.h\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"uint\", \
+ \"version\" : \"2.1.9\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"ulong\", \
+ \"size\" : 8, \
+ \"namespace\" : \"blah.test.dt\" \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"double\", \
+ \"alias\" : \"double\", \
+ \"size\" : 8 \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"B\", \
+ \"fields\" : [ \
+ { \
+ \"name\" : \"aa\", \
+ \"type\" : \"uint\" \
+ },\
+ { \
+ \"name\" : \"bb\", \
+ \"type\" : \"uint\" \
+ }\
+ ,\
+ { \
+ \"name\" : \"cc\", \
+ \"type\" : \"double\" \
+ }\
+ ] \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"long\", \
+ \"size\" : 8, \
+ \"namespace\" : \"other.dt\", \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"A\", \
+ \"namespace\" : \"blah.test.dt\", \
+ \"fields\" : [\
+ { \
+ \"name\" : \"x\", \
+ \"type\" : \"test.dt.B\" \
+ },\
+ { \
+ \"name\" : \"y\", \
+ \"type\" : \"ulong\" \
+ }\
+ ] \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"V\", \
+ \"fields\" : [\
+ {\
+ \"name\" : \"elem\", \
+ \"type\" : {\
+ \"type\" : \"array\",\
+ \"items\" : \"uint\",\
+ \"static\" : 3\
+ }\
+ }\
+ ]\
+ }, { \
+ \"type\" : \"enum\", \
+ \"name\" : \"EnumWithValue\", \
+ \"EnumValues\" : [ \"A = 3\", \"B= 1234\" ],\
+ \"symbols\" : [\"A\", \"B\"]\
+ }, { \
+ \"type\" : \"enum\", \
+ \"name\" : \"EnumWithoutValue\", \
+ \"symbols\" : [\"A\", \"B\"]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"Anne\", \
+ \"alias\" : \"CoolType\", \
+ \"MsgId\" : 1000, \
+ \"Invalid\" : {}, \
+ \"fields\" : [ {\
+ \"name\" : \"data\", \
+ \"type\" :\"test.dt.double\" \
+ } ]\
+ }, { \
+ \"type\" : \"record\", \
+ \"namespace\" : \"N\", \
+ \"name\" : \"Node\", \
+ \"fields\" : [ {\
+ \"name\" : \"data\", \
+ \"type\" :\"test.dt.double\" \
+ }, {\
+ \"name\" : \"ne_elem_left\", \
+ \"type\" : \"Node\", \
+ \"ptr\" : true \
+ }, {\
+ \"name\" : \"ne_elem_right\", \
+ \"type\" : \"Node\", \
+ \"ptr\" : true \
+ } ]\
+ } ] ,\
+ \"messages\" : {} \
+ }";
+
+const char* nestedArray = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.dt\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"uint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"NA\", \
+ \"fields\" : [\
+ { \
+ \"name\" : \"members\", \
+ \"type\" : {\
+ \"type\" : \"array\",\
+ \"items\" : {\
+ \"type\" : \"array\",\
+ \"items\" : \"uint\",\
+ \"static\" : 3\
+ },\
+ \"static\" : 3\
+ }\
+ } ] \
+ }] , \
+ \"messages\" : {} \
+ }";
+
+const char* referenceTestCase = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.dt\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"uint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"X\", \
+ \"fields\" : [\
+ { \
+ \"name\" : \"xx\", \
+ \"type\" : \"uint\" \
+ }, { \
+ \"name\" : \"level_a\", \
+ \"type\" : \"X\", \
+ \"ptr\" : true \
+ }, { \
+ \"name\" : \"level_b\", \
+ \"type\" : \"X\", \
+ \"ptr\" : true \
+ } ] \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"R\", \
+ \"fields\" : [\
+ { \
+ \"name\" : \"data\", \
+ \"type\" : \"X\", \
+ \"ptr\" : true \
+ } ] \
+ }] , \
+ \"messages\" : {} \
+ }";
+
+
+/*********************************************************************************
+ * Type building tests
+ */
+
+TEST_GROUP(DynAvprTypeTests) {
+ void setup() override {
+ dynAvprType_logSetup(stdLogA, nullptr, 3);
+ }
+};
+
+TEST(DynAvprTypeTests, SimpleTest) {
+ runTestA(theTestCase, "test.dt.uint", DYN_TYPE_SIMPLE);
+}
+
+TEST(DynAvprTypeTests, ComplexTest) {
+ runTestA(theTestCase, "blah.test.dt.A", DYN_TYPE_COMPLEX);
+}
+
+TEST(DynAvprTypeTests, EnumTest2) {
+ runTestA(theTestCase, "test.dt.EnumWithValue", DYN_TYPE_SIMPLE);
+}
+
+TEST(DynAvprTypeTests, EnumTest) {
+ runTestA(theTestCase, "test.dt.EnumWithoutValue", DYN_TYPE_SIMPLE);
+}
+
+TEST(DynAvprTypeTests, ArrayTest) {
+ runTestA(theTestCase, "test.dt.V", DYN_TYPE_COMPLEX);
+}
+
+TEST(DynAvprTypeTests, NestedArrayTest) {
+ runTestA(nestedArray, "test.dt.NA", DYN_TYPE_COMPLEX);
+}
+
+TEST(DynAvprTypeTests, ComplexComplexTest) {
+ runTestA(theTestCase, "test.dt.B", DYN_TYPE_COMPLEX);
+}
+
+TEST(DynAvprTypeTests, ReferenceTest) {
+ runTestA(referenceTestCase, "test.dt.R", DYN_TYPE_COMPLEX);
+}
+
+/*********************************************************************************
+ * Assignment tests + version testing
+ */
+
+void test_version(dyn_type* type, const std::string& version_string) {
+ struct meta_entry *entry = nullptr;
+ struct meta_properties_head *entries = nullptr;
+ CHECK_EQUAL(0, dynType_metaEntries(type, &entries));
+ CHECK_FALSE(TAILQ_EMPTY(entries));
+
+ const std::string entry_value {"version"};
+ bool compared = false;
+ TAILQ_FOREACH(entry, entries, entries) {
+ if (entry_value == entry->name) {
+ STRCMP_EQUAL(version_string.c_str(), entry->value);
+ compared = true;
+ }
+ }
+ CHECK_TRUE_TEXT(compared, "Expect a comparison, otherwise no version meta info is available");
+}
+
+TEST_GROUP(DynAvprAssignTests) {
+ void setup() override {
+ dynAvprType_logSetup(stdLogA, nullptr, 1);
+ }
+};
+
+TEST(DynAvprAssignTests, AssignSimpleTest) {
+ // Build type
+ dyn_type* type = dynType_parseAvprWithStr(theTestCase, "test.dt.uint");
+ CHECK(type != nullptr);
+
+ // set value
+ uint32_t simple = 0;
+ uint32_t nv = 42;
+ dynType_simple_setValue(type, &simple, &nv);
+
+ CHECK_EQUAL(42, simple);
+ test_version(type, "2.1.9");
+ dynType_destroy(type);
+}
+
+TEST(DynAvprAssignTests, AssignComplexTest) {
+ // Build type
+ struct exA {
+ struct {
+ uint32_t aa;
+ uint32_t bb;
+ double cc;
+ } x;
+ uint64_t y;
+ };
+
+
+ dyn_type *type = dynType_parseAvprWithStr(theTestCase, "blah.test.dt.A");
+ CHECK(type != nullptr);
+
+ // set example values
+ uint32_t a_x_aa = 52;
+ uint32_t a_x_bb = 42;
+ double a_x_cc = 31.13;
+ uint64_t a_y = 1001001;
+
+ // Simple element in complex
+ exA inst {{0, 0, 0.0}, 0};
+ dynType_complex_setValueAt(type, 1, &inst, &a_y);
+ CHECK_EQUAL(1001001, inst.y);
+
+ // Complex element in complex type, first acquire subtype, then check similar to simple type
+ void *loc = nullptr;
+ dyn_type *subType = nullptr;
+ dynType_complex_valLocAt(type, 0, static_cast<void*>(&inst), &loc);
+ dynType_complex_dynTypeAt(type, 0, &subType);
+
+ dynType_complex_setValueAt(subType, 0, &inst.x, &a_x_aa);
+ CHECK_EQUAL(52, inst.x.aa);
+
+ dynType_complex_setValueAt(subType, 1, &inst.x, &a_x_bb);
+ CHECK_EQUAL(42, inst.x.bb);
+ dynType_complex_setValueAt(subType, 2, &inst.x, &a_x_cc);
+ CHECK_EQUAL(31.13, inst.x.cc);
+
+ test_version(type, "1.1.9");
+ dynType_destroy(type);
+}
+
+TEST(DynAvprAssignTests, AssignPtrTest) {
+ // Build type
+
+ struct exNode {
+ double data;
+ exNode *ne_elem_left;
+ exNode *ne_elem_right;
+ };
+
+ dyn_type* type = dynType_parseAvprWithStr(theTestCase, "N.Node");
+ CHECK(type != nullptr);
+
+ // right tree
+ exNode rightrightright {2.0, nullptr, nullptr};
+ exNode rightleft {0.5, nullptr, nullptr};
+ exNode rightright {1.5, nullptr, &rightrightright};
+ exNode right {1.0, &rightleft, &rightright};
+
+ // left tree
+ exNode leftleft {-1.5, nullptr, nullptr};
+ exNode leftright {-0.5, nullptr, nullptr};
+ exNode left {-1.0, &leftleft, &leftright};
+
+ // Base
+ exNode base {0.0, &left, &right};
+
+ double nv = 101.101;
+ dynType_complex_setValueAt(type, 0, &base, &nv);
+ CHECK_EQUAL(101.101, base.data);
+
+ test_version(type, "1.1.9");
+ dynType_destroy(type);
+}
+
+TEST(DynAvprAssignTests, AssignEnumTest) {
+ // Build type
+ dyn_type* type = dynType_parseAvprWithStr(theTestCase, "test.dt.EnumWithValue");
+ dyn_type* type_2 = dynType_parseAvprWithStr(theTestCase, "test.dt.EnumWithoutValue");
+ CHECK(type != nullptr);
+ CHECK(type_2 != nullptr);
+
+ // Print type
+ dynType_print(type, stdout);
+ dynType_print(type_2, stdout);
+
+ // set value
+ enum exEnumV {A=3, B=1234};
+ enum exEnumV mEnum = B;
+ enum exEnumV nv = A;
+
+ dynType_simple_setValue(type, &mEnum, &nv);
+
+ CHECK_EQUAL(A, mEnum);
+ test_version(type, "1.1.9");
+ dynType_destroy(type);
+ dynType_destroy(type_2);
+}
+
+TEST(DynAvprAssignTests, AssignArrayTest) {
+ // Build type
+ struct exV_sequence {
+ uint32_t cap;
+ uint32_t len;
+ uint32_t **buf;
+ };
+
+ struct exV {
+ struct exV_sequence elem;
+ };
+
+ exV inst {exV_sequence{0,0, nullptr}};
+ exV_sequence *s = &inst.elem;
+
+ dyn_type* type = dynType_parseAvprWithStr(theTestCase, "test.dt.V");
+ CHECK(type != nullptr);
+
+ // set value
+ void *loc = nullptr;
+ dyn_type *subType = nullptr;
+ dynType_complex_valLocAt(type, 0, static_cast<void*>(&inst), &loc);
+ dynType_complex_dynTypeAt(type, 0, &subType);
+ int res = dynType_alloc(subType, reinterpret_cast<void**>(&s));
+ CHECK_EQUAL(0, res);
+ CHECK(s != nullptr);
+
+ dynType_free(type, s);
+ test_version(type, "1.1.9");
+ dynType_destroy(type);
+}
+
+TEST(DynAvprAssignTests, AnnotationTest) {
+ dyn_type* type = dynType_parseAvprWithStr(theTestCase, "test.dt.Anne");
+ CHECK(type != nullptr);
+
+ // get value for meta entry
+ struct meta_entry *entry = nullptr;
+ struct meta_properties_head *entries = nullptr;
+ CHECK_EQUAL(0, dynType_metaEntries(type, &entries));
+ CHECK_FALSE(TAILQ_EMPTY(entries));
+
+ const std::string msg_id_entry {"MsgId"};
+ bool compared = false;
+
+ TAILQ_FOREACH(entry, entries, entries) {
+ printf("Got an entry: %s\n", entry->name);
+ if (msg_id_entry == entry->name) {
+ STRCMP_EQUAL("1000", entry->value);
+ compared = true;
+ }
+ }
+ CHECK_TRUE_TEXT(compared, "Expect a comparison, otherwise no msg id entry available");
+
+ dynType_destroy(type);
+}
+
+/*********************************************************************************
+ * Invalid tests
+ */
+TEST_GROUP(DynAvprInvalidTests) {
+ void setup() override {
+ dynAvprType_logSetup(stdLogA, nullptr, 1);
+ }
+};
+
+TEST(DynAvprInvalidTests, InvalidJson) {
+ dyn_type* type = dynType_parseAvprWithStr("{", "test.invalid.type"); // Json error
+ CHECK(type == nullptr);
+}
+
+TEST(DynAvprInvalidTests, InvalidJsonObject) {
+ dyn_type* type = dynType_parseAvprWithStr("[]", "test.invalid.type"); // Root should be object not list
+ CHECK(type == nullptr);
+ type = dynType_parseAvprWithStr("{}", "test.invalid.type"); // Root should have a namespace
+ CHECK(type == nullptr);
+ type = dynType_parseAvprWithStr(R"({"namespace":"nested"})", "test.invalid.type"); // Root should have types array
+ CHECK(type == nullptr);
+ type = dynType_parseAvprWithStr(
+ R"({"namespace":"nested", "types" : [] })"
+ , "test.invalid.type"); // types is empty, so not found
+ CHECK(type == nullptr);
+ type = dynType_parseAvprWithStr(
+ "{\"namespace\":\"nested\", \"types\" : [\
+ { \"type\" : \"record\", \"name\" : \"IncompleteStruct\", \"fields\" : [\
+ { \"name\" : \"Field1\", \"type\" : \"NonExisting\" } ] } \
+ ] }"
+ , "nested.IncompleteStruct"); // struct misses definition
+ CHECK(type == nullptr);
+ type = dynType_parseAvprWithStr(
+ "{\"namespace\":\"nested\", \"types\" : [\
+ { \"type\" : \"record\", \"name\" : \"IncompleteStruct\", \"fields\" : [\
+ { \"name\" : \"Field1\" } ] } \
+ ] }"
+ , "nested.IncompleteStruct"); // struct entry misses type
+ CHECK(type == nullptr);
+ // None of the above testcases should crash the parser
+}
+
diff --git a/libs/dfi/test/dyn_function_tests.cpp b/libs/dfi/test/dyn_function_tests.cpp
index 58ad662..b8996e2 100644
--- a/libs/dfi/test/dyn_function_tests.cpp
+++ b/libs/dfi/test/dyn_function_tests.cpp
@@ -141,7 +141,7 @@ extern "C" {
static int testExample3(void *ptr, double a, double *out) {
double *b = (double *)ptr;
- CHECK_EQUAL(2.0, *b)
+ CHECK_EQUAL(2.0, *b);
CHECK_EQUAL(a, 2.0);
*out = *b * a;
return 0;
@@ -272,3 +272,4 @@ TEST(DynFunctionTests, InvalidDynFuncTest) {
test_invalidDynFunc();
test_invalidDynFuncType();
}
+
diff --git a/libs/dfi/test/dyn_interface_tests.cpp b/libs/dfi/test/dyn_interface_tests.cpp
index 5220d51..7c63d37 100644
--- a/libs/dfi/test/dyn_interface_tests.cpp
+++ b/libs/dfi/test/dyn_interface_tests.cpp
@@ -205,3 +205,4 @@ TEST(DynInterfaceTests, test2) {
TEST(DynInterfaceTests, testInvalid) {
testInvalid();
}
+
diff --git a/libs/dfi/test/dyn_message_tests.cpp b/libs/dfi/test/dyn_message_tests.cpp
index 35c7f1d..ed7d441 100644
--- a/libs/dfi/test/dyn_message_tests.cpp
+++ b/libs/dfi/test/dyn_message_tests.cpp
@@ -251,3 +251,4 @@ TEST(DynMessageTests, msg_test4) {
TEST(DynMessageTests, msg_invalid) {
msg_invalid();
}
+
diff --git a/libs/dfi/test/dyn_type_tests.cpp b/libs/dfi/test/dyn_type_tests.cpp
index 52f9537..eb1d7f1 100644
--- a/libs/dfi/test/dyn_type_tests.cpp
+++ b/libs/dfi/test/dyn_type_tests.cpp
@@ -88,6 +88,7 @@ TEST_GROUP(DynTypeTests) {
#define EX14 "{DD{FF{JJ}{II*{ss}}}}" //unnamed fields
#define EX15 "Tsample={jDD time val1 val2};Tresult={jDlsample; time result sample};Lresult;"
#define EX16 "Tpoi={BDD id lat lon};Lpoi;"
+#define EX17 "{#v1=0;#v2=1;E#v1=9;#v2=10;E enum1 enum2}"
#define CREATE_EXAMPLES_TEST(DESC) \
TEST(DynTypeTests, ParseTestExample ## DESC) { \
@@ -110,6 +111,7 @@ CREATE_EXAMPLES_TEST(EX13)
CREATE_EXAMPLES_TEST(EX14)
CREATE_EXAMPLES_TEST(EX15)
CREATE_EXAMPLES_TEST(EX16)
+CREATE_EXAMPLES_TEST(EX17)
TEST(DynTypeTests, ParseRandomGarbageTest) {
/*
@@ -295,3 +297,12 @@ TEST(DynTypeTests, SequenceWithPointerTest) {
dynType_destroy(type);
}
+TEST(DynTypeTests, EnumTest) {
+ dyn_type *type = NULL;
+ int rc = 0;
+ rc = dynType_parseWithStr("{#v1=0;#v2=1;E#v1=9;#v2=10;E enum1 enum2}", NULL, NULL, &type);
+ CHECK_EQUAL(0, rc);
+
+ dynType_print(type, stdout);
+ dynType_destroy(type);
+}
diff --git a/libs/dfi/test/json_rpc_avpr_tests.cpp b/libs/dfi/test/json_rpc_avpr_tests.cpp
new file mode 100644
index 0000000..7c52179
--- /dev/null
+++ b/libs/dfi/test/json_rpc_avpr_tests.cpp
@@ -0,0 +1,384 @@
+/**
+ *Licensed to the Apache Software Foundation (ASF) under one
+ *or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ *regarding copyright ownership. The ASF licenses this file
+ *to you under the Apache License, Version 2.0 (the
+ *"License"); you may not use this file except in compliance
+ *with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *Unless required by applicable law or agreed to in writing,
+ *software distributed under the License is distributed on an
+ *"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ *specific language governing permissions and limitations
+ *under the License.
+ */
+
+#include <CppUTest/TestHarness.h>
+#include "CppUTest/CommandLineTestRunner.h"
+
+extern "C" {
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <ctype.h>
+ #include <stdarg.h>
+ #include <assert.h>
+ #include <float.h>
+
+ #include <ffi.h>
+
+ #include "dyn_common.h"
+ #include "dyn_type.h"
+ #include "dyn_interface.h"
+
+ #include "json_serializer.h"
+ #include "json_rpc.h"
+
+ static void stdLog(void*, int level, const char *file, int line, const char *msg, ...) {
+ va_list ap;
+ const char *levels[5] = {"NIL", "ERROR", "WARNING", "INFO", "DEBUG"};
+ fprintf(stderr, "%s: FILE:%s, LINE:%i, MSG:",levels[level], file, line);
+ va_start(ap, msg);
+ vfprintf(stderr, msg, ap);
+ fprintf(stderr, "\n");
+ va_end(ap);
+ }
+}
+
+extern "C" {
+ const char* sourceAvprFile = "{ \
+ \"protocol\" : \"calculator\", \
+ \"namespace\" : \"test.rpc\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Double\", \
+ \"alias\": \"double\", \
+ \"size\" : 8 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"String\", \
+ \"alias\": \"string\", \
+ \"size\" : 8 \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"TwoDoubles\", \
+ \"fields\" : [ { \
+ \"name\" : \"a\", \
+ \"type\" : \"Double\" \
+ } , { \
+ \"name\" : \"b\", \
+ \"type\" : \"Double\" \
+ } ] \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"StatsResult\", \
+ \"fields\" : [ { \
+ \"name\" : \"average\", \
+ \"type\" : \"Double\" \
+ } , { \
+ \"name\" : \"min\", \
+ \"type\" : \"Double\" \
+ } , { \
+ \"name\" : \"max\", \
+ \"type\" : \"Double\" \
+ } , { \
+ \"name\" : \"input\", \
+ \"type\" : { \
+ \"type\" : \"array\",\
+ \"items\" : \"Double\"\
+ } \
+ } ] \
+ } ] ,\
+ \"messages\" : { \
+ \"add\" : {\
+ \"index\" : 0, \
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"Double\" \
+ } , { \
+ \"name\" : \"arg2\", \
+ \"type\" : \"Double\" \
+ } ],\
+ \"response\" : \"Double\" \
+ }, \
+ \"sub\" : {\
+ \"index\" : 1, \
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"Double\" \
+ } , { \
+ \"name\" : \"arg2\", \
+ \"type\" : \"Double\" \
+ } ],\
+ \"response\" : \"Double\" \
+ }, \
+ \"sqrt\" : {\
+ \"index\" : 2, \
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : \"Double\" \
+ } ],\
+ \"response\" : \"Double\" \
+ }, \
+ \"stats\" : {\
+ \"index\" : 3, \
+ \"request\" : [ {\
+ \"name\" : \"arg1\", \
+ \"type\" : { \
+ \"type\" : \"array\",\
+ \"items\" : \"Double\"\
+ } \
+ } ],\
+ \"response\" : \"StatsResult\" \
+ }, \
+ \"retArray\" : {\
+ \"index\" : 0, \
+ \"request\" : [ ],\
+ \"response\" : { \
+ \"type\" : \"array\",\
+ \"items\" : \"TwoDoubles\"\
+ } \
+ }, \
+ \"getName\" : {\
+ \"index\" : 0, \
+ \"request\" : [ ],\
+ \"response\" : \"String\" \
+ } \
+ } \
+ }";
+}
+
+TEST_GROUP(JsonAvprRpcTests) {
+ void setup() override {
+ int lvl = 1;
+ dynCommon_logSetup(stdLog, nullptr, lvl);
+ dynType_logSetup(stdLog, nullptr,lvl);
+ dynFunction_logSetup(stdLog, nullptr,lvl);
+ dynInterface_logSetup(stdLog, nullptr,lvl);
+ jsonSerializer_logSetup(stdLog, nullptr, lvl);
+ jsonRpc_logSetup(stdLog, nullptr, lvl);
+ }
+};
+
+TEST(JsonAvprRpcTests, prep) {
+ dyn_function_type * func = dynFunction_parseAvprWithStr(sourceAvprFile, "test.rpc.add");
+ CHECK(func != nullptr);
+ int nof_args = dynFunction_nrOfArguments(func);
+ CHECK_EQUAL(4, nof_args);
+
+ // Msg
+ char *result = nullptr;
+ void *handle = nullptr;
+
+ double arg1 = 1.0;
+ double arg2 = 2.0;
+
+ void *args[4];
+ args[0] = &handle;
+ args[1] = &arg1;
+ args[2] = &arg2;
+
+ int rc = jsonRpc_prepareInvokeRequest(func, "add", args, &result);
+ CHECK_EQUAL(0, rc);
+
+ STRCMP_CONTAINS("\"add\"", result);
+ STRCMP_CONTAINS("1.0", result);
+ STRCMP_CONTAINS("2.0", result);
+
+ // Reply
+ const char *reply = "{\"r\": 2.2}";
+ double calc_result = -1.0;
+ double *out = &calc_result;
+ //double **out_ptr = &out;
+ args[3] = &out;
+
+ rc = jsonRpc_handleReply(func, reply, args);
+ CHECK_EQUAL(0, rc);
+ DOUBLES_EQUAL(2.2, calc_result, 0.001);
+
+ free(result);
+ dynFunction_destroy(func);
+}
+
+// Test handle out
+extern "C" {
+ struct tst_seq {
+ uint32_t cap;
+ uint32_t len;
+ double *buf;
+ };
+
+ struct tst_StatsResult {
+ double average;
+ double min;
+ double max;
+ tst_seq input;
+ };
+}
+
+TEST(JsonAvprRpcTests, handle_out) {
+ dyn_interface_type * intf = dynInterface_parseAvprWithStr(sourceAvprFile);
+ CHECK(intf != nullptr);
+
+ methods_head *head;
+ dynInterface_methods(intf, &head);
+
+ dyn_function_type *func = nullptr;
+ method_entry *entry = nullptr;
+ TAILQ_FOREACH(entry, head, entries) {
+ if (strcmp(entry->name, "stats") == 0) {
+ func = entry->dynFunc;
+ break;
+ }
+ }
+ CHECK(func != nullptr);
+ int nof_args = dynFunction_nrOfArguments(func);
+ CHECK_EQUAL(3, nof_args);
+
+ const char *reply = R"({"r":{"input":[1.0,2.0],"max":2.0,"average":1.5,"min":1.0}})";
+
+ void *args[3];
+ args[0] = nullptr;
+ args[1] = nullptr;
+ args[2] = nullptr;
+
+ struct tst_StatsResult *result = nullptr;
+ void *out = &result;
+ args[2] = &out;
+
+ int rc = jsonRpc_handleReply(func, reply, args);
+ CHECK_EQUAL(0, rc);
+ CHECK(result != nullptr);
+ CHECK_EQUAL(1.5, result->average);
+
+ free(result->input.buf);
+ free(result);
+ dynInterface_destroy(intf);
+}
+
+
+// Test pre allocated
+
+extern "C" {
+ struct tst_serv {
+ void *handle;
+ int (*add)(void *, double, double, double *);
+ int (*sub)(void *, double, double, double *);
+ int (*sqrt)(void *, double, double *);
+ int (*stats)(void *, tst_seq, tst_StatsResult **);
+ };
+
+ int xadd(void*, double a, double b, double *result) {
+ *result = a + b;
+ return 0;
+ }
+}
+
+TEST(JsonAvprRpcTests, preallocated) {
+ dyn_interface_type * intf = dynInterface_parseAvprWithStr(sourceAvprFile);
+ CHECK(intf != nullptr);
+
+ char *result = nullptr;
+ tst_serv serv {nullptr, xadd, nullptr, nullptr, nullptr};
+
+ int rc = jsonRpc_call(intf, &serv, R"({"m": "add", "a": [1.0,2.0]})", &result);
+ CHECK_EQUAL(0, rc);
+ CHECK(result != nullptr);
+ STRCMP_CONTAINS("3.0", result);
+
+ free(result);
+ dynInterface_destroy(intf);
+}
+
+
+// Test output
+extern "C" {
+ int xstats(void*, struct tst_seq input, struct tst_StatsResult **out) {
+ assert(out != nullptr);
+ assert(*out == nullptr);
+ double total = 0.0;
+ unsigned int count = 0;
+ auto max = DBL_MIN;
+ auto min = DBL_MAX;
+
+ unsigned int i;
+ for (i = 0; i<input.len; i += 1) {
+ total += input.buf[i];
+ count += 1;
+ if (input.buf[i] > max) {
+ max = input.buf[i];
+ }
+ if (input.buf[i] < min) {
+ min = input.buf[i];
+ }
+ }
+
+ auto result = static_cast<tst_StatsResult *>(calloc(1, sizeof(tst_StatsResult)));
+ CHECK(result != nullptr);
+ if (count>0) {
+ result->average = total / count;
+ }
+ result->min = min;
+ result->max = max;
+ auto buf = static_cast<double *>(calloc(input.len, sizeof(double)));
+ CHECK(buf != nullptr);
+ memcpy(buf, input.buf, input.len * sizeof(double));
+ result->input.len = input.len;
+ result->input.cap = input.len;
+ result->input.buf = buf;
+
+ *out = result;
+ return 0;
+ }
+}
+
+TEST(JsonAvprRpcTests, output) {
+ dyn_interface_type * intf = dynInterface_parseAvprWithStr(sourceAvprFile);
+ CHECK(intf != nullptr);
+
+ char *result = nullptr;
+ tst_serv serv {nullptr, nullptr, nullptr, nullptr, xstats};
+
+ int rc = jsonRpc_call(intf, &serv, R"({"m":"stats", "a": [[1.0, 2.0]]})", &result);
+ CHECK_EQUAL(0, rc);
+ STRCMP_CONTAINS("1.5", result); //avg
+
+ free(result);
+ dynInterface_destroy(intf);
+}
+
+// Test char array as output
+extern "C" {
+ struct tst_service_ex_output_char {
+ void *handle;
+ int (*getName_x)(void *, char ** result);
+ };
+
+ int getName_ex(void*, char** result) {
+ *result = strdup("allocatedInFunction");
+ return 0;
+ }
+}
+
+TEST(JsonAvprRpcTests, output_char) {
+ dyn_interface_type * intf = dynInterface_parseAvprWithStr(sourceAvprFile);
+ CHECK(intf != nullptr);
+
+ char *result = nullptr;
+ tst_service_ex_output_char serv {nullptr, getName_ex};
+
+ int rc = jsonRpc_call(intf, &serv, R"({"m" : "getName", "a": []})", &result);
+ CHECK_EQUAL(0, rc);
+
+ STRCMP_CONTAINS("allocatedInFunction", result);
+
+ free(result);
+ dynInterface_destroy(intf);
+}
+
diff --git a/libs/dfi/test/json_rpc_tests.cpp b/libs/dfi/test/json_rpc_tests.cpp
index bff582e..2c66f44 100644
--- a/libs/dfi/test/json_rpc_tests.cpp
+++ b/libs/dfi/test/json_rpc_tests.cpp
@@ -47,13 +47,13 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
void prepareTest(void) {
- dyn_function_type *dynFunc = NULL;
- int rc = dynFunction_parseWithStr("add(#am=handle;PDD#am=pre;*D)N", NULL, &dynFunc);
+ dyn_function_type *dynFunc = nullptr;
+ int rc = dynFunction_parseWithStr("add(#am=handle;PDD#am=pre;*D)N", nullptr, &dynFunc);
CHECK_EQUAL(0, rc);
- char *result = NULL;
+ char *result = nullptr;
- void *handle = NULL;
+ void *handle = nullptr;
double arg1 = 1.0;
double arg2 = 2.0;
@@ -76,8 +76,8 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
}
void handleTestPre(void) {
- dyn_function_type *dynFunc = NULL;
- int rc = dynFunction_parseWithStr("add(#am=handle;PDD#am=pre;*D)N", NULL, &dynFunc);
+ dyn_function_type *dynFunc = nullptr;
+ int rc = dynFunction_parseWithStr("add(#am=handle;PDD#am=pre;*D)N", nullptr, &dynFunc);
CHECK_EQUAL(0, rc);
const char *reply = "{\"r\":2.2}";
@@ -119,12 +119,12 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
int stats(void*, struct tst_seq input, struct tst_StatsResult **out) {
- assert(out != NULL);
- assert(*out == NULL);
+ assert(out != nullptr);
+ assert(*out == nullptr);
double total = 0.0;
unsigned int count = 0;
- double max = DBL_MIN;
- double min = DBL_MAX;
+ auto max = DBL_MIN;
+ auto min = DBL_MAX;
unsigned int i;
for (i = 0; i<input.len; i += 1) {
@@ -138,13 +138,13 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
}
}
- struct tst_StatsResult *result = (struct tst_StatsResult *) calloc(1, sizeof(*result));
- if(count>0){
- result->average = total / count;
+ auto result = static_cast<tst_StatsResult *>(calloc(1, sizeof(tst_StatsResult)));
+ if(count>0) {
+ result->average = total / count;
}
result->min = min;
result->max = max;
- double *buf = (double *)calloc(input.len, sizeof(double));
+ auto buf = static_cast<double *>(calloc(input.len, sizeof(double)));
memcpy(buf, input.buf, input.len * sizeof(double));
result->input.len = input.len;
result->input.cap = input.len;
@@ -179,21 +179,17 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
};
void callTestPreAllocated(void) {
- dyn_interface_type *intf = NULL;
+ dyn_interface_type *intf = nullptr;
FILE *desc = fopen("descriptors/example1.descriptor", "r");
- CHECK(desc != NULL);
+ CHECK(desc != nullptr);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
- char *result = NULL;
+ char *result = nullptr;
+ tst_serv serv {nullptr, add, nullptr, nullptr, nullptr};
- struct tst_serv serv;
- serv.handle = NULL;
- serv.add = add;
-
-
- rc = jsonRpc_call(intf, &serv, "{\"m\":\"add(DD)D\", \"a\": [1.0,2.0]}", &result);
+ rc = jsonRpc_call(intf, &serv, R"({"m":"add(DD)D", "a": [1.0,2.0]})", &result);
CHECK_EQUAL(0, rc);
STRCMP_CONTAINS("3.0", result);
@@ -202,20 +198,17 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
}
void callTestOutput(void) {
- dyn_interface_type *intf = NULL;
+ dyn_interface_type *intf = nullptr;
FILE *desc = fopen("descriptors/example1.descriptor", "r");
- CHECK(desc != NULL);
+ CHECK(desc != nullptr);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
- char *result = NULL;
-
- struct tst_serv serv;
- serv.handle = NULL;
- serv.stats = stats;
+ char *result = nullptr;
+ tst_serv serv {nullptr, nullptr, nullptr, nullptr, stats};
- rc = jsonRpc_call(intf, &serv, "{\"m\":\"stats([D)LStatsResult;\", \"a\": [[1.0,2.0]]}", &result);
+ rc = jsonRpc_call(intf, &serv, R"({"m":"stats([D)LStatsResult;", "a": [[1.0,2.0]]})", &result);
CHECK_EQUAL(0, rc);
STRCMP_CONTAINS("1.5", result); //avg
@@ -224,33 +217,33 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
}
void handleTestOut(void) {
- dyn_interface_type *intf = NULL;
+ dyn_interface_type *intf = nullptr;
FILE *desc = fopen("descriptors/example1.descriptor", "r");
- CHECK(desc != NULL);
+ CHECK(desc != nullptr);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
struct methods_head *head;
dynInterface_methods(intf, &head);
- dyn_function_type *func = NULL;
- struct method_entry *entry = NULL;
+ dyn_function_type *func = nullptr;
+ struct method_entry *entry = nullptr;
TAILQ_FOREACH(entry, head, entries) {
if (strcmp(entry->name, "stats") == 0) {
func = entry->dynFunc;
break;
}
}
- CHECK(func != NULL);
+ CHECK(func != nullptr);
- const char *reply = "{\"r\":{\"input\":[1.0,2.0],\"max\":2.0,\"average\":1.5,\"min\":1.0}}";
+ const char *reply = R"({"r":{"input":[1.0,2.0],"max":2.0,"average":1.5,"min":1.0}})";
void *args[3];
- args[0] = NULL;
- args[1] = NULL;
- args[2] = NULL;
+ args[0] = nullptr;
+ args[1] = nullptr;
+ args[2] = nullptr;
- struct tst_StatsResult *result = NULL;
+ struct tst_StatsResult *result = nullptr;
void *out = &result;
args[2] = &out;
@@ -263,36 +256,36 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
dynInterface_destroy(intf);
}
- static void handleTestOutputSequence(void) {
- dyn_interface_type *intf = NULL;
+ static void handleTestOutputSequence() {
+ dyn_interface_type *intf = nullptr;
FILE *desc = fopen("descriptors/example2.descriptor", "r");
- CHECK(desc != NULL);
+ CHECK(desc != nullptr);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
struct methods_head *head;
dynInterface_methods(intf, &head);
- dyn_function_type *func = NULL;
- struct method_entry *entry = NULL;
+ dyn_function_type *func = nullptr;
+ struct method_entry *entry = nullptr;
TAILQ_FOREACH(entry, head, entries) {
if (strcmp(entry->name, "example1") == 0) {
func = entry->dynFunc;
break;
}
}
- CHECK(func != NULL);
+ CHECK(func != nullptr);
//dyn_type *arg = dynFunction_argumentTypeForIndex(func, 1);
//dynType_print(arg, stdout);
- const char *reply = "{\"r\":[{\"a\":1.0,\"b\":1.5},{\"a\":2.0,\"b\":2.5}]}";
+ const char *reply = R"({"r":[{"a":1.0,"b":1.5},{"a":2.0,"b":2.5}]})";
void *args[2];
- args[0] = NULL;
- args[1] = NULL;
+ args[0] = nullptr;
+ args[1] = nullptr;
- struct item_seq *result = NULL;
+ struct item_seq *result = nullptr;
void *out = &result;
args[1] = &out;
@@ -318,20 +311,17 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
void callTestOutChar(void) {
- dyn_interface_type *intf = NULL;
+ dyn_interface_type *intf = nullptr;
FILE *desc = fopen("descriptors/example4.descriptor", "r");
- CHECK(desc != NULL);
+ CHECK(desc != nullptr);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
- char *result = NULL;
+ char *result = nullptr;
+ tst_serv_example4 serv {nullptr, getName_example4};
- struct tst_serv_example4 serv;
- serv.handle = NULL;
- serv.getName_example4 = getName_example4;
-
- rc = jsonRpc_call(intf, &serv, "{\"m\":\"getName(V)t\", \"a\": []}", &result);
+ rc = jsonRpc_call(intf, &serv, R"({"m": "getName(V)t", "a": []})", &result);
CHECK_EQUAL(0, rc);
STRCMP_CONTAINS("allocatedInFunction", result);
@@ -342,17 +332,17 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
void handleTestOutChar(void) {
- dyn_interface_type *intf = NULL;
+ dyn_interface_type *intf = nullptr;
FILE *desc = fopen("descriptors/example4.descriptor", "r");
- CHECK(desc != NULL);
+ CHECK(desc != nullptr);
int rc = dynInterface_parse(desc, &intf);
CHECK_EQUAL(0, rc);
fclose(desc);
struct methods_head *head;
dynInterface_methods(intf, &head);
- dyn_function_type *func = NULL;
- struct method_entry *entry = NULL;
+ dyn_function_type *func = nullptr;
+ struct method_entry *entry = nullptr;
TAILQ_FOREACH(entry, head, entries) {
if (strcmp(entry->name, "getName") == 0) {
func = entry->dynFunc;
@@ -360,18 +350,18 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
}
}
- CHECK(func != NULL);
+ CHECK(func != nullptr);
- const char *reply = "{\"r\": \"this is a test string\" }";
- char *result = NULL;
+ const char *reply = R"({"r": "this is a test string"})";
+ char *result = nullptr;
void *out = &result;
void *args[2];
- args[0] = NULL;
+ args[0] = nullptr;
args[1] = &out;
- if(func!=NULL){ // Check needed just to satisfy Coverity
- rc = jsonRpc_handleReply(func, reply, args);
+ if (func != nullptr) { // Check needed just to satisfy Coverity
+ jsonRpc_handleReply(func, reply, args);
}
STRCMP_EQUAL("this is a test string", result);
@@ -379,20 +369,17 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
free(result);
dynInterface_destroy(intf);
}
-
-
}
TEST_GROUP(JsonRpcTests) {
- void setup() {
+ void setup() override {
int lvl = 1;
- dynCommon_logSetup(stdLog, NULL, lvl);
- dynType_logSetup(stdLog, NULL,lvl);
- dynFunction_logSetup(stdLog, NULL,lvl);
- dynInterface_logSetup(stdLog, NULL,lvl);
- jsonSerializer_logSetup(stdLog, NULL, lvl);
- jsonRpc_logSetup(stdLog, NULL, lvl);
-
+ dynCommon_logSetup(stdLog, nullptr, lvl);
+ dynType_logSetup(stdLog, nullptr,lvl);
+ dynFunction_logSetup(stdLog, nullptr,lvl);
+ dynInterface_logSetup(stdLog, nullptr,lvl);
+ jsonSerializer_logSetup(stdLog, nullptr, lvl);
+ jsonRpc_logSetup(stdLog, nullptr, lvl);
}
};
@@ -421,8 +408,6 @@ TEST(JsonRpcTests, handleOutSeq) {
handleTestOutputSequence();
}
-
-
TEST(JsonRpcTests, callTestOutChar) {
callTestOutChar();
}
diff --git a/libs/dfi/test/json_serializer_tests.cpp b/libs/dfi/test/json_serializer_tests.cpp
index a52e4cc..32fa6b7 100644
--- a/libs/dfi/test/json_serializer_tests.cpp
+++ b/libs/dfi/test/json_serializer_tests.cpp
@@ -17,7 +17,7 @@
*under the License.
*/
#include <CppUTest/TestHarness.h>
-#include "CppUTest/CommandLineTestRunner.h"
+#include "CppUTest/CommandLineTestRunner.h"
extern "C" {
#include <stdio.h>
@@ -28,6 +28,7 @@ extern "C" {
#include <ffi.h>
+#include "dyn_type_common.h"
#include "dyn_common.h"
#include "dyn_type.h"
#include "json_serializer.h"
@@ -46,6 +47,60 @@ static void stdLog(void*, int level, const char *file, int line, const char *msg
/** struct type ******************************/
const char *example1_descriptor = "{DJISF a b c d e}";
+static const char *avpr_example1_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Double\", \
+ \"size\" : 8, \
+ \"alias\" : \"double\" \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Slong\", \
+ \"size\" : 8, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Sint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Short\", \
+ \"size\" : 2, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Float\", \
+ \"size\" : 4, \
+ \"alias\" : \"float\" \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structA\", \
+ \"fields\" : [{\
+ \"name\" : \"a\", \
+ \"type\" : \"Double\" \
+ }, {\
+ \"name\" : \"b\", \
+ \"type\" : \"Slong\" \
+ }, {\
+ \"name\" : \"c\", \
+ \"type\" : \"Sint\" \
+ }, {\
+ \"name\" : \"d\", \
+ \"type\" : \"Short\" \
+ }, {\
+ \"name\" : \"e\", \
+ \"type\" : \"Float\" \
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+static const char *avpr_example1_fqn = "test.ns.structA";
+
const char *example1_input = "{ \
\"a\" : 1.0, \
\"b\" : 22, \
@@ -63,7 +118,7 @@ struct example1 {
};
static void check_example1(void *data) {
- struct example1 *ex = (struct example1 *)data;
+ auto ex = static_cast<example1*>(data);
CHECK_EQUAL(1.0, ex->a);
LONGS_EQUAL(22, ex->b);
LONGS_EQUAL(32, ex->c);
@@ -74,6 +129,58 @@ static void check_example1(void *data) {
/*********** example 2 ************************/
const char *example2_descriptor = "{BJJDFD byte long1 long2 double1 float1 double2}";
+static const char *avpr_example2_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Byte\", \
+ \"size\" : 1, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Slong\", \
+ \"size\" : 8, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Double\", \
+ \"size\" : 8, \
+ \"alias\" : \"double\" \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Float\", \
+ \"size\" : 4, \
+ \"alias\" : \"float\" \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structB\", \
+ \"fields\" : [{\
+ \"name\" : \"byte\", \
+ \"type\" : \"Byte\" \
+ }, {\
+ \"name\" : \"long1\", \
+ \"type\" : \"Slong\" \
+ }, {\
+ \"name\" : \"long2\", \
+ \"type\" : \"Slong\" \
+ }, {\
+ \"name\" : \"double1\", \
+ \"type\" : \"Double\" \
+ }, {\
+ \"name\" : \"float1\", \
+ \"type\" : \"Float\" \
+ }, {\
+ \"name\" : \"double2\", \
+ \"type\" : \"Double\" \
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+static const char *avpr_example2_fqn = "test.ns.structB";
+
const char *example2_input = "{ \
\"byte\" : 42, \
\"long1\" : 232, \
@@ -93,7 +200,7 @@ struct example2 {
};
static void check_example2(void *data) {
- struct example2 *ex = (struct example2 *)data;
+ auto ex = static_cast<example2*>(data);
CHECK_EQUAL(42, ex->byte);
LONGS_EQUAL(232, ex->long1);
LONGS_EQUAL(242, ex->long2);
@@ -107,6 +214,32 @@ static void check_example2(void *data) {
/** sequence with a simple type **************/
const char *example3_descriptor = "{[I numbers}";
+static const char *avpr_example3_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Sint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structC\", \
+ \"fields\" : [{\
+ \"name\" : \"numbers\", \
+ \"type\" : {\
+ \"type\" : \"array\", \
+ \"items\" : \"Sint\", \
+ \"static\" : 3 \
+ }\
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+static const char *avpr_example3_fqn = "test.ns.structC";
+
const char *example3_input = "{ \
\"numbers\" : [22,32,42] \
}";
@@ -120,7 +253,7 @@ struct example3 {
};
static void check_example3(void *data) {
- struct example3 *ex = (struct example3 *)data;
+ auto ex = static_cast<example3*>(data);
CHECK_EQUAL(3, ex->numbers.len);
CHECK_EQUAL(22, ex->numbers.buf[0]);
CHECK_EQUAL(32, ex->numbers.buf[1]);
@@ -131,6 +264,50 @@ static void check_example3(void *data) {
/** structs within a struct (by reference)*******/
const char *example4_descriptor = "{{IDD index val1 val2}{IDD index val1 val2} left right}";
+static const char *avpr_example4_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Int32\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Double\", \
+ \"size\" : 8, \
+ \"alias\" : \"double\" \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"leaf\", \
+ \"namespace\" : \"details\", \
+ \"fields\" : [{\
+ \"name\" : \"index\", \
+ \"type\" : \"test.ns.Int32\" \
+ }, {\
+ \"name\" : \"val1\", \
+ \"type\" : \"test.ns.Double\" \
+ }, {\
+ \"name\" : \"val2\", \
+ \"type\" : \"test.ns.Double\" \
+ }]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structD\", \
+ \"fields\" : [{\
+ \"name\" : \"left\", \
+ \"type\" : \"details.leaf\" \
+ }, {\
+ \"name\" : \"right\", \
+ \"type\" : \"details.leaf\" \
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+static const char *avpr_example4_fqn = "test.ns.structD";
+
static const char *example4_input = "{ \
\"left\" : {\"index\":1, \"val1\":1.0, \"val2\":2.0 }, \
\"right\" : {\"index\":2, \"val1\":5.0, \"val2\":4.0 } \
@@ -148,7 +325,7 @@ struct example4 {
};
static void check_example4(void *data) {
- struct example4 *ex = (struct example4 *)data;
+ auto ex = static_cast<example4*>(data);
CHECK_EQUAL(1, ex->left.index);
CHECK_EQUAL(1.0, ex->left.val1);
CHECK_EQUAL(2.0, ex->left.val2);
@@ -162,12 +339,72 @@ static void check_example4(void *data) {
/** structs within a struct (by reference)*******/
const char *example5_descriptor = "Tleaf={ts name age};Tnode={Lnode;Lnode;Lleaf; left right value};{Lnode; head}";
+static const char *avpr_example5_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Char\", \
+ \"size\" : 2 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Str\", \
+ \"size\" : 8, \
+ \"alias\" : \"string\" \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"leaf\", \
+ \"namespace\" : \"details\", \
+ \"fields\" : [{\
+ \"name\" : \"name\", \
+ \"type\" : \"test.ns.Str\" \
+ }, {\
+ \"name\" : \"age\", \
+ \"type\" : \"test.ns.Char\" \
+ }]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"node\", \
+ \"fields\" : [{\
+ \"name\" : \"left\", \
+ \"type\" : \"node\", \
+ \"ptr\" : true \
+ }, {\
+ \"name\" : \"right\", \
+ \"type\" : \"node\", \
+ \"ptr\" : true \
+ }, {\
+ \"name\" : \"value\", \
+ \"type\" : \"details.leaf\", \
+ \"ptr\" : true \
+ }]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structE\", \
+ \"fields\" : [{\
+ \"name\" : \"head\", \
+ \"type\" : \"node\", \
+ \"ptr\" : true \
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+static const char *avpr_example5_fqn = "test.ns.structE";
+
static const char *example5_input = "{ \
\"head\" : {\
\"left\" : {\
\"value\" : {\
\"name\" : \"John\",\
\"age\" : 44 \
+ },\
+ \"left\" : {\
+ \"value\" : {\
+ \"name\" : \"Victor\",\
+ \"age\" : 400 \
+ }\
}\
},\
\"right\" : {\
@@ -195,27 +432,68 @@ struct example5 {
};
static void check_example5(void *data) {
- struct example5 *ex = (struct example5 *)data;
- CHECK_TRUE(ex->head != NULL);
+ auto ex = static_cast<example5*>(data);
+ CHECK_TRUE(ex->head != nullptr);
- CHECK(ex->head->left != NULL);
- CHECK(ex->head->left->value != NULL);
+ CHECK(ex->head->left != nullptr);
+ CHECK(ex->head->left->value != nullptr);
STRCMP_EQUAL("John", ex->head->left->value->name);
CHECK_EQUAL(44, ex->head->left->value->age);
- CHECK(ex->head->left->left == NULL);
- CHECK(ex->head->left->right == NULL);
-
- CHECK(ex->head->right != NULL);
- CHECK(ex->head->right->value != NULL);
+ CHECK(ex->head->left->right == nullptr);
+ CHECK(ex->head->left->left != nullptr);
+ CHECK(ex->head->left->left->value != nullptr);
+ STRCMP_EQUAL("Victor", ex->head->left->left->value->name);
+ CHECK_EQUAL(400, ex->head->left->left->value->age);
+
+ CHECK(ex->head->right != nullptr);
+ CHECK(ex->head->right->value != nullptr);
STRCMP_EQUAL("Peter", ex->head->right->value->name);
CHECK_EQUAL(55, ex->head->right->value->age);
- CHECK(ex->head->right->left == NULL);
- CHECK(ex->head->right->right == NULL);
+ CHECK(ex->head->right->left == nullptr);
+ CHECK(ex->head->right->right == nullptr);
}
+/*********** example 6 ************************/
static const char *example6_descriptor = "Tsample={DD v1 v2};[lsample;";
-static const char *example6_input = "[{\"v1\":0.1,\"v2\":0.2},{\"v1\":1.1,\"v2\":1.2},{\"v1\":2.1,\"v2\":2.2}]";
+static const char *avpr_example6_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Double\", \
+ \"alias\" : \"double\", \
+ \"size\" : 8 \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"sample\", \
+ \"fields\" : [{\
+ \"name\" : \"v1\", \
+ \"type\" : \"Double\" \
+ }, {\
+ \"name\" : \"v2\", \
+ \"type\" : \"Double\" \
+ }]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structF\", \
+ \"fields\" : [{\
+ \"name\" : \"samples\", \
+ \"type\" : { \
+ \"type\" : \"array\",\
+ \"items\" : \"sample\"\
+ }\
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+static const char *avpr_example6_fqn = "test.ns.structF";
+
+static const char *example6_input = R"([{"v1":0.1,"v2":0.2},{"v1":1.1,"v2":1.2},{"v1":2.1,"v2":2.2}])";
+static const char *avpr_example6_input = R"({
+ "samples" : [{"v1":0.1,"v2":0.2},{"v1":1.1,"v2":1.2},{"v1":2.1,"v2":2.2}]
+})";
struct ex6_sample {
double v1;
@@ -228,6 +506,10 @@ struct ex6_sequence {
struct ex6_sample *buf;
};
+struct ex6_avpr_struct {
+ struct ex6_sequence samples;
+};
+
static void check_example6(struct ex6_sequence seq) {
CHECK_EQUAL(3, seq.cap);
CHECK_EQUAL(3, seq.len);
@@ -239,10 +521,44 @@ static void check_example6(struct ex6_sequence seq) {
CHECK_EQUAL(2.2, seq.buf[2].v2);
}
+static void check_example6_avpr(void *data) {
+ auto ex = static_cast<ex6_avpr_struct*>(data);
+ CHECK_EQUAL(3, ex->samples.cap);
+ CHECK_EQUAL(3, ex->samples.len);
+ CHECK_EQUAL(0.1, ex->samples.buf[0].v1);
+ CHECK_EQUAL(0.2, ex->samples.buf[0].v2);
+ CHECK_EQUAL(1.1, ex->samples.buf[1].v1);
+ CHECK_EQUAL(1.2, ex->samples.buf[1].v2);
+ CHECK_EQUAL(2.1, ex->samples.buf[2].v1);
+ CHECK_EQUAL(2.2, ex->samples.buf[2].v2);
+}
/*********** example 7 ************************/
const char *example7_descriptor = "{t a}";
+static const char *avpr_example7_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Str\", \
+ \"size\" : 8, \
+ \"alias\" : \"string\" \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structG\", \
+ \"fields\" : [{\
+ \"name\" : \"a\", \
+ \"type\" : \"Str\" \
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+
+static const char *avpr_example7_fqn = "test.ns.structG";
+
const char *example7_input = "{ \
\"a\" : \"apache celix\" \
}";
@@ -252,7 +568,7 @@ struct example7 {
};
static void check_example7(void *data) {
- struct example7 *ex = (struct example7 *)data;
+ auto ex = static_cast<example7*>(data);
STRCMP_EQUAL("apache celix", ex->a);
}
@@ -261,6 +577,66 @@ static void check_example7(void *data) {
const char *example8_descriptor = "{ZbijNP a b c d e f}";
+static const char *avpr_example8_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Bool\", \
+ \"alias\" : \"boolean\", \
+ \"size\" : 1 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"UChar\", \
+ \"size\" : 1 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Uint\", \
+ \"size\" : 4 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Ulong\", \
+ \"size\" : 8 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Sint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"VoidPtr\", \
+ \"size\" : 1, \
+ \"alias\" : \"void_ptr\" \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structH\", \
+ \"fields\" : [{\
+ \"name\" : \"a\", \
+ \"type\" : \"Bool\" \
+ }, {\
+ \"name\" : \"b\", \
+ \"type\" : \"UChar\" \
+ }, {\
+ \"name\" : \"c\", \
+ \"type\" : \"Uint\" \
+ }, {\
+ \"name\" : \"d\", \
+ \"type\" : \"Ulong\" \
+ }, {\
+ \"name\" : \"e\", \
+ \"type\" : \"Sint\" \
+ }, {\
+ \"name\" : \"f\", \
+ \"type\" : \"VoidPtr\" \
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+
+static const char *avpr_example8_fqn = "test.ns.structH";
+
const char *example8_input = "{ \
\"a\" : true, \
\"b\" : 4, \
@@ -279,24 +655,212 @@ struct example8 {
};
static void check_example8(void *data) {
- struct example8 *ex = (struct example8 *)data;
+ auto ex = static_cast<example8*>(data);
CHECK_EQUAL(true,ex->a);
CHECK_EQUAL(4,ex->b);
CHECK_EQUAL(8,ex->c);
//error on mac CHECK_EQUAL(16,ex->d);
- CHECK(16 == ex->d)
+ CHECK(16 == ex->d);
CHECK_EQUAL(32,ex->e);
}
+/*********** example 9 ************************/
+const char *example9_descriptor = "{It#OK=0;#NOK=1;#MAYBE=2;E id name result}";
+
+static const char *avpr_example9_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"2.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Sint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"String\", \
+ \"alias\" : \"string\", \
+ \"size\" : 8 \
+ }, { \
+ \"type\" : \"enum\", \
+ \"name\" : \"ResultEnum\", \
+ \"EnumValues\" : [ \"OK = 0\", \"NOK= 1\", \"MAYBE =2\" ],\
+ \"symbols\" : [\"OK\", \"NOK\", \"MAYBE\" ]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structI\", \
+ \"fields\" : [{\
+ \"name\" : \"id\", \
+ \"type\" : \"Sint\" \
+ }, {\
+ \"name\" : \"name\", \
+ \"type\" : \"String\" \
+ }, {\
+ \"name\" : \"result\", \
+ \"type\" : \"ResultEnum\" \
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+static const char *avpr_example9_fqn = "test.ns.structI";
+
+const char *example9_input_1 = "{\
+ \"id\" : 1000, \
+ \"name\" : \"my_name\", \
+ \"result\" : \"NOK\" \
+ }";
+
+const char *example9_input_2 = "{\
+ \"id\" : 1001, \
+ \"name\" : \"your_name\", \
+ \"result\" : \"MAYBE\" \
+ }";
+
+const char *example9_input_3 =
+ R"({
+ "id" : 1001,
+ "name" : "your_name",
+ "result" : "OK"
+ })";
+
+enum ResultEnum {
+ RE_OK = 0,
+ RE_NOK = 1,
+ RE_MAYBE = 2
+};
+
+struct example9 {
+ int32_t id;
+ char * name;
+ enum ResultEnum result;
+};
+
+static void check_example9_1(void *data) {
+ auto ex = static_cast<example9*>(data);
+ CHECK_EQUAL(1000, ex->id);
+ STRCMP_EQUAL("my_name", ex->name);
+ CHECK_EQUAL(RE_NOK, ex->result);
+}
+
+static void check_example9_2(void *data) {
+ auto ex = static_cast<example9*>(data);
+ CHECK_EQUAL(1001, ex->id);
+ STRCMP_EQUAL("your_name", ex->name);
+ CHECK_EQUAL(RE_MAYBE, ex->result);
+}
+
+static void check_example9_3(void *data) {
+ auto ex = static_cast<example9*>(data);
+ CHECK_EQUAL(1001, ex->id);
+ STRCMP_EQUAL("your_name", ex->name);
+ CHECK_EQUAL(RE_OK, ex->result);
+}
-static void parseTests(void) {
+static void parseAvprTests() {
+ dyn_type *type;
+ void *inst;
+ int rc;
+
+ inst = nullptr;
+ type = dynType_parseAvprWithStr(avpr_example1_descriptor, avpr_example1_fqn);
+ CHECK(type != nullptr);
+ rc = jsonSerializer_deserialize(type, example1_input, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example1(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
+
+ inst = nullptr;
+ type = dynType_parseAvprWithStr(avpr_example2_descriptor, avpr_example2_fqn);
+ CHECK(type != nullptr);
+ rc = jsonSerializer_deserialize(type, example2_input, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example2(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
+
+ inst = nullptr;
+ type = dynType_parseAvprWithStr(avpr_example3_descriptor, avpr_example3_fqn);
+ CHECK(type != nullptr);
+ rc = jsonSerializer_deserialize(type, example3_input, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example3(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
+
+ inst = nullptr;
+ type = dynType_parseAvprWithStr(avpr_example4_descriptor, avpr_example4_fqn);
+ CHECK(type != nullptr);
+ rc = jsonSerializer_deserialize(type, example4_input, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example4(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
+
+ inst = nullptr;
+ type = dynType_parseAvprWithStr(avpr_example5_descriptor, avpr_example5_fqn);
+ CHECK(type != nullptr);
+ rc = jsonSerializer_deserialize(type, example5_input, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example5(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
+
+ // Test 6 has custom checker because avdl does not allow an array to be a type on its own
+ inst = nullptr;
+ type = dynType_parseAvprWithStr(avpr_example6_descriptor, avpr_example6_fqn);
+ CHECK(type != nullptr);
+ rc = jsonSerializer_deserialize(type, avpr_example6_input, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example6_avpr(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
+
+ inst = nullptr;
+ type = dynType_parseAvprWithStr(avpr_example7_descriptor, avpr_example7_fqn);
+ CHECK(type != nullptr);
+ rc = jsonSerializer_deserialize(type, example7_input, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example7(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
+
+ inst = nullptr;
+ type = dynType_parseAvprWithStr(avpr_example8_descriptor, avpr_example8_fqn);
+ CHECK(type != nullptr);
+ rc = jsonSerializer_deserialize(type, example8_input, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example8(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
+
+ inst = nullptr;
+ type = dynType_parseAvprWithStr(avpr_example9_descriptor, avpr_example9_fqn);
+ CHECK(type != nullptr);
+ rc = jsonSerializer_deserialize(type, example9_input_1, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example9_1(inst);
+ dynType_free(type, inst);
+ rc = jsonSerializer_deserialize(type, example9_input_2, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example9_2(inst);
+ dynType_free(type, inst);
+ rc = jsonSerializer_deserialize(type, example9_input_3, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example9_3(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
+}
+
+static void parseTests() {
dyn_type *type;
void *inst;
int rc;
- type = NULL;
- inst = NULL;
- rc = dynType_parseWithStr(example1_descriptor, NULL, NULL, &type);
+ type = nullptr;
+ inst = nullptr;
+ rc = dynType_parseWithStr(example1_descriptor, nullptr, nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_deserialize(type, example1_input, &inst);
CHECK_EQUAL(0, rc);
@@ -304,9 +868,9 @@ static void parseTests(void) {
dynType_free(type, inst);
dynType_destroy(type);
- type = NULL;
- inst = NULL;
- rc = dynType_parseWithStr(example2_descriptor, NULL, NULL, &type);
+ type = nullptr;
+ inst = nullptr;
+ rc = dynType_parseWithStr(example2_descriptor, nullptr, nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_deserialize(type, example2_input, &inst);
CHECK_EQUAL(0, rc);
@@ -314,9 +878,9 @@ static void parseTests(void) {
dynType_free(type, inst);
dynType_destroy(type);
- type = NULL;
- inst = NULL;
- rc = dynType_parseWithStr(example3_descriptor, NULL, NULL, &type);
+ type = nullptr;
+ inst = nullptr;
+ rc = dynType_parseWithStr(example3_descriptor, nullptr, nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_deserialize(type, example3_input, &inst);
CHECK_EQUAL(0, rc);
@@ -324,9 +888,9 @@ static void parseTests(void) {
dynType_free(type, inst);
dynType_destroy(type);
- type = NULL;
- inst = NULL;
- rc = dynType_parseWithStr(example4_descriptor, NULL, NULL, &type);
+ type = nullptr;
+ inst = nullptr;
+ rc = dynType_parseWithStr(example4_descriptor, nullptr, nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_deserialize(type, example4_input, &inst);
CHECK_EQUAL(0, rc);
@@ -334,9 +898,9 @@ static void parseTests(void) {
dynType_free(type, inst);
dynType_destroy(type);
- type = NULL;
- inst = NULL;
- rc = dynType_parseWithStr(example5_descriptor, NULL, NULL, &type);
+ type = nullptr;
+ inst = nullptr;
+ rc = dynType_parseWithStr(example5_descriptor, nullptr, nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_deserialize(type, example5_input, &inst);
CHECK_EQUAL(0, rc);
@@ -344,9 +908,9 @@ static void parseTests(void) {
dynType_free(type, inst);
dynType_destroy(type);
- type = NULL;
+ type = nullptr;
struct ex6_sequence *seq;
- rc = dynType_parseWithStr(example6_descriptor, NULL, NULL, &type);
+ rc = dynType_parseWithStr(example6_descriptor, nullptr, nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_deserialize(type, example6_input, (void **)&seq);
CHECK_EQUAL(0, rc);
@@ -354,10 +918,9 @@ static void parseTests(void) {
dynType_free(type, seq);
dynType_destroy(type);
-
- type = NULL;
- inst = NULL;
- rc = dynType_parseWithStr(example7_descriptor, NULL, NULL, &type);
+ type = nullptr;
+ inst = nullptr;
+ rc = dynType_parseWithStr(example7_descriptor, nullptr, nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_deserialize(type, example7_input, &inst);
CHECK_EQUAL(0, rc);
@@ -365,19 +928,140 @@ static void parseTests(void) {
dynType_free(type, inst);
dynType_destroy(type);
- type = NULL;
- inst = NULL;
- rc = dynType_parseWithStr(example8_descriptor, NULL, NULL, &type);
+ type = nullptr;
+ inst = nullptr;
+ rc = dynType_parseWithStr(example8_descriptor, nullptr, nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_deserialize(type, example8_input, &inst);
CHECK_EQUAL(0, rc);
check_example8(inst);
dynType_free(type, inst);
dynType_destroy(type);
+
+ type = nullptr;
+ inst = nullptr;
+ rc = dynType_parseWithStr(example9_descriptor, nullptr, nullptr, &type);
+ CHECK_EQUAL(0, rc);
+ rc = jsonSerializer_deserialize(type, example9_input_1, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example9_1(inst);
+ dynType_free(type, inst);
+ rc = jsonSerializer_deserialize(type, example9_input_2, &inst);
+ CHECK_EQUAL(0, rc);
+ check_example9_2(inst);
+ dynType_free(type, inst);
+ dynType_destroy(type);
}
+/*********** write example 1 ************************/
const char *write_example1_descriptor = "{BSIJsijFDNZb a b c d e f g h i j k l}";
+const char *avpr_write_example1_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"SChar\", \
+ \"signed\" : true, \
+ \"size\" : 1 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Short\", \
+ \"size\" : 2, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Sint\", \
+ \"size\" : 4, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Slong\", \
+ \"size\" : 8, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"UShort\", \
+ \"size\" : 2 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Uint\", \
+ \"size\" : 4 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Ulong\", \
+ \"size\" : 8 \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Float\", \
+ \"size\" : 4, \
+ \"alias\" : \"float\" \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Double\", \
+ \"size\" : 8, \
+ \"alias\" : \"double\" \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"NativeInt\", \
+ \"size\" : 4, \
+ \"alias\" : \"native_int\" \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Bool\", \
+ \"size\" : 1, \
+ \"alias\" : \"boolean\" \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"UChar\", \
+ \"size\" : 1 \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structAW\", \
+ \"fields\" : [{\
+ \"name\" : \"a\", \
+ \"type\" : \"SChar\" \
+ }, {\
+ \"name\" : \"b\", \
+ \"type\" : \"Short\" \
+ }, {\
+ \"name\" : \"c\", \
+ \"type\" : \"Sint\" \
+ }, {\
+ \"name\" : \"d\", \
+ \"type\" : \"Slong\" \
+ }, {\
+ \"name\" : \"e\", \
+ \"type\" : \"UShort\" \
+ }, {\
+ \"name\" : \"f\", \
+ \"type\" : \"Uint\" \
+ }, {\
+ \"name\" : \"g\", \
+ \"type\" : \"Ulong\" \
+ }, {\
+ \"name\" : \"h\", \
+ \"type\" : \"Float\" \
+ }, {\
+ \"name\" : \"i\", \
+ \"type\" : \"Double\" \
+ }, {\
+ \"name\" : \"j\", \
+ \"type\" : \"NativeInt\" \
+ }, {\
+ \"name\" : \"k\", \
+ \"type\" : \"Bool\" \
+ }, {\
+ \"name\" : \"l\", \
+ \"type\" : \"UChar\" \
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+const char *avpr_write_example1_fqn = "test.ns.structAW";
+
struct write_example1 {
char a;
int16_t b;
@@ -394,71 +1078,133 @@ struct write_example1 {
};
void writeTest1(void) {
- struct write_example1 ex1;
- ex1.a=1;
- ex1.b=2;
- ex1.c=3;
- ex1.d=4;
- ex1.e=5;
- ex1.f=6;
- ex1.g=7;
- ex1.h=8.8f;
- ex1.i=9.9;
- ex1.j=10;
- ex1.k=true;
- ex1.l=12;
-
- dyn_type *type = NULL;
- char *result = NULL;
- int rc = dynType_parseWithStr(write_example1_descriptor, "ex1", NULL, &type);
+ write_example1 ex1 {'A',2,3,4,5,6,7,8.8f,9.9,10,true,12};
+ ex1.k = !ex1.k;
+
+ dyn_type *type = nullptr;
+ char *result = nullptr;
+ int rc = dynType_parseWithStr(write_example1_descriptor, "ex1", nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_serialize(type, &ex1, &result);
CHECK_EQUAL(0, rc);
- STRCMP_CONTAINS("\"a\":1", result);
- STRCMP_CONTAINS("\"b\":2", result);
- STRCMP_CONTAINS("\"c\":3", result);
- STRCMP_CONTAINS("\"d\":4", result);
- STRCMP_CONTAINS("\"e\":5", result);
- STRCMP_CONTAINS("\"f\":6", result);
- STRCMP_CONTAINS("\"g\":7", result);
- STRCMP_CONTAINS("\"h\":8.8", result);
- STRCMP_CONTAINS("\"i\":9.9", result);
- STRCMP_CONTAINS("\"j\":10", result);
- STRCMP_CONTAINS("\"k\":true", result);
- STRCMP_CONTAINS("\"l\":12", result);
+ STRCMP_CONTAINS(R"("a":65)", result);
+ STRCMP_CONTAINS(R"("b":2)", result);
+ STRCMP_CONTAINS(R"("c":3)", result);
+ STRCMP_CONTAINS(R"("d":4)", result);
+ STRCMP_CONTAINS(R"("e":5)", result);
+ STRCMP_CONTAINS(R"("f":6)", result);
+ STRCMP_CONTAINS(R"("g":7)", result);
+ STRCMP_CONTAINS(R"("h":8.8)", result);
+ STRCMP_CONTAINS(R"("i":9.9)", result);
+ STRCMP_CONTAINS(R"("j":10)", result);
+ STRCMP_CONTAINS(R"("k":false)", result);
+ STRCMP_CONTAINS(R"("l":12)", result);
//printf("example 1 result: '%s'\n", result);
dynType_destroy(type);
free(result);
}
+void writeAvprTest1(void) {
+ write_example1 ex1 {1,2,3,4,5,6,7,8.8f,9.9,10,true,12};
+
+ char *result = nullptr;
+ dyn_type *type = dynType_parseAvprWithStr(avpr_write_example1_descriptor, avpr_write_example1_fqn);
+ CHECK(type != nullptr);
+
+ int rc = jsonSerializer_serialize(type, &ex1, &result);
+ CHECK_EQUAL(0, rc);
+
+ STRCMP_CONTAINS(R"("a":1)", result);
+ STRCMP_CONTAINS(R"("b":2)", result);
+ STRCMP_CONTAINS(R"("c":3)", result);
+ STRCMP_CONTAINS(R"("d":4)", result);
+ STRCMP_CONTAINS(R"("e":5)", result);
+ STRCMP_CONTAINS(R"("f":6)", result);
+ STRCMP_CONTAINS(R"("g":7)", result);
+ STRCMP_CONTAINS(R"("h":8.8)", result);
+ STRCMP_CONTAINS(R"("i":9.9)", result);
+ STRCMP_CONTAINS(R"("j":10)", result);
+ STRCMP_CONTAINS(R"("k":true)", result);
+ STRCMP_CONTAINS(R"("l":12)", result);
+
+ dynType_destroy(type);
+ free(result);
+}
+
+/*********** write example 2 ************************/
const char *write_example2_descriptor = "{*{JJ a b}{SS c d} sub1 sub2}";
+const char *avpr_write_example2_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Short\", \
+ \"size\" : 2, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Slong\", \
+ \"size\" : 8, \
+ \"signed\" : true \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"SubPtr\", \
+ \"fields\" : [{\
+ \"name\" : \"a\", \
+ \"type\" : \"Slong\" \
+ }, {\
+ \"name\" : \"b\", \
+ \"type\" : \"Slong\" \
+ }]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"Sub\", \
+ \"fields\" : [{\
+ \"name\" : \"c\", \
+ \"type\" : \"Short\" \
+ }, {\
+ \"name\" : \"d\", \
+ \"type\" : \"Short\" \
+ }]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structBW\", \
+ \"fields\" : [{\
+ \"name\" : \"sub1\", \
+ \"ptr\" : true, \
+ \"type\" : \"SubPtr\" \
+ }, {\
+ \"name\" : \"sub2\", \
+ \"type\" : \"Sub\" \
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+const char *avpr_write_example2_fqn = "test.ns.structBW";
+
struct write_example2_sub {
int64_t a;
int64_t b;
};
struct write_example2 {
- struct write_example2_sub *sub1;
+ write_example2_sub *sub1;
struct {
int16_t c;
int16_t d;
- } sub2;
+ };
};
void writeTest2(void) {
- struct write_example2_sub sub1;
- sub1.a = 1;
- sub1.b = 2;
+ write_example2_sub sub1 {1,2};
+ write_example2 ex {&sub1, {3, 4}};
- struct write_example2 ex;
- ex.sub1=&sub1;
- ex.sub2.c = 3;
- ex.sub2.d = 4;
-
- dyn_type *type = NULL;
- char *result = NULL;
- int rc = dynType_parseWithStr(write_example2_descriptor, "ex2", NULL, &type);
+ dyn_type *type = nullptr;
+ char *result = nullptr;
+ int rc = dynType_parseWithStr(write_example2_descriptor, "ex2", nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_serialize(type, &ex, &result);
CHECK_EQUAL(0, rc);
@@ -471,8 +1217,78 @@ void writeTest2(void) {
free(result);
}
+void writeAvprTest2(void) {
+ write_example2_sub sub1 {0,0};
+ write_example2 ex {&sub1, {3, 4}};
+ ex.sub1->a = 1;
+ ex.sub1->b = 2;
+
+ char *result = nullptr;
+ dyn_type *type = dynType_parseAvprWithStr(avpr_write_example2_descriptor, avpr_write_example2_fqn);
+ CHECK(type != nullptr);
+
+ int rc = jsonSerializer_serialize(type, &ex, &result);
+ CHECK_EQUAL(0, rc);
+
+ STRCMP_CONTAINS("\"a\":1", result);
+ STRCMP_CONTAINS("\"b\":2", result);
+ STRCMP_CONTAINS("\"c\":3", result);
+ STRCMP_CONTAINS("\"d\":4", result);
+
+ dynType_destroy(type);
+ free(result);
+}
+
+/*********** write example 3 ************************/
const char *write_example3_descriptor = "Tperson={ti name age};[Lperson;";
+const char *avpr_write_example3_descriptor = "{\
+ \"protocol\" : \"types\", \
+ \"namespace\" : \"test.ns\", \
+ \"version\" : \"1.0.0\", \
+ \"types\" : [ { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Str\", \
+ \"size\" : 8, \
+ \"alias\" : \"string\" \
+ }, { \
+ \"type\" : \"fixed\", \
+ \"name\" : \"Uint\", \
+ \"size\" : 4 \
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"PersonPtr\", \
+ \"fields\" : [{\
+ \"name\" : \"p\", \
+ \"type\" : \"Person\", \
+ \"ptr\" : true \
+ }]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"Person\", \
+ \"fields\" : [{\
+ \"name\" : \"name\", \
+ \"type\" : \"Str\" \
+ }, {\
+ \"name\" : \"age\", \
+ \"type\" : \"Uint\" \
+ }]\
+ }, { \
+ \"type\" : \"record\", \
+ \"name\" : \"structCW\", \
+ \"fields\" : [{\
+ \"name\" : \"persons\", \
+ \"type\" : { \
+ \"type\" : \"array\",\
+ \"items\" : \"PersonPtr\"\
+ }\
+ }]\
+ }], \
+ \"messages\" : {} \
+ }";
+
+const char *avpr_write_example3_fqn = "test.ns.structCW";
+
struct write_example3_person {
const char *name;
uint32_t age;
@@ -481,37 +1297,24 @@ struct write_example3_person {
struct write_example3 {
uint32_t cap;
uint32_t len;
- struct write_example3_person **buf;
+ write_example3_person **buf;
};
void writeTest3(void) {
- struct write_example3_person p1;
- p1.name = "John";
- p1.age = 33;
-
- struct write_example3_person p2;
- p2.name = "Peter";
- p2.age = 44;
-
- struct write_example3_person p3;
- p3.name = "Carol";
- p3.age = 55;
+ write_example3_person p1 {"John", 33};
+ write_example3_person p2 {"Peter", 44};
+ write_example3_person p3 {"Carol", 55};
+ write_example3_person p4 {"Elton", 66};
- struct write_example3_person p4;
- p4.name = "Elton";
- p4.age = 66;
-
- struct write_example3 seq;
- seq.buf = (struct write_example3_person **) calloc(4, sizeof(void *));
- seq.len = seq.cap = 4;
+ write_example3 seq {4, 4, (struct write_example3_person **) calloc(4, sizeof(void *))};
seq.buf[0] = &p1;
seq.buf[1] = &p2;
seq.buf[2] = &p3;
seq.buf[3] = &p4;
- dyn_type *type = NULL;
- char *result = NULL;
- int rc = dynType_parseWithStr(write_example3_descriptor, "ex3", NULL, &type);
+ dyn_type *type = nullptr;
+ char *result = nullptr;
+ int rc = dynType_parseWithStr(write_example3_descriptor, "ex3", nullptr, &type);
CHECK_EQUAL(0, rc);
rc = jsonSerializer_serialize(type, &seq, &result);
CHECK_EQUAL(0, rc);
@@ -525,34 +1328,68 @@ void writeTest3(void) {
free(result);
}
+void writeAvprTest3(void) {
+ write_example3_person p1 {"John", 33};
+ write_example3_person p2 {"Peter", 44};
+ write_example3_person p3 {"Carol", 55};
+ write_example3_person p4 {"Elton", 66};
+
+ write_example3 seq {4, 4, (write_example3_person **) calloc(4, sizeof(void *))};
+ seq.buf[0] = &p1;
+ seq.buf[1] = &p2;
+ seq.buf[2] = &p3;
+ seq.buf[3] = &p4;
+
+ char *result = nullptr;
+ dyn_type *type = dynType_parseAvprWithStr(avpr_write_example3_descriptor, avpr_write_example3_fqn);
+ CHECK(type != nullptr);
+
+ int rc = jsonSerializer_serialize(type, &seq, &result);
+ CHECK_EQUAL(0, rc);
+ STRCMP_CONTAINS("\"age\":33", result);
+ STRCMP_CONTAINS("\"age\":44", result);
+ STRCMP_CONTAINS("\"age\":55", result);
+ STRCMP_CONTAINS("\"age\":66", result);
+ free(seq.buf);
+ dynType_destroy(type);
+ free(result);
}
+} // extern "C"
+
TEST_GROUP(JsonSerializerTests) {
- void setup() {
+ void setup() override {
int lvl = 1;
- dynCommon_logSetup(stdLog, NULL, lvl);
- dynType_logSetup(stdLog, NULL,lvl);
- jsonSerializer_logSetup(stdLog, NULL, lvl);
+ dynCommon_logSetup(stdLog, nullptr, lvl);
+ dynType_logSetup(stdLog, nullptr,lvl);
+ dynAvprType_logSetup(stdLog, nullptr,lvl);
+ dynTypeCommon_logSetup(stdLog, nullptr,lvl);
+ jsonSerializer_logSetup(stdLog, nullptr, lvl);
}
};
TEST(JsonSerializerTests, ParseTests) {
- //TODO split up
parseTests();
}
+TEST(JsonSerializerTests, ParseAvprTests) {
+ parseAvprTests();
+}
+
TEST(JsonSerializerTests, WriteTest1) {
writeTest1();
+ writeAvprTest1();
}
TEST(JsonSerializerTests, WriteTest2) {
writeTest2();
+ writeAvprTest2();
}
TEST(JsonSerializerTests, WriteTest3) {
writeTest3();
+ writeAvprTest3();
}
-
diff --git a/libs/framework/CMakeLists.txt b/libs/framework/CMakeLists.txt
index 63844fd..461514d 100644
--- a/libs/framework/CMakeLists.txt
+++ b/libs/framework/CMakeLists.txt
@@ -80,20 +80,20 @@ if (ENABLE_TESTING AND FRAMEWORK_TESTS)
private/mock/celix_log_mock.c)
target_link_libraries(attribute_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
-# add_executable(bundle_archive_test
-# private/mock/celix_log_mock.c
-# private/test/bundle_archive_test.cpp
-# src/bundle_revision.c
-# src/manifest.c
-# src/miniunz.c
-# src/unzip.c
-# src/ioapi.c
-# src/properties.c
-# src/bundle_archive.c
-# src/celix_errorcodes.c
-# src/utils.c)
-# target_link_libraries(bundle_archive_test Celix::utils ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} ${ZLIB_LIBRARY} pthread)
-
+# add_executable(bundle_archive_test
+# private/mock/celix_log_mock.c
+# private/test/bundle_archive_test.cpp #TODO: fix? contains invalid casts
+# src/bundle_revision.c
+# src/manifest.c
+# src/miniunz.c
+# src/unzip.c
+# src/ioapi.c
+# # src/properties.c
+# src/bundle_archive.c
+# src/celix_errorcodes.c
+# # src/utils.c
+# )
+# target_link_libraries(bundle_archive_test Celix::utils ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} ${ZLIB_LIBRARY} pthread)
add_executable(bundle_cache_test
private/test/bundle_cache_test.cpp
@@ -200,17 +200,18 @@ if (ENABLE_TESTING AND FRAMEWORK_TESTS)
private/mock/celix_log_mock.c)
target_link_libraries(manifest_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
-# add_executable(module_test
-# private/test/module_test.cpp
-# private/mock/bundle_mock.c
-# private/mock/version_mock.c
-# private/mock/manifest_mock.c
-# private/mock/manifest_parser_mock.c
-# private/mock/capability_mock.c
-# private/mock/requirement_mock.c
-# private/mock/wire_mock.c
-# src/module.c)
-# target_link_libraries(module_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
+# add_executable(module_test
+# private/test/module_test.cpp # TODO: fix invalid conversions from char ** to const char**
+# private/mock/bundle_mock.c
+# private/mock/version_mock.c
+# private/mock/manifest_mock.c
+# private/mock/manifest_parser_mock.c
+# private/mock/capability_mock.c
+# private/mock/requirement_mock.c
+# private/mock/wire_mock.c
+# src/module.c)
+# target_link_libraries(module_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
+# target_include_directories(module_test SYSTEM ${CPPUTEST_INCLUDE_DIR})
add_executable(requirement_test
private/test/requirement_test.cpp
@@ -222,19 +223,19 @@ if (ENABLE_TESTING AND FRAMEWORK_TESTS)
private/mock/celix_log_mock.c)
target_link_libraries(requirement_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
-# add_executable(resolver_test
-# private/test/resolver_test.cpp
-# private/mock/bundle_mock.c
-# private/mock/requirement_mock.c
-# private/mock/capability_mock.c
-# private/mock/manifest_parser_mock.c
-# private/mock/version_mock.c
-# src/wire.c
-# src/module.c
-# src/resolver.c
-# src/celix_errorcodes.c
-# private/mock/celix_log_mock.c)
-# target_link_libraries(resolver_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
+# add_executable(resolver_test
+# private/test/resolver_test.cpp #TODO: fix missing include
+# private/mock/bundle_mock.c
+# private/mock/requirement_mock.c
+# private/mock/capability_mock.c
+# private/mock/manifest_parser_mock.c
+# private/mock/version_mock.c
+# src/wire.c
+# src/module.c
+# src/resolver.c
+# src/celix_errorcodes.c
+# private/mock/celix_log_mock.c)
+# target_link_libraries(resolver_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
add_executable(service_reference_test
private/test/service_reference_test.cpp
@@ -254,7 +255,6 @@ if (ENABLE_TESTING AND FRAMEWORK_TESTS)
private/mock/celix_log_mock.c)
target_link_libraries(service_registration_test ${CPPUTEST_LIBRARY} ${CPPUTEST_EXT_LIBRARY} Celix::utils pthread)
-
add_executable(service_registry_test
private/test/service_registry_test.cpp
private/mock/framework_mock.c
diff --git a/libs/framework/tst/CMakeLists.txt b/libs/framework/tst/CMakeLists.txt
index 9b7dd97..76d0990 100644
--- a/libs/framework/tst/CMakeLists.txt
+++ b/libs/framework/tst/CMakeLists.txt
@@ -28,7 +28,9 @@ add_executable(test_framework
bundle_context_bundles_tests.cpp
bundle_context_services_test.cpp
)
+
target_link_libraries(test_framework Celix::framework ${CURL_LIBRARIES} ${CPPUTEST_LIBRARY})
+
add_dependencies(test_framework simple_test_bundle1_bundle simple_test_bundle2_bundle simple_test_bundle3_bundle simple_test_bundle4_bundle simple_test_bundle5_bundle)
target_include_directories(test_framework PRIVATE ../src)