// Originally from /jsonion_test.gml in JSOnion // JSOnion v1.0.0d is licensed under the MIT licence. You may freely adapt and use this library in commercial and non-commercial projects. #define assert_true { /** assert_true(result, errormsg): Display error unless is true. */ if (!argument0) { _assert_error_popup(argument1 + string_repeat(_assert_newline(), 2) + "Expected true, got false."); } } #define assert_false { /** assert_false(result, errormsg): Display error unless is false. */ if (argument0) { _assert_error_popup(argument1 + string_repeat(_assert_newline(), 2) + "Expected false, got true."); } } #define assert_equal { /** assert_equal(expected, result, errormsg): Display error unless and are equal. */ //Safe equality check; won't crash even if the two are different types var match; match = is_string(argument0) == is_string(argument1); if (match) { match = argument0 == argument1; } //No match? if (!match) { //Data types var type; type[0] = "(Real)"; type[1] = "(String)"; //Construct message var msg; msg = argument2; //Add expected value msg += string_repeat(_assert_newline(), 2); msg += "Expected " + type[is_string(argument0)] + ":" + _assert_newline(); msg += _assert_debug_value(argument0); //Add actual value msg += string_repeat(_assert_newline(), 2); msg += "Actual " + type[is_string(argument1)] + ":" + _assert_newline(); msg += _assert_debug_value(argument1); //Display message _assert_error_popup(msg); } } #define _assert_error_popup { /** _assert_error_popup(msg): Display an assertion error. */ //Display message if (os_browser == browser_not_a_browser) { show_error(argument0, false); //Full-fledged error message for non-browser environments } else { show_message(argument0); //Browsers don't support show_error(), use show_message() instead } } #define _assert_debug_value { /** _assert_debug_value(val): Returns a low-level debug value for the value . can be a string or a real value. */ //String if (is_string(argument0)) { if (os_browser == browser_not_a_browser) { return argument0; } else { return string_replace_all(argument0, "#", "\#"); } } //Numeric --- use GMTuple's algorithm else { //Integers if (frac(argument0) == 0) { return string(argument0); } //Decimal numbers; get exponent and mantissa var mantissa, exponent; exponent = floor(log10(abs(argument0))); mantissa = string_format(argument0/power(10,exponent), 15, 14); //Look for trailing zeros in the mantissa var i, ca; i = string_length(mantissa); do { ca = string_char_at(mantissa, i); i -= 1; } until (ca != "0") //Remove the dot if only the first digit of the normalized mantissa is nonzero if (ca != ".") { mantissa = string_copy(mantissa, 1, i+1); } else { mantissa = string_copy(mantissa, 1, i); } //Remove the exponent if it is 0 if (exponent != 0) { return mantissa + "e" + string(exponent); } else { return mantissa; } //GMTuple algorithm done } } #define _assert_newline { /** _assert_newline(): Returns a system-appropriate newline character sequence. */ if (os_browser == browser_not_a_browser) { return chr(13) + chr(10); } else { return "#"; } } #define jso_test_all { /** jso_test_all(): Run the test suite for the JSOnion library. JSOnion version: 1.0.0d */ var a, b; a = current_time; _test_jso_new(); _test_jso_map_add(); _test_jso_list_add(); _test_jso_encode(); _test_jso_compare(); _test_jso_decode(); _test_jso_lookup(); _test_jso_bugs(); __jso_gmt_test_all(); b = current_time; show_debug_message("JSOnion: Tests completed in " + string(b-a) + "ms."); } #define _test_jso_new { /** _test_jso_new(): Test jso_new_*() functions. JSOnion version: 1.0.0d */ var expected, actual; //jso_new_map() actual = jso_new_map(); assert_true(actual >= 0, "jso_new_map() failed to create a new map."); ds_map_destroy(actual); //jso_new_list() actual = jso_new_list(); assert_true(actual >= 0, "jso_new_list() failed to create a new list."); ds_list_destroy(actual); } #define _test_jso_map_add { /** _test_jso_map_add(): Test jso_map_add_*() functions. JSOnion version: 1.0.0d */ var expected, actual, key, map; map = jso_new_map(); //jso_map_add_real() expected = pi; key = "pi"; jso_map_add_real(map, key, expected); actual = jso_map_get(map, key); assert_true(ds_map_exists(map, key), "jso_map_add_real() failed to add the number."); assert_equal(expected, actual, "jso_map_add_real() added the wrong number."); ds_map_delete(map, key); //jso_map_add_string() expected = "waahoo"; key = "str"; jso_map_add_string(map, key, expected); actual = jso_map_get(map, key); assert_true(ds_map_exists(map, key), "jso_map_add_string() failed to add the string."); assert_equal(expected, actual, "jso_map_add_string() added the wrong string."); ds_map_delete(map, key); //jso_map_add_sublist() expected = jso_new_list(); key = "sublist"; jso_map_add_sublist(map, key, expected); actual = jso_map_get(map, key); assert_true(ds_map_exists(map, key), "jso_map_add_sublist() failed to add the new sublist."); assert_equal(expected, actual, "jso_map_add_sublist() added the wrong sublist."); ds_map_delete(map, key); ds_list_destroy(expected); //jso_map_add_submap() expected = jso_new_map(); key = "sublist"; jso_map_add_sublist(map, key, expected); actual = jso_map_get(map, key); assert_true(ds_map_exists(map, key), "jso_map_add_submap() failed to add the new submap."); assert_equal(expected, actual, "jso_map_add_submap() added the wrong submap."); ds_map_delete(map, key); ds_map_destroy(expected); //jso_map_add_integer() expected = 2345; key = "integer"; jso_map_add_integer(map, key, expected); actual = jso_map_get(map, key); assert_true(ds_map_exists(map, key), "jso_map_add_integer() failed to add the new integer."); assert_equal(expected, actual, "jso_map_add_integer() added the wrong integer."); ds_map_delete(map, key); //jso_map_add_boolean() --- true expected = true; key = "booleantrue"; jso_map_add_boolean(map, key, expected); actual = jso_map_get(map, key); assert_true(ds_map_exists(map, key), "jso_map_add_boolean() failed to add true."); assert_true(actual, "jso_map_add_boolean() added the wrong true."); ds_map_delete(map, key); //jso_map_add_boolean() --- false expected = false; key = "booleanfalse"; jso_map_add_boolean(map, key, expected); actual = jso_map_get(map, key) assert_true(ds_map_exists(map, key), "jso_map_add_boolean() failed to add false."); assert_false(actual, "jso_map_add_boolean() added the wrong false."); ds_map_delete(map, key); //Cleanup ds_map_destroy(map); } #define _test_jso_list_add { /** _test_jso_list_add(): Test jso_list_add_*() functions. JSOnion version: 1.0.0d */ var expected, actual, list; list = jso_new_list(); //jso_list_add_real() expected = pi; jso_list_add_real(list, expected); actual = jso_list_get(list, 0); assert_false(ds_list_empty(list), "jso_list_add_real() failed to add the number."); assert_equal(expected, actual, "jso_list_add_real() added the wrong number."); ds_list_clear(list); //jso_list_add_string() expected = "waahoo"; jso_list_add_string(list, expected); actual = jso_list_get(list, 0); assert_false(ds_list_empty(list), "jso_list_add_string() failed to add the string."); assert_equal(expected, actual, "jso_list_add_string() added the wrong string."); ds_list_clear(list); //jso_list_add_sublist() expected = jso_new_list(); jso_list_add_sublist(list, expected); actual = jso_list_get(list, 0); assert_false(ds_list_empty(list), "jso_list_add_sublist() failed to add the sublist."); assert_equal(expected, actual, "jso_list_add_sublist() added the wrong sublist."); ds_list_clear(list); ds_list_destroy(expected); //jso_list_add_submap() expected = jso_new_map(); jso_list_add_submap(list, expected); actual = jso_list_get(list, 0); assert_false(ds_list_empty(list), "jso_list_add_submap() failed to add the submap."); assert_equal(expected, actual, "jso_list_add_submap() added the wrong submap."); ds_list_clear(list); ds_map_destroy(expected); //jso_list_add_integer() expected = 2345; jso_list_add_integer(list, expected); actual = jso_list_get(list, 0); assert_false(ds_list_empty(list), "jso_list_add_integer() failed to add integer."); assert_equal(expected, actual, "jso_list_add_integer() added the wrong integer."); ds_list_clear(list); //jso_list_add_boolean() --- true expected = true; jso_list_add_boolean(list, expected); actual = jso_list_get(list, 0); assert_false(ds_list_empty(list), "jso_list_add_boolean() failed to add boolean true."); assert_true(actual, "jso_list_add_boolean() added the wrong boolean true."); ds_list_clear(list); //jso_list_add_boolean() --- false expected = false; jso_list_add_boolean(list, expected); actual = jso_list_get(list, 0); assert_false(ds_list_empty(list), "jso_list_add_boolean() failed to add boolean false."); assert_false(actual, "jso_list_add_boolean() added the wrong boolean false."); ds_list_clear(list); //Cleanup ds_list_destroy(list); } #define _test_jso_encode { /** _test_jso_encode(): Tests jso_encode_*() functions. JSOnion version: 1.0.0d */ var original, expected, actual; //jso_encode_real() --- Positive expected = 3.1415; actual = jso_encode_real(3.1415); assert_equal(expected, real(actual), "jso_encode_real() failed to encode positive real!"); //jso_encode_real() --- Negative expected = -2.71828; actual = jso_encode_real(-2.71828); assert_equal(expected, real(actual), "jso_encode_real() failed to encode negative real!"); //jso_encode_real() --- Zero expected = 0; actual = jso_encode_integer(0); assert_equal(expected, real(actual), "jso_encode_real() failed to encode zero!"); //jso_encode_integer() --- Positive expected = "2345"; actual = jso_encode_integer(2345); assert_equal(expected, actual, "jso_encode_integer() failed to encode positive integer!"); //jso_encode_integer() --- Negative expected = "-45"; actual = jso_encode_integer(-45); assert_equal(expected, actual, "jso_encode_integer() failed to encode negative integer!"); //jso_encode_integer() --- Zero expected = "0"; actual = jso_encode_integer(0); assert_equal(expected, actual, "jso_encode_integer() failed to encode zero!"); //jso_encode_boolean() --- true expected = "true"; actual = jso_encode_boolean(true); assert_equal(expected, actual, "jso_encode_boolean() failed to encode true!"); //jso_encode_boolean() --- false expected = "false"; actual = jso_encode_boolean(false); assert_equal(expected, actual, "jso_encode_boolean() failed to encode false!"); //jso_encode_string() --- Simple string expected = '"waahoo"'; actual = jso_encode_string("waahoo"); assert_equal(expected, actual, "jso_encode_string() failed to encode simple string!"); //jso_encode_string() --- Empty string expected = '""'; actual = jso_encode_string(""); assert_equal(expected, actual, "jso_encode_string() failed to encode empty string!"); //jso_encode_string() --- Basic escape characters expected = '"\\\"\b\f\n\r\t"'; actual = jso_encode_string('\"' + chr(8) + chr(12) + chr(10) + chr(13) + chr(9)); assert_equal(expected, actual, "jso_encode_string() failed to encode escape character string!"); //jso_encode_map() --- Empty map var empty_map; empty_map = jso_new_map(); expected = "{}"; actual = jso_encode_map(empty_map); assert_equal(expected, actual, "jso_encode_map() failed to encode empty map!"); jso_cleanup_map(empty_map); //jso_encode_map() --- One-element map var one_map; one_map = jso_new_map(); jso_map_add_string(one_map, "key", "value"); expected = '{"key":"value"}'; actual = jso_encode_map(one_map); assert_equal(expected, actual, "jso_encode_map() failed to encode one-element map!"); jso_cleanup_map(one_map); //jso_encode_map() --- Multi-element map var multi_map, ok1, ok2; multi_map = jso_new_map(); jso_map_add_string(multi_map, "key1", "value\1"); jso_map_add_integer(multi_map, "key2", 2); ok1 = '{"key1":"value\\1","key2":2}'; ok2 = '{"key2":2,"key1":"value\\1"}'; actual = jso_encode_map(multi_map); assert_true((actual == ok1) || (actual == ok2), "jso_encode_map() failed to encode multi-element map!"); jso_cleanup_map(multi_map); //jso_encode_list() --- Empty list var empty_list; empty_list = jso_new_list(); expected = "[]"; actual = jso_encode_list(empty_list); assert_equal(expected, actual, "jso_encode_list() failed to encode empty list!"); jso_cleanup_list(empty_list); //jso_encode_list() --- One-element nested list var one_list; one_list = jso_new_list(); jso_list_add_submap(one_list, jso_new_map()); expected = "[{}]"; actual = jso_encode_list(one_list); assert_equal(expected, actual, "jso_encode_list() failed to encode one-element nested list!"); jso_cleanup_list(one_list); //jso_encode_list() --- Multi-element nested list var multi_list, submap, sublist; multi_list = jso_new_list(); submap = jso_new_map(); jso_map_add_string(submap, "1", "one"); jso_list_add_submap(multi_list, submap); jso_list_add_integer(multi_list, 2); sublist = jso_new_list(); jso_list_add_string(sublist, "three"); jso_list_add_boolean(sublist, true); jso_list_add_sublist(multi_list, sublist); expected = '[{"1":"one"},2,["three",true]]'; actual = jso_encode_list(multi_list); assert_equal(expected, actual, "jso_encode_list() failed to encode one-element nested list!"); jso_cleanup_list(multi_list); } #define _test_jso_decode { /** _test_jso_decode(): Test core _jso_decode_*() functions. The formatting is intentionally erratic here to simulate actual formatting deviations. JSOnion version: 1.0.0d */ var json, expected, actual, expected_structure, actual_structure; ////Primitives //_jso_decode_string(): Empty string json = '""'; expected = __jso_gmt_tuple("", 3); actual = _jso_decode_string(json, 1); assert_equal(expected, actual, "_jso_decode_string() failed to decode an empty string!"); //_jso_decode_string(): Small string json = '"key" '; expected = __jso_gmt_tuple("key", 6); actual = _jso_decode_string(json, 1); assert_equal(expected, actual, "_jso_decode_string() failed to decode a small string!"); //_jso_decode_string(): Simple string json = ' "The quick brown fox jumps over the lazy dog." '; expected = __jso_gmt_tuple("The quick brown fox jumps over the lazy dog.", 49); actual = _jso_decode_string(json, 1); assert_equal(expected, actual, "_jso_decode_string() failed to decode a simple string!"); //_jso_decode_string(): Escape characters json = ' "\"\\\b\f\n\r\t\u003A"'; expected = __jso_gmt_tuple('"\' + chr(8) + chr(12) + chr(10) + chr(13) + chr(9) + chr($003a), 24); actual = _jso_decode_string(json, 1); assert_equal(expected, actual, "_jso_decode_string() failed to decode a string with escape characters!"); //_jso_decode_string(): Mixed characters json = ' "\"\\\bWaahoo\f\n\r\tnegg\u003a"'; expected = __jso_gmt_tuple('"\' + chr(8) + "Waahoo" + chr(12) + chr(10) + chr(13) + chr(9) + "negg" + chr($003a), 34); actual = _jso_decode_string(json, 1); assert_equal(expected, actual, "_jso_decode_string() failed to decode a string with mixed characters!"); //_jso_decode_boolean(): True json = 'true'; expected = __jso_gmt_tuple(true, 5); actual = _jso_decode_boolean(json, 1); assert_equal(expected, actual, "_jso_decode_boolean() failed to decode true!"); //_jso_decode_boolean(): False json = ' false '; expected = __jso_gmt_tuple(false, 8); actual = _jso_decode_boolean(json, 1); assert_equal(expected, actual, "_jso_decode_boolean() failed to decode false!"); //_jso_decode_real(): Zero json = '0'; expected = __jso_gmt_tuple(0, 2); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode standard zero!"); //_jso_decode_real(): Signed zero json = ' +0 '; expected = __jso_gmt_tuple(0, 5); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode signed zero!"); //_jso_decode_real(): Signed zero with decimal digits json = ' -0.000'; expected = __jso_gmt_tuple(0, 8); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode signed zero with decimal digits!"); //_jso_decode_real(): Positive real json = '3.14159'; expected = __jso_gmt_tuple(3.14159, 8); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode positive real number!"); //_jso_decode_real(): Negative real json = ' -2.71828'; expected = __jso_gmt_tuple(-2.71828, 10); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode negative real number!"); //_jso_decode_real(): Positive real with positive exponent json = ' 3.14159e2'; expected = __jso_gmt_tuple(3.14159*100, 11); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode positive real number with positive exponent!"); //_jso_decode_real(): Negative real with positive exponent json = ' -2.71828E2'; expected = __jso_gmt_tuple(-2.71828*100, 12); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode negative real number with positive exponent!"); //_jso_decode_real(): Positive real with negative exponent json = ' 314.159e-2'; expected = __jso_gmt_tuple(3.14159, 12); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode positive real number with negative exponent!"); //_jso_decode_real(): Negative real with negative exponent json = ' -271.828E-2'; expected = __jso_gmt_tuple(-2.71828, 13); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode negative real number with negative exponent!"); //_jso_decode_real(): Positive integer json = ' +1729'; expected = __jso_gmt_tuple(1729, 7); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode positive integer!"); //_jso_decode_real(): Negative integer json = '-583'; expected = __jso_gmt_tuple(-583, 5); actual = _jso_decode_real(json, 1); assert_equal(expected, actual, "_jso_decode_real() failed to decode negative integer!"); //_jso_decode_integer(): Zero json = ' 0 '; expected = __jso_gmt_tuple(0, 3); actual = _jso_decode_integer(json, 1); assert_equal(expected, actual, "_jso_decode_integer() failed to decode zero!"); //_jso_decode_integer(): Positive integer json = ' 1729 '; expected = __jso_gmt_tuple(1729, 6); actual = _jso_decode_integer(json, 1); assert_equal(expected, actual, "_jso_decode_integer() failed to decode positive integer!"); //_jso_decode_integer(): Negative integer json = ' -583'; expected = __jso_gmt_tuple(-583, 8); actual = _jso_decode_integer(json, 1); assert_equal(expected, actual, "_jso_decode_integer() failed to decode negative integer!"); ////Data structures //_jso_decode_map(): Empty map #1 json = '{}'; expected_structure = jso_new_map(); expected = __jso_gmt_tuple(expected_structure, 3); actual = _jso_decode_map(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (#1)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (#1)"); assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode an empty map! (#1)"); jso_cleanup_map(expected_structure); jso_cleanup_map(actual_structure); //_jso_decode_map(): Empty map #2 json = ' { } '; expected_structure = jso_new_map(); expected = __jso_gmt_tuple(expected_structure, 7); actual = _jso_decode_map(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (#2)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (#2)"); assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode an empty map! (#2)"); jso_cleanup_map(expected_structure); jso_cleanup_map(actual_structure); //_jso_decode_map(): One-entry map json = ' {"key": "value"} '; expected_structure = jso_new_map(); expected = __jso_gmt_tuple(expected_structure, 18); jso_map_add_string(expected_structure, "key", "value"); actual = _jso_decode_map(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (one-entry map)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (one-entry map)"); assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a one-entry map!"); jso_cleanup_map(expected_structure); jso_cleanup_map(actual_structure); //_jso_decode_map(): Multi-entry map json = ' {"key" : "value", "pi":3.14, "bool" : true} '; expected_structure = jso_new_map(); expected = __jso_gmt_tuple(expected_structure, 48); jso_map_add_string(expected_structure, "key", "value"); jso_map_add_real(expected_structure, "pi", 3.14); jso_map_add_boolean(expected_structure, "bool", true); actual = _jso_decode_map(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (multi-entry map)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (multi-entry map)"); assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a multi-entry map!"); jso_cleanup_map(expected_structure); jso_cleanup_map(actual_structure); //_jso_decode_map(): Nested maps var submap; json = '{ "waahoo" : { "woohah" : 3 } , "woohah" : 4 }'; expected_structure = jso_new_map(); expected = __jso_gmt_tuple(expected_structure, 47); jso_map_add_integer(expected_structure, "woohah", 4); submap = jso_new_map(); jso_map_add_integer(submap, "woohah", 3); jso_map_add_submap(expected_structure, "waahoo", submap); actual = _jso_decode_map(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (nested map)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (nested map)"); assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a nested map!"); jso_cleanup_map(expected_structure); jso_cleanup_map(actual_structure); //_jso_decode_map(): Map with nested lists var sublist, subsublist; json = '{ "waahoo" : [ "woohah", [true] ] , "woohah" : 4 }'; expected_structure = jso_new_map(); expected = __jso_gmt_tuple(expected_structure, 51); jso_map_add_real(expected_structure, "woohah", 4); sublist = jso_new_list(); jso_list_add_string(sublist, "woohah"); subsublist = jso_new_list(); jso_list_add_boolean(subsublist, true); jso_list_add_sublist(sublist, subsublist); jso_map_add_sublist(expected_structure, "waahoo", sublist); actual = _jso_decode_map(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (map with nested lists)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (map with nested lists)"); assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a map with nested lists!"); jso_cleanup_map(expected_structure); jso_cleanup_map(actual_structure); //_jso_decode_map(): Mix-up nested map var sublist; json = ' { "waahoo" : [{}, "a", 1] }'; expected_structure = jso_new_map(); expected = __jso_gmt_tuple(expected_structure, 30); sublist = jso_new_list(); jso_list_add_submap(sublist, jso_new_map()); jso_list_add_string(sublist, "a"); jso_list_add_real(sublist, 1); jso_map_add_sublist(expected_structure, "waahoo", sublist); actual = _jso_decode_map(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_map() didn't stop at the right place! (mix-up nested map)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_map() didn't include the right prefix! (mix-up nested map)"); assert_true(jso_compare_maps(expected_structure, actual_structure), "_jso_decode_map() failed to decode a mix-up nested map!"); jso_cleanup_map(expected_structure); jso_cleanup_map(actual_structure); //_jso_decode_list(): Empty list #1 json = '[]'; expected_structure = jso_new_list(); expected = __jso_gmt_tuple(expected_structure, 3); actual = _jso_decode_list(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (#1)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (#1)"); assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode an empty list! (#1)"); jso_cleanup_list(expected_structure); jso_cleanup_list(actual_structure) //_jso_decode_list(): Empty list #2 json = ' [ ] '; expected_structure = jso_new_list(); expected = __jso_gmt_tuple(expected_structure, 6); actual = _jso_decode_list(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (#2)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (#2)"); assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode an empty list! (#2)"); jso_cleanup_list(expected_structure); jso_cleanup_list(actual_structure); //_jso_decode_list(): One-entry list json = '[3]'; expected_structure = jso_new_list(); expected = __jso_gmt_tuple(expected_structure, 4); jso_list_add_integer(expected_structure, 3); actual = _jso_decode_list(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (one-entry list)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (one-entry list)"); assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a one-entry list!"); jso_cleanup_list(expected_structure); jso_cleanup_list(actual_structure); //_jso_decode_list(): Multi-entry list json = ' [4,"multi-entry",true]'; expected_structure = jso_new_list(); expected = __jso_gmt_tuple(expected_structure, 24); jso_list_add_real(expected_structure, 4); jso_list_add_string(expected_structure, "multi-entry"); jso_list_add_boolean(expected_structure, true); actual = _jso_decode_list(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (multi-entry list)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (multi-entry list)"); assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a multi-entry list!"); jso_cleanup_list(expected_structure); jso_cleanup_list(actual_structure); //_jso_decode_list(): Nested list var sublist; json = ' [ [], 3, false, ["waahoo"]]'; expected_structure = jso_new_list(); expected = __jso_gmt_tuple(expected_structure, 29); jso_list_add_sublist(expected_structure, jso_new_list()); jso_list_add_integer(expected_structure, 3); jso_list_add_boolean(expected_structure, false); sublist = jso_new_list(); jso_list_add_string(sublist, "waahoo"); jso_list_add_sublist(expected_structure, sublist); actual = _jso_decode_list(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (nested list)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (nested list)"); assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a nested list!"); jso_cleanup_list(expected_structure); jso_cleanup_list(actual_structure); //_jso_decode_list(): List with nested maps var submap; json = ' [3, false, { "waahoo":"woo"}]'; expected_structure = jso_new_list(); expected = __jso_gmt_tuple(expected_structure, 31); jso_list_add_integer(expected_structure, 3); jso_list_add_boolean(expected_structure, false); submap = jso_new_map(); jso_map_add_string(submap, "waahoo", "woo"); jso_list_add_submap(expected_structure, submap); actual = _jso_decode_list(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (list with nested maps)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (list with nested maps)"); assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a list with nested maps!"); jso_cleanup_list(expected_structure); jso_cleanup_list(actual_structure); //_jso_decode_list(): Mix-up nested list var submap; json = '[{}, {"a":[]}]'; expected_structure = jso_new_list(); expected = __jso_gmt_tuple(expected_structure, 15); jso_list_add_submap(expected_structure, jso_new_map()); submap = jso_new_map(); jso_map_add_sublist(submap, "a", jso_new_list()); jso_list_add_submap(expected_structure, submap); actual = _jso_decode_list(json, 1); actual_structure = __jso_gmt_elem(actual, 0); assert_equal(__jso_gmt_elem(expected, 1), __jso_gmt_elem(actual, 1), "_jso_decode_list() didn't stop at the right place! (mix-up nested list)"); assert_equal(actual_structure, __jso_gmt_elem(actual, 0), "_jso_decode_list() didn't include the right prefix! (mix-up nested list)"); assert_true(jso_compare_lists(expected_structure, actual_structure), "_jso_decode_list() failed to decode a mix-up nested list!"); jso_cleanup_list(expected_structure); jso_cleanup_list(actual_structure); } #define _test_jso_compare { /** _test_jso_compare(): Test basic jso_compare_*() functions. JSOnion version: 1.0.0d */ var a, b; //jso_compare_maps(): Empty maps should equal each other a = jso_new_map(); b = jso_new_map(); assert_true(jso_compare_maps(a, b), "Empty maps should equal each other. (#1)"); assert_true(jso_compare_maps(b, a), "Empty maps should equal each other. (#2)"); jso_cleanup_map(a); jso_cleanup_map(b); //jso_compare_maps(): An empty map should not equal a filled map a = jso_new_map(); b = jso_new_map(); jso_map_add_string(b, "junk", "info"); jso_map_add_integer(b, "taxi", 1729); assert_false(jso_compare_maps(a, b), "An empty map should not equal a filled map. (#1)"); assert_false(jso_compare_maps(b, a), "An empty map should not equal a filled map. (#2)"); jso_cleanup_map(a); jso_cleanup_map(b); //jso_compare_maps(): Maps with same content entered in different orders should equal each other a = jso_new_map(); b = jso_new_map(); jso_map_add_real(a, "A", 1); jso_map_add_real(a, "B", 2); jso_map_add_real(a, "C", 3); jso_map_add_real(b, "C", 3); jso_map_add_real(b, "A", 1); jso_map_add_real(b, "B", 2); assert_true(jso_compare_maps(a, b), "Maps with same content entered in different orders should equal each other. (#1)"); assert_true(jso_compare_maps(b, a), "Maps with same content entered in different orders should equal each other. (#2)"); jso_cleanup_map(a); jso_cleanup_map(b); //jso_compare_maps(): Maps with different keys should not equal each other a = jso_new_map(); b = jso_new_map(); jso_map_add_real(a, "A", 1); jso_map_add_real(a, "B", 2); jso_map_add_real(a, "C", 3); jso_map_add_real(b, "D", 3); jso_map_add_real(b, "A", 1); jso_map_add_real(b, "B", 2); assert_false(jso_compare_maps(a, b), "Maps with different keys should not equal each other. (#1)"); assert_false(jso_compare_maps(b, a), "Maps with different keys should not equal each other. (#2)"); jso_cleanup_map(a); jso_cleanup_map(b); //jso_compare_maps(): Maps with different values should not equal each other a = jso_new_map(); b = jso_new_map(); jso_map_add_real(a, "A", 5); jso_map_add_real(a, "B", 6); jso_map_add_real(a, "C", 9); jso_map_add_real(b, "A", 5); jso_map_add_real(b, "B", 6); jso_map_add_real(b, "C", 8); assert_false(jso_compare_maps(a, b), "Maps with different values should not equal each other. (#1)"); assert_false(jso_compare_maps(b, a), "Maps with different values should not equal each other. (#2)"); jso_cleanup_map(a); jso_cleanup_map(b); //jso_compare_maps(): Maps with corresponding values of different types should not equal each other, and should not crash. a = jso_new_map(); b = jso_new_map(); jso_map_add_real(a, "A", 5); jso_map_add_real(a, "B", 6); jso_map_add_real(a, "C", 8); jso_map_add_real(b, "A", 5); jso_map_add_string(b, "B", "six"); jso_map_add_real(b, "C", 8); assert_false(jso_compare_maps(a, b), "Maps with corresponding values of different types should not equal each other, and should not crash. (#1)"); assert_false(jso_compare_maps(b, a), "Maps with corresponding values of different types should not equal each other, and should not crash. (#2)"); jso_cleanup_map(a); jso_cleanup_map(b); //jso_compare_lists(): Empty lists should equal each other a = jso_new_list(); b = jso_new_list(); assert_true(jso_compare_lists(a, b), "Empty lists should equal each other. (#1)"); assert_true(jso_compare_lists(b, a), "Empty lists should equal each other. (#2)"); jso_cleanup_list(a); jso_cleanup_list(b); //jso_compare_lists(): An empty list should not equal a filled list a = jso_new_list(); b = jso_new_list(); jso_list_add_string(b, "junk"); jso_list_add_integer(b, 1729); assert_false(jso_compare_lists(a, b), "An empty list should not equal a filled list. (#1)"); assert_false(jso_compare_lists(b, a), "An empty list should not equal a filled list. (#2)"); jso_cleanup_list(a); jso_cleanup_list(b); //jso_compare_lists(): Lists with same content entered in different orders should not equal each other a = jso_new_list(); b = jso_new_list(); jso_list_add_real(a, 1); jso_list_add_real(a, 2); jso_list_add_real(a, 3); jso_list_add_real(b, 3); jso_list_add_real(b, 1); jso_list_add_real(b, 2); assert_false(jso_compare_lists(a, b), "Lists with same content entered in different orders should not equal each other. (#1)"); assert_false(jso_compare_lists(b, a), "Lists with same content entered in different orders should not equal each other. (#2)"); jso_cleanup_list(a); jso_cleanup_list(b); //jso_compare_lists(): Lists with corresponding entries of different types should not equal each other, should also not crash. a = jso_new_list(); b = jso_new_list(); jso_list_add_real(a, 1); jso_list_add_real(a, 2); jso_list_add_real(a, 3); jso_list_add_real(b, 1); jso_list_add_string(b, "two"); jso_list_add_real(b, 3); assert_false(jso_compare_lists(a, b), "Lists with corresponding entries of different types should not equal each other, should also not crash. (#1)"); assert_false(jso_compare_lists(b, a), "Lists with corresponding entries of different types should not equal each other, should also not crash. (#2)"); jso_cleanup_list(a); jso_cleanup_list(b); } #define _test_jso_lookup { /** _test_jso_lookup(): Test core jso_*_lookup() and jso_*_check() functions for nested structures. JSOnion version: 1.0.0d */ var json, structure, expected, actual; //jso_map_check(): Single argument --- exists json = '{ "one" : 1, "two" : 2, "three" : 3 }'; structure = jso_decode_map(json); assert_true(jso_map_check(structure, "one"), "jso_map_check() failed to find existing entry! (single argument)"); jso_cleanup_map(structure); //jso_map_lookup(): Single argument --- exists json = '{ "one" : 1, "two" : 2, "three" : 3 }'; structure = jso_decode_map(json); expected = 1; actual = jso_map_lookup(structure, "one") assert_equal(expected, actual, "jso_map_lookup() found the wrong entry! (single argument)"); jso_cleanup_map(structure); //jso_map_lookup_type(): Single argument --- exists json = '{ "one" : -1, "two" : true, "three" : "trap" }'; structure = jso_decode_map(json); expected = jso_type_real; actual = jso_map_lookup_type(structure, "one") assert_equal(expected, actual, "jso_map_lookup_type() found the wrong type! (single argument)"); jso_cleanup_map(structure); //jso_map_check(): Single argument --- doesn't exist json = '{ "one" : 1, "two" : 2, "three" : 3 }'; structure = jso_decode_map(json); assert_false(jso_map_check(structure, "four"), "jso_map_check() found an inexistent entry! (single argument)"); jso_cleanup_map(structure); //jso_map_check(): Single argument --- doesn't exist json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; structure = jso_decode_map(json); assert_false(jso_map_check(structure, "A"), "jso_map_check() found an inexistent entry! (single argument, nested)"); jso_cleanup_map(structure); //jso_map_check(): Multiple arguments (recurse) --- exists json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; structure = jso_decode_map(json); assert_true(jso_map_check(structure, "four", "A"), "jso_map_check() failed to find existing entry! (multiple arguments)"); jso_cleanup_map(structure); //jso_map_lookup(): Multiple arguments (recurse) --- exists json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; structure = jso_decode_map(json); expected = true; actual = jso_map_lookup(structure, "four", "A"); assert_equal(expected, actual, "jso_map_lookup() found the wrong entry! (multiple arguments)"); jso_cleanup_map(structure); //jso_map_lookup_type(): Multiple arguments (recurse) --- exists json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":"trap" } }'; structure = jso_decode_map(json); expected = jso_type_boolean; actual = jso_map_lookup_type(structure, "four", "A"); assert_equal(expected, actual, "jso_map_lookup_type() found the wrong type! (multiple arguments)"); jso_cleanup_map(structure); //jso_map_check(): Multiple arguments (recurse) --- doesn't exist json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; structure = jso_decode_map(json); assert_false(jso_map_check(structure, "four", "C"), "jso_map_check() found an inexistent entry! (multiple arguments, 1)"); jso_cleanup_map(structure); //jso_map_check(): Multiple arguments (recurse) --- doesn't exist json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : { "A":true, "B":false } }'; structure = jso_decode_map(json); assert_false(jso_map_check(structure, "three", ""), "jso_map_check() found an inexistent entry! (multiple arguments, 2)"); jso_cleanup_map(structure); //jso_map_check(): Multiple arguments with nested list --- exists json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, ["B", false] ] }'; structure = jso_decode_map(json); assert_true(jso_map_check(structure, "four", 2, 1), "jso_map_check() failed to find an existing entry! (multiple arguments, nested)"); jso_cleanup_map(structure); //jso_map_lookup(): Multiple arguments with nested list --- exists json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, ["B", false] ] }'; structure = jso_decode_map(json); expected = false; actual = jso_map_lookup(structure, "four", 2, 1); assert_equal(expected, actual, "jso_map_lookup() failed to find an existing entry! (multiple arguments, nested)"); jso_cleanup_map(structure); //jso_map_lookup_type(): Multiple arguments with nested list --- exists json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, [false, "false"] ] }'; structure = jso_decode_map(json); expected = jso_type_string; actual = jso_map_lookup_type(structure, "four", 2, 1); assert_equal(expected, actual, "jso_map_lookup_type() found the wrong type! (multiple arguments, nested)"); jso_cleanup_map(structure); //jso_map_check(): Multiple arguments with nested list --- wrong type json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, ["B", false] ] }'; structure = jso_decode_map(json); assert_false(jso_map_check(structure, "four", "A", 1), "jso_map_check() found an inexistent entry! (multiple arguments, nested, wrong type)"); jso_cleanup_map(structure); //jso_map_check(): Multiple arguments with nested list --- index overflow json = '{ "one" : 1, "two" : 2, "three" : 3, "four" : [ "A", true, ["B", false] ] }'; structure = jso_decode_map(json); assert_false(jso_map_check(structure, "four", 2, 3), "jso_map_check() found an inexistent entry! (multiple arguments, nested, index overflow)"); jso_cleanup_map(structure); //jso_list_check(): Single argument --- exists json = '["one", 2, "three", true, 5]'; structure = jso_decode_list(json); assert_true(jso_list_check(structure, 2), "jso_list_check() failed to find an existing index! (single argument)"); jso_cleanup_list(structure); //jso_list_lookup(): Single argument --- exists json = '["one", 2, "three", true, 5]'; structure = jso_decode_list(json); expected = "three"; actual = jso_list_lookup(structure, 2); assert_equal(expected, actual, "jso_list_lookup() found the wrong index! (single argument)"); jso_cleanup_list(structure); //jso_list_lookup_type(): Single argument --- exists json = '["one", 2, "three", true, 5]'; structure = jso_decode_list(json); expected = jso_type_string; actual = jso_list_lookup_type(structure, 2); assert_equal(expected, actual, "jso_list_lookup_type() found the wrong type! (single argument)"); jso_cleanup_list(structure); //jso_list_check(): Single argument --- doesn't exist json = '["one", 2, "three", true, 5]'; structure = jso_decode_list(json); assert_false(jso_list_check(structure, 5), "jso_list_check() found an inexistent index! (single argument)"); jso_cleanup_list(structure); //jso_list_check(): Multiple arguments (recurse) --- exists json = '["one", 2, ["three", 3], true, 5]'; structure = jso_decode_list(json); assert_true(jso_list_check(structure, 2, 1), "jso_list_check() failed to find an existing index! (multiple arguments)"); jso_cleanup_list(structure); //jso_list_lookup(): Multiple arguments (recurse) --- exists json = '["one", 2, ["three", 3], true, 5]'; structure = jso_decode_list(json); expected = 3; actual = jso_list_lookup(structure, 2, 1); assert_equal(expected, actual, "jso_list_lookup() failed to find an existing index! (multiple arguments)"); jso_cleanup_list(structure); //jso_list_lookup_type(): Multiple arguments (recurse) --- exists json = '["one", 2, ["three", 3], true, 5]'; structure = jso_decode_list(json); expected = jso_type_real; actual = jso_list_lookup_type(structure, 2, 1); assert_equal(expected, actual, "jso_list_lookup_type() found the wrong type! (multiple arguments)"); jso_cleanup_list(structure); //jso_list_check(): Multiple arguments (recurse) --- doesn't exist, inner index overflow json = '["one", 2, ["three", 3], true, 5]'; structure = jso_decode_list(json); assert_false(jso_list_check(structure, 2, 2), "jso_list_check() found an inexistent index! (multiple arguments, inner index overflow)"); jso_cleanup_list(structure); //jso_list_check(): Multiple arguments (recurse) --- doesn't exist, trying to index single entry json = '["one", 2, ["three", 3], true, 5]'; structure = jso_decode_list(json); assert_false(jso_list_check(structure, 1, 0), "jso_list_check() found an inexistent index! (multiple arguments, indexing single entry)"); jso_cleanup_list(structure); //jso_list_check(): Multiple arguments with nested map --- exists json = '["one", 2, {"three":3}, true, 5]'; structure = jso_decode_list(json); assert_true(jso_list_check(structure, 2, "three"), "jso_list_check() failed to find an existing entry! (multiple arguments, nested map)"); jso_cleanup_list(structure); //jso_list_lookup(): Multiple arguments with nested map --- exists json = '["one", 2, {"three":3}, true, 5]'; structure = jso_decode_list(json); expected = 3; actual = jso_list_lookup(structure, 2, "three"); assert_equal(expected, actual, "jso_list_lookup() failed to find an existing entry! (multiple arguments, nested map)"); jso_cleanup_list(structure); //jso_list_lookup_type(): Multiple arguments with nested map --- exists json = '["one", 2, {"three":false}, true, 5]'; structure = jso_decode_list(json); expected = jso_type_boolean; actual = jso_list_lookup_type(structure, 2, "three"); assert_equal(expected, actual, "jso_list_lookup_type() found the wrong type! (multiple arguments, nested map)"); jso_cleanup_list(structure); //jso_list_exists(): Multiple arguments with nested map --- doesn't exist, key on single entry json = '["one", 2, {"three":3}, true, 5]'; structure = jso_decode_list(json); assert_false(jso_list_check(structure, 1, ""), "jso_list_check() found an inexistent entry! (multiple arguments, nested map, key on single entry)"); jso_cleanup_list(structure); //jso_list_exists(): Multiple arguments with nested map --- doesn't exist, bad key json = '["one", 2, {"three":3}, true, 5]'; structure = jso_decode_list(json); assert_false(jso_list_check(structure, 2, ""), "jso_list_check() found an inexistent entry! (multiple arguments, nested map, bad key)"); jso_cleanup_list(structure); } #define _test_jso_bugs { /** _test_jso_bugs(): Test reported bugs. JSOnion version: 1.0.0d */ var expected, actual; //jso_encode_map() --- One-element map //Bug 1: Crash when encoding boolean-valued entries in maps, unknown variable jso_type_integer var one_map; one_map = jso_new_map(); jso_map_add_boolean(one_map, "true", true); expected = '{"true":true}'; actual = jso_encode_map(one_map); assert_equal(expected, actual, "jso_encode_map() failed to encode one-element map with boolean entry!"); jso_cleanup_map(one_map); }