From 8e1b49f0dc0819991783d262faf33d5e53d6f621 Mon Sep 17 00:00:00 2001 From: Mark Pulford Date: Sat, 14 Jan 2012 01:29:07 +1030 Subject: Add descriptions to all tests Rewrite test framework and add descriptions for all tests. --- lua/cjson/util.lua | 29 ++--- tests/test.lua | 335 ++++++++++++++++++++++++++++++----------------------- 2 files changed, 204 insertions(+), 160 deletions(-) diff --git a/lua/cjson/util.lua b/lua/cjson/util.lua index 2142464..5b1eba0 100644 --- a/lua/cjson/util.lua +++ b/lua/cjson/util.lua @@ -201,7 +201,7 @@ local function run_test(testname, func, input, should_work, output) test_count_total = test_count_total + 1 local teststatus = { [true] = "PASS", [false] = "FAIL" } - print(string.format("==> Test[%d] / %s: %s", + print(string.format("==> Test [%d] %s: %s", test_count_total, testname, teststatus[correct])) status_line("Input", nil, input) @@ -214,27 +214,22 @@ local function run_test(testname, func, input, should_work, output) return correct, result end -local function run_test_group(testgroup, tests) - local function run_config(configname, func) - local success, msg = pcall(func) - if msg then - print(string.format("==> Config %s: %s", configname, msg)) +local function run_test_group(tests) + local function run_helper(name, func, input) + if type(name) == "string" and #name > 0 then + print("==> " .. name) end + -- Not a protected call, these functions should never generate errors. + func(unpack(input or {})) print() end - local function test_id(group, id) - return string.format("%s[%d]", group, id) - end - - for k, v in ipairs(tests) do - if type(v) == "function" then - -- Useful for changing configuration during a batch - run_config(test_id(testgroup, k), v) - elseif type(v) == "table" then - run_test(test_id(testgroup, k), unpack(v)) + for _, v in ipairs(tests) do + -- Run the helper if "should_work" is missing + if v[4] == nil then + run_helper(unpack(v)) else - error("Testgroup can only contain functions and tables") + run_test(unpack(v)) end end end diff --git a/tests/test.lua b/tests/test.lua index 4b8525b..b1212af 100755 --- a/tests/test.lua +++ b/tests/test.lua @@ -9,7 +9,7 @@ local json = require "cjson" local util = require "cjson.util" -local function gen_ascii() +local function gen_raw_octets() local chars = {} for i = 0, 255 do chars[i + 1] = string.char(i) end return table.concat(chars) @@ -53,205 +53,254 @@ function test_decode_cycle(filename) return util.compare_values(obj1, obj2) end +-- Set up data used in tests local Inf = math.huge; local NaN = math.huge * 0; -local octets_raw = gen_ascii() + +local octets_raw = gen_raw_octets() local octets_escaped = util.file_load("octets-escaped.dat") + local utf8_loaded, utf8_raw = pcall(util.file_load, "utf8.dat") if not utf8_loaded then utf8_raw = "Failed to load utf8.dat" end local utf16_escaped = gen_utf16_escaped() + local nested5 = {{{{{ "nested" }}}}} + local table_cycle = {} local table_cycle2 = { table_cycle } table_cycle[1] = table_cycle2 -local decode_simple_tests = { - { json.decode, { '"test string"' }, true, { "test string" } }, - { json.decode, { '-5e3' }, true, { -5000 } }, - { json.decode, { 'null' }, true, { json.null } }, - { json.decode, { 'true' }, true, { true } }, - { json.decode, { 'false' }, true, { false } }, - { json.decode, { '{ "1": "one", "3": "three" }' }, +local all_tests = { + -- Simple decode tests + { "Decode string", + json.decode, { '"test string"' }, true, { "test string" } }, + { "Decode number with exponent", + json.decode, { '-5e3' }, true, { -5000 } }, + { "Decode null", + json.decode, { 'null' }, true, { json.null } }, + { "Decode true", + json.decode, { 'true' }, true, { true } }, + { "Decode false", + json.decode, { 'false' }, true, { false } }, + { "Decode object with numeric keys", + json.decode, { '{ "1": "one", "3": "three" }' }, true, { { ["1"] = "one", ["3"] = "three" } } }, - { json.decode, { '[ "one", null, "three" ]' }, - true, { { "one", json.null, "three" } } } -} - -local encode_simple_tests = { - { json.encode, { json.null }, true, { 'null' } }, - { json.encode, { true }, true, { 'true' } }, - { json.encode, { false }, true, { 'false' } }, - { json.encode, { { } }, true, { '{}' } }, - { json.encode, { 10 }, true, { '10' } }, - { json.encode, { NaN }, - false, { "Cannot serialise number: must not be NaN or Inf" } }, - { json.encode, { Inf }, - false, { "Cannot serialise number: must not be NaN or Inf" } }, - { json.encode, { "hello" }, true, { '"hello"' } }, -} + { "Decode array", + json.decode, { '[ "one", null, "three" ]' }, + true, { { "one", json.null, "three" } } }, -local decode_numeric_tests = { - { json.decode, { '[ 0.0, -1, 0.3e-3, 1023.2 ]' }, + -- Numeric decode tests + { "Decode various numbers", + json.decode, { '[ 0.0, -1, 0.3e-3, 1023.2 ]' }, true, { { 0.0, -1, 0.0003, 1023.2 } } }, - { json.decode, { '00123' }, true, { 123 } }, - { json.decode, { '05.2' }, true, { 5.2 } }, - { json.decode, { '0e10' }, true, { 0 } }, - { json.decode, { '0x6' }, true, { 6 } }, - { json.decode, { '[ +Inf, Inf, -Inf ]' }, true, { { Inf, Inf, -Inf } } }, - { json.decode, { '[ +Infinity, Infinity, -Infinity ]' }, + { "Decode integer with leading zeros", + json.decode, { '00123' }, true, { 123 } }, + { "Decode floating point with leading zero", + json.decode, { '05.2' }, true, { 5.2 } }, + { "Decode zero with exponent", + json.decode, { '0e10' }, true, { 0 } }, + { "Decode hexadecimal", + json.decode, { '0x6' }, true, { 6 } }, + { "Decode +-Inf", + json.decode, { '[ +Inf, Inf, -Inf ]' }, true, { { Inf, Inf, -Inf } } }, + { "Decode +-Infinity", + json.decode, { '[ +Infinity, Infinity, -Infinity ]' }, true, { { Inf, Inf, -Inf } } }, - { json.decode, { '[ +NaN, NaN, -NaN ]' }, true, { { NaN, NaN, NaN } } }, - { json.decode, { 'Infrared' }, + { "Decode +-NaN", + json.decode, { '[ +NaN, NaN, -NaN ]' }, true, { { NaN, NaN, NaN } } }, + { "Decode Infrared (not infinity)", + json.decode, { 'Infrared' }, false, { "Expected the end but found invalid token at character 4" } }, - { json.decode, { 'Noodle' }, + { "Decode Noodle (not NaN)", + json.decode, { 'Noodle' }, false, { "Expected value but found invalid token at character 1" } }, -} -local encode_table_tests = { - function() + -- Decode error tests + { "Decode UTF-16BE", + json.decode, { '\0"\0"' }, + false, { "JSON parser does not support UTF-16 or UTF-32" } }, + { "Decode UTF-16LE", + json.decode, { '"\0"\0' }, + false, { "JSON parser does not support UTF-16 or UTF-32" } }, + { "Decode UTF-32BE", + json.decode, { '\0\0\0"' }, + false, { "JSON parser does not support UTF-16 or UTF-32" } }, + { "Decode UTF-32LE", + json.decode, { '"\0\0\0' }, + false, { "JSON parser does not support UTF-16 or UTF-32" } }, + { "Decode partial JSON", + json.decode, { '{ "unexpected eof": ' }, + false, { "Expected value but found T_END at character 21" } }, + { "Decode with extra comma", + json.decode, { '{ "extra data": true }, false' }, + false, { "Expected the end but found T_COMMA at character 23" } }, + { "Decode invalid escape code", + json.decode, { [[ { "bad escape \q code" } ]] }, + false, { "Expected object key string but found invalid escape code at character 16" } }, + { "Decode invalid unicode escape", + json.decode, { [[ { "bad unicode \u0f6 escape" } ]] }, + false, { "Expected object key string but found invalid unicode escape code at character 17" } }, + { "Decode invalid keyword", + json.decode, { ' [ "bad barewood", test ] ' }, + false, { "Expected value but found invalid token at character 20" } }, + { "Decode invalid number #1", + json.decode, { '[ -+12 ]' }, + false, { "Expected value but found invalid number at character 3" } }, + { "Decode invalid number #2", + json.decode, { '-v' }, + false, { "Expected value but found invalid number at character 1" } }, + { "Decode invalid number exponent", + json.decode, { '[ 0.4eg10 ]' }, + false, { "Expected comma or array end but found invalid token at character 6" } }, + { "Setting decode_max_depth(5)", function () + json.decode_max_depth(5) + end }, + { "Decode array at nested limit", + json.decode, { '[[[[[ "nested" ]]]]]' }, + true, { {{{{{ "nested" }}}}} } }, + { "Decode array over nested limit", + json.decode, { '[[[[[[ "nested" ]]]]]]' }, + false, { "Too many nested data structures" } }, + { "Setting decode_max_depth(1000)", function () + json.decode_max_depth(1000) + end }, + + -- Simple encode tests + { "Encode null", + json.encode, { json.null }, true, { 'null' } }, + { "Encode true", + json.encode, { true }, true, { 'true' } }, + { "Encode false", + json.encode, { false }, true, { 'false' } }, + { "Encode empty object", + json.encode, { { } }, true, { '{}' } }, + { "Encode integer", + json.encode, { 10 }, true, { '10' } }, + { "Encode NaN (invalid numbers disabled)", + json.encode, { NaN }, + false, { "Cannot serialise number: must not be NaN or Inf" } }, + { "Encode Infinity (invalid numbers disabled)", + json.encode, { Inf }, + false, { "Cannot serialise number: must not be NaN or Inf" } }, + { "Encode string", + json.encode, { "hello" }, true, { '"hello"' } }, + + -- Table encode tests + { "Setting sparse array (true, 2, 3) / max depth (5)", function() json.encode_sparse_array(true, 2, 3) json.encode_max_depth(5) - return "Setting sparse array (true, 2, 3) / max depth (5)" - end, - { json.encode, { { [3] = "sparse test" } }, + end }, + { "Encode sparse table as array #1", + json.encode, { { [3] = "sparse test" } }, true, { '[null,null,"sparse test"]' } }, - { json.encode, { { [1] = "one", [4] = "sparse test" } }, + { "Encode sparse table as array #2", + json.encode, { { [1] = "one", [4] = "sparse test" } }, true, { '["one",null,null,"sparse test"]' } }, - { json.encode, { { [1] = "one", [5] = "sparse test" } }, + { "Encode sparse array as object", + json.encode, { { [1] = "one", [5] = "sparse test" } }, true, { '{"1":"one","5":"sparse test"}' } }, - { json.encode, { { ["2"] = "numeric string key test" } }, + { "Encode table with numeric string key as object", + json.encode, { { ["2"] = "numeric string key test" } }, true, { '{"2":"numeric string key test"}' } }, - { json.encode, { nested5 }, true, { '[[[[["nested"]]]]]' } }, - { json.encode, { { nested5 } }, + { "Encode nested table", + json.encode, { nested5 }, true, { '[[[[["nested"]]]]]' } }, + { "Encode nested table (throw error)", + json.encode, { { nested5 } }, + false, { "Cannot serialise, excessive nesting (6)" } }, + { "Encode table with cycle", + json.encode, { table_cycle }, false, { "Cannot serialise, excessive nesting (6)" } }, - { json.encode, { table_cycle }, - false, { "Cannot serialise, excessive nesting (6)" } } -} -local encode_error_tests = { - { json.encode, { { [false] = "wrong" } }, + -- Encode error tests + { "Encode table with incompatible key", + json.encode, { { [false] = "wrong" } }, false, { "Cannot serialise boolean: table key must be a number or string" } }, - { json.encode, { function () end }, + { "Encode Lua function", + json.encode, { function () end }, false, { "Cannot serialise function: type not supported" } }, - function () + { "Setting encode_invalid_numbers(false)", function () json.encode_invalid_numbers(false) - return 'Setting encode_invalid_numbers(false)' - end, - { json.encode, { NaN }, + end }, + { "Encode NaN (invalid numbers disabled)", + json.encode, { NaN }, false, { "Cannot serialise number: must not be NaN or Inf" } }, - { json.encode, { Inf }, + { "Encode Infinity (invalid numbers disabled)", + json.encode, { Inf }, false, { "Cannot serialise number: must not be NaN or Inf" } }, - function () + { 'Setting encode_invalid_numbers("null").', function () json.encode_invalid_numbers("null") - return 'Setting encode_invalid_numbers("null").' - end, - { json.encode, { NaN }, true, { "null" } }, - { json.encode, { Inf }, true, { "null" } }, - function () + end }, + { "Encode NaN as null", + json.encode, { NaN }, true, { "null" } }, + { "Encode Infinity as null", + json.encode, { Inf }, true, { "null" } }, + { 'Setting encode_invalid_numbers(true).', function () json.encode_invalid_numbers(true) - return 'Setting encode_invalid_numbers(true).' - end, - { json.encode, { NaN }, true, { "nan" } }, - { json.encode, { Inf }, true, { "inf" } }, - function () + end }, + { "Encode NaN", + json.encode, { NaN }, true, { "nan" } }, + { "Encode Infinity", + json.encode, { Inf }, true, { "inf" } }, + { 'Setting encode_invalid_numbers(false)', function () json.encode_invalid_numbers(false) - return 'Setting encode_invalid_numbers(false)' - end, -} - -local decode_error_tests = { - { json.decode, { '\0"\0"' }, - false, { "JSON parser does not support UTF-16 or UTF-32" } }, - { json.decode, { '"\0"\0' }, - false, { "JSON parser does not support UTF-16 or UTF-32" } }, - { json.decode, { '{ "unexpected eof": ' }, - false, { "Expected value but found T_END at character 21" } }, - { json.decode, { '{ "extra data": true }, false' }, - false, { "Expected the end but found T_COMMA at character 23" } }, - { json.decode, { ' { "bad escape \\q code" } ' }, - false, { "Expected object key string but found invalid escape code at character 16" } }, - { json.decode, { ' { "bad unicode \\u0f6 escape" } ' }, - false, { "Expected object key string but found invalid unicode escape code at character 17" } }, - { json.decode, { ' [ "bad barewood", test ] ' }, - false, { "Expected value but found invalid token at character 20" } }, - { json.decode, { '[ -+12 ]' }, - false, { "Expected value but found invalid number at character 3" } }, - { json.decode, { '-v' }, - false, { "Expected value but found invalid number at character 1" } }, - { json.decode, { '[ 0.4eg10 ]' }, - false, { "Expected comma or array end but found invalid token at character 6" } }, - function () - json.decode_max_depth(5) - return "Setting decode_max_depth(5)" - end, - { json.decode, { '[[[[[ "nested" ]]]]]' }, - true, { {{{{{ "nested" }}}}} } }, - { json.decode, { '[[[[[[ "nested" ]]]]]]' }, - false, { "Too many nested data structures" } }, - function () - json.decode_max_depth(1000) - return "Setting decode_max_depth(1000)" - end -} + end }, -local escape_tests = { - -- Test 8bit clean - { json.encode, { octets_raw }, true, { octets_escaped } }, - { json.decode, { octets_escaped }, true, { octets_raw } }, - -- Ensure high bits are removed from surrogate codes - { json.decode, { '"\\uF800"' }, true, { "\239\160\128" } }, - -- Test inverted surrogate pairs - { json.decode, { '"\\uDB00\\uD800"' }, + -- Escaping tests + { "Encode all octets (8-bit clean)", + json.encode, { octets_raw }, true, { octets_escaped } }, + { "Decode all escaped octets", + json.decode, { octets_escaped }, true, { octets_raw } }, + { "Decode single UTF-16 escape", + json.decode, { [["\uF800"]] }, true, { "\239\160\128" } }, + { "Decode swapped surrogate pair", + json.decode, { [["\uDC00\uD800"]] }, false, { "Expected value but found invalid unicode escape code at character 2" } }, - -- Test 2x high surrogate code units - { json.decode, { '"\\uDB00\\uDB00"' }, + { "Decode duplicate high surrogate", + json.decode, { [["\uDB00\uDB00"]] }, false, { "Expected value but found invalid unicode escape code at character 2" } }, - -- Test invalid 2nd escape - { json.decode, { '"\\uDB00\\"' }, + { "Decode duplicate low surrogate", + json.decode, { [["\uDB00\uDB00"]] }, false, { "Expected value but found invalid unicode escape code at character 2" } }, - { json.decode, { '"\\uDB00\\uD"' }, + { "Decode missing low surrogate", + json.decode, { [["\uDB00"]] }, false, { "Expected value but found invalid unicode escape code at character 2" } }, - -- Test decoding of all UTF-16 escapes - { json.decode, { utf16_escaped }, true, { utf8_raw } } -} + { "Decode invalid low surrogate", + json.decode, { [["\uDB00\uD"]] }, + false, { "Expected value but found invalid unicode escape code at character 2" } }, + { "Decode all UTF-16 escapes (including surrogate combinations)", + json.decode, { utf16_escaped }, true, { utf8_raw } }, --- The standard Lua interpreter is ANSI C online doesn't support locales --- by default. Force a known problematic locale to test strtod()/sprintf(). -local locale_tests = { - function () + -- Locale tests + -- + -- The standard Lua interpreter is ANSI C online doesn't support locales + -- by default. Force a known problematic locale to test strtod()/sprintf(). + { "Setting locale to cs_CZ (comma separator)", function () os.setlocale("cs_CZ") json.new() - return "Setting locale to cs_CZ (comma separator)" - end, - { json.encode, { 1.5 }, true, { '1.5' } }, - { json.decode, { "[ 10, \"test\" ]" }, true, { { 10, "test" } } }, - function () + end }, + { "Encode number under comma locale", + json.encode, { 1.5 }, true, { '1.5' } }, + { "Decode number in array under comma locale", + json.decode, { '[ 10, "test" ]' }, true, { { 10, "test" } } }, + { "Reverting locale to POSIX", function () os.setlocale("C") json.new() - return "Reverting locale to POSIX" - end + end }, } print(string.format("Testing Lua CJSON version %s\n", json.version)) -util.run_test_group("decode simple value", decode_simple_tests) -util.run_test_group("encode simple value", encode_simple_tests) -util.run_test_group("decode numeric", decode_numeric_tests) -util.run_test_group("encode table", encode_table_tests) -util.run_test_group("decode error", decode_error_tests) -util.run_test_group("encode error", encode_error_tests) -util.run_test_group("escape", escape_tests) -util.run_test_group("locale", locale_tests) +util.run_test_group(all_tests) json.encode_invalid_numbers(true) json.decode_invalid_numbers(true) json.encode_max_depth(20) for i = 1, #arg do - util.run_test("decode cycle " .. arg[i], test_decode_cycle, { arg[i] }, + util.run_test("Decode cycle " .. arg[i], test_decode_cycle, { arg[i] }, true, { true }) end -- cgit v1.2.3-55-g6feb