// tests/suite/test_json.el — comprehensive tests for runtime/json.el // // Covers json_get, json_get_raw, json_set, json_array_len, json_array_get, // json_array_get_string, json_escape_string, json_build_object, json_build_array, // json_array_push, typed extractors, bytes_to_str, and nested JSON. // ── json_get ────────────────────────────────────────────────────────────────── fn test_json_get_basic(_: String) -> String { let obj: String = "{\"name\":\"alice\",\"age\":\"30\"}" assert_eq(json_get(obj, "name"), "alice", "get string field") assert_eq(json_get(obj, "age"), "30", "get numeric-looking string field") assert_eq(json_get(obj, "missing"), "", "missing key returns empty string") return "" } fn test_json_get_types(_: String) -> String { let obj: String = "{\"count\":42,\"flag\":true,\"ratio\":3.14}" assert_eq(json_get(obj, "count"), "42", "get integer field") assert_eq(json_get(obj, "flag"), "true", "get boolean field") assert_eq(json_get(obj, "ratio"), "3.14", "get float field") assert_eq(json_get(obj, "absent"), "", "absent key yields empty") return "" } fn test_json_get_nested(_: String) -> String { let obj: String = "{\"user\":{\"name\":\"bob\",\"role\":\"admin\"}}" assert_eq(json_get(obj, "user.name"), "bob", "dot-path traversal: user.name") assert_eq(json_get(obj, "user.role"), "admin", "dot-path traversal: user.role") assert_eq(json_get(obj, "user.missing"), "", "missing nested key") return "" } fn test_json_get_empty(_: String) -> String { let empty_obj: String = "{}" assert_eq(json_get(empty_obj, "key"), "", "empty object: any key is missing") assert_eq(json_get(empty_obj, "a.b"), "", "empty object: nested path missing") return "" } // ── json_get typed extractors ──────────────────────────────────────────────── fn test_json_get_int_basic(_: String) -> String { let obj: String = "{\"count\":42,\"negative\":-7,\"zero\":0}" assert_int_eq(json_get_int(obj, "count"), 42, "get int field 42") assert_int_eq(json_get_int(obj, "negative"), -7, "get negative int field") assert_int_eq(json_get_int(obj, "zero"), 0, "get zero int field") assert_int_eq(json_get_int(obj, "missing"), 0, "missing int field returns 0") return "" } fn test_json_get_bool_basic(_: String) -> String { let obj: String = "{\"ok\":true,\"fail\":false}" assert_true(json_get_bool(obj, "ok"), "get true bool field") assert_false(json_get_bool(obj, "fail"), "get false bool field") assert_false(json_get_bool(obj, "missing"), "missing bool field returns false") return "" } fn test_json_get_float_basic(_: String) -> String { let obj: String = "{\"ratio\":3.14,\"negative\":-1.5}" let ratio: Float = json_get_float(obj, "ratio") assert_true(ratio > 3.13, "ratio > 3.13") assert_true(ratio < 3.15, "ratio < 3.15") let neg: Float = json_get_float(obj, "negative") assert_true(neg < -1.4, "negative float") assert_true(neg > -1.6, "negative float bound") return "" } // ── json_set ────────────────────────────────────────────────────────────────── fn test_json_set_basic(_: String) -> String { let obj: String = "{\"name\":\"alice\"}" let obj2: String = json_set(obj, "name", "\"bob\"") assert_eq(json_get(obj2, "name"), "bob", "overwrites existing key") let obj3: String = json_set(obj, "role", "\"admin\"") assert_eq(json_get(obj3, "role"), "admin", "inserts new key") assert_eq(json_get(obj3, "name"), "alice", "existing key unchanged") return "" } fn test_json_set_numeric(_: String) -> String { let obj: String = "{}" let obj2: String = json_set(obj, "count", "42") assert_eq(json_get(obj2, "count"), "42", "set integer value") let obj3: String = json_set(obj2, "count", "100") assert_eq(json_get(obj3, "count"), "100", "overwrites integer value") return "" } fn test_json_set_chained(_: String) -> String { let obj: String = "{}" let obj1: String = json_set(obj, "a", "\"1\"") let obj2: String = json_set(obj1, "b", "\"2\"") let obj3: String = json_set(obj2, "c", "\"3\"") assert_eq(json_get(obj3, "a"), "1", "chained set: a") assert_eq(json_get(obj3, "b"), "2", "chained set: b") assert_eq(json_get(obj3, "c"), "3", "chained set: c") return "" } // ── json_array_len ──────────────────────────────────────────────────────────── fn test_json_array_len_basic(_: String) -> String { assert_int_eq(json_array_len("[]"), 0, "empty array has length 0") assert_int_eq(json_array_len("[1]"), 1, "single element array") assert_int_eq(json_array_len("[1,2,3]"), 3, "three element array") assert_int_eq(json_array_len("[\"a\",\"b\"]"), 2, "string array length") assert_int_eq(json_array_len("[1,2,3,4,5]"), 5, "five element array") return "" } // ── json_array_get / json_array_get_string ──────────────────────────────────── fn test_json_array_get_basic(_: String) -> String { let arr: String = "[\"alpha\",\"beta\",\"gamma\"]" assert_eq(json_array_get_string(arr, 0), "alpha", "first element") assert_eq(json_array_get_string(arr, 1), "beta", "second element") assert_eq(json_array_get_string(arr, 2), "gamma", "third element") assert_eq(json_array_get_string(arr, 3), "", "out of bounds returns empty") return "" } fn test_json_array_get_numbers(_: String) -> String { let arr: String = "[10,20,30]" assert_eq(json_array_get(arr, 0), "10", "first number as fragment") assert_eq(json_array_get(arr, 1), "20", "second number as fragment") assert_eq(json_array_get(arr, 2), "30", "third number as fragment") assert_int_eq(str_to_int(json_array_get(arr, 0)), 10, "convert fragment to int") return "" } fn test_json_array_get_objects(_: String) -> String { let arr: String = "[{\"name\":\"alice\"},{\"name\":\"bob\"}]" let first: String = json_array_get(arr, 0) let second: String = json_array_get(arr, 1) assert_eq(json_get(first, "name"), "alice", "first object name") assert_eq(json_get(second, "name"), "bob", "second object name") assert_int_eq(json_array_len(arr), 2, "array of objects has correct length") return "" } // ── json_escape_string ──────────────────────────────────────────────────────── fn test_json_escape_string_basic(_: String) -> String { assert_eq(json_escape_string("hello"), "hello", "plain string unchanged") assert_eq(json_escape_string(""), "", "empty string unchanged") assert_contains(json_escape_string("say \"hello\""), "\\\"", "double quotes escaped") assert_contains(json_escape_string("line1\nline2"), "\\n", "newline escaped") assert_contains(json_escape_string("col1\tcol2"), "\\t", "tab escaped") return "" } fn test_json_escape_string_backslash(_: String) -> String { let escaped: String = json_escape_string("a\\b") assert_contains(escaped, "\\\\", "backslash doubled") assert_true(str_len(escaped) > 3, "escaped is longer than original") return "" } fn test_json_escape_roundtrip(_: String) -> String { // Build a JSON string with an escaped value and extract it back let raw: String = "hello world" let escaped: String = json_escape_string(raw) let json_str: String = "{\"msg\":\"" + escaped + "\"}" assert_eq(json_get(json_str, "msg"), raw, "roundtrip: escape then parse") return "" } // ── json_build_object ───────────────────────────────────────────────────────── fn test_json_build_object_basic(_: String) -> String { let parts: [String] = el_list_empty() let parts = el_list_append(parts, "name") let parts = el_list_append(parts, "alice") let parts = el_list_append(parts, "role") let parts = el_list_append(parts, "admin") let obj: String = json_build_object(parts) assert_eq(json_get(obj, "name"), "alice", "build object: name field") assert_eq(json_get(obj, "role"), "admin", "build object: role field") assert_true(str_starts_with(obj, "{"), "build object starts with {") assert_true(str_ends_with(obj, "}"), "build object ends with }") return "" } fn test_json_build_object_empty(_: String) -> String { let parts: [String] = el_list_empty() let obj: String = json_build_object(parts) assert_true(str_starts_with(obj, "{"), "empty build object starts with {") assert_true(str_ends_with(obj, "}"), "empty build object ends with }") return "" } // ── json_build_array ────────────────────────────────────────────────────────── fn test_json_build_array_basic(_: String) -> String { let items: [String] = el_list_empty() let items = el_list_append(items, "\"alice\"") let items = el_list_append(items, "\"bob\"") let arr: String = json_build_array(items) assert_int_eq(json_array_len(arr), 2, "built array has 2 elements") assert_eq(json_array_get_string(arr, 0), "alice", "first element of built array") assert_eq(json_array_get_string(arr, 1), "bob", "second element of built array") return "" } fn test_json_build_array_empty(_: String) -> String { let items: [String] = el_list_empty() let arr: String = json_build_array(items) assert_int_eq(json_array_len(arr), 0, "empty built array has 0 elements") assert_eq(arr, "[]", "empty array is []") return "" } fn test_json_build_array_numbers(_: String) -> String { let items: [String] = el_list_empty() let items = el_list_append(items, "1") let items = el_list_append(items, "2") let items = el_list_append(items, "3") let arr: String = json_build_array(items) assert_int_eq(json_array_len(arr), 3, "numeric array has 3 elements") assert_eq(json_array_get(arr, 0), "1", "first numeric element") assert_eq(json_array_get(arr, 2), "3", "last numeric element") return "" } // ── json_array_push ─────────────────────────────────────────────────────────── fn test_json_array_push_basic(_: String) -> String { let arr: String = "[]" let arr2: String = json_array_push(arr, "\"hello\"") assert_int_eq(json_array_len(arr2), 1, "after push: length 1") assert_eq(json_array_get_string(arr2, 0), "hello", "pushed element accessible") let arr3: String = json_array_push(arr2, "\"world\"") assert_int_eq(json_array_len(arr3), 2, "after second push: length 2") assert_eq(json_array_get_string(arr3, 1), "world", "second pushed element") return "" } fn test_json_array_push_preserves_order(_: String) -> String { let arr: String = "[\"a\",\"b\"]" let arr2: String = json_array_push(arr, "\"c\"") assert_eq(json_array_get_string(arr2, 0), "a", "first element preserved") assert_eq(json_array_get_string(arr2, 1), "b", "second element preserved") assert_eq(json_array_get_string(arr2, 2), "c", "pushed element at end") assert_int_eq(json_array_len(arr2), 3, "total length after push") return "" } // ── nested JSON ─────────────────────────────────────────────────────────────── fn test_json_nested_set_get(_: String) -> String { let obj: String = "{\"user\":{\"name\":\"alice\"},\"count\":1}" assert_eq(json_get(obj, "user.name"), "alice", "deep get via dot path") assert_eq(json_get(obj, "count"), "1", "top-level int field") let obj2: String = json_set(obj, "count", "2") assert_eq(json_get(obj2, "count"), "2", "updated top-level field") assert_eq(json_get(obj2, "user.name"), "alice", "nested field still accessible after set") return "" } fn test_json_array_of_objects(_: String) -> String { let arr: String = "[{\"id\":1,\"name\":\"alice\"},{\"id\":2,\"name\":\"bob\"}]" assert_int_eq(json_array_len(arr), 2, "array of objects: length 2") let first: String = json_array_get(arr, 0) let second: String = json_array_get(arr, 1) assert_eq(json_get(first, "name"), "alice", "first object name") assert_eq(json_get(second, "name"), "bob", "second object name") assert_eq(json_get(first, "id"), "1", "first object id") assert_eq(json_get(second, "id"), "2", "second object id") return "" }