add error_handler option and tests
This commit is contained in:
parent
a854f4ae3c
commit
6ec70f8a46
3 changed files with 142 additions and 17 deletions
|
@ -8,5 +8,6 @@
|
||||||
dirty_strings = false,
|
dirty_strings = false,
|
||||||
ignored_bad_escapes = false,
|
ignored_bad_escapes = false,
|
||||||
explicit_end = false,
|
explicit_end = false,
|
||||||
pre_encode = false
|
pre_encode = false,
|
||||||
|
error_handler = false
|
||||||
}).
|
}).
|
|
@ -99,11 +99,14 @@ decoder(Handler, State, Config) ->
|
||||||
|
|
||||||
%% error, incomplete and event macros
|
%% error, incomplete and event macros
|
||||||
-ifndef(error).
|
-ifndef(error).
|
||||||
-define(error(_State, _Bin, _Handler, _Stack, _Config),
|
-define(error(State, Bin, Handler, Acc, Stack, Config),
|
||||||
erlang:error(badarg)
|
case Config#config.error_handler of
|
||||||
|
false -> erlang:error(badarg);
|
||||||
|
F -> F(State, Bin, Handler, Acc, Stack, Config)
|
||||||
|
end
|
||||||
).
|
).
|
||||||
-define(error(_State, _Bin, _Handler, _Acc, _Stack, _Config),
|
-define(error(State, Bin, Handler, Stack, Config),
|
||||||
erlang:error(badarg)
|
?error(State, Bin, Handler, null, Stack, Config)
|
||||||
).
|
).
|
||||||
-endif.
|
-endif.
|
||||||
|
|
||||||
|
@ -149,7 +152,7 @@ acc_seq(Seq, C) -> [C] ++ Seq.
|
||||||
|
|
||||||
end_seq(Seq) -> unicode:characters_to_binary(lists:reverse(Seq)).
|
end_seq(Seq) -> unicode:characters_to_binary(lists:reverse(Seq)).
|
||||||
|
|
||||||
end_seq(Seq, Config=#config{dirty_strings=true}) -> list_to_binary(lists:reverse(Seq));
|
end_seq(Seq, #config{dirty_strings=true}) -> list_to_binary(lists:reverse(Seq));
|
||||||
end_seq(Seq, _) -> end_seq(Seq).
|
end_seq(Seq, _) -> end_seq(Seq).
|
||||||
|
|
||||||
|
|
||||||
|
@ -173,7 +176,7 @@ maybe_bom(<<16#bb, Rest/binary>>, Handler, Stack, Config) ->
|
||||||
maybe_bom(<<>>, Handler, Stack, Config) ->
|
maybe_bom(<<>>, Handler, Stack, Config) ->
|
||||||
?incomplete(start, <<16#ef>>, Handler, Stack, Config);
|
?incomplete(start, <<16#ef>>, Handler, Stack, Config);
|
||||||
maybe_bom(Bin, Handler, Stack, Config) ->
|
maybe_bom(Bin, Handler, Stack, Config) ->
|
||||||
?error(start, <<16#ef>>, Handler, Stack, Config).
|
?error(start, <<16#ef, Bin/binary>>, Handler, Stack, Config).
|
||||||
|
|
||||||
|
|
||||||
definitely_bom(<<16#bf, Rest/binary>>, Handler, Stack, Config) ->
|
definitely_bom(<<16#bf, Rest/binary>>, Handler, Stack, Config) ->
|
||||||
|
@ -181,7 +184,7 @@ definitely_bom(<<16#bf, Rest/binary>>, Handler, Stack, Config) ->
|
||||||
definitely_bom(<<>>, Handler, Stack, Config) ->
|
definitely_bom(<<>>, Handler, Stack, Config) ->
|
||||||
?incomplete(start, <<16#ef, 16#bb>>, Handler, Stack, Config);
|
?incomplete(start, <<16#ef, 16#bb>>, Handler, Stack, Config);
|
||||||
definitely_bom(Bin, Handler, Stack, Config) ->
|
definitely_bom(Bin, Handler, Stack, Config) ->
|
||||||
?error(start, <<16#ef, 16#bb>>, Handler, Stack, Config).
|
?error(start, <<16#ef, 16#bb, Bin/binary>>, Handler, Stack, Config).
|
||||||
|
|
||||||
|
|
||||||
value(<<?doublequote, Rest/binary>>, Handler, Stack, Config) ->
|
value(<<?doublequote, Rest/binary>>, Handler, Stack, Config) ->
|
||||||
|
@ -544,7 +547,7 @@ string(<<X, Rest/binary>>, Handler, Acc, Stack, #config{replaced_bad_utf8=true}
|
||||||
when X >= 240, X =< 247 ->
|
when X >= 240, X =< 247 ->
|
||||||
strip_continuations(Rest, Handler, Acc, Stack, Config, 3);
|
strip_continuations(Rest, Handler, Acc, Stack, Config, 3);
|
||||||
%% incompletes and unexpected bytes, including orphan continuations
|
%% incompletes and unexpected bytes, including orphan continuations
|
||||||
string(<<C, Rest/binary>>, Handler, Acc, Stack, #config{replaced_bad_utf8=true} = Config) ->
|
string(<<_, Rest/binary>>, Handler, Acc, Stack, #config{replaced_bad_utf8=true} = Config) ->
|
||||||
string(Rest, Handler, acc_seq(Acc, 16#fffd), Stack, Config);
|
string(Rest, Handler, acc_seq(Acc, 16#fffd), Stack, Config);
|
||||||
string(Bin, Handler, Acc, Stack, Config) ->
|
string(Bin, Handler, Acc, Stack, Config) ->
|
||||||
case partial_utf(Bin) of
|
case partial_utf(Bin) of
|
||||||
|
@ -733,8 +736,8 @@ decimal(Bin, Handler, Acc, Stack, Config) ->
|
||||||
|
|
||||||
e(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
|
e(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
|
||||||
exp(Rest, Handler, acc_seq(Acc, S), Stack, Config);
|
exp(Rest, Handler, acc_seq(Acc, S), Stack, Config);
|
||||||
e(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?positive; S =:= ?negative ->
|
e(<<Sign, Rest/binary>>, Handler, Acc, Stack, Config) when Sign =:= ?positive; Sign =:= ?negative ->
|
||||||
ex(Rest, Handler, acc_seq(Acc, S), Stack, Config);
|
ex(Rest, Handler, acc_seq(Acc, Sign), Stack, Config);
|
||||||
e(<<>>, Handler, [$e|Acc], Stack, Config) ->
|
e(<<>>, Handler, [$e|Acc], Stack, Config) ->
|
||||||
?incomplete(decimal, <<$e>>, Handler, Acc, Stack, Config);
|
?incomplete(decimal, <<$e>>, Handler, Acc, Stack, Config);
|
||||||
e(Bin, Handler, Acc, Stack, Config) ->
|
e(Bin, Handler, Acc, Stack, Config) ->
|
||||||
|
@ -745,8 +748,8 @@ ex(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzer
|
||||||
exp(Rest, Handler, acc_seq(Acc, S), Stack, Config);
|
exp(Rest, Handler, acc_seq(Acc, S), Stack, Config);
|
||||||
ex(<<>>, Handler, [S, $e|Acc], Stack, Config) ->
|
ex(<<>>, Handler, [S, $e|Acc], Stack, Config) ->
|
||||||
?incomplete(decimal, <<$e, S/utf8>>, Handler, Acc, Stack, Config);
|
?incomplete(decimal, <<$e, S/utf8>>, Handler, Acc, Stack, Config);
|
||||||
ex(Bin, Handler, Acc, Stack, Config) ->
|
ex(Bin, Handler, [S, $e|Acc], Stack, Config) ->
|
||||||
?error(decimal, <<$e, Bin/binary>>, Handler, Acc, Stack, Config).
|
?error(decimal, <<$e, S, Bin/binary>>, Handler, Acc, Stack, Config).
|
||||||
|
|
||||||
|
|
||||||
exp(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
|
exp(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?zero; ?is_nonzero(S) ->
|
||||||
|
@ -777,10 +780,12 @@ finish_number(<<>>, Handler, {NumType, Acc}, Stack, Config) ->
|
||||||
end;
|
end;
|
||||||
finish_number(Bin, Handler, {NumType, Acc}, Stack, Config) ->
|
finish_number(Bin, Handler, {NumType, Acc}, Stack, Config) ->
|
||||||
case NumType of
|
case NumType of
|
||||||
zero -> ?error(zero, <<>>, Handler, Acc, Stack, Config);
|
integer -> ?error(integer, Bin, Handler, Acc, Stack, Config);
|
||||||
integer -> ?error(integer, <<>>, Handler, Acc, Stack, Config);
|
decimal -> ?error(decimal, Bin, Handler, Acc, Stack, Config);
|
||||||
decimal -> ?error(decimal, <<>>, Handler, Acc, Stack, Config);
|
exp -> ?error(exp, Bin, Handler, Acc, Stack, Config);
|
||||||
exp -> ?error(exp, <<>>, Handler, Acc, Stack, Config)
|
zero ->
|
||||||
|
[$0|OldAcc] = Acc,
|
||||||
|
?error(value, <<$0, Bin/binary>>, Handler, OldAcc, Stack, Config)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1960,5 +1965,100 @@ error_test_() ->
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
||||||
|
custom_error_handler_test_() ->
|
||||||
|
Decode = fun(JSON, Config) -> start(JSON, {jsx, []}, [], jsx_utils:parse_config(Config)) end,
|
||||||
|
Error = fun(State, Rest, _Handler, _Acc, _Stack, _Config) -> {State, Rest} end,
|
||||||
|
[
|
||||||
|
{"maybe_bom error", ?_assertEqual(
|
||||||
|
{start, <<16#ef, 0>>},
|
||||||
|
Decode(<<16#ef, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"definitely_bom error", ?_assertEqual(
|
||||||
|
{start, <<16#ef, 16#bb, 0>>},
|
||||||
|
Decode(<<16#ef, 16#bb, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"value error", ?_assertEqual(
|
||||||
|
{value, <<0>>},
|
||||||
|
Decode(<<0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"object error", ?_assertEqual(
|
||||||
|
{object, <<0>>},
|
||||||
|
Decode(<<"{"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"colon error", ?_assertEqual(
|
||||||
|
{colon, <<0>>},
|
||||||
|
Decode(<<"{\"\""/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"key error", ?_assertEqual(
|
||||||
|
{key, <<0>>},
|
||||||
|
Decode(<<"{\"\":1,"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"negative error", ?_assertEqual(
|
||||||
|
{value, <<"-"/utf8, 0>>},
|
||||||
|
Decode(<<"-"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"zero error", ?_assertEqual(
|
||||||
|
{value, <<"0"/utf8, 0>>},
|
||||||
|
Decode(<<"0"/utf8, 0>>, [explicit_end, {error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"integer error", ?_assertEqual(
|
||||||
|
{integer, <<0>>},
|
||||||
|
Decode(<<"1"/utf8, 0>>, [explicit_end, {error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"decimal error", ?_assertEqual(
|
||||||
|
{decimal, <<0>>},
|
||||||
|
Decode(<<"1.0"/utf8, 0>>, [explicit_end, {error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"exp error", ?_assertEqual(
|
||||||
|
{exp, <<0>>},
|
||||||
|
Decode(<<"1.0e1"/utf8, 0>>, [explicit_end, {error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"e error", ?_assertEqual(
|
||||||
|
{decimal, <<$e, 0>>},
|
||||||
|
Decode(<<"1e"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"ex error", ?_assertEqual(
|
||||||
|
{decimal, <<$e, ?positive, 0>>},
|
||||||
|
Decode(<<"1e+"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"exp error", ?_assertEqual(
|
||||||
|
{decimal, <<$e>>},
|
||||||
|
Decode(<<"1.e"/utf8>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"true error", ?_assertEqual(
|
||||||
|
{true, <<"ru"/utf8, 0>>},
|
||||||
|
Decode(<<"tru"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"false error", ?_assertEqual(
|
||||||
|
{false, <<"als"/utf8, 0>>},
|
||||||
|
Decode(<<"fals"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"null error", ?_assertEqual(
|
||||||
|
{null, <<"ul"/utf8, 0>>},
|
||||||
|
Decode(<<"nul"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"maybe_done error", ?_assertEqual(
|
||||||
|
{maybe_done, <<0>>},
|
||||||
|
Decode(<<"[[]"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"done error", ?_assertEqual(
|
||||||
|
{done, <<0>>},
|
||||||
|
Decode(<<"[]"/utf8, 0>>, [{error_handler, Error}])
|
||||||
|
)},
|
||||||
|
{"comment error", ?_assertEqual(
|
||||||
|
{comment, <<" ]"/utf8>>},
|
||||||
|
Decode(<<"[ / ]">>, [{error_handler, Error}, comments])
|
||||||
|
)},
|
||||||
|
{"single_comment error", ?_assertEqual(
|
||||||
|
{comment, <<"/"/utf8, 192>>},
|
||||||
|
Decode(<<"[ //"/utf8, 192>>, [{error_handler, Error}, comments])
|
||||||
|
)},
|
||||||
|
{"multi_comment error", ?_assertEqual(
|
||||||
|
{comment, <<"*"/utf8, 192>>},
|
||||||
|
Decode(<<"[ /*"/utf8, 192>>, [{error_handler, Error}, comments])
|
||||||
|
)}
|
||||||
|
].
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-endif.
|
-endif.
|
|
@ -28,6 +28,10 @@
|
||||||
-export([json_escape_sequence/1]).
|
-export([json_escape_sequence/1]).
|
||||||
-export([clean_string/2]).
|
-export([clean_string/2]).
|
||||||
|
|
||||||
|
-ifdef(TEST).
|
||||||
|
-export([fake_error_handler/6]).
|
||||||
|
-endif.
|
||||||
|
|
||||||
-include("jsx_config.hrl").
|
-include("jsx_config.hrl").
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,6 +71,11 @@ parse_config([{pre_encode, Encoder}|Rest] = Options, Config) when is_function(En
|
||||||
false -> parse_config(Rest, Config#config{pre_encode=Encoder})
|
false -> parse_config(Rest, Config#config{pre_encode=Encoder})
|
||||||
; _ -> erlang:error(badarg, [Options, Config])
|
; _ -> erlang:error(badarg, [Options, Config])
|
||||||
end;
|
end;
|
||||||
|
parse_config([{error_handler, ErrorHandler}|Rest] = Options, Config) when is_function(ErrorHandler, 6) ->
|
||||||
|
case Config#config.error_handler of
|
||||||
|
false -> parse_config(Rest, Config#config{error_handler=ErrorHandler})
|
||||||
|
; _ -> erlang:error(badarg, [Options, Config])
|
||||||
|
end;
|
||||||
%% deprecated flags
|
%% deprecated flags
|
||||||
parse_config([{pre_encoder, Encoder}|Rest] = Options, Config) when is_function(Encoder, 1) ->
|
parse_config([{pre_encoder, Encoder}|Rest] = Options, Config) when is_function(Encoder, 1) ->
|
||||||
case Config#config.pre_encode of
|
case Config#config.pre_encode of
|
||||||
|
@ -102,6 +111,7 @@ valid_flags() ->
|
||||||
explicit_end,
|
explicit_end,
|
||||||
relax,
|
relax,
|
||||||
pre_encode,
|
pre_encode,
|
||||||
|
error_handler,
|
||||||
%% deprecated flags
|
%% deprecated flags
|
||||||
pre_encoder, %% pre_encode
|
pre_encoder, %% pre_encode
|
||||||
loose_unicode, %% replaced_bad_utf8
|
loose_unicode, %% replaced_bad_utf8
|
||||||
|
@ -610,8 +620,22 @@ config_test_() ->
|
||||||
{pre_encode, fun(_) -> false end}
|
{pre_encode, fun(_) -> false end}
|
||||||
])
|
])
|
||||||
)},
|
)},
|
||||||
|
{"error_handler flag", ?_assertEqual(
|
||||||
|
#config{error_handler=fun ?MODULE:fake_error_handler/6},
|
||||||
|
parse_config([{error_handler, fun ?MODULE:fake_error_handler/6}])
|
||||||
|
)},
|
||||||
|
{"two error_handlers defined", ?_assertError(
|
||||||
|
badarg,
|
||||||
|
parse_config([
|
||||||
|
{error_handler, fun(_) -> true end},
|
||||||
|
{error_handler, fun(_) -> false end}
|
||||||
|
])
|
||||||
|
)},
|
||||||
{"bad option flag", ?_assertError(badarg, parse_config([error]))}
|
{"bad option flag", ?_assertError(badarg, parse_config([error]))}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
||||||
|
fake_error_handler(_, _, _, _, _, _) -> ok.
|
||||||
|
|
||||||
|
|
||||||
%% erlang refuses to encode certain codepoints, so fake them
|
%% erlang refuses to encode certain codepoints, so fake them
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue