Difference between revisions of "Json usage in LSL/TestScript"
Kireji Haiku (talk | contribs) m (→Full Test Script: do not recalculate the list length every iteration within the loop) |
|||
Line 166: | Line 166: | ||
<lsl> | <lsl> | ||
// This is just the framework for creating new tests for LSL JSON functions without the tests. | // This is just the framework for creating new tests for LSL JSON functions without the tests. | ||
integer total_number_of_tests; | integer total_number_of_tests; | ||
integer total_number_of_fails; | integer total_number_of_fails; | ||
string typeName(string type_flag) | string typeName(string type_flag) | ||
{ | { | ||
if (type_flag == JSON_INVALID) return "JSON_INVALID"; | if (type_flag == JSON_INVALID) return "JSON_INVALID"; | ||
/* else */ if (type_flag == JSON_OBJECT) return "JSON_OBJECT"; | /* else */ if (type_flag == JSON_OBJECT) return "JSON_OBJECT"; | ||
/* else */ if (type_flag == JSON_ARRAY) return "JSON_ARRAY"; | /* else */ if (type_flag == JSON_ARRAY) return "JSON_ARRAY"; | ||
/* else */ if (type_flag == JSON_NUMBER) return "JSON_NUMBER"; | /* else */ if (type_flag == JSON_NUMBER) return "JSON_NUMBER"; | ||
/* else */ if (type_flag == JSON_STRING) return "JSON_STRING"; | /* else */ if (type_flag == JSON_STRING) return "JSON_STRING"; | ||
/* else */ if (type_flag == JSON_NULL) return "JSON_NULL"; | /* else */ if (type_flag == JSON_NULL) return "JSON_NULL"; | ||
/* else */ if (type_flag == JSON_TRUE) return "JSON_TRUE"; | /* else */ if (type_flag == JSON_TRUE) return "JSON_TRUE"; | ||
/* else */ if (type_flag == JSON_FALSE) return "JSON_FALSE"; | /* else */ if (type_flag == JSON_FALSE) return "JSON_FALSE"; | ||
/* else */ if (type_flag == JSON_DELETE) return "JSON_DELETE"; | /* else */ if (type_flag == JSON_DELETE) return "JSON_DELETE"; | ||
/* else ...... type_flag unknown */ return type_flag; | /* else ...... type_flag unknown */ return type_flag; | ||
} | } | ||
string listEntryTypeName(integer type) | string listEntryTypeName(integer type) | ||
{ | { | ||
Line 200: | Line 200: | ||
"TYPE_ROTATION" | "TYPE_ROTATION" | ||
]; | ]; | ||
integer length = llGetListLength(list_type_names); | integer length = llGetListLength(list_type_names); | ||
if (length <= type) return "UNKNOWN_LIST_TYPE"; | if (length <= type) return "UNKNOWN_LIST_TYPE"; | ||
/* else */ return llList2String(list_type_names, type); | /* else */ return llList2String(list_type_names, type); | ||
} | } | ||
integer max(integer x, integer y) | integer max(integer x, integer y) | ||
{ | { | ||
Line 212: | Line 212: | ||
/* else */ return x; | /* else */ return x; | ||
} | } | ||
integer verify(string message, string result, string expected) | integer verify(string message, string result, string expected) | ||
{ | { | ||
++total_number_of_tests; | ++total_number_of_tests; | ||
if (result != expected) | if (result != expected) | ||
{ | { | ||
++total_number_of_fails; | ++total_number_of_fails; | ||
publish("TEST FAILED" | publish("TEST FAILED" | ||
+ "\nexpected: " + typeName(expected) | + "\nexpected: " + typeName(expected) | ||
Line 226: | Line 226: | ||
+ "\nJSON string value: " + message | + "\nJSON string value: " + message | ||
+ "\n "); | + "\n "); | ||
return FALSE; | return FALSE; | ||
} | } | ||
Line 232: | Line 232: | ||
return TRUE; | return TRUE; | ||
} | } | ||
verify_list(string message, list result, list expected) | verify_list(string message, list result, list expected) | ||
{ | { | ||
integer length_result = llGetListLength(result); | integer length_result = llGetListLength(result); | ||
integer length_expected = llGetListLength(expected); | integer length_expected = llGetListLength(expected); | ||
// first verify that the list lengths match before looking at the data types | // first verify that the list lengths match before looking at the data types | ||
verify(message + ": list length", | verify(message + ": list length", | ||
(string)length_result, | (string)length_result, | ||
(string)length_expected); | (string)length_expected); | ||
// the CSV string comparison is probably enough to verify that the values stored are correct | // the CSV string comparison is probably enough to verify that the values stored are correct | ||
// but I want to check data type too | // but I want to check data type too | ||
integer index = max(length_result, length_expected); | integer index = max(length_result, length_expected); | ||
while (--index >= 0) | while (--index >= 0) | ||
Line 253: | Line 253: | ||
listEntryTypeName(llGetListEntryType(result, index)), | listEntryTypeName(llGetListEntryType(result, index)), | ||
listEntryTypeName(llGetListEntryType(expected, index))); | listEntryTypeName(llGetListEntryType(expected, index))); | ||
verify(message + ": on list value comparison on index " + (string)index, | verify(message + ": on list value comparison on index " + (string)index, | ||
typeName(llList2String(result, index)), | typeName(llList2String(result, index)), | ||
typeName(llList2String(expected, index))); | typeName(llList2String(expected, index))); | ||
} | } | ||
verify(message + ": llList2CSV comparison", | verify(message + ": llList2CSV comparison", | ||
llList2CSV(result), | llList2CSV(result), | ||
llList2CSV(expected)); | llList2CSV(expected)); | ||
} | } | ||
run_tests() | run_tests() | ||
{ | { | ||
publish("JSON TESTS: started" | publish("JSON TESTS: started" | ||
+ "\n "); | + "\n "); | ||
total_number_of_tests = 0; | total_number_of_tests = 0; | ||
total_number_of_fails = 0; | total_number_of_fails = 0; | ||
test_types(); | test_types(); | ||
test_get_value(); | test_get_value(); | ||
Line 279: | Line 279: | ||
test_strings_with_escaped_chars(); | test_strings_with_escaped_chars(); | ||
test_jira_fixes(); | test_jira_fixes(); | ||
publish("JSON TESTS: done\n" | publish("JSON TESTS: done\n" | ||
+ (string)total_number_of_fails + " of " | + (string)total_number_of_fails + " of " | ||
Line 285: | Line 285: | ||
+ "\n "); | + "\n "); | ||
} | } | ||
publish(string message) | publish(string message) | ||
{ | { | ||
Line 291: | Line 291: | ||
// | // | ||
llOwnerSay(message); | llOwnerSay(message); | ||
// if you want to make it public | // if you want to make it public | ||
// | // | ||
// llSay(PUBLIC_CHANNEL, message); | // llSay(PUBLIC_CHANNEL, message); | ||
// if you want to reach the owner wherever she/he is as fast as you can | // if you want to reach the owner wherever she/he is as fast as you can | ||
// | // | ||
Line 303: | Line 303: | ||
// else llInstantMessage(owner, message); | // else llInstantMessage(owner, message); | ||
} | } | ||
test_types() | test_types() | ||
{ | { | ||
Line 326: | Line 326: | ||
verify("Type of false",llJsonValueType("false",[]),JSON_FALSE); | verify("Type of false",llJsonValueType("false",[]),JSON_FALSE); | ||
verify("Type of null",llJsonValueType("null",[]),JSON_NULL); | verify("Type of null",llJsonValueType("null",[]),JSON_NULL); | ||
// test traversal of llJsonValueType | // test traversal of llJsonValueType | ||
string json = "[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6],\"c\":\"true\",\"d\":false}]"; | string json = "[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6],\"c\":\"true\",\"d\":false}]"; | ||
Line 343: | Line 343: | ||
verify("Type of [1,\"b\",3] (invalid index at level 2)",llJsonValueType(json,[1,"b",3]),JSON_INVALID); | verify("Type of [1,\"b\",3] (invalid index at level 2)",llJsonValueType(json,[1,"b",3]),JSON_INVALID); | ||
verify("Type of [1,\"b\",2,0,1] (invalid index at level 3) MAINT-2670",llJsonValueType(json,[1,"b",2, 0, 1]),JSON_INVALID); | verify("Type of [1,\"b\",2,0,1] (invalid index at level 3) MAINT-2670",llJsonValueType(json,[1,"b",2, 0, 1]),JSON_INVALID); | ||
// some invalid cases where keys are uncoded | // some invalid cases where keys are uncoded | ||
json = "[[1,2,3],{a:3,b:[true,\"test\",6],c:\"true\",\"d\":false}]"; | json = "[[1,2,3],{a:3,b:[true,\"test\",6],c:\"true\",\"d\":false}]"; | ||
Line 350: | Line 350: | ||
verify("Type of [1,\"c\"] where key is unquoted",llJsonValueType(json,[1,"c"]),JSON_INVALID); | verify("Type of [1,\"c\"] where key is unquoted",llJsonValueType(json,[1,"c"]),JSON_INVALID); | ||
} | } | ||
test_get_value() | test_get_value() | ||
{ | { | ||
Line 368: | Line 368: | ||
verify("llJsonGetValue [0,\"f\"] (look for missing object within array, depth=1) MAINT-2671",llJsonGetValue(json,[0,"f"]),JSON_INVALID); | verify("llJsonGetValue [0,\"f\"] (look for missing object within array, depth=1) MAINT-2671",llJsonGetValue(json,[0,"f"]),JSON_INVALID); | ||
verify("llJsonGetValue [1,2] (specify index within object - disallowed)",llJsonGetValue(json,[1,2]),JSON_INVALID); | verify("llJsonGetValue [1,2] (specify index within object - disallowed)",llJsonGetValue(json,[1,2]),JSON_INVALID); | ||
// invalid input json - missing quotes around 'a' and 'test' | // invalid input json - missing quotes around 'a' and 'test' | ||
json = "[[1,2,3,4.0],{a:3,\"b\":[true,test,6]}]"; | json = "[[1,2,3,4.0],{a:3,\"b\":[true,test,6]}]"; | ||
Line 374: | Line 374: | ||
verify("llJsonGetValue [1,\"a\"], unquoted/invalid string for key",llJsonGetValue(json,[1,"a"]),JSON_INVALID); | verify("llJsonGetValue [1,\"a\"], unquoted/invalid string for key",llJsonGetValue(json,[1,"a"]),JSON_INVALID); | ||
} | } | ||
test_set_value() | test_set_value() | ||
{ | { | ||
Line 393: | Line 393: | ||
json = llJsonSetValue(json,[1,"b",2],"6"); | json = llJsonSetValue(json,[1,"b",2],"6"); | ||
verify("llJsonSetValue completed json",json,"[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6]}]"); | verify("llJsonSetValue completed json",json,"[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6]}]"); | ||
// Test replacing | // Test replacing | ||
json = llJsonSetValue(json,[1,"b",1],"foo"); | json = llJsonSetValue(json,[1,"b",1],"foo"); | ||
Line 403: | Line 403: | ||
json = llJsonSetValue(json,[1,0,0],JSON_FALSE); | json = llJsonSetValue(json,[1,0,0],JSON_FALSE); | ||
verify("llJsonSetValue completed json",json,"[[1,2,3],[[false]]]"); | verify("llJsonSetValue completed json",json,"[[1,2,3],[[false]]]"); | ||
// Test appending | // Test appending | ||
json = llJsonSetValue("[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6]}]",[0,JSON_APPEND], "4.0"); | json = llJsonSetValue("[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6]}]",[0,JSON_APPEND], "4.0"); | ||
Line 417: | Line 417: | ||
json = llJsonSetValue("[]",[0], "\"alone\""); | json = llJsonSetValue("[]",[0], "\"alone\""); | ||
verify("llJsonSetValue append to empty array at first index (MAINT-2684)",json,"[\"alone\"]"); | verify("llJsonSetValue append to empty array at first index (MAINT-2684)",json,"[\"alone\"]"); | ||
// Test deleting | // Test deleting | ||
json = "[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6,null]}]"; | json = "[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6,null]}]"; | ||
Line 438: | Line 438: | ||
json = llJsonSetValue(json,[0],JSON_DELETE); | json = llJsonSetValue(json,[0],JSON_DELETE); | ||
verify("llJsonSetValue deleting array within array",json,"[]"); | verify("llJsonSetValue deleting array within array",json,"[]"); | ||
// Test failures in deleting | // Test failures in deleting | ||
json = "[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6,null]}]"; | json = "[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6,null]}]"; | ||
Line 445: | Line 445: | ||
verify("llJsonSetValue deleting depth within object that doesn't exist",llJsonSetValue(json,[1,"a","unicorn"],JSON_DELETE),JSON_INVALID); | verify("llJsonSetValue deleting depth within object that doesn't exist",llJsonSetValue(json,[1,"a","unicorn"],JSON_DELETE),JSON_INVALID); | ||
verify("llJsonSetValue deleting depth within array that doesn't exist",llJsonSetValue(json,[0,1,1],JSON_DELETE),JSON_INVALID); | verify("llJsonSetValue deleting depth within array that doesn't exist",llJsonSetValue(json,[0,1,1],JSON_DELETE),JSON_INVALID); | ||
// this is the only failure mode that should exist. | // this is the only failure mode that should exist. | ||
json = "[[1,2,3],{\"a\":3,\"b\":[true,\"foo\",6]}]"; | json = "[[1,2,3],{\"a\":3,\"b\":[true,\"foo\",6]}]"; | ||
json = llJsonSetValue(json,[3],JSON_FALSE); | json = llJsonSetValue(json,[3],JSON_FALSE); | ||
verify("llJsonSetValue fail to insert data into invalid array index (MAINT-2675)",json,JSON_INVALID); | verify("llJsonSetValue fail to insert data into invalid array index (MAINT-2675)",json,JSON_INVALID); | ||
} | } | ||
test_json_to_list() | test_json_to_list() | ||
{ | { | ||
Line 476: | Line 476: | ||
verify_list("llJson2List, malformed input",n,["[malformed}"]); | verify_list("llJson2List, malformed input",n,["[malformed}"]); | ||
} | } | ||
test_list_to_json() | test_list_to_json() | ||
{ | { | ||
Line 482: | Line 482: | ||
string json = llList2Json(JSON_OBJECT,["a",1,"b",2.5,"c","test","d","true","e","[1,2,3]"]); | string json = llList2Json(JSON_OBJECT,["a",1,"b",2.5,"c","test","d","true","e","[1,2,3]"]); | ||
verify("llList2Json, json object",json,"{\"a\":1,\"b\":2.500000,\"c\":\"test\",\"d\":true,\"e\":[1,2,3]}"); | verify("llList2Json, json object",json,"{\"a\":1,\"b\":2.500000,\"c\":\"test\",\"d\":true,\"e\":[1,2,3]}"); | ||
// test arrays | // test arrays | ||
json = llList2Json(JSON_ARRAY,[1,2.5,"test","true","[1,2,3]"]); | json = llList2Json(JSON_ARRAY,[1,2.5,"test","true","[1,2,3]"]); | ||
verify("llList2Json, json array",json,"[1,2.500000,\"test\",true,[1,2,3]]"); | verify("llList2Json, json array",json,"[1,2.500000,\"test\",true,[1,2,3]]"); | ||
// test arrays | // test arrays | ||
json = llList2Json(JSON_ARRAY,[1,2.5,"test",JSON_TRUE,"[1,2,3]"]); | json = llList2Json(JSON_ARRAY,[1,2.5,"test",JSON_TRUE,"[1,2,3]"]); | ||
verify("llList2Json, json array, alternative true representation",json,"[1,2.500000,\"test\",true,[1,2,3]]"); | verify("llList2Json, json array, alternative true representation",json,"[1,2.500000,\"test\",true,[1,2,3]]"); | ||
// test objects, with empty input | // test objects, with empty input | ||
json = llList2Json(JSON_OBJECT,[]); | json = llList2Json(JSON_OBJECT,[]); | ||
verify("llList2Json, json object with empty input (MAINT-2681)",json,"{}"); | verify("llList2Json, json object with empty input (MAINT-2681)",json,"{}"); | ||
// test arrays, with empty input | // test arrays, with empty input | ||
json = llList2Json(JSON_ARRAY,[]); | json = llList2Json(JSON_ARRAY,[]); | ||
verify("llList2Json, json array with empty input (MAINT-2681)",json,"[]"); | verify("llList2Json, json array with empty input (MAINT-2681)",json,"[]"); | ||
// test objects which are truncated | // test objects which are truncated | ||
json = llList2Json(JSON_OBJECT,["a",1,"b",2.5,"c","test","d","true","e"]); | json = llList2Json(JSON_OBJECT,["a",1,"b",2.5,"c","test","d","true","e"]); | ||
verify("llList2Json, json object, truncated",json,JSON_INVALID); | verify("llList2Json, json object, truncated",json,JSON_INVALID); | ||
// test objects which has a non-string identifier somewhere | // test objects which has a non-string identifier somewhere | ||
json = llList2Json(JSON_OBJECT,["a",1,TRUE,2.5,"c","test","d","true","e"]); | json = llList2Json(JSON_OBJECT,["a",1,TRUE,2.5,"c","test","d","true","e"]); | ||
verify("llList2Json, json object, non-string in one of the first stride values",json,JSON_INVALID); | verify("llList2Json, json object, non-string in one of the first stride values",json,JSON_INVALID); | ||
// test invalid type | // test invalid type | ||
json = llList2Json("foo",["a",1,"b",2.5,"c","test","d","true","e","[1,2,3]"]); | json = llList2Json("foo",["a",1,"b",2.5,"c","test","d","true","e","[1,2,3]"]); | ||
verify("llList2Json, json invalid type",json,JSON_INVALID); | verify("llList2Json, json invalid type",json,JSON_INVALID); | ||
} | } | ||
test_strings_with_escaped_chars() | test_strings_with_escaped_chars() | ||
{ | { | ||
Line 532: | Line 532: | ||
"vanilla string", "vanilla string", "nothing that needs to be escaped.." | "vanilla string", "vanilla string", "nothing that needs to be escaped.." | ||
]; | ]; | ||
integer length_escaped_pairs = llGetListLength(escaped_pairs); | integer length_escaped_pairs = llGetListLength(escaped_pairs); | ||
integer i; | integer i; | ||
for (i=0; i < length_escaped_pairs; i+=3) | for (i=0; i < length_escaped_pairs; i+=3) | ||
Line 541: | Line 541: | ||
string funky_string_escaped = llList2String(escaped_pairs, i+1); | string funky_string_escaped = llList2String(escaped_pairs, i+1); | ||
string escaped_desc = " '" + llList2String(escaped_pairs, i+2) + "'"; | string escaped_desc = " '" + llList2String(escaped_pairs, i+2) + "'"; | ||
verify("Type of string with escaped char (for MAINT-2698),"+escaped_desc,llJsonValueType("\""+funky_string_escaped+"\"",[]),JSON_STRING); | verify("Type of string with escaped char (for MAINT-2698),"+escaped_desc,llJsonValueType("\""+funky_string_escaped+"\"",[]),JSON_STRING); | ||
string json = "[[1,2,3,4.0],{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"; | string json = "[[1,2,3,4.0],{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"; | ||
verify("llJsonGetValue [1,\""+funky_string_escaped+"\"] (for MAINT-2698),"+escaped_desc, | verify("llJsonGetValue [1,\""+funky_string_escaped+"\"] (for MAINT-2698),"+escaped_desc, | ||
llJsonGetValue(json,[1,funky_string]),"3"); | llJsonGetValue(json,[1,funky_string]),"3"); | ||
verify("llJsonGetValue [1,\"b\"] (for MAINT-2698),"+escaped_desc,llJsonGetValue(json,[1,"b"]),funky_string+"value"); | verify("llJsonGetValue [1,\"b\"] (for MAINT-2698),"+escaped_desc,llJsonGetValue(json,[1,"b"]),funky_string+"value"); | ||
// llSay(PUBLIC_CHANNEL, "DEBUG: '" + llEscapeURL(json) + "' is input for test " + escaped_desc); | // llSay(PUBLIC_CHANNEL, "DEBUG: '" + llEscapeURL(json) + "' is input for test " + escaped_desc); | ||
json = llJsonSetValue(json,[0],funky_string); | json = llJsonSetValue(json,[0],funky_string); | ||
verify("llJsonSetValue with escaped string as value (for MAINT-2698),"+escaped_desc,json, | verify("llJsonSetValue with escaped string as value (for MAINT-2698),"+escaped_desc,json, | ||
"[\""+funky_string_escaped+"\",{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"); | "[\""+funky_string_escaped+"\",{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"); | ||
json = llJsonSetValue(json,[0],funky_string); | json = llJsonSetValue(json,[0],funky_string); | ||
verify("llJsonSetValue with escaped string as value (for MAINT-2698),"+escaped_desc,json, | verify("llJsonSetValue with escaped string as value (for MAINT-2698),"+escaped_desc,json, | ||
"[\""+funky_string_escaped+"\",{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"); | "[\""+funky_string_escaped+"\",{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"); | ||
json = llJsonSetValue(json,[0,funky_string], funky_string+"value"); | json = llJsonSetValue(json,[0,funky_string], funky_string+"value"); | ||
verify("llJsonSetValue with escaped string as key's value (for MAINT-2698),"+escaped_desc,json, | verify("llJsonSetValue with escaped string as key's value (for MAINT-2698),"+escaped_desc,json, | ||
"[{\""+funky_string_escaped+"\":\""+funky_string_escaped+"value\"},{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"); | "[{\""+funky_string_escaped+"\":\""+funky_string_escaped+"value\"},{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"); | ||
list l = llJson2List(json); | list l = llJson2List(json); | ||
verify_list("llJson2List extracting object containing escaped string (for MAINT-2698),"+escaped_desc, l, | verify_list("llJson2List extracting object containing escaped string (for MAINT-2698),"+escaped_desc, l, | ||
Line 568: | Line 568: | ||
verify_list("llJson2List extracting escaped strings (for MAINT-2698),"+escaped_desc, n, | verify_list("llJson2List extracting escaped strings (for MAINT-2698),"+escaped_desc, n, | ||
[funky_string,funky_string+"value"]); | [funky_string,funky_string+"value"]); | ||
json = llList2Json(JSON_ARRAY,n); | json = llList2Json(JSON_ARRAY,n); | ||
verify("llList2Json from escaped-containing string to array (for MAINT-2698),"+escaped_desc,json, | verify("llList2Json from escaped-containing string to array (for MAINT-2698),"+escaped_desc,json, | ||
"[\""+funky_string_escaped+"\",\""+funky_string_escaped+"value\"]"); | "[\""+funky_string_escaped+"\",\""+funky_string_escaped+"value\"]"); | ||
json = llList2Json(JSON_OBJECT,n); | json = llList2Json(JSON_OBJECT,n); | ||
verify("llList2Json from escaped-containing string to object (for MAINT-2698),"+escaped_desc,json, | verify("llList2Json from escaped-containing string to object (for MAINT-2698),"+escaped_desc,json, | ||
Line 578: | Line 578: | ||
} | } | ||
} | } | ||
maint3070() | maint3070() | ||
{ | { | ||
Line 586: | Line 586: | ||
} | } | ||
maint4187() | |||
{ | |||
verify("Valid json number with + before exponent", llJsonValueType("1.0e+1", []), JSON_NUMBER); | |||
verify("Valid json number with - before exponent", llJsonValueType("1.0e-1", []), JSON_NUMBER); | |||
verify("Valid json number with - before exponent and mantissa", llJsonValueType("-1.0e-1", []), JSON_NUMBER); | |||
verify("Valid json number with unsigned exponent", llJsonValueType("1.0e1", []), JSON_NUMBER); | |||
verify("Invalid json number due to + before mantissa", llJsonValueType("+1.0e1", []), JSON_INVALID); | |||
verify("Invalid json number due to leading e", llJsonValueType("e1", []), JSON_INVALID); | |||
verify("Invalid json number due to leading 0", llJsonValueType("01", []), JSON_INVALID); | |||
verify("Invalid json number due to leading -0", llJsonValueType("-01", []), JSON_INVALID); | |||
verify("Valid json number with 0 immediately before .", llJsonValueType("0.01", []), JSON_NUMBER); | |||
verify("Valid json number with -0 immediately before .", llJsonValueType("-0.01", []), JSON_NUMBER); | |||
} | |||
maint3053() | maint3053() | ||
{ | { | ||
Line 595: | Line 610: | ||
verify("llJsonSetValue(jT1,[0, 1],\"t\")",llJsonSetValue(jT1,[0, 1],"t"),JSON_INVALID); | verify("llJsonSetValue(jT1,[0, 1],\"t\")",llJsonSetValue(jT1,[0, 1],"t"),JSON_INVALID); | ||
verify("llJsonSetValue(jT1,[0, 1, 2, \"t\", 75],\"t\")",llJsonSetValue(jT1,[0, 1, 2, "t", 75],"t"),JSON_INVALID); | verify("llJsonSetValue(jT1,[0, 1, 2, \"t\", 75],\"t\")",llJsonSetValue(jT1,[0, 1, 2, "t", 75],"t"),JSON_INVALID); | ||
string jT2 = "[ [\"A\", \"B\", \"C\"], 2]"; | string jT2 = "[ [\"A\", \"B\", \"C\"], 2]"; | ||
verify("llJsonSetValue(jT2,[0, 3],\"t\")",llJsonSetValue(jT2,[0, 3],"t"),"[[\"A\",\"B\",\"C\",\"t\"],2]"); | verify("llJsonSetValue(jT2,[0, 3],\"t\")",llJsonSetValue(jT2,[0, 3],"t"),"[[\"A\",\"B\",\"C\",\"t\"],2]"); | ||
Line 601: | Line 616: | ||
verify("llJsonSetValue(jT2,[0, 1, 0],\"t\")",llJsonSetValue(jT2,[0, 1, 0],"t"),"[[\"A\",[\"t\"],\"C\"],2]"); | verify("llJsonSetValue(jT2,[0, 1, 0],\"t\")",llJsonSetValue(jT2,[0, 1, 0],"t"),"[[\"A\",[\"t\"],\"C\"],2]"); | ||
verify("llJsonSetValue(jT2,[0, 1, 1],\"t\")",llJsonSetValue(jT2,[0, 1, 1],"t"),JSON_INVALID); | verify("llJsonSetValue(jT2,[0, 1, 1],\"t\")",llJsonSetValue(jT2,[0, 1, 1],"t"),JSON_INVALID); | ||
string jT3 = "{\"1\":2}"; | string jT3 = "{\"1\":2}"; | ||
verify("llJsonSetValue(jT3,[\"1\"],\"t\")",llJsonSetValue(jT3,["1"],"t"),"{\"1\":\"t\"}"); | verify("llJsonSetValue(jT3,[\"1\"],\"t\")",llJsonSetValue(jT3,["1"],"t"),"{\"1\":\"t\"}"); | ||
verify("llJsonSetValue(jT3,[\"1\",0],\"t\")",llJsonSetValue(jT3,["1",0],"t"),"{\"1\":[\"t\"]}"); | verify("llJsonSetValue(jT3,[\"1\",0],\"t\")",llJsonSetValue(jT3,["1",0],"t"),"{\"1\":[\"t\"]}"); | ||
verify("llJsonSetValue(jT3,[\"1\",1],\"t\")",llJsonSetValue(jT3,["1",1],"t"),JSON_INVALID); | verify("llJsonSetValue(jT3,[\"1\",1],\"t\")",llJsonSetValue(jT3,["1",1],"t"),JSON_INVALID); | ||
string jGood = "[null, 2]"; | string jGood = "[null, 2]"; | ||
verify("llJsonValueType(jGood, [0])",llJsonValueType(jGood, [0]),JSON_NULL); | verify("llJsonValueType(jGood, [0])",llJsonValueType(jGood, [0]),JSON_NULL); | ||
verify("llJsonValueType(jGood, [0, 0])",llJsonValueType(jGood, [0, 0]),JSON_INVALID); | verify("llJsonValueType(jGood, [0, 0])",llJsonValueType(jGood, [0, 0]),JSON_INVALID); | ||
string jBad = "[, 2]"; | string jBad = "[, 2]"; | ||
verify("llJsonValueType(jBad,[0])",llJsonValueType(jBad,[0]),JSON_INVALID); | verify("llJsonValueType(jBad,[0])",llJsonValueType(jBad,[0]),JSON_INVALID); | ||
Line 616: | Line 631: | ||
verify("llJsonGetValue(jBad,[1, 0, 2, \"t\", 75])",llJsonGetValue(jBad,[1, 0, 2, "t", 75]),JSON_INVALID); | verify("llJsonGetValue(jBad,[1, 0, 2, \"t\", 75])",llJsonGetValue(jBad,[1, 0, 2, "t", 75]),JSON_INVALID); | ||
} | } | ||
maint3081() | maint3081() | ||
{ | { | ||
Line 626: | Line 641: | ||
verify("Identity (set->get) JSON_NULL",llJsonGetValue(llJsonSetValue("",["test"],JSON_NULL),["test"]),JSON_NULL); | verify("Identity (set->get) JSON_NULL",llJsonGetValue(llJsonSetValue("",["test"],JSON_NULL),["test"]),JSON_NULL); | ||
} | } | ||
test_jira_fixes() | test_jira_fixes() | ||
{ | { | ||
maint3070(); | maint3070(); | ||
maint4187(); | |||
maint3053(); | maint3053(); | ||
maint3081(); | maint3081(); | ||
} | } | ||
default | default | ||
{ | { | ||
Line 640: | Line 656: | ||
llResetScript(); | llResetScript(); | ||
} | } | ||
changed(integer change) | changed(integer change) | ||
{ | { | ||
Line 648: | Line 664: | ||
} | } | ||
} | } | ||
state_entry() | state_entry() | ||
{ | { | ||
run_tests(); | run_tests(); | ||
} | } | ||
touch_start(integer num_detected) | touch_start(integer num_detected) | ||
{ | { |
Revision as of 10:21, 26 June 2014
JSON Test Framework
<lsl> // This is just the framework for creating new tests for LSL JSON functions without the tests.
integer total_number_of_tests; integer total_number_of_fails;
string typeName(string type_flag) {
if (type_flag == JSON_INVALID) return "JSON_INVALID";
/* else */ if (type_flag == JSON_OBJECT) return "JSON_OBJECT"; /* else */ if (type_flag == JSON_ARRAY) return "JSON_ARRAY";
/* else */ if (type_flag == JSON_NUMBER) return "JSON_NUMBER"; /* else */ if (type_flag == JSON_STRING) return "JSON_STRING"; /* else */ if (type_flag == JSON_NULL) return "JSON_NULL";
/* else */ if (type_flag == JSON_TRUE) return "JSON_TRUE"; /* else */ if (type_flag == JSON_FALSE) return "JSON_FALSE";
/* else */ if (type_flag == JSON_DELETE) return "JSON_DELETE";
/* else ...... type_flag unknown */ return type_flag;
}
string listEntryTypeName(integer type) {
list list_type_names = [ "TYPE_INVALID", "TYPE_INTEGER", "TYPE_FLOAT", "TYPE_STRING", "TYPE_KEY", "TYPE_VECTOR", "TYPE_ROTATION" ];
integer length = llGetListLength(list_type_names);
if (length <= type) return "UNKNOWN_LIST_TYPE"; /* else */ return llList2String(list_type_names, type);
}
integer max(integer x, integer y) {
if (x < y) return y; /* else */ return x;
}
integer verify(string message, string result, string expected) {
++total_number_of_tests;
if (result != expected) { ++total_number_of_fails;
publish("TEST FAILED" + "\nexpected: " + typeName(expected) + "\nresult: " + typeName(result) + "\nJSON string value: " + message + "\n ");
return FALSE; } /* else */ return TRUE;
}
verify_list(string message, list result, list expected) {
integer length_result = llGetListLength(result); integer length_expected = llGetListLength(expected);
// first verify that the list lengths match before looking at the data types
verify(message + ": list length", (string)length_result, (string)length_expected);
// the CSV string comparison is probably enough to verify that the values stored are correct // but I want to check data type too
integer index = max(length_result, length_expected); while (--index >= 0) { verify(message + ": on list entry type comparison on index " + (string)index, listEntryTypeName(llGetListEntryType(result, index)), listEntryTypeName(llGetListEntryType(expected, index)));
verify(message + ": on list value comparison on index " + (string)index, typeName(llList2String(result, index)), typeName(llList2String(expected, index))); }
verify(message + ": llList2CSV comparison", llList2CSV(result), llList2CSV(expected));
}
run_tests() {
publish("JSON TESTS: started" + "\n ");
total_number_of_tests = 0; total_number_of_fails = 0;
// Add new tests here. // ... // ... // ...
publish("JSON TESTS: done\n" + (string)total_number_of_fails + " of " + (string)total_number_of_tests + " tests failed." + "\n ");
}
publish(string message) { // if you want to keep it private //
llOwnerSay(message);
// if you want to make it public // // llSay(PUBLIC_CHANNEL, message);
// if you want to reach the owner wherever she/he is as fast as you can // // key owner = llGetOwner(); // vector ownerSize = llGetAgentSize(owner); // if (ownerSize != ZERO_VECTOR) llRegionSayTo(owner, PUBLIC_CHANNEL, message); // else llInstantMessage(owner, message); }
default {
on_rez(integer start_param) { llResetScript(); }
changed(integer change) { if (change & (CHANGED_OWNER | CHANGED_INVENTORY)) { llResetScript(); } }
state_entry() { run_tests(); }
touch_start(integer num_detected) { run_tests(); }
} </lsl>
Full Test Script
<lsl> // This is just the framework for creating new tests for LSL JSON functions without the tests.
integer total_number_of_tests; integer total_number_of_fails;
string typeName(string type_flag) {
if (type_flag == JSON_INVALID) return "JSON_INVALID"; /* else */ if (type_flag == JSON_OBJECT) return "JSON_OBJECT"; /* else */ if (type_flag == JSON_ARRAY) return "JSON_ARRAY"; /* else */ if (type_flag == JSON_NUMBER) return "JSON_NUMBER"; /* else */ if (type_flag == JSON_STRING) return "JSON_STRING"; /* else */ if (type_flag == JSON_NULL) return "JSON_NULL"; /* else */ if (type_flag == JSON_TRUE) return "JSON_TRUE"; /* else */ if (type_flag == JSON_FALSE) return "JSON_FALSE"; /* else */ if (type_flag == JSON_DELETE) return "JSON_DELETE"; /* else ...... type_flag unknown */ return type_flag;
}
string listEntryTypeName(integer type) {
list list_type_names = [ "TYPE_INVALID", "TYPE_INTEGER", "TYPE_FLOAT", "TYPE_STRING", "TYPE_KEY", "TYPE_VECTOR", "TYPE_ROTATION" ]; integer length = llGetListLength(list_type_names); if (length <= type) return "UNKNOWN_LIST_TYPE"; /* else */ return llList2String(list_type_names, type);
}
integer max(integer x, integer y) {
if (x < y) return y; /* else */ return x;
}
integer verify(string message, string result, string expected) {
++total_number_of_tests; if (result != expected) { ++total_number_of_fails; publish("TEST FAILED" + "\nexpected: " + typeName(expected) + "\nresult: " + typeName(result) + "\nJSON string value: " + message + "\n "); return FALSE; } /* else */ return TRUE;
}
verify_list(string message, list result, list expected) {
integer length_result = llGetListLength(result); integer length_expected = llGetListLength(expected);
// first verify that the list lengths match before looking at the data types
verify(message + ": list length", (string)length_result, (string)length_expected);
// the CSV string comparison is probably enough to verify that the values stored are correct // but I want to check data type too
integer index = max(length_result, length_expected); while (--index >= 0) { verify(message + ": on list entry type comparison on index " + (string)index, listEntryTypeName(llGetListEntryType(result, index)), listEntryTypeName(llGetListEntryType(expected, index))); verify(message + ": on list value comparison on index " + (string)index, typeName(llList2String(result, index)), typeName(llList2String(expected, index))); } verify(message + ": llList2CSV comparison", llList2CSV(result), llList2CSV(expected));
}
run_tests() {
publish("JSON TESTS: started" + "\n "); total_number_of_tests = 0; total_number_of_fails = 0; test_types(); test_get_value(); test_set_value(); test_json_to_list(); test_list_to_json(); test_strings_with_escaped_chars(); test_jira_fixes(); publish("JSON TESTS: done\n" + (string)total_number_of_fails + " of " + (string)total_number_of_tests + " tests failed." + "\n ");
}
publish(string message) { // if you want to keep it private //
llOwnerSay(message);
// if you want to make it public // // llSay(PUBLIC_CHANNEL, message);
// if you want to reach the owner wherever she/he is as fast as you can // // key owner = llGetOwner(); // vector ownerSize = llGetAgentSize(owner); // if (ownerSize != ZERO_VECTOR) llRegionSayTo(owner, PUBLIC_CHANNEL, message); // else llInstantMessage(owner, message); }
test_types() {
verify("Type of string",llJsonValueType("\"test\"",[]),JSON_STRING); verify("Type of string, unquoted",llJsonValueType("test",[]),JSON_INVALID); verify("Type of invalid",llJsonValueType("test",[]),JSON_INVALID); verify("Type of integer",llJsonValueType((string)12,[]),JSON_NUMBER); verify("Type of float",llJsonValueType((string)12.3,[]),JSON_NUMBER); verify("Type of Inf (is unsupported by JSON standard)",llJsonValueType("Inf",[]),JSON_INVALID); verify("Type of NaN (is unsupported by JSON standard)",llJsonValueType("NaN",[]),JSON_INVALID); verify("Type of number",llJsonValueType("-123.4e-5",[]),JSON_NUMBER); verify("Type of object",llJsonValueType("{\"a\":\"b\"}",[]),JSON_OBJECT);
// Expected to be OBJECT, since we don't do deep validation on input // verify("Type of object, invalid/unquoted key",llJsonValueType("{a:\"b\"}",[]),JSON_INVALID); // Expected to be OBJECT, since we don't do deep validation on input // verify("Type of object, invalid/unquoted value",llJsonValueType("{\"a\":b}",[]),JSON_INVALID);
verify("Type of array",llJsonValueType("[1,2,3]",[]),JSON_ARRAY); verify("Type of array padded front",llJsonValueType(" [1,2,3]",[]),JSON_ARRAY); verify("Type of array padded back",llJsonValueType("[1,2,3] ",[]),JSON_ARRAY); verify("Type of array padded",llJsonValueType(" [1,2,3] ",[]),JSON_ARRAY); verify("Type of true",llJsonValueType("true",[]),JSON_TRUE); verify("Type of false",llJsonValueType("false",[]),JSON_FALSE); verify("Type of null",llJsonValueType("null",[]),JSON_NULL);
// test traversal of llJsonValueType
string json = "[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6],\"c\":\"true\",\"d\":false}]"; verify("Type of [0]",llJsonValueType(json,[0]),JSON_ARRAY); verify("Type of [0,1]",llJsonValueType(json,[0,1]),JSON_NUMBER); verify("Type of [1]",llJsonValueType(json,[1]),JSON_OBJECT); verify("Type of [1,\"b\"]",llJsonValueType(json,[1,"b"]),JSON_ARRAY); verify("Type of [1,\"b\",0]",llJsonValueType(json,[1,"b",0]),JSON_TRUE); verify("Type of [1,\"b\",1]",llJsonValueType(json,[1,"b",1]),JSON_STRING); verify("Type of [1,\"b\",2]",llJsonValueType(json,[1,"b",2]),JSON_NUMBER); verify("Type of [1,\"c\"]",llJsonValueType(json,[1,"c"]),JSON_STRING); verify("Type of [1,\"d\"]",llJsonValueType(json,[1,"d"]),JSON_FALSE); verify("Type of [3] (invalid index at level 0)",llJsonValueType(json,[3]),JSON_INVALID); verify("Type of [-1] (invalid index at level 0)",llJsonValueType(json,[-1]),JSON_INVALID); verify("Type of [1,\"c\",3] (invalid index at level 1), MAINT-2670",llJsonValueType(json,[1,"c",3]),JSON_INVALID); verify("Type of [1,\"b\",3] (invalid index at level 2)",llJsonValueType(json,[1,"b",3]),JSON_INVALID); verify("Type of [1,\"b\",2,0,1] (invalid index at level 3) MAINT-2670",llJsonValueType(json,[1,"b",2, 0, 1]),JSON_INVALID);
// some invalid cases where keys are uncoded
json = "[[1,2,3],{a:3,b:[true,\"test\",6],c:\"true\",\"d\":false}]"; verify("Type of [1,\"a\"] where key is unquoted",llJsonValueType(json,[1,"a"]),JSON_INVALID); verify("Type of [1,\"b\"] where key is unquoted",llJsonValueType(json,[1,"b"]),JSON_INVALID); verify("Type of [1,\"c\"] where key is unquoted",llJsonValueType(json,[1,"c"]),JSON_INVALID);
}
test_get_value() {
string json = "[[1,2,3,4.0],{\"a\":3,\"b\":[true,\"test\",6]}]"; verify("llJsonGetValue [0]",llJsonGetValue(json,[0]),"[1,2,3,4.0]"); verify("llJsonGetValue [0,1]",llJsonGetValue(json,[0,1]),"2"); verify("llJsonGetValue [1]",llJsonGetValue(json,[1]),"{\"a\":3,\"b\":[true,\"test\",6]}"); verify("llJsonGetValue [1,\"b\"]",llJsonGetValue(json,[1,"b"]),"[true,\"test\",6]"); verify("llJsonGetValue [1,\"b\",0]",llJsonGetValue(json,[1,"b",0]),JSON_TRUE); verify("llJsonGetValue [1,\"b\",1]",llJsonGetValue(json,[1,"b",1]),"test"); verify("llJsonGetValue [1,\"b\",2]",llJsonGetValue(json,[1,"b",2]),"6"); verify("llJsonGetValue [0,3]",llJsonGetValue(json,[0,3]), "4.0"); verify("llJsonGetValue [2] (invalid index at level 0)",llJsonGetValue(json,[2]),JSON_INVALID); verify("llJsonGetValue [-1] (invalid index at level 0)",llJsonGetValue(json,[-1]),JSON_INVALID); verify("llJsonGetValue [0,4] (invalid index within array)",llJsonGetValue(json,[0,4]),JSON_INVALID); verify("llJsonGetValue [\"f\"] (look for missing object within array, depth=0) MAINT-2671",llJsonGetValue(json,["f"]),JSON_INVALID); verify("llJsonGetValue [0,\"f\"] (look for missing object within array, depth=1) MAINT-2671",llJsonGetValue(json,[0,"f"]),JSON_INVALID); verify("llJsonGetValue [1,2] (specify index within object - disallowed)",llJsonGetValue(json,[1,2]),JSON_INVALID);
// invalid input json - missing quotes around 'a' and 'test'
json = "[[1,2,3,4.0],{a:3,\"b\":[true,test,6]}]"; verify("llJsonGetValue [1,\"b\",1], unquoted/invalid string value",llJsonGetValue(json,[1,"b",1]),JSON_INVALID); verify("llJsonGetValue [1,\"a\"], unquoted/invalid string for key",llJsonGetValue(json,[1,"a"]),JSON_INVALID);
}
test_set_value() { // Test building from scratch
string json; json = llJsonSetValue(json,[0,0],(string)1); verify("llJsonSetValue build json",json,"1"); json = llJsonSetValue(json,[0,1],(string)2); verify("llJsonSetValue build json",json,"1,2"); json = llJsonSetValue(json,[0,2],(string)3); verify("llJsonSetValue build json",json,"1,2,3"); json = llJsonSetValue(json,[1,"a"],(string)3); verify("llJsonSetValue build json",json,"[[1,2,3],{\"a\":3}]"); json = llJsonSetValue(json,[1,"b",0],JSON_TRUE); verify("llJsonSetValue build json",json,"[[1,2,3],{\"a\":3,\"b\":[true]}]"); json = llJsonSetValue(json,[1,"b",1],"test"); verify("llJsonSetValue build json",json,"[[1,2,3],{\"a\":3,\"b\":[true,\"test\"]}]"); json = llJsonSetValue(json,[1,"b",2],"6"); verify("llJsonSetValue completed json",json,"[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6]}]");
// Test replacing
json = llJsonSetValue(json,[1,"b",1],"foo"); verify("llJsonSetValue completed json",json,"[[1,2,3],{\"a\":3,\"b\":[true,\"foo\",6]}]"); json = llJsonSetValue(json,[1,"b"],JSON_TRUE); verify("llJsonSetValue completed json, true",json,"[[1,2,3],{\"a\":3,\"b\":true}]"); json = llJsonSetValue(json,[1,"b"],"true"); verify("llJsonSetValue completed json, alt true",json,"[[1,2,3],{\"a\":3,\"b\":true}]"); json = llJsonSetValue(json,[1,0,0],JSON_FALSE); verify("llJsonSetValue completed json",json,"[[1,2,3],false]");
// Test appending
json = llJsonSetValue("[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6]}]",[0,JSON_APPEND], "4.0"); verify("llJsonSetValue append to first array",json,"[[1,2,3,4.0],{\"a\":3,\"b\":[true,\"test\",6]}]"); json = llJsonSetValue(json,[1,"b",JSON_APPEND], "5.0"); verify("llJsonSetValue append to array withhin object",json,"[[1,2,3,4.0],{\"a\":3,\"b\":[true,\"test\",6,5.0]}]"); json = llJsonSetValue(json,[JSON_APPEND], "6.0"); verify("llJsonSetValue append to outer array",json,"[[1,2,3,4.0],{\"a\":3,\"b\":[true,\"test\",6,5.0]},6.0]"); json = llJsonSetValue("[]",[JSON_APPEND], "\"alone\""); verify("llJsonSetValue append to empty array (MAINT-2684)",json,"[\"alone\"]"); json = llJsonSetValue("[]",[1], "\"alone\""); verify("llJsonSetValue append to empty array at invalid index (MAINT-2684)",json,JSON_INVALID); json = llJsonSetValue("[]",[0], "\"alone\""); verify("llJsonSetValue append to empty array at first index (MAINT-2684)",json,"[\"alone\"]");
// Test deleting
json = "[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6,null]}]"; json = llJsonSetValue(json,[1,"b",1],JSON_DELETE); verify("llJsonSetValue deleting string in middle of array",json,"[[1,2,3],{\"a\":3,\"b\":[true,6,null]}]"); json = llJsonSetValue(json,[1,"b",2],JSON_DELETE); verify("llJsonSetValue deleting null at end of array",json,"[[1,2,3],{\"a\":3,\"b\":[true,6]}]"); json = llJsonSetValue(json,[1,"b"],JSON_DELETE); verify("llJsonSetValue deleting key-value",json,"[[1,2,3],{\"a\":3}]"); json = llJsonSetValue(json,[1],JSON_DELETE); verify("llJsonSetValue deleting object in array",json,"1,2,3"); json = "[[1,2,3],4]"; json = llJsonSetValue(json,[0],JSON_DELETE); verify("llJsonSetValue deleting array (which is first index in array)",json,"[4]"); json = llJsonSetValue(json,[0],JSON_DELETE); verify("llJsonSetValue deleting last element in array",json,"[]"); json = "1"; json = llJsonSetValue(json,[0,0],JSON_DELETE); verify("llJsonSetValue deleting last element in array",json,"[[]]"); json = llJsonSetValue(json,[0],JSON_DELETE); verify("llJsonSetValue deleting array within array",json,"[]");
// Test failures in deleting
json = "[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6,null]}]"; verify("llJsonSetValue deleting undefined key-value in object",llJsonSetValue(json,[1,"d"],JSON_DELETE),JSON_INVALID); verify("llJsonSetValue deleting out-of-range index in array",llJsonSetValue(json,[2],JSON_DELETE),JSON_INVALID); verify("llJsonSetValue deleting depth within object that doesn't exist",llJsonSetValue(json,[1,"a","unicorn"],JSON_DELETE),JSON_INVALID); verify("llJsonSetValue deleting depth within array that doesn't exist",llJsonSetValue(json,[0,1,1],JSON_DELETE),JSON_INVALID);
// this is the only failure mode that should exist.
json = "[[1,2,3],{\"a\":3,\"b\":[true,\"foo\",6]}]"; json = llJsonSetValue(json,[3],JSON_FALSE); verify("llJsonSetValue fail to insert data into invalid array index (MAINT-2675)",json,JSON_INVALID);
}
test_json_to_list() {
list l = llJson2List("[[1,2,3],{\"a\":3,\"b\":[true,\"test\",6]}]"); verify_list("llJson2List first",l,["[1,2,3]","{\"a\":3,\"b\":[true,\"test\",6]}"]); list n = llJson2List(llList2String(l,0)); verify_list("llJson2List l,0",n,[1,2,3]); n = llJson2List(llList2String(l,1)); verify_list("llJson2List l,0",n,["a",3,"b","[true,\"test\",6]"]); n = llJson2List(llList2String(n,3)); verify_list("llJson2List l,0",n,[JSON_TRUE, "test", 6]); n = llJson2List(llList2String(n,1)); verify_list("llJson2List l,0",n,["test"]); n = llJson2List(""); verify_list("Empty JSON string becomes empty list",n,[]); n = llJson2List("[]"); verify_list("Empty JSON array becomes empty list (MAINT-2678)",n,[]); n = llJson2List("{}"); verify_list("Empty JSON object becomes empty list (MAINT-2678)",n,[]); n = llJson2List("Non-JSON string, with comma"); verify_list("llJson2List for non-JSON string is stored as a single object",n,["Non-JSON string, with comma"]); n = llJson2List("[malformed}"); verify_list("llJson2List, malformed input",n,["[malformed}"]);
}
test_list_to_json() { // test objects
string json = llList2Json(JSON_OBJECT,["a",1,"b",2.5,"c","test","d","true","e","[1,2,3]"]); verify("llList2Json, json object",json,"{\"a\":1,\"b\":2.500000,\"c\":\"test\",\"d\":true,\"e\":[1,2,3]}");
// test arrays
json = llList2Json(JSON_ARRAY,[1,2.5,"test","true","[1,2,3]"]); verify("llList2Json, json array",json,"[1,2.500000,\"test\",true,[1,2,3]]");
// test arrays
json = llList2Json(JSON_ARRAY,[1,2.5,"test",JSON_TRUE,"[1,2,3]"]); verify("llList2Json, json array, alternative true representation",json,"[1,2.500000,\"test\",true,[1,2,3]]");
// test objects, with empty input
json = llList2Json(JSON_OBJECT,[]); verify("llList2Json, json object with empty input (MAINT-2681)",json,"{}");
// test arrays, with empty input
json = llList2Json(JSON_ARRAY,[]); verify("llList2Json, json array with empty input (MAINT-2681)",json,"[]");
// test objects which are truncated
json = llList2Json(JSON_OBJECT,["a",1,"b",2.5,"c","test","d","true","e"]); verify("llList2Json, json object, truncated",json,JSON_INVALID);
// test objects which has a non-string identifier somewhere
json = llList2Json(JSON_OBJECT,["a",1,TRUE,2.5,"c","test","d","true","e"]); verify("llList2Json, json object, non-string in one of the first stride values",json,JSON_INVALID);
// test invalid type
json = llList2Json("foo",["a",1,"b",2.5,"c","test","d","true","e","[1,2,3]"]); verify("llList2Json, json invalid type",json,JSON_INVALID);
}
test_strings_with_escaped_chars() {
list escaped_pairs = [ "funky\"string", "funky\\\"string", "quote in middle", "funkystr\"ing", "funkystr\\\"ing", "quote in middle, other position",
// note that we have to double-up backslashes to assign them to strings..
"funky\\string", "funky\\\\string", "backslashes in middle", "\\funkystring", "\\\\funkystring", "backslashes at beginning", "funky\nstring", "funky\\nstring", "newline in string", "funky/string", "funky\\/string", "forward slash in string",
// TAB (\t) fails, because it seems that LSL automatically converts any tab into 4 consecutive spaces. // * "funky\tstring", "funky\\tstring", "tab in string", // these cases fail; it seems that LSL doesn't support these characters, and strips the '\' // * "funky\bstring", "funky\\\bstring", "backspace in middle", // * "funky\fstring", "funky\\\fstring", "form feed in middle", // * "funky\rstring", "funky\\rstring", "carriage return in string", // note that the following case can't be supported, since strings starting with \" can't be escaped // * "\"funkystring", "\\\"funkystring", "quote in beginning",
"vanilla string", "vanilla string", "nothing that needs to be escaped.." ]; integer length_escaped_pairs = llGetListLength(escaped_pairs); integer i; for (i=0; i < length_escaped_pairs; i+=3) { string funky_string = llList2String(escaped_pairs, i); string funky_string_escaped = llList2String(escaped_pairs, i+1); string escaped_desc = " '" + llList2String(escaped_pairs, i+2) + "'"; verify("Type of string with escaped char (for MAINT-2698),"+escaped_desc,llJsonValueType("\""+funky_string_escaped+"\"",[]),JSON_STRING); string json = "[[1,2,3,4.0],{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"; verify("llJsonGetValue [1,\""+funky_string_escaped+"\"] (for MAINT-2698),"+escaped_desc, llJsonGetValue(json,[1,funky_string]),"3"); verify("llJsonGetValue [1,\"b\"] (for MAINT-2698),"+escaped_desc,llJsonGetValue(json,[1,"b"]),funky_string+"value");
// llSay(PUBLIC_CHANNEL, "DEBUG: '" + llEscapeURL(json) + "' is input for test " + escaped_desc);
json = llJsonSetValue(json,[0],funky_string); verify("llJsonSetValue with escaped string as value (for MAINT-2698),"+escaped_desc,json, "[\""+funky_string_escaped+"\",{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"); json = llJsonSetValue(json,[0],funky_string); verify("llJsonSetValue with escaped string as value (for MAINT-2698),"+escaped_desc,json, "[\""+funky_string_escaped+"\",{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"); json = llJsonSetValue(json,[0,funky_string], funky_string+"value"); verify("llJsonSetValue with escaped string as key's value (for MAINT-2698),"+escaped_desc,json, "[{\""+funky_string_escaped+"\":\""+funky_string_escaped+"value\"},{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}]"); list l = llJson2List(json); verify_list("llJson2List extracting object containing escaped string (for MAINT-2698),"+escaped_desc, l, ["{\""+funky_string_escaped+"\":\""+funky_string_escaped+"value\"}","{\""+funky_string_escaped+"\":3,\"b\":\""+funky_string_escaped+"value"+"\"}"]); list n = llJson2List(llList2String(l, 0)); verify_list("llJson2List extracting escaped strings (for MAINT-2698),"+escaped_desc, n, [funky_string,funky_string+"value"]); json = llList2Json(JSON_ARRAY,n); verify("llList2Json from escaped-containing string to array (for MAINT-2698),"+escaped_desc,json, "[\""+funky_string_escaped+"\",\""+funky_string_escaped+"value\"]"); json = llList2Json(JSON_OBJECT,n); verify("llList2Json from escaped-containing string to object (for MAINT-2698),"+escaped_desc,json, "{\""+funky_string_escaped+"\":\""+funky_string_escaped+"value\"}"); }
}
maint3070() {
verify("Set value 'messa[g]e'", llJsonSetValue("",["toast"],"messa[g]e"), "{\"toast\":\"messa[g]e\"}"); verify("Set value 'messag[e]'", llJsonSetValue("",["toast"],"messag[e]"), "{\"toast\":\"messag[e]\"}"); verify("Set value 'messag\[e\]'", llJsonSetValue("",["toast"],"messag\[e\]"), "{\"toast\":\"messag[e]\"}");
}
maint4187() {
verify("Valid json number with + before exponent", llJsonValueType("1.0e+1", []), JSON_NUMBER); verify("Valid json number with - before exponent", llJsonValueType("1.0e-1", []), JSON_NUMBER); verify("Valid json number with - before exponent and mantissa", llJsonValueType("-1.0e-1", []), JSON_NUMBER); verify("Valid json number with unsigned exponent", llJsonValueType("1.0e1", []), JSON_NUMBER); verify("Invalid json number due to + before mantissa", llJsonValueType("+1.0e1", []), JSON_INVALID); verify("Invalid json number due to leading e", llJsonValueType("e1", []), JSON_INVALID); verify("Invalid json number due to leading 0", llJsonValueType("01", []), JSON_INVALID); verify("Invalid json number due to leading -0", llJsonValueType("-01", []), JSON_INVALID); verify("Valid json number with 0 immediately before .", llJsonValueType("0.01", []), JSON_NUMBER); verify("Valid json number with -0 immediately before .", llJsonValueType("-0.01", []), JSON_NUMBER);
}
maint3053() {
string jT1 = "[1, 2]"; // A JSON array verify("llJsonSetValue(jT1,[2],\"t\")",llJsonSetValue(jT1,[2],"t"),"[1,2,\"t\"]"); verify("llJsonSetValue(jT1,[3],\"t\")",llJsonSetValue(jT1,[3],"t"),JSON_INVALID); verify("llJsonSetValue(jT1,[0, 0],\"t\")",llJsonSetValue(jT1,[0, 0],"t"),"[[\"t\"],2]"); verify("llJsonSetValue(jT1,[0, 0, 2, \"t\", 75],\"t\")",llJsonSetValue(jT1,[0, 0, 2, "t", 75],"t"),JSON_INVALID); verify("llJsonSetValue(jT1,[0, 1],\"t\")",llJsonSetValue(jT1,[0, 1],"t"),JSON_INVALID); verify("llJsonSetValue(jT1,[0, 1, 2, \"t\", 75],\"t\")",llJsonSetValue(jT1,[0, 1, 2, "t", 75],"t"),JSON_INVALID); string jT2 = "[ [\"A\", \"B\", \"C\"], 2]"; verify("llJsonSetValue(jT2,[0, 3],\"t\")",llJsonSetValue(jT2,[0, 3],"t"),"[[\"A\",\"B\",\"C\",\"t\"],2]"); verify("llJsonSetValue(jT2,[0, 4],\"t\")",llJsonSetValue(jT2,[0, 4],"t"),JSON_INVALID); verify("llJsonSetValue(jT2,[0, 1, 0],\"t\")",llJsonSetValue(jT2,[0, 1, 0],"t"),"[[\"A\",[\"t\"],\"C\"],2]"); verify("llJsonSetValue(jT2,[0, 1, 1],\"t\")",llJsonSetValue(jT2,[0, 1, 1],"t"),JSON_INVALID); string jT3 = "{\"1\":2}"; verify("llJsonSetValue(jT3,[\"1\"],\"t\")",llJsonSetValue(jT3,["1"],"t"),"{\"1\":\"t\"}"); verify("llJsonSetValue(jT3,[\"1\",0],\"t\")",llJsonSetValue(jT3,["1",0],"t"),"{\"1\":[\"t\"]}"); verify("llJsonSetValue(jT3,[\"1\",1],\"t\")",llJsonSetValue(jT3,["1",1],"t"),JSON_INVALID); string jGood = "[null, 2]"; verify("llJsonValueType(jGood, [0])",llJsonValueType(jGood, [0]),JSON_NULL); verify("llJsonValueType(jGood, [0, 0])",llJsonValueType(jGood, [0, 0]),JSON_INVALID); string jBad = "[, 2]"; verify("llJsonValueType(jBad,[0])",llJsonValueType(jBad,[0]),JSON_INVALID); verify("llJsonValueType(jBad,[0, 0, 2, \"t\", 75])",llJsonValueType(jBad,[0, 0, 2, "t", 75]),JSON_INVALID); verify("llJsonGetValue(jBad,[1, 0, 2, \"t\", 75])",llJsonGetValue(jBad,[1, 0, 2, "t", 75]),JSON_INVALID);
}
maint3081() {
verify("llJsonSetValue blank string",llJsonSetValue("",["test"],""),"{\"test\":\"\"}"); verify("llJsonSetValue JSON_NULL",llJsonSetValue("",["test"],JSON_NULL),"{\"test\":null}"); verify("llJsonGetValue blank string",llJsonGetValue("{\"test\":\"\"}",["test"]),""); verify("llJsonGetValue JSON_NULL",llJsonGetValue("{\"test\":null}",["test"]),JSON_NULL); verify("Identity (set->get) blank string",llJsonGetValue(llJsonSetValue("",["test"],""),["test"]),""); verify("Identity (set->get) JSON_NULL",llJsonGetValue(llJsonSetValue("",["test"],JSON_NULL),["test"]),JSON_NULL);
}
test_jira_fixes() {
maint3070(); maint4187(); maint3053(); maint3081();
}
default {
on_rez(integer start_param) { llResetScript(); } changed(integer change) { if (change & (CHANGED_OWNER | CHANGED_INVENTORY)) { llResetScript(); } } state_entry() { run_tests(); } touch_start(integer num_detected) { run_tests(); }
} </lsl>