1 local json
= require("json")
2 local lunit
= require("lunit")
3 local math
= require("math")
4 local testutil
= require("testutil")
5 local string = require("string")
7 local encode
= json
.encode
8 -- DECODE NOT 'local' due to requirement for testutil to access it
9 decode
= json
.decode
.getDecoder(false)
13 _ENV
= lunit
.module("lunit-numbers", 'seeall')
16 module("lunit-numbers", lunit
.testcase
, package
.seeall
)
21 -- Ensure that the decoder is reset
22 _G
["decode"] = json
.decode
.getDecoder(false)
25 local function is_near(expect
, received
)
27 if expect
== received
then
30 pctDiff
= math
.abs(1 - expect
/ received
)
32 if pctDiff
< 0.000001 then
35 return false, ("expected '%s' but was '%s' .. '%s'%% apart"):format(expect
, received
, pctDiff
* 100)
38 local function assert_near(expect
, received
)
39 assert(is_near(expect
, received
))
41 local function test_simple(num
)
42 assert_near(num
, decode(tostring(num
)))
44 local function test_simple_w_encode(num
)
45 assert_near(num
, decode(encode(num
)))
47 local function test_scientific(num
)
48 assert_near(num
, decode(string.format('%e', num
)))
49 assert_near(num
, decode(string.format('%E', num
)))
51 local function test_scientific_denied(num
)
52 local decode
= json
.decode
.getDecoder({ number = { exp = false } })
53 assert_error_match("Exponent-denied error did not match", "Exponents.*denied", function()
54 decode(string.format('%e', num
))
56 assert_error_match("Exponent-denied error did not match", "Exponents.*denied", function()
57 decode(string.format('%E', num
))
61 0, 1, -1, math
.pi
, -math
.pi
63 math
.randomseed(0xDEADBEEF)
64 local pow
= math
.pow
or load("return function(a, b) return a ^ b end")()
65 -- Add sequence of numbers at low/high end of value-set
66 for i
= -300,300,60 do
67 numbers
[#numbers
+ 1] = math
.random() * pow(10, i
)
68 numbers
[#numbers
+ 1] = -math
.random() * pow(10, i
)
71 local function get_number_tester(f
)
73 for _
, v
in ipairs(numbers
) do
79 local function test_fraction(num
)
80 assert_near(num
, decode(string.format("%f", num
)))
82 local function test_fraction_denied(num
)
83 local decode
= json
.decode
.getDecoder({ number = { frac
= false } })
84 local formatted
= string.format('%f', num
)
85 assert_error_match("Fraction-denied error did not match for " .. formatted
, "Fractions.*denied", function()
89 local function get_number_fraction_tester(f
)
91 for _
, v
in ipairs(numbers
) do
92 -- Fractional portion must be present
93 local formatted
= string.format("%f", v
)
94 -- San check that the formatted value is near the desired value
95 if nil ~= formatted
:find("%.") and is_near(v
, tonumber(formatted
)) then
102 test_simple_numbers
= get_number_tester(test_simple
)
103 test_simple_numbers_w_encode
= get_number_tester(test_simple_w_encode
)
104 test_simple_numbers_scientific
= get_number_tester(test_scientific
)
105 test_simple_numbers_scientific_denied
= get_number_tester(test_scientific_denied
)
106 test_simple_numbers_fraction_only
= get_number_fraction_tester(test_fraction
)
107 test_simple_numbers_fraction_denied_only
= get_number_fraction_tester(test_fraction_denied
)
109 function test_infinite_nostrict()
110 assert_equal(math
.huge
, decode("Infinity"))
111 assert_equal(math
.huge
, decode("infinity"))
112 assert_equal(-math
.huge
, decode("-Infinity"))
113 assert_equal(-math
.huge
, decode("-infinity"))
116 function test_nan_nostrict()
117 local value
= decode("nan")
118 assert_true(value
~= value
)
119 local value
= decode("NaN")
120 assert_true(value
~= value
)
121 assert_equal("NaN", encode(decode("NaN")))
124 function test_expression()
125 assert_error(function()
130 -- For strict tests, small concession must be made to allow non-array/objects as root
131 local strict
= json
.util
.merge({}, json
.decode
.strict
, {initialObject
= false})
132 local strictDecoder
= json
.decode
.getDecoder(strict
)
134 local numberValue
= {hex
= true}
136 local hex
= {number = numberValue
}
137 local hexDecoder
= json
.decode
.getDecoder(hex
)
140 if decode
== hexDecoder
then -- MUST SKIP FAIL UNTIL BETTER METHOD SETUP
143 assert_error(function()
157 function test_hex_only()
158 _G
["decode"] = hexDecoder
159 for _
, v
in ipairs(hexNumbers
) do
160 assert_equal(v
, decode(("0x%x"):format(v
)))
161 assert_equal(v
, decode(("0X%X"):format(v
)))
162 assert_equal(v
, decode(("0x%X"):format(v
)))
163 assert_equal(v
, decode(("0X%x"):format(v
)))
167 local decimal_hexes
= {
173 function test_no_decimal_hex_only()
174 for _
, str
in ipairs(decimal_hexes
) do
175 assert_error(function()
181 function test_nearly_scientific_hex_only()
182 assert_equal(0x00E1, hexDecoder("0x00e1"))
185 local function buildStrictDecoder(f
)
186 return testutil
.buildPatchedDecoder(f
, strictDecoder
)
188 local function buildFailedStrictDecoder(f
)
189 return testutil
.buildFailedPatchedDecoder(f
, strictDecoder
)
191 -- SETUP CHECKS FOR SEQUENCE OF DECODERS
192 for k
, v
in pairs(TEST_ENV
) do
193 if k
:match("^test_") and not k
:match("_gen$") and not k
:match("_only$") then
194 if k
:match("_nostrict") then
195 TEST_ENV
[k
.. "_strict_gen"] = buildFailedStrictDecoder(v
)
197 TEST_ENV
[k
.. "_strict_gen"] = buildStrictDecoder(v
)
199 TEST_ENV
[k
.. "_hex_gen"] = testutil
.buildPatchedDecoder(v
, hexDecoder
)