tests/test_json.c

changeset 1015
a0922b925d2a
parent 1007
81b2986d2b04
--- a/tests/test_json.c	Sun Dec 15 14:32:39 2024 +0100
+++ b/tests/test_json.c	Sun Dec 15 14:32:51 2024 +0100
@@ -116,6 +116,31 @@
     }
 }
 
+CX_TEST(test_json_escaped_strings) {
+    cxstring text = cx_str(
+            "{\n"
+            "\t\"object\":\"{\\n\\t\\\"object\\\":null\\n}\"}\"\n"
+            "}"
+    );
+
+    CxJson json;
+    cxJsonInit(&json, NULL);
+    CX_TEST_DO {
+        cxJsonFill(&json, text);
+        CxJsonValue *obj;
+        CxJsonStatus result = cxJsonNext(&json, &obj);
+        CX_TEST_ASSERT(result == CX_JSON_NO_ERROR);
+        CX_TEST_ASSERT(cxJsonIsObject(obj));
+        CxJsonValue *object = cxJsonObjGet(obj, "object");
+        CX_TEST_ASSERT(cxJsonIsString(object));
+        CX_TEST_ASSERT(0 == cx_strcmp(
+            cxJsonAsCxString(object),
+            CX_STR("{\n\t\"object\":null\n}"))
+        );
+    }
+    cxJsonDestroy(&json);
+}
+
 CX_TEST(test_json_object_incomplete_token) {
     cxstring text = cx_str(
             "{\"message\":\"success\"  ,     \"__timestamp\":1729348561}");
@@ -166,6 +191,28 @@
     }
 }
 
