Merge branch 'master' into std-formats

Conflicts:
	test/jesse_tests_draft4_SUITE.erl
This commit is contained in:
Anton Yabchinskiy 2016-12-16 14:57:39 +03:00
commit 79fa984755
11 changed files with 329 additions and 11 deletions

View File

@ -5,10 +5,16 @@
jesse (JSON Schema Erlang) is an implementation of a JSON Schema validator
for Erlang.
jesse implements [Draft 03] (http://tools.ietf.org/html/draft-zyp-json-schema-03) and [Draft 04] (http://tools.ietf.org/html/draft-zyp-json-schema-04) of
the specification. It supports all core schema definitions except:
jesse implements the following specifications:
* format
* [Draft 03](http://tools.ietf.org/html/draft-zyp-json-schema-03)
* [Draft 04](http://tools.ietf.org/html/draft-zyp-json-schema-04)
## Erlang API Docs
Automatically generated docs are available https://dev.erldocs.com/github.com/for-get/jesse/ .
Please keep in mind that the public API is the `jesse.erl` module alone.
## Quick start - CLI

View File

@ -30,6 +30,7 @@
%% JSON-Schema-Test-Suite attributes definitions
-define(DATA, <<"data">>).
-define(DESCRIPTION, <<"description">>).
-define(OPTIONS, <<"options">>).
-define(SCHEMA, <<"schema">>).
-define(TESTS, <<"tests">>).
-define(VALID, <<"valid">>).
@ -57,26 +58,29 @@ do_test(Key, Config) ->
Description = get_path(?DESCRIPTION, Test),
Schema = get_path(?SCHEMA, Test),
SchemaTests = get_path(?TESTS, Test),
Options = get_path(?OPTIONS, Test),
ct:pal( "** Description: ~s~n"
"** Options: ~p~n"
"** Schema: ~p~n"
"** Schema tests: ~p~n"
, [Description, Schema, SchemaTests]
, [Description, Options, Schema, SchemaTests]
),
test_schema(DefaultSchema, Schema, SchemaTests)
test_schema(DefaultSchema, Options, Schema, SchemaTests)
end
, Tests
).
%%% Internal functions
test_schema(DefaultSchema, Schema, SchemaTests) ->
test_schema(DefaultSchema, Opts0, Schema, SchemaTests) ->
Opts1 = make_options(Opts0),
lists:foreach( fun(Test) ->
Description = get_path(?DESCRIPTION, Test),
Instance = get_path(?DATA, Test),
ct:pal("* Test case: ~s~n", [Description]),
Opts = [ {default_schema_ver, DefaultSchema}
, {schema_loader_fun, fun load_schema/1}
],
] ++ Opts1,
try jesse:validate_with_schema(Schema, Instance, Opts) of
Result ->
ct:pal("Result: ~p~n", [Result]),
@ -96,6 +100,21 @@ test_schema(DefaultSchema, Schema, SchemaTests) ->
, SchemaTests
).
make_options(Options) ->
lists:map( fun ({Key0, Value0}) ->
Key = case is_binary(Key0) of
true -> list_to_existing_atom(binary_to_list(Key0));
false -> Key0
end,
Value = case is_binary(Value0) of
true -> list_to_existing_atom(binary_to_list(Value0));
false -> Value0
end,
{Key, Value}
end
, Options
).
testfile_to_key(TestFile) ->
filename:rootname(filename:basename(TestFile)).

View File

@ -487,7 +487,7 @@ get_additional_properties(Value, Properties, PatternProperties) ->
%% @private
filter_extra_names(Pattern, ExtraNames) ->
Filter = fun(ExtraName) ->
case re:run(ExtraName, Pattern, [{capture, none}]) of
case re:run(ExtraName, Pattern, [{capture, none}, unicode]) of
match -> false;
nomatch -> true
end

View File

@ -490,7 +490,7 @@ get_additional_properties(Value, Properties, PatternProperties) ->
%% @private
filter_extra_names(Pattern, ExtraNames) ->
Filter = fun(ExtraName) ->
case re:run(ExtraName, Pattern, [{capture, none}]) of
case re:run(ExtraName, Pattern, [{capture, none}, unicode]) of
match -> false;
nomatch -> true
end
@ -968,11 +968,13 @@ check_format(Value, _Format = <<"email">>, State) when is_binary(Value) ->
nomatch -> handle_data_invalid(?wrong_format, Value, State)
end;
check_format(Value, _Format = <<"ip-address">>, State) when is_binary(Value) ->
%% avoiding inet:parse_ipv4strict_address to maintain R15 compatibility
case inet_parse:ipv4strict_address(binary_to_list(Value)) of
{ok, _IPv4Address} -> State;
{error, einval} -> handle_data_invalid(?wrong_format, Value, State)
end;
check_format(Value, _Format = <<"ipv6">>, State) when is_binary(Value) ->
%% avoiding inet:parse_ipv6strict_address to maintain R15 compatibility
case inet_parse:ipv6strict_address(binary_to_list(Value)) of
{ok, _IPv6Address} -> State;
{error, einval} -> handle_data_invalid(?wrong_format, Value, State)
@ -1134,7 +1136,11 @@ check_any_of_(Value, [], State) ->
handle_data_invalid(?any_schemas_not_valid, Value, State);
check_any_of_(Value, [Schema | Schemas], State) ->
case validate_schema(Value, Schema, State) of
{true, NewState} -> NewState;
{true, NewState} ->
case jesse_state:get_error_list(NewState) of
[] -> NewState;
_ -> check_any_of_(Value, Schemas, State)
end;
{false, _} -> check_any_of_(Value, Schemas, State)
end.
@ -1168,7 +1174,10 @@ check_one_of_(Value, _Schemas, State, Valid) when Valid > 1 ->
check_one_of_(Value, [Schema | Schemas], State, Valid) ->
case validate_schema(Value, Schema, State) of
{true, NewState} ->
check_one_of_(Value, Schemas, NewState, Valid + 1);
case jesse_state:get_error_list(NewState) of
[] -> check_one_of_(Value, Schemas, NewState, Valid + 1);
_ -> check_one_of_(Value, Schemas, State, Valid)
end;
{false, _} ->
check_one_of_(Value, Schemas, State, Valid)
end.
@ -1335,6 +1344,7 @@ remove_last_from_path(State) ->
%% @private
valid_date(<<Year:4/bytes, $-, Month:2/bytes, $-, Day:2/bytes>>) ->
try
%% avoiding binary_to_integer to maintain R15 compatibility
calendar:valid_date( list_to_integer(binary_to_list(Year))
, list_to_integer(binary_to_list(Month))
, list_to_integer(binary_to_list(Day))
@ -1346,6 +1356,7 @@ valid_date(_Other) -> false.
%% @private
valid_time(<<Hour:2/bytes, $:, Minute:2/bytes, $:, Second:2/bytes>>) ->
%% avoiding binary_to_integer to maintain R15 compatibility
try { list_to_integer(binary_to_list(Hour))
, list_to_integer(binary_to_list(Minute))
, list_to_integer(binary_to_list(Second))

View File

@ -0,0 +1,21 @@
{
"description": "using non-ascii regex additionalProperties being false does not allow other properties ",
"schema": {
"patternProperties": {
"^á": {}
},
"additionalProperties": false
},
"tests": [
{
"description": "non-ascii patternProperties matching the pattern is valid",
"data": {"ármányos": 2},
"valid": true
},
{
"description": "additional non-ascii patternProperties not matching the pattern is invalid",
"data": {"élmény": 2},
"valid": false
}
]
}

View File

@ -0,0 +1,75 @@
[
{
"description": "anyOf/oneOf with allowed_errors",
"options": {
"allowed_errors": "infinity"
},
"schema": {
"type": "object",
"properties": {
"anyOf": {
"anyOf": [
{
"enum": [0]
}, {
"enum": [0, 1]
}
]
},
"oneOf": {
"oneOf": [
{
"enum": [0]
}, {
"enum": [0, 1]
}
]
}
}
},
"tests": [
{
"description": "anyOf: all valid",
"data": {
"anyOf": 0
},
"valid": true
},
{
"description": "anyOf: one valid",
"data": {
"anyOf": 1
},
"valid": true
},
{
"description": "anyOf: invalid",
"data": {
"anyOf": 2
},
"valid": false
},
{
"description": "oneOf: all valid",
"data": {
"oneOf": 0
},
"valid": false
},
{
"description": "oneOf: one valid",
"data": {
"oneOf": 1
},
"valid": true
},
{
"description": "oneOf: invalid",
"data": {
"oneOf": 2
},
"valid": false
}
]
}
]

View File

@ -0,0 +1,75 @@
[
{
"description": "anyOf/oneOf with allowed_errors",
"options": {
"allowed_errors": 1
},
"schema": {
"type": "object",
"properties": {
"anyOf": {
"anyOf": [
{
"enum": [0]
}, {
"enum": [0, 1]
}
]
},
"oneOf": {
"oneOf": [
{
"enum": [0]
}, {
"enum": [0, 1]
}
]
}
}
},
"tests": [
{
"description": "anyOf: all valid",
"data": {
"anyOf": 0
},
"valid": true
},
{
"description": "anyOf: one valid",
"data": {
"anyOf": 1
},
"valid": true
},
{
"description": "anyOf: invalid",
"data": {
"anyOf": 2
},
"valid": false
},
{
"description": "oneOf: all valid",
"data": {
"oneOf": 0
},
"valid": false
},
{
"description": "oneOf: one valid",
"data": {
"oneOf": 1
},
"valid": true
},
{
"description": "oneOf: invalid",
"data": {
"oneOf": 2
},
"valid": false
}
]
}
]

View File

@ -0,0 +1,75 @@
[
{
"description": "anyOf/oneOf with allowed_errors",
"options": {
"allowed_errors": 0
},
"schema": {
"type": "object",
"properties": {
"anyOf": {
"anyOf": [
{
"enum": [0]
}, {
"enum": [0, 1]
}
]
},
"oneOf": {
"oneOf": [
{
"enum": [0]
}, {
"enum": [0, 1]
}
]
}
}
},
"tests": [
{
"description": "anyOf: all valid",
"data": {
"anyOf": 0
},
"valid": true
},
{
"description": "anyOf: one valid",
"data": {
"anyOf": 1
},
"valid": true
},
{
"description": "anyOf: invalid",
"data": {
"anyOf": 2
},
"valid": false
},
{
"description": "oneOf: all valid",
"data": {
"oneOf": 0
},
"valid": false
},
{
"description": "oneOf: one valid",
"data": {
"oneOf": 1
},
"valid": true
},
{
"description": "oneOf: invalid",
"data": {
"oneOf": 2
},
"valid": false
}
]
}
]

View File

@ -0,0 +1,21 @@
{
"description": "using non-ascii regex additionalProperties being false does not allow other properties ",
"schema": {
"patternProperties": {
"^á": {}
},
"additionalProperties": false
},
"tests": [
{
"description": "non-ascii patternProperties matching the pattern is valid",
"data": {"ármányos": 2},
"valid": true
},
{
"description": "additional non-ascii patternProperties not matching the pattern is invalid",
"data": {"élmény": 2},
"valid": false
}
]
}

View File

@ -140,3 +140,6 @@ itemsExtra(Config) ->
remoteRefExtra(Config) ->
do_test("remoteRefExtra", Config).
unicodePatternProperties(Config) ->
do_test("unicodePatternProperties", Config).

View File

@ -156,6 +156,18 @@ itemsExtra(Config) ->
remoteRefExtra(Config) ->
do_test("remoteRefExtra", Config).
anyOfOneOfAllowedErrorsZeroExtra(Config) ->
do_test("anyOfOneOfAllowedErrorsZeroExtra", Config).
anyOfOneOfAllowedErrorsOneExtra(Config) ->
do_test("anyOfOneOfAllowedErrorsOneExtra", Config).
anyOfOneOfAllowedErrorsInfinityExtra(Config) ->
do_test("anyOfOneOfAllowedErrorsInfinityExtra", Config).
unicodePatternProperties(Config) ->
do_test("unicodePatternProperties", Config).
dateFormat(Config) ->
do_test("dateFormat", Config).