| local json = require("json") |
| local lunit = require("lunit") |
| local math = require("math") |
| local testutil = require("testutil") |
| local string = require("string") |
| |
| local encode = json.encode |
| -- DECODE NOT 'local' due to requirement for testutil to access it |
| decode = json.decode.getDecoder(false) |
| |
| module("lunit-numbers", lunit.testcase, package.seeall) |
| |
| function setup() |
| -- Ensure that the decoder is reset |
| _G["decode"] = json.decode.getDecoder(false) |
| end |
| |
| local function assert_near(expect, received) |
| local pctDiff |
| if expect == received then |
| pctDiff = 0 |
| else |
| pctDiff = math.abs(1 - expect / received) |
| end |
| local msg = ("expected '%s' but was '%s' .. '%s'%% apart"):format(expect, received, pctDiff * 100) |
| assert(pctDiff < 0.000001, msg) |
| end |
| local function test_simple(num) |
| assert_near(num, decode(tostring(num))) |
| end |
| local function test_simple_w_encode(num) |
| assert_near(num, decode(encode(num))) |
| end |
| local function test_scientific(num) |
| assert_near(num, decode(string.format('%e', num))) |
| assert_near(num, decode(string.format('%E', num))) |
| end |
| local numbers = { |
| 0, 1, -1, math.pi, -math.pi |
| } |
| math.randomseed(0xDEADBEEF) |
| -- Add sequence of numbers at low/high end of value-set |
| for i = -300,300,60 do |
| numbers[#numbers + 1] = math.random() * math.pow(10, i) |
| numbers[#numbers + 1] = -math.random() * math.pow(10, i) |
| end |
| |
| local function get_number_tester(f) |
| return function () |
| for _, v in ipairs(numbers) do |
| f(v) |
| end |
| end |
| end |
| |
| test_simple_numbers = get_number_tester(test_simple) |
| test_simple_numbers_w_encode = get_number_tester(test_simple_w_encode) |
| test_simple_numbers_scientific = get_number_tester(test_scientific) |
| |
| function test_infinite_nostrict() |
| assert_equal(math.huge, decode("Infinity")) |
| assert_equal(math.huge, decode("infinity")) |
| assert_equal(-math.huge, decode("-Infinity")) |
| assert_equal(-math.huge, decode("-infinity")) |
| end |
| |
| function test_nan_nostrict() |
| local value = decode("nan") |
| assert_true(value ~= value) |
| local value = decode("NaN") |
| assert_true(value ~= value) |
| end |
| |
| function test_expression() |
| assert_error(function() |
| decode("1 + 2") |
| end) |
| end |
| |
| -- For strict tests, small concession must be made to allow non-array/objects as root |
| local strict = json.util.merge({}, json.decode.strict, {initialObject = false}) |
| local strictDecoder = json.decode.getDecoder(strict) |
| |
| local numberValue = {hex = true} |
| |
| local hex = {number = numberValue} |
| local hexDecoder = json.decode.getDecoder(hex) |
| |
| function test_hex() |
| if decode == hexDecoder then -- MUST SKIP FAIL UNTIL BETTER METHOD SETUP |
| return |
| end |
| assert_error(function() |
| decode("0x20") |
| end) |
| end |
| |
| local hexNumbers = { |
| 0xDEADBEEF, |
| 0xCAFEBABE, |
| 0x00000000, |
| 0xFFFFFFFF, |
| 0xCE, |
| 0x01 |
| } |
| |
| function test_hex_only() |
| _G["decode"] = hexDecoder |
| for _, v in ipairs(hexNumbers) do |
| assert_equal(v, decode(("0x%x"):format(v))) |
| assert_equal(v, decode(("0X%X"):format(v))) |
| assert_equal(v, decode(("0x%X"):format(v))) |
| assert_equal(v, decode(("0X%x"):format(v))) |
| end |
| end |
| |
| local decimal_hexes = { |
| "0x0.1", |
| "0x.1", |
| "0x0e+1", |
| "0x0E-1" |
| } |
| function test_no_decimal_hex_only() |
| for _, str in ipairs(decimal_hexes) do |
| assert_error(function() |
| hexDecoder(str) |
| end) |
| end |
| end |
| |
| function test_nearly_scientific_hex_only() |
| assert_equal(0x00E1, hexDecoder("0x00e1")) |
| end |
| |
| local function buildStrictDecoder(f) |
| return testutil.buildPatchedDecoder(f, strictDecoder) |
| end |
| local function buildFailedStrictDecoder(f) |
| return testutil.buildFailedPatchedDecoder(f, strictDecoder) |
| end |
| -- SETUP CHECKS FOR SEQUENCE OF DECODERS |
| for k, v in pairs(_M) do |
| if k:match("^test_") and not k:match("_gen$") and not k:match("_only$") then |
| if k:match("_nostrict") then |
| _M[k .. "_strict_gen"] = buildFailedStrictDecoder(v) |
| else |
| _M[k .. "_strict_gen"] = buildStrictDecoder(v) |
| end |
| _M[k .. "_hex_gen"] = testutil.buildPatchedDecoder(v, hexDecoder) |
| end |
| end |