blob: 57aa34eccbc0fd1e6816f4c145af18f3e5f5cb42 [file]
/*
* 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 "gtest/gtest.h"
extern "C" {
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <ffi.h>
#include "dyn_type_common.h"
#include "dyn_common.h"
#include "dyn_type.h"
#include "json_serializer.h"
#include "celix_properties.h"
#include "celix_array_list.h"
#include "celix_err.h"
#include <jansson.h>
/*********** example 1 ************************/
/** struct type ******************************/
const char *example1_descriptor = "{DJISF a b c d e}";
const char *example1_input = "{ \
\"a\" : 1.0, \
\"b\" : 22, \
\"c\" : 32, \
\"d\" : 42, \
\"e\" : 4.4 \
}";
struct example1 {
double a; //0
int64_t b; //1
int32_t c; //2
int16_t d; //3
float e; //4
};
static void check_example1(void *data) {
auto ex = static_cast<example1*>(data);
ASSERT_EQ(1.0, ex->a);
ASSERT_EQ(22, ex->b);
ASSERT_EQ(32, ex->c);
ASSERT_EQ(42, ex->d);
ASSERT_EQ(4.4f, ex->e);
}
/*********** example 2 ************************/
const char *example2_descriptor = "{BJJDFD byte long1 long2 double1 float1 double2}";
const char *example2_input = "{ \
\"byte\" : 42, \
\"long1\" : 232, \
\"long2\" : 242, \
\"double1\" : 4.2, \
\"float1\" : 3.2, \
\"double2\" : 4.4 \
}";
struct example2 {
char byte; //0
int64_t long1; //1
int64_t long2; //2
double double1; //3
float float1; //4
double double2; //5
};
static void check_example2(void *data) {
auto ex = static_cast<example2*>(data);
ASSERT_EQ(42, ex->byte);
ASSERT_EQ(232, ex->long1);
ASSERT_EQ(242, ex->long2);
ASSERT_EQ(4.2, ex->double1);
ASSERT_EQ(3.2f, ex->float1);
ASSERT_EQ(4.4, ex->double2);
}
/*********** example 3 ************************/
/** sequence with a simple type **************/
const char *example3_descriptor = "{[I numbers}";
const char *example3_input = "{ \
\"numbers\" : [22,32,42] \
}";
struct example3 {
struct {
uint32_t cap;
uint32_t len;
int32_t *buf;
} numbers;
};
static void check_example3(void *data) {
auto ex = static_cast<example3*>(data);
ASSERT_EQ(3, ex->numbers.len);
ASSERT_EQ(22, ex->numbers.buf[0]);
ASSERT_EQ(32, ex->numbers.buf[1]);
ASSERT_EQ(42, ex->numbers.buf[2]);
}
/*********** example 4 ************************/
/** structs within a struct (by reference)*******/
const char *example4_descriptor = "{{IDD index val1 val2}{IDD index val1 val2} left right}";
static const char *example4_input = "{ \
\"left\" : {\"index\":1, \"val1\":1.0, \"val2\":2.0 }, \
\"right\" : {\"index\":2, \"val1\":5.0, \"val2\":4.0 } \
}";
struct ex4_leaf {
int32_t index;
double val1;
double val2;
};
struct example4 {
struct ex4_leaf left;
struct ex4_leaf right;
};
static void check_example4(void *data) {
auto ex = static_cast<example4*>(data);
ASSERT_EQ(1, ex->left.index);
ASSERT_EQ(1.0, ex->left.val1);
ASSERT_EQ(2.0, ex->left.val2);
ASSERT_EQ(2, ex->right.index);
ASSERT_EQ(5.0, ex->right.val1);
ASSERT_EQ(4.0, ex->right.val2);
}
/*********** example 5 ************************/
/** 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 *example5_input = "{ \
\"head\" : {\
\"left\" : {\
\"value\" : {\
\"name\" : \"John\",\
\"age\" : 44 \
},\
\"left\" : {\
\"left\" : null,\
\"right\" : null,\
\"value\" : {\
\"name\" : \"Victor\",\
\"age\" : 400 \
}\
},\
\"right\" : null\
},\
\"right\" : {\
\"left\" : null,\
\"right\" : null,\
\"value\" : {\
\"name\" : \"Peter\", \
\"age\" : 55 \
}\
},\
\"value\" : null\
}\
}";
struct leaf {
const char *name;
uint16_t age;
};
struct node {
struct node *left;
struct node *right;
struct leaf *value;
};
struct example5 {
struct node *head;
};
static void check_example5(void *data) {
auto ex = static_cast<example5*>(data);
ASSERT_TRUE(ex->head != nullptr);
ASSERT_TRUE(ex->head->left != nullptr);
ASSERT_TRUE(ex->head->left->value != nullptr);
ASSERT_STREQ("John", ex->head->left->value->name);
ASSERT_EQ(44, ex->head->left->value->age);
ASSERT_TRUE(ex->head->left->right == nullptr);
ASSERT_TRUE(ex->head->left->left != nullptr);
ASSERT_TRUE(ex->head->left->left->value != nullptr);
ASSERT_STREQ("Victor", ex->head->left->left->value->name);
ASSERT_EQ(400, ex->head->left->left->value->age);
ASSERT_TRUE(ex->head->right != nullptr);
ASSERT_TRUE(ex->head->right->value != nullptr);
ASSERT_STREQ("Peter", ex->head->right->value->name);
ASSERT_EQ(55, ex->head->right->value->age);
ASSERT_TRUE(ex->head->right->left == nullptr);
ASSERT_TRUE(ex->head->right->right == nullptr);
ASSERT_TRUE(ex->head->value == nullptr);
}
/*********** example 6 ************************/
static const char *example6_descriptor = "Tsample={DD v1 v2};[lsample;";
static const char *example6_input = R"([{"v1":0.1,"v2":0.2},{"v1":1.1,"v2":1.2},{"v1":2.1,"v2":2.2}])";
struct ex6_sample {
double v1;
double v2;
};
struct ex6_sequence {
uint32_t cap;
uint32_t len;
struct ex6_sample *buf;
};
static void check_example6(struct ex6_sequence seq) {
ASSERT_EQ(3, seq.cap);
ASSERT_EQ(3, seq.len);
ASSERT_EQ(0.1, seq.buf[0].v1);
ASSERT_EQ(0.2, seq.buf[0].v2);
ASSERT_EQ(1.1, seq.buf[1].v1);
ASSERT_EQ(1.2, seq.buf[1].v2);
ASSERT_EQ(2.1, seq.buf[2].v1);
ASSERT_EQ(2.2, seq.buf[2].v2);
}
/*********** example 7 ************************/
const char *example7_descriptor = "{t a}";
const char *example7_input = "{ \
\"a\" : \"apache celix\" \
}";
struct example7 {
char* a; //0
};
static void check_example7(void *data) {
auto ex = static_cast<example7*>(data);
ASSERT_STREQ("apache celix", ex->a);
}
/*********** example 8 ************************/
const char *example8_descriptor = "{ZbijNP a b c d e f}";
const char *example8_input = "{ \
\"a\" : true, \
\"b\" : 4, \
\"c\" : 8, \
\"d\" : 16, \
\"e\" : 32 \
}";
/*********** example 9 ************************/
const char *example9_descriptor = "{It#OK=0;#NOK=1;#MAYBE=2;E id name result}";
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);
ASSERT_EQ(1000, ex->id);
ASSERT_STREQ("my_name", ex->name);
ASSERT_EQ(RE_NOK, ex->result);
}
static void check_example9_2(void *data) {
auto ex = static_cast<example9*>(data);
ASSERT_EQ(1001, ex->id);
ASSERT_STREQ("your_name", ex->name);
ASSERT_EQ(RE_MAYBE, ex->result);
}
/*********** example A ************************/
const char *exampleA_descriptor = "TPoint={DD x y};{lPoint;lPoint;t point_a point_b name}";
const char *exampleA_input =
R"({
"point_a" : { "x" : 1.0, "y" : 2.0 },
"point_b" : { "x" : 3.0, "y" : 4.0 },
"name" : "this_is_my_name"
})";
struct exA_point {
double x;
double y;
};
struct exA_struct {
exA_point point_a;
exA_point point_b;
char* name;
};
static void check_exampleA(void *data) {
auto inp = static_cast<exA_struct*>(data);
ASSERT_EQ(1.0, inp->point_a.x);
ASSERT_EQ(2.0, inp->point_a.y);
ASSERT_EQ(3.0, inp->point_b.x);
ASSERT_EQ(4.0, inp->point_b.y);
ASSERT_STREQ("this_is_my_name", inp->name);
}
static void parseTests() {
dyn_type *type;
void *inst;
int rc;
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(example1_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, example1_input, strlen(example1_input), &inst);
ASSERT_EQ(0, rc);
check_example1(inst);
dynType_free(type, inst);
dynType_destroy(type);
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(example2_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, example2_input, strlen(example2_input), &inst);
ASSERT_EQ(0, rc);
check_example2(inst);
dynType_free(type, inst);
dynType_destroy(type);
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(example3_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, example3_input, strlen(example3_input), &inst);
ASSERT_EQ(0, rc);
check_example3(inst);
dynType_free(type, inst);
dynType_destroy(type);
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(example4_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, example4_input, strlen(example4_input), &inst);
ASSERT_EQ(0, rc);
check_example4(inst);
dynType_free(type, inst);
dynType_destroy(type);
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(example5_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, example5_input, strlen(example5_input), &inst);
ASSERT_EQ(0, rc);
check_example5(inst);
dynType_free(type, inst);
dynType_destroy(type);
type = nullptr;
struct ex6_sequence *seq;
rc = dynType_parseWithStr(example6_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, example6_input, strlen(example6_input), (void **)&seq);
ASSERT_EQ(0, rc);
check_example6((*seq));
dynType_free(type, seq);
dynType_destroy(type);
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(example7_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, example7_input, strlen(example7_input), &inst);
ASSERT_EQ(0, rc);
check_example7(inst);
dynType_free(type, inst);
dynType_destroy(type);
// missing object member "f"
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(example8_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, example8_input, strlen(example8_input), &inst);
ASSERT_NE(0, rc);
EXPECT_STREQ("Error cannot deserialize json. Input is '{ \"a\" : true, \"b\" : 4, \"c\" : 8, \"d\" : 16, \"e\" : 32 }'",
celix_err_popLastError());
dynType_destroy(type);
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(example9_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, example9_input_1, strlen(example9_input_1), &inst);
ASSERT_EQ(0, rc);
check_example9_1(inst);
dynType_free(type, inst);
rc = jsonSerializer_deserialize(type, example9_input_2, strlen(example9_input_2), &inst);
ASSERT_EQ(0, rc);
check_example9_2(inst);
dynType_free(type, inst);
dynType_destroy(type);
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(exampleA_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, exampleA_input, strlen(exampleA_input), &inst);
ASSERT_EQ(0, rc);
check_exampleA(inst);
dynType_free(type, inst);
dynType_destroy(type);
//parse ref by value
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr("Ttype={DD a b};ltype;", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
auto inputStr = R"({"a":1.0, "b":2.0})";
json_error_t error;
json_auto_t *input = json_loadb(inputStr, strlen(inputStr), JSON_DECODE_ANY, &error);
rc = jsonSerializer_deserializeJson(type, input, &inst);
ASSERT_EQ(0, rc);
struct {
double a;
double b;
} *data = static_cast<decltype(data)>(inst);
ASSERT_EQ(1.0, data->a);
ASSERT_EQ(2.0, data->b);
dynType_free(type, inst);
dynType_destroy(type);
//invalid input
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr("{DD a b}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_deserialize(type, "invalid", strlen("invalid"), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
//double pointer unsupported
rc = dynType_parseWithStr("{*t a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":"hello world"})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
EXPECT_STREQ("Error cannot deserialize json. Input is '{\"a\":\"hello world\"}'", celix_err_popLastError());
EXPECT_STREQ("Error cannot deserialize pointer to pointer", celix_err_popLastError());
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
//text type mismatch
rc = dynType_parseWithStr("{t a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":1.0})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
//enum type mismatch
rc = dynType_parseWithStr("{#v1=1;#v2=2;E a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":1.0})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
//enum value unknown
rc = dynType_parseWithStr("{#v1=1;#v2=2;E a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":"v3"})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
//sequence element type mismatch
rc = dynType_parseWithStr("[t", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"([1.0, 2.0])";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
//unsupported untyped pointer
rc = dynType_parseWithStr("{P a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":1.0})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
// integer type mismatch - string instead of integer
rc = dynType_parseWithStr("{I a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":"not_an_integer"})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
// double type mismatch - string instead of double
rc = dynType_parseWithStr("{D a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":"not_a_double"})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
// boolean type mismatch - integer instead of boolean
rc = dynType_parseWithStr("{Z a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":1})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
// float type mismatch - string instead of float
rc = dynType_parseWithStr("{F a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":"not_a_float"})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
// integer type mismatches - string instead of integer for all remaining integer descriptors
const char *integerDescriptors[] = {"N", "B", "S", "J", "b", "s", "i", "j"};
for (const char *descriptor : integerDescriptors) {
char descriptorStr[8];
snprintf(descriptorStr, sizeof(descriptorStr), "{%s a}", descriptor);
rc = dynType_parseWithStr(descriptorStr, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":"not_an_integer"})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
char expectedErr[64];
snprintf(expectedErr, sizeof(expectedErr), "Expected json integer type but got %i", JSON_STRING);
EXPECT_STREQ("Error cannot deserialize json. Input is '{\"a\":\"not_an_integer\"}'", celix_err_popLastError());
EXPECT_STREQ(expectedErr, celix_err_popLastError());
dynType_destroy(type);
}
// extra member ("b") is allowed
rc = dynType_parseWithStr("{t a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":"hello", "b":"world"})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(0, rc);
dynType_free(type, inst);
dynType_destroy(type);
// parse complex from non-object
rc = dynType_parseWithStr("{t a}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"(["a"])";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
//simple string
rc = dynType_parseWithStr("t", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"("hello")";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(0, rc);
EXPECT_STREQ("hello", *(char**)inst);
dynType_free(type, inst);
dynType_destroy(type);
//null string
rc = dynType_parseWithStr("t", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"(null)";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(0, rc);
EXPECT_EQ(nullptr, *(char**)inst);
dynType_free(type, inst);
dynType_destroy(type);
// double*
rc = dynType_parseWithStr("*D", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"(0.1)";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(0, rc);
EXPECT_EQ(0.1, **(double**)inst);
dynType_free(type, inst);
dynType_destroy(type);
// null double*
rc = dynType_parseWithStr("*D", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"(null)";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
ASSERT_EQ(0, rc);
EXPECT_EQ(nullptr, *(double**)inst);
dynType_free(type, inst);
dynType_destroy(type);
// unnamed fields
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr("{DD}", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
inputStr = R"({"a":1.0, "b":2.0})";
rc = jsonSerializer_deserialize(type, inputStr, strlen(inputStr), &inst);
EXPECT_NE(0, rc);
EXPECT_STREQ("Error cannot deserialize json. Input is '{\"a\":1.0, \"b\":2.0}'", celix_err_popLastError());
EXPECT_STREQ("Unamed field unsupported", celix_err_popLastError());
dynType_destroy(type);
}
/*********** write example 1 ************************/
const char *write_example1_descriptor = "{BSIJsijFDNZb a b c d e f g h i j k l}";
struct write_example1 {
char a;
int16_t b;
int32_t c;
int64_t d;
uint16_t e;
uint32_t f;
uint64_t g;
float h;
double i;
int j;
bool k;
unsigned char l;
};
void writeTest1(void) {
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);
ASSERT_EQ(0, rc);
rc = jsonSerializer_serialize(type, &ex1, &result);
ASSERT_EQ(0, rc);
ASSERT_TRUE(strstr(result, R"("b":2)") != nullptr);
ASSERT_TRUE(strstr(result, R"("c":3)") != nullptr);
ASSERT_TRUE(strstr(result, R"("d":4)") != nullptr);
ASSERT_TRUE(strstr(result, R"("e":5)") != nullptr);
ASSERT_TRUE(strstr(result, R"("f":6)") != nullptr);
ASSERT_TRUE(strstr(result, R"("g":7)") != nullptr);
ASSERT_TRUE(strstr(result, R"("h":8.8)") != nullptr);
ASSERT_TRUE(strstr(result, R"("i":9.9)") != nullptr);
ASSERT_TRUE(strstr(result, R"("j":10)") != nullptr);
ASSERT_TRUE(strstr(result, R"("k":false)") != nullptr);
ASSERT_TRUE(strstr(result, R"("l":12)") != nullptr);
//printf("example 1 result: '%s'\n", result);
dynType_destroy(type);
free(result);
}
/*********** write example 2 ************************/
const char *write_example2_descriptor = "{*{JJ a b}{SS c d} sub1 sub2}";
struct write_example2_sub {
int64_t a;
int64_t b;
};
struct write_example2 {
write_example2_sub *sub1;
struct {
int16_t c;
int16_t d;
};
};
void writeTest2(void) {
write_example2_sub sub1 {1,2};
write_example2 ex {&sub1, {3, 4}};
dyn_type *type = nullptr;
char *result = nullptr;
int rc = dynType_parseWithStr(write_example2_descriptor, "ex2", nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_serialize(type, &ex, &result);
ASSERT_EQ(0, rc);
ASSERT_TRUE(strstr(result, "\"a\":1") != nullptr);
ASSERT_TRUE(strstr(result, "\"b\":2") != nullptr);
ASSERT_TRUE(strstr(result, "\"c\":3") != nullptr);
ASSERT_TRUE(strstr(result, "\"d\":4") != nullptr);
//printf("example 2 result: '%s'\n", result);
dynType_destroy(type);
free(result);
}
/*********** write example 3 ************************/
const char *write_example3_descriptor = "Tperson={ti name age};[Lperson;";
struct write_example3_person {
const char *name;
uint32_t age;
};
struct write_example3 {
uint32_t cap;
uint32_t len;
write_example3_person **buf;
};
void writeTest3(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, (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 = nullptr;
char *result = nullptr;
int rc = dynType_parseWithStr(write_example3_descriptor, "ex3", nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_serialize(type, &seq, &result);
ASSERT_EQ(0, rc);
ASSERT_TRUE(strstr(result, "\"age\":33") != nullptr);
ASSERT_TRUE(strstr(result, "\"age\":44") != nullptr);
ASSERT_TRUE(strstr(result, "\"age\":55") != nullptr);
ASSERT_TRUE(strstr(result, "\"age\":66") != nullptr);
//printf("example 3 result: '%s'\n", result);
free(seq.buf);
dynType_destroy(type);
free(result);
}
void writeEnum(void) {
dyn_type *type = nullptr;
char *result = nullptr;
int rc = dynType_parseWithStr(R"(#v1=1;#v2=2;E)", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
enum {
v1 = 1,
v2 = 2
}enumVal = v2;
rc = jsonSerializer_serialize(type, &enumVal, &result);
ASSERT_EQ(0, rc);
ASSERT_TRUE(strstr(result, R"(v2)") != nullptr);
free(result);
dynType_destroy(type);
}
void writeRefByVal(void) {
dyn_type *type = nullptr;
char *result = nullptr;
int rc = dynType_parseWithStr(R"(Ttype={DD a b};ltype;)", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
struct {
double a;
double b;
}input{1.0,2.0};
rc = jsonSerializer_serialize(type, &input, &result);
ASSERT_EQ(0, rc);
ASSERT_TRUE(strstr(result, R"("a":1.0)") != nullptr);
ASSERT_TRUE(strstr(result, R"("b":2.0)") != nullptr);
free(result);
dynType_destroy(type);
}
void writeSequenceFailed(void) {
dyn_type *type = nullptr;
char *result = nullptr;
int rc = dynType_parseWithStr(R"([D)", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
double input[] = {1.0,2.0};
struct {
uint32_t cap;
uint32_t len;
double *buf;
}seq{1,2,input};//cap < len
rc = jsonSerializer_serialize(type, &seq, &result);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
}
void writeComplexFailed(void) {
dyn_type *type = nullptr;
char *result = nullptr;
//has unnamed complex element
int rc = dynType_parseWithStr(R"({II a})", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
struct {
int32_t a;
int32_t b;
}input{1,2};
rc = jsonSerializer_serialize(type, &input, &result);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
}
void writeEnumFailed(void) {
dyn_type *type = nullptr;
char *result = nullptr;
int rc = dynType_parseWithStr(R"(#v1=1;#v2=2;E)", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
enum {
v1 = 1,
v2 = 2,
v3 = 3
}enumVal = v3;//schema only has v1 and v2
rc = jsonSerializer_serialize(type, &enumVal, &result);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
}
} // extern "C"
class JsonSerializerTests : public ::testing::Test {
public:
JsonSerializerTests() {
}
~JsonSerializerTests() override {
celix_err_resetErrors();
}
};
TEST_F(JsonSerializerTests, ParseTests) {
parseTests();
}
TEST_F(JsonSerializerTests, WriteTest1) {
writeTest1();
}
TEST_F(JsonSerializerTests, WriteTest2) {
writeTest2();
}
TEST_F(JsonSerializerTests, WriteTest3) {
writeTest3();
}
TEST_F(JsonSerializerTests, WriteEnum) {
writeEnum();
}
TEST_F(JsonSerializerTests, WriteRefByVal) {
writeRefByVal();
}
TEST_F(JsonSerializerTests, WriteSequenceFailed) {
writeSequenceFailed();
}
TEST_F(JsonSerializerTests, WriteSequenceFailed2) {
dyn_type* type = nullptr;
char* result = nullptr;
int rc = dynType_parseWithStr(R"([**D)", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
double** input[] = {nullptr};
struct {
uint32_t cap;
uint32_t len;
double*** buf;
}seq{1,1,input};
rc = jsonSerializer_serialize(type, &seq, &result);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, WriteComplexFailed) {
writeComplexFailed();
}
TEST_F(JsonSerializerTests, WriteComplexFailed2) {
dyn_type *type = nullptr;
char *result = nullptr;
int rc = dynType_parseWithStr(R"({**D a})", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
struct {
double** a;
}input{nullptr};
rc = jsonSerializer_serialize(type, &input, &result);
ASSERT_EQ(1, rc);
celix_err_printErrors(stderr, nullptr, nullptr);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, WriteEnumFailed) {
writeEnumFailed();
}
TEST_F(JsonSerializerTests, WriteDoublePointer) {
dyn_type *type;
int rc;
double val = 1.0;
double* valp = &val;
double** valpp = &valp;
char *result = nullptr;
rc = dynType_parseWithStr("**D", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
rc = jsonSerializer_serialize(type, &valpp, &result);
EXPECT_NE(0, rc);
EXPECT_STREQ("Error cannot serialize pointer to pointer", celix_err_popLastError());
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, SerializationDeserilizationTest) {
dyn_type *type;
void *inst;
int rc;
type = nullptr;
inst = nullptr;
rc = dynType_parseWithStr(example5_descriptor, nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_loads(example5_input, JSON_DECODE_ANY, NULL);
ASSERT_NE(nullptr, root);
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_EQ(0, rc);
check_example5(inst);
json_auto_t* result = nullptr;
rc = jsonSerializer_serializeJson(type, inst, &result);
ASSERT_EQ(0, rc);
EXPECT_TRUE(json_equal(root, result));
dynType_free(type, inst);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, SerializationDeserilizationNullStringTest) {
dyn_type *type;
void *inst;
int rc;
rc = dynType_parseWithStr("t", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_null();
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_EQ(0, rc);
EXPECT_EQ(nullptr, *(char**)inst);
json_auto_t* result = nullptr;
rc = jsonSerializer_serializeJson(type, inst, &result);
ASSERT_EQ(0, rc);
EXPECT_TRUE(json_equal(root, result));
dynType_free(type, inst);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, SerializationDeserilizationStringTest) {
dyn_type *type;
void *inst;
int rc;
rc = dynType_parseWithStr("t", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_loads(R"("hello")", JSON_DECODE_ANY, NULL);
ASSERT_NE(nullptr, root);
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_EQ(0, rc);
EXPECT_STREQ("hello", *(char**)inst);
json_auto_t* result = nullptr;
rc = jsonSerializer_serializeJson(type, inst, &result);
ASSERT_EQ(0, rc);
EXPECT_TRUE(json_equal(root, result));
dynType_free(type, inst);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, SerializationDeserilizationNullPropertiesTest) {
dyn_type *type;
void *inst;
auto rc = dynType_parseWithStr("p", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_null();
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_EQ(0, rc);
EXPECT_EQ(nullptr, *(celix_properties_t**)inst);
json_auto_t* result = nullptr;
rc = jsonSerializer_serializeJson(type, inst, &result);
ASSERT_EQ(0, rc);
EXPECT_TRUE(json_equal(root, result));
dynType_free(type, inst);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, SerializationDeserilizationPropertiesTest) {
dyn_type *type;
void *inst;
auto rc = dynType_parseWithStr("p", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_loads(R"({"key1":"value1", "key2":true, "key3":123})", JSON_DECODE_ANY, NULL);
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_EQ(0, rc);
auto props = *(celix_properties_t**)inst;
auto value1 = celix_properties_getAsString(props, "key1", nullptr);
ASSERT_STREQ("value1", value1);
auto value2 = celix_properties_getAsBool(props, "key2", false);
ASSERT_TRUE(value2);
auto value3 = celix_properties_getAsLong(props, "key3", 0L);
ASSERT_EQ(123, value3);
json_auto_t* result = nullptr;
rc = jsonSerializer_serializeJson(type, inst, &result);
ASSERT_EQ(0, rc);
EXPECT_TRUE(json_equal(root, result));
dynType_free(type, inst);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, SerializationPropertiesErrorOnEmptyArraysTest) {
dyn_type *type;
auto rc = dynType_parseWithStr("p", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* result = nullptr;
celix_autoptr(celix_properties_t) props = celix_properties_create();
auto emptyList = celix_arrayList_createStringArray();
auto status = celix_properties_assignArrayList(props, "key", emptyList);
ASSERT_EQ(CELIX_SUCCESS, status);
void *inst = &props;
rc = jsonSerializer_serializeJson(type, inst, &result);
ASSERT_NE(0, rc);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, DeserilizationInvalidPropertiesTest) {
dyn_type *type;
void *inst;
auto rc = dynType_parseWithStr("p", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_loads(R"("invalid_properties")", JSON_DECODE_ANY, NULL);
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_NE(0, rc);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, DeserilizationPropertiesWithInvalidElementTest) {
dyn_type *type;
void *inst;
auto rc = dynType_parseWithStr("p", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_loads(R"({"key1":[]})", JSON_DECODE_ANY, NULL);
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_NE(0, rc);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, SerializationDeserilizationNullArrayListTest) {
dyn_type *type;
void *inst;
auto rc = dynType_parseWithStr("a", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_null();
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_EQ(0, rc);
EXPECT_EQ(nullptr, *(celix_array_list_t**)inst);
json_auto_t* result = nullptr;
rc = jsonSerializer_serializeJson(type, inst, &result);
ASSERT_EQ(0, rc);
EXPECT_TRUE(json_equal(root, result));
dynType_free(type, inst);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, SerializationDeserilizationArrayListTest) {
dyn_type *type;
void *inst;
auto rc = dynType_parseWithStr("a", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_loads(R"(["val1", "val2", "val3"])", JSON_DECODE_ANY, NULL);
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_EQ(0, rc);
auto arrList = *(celix_array_list_t**)inst;
ASSERT_EQ(3, celix_arrayList_size(arrList));
ASSERT_EQ(CELIX_ARRAY_LIST_ELEMENT_TYPE_STRING, celix_arrayList_getElementType(arrList));
ASSERT_STREQ("val1", celix_arrayList_getString(arrList, 0));
ASSERT_STREQ("val2", celix_arrayList_getString(arrList, 1));
ASSERT_STREQ("val3", celix_arrayList_getString(arrList, 2));
json_auto_t* result = nullptr;
rc = jsonSerializer_serializeJson(type, inst, &result);
ASSERT_EQ(0, rc);
EXPECT_TRUE(json_equal(root, result));
dynType_free(type, inst);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, SerializationArrayListErrorOnEmptyArraysTest) {
dyn_type *type;
auto rc = dynType_parseWithStr("a", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* result = nullptr;
celix_autoptr(celix_array_list_t) emptyList = celix_arrayList_createStringArray();
void *inst = &emptyList;
rc = jsonSerializer_serializeJson(type, inst, &result);
ASSERT_NE(0, rc);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, DeserilizationInvalidArrayListTest) {
dyn_type *type;
void *inst;
auto rc = dynType_parseWithStr("a", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_loads(R"("invalid_array_list")", JSON_DECODE_ANY, NULL);
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_NE(0, rc);
dynType_destroy(type);
}
TEST_F(JsonSerializerTests, DeserilizationArrayListWithInvalidElementTest) {
dyn_type *type;
void *inst;
auto rc = dynType_parseWithStr("a", nullptr, nullptr, &type);
ASSERT_EQ(0, rc);
json_auto_t* root = json_loads(R"(["hello", 123])", JSON_DECODE_ANY, NULL);
rc = jsonSerializer_deserializeJson(type, root, &inst);
ASSERT_NE(0, rc);
dynType_destroy(type);
}