+CX_TEST(test_json_token_wrongly_completed) {
+    cxstring text = cx_str("{\"number\": 47110815!}");
+    cxstring part1 = cx_strsubsl(text, 0, 16);
+    cxstring part2 = cx_strsubs(text, 16);
+
+    CxJson json;
+    cxJsonInit(&json, NULL);
+    CX_TEST_DO {
+        CxJsonStatus result;
+        CxJsonValue *obj;
+
+        cxJsonFill(&json, part1);
+        result = cxJsonNext(&json, &obj);
+        CX_TEST_ASSERT(result == CX_JSON_INCOMPLETE_DATA);
+        cxJsonFill(&json, part2);
+        result = cxJsonNext(&json, &obj);
+        CX_TEST_ASSERT(result == CX_JSON_FORMAT_ERROR_NUMBER);
+        CX_TEST_ASSERT(obj->type == CX_JSON_NOTHING);
+    }
+    cxJsonDestroy(&json);
+}
+
 CX_TEST(test_json_subsequent_fill) {
     cxstring text = cx_str(
             "{\"message\":\"success\"  ,     \"__timestamp\":1729348561}");
@@ -296,21 +343,119 @@
     CxJson json;
     cxJsonInit(&json, NULL);
     CX_TEST_DO {
-        // TODO: find a better way to terminate values that are not arrays/objects
         CxJsonValue *v;
         CxJsonStatus result;
+
         cxJsonFill(&json, "3.1415 ");
         result = cxJsonNext(&json, &v);
         CX_TEST_ASSERT(result == CX_JSON_NO_ERROR);
         CX_TEST_ASSERT(cxJsonIsNumber(v));
         CX_TEST_ASSERT(cxJsonAsDouble(v) == 3.1415);
         cxJsonValueFree(v);
+
         cxJsonFill(&json, "-47.11e2 ");
         result = cxJsonNext(&json, &v);
         CX_TEST_ASSERT(result == CX_JSON_NO_ERROR);
         CX_TEST_ASSERT(cxJsonIsNumber(v));
         CX_TEST_ASSERT(cxJsonAsDouble(v) == -4711.0);
         cxJsonValueFree(v);
+
+        cxJsonFill(&json, "0.815e-3 ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERT(result == CX_JSON_NO_ERROR);
+        CX_TEST_ASSERT(cxJsonIsNumber(v));
+        CX_TEST_ASSERT(cxJsonAsDouble(v) == 0.000815);
+
+        cxJsonFill(&json, "1.23E4 ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERT(result == CX_JSON_NO_ERROR);
+        CX_TEST_ASSERT(cxJsonIsNumber(v));
+        CX_TEST_ASSERT(cxJsonAsInteger(v) == 12300);
+        CX_TEST_ASSERT(cxJsonAsDouble(v) == 12300.0);
+
+        cxJsonValueFree(v);
+    }
+    cxJsonDestroy(&json);
+}
+
+CX_TEST(test_json_number_format_errors) {
+    CxJson json;
+    cxJsonInit(&json, NULL);
+    CX_TEST_DO {
+        CxJsonValue *v;
+        CxJsonStatus result;
+
+        cxJsonFill(&json, "+3.1415 ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_NUMBER,
+                        "leading plus is not RFC-8259 compliant");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
+
+#if 0 // TODO: discuss if it is intended that this produces -47 as valid value
+        cxJsonFill(&json, "-47,11e2 ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN,
+                        "decimal separator cannot be a comma");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
+#endif
+
+        cxJsonFill(&json, "0.815e-3.0 ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_NUMBER,
+                        "exponent must be an integer");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
+
+        cxJsonFill(&json, "3.14e ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_NUMBER,
+                        "exponent cannot be empty");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
+
+        cxJsonFill(&json, "3.14e~7 ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_NUMBER,
+                       "exponent cannot start with bullshit");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
+
+        cxJsonFill(&json, "1.23e4f ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_NUMBER,
+            "non-digits in exponent");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
+
+        cxJsonFill(&json, "1.23f ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_NUMBER,
+            "non-digits in value");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
+
+        cxJsonFill(&json, "1.23.45 ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_NUMBER,
+            "multiple decimal separators");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
+
+        cxJsonFill(&json, "184467440737095516150123456789 ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_NUMBER,
+            "30 digit int does not fit into 64-bit int");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
+
+        cxJsonFill(&json, "18446744073709551615.0123456789 ");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERTM(result == CX_JSON_FORMAT_ERROR_NUMBER,
+            "numbers with more than 30 characters are unsupported in general");
+        CX_TEST_ASSERT(v->type == CX_JSON_NOTHING);
+        cxJsonReset(&json);
     }
     cxJsonDestroy(&json);
 }
@@ -365,12 +510,23 @@
         result = cxJsonNext(&json, &v);
         CX_TEST_ASSERT(result == CX_JSON_NO_ERROR);
         CX_TEST_ASSERT(cxJsonIsLiteral(v));
+        CX_TEST_ASSERT(cxJsonIsBool(v));
+        CX_TEST_ASSERT(cxJsonIsTrue(v));
         CX_TEST_ASSERT(cxJsonAsBool(v));
         cxJsonValueFree(v);
-        // read null
+        cxJsonFill(&json, "false\n");
+        result = cxJsonNext(&json, &v);
+        CX_TEST_ASSERT(result == CX_JSON_NO_ERROR);
+        CX_TEST_ASSERT(cxJsonIsLiteral(v));
+        CX_TEST_ASSERT(cxJsonIsBool(v));
+        CX_TEST_ASSERT(cxJsonIsFalse(v));
+        CX_TEST_ASSERT(!cxJsonAsBool(v));
+        cxJsonValueFree(v);
         cxJsonFill(&json, "null\n");
         result = cxJsonNext(&json, &v);
         CX_TEST_ASSERT(result == CX_JSON_NO_ERROR);
+        CX_TEST_ASSERT(cxJsonIsLiteral(v));
+        CX_TEST_ASSERT(!cxJsonIsBool(v));
         CX_TEST_ASSERT(cxJsonIsNull(v));
         cxJsonValueFree(v);
     }
@@ -443,11 +599,14 @@
 
     cx_test_register(suite, test_json_init_default);
     cx_test_register(suite, test_json_simple_object);
+    cx_test_register(suite, test_json_escaped_strings);
     cx_test_register(suite, test_json_object_incomplete_token);
+    cx_test_register(suite, test_json_token_wrongly_completed);
     cx_test_register(suite, test_json_object_error);
     cx_test_register(suite, test_json_subsequent_fill);
     cx_test_register(suite, test_json_large_nesting_depth);
     cx_test_register(suite, test_json_number);
+    cx_test_register(suite, test_json_number_format_errors);
     cx_test_register(suite, test_json_multiple_values);
     cx_test_register(suite, test_json_allocator);
     cx_test_register(suite, test_json_allocator_parse_error);

mercurial