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,
|
||||
ignored_bad_escapes = 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
|
||||
-ifndef(error).
|
||||
-define(error(_State, _Bin, _Handler, _Stack, _Config),
|
||||
erlang:error(badarg)
|
||||
-define(error(State, Bin, Handler, Acc, Stack, Config),
|
||||
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),
|
||||
erlang:error(badarg)
|
||||
-define(error(State, Bin, Handler, Stack, Config),
|
||||
?error(State, Bin, Handler, null, Stack, Config)
|
||||
).
|
||||
-endif.
|
||||
|
||||
|
@ -149,7 +152,7 @@ acc_seq(Seq, C) -> [C] ++ 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).
|
||||
|
||||
|
||||
|
@ -173,7 +176,7 @@ maybe_bom(<<16#bb, Rest/binary>>, Handler, Stack, Config) ->
|
|||
maybe_bom(<<>>, Handler, Stack, Config) ->
|
||||
?incomplete(start, <<16#ef>>, 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) ->
|
||||
|
@ -181,7 +184,7 @@ definitely_bom(<<16#bf, Rest/binary>>, Handler, Stack, Config) ->
|
|||
definitely_bom(<<>>, Handler, Stack, Config) ->
|
||||
?incomplete(start, <<16#ef, 16#bb>>, 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) ->
|
||||
|
@ -544,7 +547,7 @@ string(<<X, Rest/binary>>, Handler, Acc, Stack, #config{replaced_bad_utf8=true}
|
|||
when X >= 240, X =< 247 ->
|
||||
strip_continuations(Rest, Handler, Acc, Stack, Config, 3);
|
||||
%% 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(Bin, Handler, Acc, Stack, Config) ->
|
||||
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) ->
|
||||
exp(Rest, Handler, acc_seq(Acc, S), Stack, Config);
|
||||
e(<<S, Rest/binary>>, Handler, Acc, Stack, Config) when S =:= ?positive; S =:= ?negative ->
|
||||
ex(Rest, Handler, acc_seq(Acc, S), Stack, Config);
|
||||
e(<<Sign, Rest/binary>>, Handler, Acc, Stack, Config) when Sign =:= ?positive; Sign =:= ?negative ->
|
||||
ex(Rest, Handler, acc_seq(Acc, Sign), Stack, Config);
|
||||
e(<<>>, Handler, [$e|Acc], Stack, Config) ->
|
||||
?incomplete(decimal, <<$e>>, 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);
|
||||
ex(<<>>, Handler, [S, $e|Acc], Stack, Config) ->
|
||||
?incomplete(decimal, <<$e, S/utf8>>, Handler, Acc, Stack, Config);
|
||||
ex(Bin, Handler, Acc, Stack, Config) ->
|
||||
?error(decimal, <<$e, Bin/binary>>, Handler, Acc, Stack, Config).
|
||||
ex(Bin, Handler, [S, $e|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) ->
|
||||
|
@ -777,10 +780,12 @@ finish_number(<<>>, Handler, {NumType, Acc}, Stack, Config) ->
|
|||
end;
|
||||
finish_number(Bin, Handler, {NumType, Acc}, Stack, Config) ->
|
||||
case NumType of
|
||||
zero -> ?error(zero, <<>>, Handler, Acc, Stack, Config);
|
||||
integer -> ?error(integer, <<>>, Handler, Acc, Stack, Config);
|
||||
decimal -> ?error(decimal, <<>>, Handler, Acc, Stack, Config);
|
||||
exp -> ?error(exp, <<>>, Handler, Acc, Stack, Config)
|
||||
integer -> ?error(integer, Bin, Handler, Acc, Stack, Config);
|
||||
decimal -> ?error(decimal, Bin, Handler, Acc, Stack, Config);
|
||||
exp -> ?error(exp, Bin, Handler, Acc, Stack, Config);
|
||||
zero ->
|
||||
[$0|OldAcc] = Acc,
|
||||
?error(value, <<$0, Bin/binary>>, Handler, OldAcc, Stack, Config)
|
||||
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.
|
|
@ -28,6 +28,10 @@
|
|||
-export([json_escape_sequence/1]).
|
||||
-export([clean_string/2]).
|
||||
|
||||
-ifdef(TEST).
|
||||
-export([fake_error_handler/6]).
|
||||
-endif.
|
||||
|
||||
-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})
|
||||
; _ -> erlang:error(badarg, [Options, Config])
|
||||
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
|
||||
parse_config([{pre_encoder, Encoder}|Rest] = Options, Config) when is_function(Encoder, 1) ->
|
||||
case Config#config.pre_encode of
|
||||
|
@ -102,6 +111,7 @@ valid_flags() ->
|
|||
explicit_end,
|
||||
relax,
|
||||
pre_encode,
|
||||
error_handler,
|
||||
%% deprecated flags
|
||||
pre_encoder, %% pre_encode
|
||||
loose_unicode, %% replaced_bad_utf8
|
||||
|
@ -610,8 +620,22 @@ config_test_() ->
|
|||
{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]))}
|
||||
].
|
||||
|
||||
|
||||
fake_error_handler(_, _, _, _, _, _) -> ok.
|
||||
|
||||
|
||||
%% erlang refuses to encode certain codepoints, so fake them
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue