Merge pull request #92 from jfacorro/90-improve-error-messages-one-of-return-all-messages

[#90] Improve error messages (alternative)
This commit is contained in:
Sergey Prokhorov 2020-06-05 10:30:38 +02:00 committed by GitHub
commit bf5ba4b644
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 131 additions and 28 deletions

View File

@ -23,6 +23,9 @@ distclean:
$(RM) doc/stylesheet.css $(RM) doc/stylesheet.css
$(RM) -r logs $(RM) -r logs
.PHONY: clean-tests
clean-tests:
@ rm -rf _build/test/lib
# Docs # Docs
.PHONY: docs .PHONY: docs
@ -53,10 +56,14 @@ test: eunit ct xref dialyzer cover
.PHONY: eunit .PHONY: eunit
eunit: eunit:
@ $(MAKE) clean-tests
$(REBAR) eunit $(REBAR) eunit
# @ rm -rf _build
.PHONY: ct .PHONY: ct
ct: test/JSON-Schema-Test-Suite/tests ct: test/JSON-Schema-Test-Suite/tests
@ $(MAKE) clean-tests
$(REBAR) ct $(REBAR) ct
.PHONY: xref .PHONY: xref
@ -73,4 +80,5 @@ elvis:
.PHONY: cover .PHONY: cover
cover: cover:
@ $(MAKE) clean-tests
$(REBAR) cover -v $(REBAR) cover -v

View File

@ -56,7 +56,8 @@
-type error_type() :: atom() -type error_type() :: atom()
| {atom(), jesse:json_term()} | {atom(), jesse:json_term()}
| {atom(), binary()}. | {atom(), binary()}
| {atom(), [error_reason()]}.
%% Includes %% Includes
-include("jesse_schema_validator.hrl"). -include("jesse_schema_validator.hrl").

View File

@ -122,6 +122,7 @@
-define(any_schemas_not_valid, 'any_schemas_not_valid'). -define(any_schemas_not_valid, 'any_schemas_not_valid').
-define(not_multiple_of, 'not_multiple_of'). -define(not_multiple_of, 'not_multiple_of').
-define(not_one_schema_valid, 'not_one_schema_valid'). -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(not_schema_valid, 'not_schema_valid').
-define(wrong_not_schema, 'wrong_not_schema'). -define(wrong_not_schema, 'wrong_not_schema').
-define(external, 'external'). -define(external, 'external').

View File

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

View File

@ -221,6 +221,73 @@ schema_unsupported_test() ->
, jesse_schema_validator:validate(UnsupportedSchema, Json, []) , jesse_schema_validator:validate(UnsupportedSchema, Json, [])
). ).
data_invalid_one_of_test() ->
IntegerSchema = {[{<<"type">>, <<"integer">>}]},
StringSchema = {[{<<"type">>, <<"string">>}]},
ObjectSchema = {[ {<<"type">>, <<"object">>}
, { <<"properties">>
, [ {<<"name">>, StringSchema}
, {<<"age">>, IntegerSchema}
]
}
, {<<"additionalProperties">>, false}
]},
Schema = {[ {<<"$schema">>, <<"http://json-schema.org/draft-04/schema#">>}
, {<<"oneOf">>, [IntegerSchema, StringSchema, ObjectSchema]}
]},
Json = [ {<<"name">>, 42}
, {<<"age">>, <<"John">>}
],
?assertThrow(
[ { data_invalid
, Schema
, { not_one_schema_valid
, [ {data_invalid, IntegerSchema, wrong_type, Json, []}
, {data_invalid, StringSchema, wrong_type, Json, []}
, {data_invalid, StringSchema, wrong_type, 42, [<<"name">>]}
]
}
, Json
, []
}],
jesse_schema_validator:validate(Schema, Json, [])
).
data_invalid_any_of_test() ->
IntegerSchema = {[{<<"type">>, <<"integer">>}]},
StringSchema = {[{<<"type">>, <<"string">>}]},
ObjectSchema = {[ {<<"type">>, <<"object">>}
, { <<"properties">>
, [ {<<"name">>, StringSchema}
, {<<"age">>, IntegerSchema}
]
}
, {<<"additionalProperties">>, false}
]},
Schema = {[ {<<"$schema">>, <<"http://json-schema.org/draft-04/schema#">>}
, {<<"anyOf">>, [IntegerSchema, StringSchema, ObjectSchema]}
]},
Json = [ {<<"name">>, 42}
, {<<"age">>, <<"John">>}
],
?assertThrow(
[ { data_invalid
, Schema
, { any_schemas_not_valid
, [{data_invalid, IntegerSchema, wrong_type, Json, []}]
}
, Json
, []
}],
jesse_schema_validator:validate(Schema, Json, [])
).
-ifndef(erlang_deprecated_types). -ifndef(erlang_deprecated_types).
-ifndef(COMMON_TEST). % see Emakefile -ifndef(COMMON_TEST). % see Emakefile
map_schema_test() -> map_schema_test() ->