浏览代码

json库从jsx换成jiffy

erlArango_v1
SisMaker 5 年前
父节点
当前提交
da72a4a509
共有 13 个文件被更改,包括 5 次插入5251 次删除
  1. +3
    -0
      rebar.config
  2. +0
    -15
      rebar.config.script
  3. +2
    -2
      src/arangoApi/agDbMgr.erl
  4. +0
    -527
      src/jsx-2.10.0/jsx.erl
  5. +0
    -346
      src/jsx-2.10.0/jsx_config.erl
  6. +0
    -18
      src/jsx-2.10.0/jsx_config.hrl
  7. +0
    -99
      src/jsx-2.10.0/jsx_consult.erl
  8. +0
    -1916
      src/jsx-2.10.0/jsx_decoder.erl
  9. +0
    -127
      src/jsx-2.10.0/jsx_encoder.erl
  10. +0
    -1214
      src/jsx-2.10.0/jsx_parser.erl
  11. +0
    -409
      src/jsx-2.10.0/jsx_to_json.erl
  12. +0
    -459
      src/jsx-2.10.0/jsx_to_term.erl
  13. +0
    -119
      src/jsx-2.10.0/jsx_verify.erl

+ 3
- 0
rebar.config 查看文件

@ -1,3 +1,6 @@
{erl_opts, [{i, "include"}]}. {erl_opts, [{i, "include"}]}.
{edoc_opts, [{preprocess, true}]}. {edoc_opts, [{preprocess, true}]}.
{deps,[
{jiffy, {git, "https://github.com/davisp/jiffy.git", {tag, "1.0.4"}}}
]}.

+ 0
- 15
rebar.config.script 查看文件

@ -1,15 +0,0 @@
Def0 = case erlang:is_builtin(erlang, binary_to_integer, 1) andalso
erlang:is_builtin(erlang, binary_to_float, 1) of
true -> [];
false -> [{d, no_binary_to_whatever}]
end,
Def1 = case erlang:is_builtin(erlang, is_map, 1) of
true -> [{d, maps_support}|Def0];
false -> Def0
end,
Defs = case os:getenv("JSX_FORCE_MAPS") of
false -> Def1;
_ -> [{d, maps_always}|Def1]
end,
lists:keystore(erl_opts, 1, CONFIG,
{erl_opts, proplists:get_value(erl_opts, CONFIG, []) ++ Defs}).

+ 2
- 2
src/arangoApi/agDbMgr.erl 查看文件

