test/json.c

Fri, 12 Dec 2025 10:42:53 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Fri, 12 Dec 2025 10:42:53 +0100
changeset 30
d33eaaec15da
parent 29
b8c826c720f3
permissions
-rw-r--r--

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);
    }
}

mercurial