Fri, 12 Dec 2025 10:42:53 +0100
update ucx
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2025 Olaf Wintermann. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBLIITY OF SUCH DAMAGE. */ #include "json.h" #include <stdbool.h> #include <cx/buffer.h> #include <cx/linked_list.h> typedef struct Test1 { char *str; cxmutstr str2; int8_t i8; uint8_t u8; int64_t i64; int16_t i16; int32_t i32; uint32_t u32; uint16_t u16; uint64_t u64; bool bt; bool bf; double d; } Test1; typedef struct Test2 { char *name; int i; } Test2; typedef struct Test3 { char *test3; Test2 *test2; } Test3; typedef struct Test4 { int id; Test3 *test3; Test2 *test2; } Test4; typedef struct Test5 { char *test; CxList *test2List; } Test5; static DBUContext *ctx; static DBUClass *test1_class; static DBUClass *test2_class; static DBUClass *test3_class; static DBUClass *test4_class; static DBUClass *test5_class; int init_json_tests(void) { ctx = dbuContextCreate(); test1_class = dbuRegisterClassWithoutPK(ctx, "test1", sizeof(Test1)); dbuClassAdd(test1_class, Test1, str); dbuClassAdd(test1_class, Test1, str2); dbuClassAdd(test1_class, Test1, i8); dbuClassAdd(test1_class, Test1, u8); dbuClassAdd(test1_class, Test1, i16); dbuClassAdd(test1_class, Test1, u16); dbuClassAdd(test1_class, Test1, i32); dbuClassAdd(test1_class, Test1, u32); dbuClassAdd(test1_class, Test1, i64); dbuClassAdd(test1_class, Test1, u64); dbuClassAdd(test1_class, Test1, bt); dbuClassAdd(test1_class, Test1, bf); dbuClassAdd(test1_class, Test1, d); test2_class = dbuRegisterClassWithoutPK(ctx, "test2", sizeof(Test2)); dbuClassAdd(test2_class, Test2, name); dbuClassAdd(test2_class, Test2, i); test3_class = dbuRegisterClassWithoutPK(ctx, "test3", sizeof(Test3)); dbuClassAdd(test3_class, Test3, test3); dbuClassAddObj(test3_class, "test2", offsetof(Test3, test2), test2_class); test4_class = dbuRegisterClassWithoutPK(ctx, "test4", sizeof(Test4)); dbuClassAdd(test4_class, Test4, id); dbuClassAddObj(test4_class, "test2", offsetof(Test4, test2), test2_class); dbuClassAddObj(test4_class, "test3", offsetof(Test4, test3), test3_class); test5_class = dbuRegisterClassWithoutPK(ctx, "test5", sizeof(Test5)); dbuClassAdd(test5_class, Test5, test); dbuClassAddCxLinkedList(test5_class, "test2List", offsetof(Test5, test2List), test2_class); } void cleanup_json_tests(void) { dbuContextFree(ctx); } CX_TEST(testObjectToJsonSimple) { Test1 test; test.str = "hello str"; test.str2 = cx_mutstr("hello cx str"); test.i8 = 32; test.u8 = 250; test.i16 = -5533; test.u16 = 8000; test.i32 = -123456; test.u32 = 4000000000; test.i64 = -999999999999L; test.u64 = 2501; test.bt = true; test.bf = false; test.d = 431.15; CX_TEST_DO { CxJsonValue *value = dbuObjectToJson(test1_class, &test, NULL); CX_TEST_ASSERT(value); CX_TEST_ASSERT(cxJsonIsObject(value)); CxJsonValue *str = cxJsonObjGet(value, "str"); CxJsonValue *str2 = cxJsonObjGet(value, "str2"); CxJsonValue *i8 = cxJsonObjGet(value, "i8"); CxJsonValue *u8 = cxJsonObjGet(value, "u8"); CxJsonValue *i16 = cxJsonObjGet(value, "i16"); CxJsonValue *u16 = cxJsonObjGet(value, "u16"); CxJsonValue *i32 = cxJsonObjGet(value, "i32"); CxJsonValue *u32 = cxJsonObjGet(value, "u32"); CxJsonValue *i64 = cxJsonObjGet(value, "i64"); CxJsonValue *u64 = cxJsonObjGet(value, "u64"); CxJsonValue *bt = cxJsonObjGet(value, "bt"); CxJsonValue *bf = cxJsonObjGet(value, "bf"); CxJsonValue *d = cxJsonObjGet(value, "d"); CX_TEST_ASSERT(str && str->type == CX_JSON_STRING); CX_TEST_ASSERT(str2 && str2->type == CX_JSON_STRING); CX_TEST_ASSERT(i8 && i8->type == CX_JSON_INTEGER); CX_TEST_ASSERT(u8 && u8->type == CX_JSON_INTEGER); CX_TEST_ASSERT(i16 && i16->type == CX_JSON_INTEGER); CX_TEST_ASSERT(u16 && u16->type == CX_JSON_INTEGER); CX_TEST_ASSERT(i32 && i32->type == CX_JSON_INTEGER); CX_TEST_ASSERT(u32 && u32->type == CX_JSON_INTEGER); CX_TEST_ASSERT(i64 && i64->type == CX_JSON_INTEGER); CX_TEST_ASSERT(u64 && u64->type == CX_JSON_INTEGER); CX_TEST_ASSERT(d && d->type == CX_JSON_NUMBER); CX_TEST_ASSERT(!cx_strcmp(str->string, test.str)); CX_TEST_ASSERT(!cx_strcmp(str2->string, test.str2)); CX_TEST_ASSERT(i8->integer == test.i8); CX_TEST_ASSERT(u8->integer == test.u8); CX_TEST_ASSERT(i16->integer == test.i16); CX_TEST_ASSERT(u16->integer == test.u16); CX_TEST_ASSERT(i32->integer == test.i32); CX_TEST_ASSERT(u32->integer == test.u32); CX_TEST_ASSERT(i64->integer == test.i64); CX_TEST_ASSERT(u64->integer == test.u64); CX_TEST_ASSERT(d->number < test.d + 0.1 && d->number > test.d - 0.1); cxJsonValueFree(value); } } CX_TEST(testObjectToJsonChildObj) { Test2 t2_1; t2_1.i = 12; t2_1.name = "t2_1"; Test2 t2_2; t2_2.i = 45; t2_2.name = "t2_2"; Test3 t3; t3.test3 = "t3"; t3.test2 = &t2_1; Test4 t4; t4.id = 15; t4.test2 = &t2_2; t4.test3 = &t3; CX_TEST_DO { CxJsonValue *value = dbuObjectToJson(test4_class, &t4, NULL); CX_TEST_ASSERT(value); CX_TEST_ASSERT(cxJsonIsObject(value)); CxJsonValue *v = cxJsonObjGet(value, "id"); CX_TEST_ASSERT(v); CX_TEST_ASSERT(cxJsonIsInteger(v)); CX_TEST_ASSERT(v->integer == t4.id); v = cxJsonObjGet(value, "test2"); CX_TEST_ASSERT(v); CX_TEST_ASSERT(cxJsonIsObject(v)); CxJsonValue *s = cxJsonObjGet(v, "i"); CX_TEST_ASSERT(s); CX_TEST_ASSERT(cxJsonIsInteger(s)); CX_TEST_ASSERT(s->integer == t2_2.i); s = cxJsonObjGet(v, "name"); CX_TEST_ASSERT(s); CX_TEST_ASSERT(cxJsonIsString(s)); CX_TEST_ASSERT(!cx_strcmp(s->string, t2_2.name)); v = cxJsonObjGet(value, "test3"); CX_TEST_ASSERT(v); CX_TEST_ASSERT(cxJsonIsObject(v)); s = cxJsonObjGet(v, "test3"); CX_TEST_ASSERT(s); CX_TEST_ASSERT(cxJsonIsString(s)); CX_TEST_ASSERT(!cx_strcmp(s->string, t3.test3)); s = cxJsonObjGet(v, "test2"); CX_TEST_ASSERT(s); CX_TEST_ASSERT(cxJsonIsObject(s)); CxJsonValue *x = cxJsonObjGet(s, "i"); CX_TEST_ASSERT(x); CX_TEST_ASSERT(cxJsonIsInteger(x)); CX_TEST_ASSERT(x->integer == t2_1.i); x = cxJsonObjGet(s, "name"); CX_TEST_ASSERT(x); CX_TEST_ASSERT(cxJsonIsString(x)); CX_TEST_ASSERT(!cx_strcmp(x->string, t2_1.name)); cxJsonValueFree(value); } } CX_TEST(testObjectToJsonChildList) { Test5 test5; test5.test = "hello"; test5.test2List = cxLinkedListCreateSimple(CX_STORE_POINTERS); Test2 c1; c1.i = 1; c1.name = "c1"; Test2 c2; c2.i = 2; c2.name = "c2"; Test2 c3; c3.i = 3; c3.name = "c3"; cxListAdd(test5.test2List, &c1); cxListAdd(test5.test2List, &c2); cxListAdd(test5.test2List, &c3); CX_TEST_DO { CxJsonValue *value = dbuObjectToJson(test5_class, &test5, NULL); CX_TEST_ASSERT(value); CX_TEST_ASSERT(cxJsonIsObject(value)); CxJsonValue *v = cxJsonObjGet(value, "test"); CX_TEST_ASSERT(v); CX_TEST_ASSERT(cxJsonIsString(v)); CX_TEST_ASSERT(!cx_strcmp(v->string, test5.test)); v = cxJsonObjGet(value, "test2List"); CX_TEST_ASSERT(v); CX_TEST_ASSERT(cxJsonIsArray(v)); CxJsonValue *x = cxJsonArrGet(v, 0); CX_TEST_ASSERT(cxJsonIsObject(x)); CxJsonValue *z = cxJsonObjGet(x, "i"); CX_TEST_ASSERT(cxJsonIsInteger(z)); CX_TEST_ASSERT(z->integer == c1.i); z = cxJsonObjGet(x, "name"); CX_TEST_ASSERT(cxJsonIsString(z)); CX_TEST_ASSERT(!cx_strcmp(z->string, c1.name)); x = cxJsonArrGet(v, 1); CX_TEST_ASSERT(cxJsonIsObject(x)); z = cxJsonObjGet(x, "i"); CX_TEST_ASSERT(cxJsonIsInteger(z)); CX_TEST_ASSERT(z->integer == c2.i); z = cxJsonObjGet(x, "name"); CX_TEST_ASSERT(cxJsonIsString(z)); CX_TEST_ASSERT(!cx_strcmp(z->string, c2.name)); x = cxJsonArrGet(v, 2); CX_TEST_ASSERT(cxJsonIsObject(x)); z = cxJsonObjGet(x, "i"); CX_TEST_ASSERT(cxJsonIsInteger(z)); CX_TEST_ASSERT(z->integer == c3.i); z = cxJsonObjGet(x, "name"); CX_TEST_ASSERT(cxJsonIsString(z)); CX_TEST_ASSERT(!cx_strcmp(z->string, c3.name)); cxJsonValueFree(value); } }