decode_spec.lua 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. local t = require('test.unit.testutil')
  2. local itp = t.gen_itp(it)
  3. local cimport = t.cimport
  4. local eq = t.eq
  5. local neq = t.neq
  6. local ffi = t.ffi
  7. local decode = cimport(
  8. './src/nvim/eval/decode.h',
  9. './src/nvim/eval/typval.h',
  10. './src/nvim/globals.h',
  11. './src/nvim/memory.h',
  12. './src/nvim/message.h'
  13. )
  14. describe('json_decode_string()', function()
  15. local char = function(c)
  16. return ffi.gc(decode.xmemdup(c, 1), decode.xfree)
  17. end
  18. itp('does not overflow when running with `n…`, `t…`, `f…`', function()
  19. local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
  20. decode.emsg_silent = 1
  21. -- This will not crash, but if `len` argument will be ignored it will parse
  22. -- `null` as `null` and if not it will parse `null` as `n`.
  23. eq(0, decode.json_decode_string('null', 1, rettv))
  24. eq(decode.VAR_UNKNOWN, rettv.v_type)
  25. eq(0, decode.json_decode_string('true', 1, rettv))
  26. eq(decode.VAR_UNKNOWN, rettv.v_type)
  27. eq(0, decode.json_decode_string('false', 1, rettv))
  28. eq(decode.VAR_UNKNOWN, rettv.v_type)
  29. eq(0, decode.json_decode_string('null', 2, rettv))
  30. eq(decode.VAR_UNKNOWN, rettv.v_type)
  31. eq(0, decode.json_decode_string('true', 2, rettv))
  32. eq(decode.VAR_UNKNOWN, rettv.v_type)
  33. eq(0, decode.json_decode_string('false', 2, rettv))
  34. eq(decode.VAR_UNKNOWN, rettv.v_type)
  35. eq(0, decode.json_decode_string('null', 3, rettv))
  36. eq(decode.VAR_UNKNOWN, rettv.v_type)
  37. eq(0, decode.json_decode_string('true', 3, rettv))
  38. eq(decode.VAR_UNKNOWN, rettv.v_type)
  39. eq(0, decode.json_decode_string('false', 3, rettv))
  40. eq(decode.VAR_UNKNOWN, rettv.v_type)
  41. eq(0, decode.json_decode_string('false', 4, rettv))
  42. eq(decode.VAR_UNKNOWN, rettv.v_type)
  43. end)
  44. itp('does not overflow and crash when running with `n`, `t`, `f`', function()
  45. local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
  46. decode.emsg_silent = 1
  47. eq(0, decode.json_decode_string(char('n'), 1, rettv))
  48. eq(decode.VAR_UNKNOWN, rettv.v_type)
  49. eq(0, decode.json_decode_string(char('t'), 1, rettv))
  50. eq(decode.VAR_UNKNOWN, rettv.v_type)
  51. eq(0, decode.json_decode_string(char('f'), 1, rettv))
  52. eq(decode.VAR_UNKNOWN, rettv.v_type)
  53. end)
  54. itp('does not overflow when running with `"…`', function()
  55. local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
  56. decode.emsg_silent = 1
  57. eq(0, decode.json_decode_string('"t"', 2, rettv))
  58. eq(decode.VAR_UNKNOWN, rettv.v_type)
  59. eq(0, decode.json_decode_string('""', 1, rettv))
  60. eq(decode.VAR_UNKNOWN, rettv.v_type)
  61. end)
  62. local check_failure = function(s, len, msg)
  63. local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
  64. eq(0, decode.json_decode_string(s, len, rettv))
  65. eq(decode.VAR_UNKNOWN, rettv.v_type)
  66. neq(nil, decode.last_msg_hist)
  67. eq(msg, ffi.string(decode.last_msg_hist.msg))
  68. end
  69. itp('does not overflow in error messages', function()
  70. collectgarbage('restart')
  71. check_failure(']test', 1, 'E474: No container to close: ]')
  72. check_failure('[}test', 2, 'E474: Closing list with curly bracket: }')
  73. check_failure('{]test', 2, 'E474: Closing dictionary with square bracket: ]')
  74. check_failure('[1,]test', 4, 'E474: Trailing comma: ]')
  75. check_failure('{"1":}test', 6, 'E474: Expected value after colon: }')
  76. check_failure('{"1"}test', 5, 'E474: Expected value: }')
  77. check_failure(',test', 1, 'E474: Comma not inside container: ,')
  78. check_failure('[1,,1]test', 6, 'E474: Duplicate comma: ,1]')
  79. check_failure('{"1":,}test', 7, 'E474: Comma after colon: ,}')
  80. check_failure('{"1",}test', 6, 'E474: Using comma in place of colon: ,}')
  81. check_failure('{,}test', 3, 'E474: Leading comma: ,}')
  82. check_failure('[,]test', 3, 'E474: Leading comma: ,]')
  83. check_failure(':test', 1, 'E474: Colon not inside container: :')
  84. check_failure('[:]test', 3, 'E474: Using colon not in dictionary: :]')
  85. check_failure('{:}test', 3, 'E474: Unexpected colon: :}')
  86. check_failure('{"1"::1}test', 8, 'E474: Duplicate colon: :1}')
  87. check_failure('ntest', 1, 'E474: Expected null: n')
  88. check_failure('ttest', 1, 'E474: Expected true: t')
  89. check_failure('ftest', 1, 'E474: Expected false: f')
  90. check_failure('"\\test', 2, 'E474: Unfinished escape sequence: "\\')
  91. check_failure('"\\u"test', 4, 'E474: Unfinished unicode escape sequence: "\\u"')
  92. check_failure('"\\uXXXX"est', 8, 'E474: Expected four hex digits after \\u: \\uXXXX"')
  93. check_failure('"\\?"test', 4, 'E474: Unknown escape sequence: \\?"')
  94. check_failure(
  95. '"\t"test',
  96. 3,
  97. 'E474: ASCII control characters cannot be present inside string: \t"'
  98. )
  99. check_failure('"\194"test', 3, 'E474: Only UTF-8 strings allowed: \194"')
  100. check_failure(
  101. '"\252\144\128\128\128\128"test',
  102. 8,
  103. 'E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: \252\144\128\128\128\128"'
  104. )
  105. check_failure('"test', 1, 'E474: Expected string end: "')
  106. check_failure('-test', 1, 'E474: Missing number after minus sign: -')
  107. check_failure('-1.test', 3, 'E474: Missing number after decimal dot: -1.')
  108. check_failure('-1.0etest', 5, 'E474: Missing exponent: -1.0e')
  109. check_failure('?test', 1, 'E474: Unidentified byte: ?')
  110. check_failure('1?test', 2, 'E474: Trailing characters: ?')
  111. check_failure('[1test', 2, 'E474: Unexpected end of input: [1')
  112. end)
  113. itp('does not overflow with `-`', function()
  114. check_failure('-0', 1, 'E474: Missing number after minus sign: -')
  115. end)
  116. itp('does not overflow and crash when running with `"`', function()
  117. local rettv = ffi.new('typval_T', { v_type = decode.VAR_UNKNOWN })
  118. decode.emsg_silent = 1
  119. eq(0, decode.json_decode_string(char('"'), 1, rettv))
  120. eq(decode.VAR_UNKNOWN, rettv.v_type)
  121. end)
  122. end)