@ -26,12 +26,12 @@ userVisitDbs(PoolName) ->
% extraJSON对象Extra中包含的数据 ArangoDB不会进一步解释 % extraJSON对象Extra中包含的数据 ArangoDB不会进一步解释
newDb(PoolName, Name) -> newDb(PoolName, Name) ->
NameStr = jsx:encode(Name),
NameStr = jiffy:encode(Name),
agHttpCli:callAgency(PoolName, ?Post, <<"/_api/database">>, [], [<<"{\"name\":">>, NameStr, <<"}">>], infinity). agHttpCli:callAgency(PoolName, ?Post, <<"/_api/database">>, [], [<<"{\"name\":">>, NameStr, <<"}">>], infinity).
newDb(PoolName, Name, Users) -> newDb(PoolName, Name, Users) ->
BodyStr = jsx:encode(#{<<"name">> => Name, <<"users">> => Users}),
BodyStr = jiffy:encode(#{<<"name">> => Name, <<"users">> => Users}),
agHttpCli:callAgency(PoolName, ?Post, <<"/_api/database">>, [], BodyStr, infinity). agHttpCli:callAgency(PoolName, ?Post, <<"/_api/database">>, [], BodyStr, infinity).
%% %%

+ 0
- 527
src/jsx-2.10.0/jsx.erl 查看文件

@ -1,527 +0,0 @@
%% The MIT License
%% Copyright (c) 2010-2013 alisdair sullivan <alisdairsullivan@yahoo.ca>
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(jsx).
-export([encode/1, encode/2, decode/1, decode/2]).
-export([is_json/1, is_json/2, is_term/1, is_term/2]).
-export([format/1, format/2, minify/1, prettify/1]).
-export([consult/1, consult/2]).
-export([encoder/3, decoder/3, parser/3]).
-export([resume/3]).
-export([maps_support/0]).
-export_type([json_term/0, json_text/0, token/0]).
-export_type([encoder/0, decoder/0, parser/0, internal_state/0]).
-export_type([config/0]).
-ifdef(TEST).
%% data and helper functions for tests
-export([test_cases/0, special_test_cases/0]).
-export([init/1, handle_event/2]).
-endif.
-ifndef(maps_support).
-type json_term() :: [{binary() | atom(), json_term()}] | [{},...]
| [json_term()] | []
| true | false | null
| integer() | float()
| binary() | atom()
| calendar:datetime().
-endif.
-ifdef(maps_support).
-type json_term() :: [{binary() | atom(), json_term()}] | [{},...]
| [json_term()] | []
| map()
| true | false | null
| integer() | float()
| binary() | atom()
| calendar:datetime().
-endif.
-type json_text() :: binary().
-type config() :: jsx_config:config().
-spec encode(Source::json_term()) -> json_text().
encode(Source) -> encode(Source, []).
-spec encode(Source::json_term(), Config::jsx_to_json:config()) -> json_text() | {incomplete, encoder()}.
encode(Source, Config) -> jsx_to_json:to_json(Source, Config).
-spec decode(Source::json_text()) -> json_term().
decode(Source) -> decode(Source, []).
-spec decode(Source::json_text(), Config::jsx_to_term:config()) -> json_term() | {incomplete, decoder()}.
decode(Source, Config) -> jsx_to_term:to_term(Source, Config).
-spec format(Source::json_text()) -> json_text().
format(Source) -> format(Source, []).
-spec format(Source::json_text(), Config::jsx_to_json:config()) -> json_text() | {incomplete, decoder()}.
format(Source, Config) -> jsx_to_json:format(Source, Config).
-spec minify(Source::json_text()) -> json_text().
minify(Source) -> format(Source, []).
-spec prettify(Source::json_text()) -> json_text().
prettify(Source) -> format(Source, [space, {indent, 2}]).
-spec is_json(Source::any()) -> boolean().
is_json(Source) -> is_json(Source, []).
-spec is_json(Source::any(), Config::jsx_verify:config()) -> boolean() | {incomplete, decoder()}.
is_json(Source, Config) -> jsx_verify:is_json(Source, Config).
-spec is_term(Source::any()) -> boolean().
is_term(Source) -> is_term(Source, []).
-spec is_term(Source::any(), Config::jsx_verify:config()) -> boolean() | {incomplete, encoder()}.
is_term(Source, Config) -> jsx_verify:is_term(Source, Config).
-spec consult(File::file:name_all()) -> list(json_term()).
consult(File) -> consult(File, []).
-spec consult(File::file:name_all(), Config::jsx_to_term:config()) -> list(json_term()).
consult(File, Config) -> jsx_consult:consult(File, Config).
-type decoder() :: fun((json_text() | end_stream | end_json) -> any()).
-spec decoder(Handler::module(), State::any(), Config::list()) -> decoder().
decoder(Handler, State, Config) -> jsx_decoder:decoder(Handler, State, Config).
-type encoder() :: fun((json_term() | end_stream | end_json) -> any()).
-spec encoder(Handler::module(), State::any(), Config::list()) -> encoder().
encoder(Handler, State, Config) -> jsx_encoder:encoder(Handler, State, Config).
-type token() :: [token()]
| start_object
| end_object
| start_array
| end_array
| {key, binary()}
| {string, binary()}
| binary()
| {number, integer() | float()}
| {integer, integer()}
| {float, float()}
| integer()
| float()
| {literal, true}
| {literal, false}
| {literal, null}
| true
| false
| null
| end_json.
-type parser() :: fun((token() | end_stream) -> any()).
-spec parser(Handler::module(), State::any(), Config::list()) -> parser().
parser(Handler, State, Config) -> jsx_parser:parser(Handler, State, Config).
-opaque internal_state() :: tuple().
-spec resume(Term::json_text() | token(), InternalState::internal_state(), Config::list()) -> any().
resume(Term, {decoder, State, Handler, Acc, Stack}, Config) ->
jsx_decoder:resume(Term, State, Handler, Acc, Stack, jsx_config:parse_config(Config));
resume(Term, {parser, State, Handler, Stack}, Config) ->
jsx_parser:resume(Term, State, Handler, Stack, jsx_config:parse_config(Config)).
-spec maps_support() -> boolean().
-ifndef(maps_support).
maps_support() -> false.
-endif.
-ifdef(maps_support).
maps_support() -> true.
-endif.
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
%% test handler
init([]) -> [].
handle_event(end_json, State) -> lists:reverse([end_json] ++ State);
handle_event(Event, State) -> [Event] ++ State.
test_cases() ->
empty_array()
++ nested_array()
++ empty_object()
++ nested_object()
++ strings()
++ literals()
++ integers()
++ floats()
++ compound_object().
%% segregate these so we can skip them in `jsx_to_term`
special_test_cases() -> special_objects() ++ special_array().
empty_array() -> [{"[]", <<"[]">>, [], [start_array, end_array]}].
nested_array() ->
[{
"[[[]]]",
<<"[[[]]]">>,
[[[]]],
[start_array, start_array, start_array, end_array, end_array, end_array]
}].
empty_object() -> [{"{}", <<"{}">>, [{}], [start_object, end_object]}].
nested_object() ->
[{
"{\"key\":{\"key\":{}}}",
<<"{\"key\":{\"key\":{}}}">>,
[{<<"key">>, [{<<"key">>, [{}]}]}],
[
start_object,
{key, <<"key">>},
start_object,
{key, <<"key">>},
start_object,
end_object,
end_object,
end_object
]
}].
naked_strings() ->
Raw = [
"",
"hello world"
],
[
{
String,
<<"\"", (list_to_binary(String))/binary, "\"">>,
list_to_binary(String),
[{string, list_to_binary(String)}]
}
|| String <- Raw
].
strings() ->
naked_strings()
++ [ wrap_with_array(Test) || Test <- naked_strings() ]
++ [ wrap_with_object(Test) || Test <- naked_strings() ].
naked_integers() ->
Raw = [
1, 2, 3,
127, 128, 129,
255, 256, 257,
65534, 65535, 65536,
18446744073709551616,
18446744073709551617
],
[
{
integer_to_list(X),
list_to_binary(integer_to_list(X)),
X,
[{integer, X}]
}
|| X <- Raw ++ [ -1 * Y || Y <- Raw ] ++ [0]
].
integers() ->
naked_integers()
++ [ wrap_with_array(Test) || Test <- naked_integers() ]
++ [ wrap_with_object(Test) || Test <- naked_integers() ].
naked_floats() ->
Raw = [
0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9,
1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9,
1234567890.0987654321,
0.0e0,
1234567890.0987654321e16,
0.1e0, 0.1e1, 0.1e2, 0.1e4, 0.1e8, 0.1e16, 0.1e308,
1.0e0, 1.0e1, 1.0e2, 1.0e4, 1.0e8, 1.0e16, 1.0e308,
2.2250738585072014e-308, %% min normalized float
1.7976931348623157e308, %% max normalized float
5.0e-324, %% min denormalized float
2.225073858507201e-308 %% max denormalized float
],
[
{
sane_float_to_list(X),
list_to_binary(sane_float_to_list(X)),
X,
[{float, X}]
}
|| X <- Raw ++ [ -1 * Y || Y <- Raw ]
].
floats() ->
naked_floats()
++ [ wrap_with_array(Test) || Test <- naked_floats() ]
++ [ wrap_with_object(Test) || Test <- naked_floats() ].
naked_literals() ->
[
{
atom_to_list(Literal),
atom_to_binary(Literal, unicode),
Literal,
[{literal, Literal}]
}
|| Literal <- [true, false, null]
].
literals() ->
naked_literals()
++ [ wrap_with_array(Test) || Test <- naked_literals() ]
++ [ wrap_with_object(Test) || Test <- naked_literals() ].
compound_object() ->
[{
"[{\"alpha\":[1,2,3],\"beta\":{\"alpha\":[1.0,2.0,3.0],\"beta\":[true,false]}},[{}]]",
<<"[{\"alpha\":[1,2,3],\"beta\":{\"alpha\":[1.0,2.0,3.0],\"beta\":[true,false]}},[{}]]">>,
[[{<<"alpha">>, [1, 2, 3]}, {<<"beta">>, [{<<"alpha">>, [1.0, 2.0, 3.0]}, {<<"beta">>, [true, false]}]}], [[{}]]],
[
start_array,
start_object,
{key, <<"alpha">>},
start_array,
{integer, 1},
{integer, 2},
{integer, 3},
end_array,
{key, <<"beta">>},
start_object,
{key, <<"alpha">>},
start_array,
{float, 1.0},
{float, 2.0},
{float, 3.0},
end_array,
{key, <<"beta">>},
start_array,
{literal, true},
{literal, false},
end_array,
end_object,
end_object,
start_array,
start_object,
end_object,
end_array,
end_array
]
}].
special_objects() ->
[
{
"[{key, atom}]",
<<"{\"key\":\"atom\"}">>,
[{key, atom}],
[start_object, {key, <<"key">>}, {string, <<"atom">>}, end_object]
},
{
"[{1, true}]",
<<"{\"1\":true}">>,
[{1, true}],
[start_object, {key, <<"1">>}, {literal, true}, end_object]
}
].
special_array() ->
[
{
"[foo, bar]",
<<"[\"foo\",\"bar\"]">>,
[foo, bar],
[start_array, {string, <<"foo">>}, {string, <<"bar">>}, end_array]
}
].
wrap_with_array({Title, JSON, Term, Events}) ->
{
"[" ++ Title ++ "]",
<<"[", JSON/binary, "]">>,
[Term],
[start_array] ++ Events ++ [end_array]
}.
wrap_with_object({Title, JSON, Term, Events}) ->
{
"{\"key\":" ++ Title ++ "}",
<<"{\"key\":", JSON/binary, "}">>,
[{<<"key">>, Term}],
[start_object, {key, <<"key">>}] ++ Events ++ [end_object]
}.
sane_float_to_list(X) ->
[Output] = io_lib:format("~p", [X]),
Output.
incremental_decode(JSON) ->
Final = lists:foldl(
fun(Byte, Decoder) -> {incomplete, F} = Decoder(Byte), F end,
decoder(jsx, [], [stream]),
json_to_bytes(JSON)
),
Final(end_stream).
incremental_parse(Events) ->
Final = lists:foldl(
fun(Event, Parser) -> {incomplete, F} = Parser(Event), F end,
parser(?MODULE, [], [stream]),
lists:map(fun(X) -> [X] end, Events)
),
Final(end_stream).
%% used to convert a json text into a list of codepoints to be incrementally
%% parsed
json_to_bytes(JSON) -> json_to_bytes(JSON, []).
json_to_bytes(<<>>, Acc) -> [<<>>] ++ lists:reverse(Acc);
json_to_bytes(<<X, Rest/binary>>, Acc) -> json_to_bytes(Rest, [<<X>>] ++ Acc).
%% actual tests!
decode_test_() ->
Data = test_cases(),
[{Title, ?_assertEqual(Events ++ [end_json], (decoder(?MODULE, [], []))(JSON))}
|| {Title, JSON, _, Events} <- Data
] ++
[{Title ++ " (incremental)", ?_assertEqual(Events ++ [end_json], incremental_decode(JSON))}
|| {Title, JSON, _, Events} <- Data
].
parse_test_() ->
Data = test_cases(),
[{Title, ?_assertEqual(Events ++ [end_json], (parser(?MODULE, [], []))(Events ++ [end_json]))}
|| {Title, _, _, Events} <- Data
] ++
[{Title ++ " (incremental)", ?_assertEqual(Events ++ [end_json], incremental_parse(Events))}
|| {Title, _, _, Events} <- Data
].
encode_test_() ->
Data = test_cases(),
[
{
Title, ?_assertEqual(
Events ++ [end_json],
(jsx:encoder(jsx, [], []))(Term)
)
} || {Title, _, Term, Events} <- Data
].
end_stream_test_() ->
Tokens = [start_object, end_object, end_json],
[
{"encoder end_stream", ?_assertEqual(
Tokens,
begin
{incomplete, F} = (jsx:parser(jsx, [], [stream]))([start_object, end_object]),
F(end_stream)
end
)},
{"encoder end_json", ?_assertEqual(
Tokens,
begin
{incomplete, F} = (jsx:parser(jsx, [], [stream]))([start_object, end_object]),
F(end_json)
end
)},
{"decoder end_stream", ?_assertEqual(
Tokens,
begin {incomplete, F} = (jsx:decoder(jsx, [], [stream]))(<<"{}">>), F(end_stream) end
)},
{"decoder end_json", ?_assertEqual(
Tokens,
begin {incomplete, F} = (jsx:decoder(jsx, [], [stream]))(<<"{}">>), F(end_json) end
)}
].
-endif.

+ 0
- 346
src/jsx-2.10.0/jsx_config.erl 查看文件

@ -1,346 +0,0 @@
%% The MIT License
%% Copyright (c) 2010-2013 alisdair sullivan <alisdairsullivan@yahoo.ca>
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(jsx_config).
-export([parse_config/1]).
-export([config_to_list/1]).
-export([extract_config/1, valid_flags/0]).
-ifdef(TEST).
-export([fake_error_handler/3]).
-endif.
-include("jsx_config.hrl").
-type handler_type(Handler) ::
fun((jsx:json_text() | end_stream |
jsx:json_term(),
{decoder, any(), module(), null | list(), list()} |
{parser, any(), module(), list()} |
{encoder, any(), module()},
list({pre_encode, fun((any()) -> any())} |
{error_handler, Handler} |
{incomplete_handler, Handler} |
atom())) -> any()).
-type handler() :: handler_type(handler()).
-export_type([handler/0]).
-type config() :: #config{}.
-export_type([config/0]).
%% parsing of jsx config
-spec parse_config(Config::proplists:proplist()) -> config().
parse_config(Config) -> parse_config(Config, #config{}).
parse_config([], Config) -> Config;
parse_config([escaped_forward_slashes|Rest], Config) ->
parse_config(Rest, Config#config{escaped_forward_slashes=true});
parse_config([escaped_strings|Rest], Config) ->
parse_config(Rest, Config#config{escaped_strings=true});
parse_config([unescaped_jsonp|Rest], Config) ->
parse_config(Rest, Config#config{unescaped_jsonp=true});
parse_config([dirty_strings|Rest], Config) ->
parse_config(Rest, Config#config{dirty_strings=true});
parse_config([multi_term|Rest], Config) ->
parse_config(Rest, Config#config{multi_term=true});
parse_config([return_tail|Rest], Config) ->
parse_config(Rest, Config#config{return_tail=true});
%% retained for backwards compat, now does nothing however
parse_config([repeat_keys|Rest], Config) ->
parse_config(Rest, Config);
parse_config([uescape|Rest], Config) ->
parse_config(Rest, Config#config{uescape=true});
parse_config([strict|Rest], Config) ->
parse_config(Rest, Config#config{
strict_comments=true,
strict_commas=true,
strict_utf8=true,
strict_single_quotes=true,
strict_escapes=true,
strict_control_codes=true
});
parse_config([{strict, Strict}|Rest], Config) ->
parse_strict(Strict, Rest, Config);
parse_config([stream|Rest], Config) ->
parse_config(Rest, Config#config{stream=true});
parse_config([{error_handler, ErrorHandler}|Rest] = Options, Config) when is_function(ErrorHandler, 3) ->
case Config#config.error_handler of
false -> parse_config(Rest, Config#config{error_handler=ErrorHandler})
; _ -> erlang:error(badarg, [Options, Config])
end;
parse_config([{incomplete_handler, IncompleteHandler}|Rest] = Options, Config) when is_function(IncompleteHandler, 3) ->
case Config#config.incomplete_handler of
false -> parse_config(Rest, Config#config{incomplete_handler=IncompleteHandler})
; _ -> erlang:error(badarg, [Options, Config])
end;
parse_config(_Options, _Config) -> erlang:error(badarg).
parse_strict([], Rest, Config) -> parse_config(Rest, Config);
parse_strict([comments|Strict], Rest, Config) ->
parse_strict(Strict, Rest, Config#config{strict_comments=true});
parse_strict([trailing_commas|Strict], Rest, Config) ->
parse_strict(Strict, Rest, Config#config{strict_commas=true});
parse_strict([utf8|Strict], Rest, Config) ->
parse_strict(Strict, Rest, Config#config{strict_utf8=true});
parse_strict([single_quotes|Strict], Rest, Config) ->
parse_strict(Strict, Rest, Config#config{strict_single_quotes=true});
parse_strict([escapes|Strict], Rest, Config) ->
parse_strict(Strict, Rest, Config#config{strict_escapes=true});
parse_strict([control_codes|Strict], Rest, Config) ->
parse_strict(Strict, Rest, Config#config{strict_control_codes=true});
parse_strict(_Strict, _Rest, _Config) ->
erlang:error(badarg).
-spec config_to_list(Config::config()) -> proplists:proplist().
config_to_list(Config) ->
reduce_config(lists:map(
fun ({error_handler, F}) -> {error_handler, F};
({incomplete_handler, F}) -> {incomplete_handler, F};
({Key, true}) -> Key
end,
lists:filter(
fun({_, false}) -> false; (_) -> true end,
lists:zip(record_info(fields, config), tl(tuple_to_list(Config)))
)
)).
reduce_config(Input) -> reduce_config(Input, [], []).
reduce_config([], Output, Strict) ->
case length(Strict) of
0 -> lists:reverse(Output);
5 -> lists:reverse(Output) ++ [strict];
_ -> lists:reverse(Output) ++ [{strict, lists:reverse(Strict)}]
end;
reduce_config([strict_comments|Input], Output, Strict) ->
reduce_config(Input, Output, [comments] ++ Strict);
reduce_config([strict_utf8|Input], Output, Strict) ->
reduce_config(Input, Output, [utf8] ++ Strict);
reduce_config([strict_single_quotes|Input], Output, Strict) ->
reduce_config(Input, Output, [single_quotes] ++ Strict);
reduce_config([strict_escapes|Input], Output, Strict) ->
reduce_config(Input, Output, [escapes] ++ Strict);
reduce_config([strict_control_codes|Input], Output, Strict) ->
reduce_config(Input, Output, [control_codes] ++ Strict);
reduce_config([Else|Input], Output, Strict) ->
reduce_config(Input, [Else] ++ Output, Strict).
-spec valid_flags() -> [atom()].
valid_flags() ->
[
escaped_forward_slashes,
escaped_strings,
unescaped_jsonp,
dirty_strings,
multi_term,
return_tail,
repeat_keys,
strict,
stream,
uescape,
error_handler,
incomplete_handler
].
-spec extract_config(Config::proplists:proplist()) -> proplists:proplist().
extract_config(Config) ->
extract_parser_config(Config, []).
extract_parser_config([], Acc) -> Acc;
extract_parser_config([{K,V}|Rest], Acc) ->
case lists:member(K, valid_flags()) of
true -> extract_parser_config(Rest, [{K,V}] ++ Acc)
; false -> extract_parser_config(Rest, Acc)
end;
extract_parser_config([K|Rest], Acc) ->
case lists:member(K, valid_flags()) of
true -> extract_parser_config(Rest, [K] ++ Acc)
; false -> extract_parser_config(Rest, Acc)
end.
%% eunit tests
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
config_test_() ->
[
{"all flags",
?_assertEqual(
#config{escaped_forward_slashes = true,
escaped_strings = true,
unescaped_jsonp = true,
dirty_strings = true,
multi_term = true,
return_tail = true,
strict_comments = true,
strict_commas = true,
strict_utf8 = true,
strict_single_quotes = true,
strict_escapes = true,
strict_control_codes = true,
stream = true,
uescape = true
},
parse_config([dirty_strings,
escaped_forward_slashes,
escaped_strings,
unescaped_jsonp,
multi_term,
return_tail,
repeat_keys,
strict,
stream,
uescape
])
)
},
{"strict flag",
?_assertEqual(
#config{strict_comments = true,
strict_commas = true,
strict_utf8 = true,
strict_single_quotes = true,
strict_escapes = true,
strict_control_codes = true
},
parse_config([strict])
)
},
{"strict selective",
?_assertEqual(
#config{strict_comments = true},
parse_config([{strict, [comments]}])
)
},
{"strict expanded",
?_assertEqual(
#config{strict_comments = true,
strict_utf8 = true,
strict_single_quotes = true,
strict_escapes = true
},
parse_config([{strict, [comments, utf8, single_quotes, escapes]}])
)
},
{"error_handler flag", ?_assertEqual(
#config{error_handler=fun ?MODULE:fake_error_handler/3},
parse_config([{error_handler, fun ?MODULE:fake_error_handler/3}])
)},
{"two error_handlers defined", ?_assertError(
badarg,
parse_config([
{error_handler, fun(_, _, _) -> true end},
{error_handler, fun(_, _, _) -> false end}
])
)},
{"incomplete_handler flag", ?_assertEqual(
#config{incomplete_handler=fun ?MODULE:fake_error_handler/3},
parse_config([{incomplete_handler, fun ?MODULE:fake_error_handler/3}])
)},
{"two incomplete_handlers defined", ?_assertError(
badarg,
parse_config([
{incomplete_handler, fun(_, _, _) -> true end},
{incomplete_handler, fun(_, _, _) -> false end}
])
)},
{"bad option flag", ?_assertError(badarg, parse_config([this_flag_does_not_exist]))}
].
config_to_list_test_() ->
[
{"empty config", ?_assertEqual(
[],
config_to_list(#config{})
)},
{"all flags", ?_assertEqual(
[dirty_strings,
escaped_forward_slashes,
escaped_strings,
multi_term,
stream,
uescape,
unescaped_jsonp,
strict
],
config_to_list(
#config{escaped_forward_slashes = true,
escaped_strings = true,
unescaped_jsonp = true,
dirty_strings = true,
multi_term = true,
strict_comments = true,
strict_utf8 = true,
strict_single_quotes = true,
strict_escapes = true,
strict_control_codes = true,
stream = true,
uescape = true
}
)
)},
{"single strict", ?_assertEqual(
[{strict, [comments]}],
config_to_list(#config{strict_comments = true})
)},
{"multiple strict", ?_assertEqual(
[{strict, [utf8, single_quotes, escapes]}],
config_to_list(#config{strict_utf8 = true, strict_single_quotes = true, strict_escapes = true})
)},
{"all strict", ?_assertEqual(
[strict],
config_to_list(#config{strict_comments = true,
strict_utf8 = true,
strict_single_quotes = true,
strict_escapes = true,
strict_control_codes = true})
)},
{"error handler", ?_assertEqual(
[{error_handler, fun ?MODULE:fake_error_handler/3}],
config_to_list(#config{error_handler=fun ?MODULE:fake_error_handler/3})
)},
{"incomplete handler", ?_assertEqual(
[{incomplete_handler, fun ?MODULE:fake_error_handler/3}],
config_to_list(#config{incomplete_handler=fun ?MODULE:fake_error_handler/3})
)}
].
fake_error_handler(_, _, _) -> ok.
-endif.

+ 0
- 18
src/jsx-2.10.0/jsx_config.hrl 查看文件

@ -1,18 +0,0 @@
-record(config, {
dirty_strings = false :: boolean(),
escaped_forward_slashes = false :: boolean(),
escaped_strings = false :: boolean(),
multi_term = false :: boolean(),
strict_comments = false :: boolean(),
strict_commas = false :: boolean(),
strict_utf8 = false :: boolean(),
strict_single_quotes = false :: boolean(),
strict_escapes = false :: boolean(),
strict_control_codes = false :: boolean(),
stream = false :: boolean(),
return_tail = false :: boolean(),
uescape = false :: boolean(),
unescaped_jsonp = false :: boolean(),
error_handler = false :: false | jsx_config:handler(),
incomplete_handler = false :: false | jsx_config:handler()
}).

+ 0
- 99
src/jsx-2.10.0/jsx_consult.erl 查看文件

@ -1,99 +0,0 @@
%% The MIT License
%% Copyright (c) 2010-2015 Alisdair Sullivan <alisdairsullivan@yahoo.ca>
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(jsx_consult).
-export([consult/2]).
-export([init/1, reset/1, handle_event/2]).
-record(config, {
labels = binary,
return_maps = false
}).
-type config() :: list().
-export_type([config/0]).
-ifndef(maps_support).
-type json_value() :: list(json_value())
| list({binary() | atom(), json_value()})
| true
| false
| null
| integer()
| float()
| binary().
-endif.
-ifdef(maps_support).
-type json_value() :: list(json_value())
| map()
| true
| false
| null
| integer()
| float()
| binary().
-endif.
-ifdef(maps_always).
opts(Opts) -> [return_maps, multi_term] ++ Opts.
-endif.
-ifndef(maps_always).
opts(Opts) -> [multi_term] ++ Opts.
-endif.
-spec consult(File::file:name_all(), Config::config()) -> [json_value()].
consult(File, Config) when is_list(Config) ->
case file:read_file(File) of
{ok, Bin} ->
{Final, _, _} = (jsx:decoder(
?MODULE,
opts(Config),
jsx_config:extract_config(opts(Config))
))(Bin),
lists:reverse(Final);
{error, _} -> erlang:error(badarg)
end.
-type state() :: {[], proplists:proplist(), {list(), #config{}}}.
-spec init(Config::proplists:proplist()) -> state().
init(Config) -> {[], Config, jsx_to_term:start_term(Config)}.
-spec reset(State::state()) -> state().
reset({Acc, Config, _}) -> {Acc, Config, jsx_to_term:start_term(Config)}.
-spec handle_event(Event::any(), State::state()) -> state().
handle_event(end_json, {Acc, Config, State}) ->
{[jsx_to_term:get_value(State)] ++ Acc, Config, State};
handle_event(Event, {Acc, Config, State}) ->
{Acc, Config, jsx_to_term:handle_event(Event, State)}.

+ 0
- 1916
src/jsx-2.10.0/jsx_decoder.erl
文件差异内容过多而无法显示
查看文件


+ 0
- 127
src/jsx-2.10.0/jsx_encoder.erl 查看文件

@ -1,127 +0,0 @@
%% The MIT License
%% Copyright (c) 2010-2013 Alisdair Sullivan <alisdairsullivan@yahoo.ca>
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(jsx_encoder).
-export([encoder/3, encode/1, encode/2]).
-spec encoder(Handler::module(), State::any(), Config::list()) -> jsx:encoder().
encoder(Handler, State, Config) ->
Parser = jsx:parser(Handler, State, Config),
fun(Term) -> Parser(encode(Term) ++ [end_json]) end.
-spec encode(Term::any()) -> any().
encode(Term) -> encode(Term, ?MODULE).
-spec encode(Term::any(), EntryPoint::module()) -> any().
-ifndef(maps_support).
encode(Term, EntryPoint) -> encode_(Term, EntryPoint).
-endif.
-ifdef(maps_support).
encode(Map, _EntryPoint) when is_map(Map), map_size(Map) < 1 ->
[start_object, end_object];
encode(Term, EntryPoint) when is_map(Term) ->
[start_object] ++ unpack(Term, EntryPoint);
encode(Term, EntryPoint) -> encode_(Term, EntryPoint).
-endif.
encode_([], _EntryPoint) -> [start_array, end_array];
encode_([{}], _EntryPoint) -> [start_object, end_object];
%% datetime special case
encode_([{{_,_,_},{_,_,_}} = DateTime|Rest], EntryPoint) ->
[start_array] ++ [DateTime] ++ unhitch(Rest, EntryPoint);
encode_([{_, _}|_] = Term, EntryPoint) ->
[start_object] ++ unzip(Term, EntryPoint);
encode_(Term, EntryPoint) when is_list(Term) ->
[start_array] ++ unhitch(Term, EntryPoint);
encode_(Else, _EntryPoint) -> [Else].
unzip([{K, V}|Rest], EntryPoint) when is_integer(K); is_binary(K); is_atom(K) ->
[K] ++ EntryPoint:encode(V, EntryPoint) ++ unzip(Rest, EntryPoint);
unzip([], _) -> [end_object];
unzip(_, _) -> erlang:error(badarg).
unhitch([V|Rest], EntryPoint) ->
EntryPoint:encode(V, EntryPoint) ++ unhitch(Rest, EntryPoint);
unhitch([], _) -> [end_array].
-ifdef(maps_support).
unpack(Map, EntryPoint) -> unpack(Map, maps:keys(Map), EntryPoint).
unpack(Map, [K|Rest], EntryPoint) when is_integer(K); is_binary(K); is_atom(K) ->
[K] ++ EntryPoint:encode(maps:get(K, Map), EntryPoint) ++ unpack(Map, Rest, EntryPoint);
unpack(_, [], _) -> [end_object].
-endif.
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
parser(Term, Opts) -> (jsx:parser(jsx, [], Opts))(Term).
error_test_() ->
[
{"value error", ?_assertError(badarg, parser(self(), []))},
{"string error", ?_assertError(badarg, parser(<<239, 191, 191>>, [strict]))}
].
custom_error_handler_test_() ->
Error = fun(Term, {_, State, _, _}, _) -> {State, Term} end,
[
{"value error", ?_assertEqual(
{value, [self()]},
parser(self(), [{error_handler, Error}])
)},
{"string error", ?_assertEqual(
{value, [{string, <<237, 160, 128>>}]},
parser(<<237, 160, 128>>, [{error_handler, Error}, strict])
)}
].
improper_lists_test_() ->
[
{"improper proplist", ?_assertError(
badarg,
encode([{<<"key">>, <<"value">>}, false])
)},
{"improper list", ?_assertError(
badarg,
encode([{literal, true}, false, null])
)}
].
-endif.

+ 0
- 1214
src/jsx-2.10.0/jsx_parser.erl
文件差异内容过多而无法显示
查看文件


+ 0
- 409
src/jsx-2.10.0/jsx_to_json.erl 查看文件

@ -1,409 +0,0 @@
%% The MIT License
%% Copyright (c) 2010-2013 alisdair sullivan <alisdairsullivan@yahoo.ca>
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(jsx_to_json).
-export([to_json/2, format/2]).
-export([init/1, handle_event/2]).
-export([start_json/0, start_json/1]).
-export([start_object/1, start_array/1, finish/1, insert/2, get_key/1, get_value/1]).
-record(config, {
space = 0,
indent = 0,
depth = 0,
newline = <<$\n>>
}).
-type config() :: list().
-export_type([config/0]).
-spec to_json(Source::any(), Config::config()) -> binary().
to_json(Source, Config) when is_list(Config) ->
(jsx:encoder(?MODULE, Config, jsx_config:extract_config(Config ++ [escaped_strings])))(Source).
-spec format(Source::binary(), Config::config()) -> binary().
format(Source, Config) when is_binary(Source) andalso is_list(Config) ->
(jsx:decoder(?MODULE, Config, jsx_config:extract_config(Config ++ [escaped_strings])))(Source);
format(_, _) -> erlang:error(badarg).
parse_config(Config) -> parse_config(Config, #config{}).
parse_config([{space, Val}|Rest], Config) when is_integer(Val), Val > 0 ->
parse_config(Rest, Config#config{space = Val});
parse_config([space|Rest], Config) ->
parse_config(Rest, Config#config{space = 1});
parse_config([{indent, Val}|Rest], Config) when is_integer(Val), Val > 0 ->
parse_config(Rest, Config#config{indent = Val});
parse_config([indent|Rest], Config) ->
parse_config(Rest, Config#config{indent = 1});
parse_config([{newline, Val}|Rest], Config) when is_binary(Val) ->
parse_config(Rest, Config#config{newline = Val});
parse_config([{K, _}|Rest] = Options, Config) ->
case lists:member(K, jsx_config:valid_flags()) of
true -> parse_config(Rest, Config)
; false -> erlang:error(badarg, [Options, Config])
end;
parse_config([K|Rest] = Options, Config) ->
case lists:member(K, jsx_config:valid_flags()) of
true -> parse_config(Rest, Config)
; false -> erlang:error(badarg, [Options, Config])
end;
parse_config([], Config) ->
Config.
-define(start_object, <<"{">>).
-define(start_array, <<"[">>).
-define(end_object, <<"}">>).
-define(end_array, <<"]">>).
-define(colon, <<":">>).
-define(comma, <<",">>).
-define(quote, <<"\"">>).
-define(space, <<" ">>).
-define(newline, <<"\n">>).
-type state() :: {unicode:charlist(), #config{}}.
-spec init(Config::proplists:proplist()) -> state().
init(Config) -> {[], parse_config(Config)}.
-spec handle_event(Event::any(), State::state()) -> state().
handle_event(end_json, State) -> get_value(State);
handle_event(start_object, State) -> start_object(State);
handle_event(end_object, State) -> finish(State);
handle_event(start_array, State) -> start_array(State);
handle_event(end_array, State) -> finish(State);
handle_event({Type, Event}, {_, Config} = State) -> insert(encode(Type, Event, Config), State).
encode(string, String, _Config) ->
[?quote, String, ?quote];
encode(key, Key, _Config) ->
[?quote, Key, ?quote];
encode(literal, Literal, _Config) ->
erlang:atom_to_list(Literal);
encode(integer, Integer, _Config) ->
erlang:integer_to_list(Integer);
encode(float, Float, _Config) ->
io_lib:format("~p", [Float]).
space(Config) ->
case Config#config.space of
0 -> <<>>
; X when X > 0 -> binary:copy(?space, X)
end.
indent(Config) ->
case Config#config.indent of
0 -> <<>>
; X when X > 0 -> <<(Config#config.newline)/binary, (binary:copy(?space, X * Config#config.depth))/binary>>
end.
indent_or_space(Config) ->
case Config#config.indent > 0 of
true -> indent(Config)
; false -> space(Config)
end.
%% internal state is a stack and a config object
%% `{Stack, Config}`
%% the stack is a list of in progress objects/arrays
%% `[Current, Parent, Grandparent,...OriginalAncestor]`
%% an object has the representation on the stack of
%% `{object, Object}`
%% of if there's a key with a yet to be matched value
%% `{object, Key, Object}`
%% an array looks like
%% `{array, Array}`
%% `Object` and `Array` are utf8 encoded binaries
start_json() -> {[], #config{}}.
start_json(Config) when is_list(Config) -> {[], parse_config(Config)}.
%% allocate a new object on top of the stack
start_object({Stack, Config = #config{depth = Depth}}) ->
{[{object, ?start_object}] ++ Stack, Config#config{depth = Depth + 1}}.
%% allocate a new array on top of the stack
start_array({Stack, Config = #config{depth = Depth}}) ->
{[{array, ?start_array}] ++ Stack, Config#config{depth = Depth + 1}}.
%% finish an object or array and insert it into the parent object if it exists
finish({Stack, Config = #config{depth = Depth}}) ->
NewConfig = Config#config{depth = Depth - 1},
finish_({Stack, NewConfig}).
finish_({[{object, <<"{">>}], Config}) -> {<<"{}">>, Config};
finish_({[{array, <<"[">>}], Config}) -> {<<"[]">>, Config};
finish_({[{object, <<"{">>}|Rest], Config}) -> insert(<<"{}">>, {Rest, Config});
finish_({[{array, <<"[">>}|Rest], Config}) -> insert(<<"[]">>, {Rest, Config});
finish_({[{object, Object}], Config}) ->
{[Object, indent(Config), ?end_object], Config};
finish_({[{object, Object}|Rest], Config}) ->
insert([Object, indent(Config), ?end_object], {Rest, Config});
finish_({[{array, Array}], Config}) ->
{[Array, indent(Config), ?end_array], Config};
finish_({[{array, Array}|Rest], Config}) ->
insert([Array, indent(Config), ?end_array], {Rest, Config});
finish_(_) -> erlang:error(badarg).
%% insert a value when there's no parent object or array
insert(Value, {[], Config}) ->
{Value, Config};
%% insert a key or value into an object or array, autodetects the 'right' thing
insert(Key, {[{object, Object}|Rest], Config}) ->
{[{object, Key, Object}] ++ Rest, Config};
insert(Value, {[{object, Key, ?start_object}|Rest], Config}) ->
{
[{object, [
?start_object,
indent(Config),
Key,
?colon,
space(Config),
Value
]}] ++ Rest,
Config
};
insert(Value, {[{object, Key, Object}|Rest], Config}) ->
{
[{object, [
Object,
?comma,
indent_or_space(Config),
Key,
?colon,
space(Config),
Value
]}] ++ Rest,
Config
};
insert(Value, {[{array, ?start_array}|Rest], Config}) ->
{[{array, [?start_array, indent(Config), Value]}] ++ Rest, Config};
insert(Value, {[{array, Array}|Rest], Config}) ->
{
[{array, [Array,
?comma,
indent_or_space(Config),
Value
]}] ++ Rest,
Config
};
insert(_, _) -> erlang:error(badarg).
get_key({[{object, Key, _}|_], _}) -> Key;
get_key(_) -> erlang:error(badarg).
get_value({Value, _Config}) ->
try unicode:characters_to_binary(Value)
catch error:_ -> erlang:error(badarg)
end;
get_value(_) -> erlang:error(badarg).
%% eunit tests
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
config_test_() ->
[
{"empty config", ?_assertEqual(#config{}, parse_config([]))},
{"unspecified indent/space", ?_assertEqual(
#config{space=1, indent=1},
parse_config([space, indent])
)},
{"specific indent", ?_assertEqual(
#config{indent=4},
parse_config([{indent, 4}])
)},
{"specific space", ?_assertEqual(
#config{space=2},
parse_config([{space, 2}])
)},
{"specific space and indent", ?_assertEqual(
#config{space=2, indent=2},
parse_config([{space, 2}, {indent, 2}])
)},
{"invalid opt flag", ?_assertError(badarg, parse_config([error]))},
{"invalid opt tuple", ?_assertError(badarg, parse_config([{error, true}]))}
].
space_test_() ->
[
{"no space", ?_assertEqual(<<>>, space(#config{space=0}))},
{"one space", ?_assertEqual(<<" ">>, space(#config{space=1}))},
{"four spaces", ?_assertEqual(<<" ">>, space(#config{space=4}))}
].
indent_test_() ->
[
{"no indent", ?_assertEqual(<<>>, indent(#config{indent=0, depth=1}))},
{"indent 1 depth 1", ?_assertEqual(
<<?newline/binary, <<" ">>/binary>>,
indent(#config{indent=1, depth=1})
)},
{"indent 1 depth 2", ?_assertEqual(
<<?newline/binary, <<" ">>/binary>>,
indent(#config{indent=1, depth=2})
)},
{"indent 4 depth 1", ?_assertEqual(
<<?newline/binary, <<" ">>/binary>>,
indent(#config{indent=4, depth=1})
)},
{"indent 4 depth 2", ?_assertEqual(
<<?newline/binary, <<" ">>/binary, <<" ">>/binary>>,
indent(#config{indent=4, depth=2})
)}
].
indent_or_space_test_() ->
[
{"no indent so space", ?_assertEqual(
<<" ">>,
indent_or_space(#config{space=1, indent=0, depth=1})
)},
{"indent so no space", ?_assertEqual(
<<?newline/binary, <<" ">>/binary>>,
indent_or_space(#config{space=1, indent=1, depth=1})
)}
].
encode_test_() ->
[
{"0.0", ?_assert(encode(float, 0.0, #config{}) =:= ["0.0"])},
{"1.0", ?_assert(encode(float, 1.0, #config{}) =:= ["1.0"])},
{"-1.0", ?_assert(encode(float, -1.0, #config{}) =:= ["-1.0"])},
{"3.1234567890987654321",
?_assert(
encode(float, 3.1234567890987654321, #config{}) =:= ["3.1234567890987655"])
},
{"1.0e23", ?_assert(encode(float, 1.0e23, #config{}) =:= ["1.0e23"])},
{"0.3", ?_assert(encode(float, 3.0/10.0, #config{}) =:= ["0.3"])},
{"0.0001", ?_assert(encode(float, 0.0001, #config{}) =:= ["0.0001"])},
{"0.00001", ?_assert(encode(float, 0.00001, #config{}) =:= ["1.0e-5"])},
{"0.00000001", ?_assert(encode(float, 0.00000001, #config{}) =:= ["1.0e-8"])},
{"1.0e-323", ?_assert(encode(float, 1.0e-323, #config{}) =:= ["1.0e-323"])},
{"1.0e308", ?_assert(encode(float, 1.0e308, #config{}) =:= ["1.0e308"])},
{"min normalized float",
?_assert(
encode(float, math:pow(2, -1022), #config{}) =:= ["2.2250738585072014e-308"]
)
},
{"max normalized float",
?_assert(
encode(float, (2 - math:pow(2, -52)) * math:pow(2, 1023), #config{})
=:= ["1.7976931348623157e308"]
)
},
{"min denormalized float",
?_assert(encode(float, math:pow(2, -1074), #config{}) =:= ["5.0e-324"])
},
{"max denormalized float",
?_assert(
encode(float, (1 - math:pow(2, -52)) * math:pow(2, -1022), #config{})
=:= ["2.225073858507201e-308"]
)
},
{"hello world", ?_assert(encode(string, <<"hello world">>, #config{})
=:= [<<"\"">>, <<"hello world">>, <<"\"">>]
)},
{"key", ?_assert(encode(key, <<"key">>, #config{}) =:= [<<"\"">>, <<"key">>, <<"\"">>])},
{"1", ?_assert(encode(integer, 1, #config{}) =:= "1")},
{"-1", ?_assert(encode(integer, -1, #config{}) =:= "-1")},
{"true", ?_assert(encode(literal, true, #config{}) =:= "true")},
{"false", ?_assert(encode(literal, false, #config{}) =:= "false")},
{"null", ?_assert(encode(literal, null, #config{}) =:= "null")}
].
format_test_() ->
% {minified version, pretty version}
Cases = [
{"empty object", <<"{}">>, <<"{}">>},
{"empty array", <<"[]">>, <<"[]">>},
{"single key object", <<"{\"k\":\"v\"}">>, <<"{\n \"k\": \"v\"\n}">>},
{"single member array", <<"[true]">>, <<"[\n true\n]">>},
{"multiple key object",
<<"{\"k\":\"v\",\"x\":\"y\"}">>,
<<"{\n \"k\": \"v\",\n \"x\": \"y\"\n}">>
},
{"multiple member array",
<<"[1.0,2.0,3.0]">>,
<<"[\n 1.0,\n 2.0,\n 3.0\n]">>
},
{"nested structure",
<<"[[{},[],true],{\"k\":\"v\",\"x\":\"y\"}]">>,
<<"[\n [\n {},\n [],\n true\n ],\n {\n \"k\": \"v\",\n \"x\": \"y\"\n }\n]">>
}
],
[{Title, ?_assertEqual(Min, jsx:minify(Pretty))} || {Title, Min, Pretty} <- Cases] ++
[{Title, ?_assertEqual(Pretty, jsx:prettify(Min))} || {Title, Min, Pretty} <- Cases].
custom_newline_test_() ->
[
{"single key object", ?_assert(
jsx:format(<<"{\"k\":\"v\"}">>, [space, {indent, 2}, {newline, <<$\r>>}])
=:= <<"{\r \"k\": \"v\"\r}">>)
}
].
handle_event_test_() ->
Data = jsx:test_cases() ++ jsx:special_test_cases(),
[
{
Title, ?_assertEqual(
JSON,
lists:foldl(fun handle_event/2, init([]), Events ++ [end_json])
)
} || {Title, JSON, _, Events} <- Data
].
-endif.

+ 0
- 459
src/jsx-2.10.0/jsx_to_term.erl 查看文件

@ -1,459 +0,0 @@
%% The MIT License
%% Copyright (c) 2010-2013 Alisdair Sullivan <alisdairsullivan@yahoo.ca>
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(jsx_to_term).
-export([to_term/2]).
-export([init/1, handle_event/2]).
-export([
start_term/1,
start_object/1,
start_array/1,
finish/1,
insert/2,
get_key/1,
get_value/1
]).
-record(config, {
labels = binary,
return_maps = false
}).
-type config() :: list().
-export_type([config/0]).
-ifndef(maps_support).
-type json_value() :: list(json_value())
| list({binary() | atom(), json_value()}) | [{},...]
| true
| false
| null
| integer()
| float()
| binary().
-endif.
-ifdef(maps_support).
-type json_value() :: list(json_value())
| list({binary() | atom(), json_value()}) | [{},...]
| map()
| true
| false
| null
| integer()
| float()
| binary().
-endif.
-spec to_term(Source::binary(), Config::config()) -> json_value().
-ifdef(maps_always).
to_term(Source, Config) when is_list(Config) ->
(jsx:decoder(?MODULE, [return_maps] ++ Config, jsx_config:extract_config(Config)))(Source).
-endif.
-ifndef(maps_always).
to_term(Source, Config) when is_list(Config) ->
(jsx:decoder(?MODULE, Config, jsx_config:extract_config(Config)))(Source).
-endif.
parse_config(Config) -> parse_config(Config, #config{}).
parse_config([{labels, Val}|Rest], Config)
when Val == binary; Val == atom; Val == existing_atom; Val == attempt_atom ->
parse_config(Rest, Config#config{labels = Val});
parse_config([labels|Rest], Config) ->
parse_config(Rest, Config#config{labels = binary});
parse_config([{return_maps, Val}|Rest], Config)
when Val == true; Val == false ->
parse_config(Rest, Config#config{return_maps = Val});
parse_config([return_maps|Rest], Config) ->
parse_config(Rest, Config#config{return_maps = true});
parse_config([{K, _}|Rest] = Options, Config) ->
case lists:member(K, jsx_config:valid_flags()) of
true -> parse_config(Rest, Config)
; false -> erlang:error(badarg, [Options, Config])
end;
parse_config([K|Rest] = Options, Config) ->
case lists:member(K, jsx_config:valid_flags()) of
true -> parse_config(Rest, Config)
; false -> erlang:error(badarg, [Options, Config])
end;
parse_config([], Config) ->
Config.
-type state() :: {list(), #config{}}.
-spec init(Config::proplists:proplist()) -> state().
init(Config) -> start_term(Config).
-spec handle_event(Event::any(), State::state()) -> state().
handle_event(end_json, State) -> get_value(State);
handle_event(start_object, State) -> start_object(State);
handle_event(end_object, State) -> finish(State);
handle_event(start_array, State) -> start_array(State);
handle_event(end_array, State) -> finish(State);
handle_event({key, Key}, {_, Config} = State) -> insert(format_key(Key, Config), State);
handle_event({_, Event}, State) -> insert(Event, State).
format_key(Key, Config) ->
case Config#config.labels of
binary -> Key
; atom -> binary_to_atom(Key, utf8)
; existing_atom -> binary_to_existing_atom(Key, utf8)
; attempt_atom ->
try binary_to_existing_atom(Key, utf8) of
Result -> Result
catch
error:badarg -> Key
end
end.
%% internal state is a stack and a config object
%% `{Stack, Config}`
%% the stack is a list of in progress objects/arrays
%% `[Current, Parent, Grandparent,...OriginalAncestor]`
%% an object has the representation on the stack of
%% `{object, [
%% {NthKey, NthValue},
%% {NMinus1Key, NthMinus1Value},
%% ...,
%% {FirstKey, FirstValue}
%% ]}`
%% or if returning maps
%% `{object, #{
%% FirstKey => FirstValue,
%% SecondKey => SecondValue,
%% ...,
%% NthKey => NthValue
%% }}`
%% or if there's a key with a yet to be matched value
%% `{object, Key, ...}`
%% an array looks like
%% `{array, [NthValue, NthMinus1Value,...FirstValue]}`
start_term(Config) when is_list(Config) -> {[], parse_config(Config)}.
-ifndef(maps_support).
%% allocate a new object on top of the stack
start_object({Stack, Config}) -> {[{object, []}] ++ Stack, Config}.
%% allocate a new array on top of the stack
start_array({Stack, Config}) -> {[{array, []}] ++ Stack, Config}.
%% finish an object or array and insert it into the parent object if it exists or
%% return it if it is the root object
finish({[{object, []}], Config}) -> {[{}], Config};
finish({[{object, []}|Rest], Config}) -> insert([{}], {Rest, Config});
finish({[{object, Pairs}], Config}) -> {lists:reverse(Pairs), Config};
finish({[{object, Pairs}|Rest], Config}) -> insert(lists:reverse(Pairs), {Rest, Config});
finish({[{array, Values}], Config}) -> {lists:reverse(Values), Config};
finish({[{array, Values}|Rest], Config}) -> insert(lists:reverse(Values), {Rest, Config});
finish(_) -> erlang:error(badarg).
%% insert a value when there's no parent object or array
insert(Value, {[], Config}) -> {Value, Config};
%% insert a key or value into an object or array, autodetects the 'right' thing
insert(Key, {[{object, Pairs}|Rest], Config}) ->
{[{object, Key, Pairs}] ++ Rest, Config};
insert(Value, {[{object, Key, Pairs}|Rest], Config}) ->
{[{object, [{Key, Value}] ++ Pairs}] ++ Rest, Config};
insert(Value, {[{array, Values}|Rest], Config}) ->
{[{array, [Value] ++ Values}] ++ Rest, Config};
insert(_, _) -> erlang:error(badarg).
-endif.
-ifdef(maps_support).
%% allocate a new object on top of the stack
start_object({Stack, Config=#config{return_maps=true}}) ->
{[{object, #{}}] ++ Stack, Config};
start_object({Stack, Config}) ->
{[{object, []}] ++ Stack, Config}.
%% allocate a new array on top of the stack
start_array({Stack, Config}) -> {[{array, []}] ++ Stack, Config}.
%% finish an object or array and insert it into the parent object if it exists or
%% return it if it is the root object
finish({[{object, Map}], Config=#config{return_maps=true}}) -> {Map, Config};
finish({[{object, Map}|Rest], Config=#config{return_maps=true}}) -> insert(Map, {Rest, Config});
finish({[{object, []}], Config}) -> {[{}], Config};
finish({[{object, []}|Rest], Config}) -> insert([{}], {Rest, Config});
finish({[{object, Pairs}], Config}) -> {lists:reverse(Pairs), Config};
finish({[{object, Pairs}|Rest], Config}) -> insert(lists:reverse(Pairs), {Rest, Config});
finish({[{array, Values}], Config}) -> {lists:reverse(Values), Config};
finish({[{array, Values}|Rest], Config}) -> insert(lists:reverse(Values), {Rest, Config});
finish(_) -> erlang:error(badarg).
%% insert a value when there's no parent object or array
insert(Value, {[], Config}) -> {Value, Config};
%% insert a key or value into an object or array, autodetects the 'right' thing
insert(Key, {[{object, Map}|Rest], Config=#config{return_maps=true}}) ->
{[{object, Key, Map}] ++ Rest, Config};
insert(Key, {[{object, Pairs}|Rest], Config}) ->
{[{object, Key, Pairs}] ++ Rest, Config};
insert(Value, {[{object, Key, Map}|Rest], Config=#config{return_maps=true}}) ->
{[{object, maps:put(Key, Value, Map)}] ++ Rest, Config};
insert(Value, {[{object, Key, Pairs}|Rest], Config}) ->
{[{object, [{Key, Value}] ++ Pairs}] ++ Rest, Config};
insert(Value, {[{array, Values}|Rest], Config}) ->
{[{array, [Value] ++ Values}] ++ Rest, Config};
insert(_, _) -> erlang:error(badarg).
-endif.
get_key({[{object, Key, _}|_], _}) -> Key;
get_key(_) -> erlang:error(badarg).
get_value({Value, _Config}) -> Value;
get_value(_) -> erlang:error(badarg).
%% eunit tests
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
config_test_() ->
[
{"empty config", ?_assertEqual(#config{}, parse_config([]))},
{"implicit binary labels", ?_assertEqual(#config{}, parse_config([labels]))},
{"binary labels", ?_assertEqual(#config{}, parse_config([{labels, binary}]))},
{"atom labels", ?_assertEqual(#config{labels=atom}, parse_config([{labels, atom}]))},
{"existing atom labels", ?_assertEqual(
#config{labels=existing_atom},
parse_config([{labels, existing_atom}])
)},
{"return_maps true", ?_assertEqual(
#config{return_maps=true},
parse_config([return_maps])
)},
{"invalid opt flag", ?_assertError(badarg, parse_config([error]))},
{"invalid opt tuple", ?_assertError(badarg, parse_config([{error, true}]))}
].
format_key_test_() ->
[
{"binary key", ?_assertEqual(<<"key">>, format_key(<<"key">>, #config{labels=binary}))},
{"atom key", ?_assertEqual(key, format_key(<<"key">>, #config{labels=atom}))},
{"existing atom key", ?_assertEqual(
key,
format_key(<<"key">>, #config{labels=existing_atom})
)},
{"nonexisting atom key", ?_assertError(
badarg,
format_key(<<"nonexistentatom">>, #config{labels=existing_atom})
)},
{"sloppy existing atom key", ?_assertEqual(
key,
format_key(<<"key">>, #config{labels=attempt_atom})
)},
{"nonexisting atom key", ?_assertEqual(
<<"nonexistentatom">>,
format_key(<<"nonexistentatom">>, #config{labels=attempt_atom})
)}
].
rep_manipulation_test_() ->
[
{"allocate a new context with option", ?_assertEqual(
{[], #config{labels=atom}},
start_term([{labels, atom}])
)},
{"allocate a new object on an empty stack", ?_assertEqual(
{[{object, []}], #config{}},
start_object({[], #config{}})
)},
{"allocate a new object on a stack", ?_assertEqual(
{[{object, []}, {object, []}], #config{}},
start_object({[{object, []}], #config{}})
)},
{"allocate a new array on an empty stack", ?_assertEqual(
{[{array, []}], #config{}},
start_array({[], #config{}})
)},
{"allocate a new array on a stack", ?_assertEqual(
{[{array, []}, {object, []}], #config{}},
start_array({[{object, []}], #config{}})
)},
{"insert a key into an object", ?_assertEqual(
{[{object, key, []}, junk], #config{}},
insert(key, {[{object, []}, junk], #config{}})
)},
{"get current key", ?_assertEqual(
key,
get_key({[{object, key, []}], #config{}})
)},
{"try to get non-key from object", ?_assertError(
badarg,
get_key({[{object, []}], #config{}})
)},
{"try to get key from array", ?_assertError(
badarg,
get_key({[{array, []}], #config{}})
)},
{"insert a value into an object", ?_assertEqual(
{[{object, [{key, value}]}, junk], #config{}},
insert(value, {[{object, key, []}, junk], #config{}})
)},
{"insert a value into an array", ?_assertEqual(
{[{array, [value]}, junk], #config{}},
insert(value, {[{array, []}, junk], #config{}})
)},
{"finish an object with no ancestor", ?_assertEqual(
{[{a, b}, {x, y}], #config{}},
finish({[{object, [{x, y}, {a, b}]}], #config{}})
)},
{"finish an empty object", ?_assertEqual(
{[{}], #config{}},
finish({[{object, []}], #config{}})
)},
{"finish an object with an ancestor", ?_assertEqual(
{[{object, [{key, [{a, b}, {x, y}]}, {foo, bar}]}], #config{}},
finish({[{object, [{x, y}, {a, b}]}, {object, key, [{foo, bar}]}], #config{}})
)},
{"finish an array with no ancestor", ?_assertEqual(
{[a, b, c], #config{}},
finish({[{array, [c, b, a]}], #config{}})
)},
{"finish an array with an ancestor", ?_assertEqual(
{[{array, [[a, b, c], d, e, f]}], #config{}},
finish({[{array, [c, b, a]}, {array, [d, e, f]}], #config{}})
)}
].
-ifdef(maps_support).
rep_manipulation_with_maps_test_() ->
[
{"allocate a new object on an empty stack", ?_assertEqual(
{[{object, #{}}], #config{return_maps=true}},
start_object({[], #config{return_maps=true}})
)},
{"allocate a new object on a stack", ?_assertEqual(
{[{object, #{}}, {object, #{}}], #config{return_maps=true}},
start_object({[{object, #{}}], #config{return_maps=true}})
)},
{"insert a key into an object", ?_assertEqual(
{[{object, key, #{}}, junk], #config{return_maps=true}},
insert(key, {[{object, #{}}, junk], #config{return_maps=true}})
)},
{"get current key", ?_assertEqual(
key,
get_key({[{object, key, #{}}], #config{return_maps=true}})
)},
{"try to get non-key from object", ?_assertError(
badarg,
get_key({[{object, #{}}], #config{return_maps=true}})
)},
{"insert a value into an object", ?_assertEqual(
{[{object, #{key => value}}, junk], #config{return_maps=true}},
insert(value, {[{object, key, #{}}, junk], #config{return_maps=true}})
)},
{"finish an object with no ancestor", ?_assertEqual(
{#{a => b, x => y}, #config{return_maps=true}},
finish({[{object, #{x => y, a => b}}], #config{return_maps=true}})
)},
{"finish an empty object", ?_assertEqual(
{#{}, #config{return_maps=true}},
finish({[{object, #{}}], #config{return_maps=true}})
)},
{"finish an object with an ancestor", ?_assertEqual(
{
[{object, #{key => #{a => b, x => y}, foo => bar}}],
#config{return_maps=true}
},
finish({
[{object, #{x => y, a => b}}, {object, key, #{foo => bar}}],
#config{return_maps=true}
})
)}
].
return_maps_test_() ->
[
{"an empty map", ?_assertEqual(
#{},
jsx:decode(<<"{}">>, [return_maps])
)},
{"an empty map", ?_assertEqual(
[{}],
jsx:decode(<<"{}">>, [])
)},
{"an empty map", ?_assertEqual(
[{}],
jsx:decode(<<"{}">>, [{return_maps, false}])
)},
{"a small map", ?_assertEqual(
#{<<"awesome">> => true, <<"library">> => <<"jsx">>},
jsx:decode(<<"{\"library\": \"jsx\", \"awesome\": true}">>, [return_maps])
)},
{"a recursive map", ?_assertEqual(
#{<<"key">> => #{<<"key">> => true}},
jsx:decode(<<"{\"key\": {\"key\": true}}">>, [return_maps])
)},
{"a map inside a list", ?_assertEqual(
[#{}],
jsx:decode(<<"[{}]">>, [return_maps])
)}
].
-endif.
handle_event_test_() ->
Data = jsx:test_cases(),
[
{
Title, ?_assertEqual(
Term,
lists:foldl(fun handle_event/2, init([]), Events ++ [end_json])
)
} || {Title, _, Term, Events} <- Data
].
-endif.

+ 0
- 119
src/jsx-2.10.0/jsx_verify.erl 查看文件

@ -1,119 +0,0 @@
%% The MIT License
%% Copyright (c) 2010-2013 alisdair sullivan <alisdairsullivan@yahoo.ca>
%% Permission is hereby granted, free of charge, to any person obtaining a copy
%% of this software and associated documentation files (the "Software"), to deal
%% in the Software without restriction, including without limitation the rights
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%% copies of the Software, and to permit persons to whom the Software is
%% furnished to do so, subject to the following conditions:
%% The above copyright notice and this permission notice shall be included in
%% all copies or substantial portions of the Software.
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%% THE SOFTWARE.
-module(jsx_verify).
-export([is_json/2, is_term/2]).
-export([init/1, handle_event/2]).
-spec is_json(Source::binary(), Config::proplists:proplist()) -> true | false | {incomplete, jsx:decoder()}.
is_json(Source, Config) when is_list(Config) ->
try (jsx:decoder(?MODULE, Config, jsx_config:extract_config(Config)))(Source)
catch error:badarg -> false
end.
-spec is_term(Source::any(), Config::proplists:proplist()) -> true | false | {incomplete, jsx:encoder()}.
is_term(Source, Config) when is_list(Config) ->
try (jsx:encoder(?MODULE, Config, jsx_config:extract_config(Config)))(Source)
catch error:badarg -> false
end.
parse_config(Config) -> parse_config(Config, []).
%% ignore deprecated flags
parse_config([no_repeated_keys|Rest], Config) ->
parse_config(Rest, Config);
parse_config([{repeated_keys, Val}|Rest], Config) when Val == true; Val == false ->
parse_config(Rest, Config);
parse_config([repeated_keys|Rest], Config) ->
parse_config(Rest, Config);
parse_config([{K, _}|Rest] = Options, Config) ->
case lists:member(K, jsx_config:valid_flags()) of
true -> parse_config(Rest, Config);
false -> erlang:error(badarg, [Options, Config])
end;
parse_config([K|Rest] = Options, Config) ->
case lists:member(K, jsx_config:valid_flags()) of
true -> parse_config(Rest, Config);
false -> erlang:error(badarg, [Options, Config])
end;
parse_config([], Config) ->
Config.
%% we don't actually need any state for this
-type state() :: [].
-spec init(Config::proplists:proplist()) -> state().
init(Config) -> parse_config(Config).
-spec handle_event(Event::any(), State::state()) -> state().
handle_event(end_json, _) -> true;
handle_event(_, State) -> State.
%% eunit tests
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
config_test_() ->
[
{"empty config", ?_assertEqual([], parse_config([]))},
{"no repeat keys", ?_assertEqual([], parse_config([no_repeated_keys]))},
{"bare repeated keys", ?_assertEqual([], parse_config([repeated_keys]))},
{"repeated keys true", ?_assertEqual(
[],
parse_config([{repeated_keys, true}])
)},
{"repeated keys false", ?_assertEqual(
[],
parse_config([{repeated_keys, false}])
)},
{"invalid opt flag", ?_assertError(badarg, parse_config([error]))},
{"invalid opt tuple", ?_assertError(badarg, parse_config([{error, true}]))}
].
handle_event_test_() ->
Data = jsx:test_cases() ++ jsx:special_test_cases(),
[
{
Title, ?_assertEqual(
true,
lists:foldl(fun handle_event/2, [], Events ++ [end_json])
)
} || {Title, _, _, Events} <- Data
].
-endif.

正在加载...
取消
保存