jsone_decode_tests.erl 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. %% Copyright (c) 2013-2014, Takeru Ohta <phjgt308@gmail.com>
  2. %% coding: latin-1
  3. -module(jsone_decode_tests).
  4. -include_lib("eunit/include/eunit.hrl").
  5. decode_test_() ->
  6. [
  7. %% Symbols
  8. {"false",
  9. fun () ->
  10. ?assertEqual({ok, false, <<"">>}, jsone_decode:decode(<<"false">>))
  11. end},
  12. {"true",
  13. fun () ->
  14. ?assertEqual({ok, true, <<"">>}, jsone_decode:decode(<<"true">>))
  15. end},
  16. {"null",
  17. fun () ->
  18. ?assertEqual({ok, null, <<"">>}, jsone_decode:decode(<<"null">>))
  19. end},
  20. %% Numbers: Integer
  21. {"positive integer",
  22. fun () ->
  23. ?assertEqual({ok, 1, <<"">>}, jsone_decode:decode(<<"1">>))
  24. end},
  25. {"zero",
  26. fun () ->
  27. ?assertEqual({ok, 0, <<"">>}, jsone_decode:decode(<<"0">>))
  28. end},
  29. {"negative integer",
  30. fun () ->
  31. ?assertEqual({ok, -1, <<"">>}, jsone_decode:decode(<<"-1">>))
  32. end},
  33. {"large integer (no limit on size)",
  34. fun () ->
  35. ?assertEqual({ok, 111111111111111111111111111111111111111111111111111111111111111111111111111111, <<"">>},
  36. jsone_decode:decode(<<"111111111111111111111111111111111111111111111111111111111111111111111111111111">>))
  37. end},
  38. {"integer with leading zero (interpreted as zero and remaining binary)",
  39. fun () ->
  40. ?assertEqual({ok, 0, <<"0">>}, jsone_decode:decode(<<"00">>)),
  41. ?assertEqual({ok, 0, <<"1">>}, jsone_decode:decode(<<"01">>)),
  42. ?assertEqual({ok, 0, <<"1">>}, jsone_decode:decode(<<"-01">>))
  43. end},
  44. {"integer can't begin with an explicit plus sign",
  45. fun () ->
  46. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"+1">>))
  47. end},
  48. %% Numbers: Floats
  49. {"float: decimal notation",
  50. fun () ->
  51. ?assertEqual({ok, 1.23, <<"">>}, jsone_decode:decode(<<"1.23">>))
  52. end},
  53. {"float: exponential notation",
  54. fun () ->
  55. ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"12345e-3">>)), % lower case 'e'
  56. ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"12345E-3">>)), % upper case 'E'
  57. ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"12345.0e-3">>)),
  58. ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"0.12345E2">>)),
  59. ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"0.12345e+2">>)), % exponent part can begin with plus sign
  60. ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"0.12345E+2">>)),
  61. ?assertEqual({ok, -12.345, <<"">>}, jsone_decode:decode(<<"-0.012345e3">>))
  62. end},
  63. {"float: invalid format",
  64. fun () ->
  65. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<".123">>)), % omitted integer part
  66. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.">>)), % omitted fraction part: EOS
  67. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.e+3">>)), % omitted fraction part: with exponent part
  68. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e">>)), % imcomplete fraction part
  69. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e-">>)), % imcomplete fraction part
  70. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1ee-1">>)), % duplicated 'e'
  71. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e--1">>)), % duplicated sign
  72. ?assertEqual({ok, 0.1, <<".2">>}, jsone_decode:decode(<<"0.1.2">>)) % duplicated '.': interpreted as individual tokens
  73. end},
  74. %% Strings
  75. {"simple string",
  76. fun () ->
  77. ?assertEqual({ok, <<"abc">>, <<"">>}, jsone_decode:decode(<<"\"abc\"">>))
  78. end},
  79. {"string: escaped characters",
  80. fun () ->
  81. Input = list_to_binary([$", [[$\\, C] || C <- [$", $/, $\\, $b, $f, $n, $r, $t]], $"]),
  82. Expected = <<"\"\/\\\b\f\n\r\t">>,
  83. ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
  84. end},
  85. {"string: escaped Unicode characters",
  86. fun () ->
  87. %% japanese
  88. Input1 = <<"\"\\u3042\\u3044\\u3046\\u3048\\u304A\"">>,
  89. Expected1 = <<"あいうえお">>, % assumed that the encoding of this file is UTF-8
  90. ?assertEqual({ok, Expected1, <<"">>}, jsone_decode:decode(Input1)),
  91. %% ascii
  92. Input2 = <<"\"\\u0061\\u0062\\u0063\"">>,
  93. Expected2 = <<"abc">>,
  94. ?assertEqual({ok, Expected2, <<"">>}, jsone_decode:decode(Input2)),
  95. %% other multi-byte characters
  96. Input3 = <<"\"\\u06DD\\u06DE\\u10AE\\u10AF\"">>,
  97. Expected3 = <<"۝۞ႮႯ">>,
  98. ?assertEqual({ok, Expected3, <<"">>}, jsone_decode:decode(Input3)),
  99. %% mixture of ascii and japanese characters
  100. Input4 = <<"\"a\\u30421\\u3044bb\\u304622\\u3048ccc\\u304A333\"">>,
  101. Expected4 = <<"aあ1いbbう22えcccお333">>, % assumed that the encoding of this file is UTF-8
  102. ?assertEqual({ok, Expected4, <<"">>}, jsone_decode:decode(Input4))
  103. end},
  104. {"string: surrogate pairs",
  105. fun () ->
  106. Input = <<"\"\\ud848\\udc49\\ud848\\udc9a\\ud848\\udcfc\"">>,
  107. Expected = <<"𢁉𢂚𢃼">>,
  108. ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
  109. end},
  110. {"string: invalid escape characters",
  111. fun () ->
  112. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\z\"">>)), % '\z' is undefined
  113. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\uab\"">>)), % too few hex characters
  114. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\ud848\"">>)), % high(first) surrogate only
  115. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\udc49\"">>)), % low(second) surrogate only
  116. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\ud848\\u0061\"">>)) % missing low(second) surrogate
  117. end},
  118. %% Arrays
  119. {"simple array",
  120. fun () ->
  121. Input = <<"[1,2,\"abc\",null]">>,
  122. Expected = [1, 2, <<"abc">>, null],
  123. ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
  124. end},
  125. {"array: contains whitespaces",
  126. fun () ->
  127. Input = <<"[ 1,\t2, \n \"abc\",\r null]">>,
  128. Expected = [1, 2, <<"abc">>, null],
  129. ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
  130. end},
  131. {"empty array",
  132. fun () ->
  133. ?assertEqual({ok, [], <<"">>}, jsone_decode:decode(<<"[]">>)),
  134. ?assertEqual({ok, [], <<"">>}, jsone_decode:decode(<<"[ \t\r\n]">>))
  135. end},
  136. {"array: trailing comma is disallowed",
  137. fun () ->
  138. Input = <<"[1, 2, \"abc\", null, ]">>,
  139. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
  140. end},
  141. {"array: missing comma",
  142. fun () ->
  143. Input = <<"[1 2, \"abc\", null]">>, % a missing comma between '1' and '2'
  144. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
  145. end},
  146. {"array: missing closing bracket",
  147. fun () ->
  148. Input = <<"[1, 2, \"abc\", null">>,
  149. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
  150. end},
  151. %% Objects
  152. {"simple object",
  153. fun () ->
  154. Input = <<"{\"1\":2,\"key\":\"value\"}">>,
  155. Expected = {[{<<"key">>, <<"value">>}, {<<"1">>, 2}]},
  156. ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
  157. end},
  158. {"object: contains whitespaces",
  159. fun () ->
  160. Input = <<"{ \"1\" :\t 2,\n\r\"key\" : \n \"value\"}">>,
  161. Expected = {[{<<"key">>, <<"value">>}, {<<"1">>, 2}]},
  162. ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
  163. end},
  164. {"empty object",
  165. fun () ->
  166. ?assertEqual({ok, {[]}, <<"">>}, jsone_decode:decode(<<"{}">>)),
  167. ?assertEqual({ok, {[]}, <<"">>}, jsone_decode:decode(<<"{ \t\r\n}">>))
  168. end},
  169. {"object: trailing comma is disallowed",
  170. fun () ->
  171. Input = <<"{\"1\":2, \"key\":\"value\", }">>,
  172. io:format("~p\n", [catch jsone_decode:decode(Input)]),
  173. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
  174. end},
  175. {"object: missing comma",
  176. fun () ->
  177. Input = <<"{\"1\":2 \"key\":\"value\"}">>,
  178. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
  179. end},
  180. {"object: missing field key",
  181. fun () ->
  182. Input = <<"{:2, \"key\":\"value\"}">>,
  183. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
  184. end},
  185. {"object: non string key",
  186. fun () ->
  187. Input = <<"{1:2, \"key\":\"value\"}">>,
  188. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
  189. end},
  190. {"object: missing field value",
  191. fun () ->
  192. Input = <<"{\"1\", \"key\":\"value\"}">>,
  193. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
  194. end},
  195. {"object: missing closing brace",
  196. fun () ->
  197. Input = <<"{\"1\":2 \"key\":\"value\"">>,
  198. ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
  199. end},
  200. %% Others
  201. {"compound data",
  202. fun () ->
  203. Input = <<" [true, {\"1\" : 2, \"array\":[[[[1]]], {\"ab\":\"cd\"}, false]}, null] ">>,
  204. Expected = [true, {[{<<"array">>, [[[[1]]], {[{<<"ab">>, <<"cd">>}]}, false]}, {<<"1">>, 2}]}, null],
  205. ?assertEqual({ok, Expected, <<" ">>}, jsone_decode:decode(Input))
  206. end}
  207. ].