[#90] Include more specific errors when a oneOf, allOf and anyOf schema validation fails

This commit is contained in:
Juan Facorro 2020-05-20 13:10:52 +02:00
parent 904ae086c3
commit 2b2c906ece
2 changed files with 42 additions and 25 deletions

View File

@ -122,6 +122,7 @@
-define(any_schemas_not_valid, 'any_schemas_not_valid').
-define(not_multiple_of, 'not_multiple_of').
-define(not_one_schema_valid, 'not_one_schema_valid').
-define(more_than_one_schema_valid, 'more_than_one_schema_valid').
-define(not_schema_valid, 'not_schema_valid').
-define(wrong_not_schema, 'wrong_not_schema').
-define(external, 'external').

View File

@ -60,6 +60,7 @@
| ?not_in_range
| ?not_multiple_of
| ?not_one_schema_valid
| ?more_than_one_schema_valid
| ?not_schema_valid
| ?too_few_properties
| ?too_many_properties
@ -69,7 +70,8 @@
| ?external.
-type data_error_type() :: data_error()
| {data_error(), binary()}.
| {data_error(), binary()}
| {data_error(), [jesse_error:error_reason()]}.
%%% API
%% @doc Goes through attributes of the given schema `JsonSchema' and
@ -1111,8 +1113,10 @@ check_all_of_(_Value, [], State) ->
State;
check_all_of_(Value, [Schema | Schemas], State) ->
case validate_schema(Value, Schema, State) of
{true, NewState} -> check_all_of_(Value, Schemas, NewState);
{false, _} -> handle_data_invalid(?all_schemas_not_valid, Value, State)
{true, NewState} ->
check_all_of_(Value, Schemas, NewState);
{false, Errors} ->
handle_data_invalid({?all_schemas_not_valid, Errors}, Value, State)
end.
%% @doc 5.5.4. anyOf
@ -1132,21 +1136,26 @@ check_all_of_(Value, [Schema | Schemas], State) ->
%%
%% @private
check_any_of(Value, [_ | _] = Schemas, State) ->
check_any_of_(Value, Schemas, State);
check_any_of_(Value, Schemas, State, []);
check_any_of(_Value, _InvalidSchemas, State) ->
handle_schema_invalid(?wrong_any_of_schema_array, State).
check_any_of_(Value, [], State) ->
check_any_of_(Value, [], State, []) ->
handle_data_invalid(?any_schemas_not_valid, Value, State);
check_any_of_(Value, [Schema | Schemas], State) ->
check_any_of_(Value, [], State, SchemaErrors) ->
[Errors | _] = lists:sort(fun by_length/2, SchemaErrors),
handle_data_invalid({?any_schemas_not_valid, Errors}, Value, State);
check_any_of_(Value, [Schema | Schemas], State, SchemaErrors) ->
NumErrsBefore = length(jesse_state:get_error_list(State)),
case validate_schema(Value, Schema, State) of
{true, NewState} ->
case length(jesse_state:get_error_list(NewState)) of
NumErrsBefore -> NewState;
_ -> check_any_of_(Value, Schemas, State)
end;
{false, _} -> check_any_of_(Value, Schemas, State)
Errors = jesse_state:get_error_list(NewState),
case length(Errors) of
NumErrsBefore -> NewState;
_ -> check_any_of_(Value, Schemas, State, [Errors | SchemaErrors])
end;
{false, Errors} ->
check_any_of_(Value, Schemas, State, [Errors | SchemaErrors])
end.
%% @doc 5.5.5. oneOf
@ -1166,29 +1175,32 @@ check_any_of_(Value, [Schema | Schemas], State) ->
%%
%% @private
check_one_of(Value, [_ | _] = Schemas, State) ->
check_one_of_(Value, Schemas, State, 0);
check_one_of_(Value, Schemas, State, 0, []);
check_one_of(_Value, _InvalidSchemas, State) ->
handle_schema_invalid(?wrong_one_of_schema_array, State).
check_one_of_(_Value, [], State, 1) ->
check_one_of_(_Value, [], State, 1, _SchemaErrors) ->
State;
check_one_of_(Value, [], State, 0) ->
handle_data_invalid(?not_one_schema_valid, Value, State);
check_one_of_(Value, _Schemas, State, Valid) when Valid > 1 ->
handle_data_invalid(?not_one_schema_valid, Value, State);
check_one_of_(Value, [Schema | Schemas], State, Valid) ->
check_one_of_(Value, [], State, 0, SchemaErrors) ->
[Errors | _] = lists:sort(fun by_length/2, SchemaErrors),
handle_data_invalid({?not_one_schema_valid, Errors}, Value, State);
check_one_of_(Value, _Schemas, State, Valid, _SchemaErrors) when Valid > 1 ->
handle_data_invalid(?more_than_one_schema_valid, Value, State);
check_one_of_(Value, [Schema | Schemas], State, Valid, SchemaErrors) ->
NumErrsBefore = length(jesse_state:get_error_list(State)),
case validate_schema(Value, Schema, State) of
{true, NewState} ->
case length(jesse_state:get_error_list(NewState)) of
NumErrsBefore -> check_one_of_(Value, Schemas, NewState, Valid + 1);
_ -> check_one_of_(Value, Schemas, State, Valid)
end;
{false, _} ->
check_one_of_(Value, Schemas, State, Valid)
Errors = jesse_state:get_error_list(NewState),
case length(Errors) of
NumErrsBefore ->
check_one_of_(Value, Schemas, NewState, Valid + 1, SchemaErrors);
_ ->
check_one_of_(Value, Schemas, State, Valid, [Errors | SchemaErrors])
end;
{false, Errors} ->
check_one_of_(Value, Schemas, State, Valid, [Errors | SchemaErrors])
end.
%% @doc 5.5.6. not
%%
%% 5.5.6.1. Valid values
@ -1380,3 +1392,7 @@ maybe_external_check_value(Value, State) ->
Fun ->
Fun(Value, State)
end.
%% @private
-spec by_length(list(), list()) -> boolean().
by_length(X, Y) -> length(X) < length(Y).