# HG changeset patch # User Olaf Wintermann # Date 1765635385 -3600 # Node ID 7f1cadc3ebc140e93aab9774bf020a235abf1d04 # Parent 8ccfbc00f6902531250bf7278cd09d43d0c44347 add json compare tests diff -r 8ccfbc00f690 -r 7f1cadc3ebc1 src/json.c --- a/src/json.c Sat Dec 13 13:55:27 2025 +0100 +++ b/src/json.c Sat Dec 13 15:16:25 2025 +0100 @@ -452,6 +452,8 @@ return ret; } +#include "cx/hash_map.h" + static CxJsonObject json_create_object_map(const CxAllocator *allocator) { CxMap *map = cxKvListCreateAsMap(allocator, NULL, CX_STORE_POINTERS); if (map == NULL) return NULL; // LCOV_EXCL_LINE diff -r 8ccfbc00f690 -r 7f1cadc3ebc1 tests/test_json.c --- a/tests/test_json.c Sat Dec 13 13:55:27 2025 +0100 +++ b/tests/test_json.c Sat Dec 13 15:16:25 2025 +0100 @@ -32,6 +32,8 @@ #include "cx/json.h" #include "cx/compare.h" +#include + CX_TEST(test_json_init_default) { CxJson json; CX_TEST_DO { @@ -1249,6 +1251,132 @@ cx_testing_allocator_destroy(&talloc); } +CX_TEST(test_json_compare_primitives) { + CxJsonValue *a[14]; + a[0] = cxJsonCreateLiteral(NULL, CX_JSON_NULL); + a[1] = cxJsonCreateLiteral(NULL, CX_JSON_TRUE); + a[2] = cxJsonCreateLiteral(NULL, CX_JSON_FALSE); + a[3] = cxJsonCreateInteger(NULL, 1234); + a[4] = cxJsonCreateInteger(NULL, 5432); + a[5] = cxJsonCreateInteger(NULL, -10); + a[6] = cxJsonCreateInteger(NULL, 0); + a[7] = cxJsonCreateNumber(NULL, 0.0f); + a[8] = cxJsonCreateNumber(NULL, 13.37f); + a[9] = cxJsonCreateNumber(NULL, -123.456f); + a[10] = cxJsonCreateNumber(NULL, 1234.0f); + a[11] = cxJsonCreateNumber(NULL, -10.3f); + a[12] = cxJsonCreateString(NULL, "hello"); + a[13] = cxJsonCreateString(NULL, "world"); + + CxJsonValue *b[14]; + b[0] = cxJsonCreateLiteral(NULL, CX_JSON_NULL); + b[1] = cxJsonCreateLiteral(NULL, CX_JSON_TRUE); + b[2] = cxJsonCreateLiteral(NULL, CX_JSON_FALSE); + b[3] = cxJsonCreateInteger(NULL, 1234); + b[4] = cxJsonCreateInteger(NULL, 5432); + b[5] = cxJsonCreateInteger(NULL, -10); + b[6] = cxJsonCreateInteger(NULL, 0); + b[7] = cxJsonCreateNumber(NULL, 0.0f); + b[8] = cxJsonCreateNumber(NULL, 13.37f); + b[9] = cxJsonCreateNumber(NULL, -123.456f); + b[10] = cxJsonCreateNumber(NULL, 1234.0f); + b[11] = cxJsonCreateNumber(NULL, -10.3f); + b[12] = cxJsonCreateString(NULL, "hello"); + b[13] = cxJsonCreateString(NULL, "world"); + + CX_TEST_DO { + for(int i=0;i<12;i++) { + for(int j=0;j<12;j++) { + int ret = cxJsonCompare(a[i], b[j]); + if(i == j) { + CX_TEST_ASSERT(ret == 0); + } else { + if(cxJsonIsNumber(a[i]) && cxJsonIsNumber(b[j])) { + double diff = fabs(cxJsonAsDouble(a[i]) - cxJsonAsDouble(b[j])); + if(diff < 0.001) { + CX_TEST_ASSERT(ret == 0); + } else { + CX_TEST_ASSERT(ret != 0); + } + } else { + CX_TEST_ASSERT(ret != 0); + } + } + } + } + + } + for(int i=0;i<14;i++) { + cxJsonValueFree(a[i]); + cxJsonValueFree(b[i]); + } +} + +CX_TEST(test_json_compare_objects) { + CxJsonValue *json[7]; + cxJsonFromString(NULL, "{ }", &json[0]); + cxJsonFromString(NULL, "{ }", &json[1]); + cxJsonFromString(NULL, "{ \"name\": \"value\" }", &json[2]); + cxJsonFromString(NULL, "{ \"key0\": \"value0\", \"key1\": \"value1\", \"key2\":null }", &json[3]); + cxJsonFromString(NULL, "{ \"key1\": \"value1\", \"key2\":null, \"key0\": \"value0\" }", &json[4]); + + const char *json_complex_object = + "{\n" + " \"bool\": false,\n" + " \"int\": 47,\n" + " \"strings\": [ \"hello\", \"world\" ],\n" + " \"nested\": {\n" + " \"string\": \"test\",\n" + " \"floats\": [ 3.1415, 47.11, 8.15 ],\n" + " \"ints\": [ 4, 8, 15, 16, 23, 42 ],\n" + " \"literals\": [ true, null, false ],\n" + " \"objects\": [\n" + " {},\n" + " { \"unicode\": \"\\u03a3\\u29b0\" },\n" + " { \"array\": [ 1,2,3] }\n" + " ]\n" + " }\n" + "}\n"; + cxJsonFromString(NULL, json_complex_object, &json[5]); + cxJsonFromString(NULL, json_complex_object, &json[6]); + + CX_TEST_DO { + for(int i=0;i<7;i++) { + CX_TEST_ASSERT(cxJsonIsObject(json[i])); + } + + CX_TEST_ASSERT(cxJsonCompare(json[0], json[0]) == 0); + CX_TEST_ASSERT(cxJsonCompare(json[0], json[1]) == 0); + CX_TEST_ASSERT(cxJsonCompare(json[2], json[2]) == 0); // <-- fail + + // compare empty object with all other objects + for(int i=2;i<6;i++) { + CX_TEST_ASSERT(cxJsonCompare(json[0], json[i]) != 0); + } + + // compare different objects + CX_TEST_ASSERT(cxJsonCompare(json[2], json[3]) != 0); + CX_TEST_ASSERT(cxJsonCompare(json[2], json[5]) != 0); + + // compare equal objects with different orders + CX_TEST_ASSERT(cxJsonCompare(json[3], json[4]) == 0); // <-- fail + + // test the same complex object + CX_TEST_ASSERT(cxJsonCompare(json[6], json[7])); // <-- fail, even with hashmap + } + + for(int i=0;i<7;i++) { + cxJsonValueFree(json[i]); + } +} + +CX_TEST(test_json_compare_arrays) { + CX_TEST_DO { + + } +} + + static CxJsonValue *test_json_write_create_test_object(const CxAllocator *allocator) { CxJsonValue *obj = cxJsonCreateObj(allocator); cxJsonObjPutLiteral(obj, "bool", CX_JSON_FALSE); @@ -1681,6 +1809,9 @@ cx_test_register(suite, test_json_allocator_parse_error); cx_test_register(suite, test_json_create_value); cx_test_register(suite, test_json_overwrite_value); + cx_test_register(suite, test_json_compare_primitives); + cx_test_register(suite, test_json_compare_objects); + cx_test_register(suite, test_json_compare_arrays); cx_test_register(suite, test_json_write_default_format); cx_test_register(suite, test_json_write_pretty_default_spaces); cx_test_register(suite, test_json_write_pretty_default_tabs);