json_functions_spec.lua (33626B)
1 local t = require('test.testutil') 2 local n = require('test.functional.testnvim')() 3 4 local clear = n.clear 5 local fn = n.fn 6 local api = n.api 7 local eq = t.eq 8 local eval = n.eval 9 local command = n.command 10 local exc_exec = n.exc_exec 11 local pcall_err = t.pcall_err 12 local NIL = vim.NIL 13 local source = n.source 14 15 describe('json_decode() function', function() 16 setup(function() 17 clear() 18 source([[ 19 language C 20 function Eq(exp, act) 21 let act = a:act 22 let exp = a:exp 23 if type(exp) != type(act) 24 return 0 25 endif 26 if type(exp) == type({}) 27 if sort(keys(exp)) !=# sort(keys(act)) 28 return 0 29 endif 30 if sort(keys(exp)) ==# ['_TYPE', '_VAL'] 31 let exp_typ = v:msgpack_types[exp._TYPE] 32 let act_typ = act._TYPE 33 if exp_typ isnot act_typ 34 return 0 35 endif 36 return Eq(exp._VAL, act._VAL) 37 else 38 return empty(filter(copy(exp), '!Eq(v:val, act[v:key])')) 39 endif 40 else 41 if type(exp) == type([]) 42 if len(exp) != len(act) 43 return 0 44 endif 45 return empty(filter(copy(exp), '!Eq(v:val, act[v:key])')) 46 endif 47 return exp ==# act 48 endif 49 return 1 50 endfunction 51 function EvalEq(exp, act_expr) 52 let act = eval(a:act_expr) 53 if Eq(a:exp, act) 54 return 1 55 else 56 return string(act) 57 endif 58 endfunction 59 ]]) 60 end) 61 62 local speq = function(expected, actual_expr) 63 eq(1, fn.EvalEq(expected, actual_expr)) 64 end 65 66 it('accepts readfile()-style list', function() 67 eq( 68 { Test = 1 }, 69 fn.json_decode({ 70 '{', 71 '\t"Test": 1', 72 '}', 73 }) 74 ) 75 end) 76 77 it('accepts strings with newlines', function() 78 eq( 79 { Test = 1 }, 80 fn.json_decode([[ 81 { 82 "Test": 1 83 } 84 ]]) 85 ) 86 end) 87 88 it('parses null, true, false', function() 89 eq(NIL, fn.json_decode('null')) 90 eq(true, fn.json_decode('true')) 91 eq(false, fn.json_decode('false')) 92 end) 93 94 it('fails to parse incomplete null, true, false', function() 95 eq('Vim(call):E474: Expected null: n', exc_exec('call json_decode("n")')) 96 eq('Vim(call):E474: Expected null: nu', exc_exec('call json_decode("nu")')) 97 eq('Vim(call):E474: Expected null: nul', exc_exec('call json_decode("nul")')) 98 eq('Vim(call):E474: Expected null: nul\n\t', exc_exec('call json_decode("nul\\n\\t")')) 99 100 eq('Vim(call):E474: Expected true: t', exc_exec('call json_decode("t")')) 101 eq('Vim(call):E474: Expected true: tr', exc_exec('call json_decode("tr")')) 102 eq('Vim(call):E474: Expected true: tru', exc_exec('call json_decode("tru")')) 103 eq('Vim(call):E474: Expected true: tru\t\n', exc_exec('call json_decode("tru\\t\\n")')) 104 105 eq('Vim(call):E474: Expected false: f', exc_exec('call json_decode("f")')) 106 eq('Vim(call):E474: Expected false: fa', exc_exec('call json_decode("fa")')) 107 eq('Vim(call):E474: Expected false: fal', exc_exec('call json_decode("fal")')) 108 eq('Vim(call):E474: Expected false: fal <', exc_exec('call json_decode(" fal <")')) 109 eq('Vim(call):E474: Expected false: fals', exc_exec('call json_decode("fals")')) 110 end) 111 112 it('parses integer numbers', function() 113 eq(100000, fn.json_decode('100000')) 114 eq(-100000, fn.json_decode('-100000')) 115 eq(100000, fn.json_decode(' 100000 ')) 116 eq(-100000, fn.json_decode(' -100000 ')) 117 eq(0, fn.json_decode('0')) 118 eq(0, fn.json_decode('-0')) 119 end) 120 121 it('fails to parse +numbers and .number', function() 122 eq('Vim(call):E474: Unidentified byte: +1000', exc_exec('call json_decode("+1000")')) 123 eq('Vim(call):E474: Unidentified byte: .1000', exc_exec('call json_decode(".1000")')) 124 end) 125 126 it('fails to parse numbers with leading zeroes', function() 127 eq('Vim(call):E474: Leading zeroes are not allowed: 00.1', exc_exec('call json_decode("00.1")')) 128 eq('Vim(call):E474: Leading zeroes are not allowed: 01', exc_exec('call json_decode("01")')) 129 eq('Vim(call):E474: Leading zeroes are not allowed: -01', exc_exec('call json_decode("-01")')) 130 eq( 131 'Vim(call):E474: Leading zeroes are not allowed: -001.0', 132 exc_exec('call json_decode("-001.0")') 133 ) 134 end) 135 136 it('fails to parse incomplete numbers', function() 137 eq('Vim(call):E474: Missing number after minus sign: -.1', exc_exec('call json_decode("-.1")')) 138 eq('Vim(call):E474: Missing number after minus sign: -', exc_exec('call json_decode("-")')) 139 eq('Vim(call):E474: Missing number after decimal dot: -1.', exc_exec('call json_decode("-1.")')) 140 eq('Vim(call):E474: Missing number after decimal dot: 0.', exc_exec('call json_decode("0.")')) 141 eq('Vim(call):E474: Missing exponent: 0.0e', exc_exec('call json_decode("0.0e")')) 142 eq('Vim(call):E474: Missing exponent: 0.0e+', exc_exec('call json_decode("0.0e+")')) 143 eq('Vim(call):E474: Missing exponent: 0.0e-', exc_exec('call json_decode("0.0e-")')) 144 eq('Vim(call):E474: Missing exponent: 0.0e-', exc_exec('call json_decode("0.0e-")')) 145 eq( 146 'Vim(call):E474: Missing number after decimal dot: 1.e5', 147 exc_exec('call json_decode("1.e5")') 148 ) 149 eq( 150 'Vim(call):E474: Missing number after decimal dot: 1.e+5', 151 exc_exec('call json_decode("1.e+5")') 152 ) 153 eq( 154 'Vim(call):E474: Missing number after decimal dot: 1.e+', 155 exc_exec('call json_decode("1.e+")') 156 ) 157 end) 158 159 it('parses floating-point numbers', function() 160 -- Also test method call (->) syntax 161 eq('100000.0', eval('"100000.0"->json_decode()->string()')) 162 eq(100000.5, fn.json_decode('100000.5')) 163 eq(-100000.5, fn.json_decode('-100000.5')) 164 eq(-100000.5e50, fn.json_decode('-100000.5e50')) 165 eq(100000.5e50, fn.json_decode('100000.5e50')) 166 eq(100000.5e50, fn.json_decode('100000.5e+50')) 167 eq(-100000.5e-50, fn.json_decode('-100000.5e-50')) 168 eq(100000.5e-50, fn.json_decode('100000.5e-50')) 169 eq(100000e-50, fn.json_decode('100000e-50')) 170 eq(0.5, fn.json_decode('0.5')) 171 eq(0.005, fn.json_decode('0.005')) 172 eq(0.005, fn.json_decode('0.00500')) 173 eq(0.5, fn.json_decode('0.00500e+002')) 174 eq(0.00005, fn.json_decode('0.00500e-002')) 175 176 eq(-0.0, fn.json_decode('-0.0')) 177 eq(-0.0, fn.json_decode('-0.0e0')) 178 eq(-0.0, fn.json_decode('-0.0e+0')) 179 eq(-0.0, fn.json_decode('-0.0e-0')) 180 eq(-0.0, fn.json_decode('-0e-0')) 181 eq(-0.0, fn.json_decode('-0e-2')) 182 eq(-0.0, fn.json_decode('-0e+2')) 183 184 eq(0.0, fn.json_decode('0.0')) 185 eq(0.0, fn.json_decode('0.0e0')) 186 eq(0.0, fn.json_decode('0.0e+0')) 187 eq(0.0, fn.json_decode('0.0e-0')) 188 eq(0.0, fn.json_decode('0e-0')) 189 eq(0.0, fn.json_decode('0e-2')) 190 eq(0.0, fn.json_decode('0e+2')) 191 end) 192 193 it('fails to parse numbers with spaces inside', function() 194 eq( 195 'Vim(call):E474: Missing number after minus sign: - 1000', 196 exc_exec('call json_decode("- 1000")') 197 ) 198 eq('Vim(call):E474: Missing number after decimal dot: 0. ', exc_exec('call json_decode("0. ")')) 199 eq( 200 'Vim(call):E474: Missing number after decimal dot: 0. 0', 201 exc_exec('call json_decode("0. 0")') 202 ) 203 eq('Vim(call):E474: Missing exponent: 0.0e 1', exc_exec('call json_decode("0.0e 1")')) 204 eq('Vim(call):E474: Missing exponent: 0.0e+ 1', exc_exec('call json_decode("0.0e+ 1")')) 205 eq('Vim(call):E474: Missing exponent: 0.0e- 1', exc_exec('call json_decode("0.0e- 1")')) 206 end) 207 208 it('fails to parse "," and ":"', function() 209 eq('Vim(call):E474: Comma not inside container: , ', exc_exec('call json_decode(" , ")')) 210 eq('Vim(call):E474: Colon not inside container: : ', exc_exec('call json_decode(" : ")')) 211 end) 212 213 it('parses empty containers', function() 214 eq({}, fn.json_decode('[]')) 215 eq('[]', eval('string(json_decode("[]"))')) 216 end) 217 218 it('fails to parse "[" and "{"', function() 219 eq('Vim(call):E474: Unexpected end of input: {', exc_exec('call json_decode("{")')) 220 eq('Vim(call):E474: Unexpected end of input: [', exc_exec('call json_decode("[")')) 221 end) 222 223 it('fails to parse "}" and "]"', function() 224 eq('Vim(call):E474: No container to close: ]', exc_exec('call json_decode("]")')) 225 eq('Vim(call):E474: No container to close: }', exc_exec('call json_decode("}")')) 226 end) 227 228 it('fails to parse containers which are closed by different brackets', function() 229 eq( 230 'Vim(call):E474: Closing dictionary with square bracket: ]', 231 exc_exec('call json_decode("{]")') 232 ) 233 eq('Vim(call):E474: Closing list with curly bracket: }', exc_exec('call json_decode("[}")')) 234 end) 235 236 it('fails to parse concat inside container', function() 237 eq( 238 'Vim(call):E474: Expected comma before list item: []]', 239 exc_exec('call json_decode("[[][]]")') 240 ) 241 eq( 242 'Vim(call):E474: Expected comma before list item: {}]', 243 exc_exec('call json_decode("[{}{}]")') 244 ) 245 eq('Vim(call):E474: Expected comma before list item: ]', exc_exec('call json_decode("[1 2]")')) 246 eq( 247 'Vim(call):E474: Expected comma before dictionary key: ": 4}', 248 exc_exec('call json_decode("{\\"1\\": 2 \\"3\\": 4}")') 249 ) 250 eq( 251 'Vim(call):E474: Expected colon before dictionary value: , "3" 4}', 252 exc_exec('call json_decode("{\\"1\\" 2, \\"3\\" 4}")') 253 ) 254 end) 255 256 it('fails to parse containers with leading comma or colon', function() 257 eq('Vim(call):E474: Leading comma: ,}', exc_exec('call json_decode("{,}")')) 258 eq('Vim(call):E474: Leading comma: ,]', exc_exec('call json_decode("[,]")')) 259 eq('Vim(call):E474: Using colon not in dictionary: :]', exc_exec('call json_decode("[:]")')) 260 eq('Vim(call):E474: Unexpected colon: :}', exc_exec('call json_decode("{:}")')) 261 end) 262 263 it('fails to parse containers with trailing comma', function() 264 eq('Vim(call):E474: Trailing comma: ]', exc_exec('call json_decode("[1,]")')) 265 eq('Vim(call):E474: Trailing comma: }', exc_exec('call json_decode("{\\"1\\": 2,}")')) 266 end) 267 268 it('fails to parse dictionaries with missing value', function() 269 eq('Vim(call):E474: Expected value after colon: }', exc_exec('call json_decode("{\\"1\\":}")')) 270 eq('Vim(call):E474: Expected value: }', exc_exec('call json_decode("{\\"1\\"}")')) 271 end) 272 273 it('fails to parse containers with two commas or colons', function() 274 eq( 275 'Vim(call):E474: Duplicate comma: , "2": 2}', 276 exc_exec('call json_decode("{\\"1\\": 1,, \\"2\\": 2}")') 277 ) 278 eq( 279 'Vim(call):E474: Duplicate comma: , "2", 2]', 280 exc_exec('call json_decode("[\\"1\\", 1,, \\"2\\", 2]")') 281 ) 282 eq( 283 'Vim(call):E474: Duplicate colon: : 2}', 284 exc_exec('call json_decode("{\\"1\\": 1, \\"2\\":: 2}")') 285 ) 286 eq( 287 'Vim(call):E474: Comma after colon: , 2}', 288 exc_exec('call json_decode("{\\"1\\": 1, \\"2\\":, 2}")') 289 ) 290 eq( 291 'Vim(call):E474: Unexpected colon: : "2": 2}', 292 exc_exec('call json_decode("{\\"1\\": 1,: \\"2\\": 2}")') 293 ) 294 eq( 295 'Vim(call):E474: Unexpected colon: :, "2": 2}', 296 exc_exec('call json_decode("{\\"1\\": 1:, \\"2\\": 2}")') 297 ) 298 end) 299 300 it('fails to parse concat of two values', function() 301 eq('Vim(call):E474: Trailing characters: []', exc_exec('call json_decode("{}[]")')) 302 end) 303 304 it('parses containers', function() 305 eq({ 1 }, fn.json_decode('[1]')) 306 eq({ NIL, 1 }, fn.json_decode('[null, 1]')) 307 eq({ ['1'] = 2 }, fn.json_decode('{"1": 2}')) 308 eq( 309 { ['1'] = 2, ['3'] = { { ['4'] = { ['5'] = { {}, 1 } } } } }, 310 fn.json_decode('{"1": 2, "3": [{"4": {"5": [[], 1]}}]}') 311 ) 312 end) 313 314 it('fails to parse incomplete strings', function() 315 eq('Vim(call):E474: Expected string end: \t"', exc_exec('call json_decode("\\t\\"")')) 316 eq('Vim(call):E474: Expected string end: \t"abc', exc_exec('call json_decode("\\t\\"abc")')) 317 eq( 318 'Vim(call):E474: Unfinished escape sequence: \t"abc\\', 319 exc_exec('call json_decode("\\t\\"abc\\\\")') 320 ) 321 eq( 322 'Vim(call):E474: Unfinished unicode escape sequence: \t"abc\\u', 323 exc_exec('call json_decode("\\t\\"abc\\\\u")') 324 ) 325 eq( 326 'Vim(call):E474: Unfinished unicode escape sequence: \t"abc\\u0', 327 exc_exec('call json_decode("\\t\\"abc\\\\u0")') 328 ) 329 eq( 330 'Vim(call):E474: Unfinished unicode escape sequence: \t"abc\\u00', 331 exc_exec('call json_decode("\\t\\"abc\\\\u00")') 332 ) 333 eq( 334 'Vim(call):E474: Unfinished unicode escape sequence: \t"abc\\u000', 335 exc_exec('call json_decode("\\t\\"abc\\\\u000")') 336 ) 337 eq( 338 'Vim(call):E474: Expected four hex digits after \\u: \\u" ', 339 exc_exec('call json_decode("\\t\\"abc\\\\u\\" ")') 340 ) 341 eq( 342 'Vim(call):E474: Expected four hex digits after \\u: \\u0" ', 343 exc_exec('call json_decode("\\t\\"abc\\\\u0\\" ")') 344 ) 345 eq( 346 'Vim(call):E474: Expected four hex digits after \\u: \\u00" ', 347 exc_exec('call json_decode("\\t\\"abc\\\\u00\\" ")') 348 ) 349 eq( 350 'Vim(call):E474: Expected four hex digits after \\u: \\u000" ', 351 exc_exec('call json_decode("\\t\\"abc\\\\u000\\" ")') 352 ) 353 eq( 354 'Vim(call):E474: Expected string end: \t"abc\\u0000', 355 exc_exec('call json_decode("\\t\\"abc\\\\u0000")') 356 ) 357 end) 358 359 it('fails to parse unknown escape sequences', function() 360 eq( 361 'Vim(call):E474: Unknown escape sequence: \\a"', 362 exc_exec('call json_decode("\\t\\"\\\\a\\"")') 363 ) 364 end) 365 366 it('parses strings properly', function() 367 eq('\n', fn.json_decode('"\\n"')) 368 eq('', fn.json_decode('""')) 369 eq('\\/"\t\b\n\r\f', fn.json_decode([["\\\/\"\t\b\n\r\f"]])) 370 eq('/a', fn.json_decode([["\/a"]])) 371 -- Unicode characters: 2-byte, 3-byte, 4-byte 372 eq( 373 { 374 '«', 375 'ફ', 376 '\240\144\128\128', 377 }, 378 fn.json_decode({ 379 '[', 380 '"«",', 381 '"ફ",', 382 '"\240\144\128\128"', 383 ']', 384 }) 385 ) 386 end) 387 388 it('fails on strings with invalid bytes', function() 389 eq( 390 'Vim(call):E474: Only UTF-8 strings allowed: \255"', 391 exc_exec('call json_decode("\\t\\"\\xFF\\"")') 392 ) 393 eq( 394 'Vim(call):E474: ASCII control characters cannot be present inside string: ', 395 exc_exec('call json_decode(["\\"\\n\\""])') 396 ) 397 -- 0xC2 starts 2-byte unicode character 398 eq( 399 'Vim(call):E474: Only UTF-8 strings allowed: \194"', 400 exc_exec('call json_decode("\\t\\"\\xC2\\"")') 401 ) 402 -- 0xE0 0xAA starts 3-byte unicode character 403 eq( 404 'Vim(call):E474: Only UTF-8 strings allowed: \224"', 405 exc_exec('call json_decode("\\t\\"\\xE0\\"")') 406 ) 407 eq( 408 'Vim(call):E474: Only UTF-8 strings allowed: \224\170"', 409 exc_exec('call json_decode("\\t\\"\\xE0\\xAA\\"")') 410 ) 411 -- 0xF0 0x90 0x80 starts 4-byte unicode character 412 eq( 413 'Vim(call):E474: Only UTF-8 strings allowed: \240"', 414 exc_exec('call json_decode("\\t\\"\\xF0\\"")') 415 ) 416 eq( 417 'Vim(call):E474: Only UTF-8 strings allowed: \240\144"', 418 exc_exec('call json_decode("\\t\\"\\xF0\\x90\\"")') 419 ) 420 eq( 421 'Vim(call):E474: Only UTF-8 strings allowed: \240\144\128"', 422 exc_exec('call json_decode("\\t\\"\\xF0\\x90\\x80\\"")') 423 ) 424 -- 0xF9 0x80 0x80 0x80 starts 5-byte unicode character 425 eq( 426 'Vim(call):E474: Only UTF-8 strings allowed: \249"', 427 exc_exec('call json_decode("\\t\\"\\xF9\\"")') 428 ) 429 eq( 430 'Vim(call):E474: Only UTF-8 strings allowed: \249\128"', 431 exc_exec('call json_decode("\\t\\"\\xF9\\x80\\"")') 432 ) 433 eq( 434 'Vim(call):E474: Only UTF-8 strings allowed: \249\128\128"', 435 exc_exec('call json_decode("\\t\\"\\xF9\\x80\\x80\\"")') 436 ) 437 eq( 438 'Vim(call):E474: Only UTF-8 strings allowed: \249\128\128\128"', 439 exc_exec('call json_decode("\\t\\"\\xF9\\x80\\x80\\x80\\"")') 440 ) 441 -- 0xFC 0x90 0x80 0x80 0x80 starts 6-byte unicode character 442 eq( 443 'Vim(call):E474: Only UTF-8 strings allowed: \252"', 444 exc_exec('call json_decode("\\t\\"\\xFC\\"")') 445 ) 446 eq( 447 'Vim(call):E474: Only UTF-8 strings allowed: \252\144"', 448 exc_exec('call json_decode("\\t\\"\\xFC\\x90\\"")') 449 ) 450 eq( 451 'Vim(call):E474: Only UTF-8 strings allowed: \252\144\128"', 452 exc_exec('call json_decode("\\t\\"\\xFC\\x90\\x80\\"")') 453 ) 454 eq( 455 'Vim(call):E474: Only UTF-8 strings allowed: \252\144\128\128"', 456 exc_exec('call json_decode("\\t\\"\\xFC\\x90\\x80\\x80\\"")') 457 ) 458 eq( 459 'Vim(call):E474: Only UTF-8 strings allowed: \252\144\128\128\128"', 460 exc_exec('call json_decode("\\t\\"\\xFC\\x90\\x80\\x80\\x80\\"")') 461 ) 462 -- Specification does not allow unquoted characters above 0x10FFFF 463 eq( 464 'Vim(call):E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \249\128\128\128\128"', 465 exc_exec('call json_decode("\\t\\"\\xF9\\x80\\x80\\x80\\x80\\"")') 466 ) 467 eq( 468 'Vim(call):E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \252\144\128\128\128\128"', 469 exc_exec('call json_decode("\\t\\"\\xFC\\x90\\x80\\x80\\x80\\x80\\"")') 470 ) 471 -- '"\249\128\128\128\128"', 472 -- '"\252\144\128\128\128\128"', 473 end) 474 475 it('parses surrogate pairs properly', function() 476 eq('\240\144\128\128', fn.json_decode('"\\uD800\\uDC00"')) 477 eq('\237\160\128a\237\176\128', fn.json_decode('"\\uD800a\\uDC00"')) 478 eq('\237\160\128\t\237\176\128', fn.json_decode('"\\uD800\\t\\uDC00"')) 479 480 eq('\237\160\128', fn.json_decode('"\\uD800"')) 481 eq('\237\160\128a', fn.json_decode('"\\uD800a"')) 482 eq('\237\160\128\t', fn.json_decode('"\\uD800\\t"')) 483 484 eq('\237\176\128', fn.json_decode('"\\uDC00"')) 485 eq('\237\176\128a', fn.json_decode('"\\uDC00a"')) 486 eq('\237\176\128\t', fn.json_decode('"\\uDC00\\t"')) 487 488 eq('\237\176\128', fn.json_decode('"\\uDC00"')) 489 eq('a\237\176\128', fn.json_decode('"a\\uDC00"')) 490 eq('\t\237\176\128', fn.json_decode('"\\t\\uDC00"')) 491 492 eq('\237\160\128¬', fn.json_decode('"\\uD800\\u00AC"')) 493 494 eq('\237\160\128\237\160\128', fn.json_decode('"\\uD800\\uD800"')) 495 end) 496 497 local sp_decode_eq = function(expected, json) 498 api.nvim_set_var('__json', json) 499 speq(expected, 'json_decode(g:__json)') 500 command('unlet! g:__json') 501 end 502 503 it('parses strings with NUL properly', function() 504 sp_decode_eq('\000', '"\\u0000"') 505 sp_decode_eq('\000\n\000', '"\\u0000\\n\\u0000"') 506 sp_decode_eq('\000«\000', '"\\u0000\\u00AB\\u0000"') 507 end) 508 509 it('parses dictionaries with duplicate keys to special maps', function() 510 sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a', 1 }, { 'a', 2 } } }, '{"a": 1, "a": 2}') 511 sp_decode_eq( 512 { _TYPE = 'map', _VAL = { { 'b', 3 }, { 'a', 1 }, { 'a', 2 } } }, 513 '{"b": 3, "a": 1, "a": 2}' 514 ) 515 sp_decode_eq( 516 { _TYPE = 'map', _VAL = { { 'b', 3 }, { 'a', 1 }, { 'c', 4 }, { 'a', 2 } } }, 517 '{"b": 3, "a": 1, "c": 4, "a": 2}' 518 ) 519 sp_decode_eq( 520 { _TYPE = 'map', _VAL = { { 'b', 3 }, { 'a', 1 }, { 'c', 4 }, { 'a', 2 }, { 'c', 4 } } }, 521 '{"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}' 522 ) 523 sp_decode_eq( 524 { { _TYPE = 'map', _VAL = { { 'b', 3 }, { 'a', 1 }, { 'c', 4 }, { 'a', 2 }, { 'c', 4 } } } }, 525 '[{"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}]' 526 ) 527 sp_decode_eq({ 528 { 529 d = { 530 _TYPE = 'map', 531 _VAL = { { 'b', 3 }, { 'a', 1 }, { 'c', 4 }, { 'a', 2 }, { 'c', 4 } }, 532 }, 533 }, 534 }, '[{"d": {"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}}]') 535 sp_decode_eq({ 536 1, 537 { 538 d = { 539 _TYPE = 'map', 540 _VAL = { { 'b', 3 }, { 'a', 1 }, { 'c', 4 }, { 'a', 2 }, { 'c', 4 } }, 541 }, 542 }, 543 }, '[1, {"d": {"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}}]') 544 sp_decode_eq({ 545 1, 546 { 547 a = {}, 548 d = { 549 _TYPE = 'map', 550 _VAL = { 551 { 'b', 3 }, 552 { 'a', 1 }, 553 { 'c', 4 }, 554 { 'a', 2 }, 555 { 556 'c', 557 4, 558 }, 559 }, 560 }, 561 }, 562 }, '[1, {"a": [], "d": {"b": 3, "a": 1, "c": 4, "a": 2, "c": 4}}]') 563 sp_decode_eq( 564 { _TYPE = 'map', _VAL = { { '', 3 }, { 'a', 1 }, { 'c', 4 }, { 'd', 2 }, { '', 4 } } }, 565 '{"": 3, "a": 1, "c": 4, "d": 2, "": 4}' 566 ) 567 sp_decode_eq( 568 { { _TYPE = 'map', _VAL = { { '', 3 }, { 'a', 1 }, { 'c', 4 }, { 'd', 2 }, { '', 4 } } } }, 569 '[{"": 3, "a": 1, "c": 4, "d": 2, "": 4}]' 570 ) 571 end) 572 573 it('parses dictionaries with empty keys', function() 574 eq({ [''] = 4 }, fn.json_decode('{"": 4}')) 575 eq( 576 { b = 3, a = 1, c = 4, d = 2, [''] = 4 }, 577 fn.json_decode('{"b": 3, "a": 1, "c": 4, "d": 2, "": 4}') 578 ) 579 end) 580 581 it('parses dictionaries with keys with NUL bytes to special maps', function() 582 sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb', 4 } } }, '{"a\\u0000\\nb": 4}') 583 sp_decode_eq({ _TYPE = 'map', _VAL = { { 'a\000\nb\n', 4 } } }, '{"a\\u0000\\nb\\n": 4}') 584 sp_decode_eq({ 585 _TYPE = 'map', 586 _VAL = { 587 { 'b', 3 }, 588 { 'a', 1 }, 589 { 'c', 4 }, 590 { 'd', 2 }, 591 { '\000', 4 }, 592 }, 593 }, '{"b": 3, "a": 1, "c": 4, "d": 2, "\\u0000": 4}') 594 end) 595 596 it('parses U+00C3 correctly', function() 597 eq('\195\131', fn.json_decode('"\195\131"')) 598 end) 599 600 it('fails to parse empty string', function() 601 eq('Vim(call):E474: Attempt to decode a blank string', exc_exec('call json_decode("")')) 602 eq('Vim(call):E474: Attempt to decode a blank string', exc_exec('call json_decode([])')) 603 eq('Vim(call):E474: Attempt to decode a blank string', exc_exec('call json_decode([""])')) 604 eq('Vim(call):E474: Attempt to decode a blank string', exc_exec('call json_decode(" ")')) 605 eq('Vim(call):E474: Attempt to decode a blank string', exc_exec('call json_decode("\\t")')) 606 eq('Vim(call):E474: Attempt to decode a blank string', exc_exec('call json_decode("\\n")')) 607 eq( 608 'Vim(call):E474: Attempt to decode a blank string', 609 exc_exec('call json_decode(" \\t\\n \\n\\t\\t \\n\\t\\n \\n \\t\\n\\t ")') 610 ) 611 end) 612 613 it('accepts all spaces in every position where space may be put', function() 614 local s = 615 ' \t\n\r \t\r\n \n\t\r \n\r\t \r\t\n \r\n\t\t \n\r\t \r\n\t\n \r\t\n\r \t\r \n\t\r\n \n \t\r\n \r\t\n\t \r\n\t\r \n\r \t\n\r\t \r \t\n\r \n\t\r\t \n\r\t\n \r\n \t\r\n\t' 616 local str = ('%s{%s"key"%s:%s[%s"val"%s,%s"val2"%s]%s,%s"key2"%s:%s1%s}%s'):gsub('%%s', s) 617 eq({ key = { 'val', 'val2' }, key2 = 1 }, fn.json_decode(str)) 618 end) 619 620 it('does not overflow when writing error message about decoding ["", ""]', function() 621 eq( 622 'Vim(call):E474: Attempt to decode a blank string', 623 pcall_err(command, 'call json_decode(["", ""])') 624 ) 625 end) 626 end) 627 628 describe('json_encode() function', function() 629 setup(function() 630 clear() 631 command('language C') 632 end) 633 634 it('dumps strings', function() 635 eq('"Test"', fn.json_encode('Test')) 636 eq('""', fn.json_encode('')) 637 eq('"\\t"', fn.json_encode('\t')) 638 eq('"\\n"', fn.json_encode('\n')) 639 eq('"\\u001B"', fn.json_encode('\27')) 640 eq('"þÿþ"', fn.json_encode('þÿþ')) 641 end) 642 643 it('dumps blobs', function() 644 eq('[]', eval('json_encode(0z)')) 645 eq('[222, 173, 190, 239]', eval('json_encode(0zDEADBEEF)')) 646 end) 647 648 it('dumps numbers', function() 649 eq('0', fn.json_encode(0)) 650 eq('10', fn.json_encode(10)) 651 eq('-10', fn.json_encode(-10)) 652 end) 653 654 it('dumps floats', function() 655 -- Also test method call (->) syntax 656 eq('0.0', eval('0.0->json_encode()')) 657 eq('10.5', fn.json_encode(10.5)) 658 eq('-10.5', fn.json_encode(-10.5)) 659 eq('-1.0e-5', fn.json_encode(-1e-5)) 660 eq('1.0e50', eval('1.0e50->json_encode()')) 661 end) 662 663 it('fails to dump NaN and infinite values', function() 664 eq( 665 'Vim(call):E474: Unable to represent NaN value in JSON', 666 exc_exec('call json_encode(str2float("nan"))') 667 ) 668 eq( 669 'Vim(call):E474: Unable to represent infinity in JSON', 670 exc_exec('call json_encode(str2float("inf"))') 671 ) 672 eq( 673 'Vim(call):E474: Unable to represent infinity in JSON', 674 exc_exec('call json_encode(-str2float("inf"))') 675 ) 676 end) 677 678 it('dumps lists', function() 679 eq('[]', fn.json_encode({})) 680 eq('[[]]', fn.json_encode({ {} })) 681 eq('[[], []]', fn.json_encode({ {}, {} })) 682 end) 683 684 it('dumps dictionaries', function() 685 eq('{}', eval('json_encode({})')) 686 eq('{"d": []}', fn.json_encode({ d = {} })) 687 eq('{"d": [], "e": []}', fn.json_encode({ d = {}, e = {} })) 688 -- Empty keys are allowed per JSON spec (and Vim dicts, and msgpack). 689 eq('{"": []}', fn.json_encode({ [''] = {} })) 690 end) 691 692 it('cannot dump generic mapping with generic mapping keys and values', function() 693 command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}') 694 command('let todumpv1 = {"_TYPE": v:msgpack_types.map, "_VAL": []}') 695 command('let todumpv2 = {"_TYPE": v:msgpack_types.map, "_VAL": []}') 696 command('call add(todump._VAL, [todumpv1, todumpv2])') 697 eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) 698 end) 699 700 it('cannot dump generic mapping with ext key', function() 701 command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}') 702 command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') 703 eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) 704 end) 705 706 it('cannot dump generic mapping with array key', function() 707 command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}') 708 command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') 709 eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) 710 end) 711 712 it('cannot dump generic mapping with UINT64_MAX key', function() 713 command('let todump = {"_TYPE": v:msgpack_types.integer}') 714 command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]') 715 command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') 716 eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) 717 end) 718 719 it('cannot dump generic mapping with floating-point key', function() 720 command('let todump = {"_TYPE": v:msgpack_types.float, "_VAL": 0.125}') 721 command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') 722 eq('Vim(call):E474: Invalid key in special dictionary', exc_exec('call json_encode(todump)')) 723 end) 724 725 it('can dump generic mapping with STR special key and NUL', function() 726 command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n"]}') 727 command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [[todump, 1]]}') 728 eq('{"\\u0000": 1}', eval('json_encode(todump)')) 729 end) 730 731 it('can dump STR special mapping with NUL and NL', function() 732 command('let todump = {"_TYPE": v:msgpack_types.string, "_VAL": ["\\n", ""]}') 733 eq('"\\u0000\\n"', eval('json_encode(todump)')) 734 end) 735 736 it('cannot dump special ext mapping', function() 737 command('let todump = {"_TYPE": v:msgpack_types.ext, "_VAL": [5, ["",""]]}') 738 eq('Vim(call):E474: Unable to convert EXT string to JSON', exc_exec('call json_encode(todump)')) 739 end) 740 741 it('can dump special array mapping', function() 742 command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": [5, [""]]}') 743 eq('[5, [""]]', eval('json_encode(todump)')) 744 end) 745 746 it('can dump special UINT64_MAX mapping', function() 747 command('let todump = {"_TYPE": v:msgpack_types.integer}') 748 command('let todump._VAL = [1, 3, 0x7FFFFFFF, 0x7FFFFFFF]') 749 eq('18446744073709551615', eval('json_encode(todump)')) 750 end) 751 752 it('can dump special INT64_MIN mapping', function() 753 command('let todump = {"_TYPE": v:msgpack_types.integer}') 754 command('let todump._VAL = [-1, 2, 0, 0]') 755 eq('-9223372036854775808', eval('json_encode(todump)')) 756 end) 757 758 it('can dump special BOOLEAN true mapping', function() 759 command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 1}') 760 eq('true', eval('json_encode(todump)')) 761 end) 762 763 it('can dump special BOOLEAN false mapping', function() 764 command('let todump = {"_TYPE": v:msgpack_types.boolean, "_VAL": 0}') 765 eq('false', eval('json_encode(todump)')) 766 end) 767 768 it('can dump special NIL mapping', function() 769 command('let todump = {"_TYPE": v:msgpack_types.nil, "_VAL": 0}') 770 eq('null', eval('json_encode(todump)')) 771 end) 772 773 it('fails to dump a function reference', function() 774 eq( 775 'Vim(call):E474: Error while dumping encode_tv2json() argument, itself: attempt to dump function reference', 776 exc_exec('call json_encode(function("tr"))') 777 ) 778 end) 779 780 it('fails to dump a partial', function() 781 command('function T() dict\nendfunction') 782 eq( 783 'Vim(call):E474: Error while dumping encode_tv2json() argument, itself: attempt to dump function reference', 784 exc_exec('call json_encode(function("T", [1, 2], {}))') 785 ) 786 end) 787 788 it('fails to dump a function reference in a list', function() 789 eq( 790 'Vim(call):E474: Error while dumping encode_tv2json() argument, index 0: attempt to dump function reference', 791 exc_exec('call json_encode([function("tr")])') 792 ) 793 end) 794 795 it('fails to dump a recursive list', function() 796 command('let todump = [[[]]]') 797 command('call add(todump[0][0], todump)') 798 eq( 799 'Vim(call):E724: unable to correctly dump variable with self-referencing container', 800 exc_exec('call json_encode(todump)') 801 ) 802 end) 803 804 it('fails to dump a recursive dict', function() 805 command('let todump = {"d": {"d": {}}}') 806 command('call extend(todump.d.d, {"d": todump})') 807 eq( 808 'Vim(call):E724: unable to correctly dump variable with self-referencing container', 809 exc_exec('call json_encode([todump])') 810 ) 811 end) 812 813 it('can dump dict with two same dicts inside', function() 814 command('let inter = {}') 815 command('let todump = {"a": inter, "b": inter}') 816 eq('{"a": {}, "b": {}}', eval('json_encode(todump)')) 817 end) 818 819 it('can dump list with two same lists inside', function() 820 command('let inter = []') 821 command('let todump = [inter, inter]') 822 eq('[[], []]', eval('json_encode(todump)')) 823 end) 824 825 it('fails to dump a recursive list in a special dict', function() 826 command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') 827 command('call add(todump._VAL, todump)') 828 eq( 829 'Vim(call):E724: unable to correctly dump variable with self-referencing container', 830 exc_exec('call json_encode(todump)') 831 ) 832 end) 833 834 it('fails to dump a recursive (val) map in a special dict', function() 835 command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": []}') 836 command('call add(todump._VAL, ["", todump])') 837 eq( 838 'Vim(call):E724: unable to correctly dump variable with self-referencing container', 839 exc_exec('call json_encode([todump])') 840 ) 841 end) 842 843 it('fails to dump a recursive (val) map in a special dict, _VAL reference', function() 844 command('let todump = {"_TYPE": v:msgpack_types.map, "_VAL": [["", []]]}') 845 command('call add(todump._VAL[0][1], todump._VAL)') 846 eq( 847 'Vim(call):E724: unable to correctly dump variable with self-referencing container', 848 exc_exec('call json_encode(todump)') 849 ) 850 end) 851 852 it('fails to dump a recursive (val) special list in a special dict', function() 853 command('let todump = {"_TYPE": v:msgpack_types.array, "_VAL": []}') 854 command('call add(todump._VAL, ["", todump._VAL])') 855 eq( 856 'Vim(call):E724: unable to correctly dump variable with self-referencing container', 857 exc_exec('call json_encode(todump)') 858 ) 859 end) 860 861 it('fails when called with no arguments', function() 862 eq( 863 'Vim(call):E119: Not enough arguments for function: json_encode', 864 exc_exec('call json_encode()') 865 ) 866 end) 867 868 it('fails when called with two arguments', function() 869 eq( 870 'Vim(call):E118: Too many arguments for function: json_encode', 871 exc_exec('call json_encode(["", ""], 1)') 872 ) 873 end) 874 875 it('ignores improper values in &isprint', function() 876 api.nvim_set_option_value('isprint', '1', {}) 877 eq(1, eval('"\1" =~# "\\\\p"')) 878 eq('"\\u0001"', fn.json_encode('\1')) 879 end) 880 881 it('fails when using surrogate character in a UTF-8 string', function() 882 eq( 883 'Vim(call):E474: UTF-8 string contains code point which belongs to a surrogate pair: \237\160\128', 884 exc_exec('call json_encode("\237\160\128")') 885 ) 886 eq( 887 'Vim(call):E474: UTF-8 string contains code point which belongs to a surrogate pair: \237\175\191', 888 exc_exec('call json_encode("\237\175\191")') 889 ) 890 end) 891 892 it('dumps control characters as expected', function() 893 eq( 894 [["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000B\f\r\u000E\u000F\u0010\u0011\u0012\u0013"]], 895 eval( 896 'json_encode({"_TYPE": v:msgpack_types.string, "_VAL": ["\n\1\2\3\4\5\6\7\8\9", "\11\12\13\14\15\16\17\18\19"]})' 897 ) 898 ) 899 end) 900 901 it('can dump NULL string', function() 902 eq('""', eval('json_encode($XXX_UNEXISTENT_VAR_XXX)')) 903 end) 904 905 it('can dump NULL blob', function() 906 eq('[]', eval('json_encode(v:_null_blob)')) 907 end) 908 909 it('can dump NULL list', function() 910 eq('[]', eval('json_encode(v:_null_list)')) 911 end) 912 913 it('can dump NULL dict', function() 914 eq('{}', eval('json_encode(v:_null_dict)')) 915 end) 916 917 it('fails to parse NULL strings and lists', function() 918 eq( 919 'Vim(call):E474: Attempt to decode a blank string', 920 exc_exec('call json_decode($XXX_UNEXISTENT_VAR_XXX)') 921 ) 922 eq( 923 'Vim(call):E474: Attempt to decode a blank string', 924 exc_exec('call json_decode(v:_null_list)') 925 ) 926 end) 927 end)