# vim:ft= use lib '.'; use TestLua; plan tests => 2 * blocks(); run_tests(); __DATA__ === TEST 1: empty tables as objects --- lua local cjson = require "cjson" print(cjson.encode({})) print(cjson.encode({dogs = {}})) --- out {} {"dogs":{}} === TEST 2: empty tables as arrays --- lua local cjson = require "cjson" cjson.encode_empty_table_as_object(false) print(cjson.encode({})) print(cjson.encode({dogs = {}})) --- out [] {"dogs":[]} === TEST 3: empty tables as objects (explicit) --- lua local cjson = require "cjson" cjson.encode_empty_table_as_object(true) print(cjson.encode({})) print(cjson.encode({dogs = {}})) --- out {} {"dogs":{}} === TEST 4: empty_array userdata --- lua local cjson = require "cjson" print(cjson.encode({arr = cjson.empty_array})) --- out {"arr":[]} === TEST 5: empty_array_mt --- lua local cjson = require "cjson" local empty_arr = setmetatable({}, cjson.empty_array_mt) print(cjson.encode({arr = empty_arr})) --- out {"arr":[]} === TEST 6: empty_array_mt and empty tables as objects (explicit) --- lua local cjson = require "cjson" local sort_json = require "tests.sort_json" local empty_arr = setmetatable({}, cjson.empty_array_mt) print(sort_json(cjson.encode({obj = {}, arr = empty_arr}))) --- out {"arr":[],"obj":{}} === TEST 7: empty_array_mt and empty tables as objects (explicit) --- lua local cjson = require "cjson" local sort_json = require "tests.sort_json" cjson.encode_empty_table_as_object(true) local empty_arr = setmetatable({}, cjson.empty_array_mt) local data = { arr = empty_arr, foo = { obj = {}, foobar = { arr = cjson.empty_array, obj = {} } } } print(sort_json(cjson.encode(data))) --- out {"arr":[],"foo":{"foobar":{"arr":[],"obj":{}},"obj":{}}} === TEST 8: empty_array_mt on non-empty tables --- lua local cjson = require "cjson" local sort_json = require "tests.sort_json" cjson.encode_empty_table_as_object(true) local array = {"hello", "world", "lua"} setmetatable(array, cjson.empty_array_mt) local data = { arr = array, foo = { obj = {}, foobar = { arr = cjson.empty_array, obj = {} } } } print(sort_json(cjson.encode(data))) --- out {"arr":["hello","world","lua"],"foo":{"foobar":{"arr":[],"obj":{}},"obj":{}}} === TEST 9: array_mt on empty tables --- lua local cjson = require "cjson" local data = {} setmetatable(data, cjson.array_mt) print(cjson.encode(data)) --- out [] === TEST 10: array_mt on non-empty tables --- lua local cjson = require "cjson" local data = { "foo", "bar" } setmetatable(data, cjson.array_mt) print(cjson.encode(data)) --- out ["foo","bar"] === TEST 11: array_mt on non-empty tables with holes --- lua local cjson = require "cjson" local data = {} data[1] = "foo" data[2] = "bar" data[4] = "last" data[9] = "none" setmetatable(data, cjson.array_mt) print(cjson.encode(data)) --- out ["foo","bar",null,"last"] === TEST 12: decode() by default does not set array_mt on empty arrays --- lua local cjson = require "cjson" local json = [[{"my_array":[]}]] local t = cjson.decode(json) local has_metatable = getmetatable(t.my_array) == cjson.array_mt print("decoded JSON array has metatable: " .. tostring(has_metatable)) print(cjson.encode(t)) --- out decoded JSON array has metatable: false {"my_array":{}} === TEST 13: decode() sets array_mt on non-empty arrays if enabled --- lua local cjson = require "cjson" cjson.decode_array_with_array_mt(true) local json = [[{"my_array":["hello","world"]}]] local t = cjson.decode(json) t.my_array.hash_value = "adding a hash value" -- emptying the array part t.my_array[1] = nil t.my_array[2] = nil local has_metatable = getmetatable(t.my_array) == cjson.array_mt print("decoded JSON array has metatable: " .. tostring(has_metatable)) print(cjson.encode(t)) --- out decoded JSON array has metatable: true {"my_array":[]} === TEST 14: cfg can enable/disable setting array_mt --- lua local cjson = require "cjson" cjson.decode_array_with_array_mt(true) cjson.decode_array_with_array_mt(false) local json = [[{"my_array":[]}]] local t = cjson.decode(json) local has_metatable = getmetatable(t.my_array) == cjson.array_mt print("decoded JSON array has metatable: " .. tostring(has_metatable)) print(cjson.encode(t)) --- out decoded JSON array has metatable: false {"my_array":{}} === TEST 15: array_mt on tables with hash part --- lua local cjson = require "cjson" local data if jit and string.find(jit.version, "LuaJIT 2.1.0", nil, true) then local new_tab = require "table.new" data = new_tab(0, 2) -- allocating hash part only else data = {} end data.foo = "bar" data[1] = "hello" setmetatable(data, cjson.array_mt) print(cjson.encode(data)) --- out ["hello"] === TEST 16: multiple calls to lua_cjson_new (1/3) --- lua local cjson = require "cjson" package.loaded["cjson"] = nil require "cjson" local arr = setmetatable({}, cjson.array_mt) print(cjson.encode(arr)) --- out [] === TEST 17: multiple calls to lua_cjson_new (2/3) --- lua local cjson = require "cjson" package.loaded["cjson"] = nil require "cjson" local arr = setmetatable({}, cjson.empty_array_mt) print(cjson.encode(arr)) --- out [] === TEST 18: multiple calls to lua_cjson_new (3/3) --- lua local cjson = require "cjson.safe" -- load another cjson instance (not in package.loaded) require "cjson" local arr = setmetatable({}, cjson.empty_array_mt) print(cjson.encode(arr)) --- out [] === TEST 19: & in JSON --- lua local cjson = require "cjson" local a="[\"a=1&b=2\"]" local b=cjson.decode(a) print(cjson.encode(b)) --- out ["a=1&b=2"] === TEST 20: default and max precision --- lua local math = require "math" local cjson = require "cjson" local double = math.pow(2, 53) print(cjson.encode(double)) cjson.encode_number_precision(16) print(cjson.encode(double)) print(string.format("%16.0f", cjson.decode("9007199254740992"))) --- out 9.007199254741e+15 9007199254740992 9007199254740992 === TEST 21: / in string --- lua local cjson = require "cjson" local a={test = "http://google.com/google"} local b=cjson.encode(a) print(b) cjson.encode_escape_forward_slash(false) local b=cjson.encode(a) print(b) cjson.encode_escape_forward_slash(true) local b=cjson.encode(a) print(b) --- out {"test":"http:\/\/google.com\/google"} {"test":"http://google.com/google"} {"test":"http:\/\/google.com\/google"} === TEST 22: disable error on invalid type --- lua local cjson = require "cjson" local f = function (x) return 2*x end local res, err = pcall(cjson.encode, f) print(err) local t = {f = f, valid = "valid"} local res, err = pcall(cjson.encode, t) print(err) local arr = {"one", "two", f, "three"} local res, err = pcall(cjson.encode, arr) print(err) cjson.encode_skip_unsupported_value_types(true) print(cjson.encode(f)) print(cjson.encode(t)) print(cjson.encode(arr)) --- out Cannot serialise function: type not supported Cannot serialise function: type not supported Cannot serialise function: type not supported {"valid":"valid"} ["one","two","three"] === TEST 23: array-like proxy object with __len and __index --- lua local cjson = require "cjson" local real_array = {"foo", "bar", "baz"} local proxy_array = {} setmetatable(proxy_array, { __len = function() return 3 end, __index = function(t, k) return real_array[k] end, }) print(cjson.encode(proxy_array)) --- out ["foo","bar","baz"] === TEST 24: check that integers are handled correctly on Lua 5.3+ --- lua local lv = tonumber((_VERSION):match("Lua 5%.([0-9]+)")) if lv >= 3 then local cjson = require "cjson" local array = cjson.decode [[ [10, 10.0, 3.5] ]] for i = 1, 4 do print(tostring(i) .. ": " .. tostring(math.type(array[i]))) end else print("1: integer") print("2: float") print("3: float") print("4: nil") end --- out 1: integer 2: float 3: float 4: nil