![](https://seccdn.libravatar.org/avatar/128a7b98d536a9cf9b4d4d5a90d63475.jpg?s=120&d=mm&r=g)
Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package perl-JSON-Validator for openSUSE:Factory checked in at 2021-02-02 14:24:54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/perl-JSON-Validator (Old) and /work/SRC/openSUSE:Factory/.perl-JSON-Validator.new.28504 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Package is "perl-JSON-Validator" Tue Feb 2 14:24:54 2021 rev:28 rq:868344 version:4.13 Changes: -------- --- /work/SRC/openSUSE:Factory/perl-JSON-Validator/perl-JSON-Validator.changes 2021-01-27 18:58:49.344487935 +0100 +++ /work/SRC/openSUSE:Factory/.perl-JSON-Validator.new.28504/perl-JSON-Validator.changes 2021-02-02 14:24:59.339328109 +0100 @@ -1,0 +2,10 @@ +Fri Jan 29 03:08:04 UTC 2021 - Tina M��ller <timueller+perl@suse.de> + +- updated to 4.13 + see /usr/share/doc/packages/perl-JSON-Validator/Changes + + 4.13 2021-01-28T18:22:43+0900 + - Fix handling offset in RFC3339 date-time #236 + - Add CLEAR method to JSON::Validator::Ref #237 + +------------------------------------------------------------------- Old: ---- JSON-Validator-4.12.tar.gz New: ---- JSON-Validator-4.13.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ perl-JSON-Validator.spec ++++++ --- /var/tmp/diff_new_pack.9NvHIv/_old 2021-02-02 14:25:00.047329210 +0100 +++ /var/tmp/diff_new_pack.9NvHIv/_new 2021-02-02 14:25:00.051329216 +0100 @@ -18,7 +18,7 @@ %define cpan_name JSON-Validator Name: perl-JSON-Validator -Version: 4.12 +Version: 4.13 Release: 0 Summary: Validate data against a JSON schema License: Artistic-2.0 ++++++ JSON-Validator-4.12.tar.gz -> JSON-Validator-4.13.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/Changes new/JSON-Validator-4.13/Changes --- old/JSON-Validator-4.12/Changes 2021-01-24 23:52:34.000000000 +0100 +++ new/JSON-Validator-4.13/Changes 2021-01-28 10:22:43.000000000 +0100 @@ -1,5 +1,9 @@ Revision history for perl distribution JSON-Validator +4.13 2021-01-28T18:22:43+0900 + - Fix handling offset in RFC3339 date-time #236 + - Add CLEAR method to JSON::Validator::Ref #237 + 4.12 2021-01-25T07:52:34+0900 - Fix not using Mojo::Exception::raise() #235 - Fix uninitialized warning when looking up schema for an internal $ref diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/MANIFEST new/JSON-Validator-4.13/MANIFEST --- old/JSON-Validator-4.12/MANIFEST 2021-01-24 23:52:36.000000000 +0100 +++ new/JSON-Validator-4.13/MANIFEST 2021-01-28 10:22:44.000000000 +0100 @@ -52,7 +52,6 @@ t/draft6.t t/draft7-acceptance.t t/draft7.t -t/formats.t t/get.t t/Helper.pm t/id-keyword-draft4.t diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/META.json new/JSON-Validator-4.13/META.json --- old/JSON-Validator-4.12/META.json 2021-01-24 23:52:36.000000000 +0100 +++ new/JSON-Validator-4.13/META.json 2021-01-28 10:22:44.000000000 +0100 @@ -63,6 +63,6 @@ }, "x_IRC" : "irc://irc.freenode.net/#mojo" }, - "version" : "4.12", + "version" : "4.13", "x_serialization_backend" : "JSON::PP version 4.04" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/META.yml new/JSON-Validator-4.13/META.yml --- old/JSON-Validator-4.12/META.yml 2021-01-24 23:52:35.000000000 +0100 +++ new/JSON-Validator-4.13/META.yml 2021-01-28 10:22:44.000000000 +0100 @@ -32,5 +32,5 @@ homepage: https://mojolicious.org license: http://www.opensource.org/licenses/artistic-license-2.0 repository: https://github.com/mojolicious/json-validator.git -version: '4.12' +version: '4.13' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/lib/JSON/Validator/Formats.pm new/JSON-Validator-4.13/lib/JSON/Validator/Formats.pm --- old/JSON-Validator-4.12/lib/JSON/Validator/Formats.pm 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/lib/JSON/Validator/Formats.pm 2021-01-28 10:20:53.000000000 +0100 @@ -31,8 +31,10 @@ } sub check_date_time { - my @dt = $_[0] =~ m!^(\d{4})-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d(?:\.\d+)?)(?:Z|([+-])(\d+):(\d+))?$!io; + my @dt = $_[0] =~ m!^(\d{4})-(\d\d)-(\d\d)[T ](\d\d):(\d\d):(\d\d(?:\.\d+)?)(?:Z|([+-])(\d\d):(\d\d))?$!io; return 'Does not match date-time format.' unless @dt; + return 'Time offset hour out of range.' if defined $dt[7] and $dt[7] > 23; + return 'Time offset minute out of range.' if defined $dt[8] and $dt[8] > 59; @dt = map { s/^0//; $_ } reverse @dt[0 .. 5]; $dt[4] -= 1; # month are zero based local $@; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/lib/JSON/Validator/Ref.pm new/JSON-Validator-4.13/lib/JSON/Validator/Ref.pm --- old/JSON-Validator-4.12/lib/JSON/Validator/Ref.pm 2021-01-24 05:50:54.000000000 +0100 +++ new/JSON-Validator-4.13/lib/JSON/Validator/Ref.pm 2021-01-28 00:50:27.000000000 +0100 @@ -31,6 +31,11 @@ return undef; } +sub CLEAR { + my ($self) = @_; + $self->[0] = {}; +} + # Make it look like there is only one key in the hash sub FIRSTKEY { scalar keys %{$_[0][0]}; each %{$_[0][0]} } sub NEXTKEY { each %{$_[0][0]} } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/lib/JSON/Validator.pm new/JSON-Validator-4.13/lib/JSON/Validator.pm --- old/JSON-Validator-4.12/lib/JSON/Validator.pm 2021-01-24 23:52:34.000000000 +0100 +++ new/JSON-Validator-4.13/lib/JSON/Validator.pm 2021-01-28 10:22:43.000000000 +0100 @@ -16,7 +16,7 @@ use constant RECURSION_LIMIT => $ENV{JSON_VALIDATOR_RECURSION_LIMIT} || 100; -our $VERSION = '4.12'; +our $VERSION = '4.13'; our @EXPORT_OK = qw(joi validate_json); our %SCHEMAS = ( @@ -55,8 +55,9 @@ my ($self, $args) = @_; my $cloner; - my $schema = $self->_new_schema($args->{schema} || $self->schema); - my $schema_id = $schema->id || ($self->schema ? $self->schema->id : ''); + my $get_data = $self->can('data') ? 'data' : 'schema'; + my $schema = $self->_new_schema($args->{schema} || $self->$get_data); + my $schema_id = $schema->id; my @topics = ([$schema->data, my $bundle = {}]); # ([$from, $to], ...); if ($args->{replace}) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/Helper.pm new/JSON-Validator-4.13/t/Helper.pm --- old/JSON-Validator-4.12/t/Helper.pm 2020-10-28 02:34:19.000000000 +0100 +++ new/JSON-Validator-4.13/t/Helper.pm 2021-01-28 00:59:36.000000000 +0100 @@ -83,7 +83,8 @@ my ($class, $category, @methods) = @_; my $test_class = "t::test::$category"; eval "require $test_class;1" or die $@; - (note("$category $_"), $test_class->$_) for @methods; + subtest "$category $_", sub { $test_class->$_ } + for @methods; } sub validate_ok { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/bundle.t new/JSON-Validator-4.13/t/bundle.t --- old/JSON-Validator-4.12/t/bundle.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/bundle.t 2021-01-28 00:56:59.000000000 +0100 @@ -6,94 +6,103 @@ my $workdir = path(__FILE__)->to_abs->dirname; my $jv = JSON::Validator->new; -my $bundled; -my $schema - = JSON::Validator::Schema::Draft7->new({ - definitions => {name => {type => 'string'}}, surname => {'$ref' => '#/definitions/name'}, - }); - -is $schema->bundle({replace => 1})->data->{surname}{type}, 'string', "schema->bundle"; - -note 'Run multiple times to make sure _reset() works'; -for my $n (1 .. 3) { - note "[$n] replace=1"; - $bundled = $jv->bundle({ - replace => 1, - schema => {definitions => {name => {type => 'string'}}, surname => {'$ref' => '#/definitions/name'}}, - }); - - is $bundled->{surname}{type}, 'string', "[$n] replace=1"; - - note "[$n] replace=0"; - $bundled = $jv->schema({ - surname => {'$ref' => '#/definitions/name'}, - age => {'$ref' => 'b.json#/definitions/years'}, - definitions => {name => {type => 'string'}}, - B => {id => 'b.json', definitions => {years => {type => 'integer'}}}, - })->bundle; - ok $bundled->{definitions}{name}, "[$n] definitions/name still in definitions"; - is $bundled->{definitions}{name}{type}, 'string', "[$n] definitions/name/type still in definitions"; - is $bundled->{definitions}{years}{type}, 'integer', "[$n] added to definitions"; - isnt $bundled->{age}, $jv->schema->get('/age'), "[$n] new age ref"; - is $bundled->{surname}, $jv->schema->get('/surname'), "[$n] same surname ref"; - is $bundled->{age}{'$ref'}, '#/definitions/years', "[$n] age \$ref point to /definitions/years"; - is $bundled->{surname}{'$ref'}, '#/definitions/name', "[$n] surname \$ref point to /definitions/name"; -} - -is $jv->get([qw(surname type)]), 'string', 'get /surname/$ref'; -is $jv->get('/surname/type'), 'string', 'get /surname/type'; -is $jv->get('/surname/$ref'), undef, 'get /surname/$ref'; -is $jv->schema->get('/surname/type'), 'string', 'schema get /surname/type'; -is $jv->schema->get('/surname/$ref'), '#/definitions/name', 'schema get /surname/$ref'; - -$bundled = $jv->schema('data://main/bundled.json')->bundle; -is_deeply [sort keys %{$bundled->{definitions}}], ['objtype'], 'no dup definitions'; - -note 'definitions in disk spec'; -for my $path ( - ['test-definitions-key.json'], - ['with-deep-mixed-ref.json'], - ['with-deep-mixed-ref.json'], - [File::Spec->updir, 'spec', 'with-deep-mixed-ref.json'], - ) -{ - my $file = path $workdir, 'spec', @$path; - - my @expected = qw(age_json-SHA height unit_json-SHA weight_json-SHA); - $expected[0] = 'age_json-type-SHA' if $path->[0] eq 'test-definitions-key.json'; - - $bundled = $jv->schema($file)->bundle; - is_deeply [sort map { s!-[a-z0-9]{10}$!-SHA!; $_ } keys %{$bundled->{definitions}}], \@expected, - "right definitions in disk spec @$path" - or diag join ', ', sort keys %{$bundled->{definitions}}; -} - -note 'ensure filenames with funny characters not mangled by Mojo::URL'; -my $file3 = path $workdir, 'spec', 'space bundle.json'; -eval { $bundled = $jv->schema($file3)->bundle }; -is $@, '', 'loaded absolute filename with space'; -is $bundled->{properties}{age}{description}, 'Age in years', 'right definitions in disk spec' or diag explain $bundled; - -note 'extract subset of schema'; -$jv->schema('data://main/bundled.json'); -$bundled = $jv->bundle({schema => $jv->get([qw(paths /withdots get)])}); -is_deeply( - $bundled, +subtest 'replace' => sub { + my $schema + = JSON::Validator::Schema::Draft7->new({ + definitions => {name => {type => 'string'}}, surname => {'$ref' => '#/definitions/name'}, + }); + + is $schema->bundle({replace => 1})->data->{surname}{type}, 'string', "schema->bundle"; +}; + +subtest 'Run multiple times to make sure _reset() works' => sub { + for my $n (1 .. 3) { + note "[$n] replace=1"; + my $bundled = $jv->bundle({ + replace => 1, + schema => {definitions => {name => {type => 'string'}}, surname => {'$ref' => '#/definitions/name'}}, + }); + + is $bundled->{surname}{type}, 'string', "[$n] replace=1"; + + note "[$n] replace=0"; + $bundled = $jv->schema({ + surname => {'$ref' => '#/definitions/name'}, + age => {'$ref' => 'b.json#/definitions/years'}, + definitions => {name => {type => 'string'}}, + B => {id => 'b.json', definitions => {years => {type => 'integer'}}}, + })->bundle; + ok $bundled->{definitions}{name}, "[$n] definitions/name still in definitions"; + is $bundled->{definitions}{name}{type}, 'string', "[$n] definitions/name/type still in definitions"; + is $bundled->{definitions}{years}{type}, 'integer', "[$n] added to definitions"; + isnt $bundled->{age}, $jv->schema->get('/age'), "[$n] new age ref"; + is $bundled->{surname}, $jv->schema->get('/surname'), "[$n] same surname ref"; + is $bundled->{age}{'$ref'}, '#/definitions/years', "[$n] age \$ref point to /definitions/years"; + is $bundled->{surname}{'$ref'}, '#/definitions/name', "[$n] surname \$ref point to /definitions/name"; + } +}; + +subtest 'check bundled structure' => sub { + is $jv->get([qw(surname type)]), 'string', 'get /surname/$ref'; + is $jv->get('/surname/type'), 'string', 'get /surname/type'; + is $jv->get('/surname/$ref'), undef, 'get /surname/$ref'; + is $jv->schema->get('/surname/type'), 'string', 'schema get /surname/type'; + is $jv->schema->get('/surname/$ref'), '#/definitions/name', 'schema get /surname/$ref'; + + my $bundled = $jv->schema('data://main/bundled.json')->bundle; + is_deeply [sort keys %{$bundled->{definitions}}], ['objtype'], 'no dup definitions'; +}; + +subtest 'definitions in disk spec' => sub { + for my $path ( + ['test-definitions-key.json'], + ['with-deep-mixed-ref.json'], + ['with-deep-mixed-ref.json'], + [File::Spec->updir, 'spec', 'with-deep-mixed-ref.json'], + ) { - definitions => {objtype => {properties => {propname => {type => 'string'}}, type => 'object'}}, - responses => {200 => {schema => {'$ref' => '#/definitions/objtype'}}} - }, - 'subset of schema was bundled' -) or diag explain $bundled; - -note 'no leaking path'; -my $ref_name_prefix = $workdir; -$ref_name_prefix =~ s![^\w-]!_!g; -$jv->schema(path $workdir, 'spec', 'bundle-no-leaking-filename.json'); -my @definitions = keys %{$bundled->{definitions}}; -ok @definitions, 'definitions are present'; -is_deeply [grep { 0 == index $_, $ref_name_prefix } @definitions], [], 'no leaking of path'; + my $file = path $workdir, 'spec', @$path; + + my @expected = qw(age_json-SHA height unit_json-SHA weight_json-SHA); + $expected[0] = 'age_json-type-SHA' if $path->[0] eq 'test-definitions-key.json'; + + my $bundled = $jv->schema($file)->bundle; + is_deeply [sort map { s!-[a-z0-9]{10}$!-SHA!; $_ } keys %{$bundled->{definitions}}], \@expected, + "right definitions in disk spec @$path" + or diag join ', ', sort keys %{$bundled->{definitions}}; + } +}; + +subtest 'ensure filenames with funny characters not mangled by Mojo::URL' => sub { + my $file3 = path $workdir, 'spec', 'space bundle.json'; + my $bundled = eval { $jv->schema($file3)->bundle }; + is $@, '', 'loaded absolute filename with space'; + is $bundled->{properties}{age}{description}, 'Age in years', 'right definitions in disk spec' + or diag explain $bundled; +}; + +subtest 'extract subset of schema' => sub { + my $bundled = $jv->schema('data://main/bundled.json')->bundle({schema => $jv->get([qw(paths /withdots get)])}); + is_deeply( + $bundled, + { + definitions => {objtype => {properties => {propname => {type => 'string'}}, type => 'object'}}, + responses => {200 => {schema => {'$ref' => '#/definitions/objtype'}}} + }, + 'subset of schema was bundled' + ) or diag explain $bundled; +}; + +subtest 'no leaking path' => sub { + my $bundled = $jv->schema('data://main/bundled.json')->bundle({schema => $jv->get([qw(paths /withdots get)])}); + my $ref_name_prefix = $workdir; + $ref_name_prefix =~ s![^\w-]!_!g; + $jv->schema(path $workdir, 'spec', 'bundle-no-leaking-filename.json'); + my @definitions = keys %{$bundled->{definitions}}; + ok @definitions, 'definitions are present'; + is_deeply [grep { 0 == index $_, $ref_name_prefix } @definitions], [], 'no leaking of path'; +}; done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/coerce.t new/JSON-Validator-4.13/t/coerce.t --- old/JSON-Validator-4.12/t/coerce.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/coerce.t 2021-01-28 00:50:27.000000000 +0100 @@ -5,13 +5,11 @@ my $jv = JSON::Validator->new; my %coerce = (booleans => 1); -is_deeply($jv->coerce(%coerce)->coerce, {booleans => 1}, 'hash is accepted'); +is_deeply($jv->coerce(%coerce)->coerce, {booleans => 1}, 'hash is accepted'); is_deeply($jv->coerce(\%coerce)->coerce, {booleans => 1}, 'hash reference is accepted'); -note 'coerce(1) is here for back compat reasons, even though not documented any more'; -is_deeply($jv->coerce(1)->coerce, {%coerce, numbers => 1, strings => 1}, '1 is accepted'); - note 'make sure input is coerced'; +is_deeply($jv->coerce('booleans,numbers,strings')->coerce, {%coerce, numbers => 1, strings => 1}, '1 is accepted'); my @items = ([boolean => 'true'], [integer => '42'], [number => '4.2']); for my $i (@items) { for my $schema (schemas($i->[0])) { @@ -38,6 +36,6 @@ {type => ['array', $base->{type}]}, {allOf => [$base]}, {anyOf => [{type => 'array'}, $base]}, - {oneOf => [$base, {type => 'array'}]}, + {oneOf => [$base, {type => 'array'}]}, ); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/draft2019-09.t new/JSON-Validator-4.13/t/draft2019-09.t --- old/JSON-Validator-4.12/t/draft2019-09.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/draft2019-09.t 2021-01-28 00:59:36.000000000 +0100 @@ -5,8 +5,10 @@ my $schema = JSON::Validator::Schema::Draft201909->new; t::Helper->schema($schema); -ok $schema->formats->{duration}, 'duration'; -ok $schema->formats->{uuid}, 'uuid'; +subtest 'formats' => sub { + ok $schema->formats->{duration}, 'duration'; + ok $schema->formats->{uuid}, 'uuid'; +}; t::Helper->test(number => qw(basic maximum minimum)); t::Helper->test(array => qw(basic items additional_items contains min_max min_max_contains)); @@ -15,26 +17,28 @@ t::Helper->test(object => qw(additional_properties pattern_properties min_max names)); t::Helper->test(object => qw(dependent_required dependent_schemas unevaluated_properties)); -note 'anchor'; -$schema->data({'$ref' => '#foo', '$defs' => {'A' => {'$anchor' => 'foo', 'type' => 'integer'}}})->resolve; -is $schema->data->{type}, 'integer', 'foo anchor type'; - -note 'recursiveRef, without recursiveAnchor'; -my $jv = JSON::Validator->new->schema('data://main/tree.json'); -$jv->schema('data://main/recursiveRef.json'); -isa_ok $jv->schema, 'JSON::Validator::Schema::Draft201909'; -is $jv->schema->data->{type}, 'object', 'recursiveRef type'; -is $jv->schema->data->{properties}{data}, true, 'recursiveRef properties data'; -is $jv->schema->data->{properties}{children}{items}{type}, 'object', 'recursiveRef properties data items'; -is $jv->schema->data->{properties}{children}{items}{properties}{children}{items}{type}, 'object', 'recursive'; -is_deeply [sort keys %{$jv->store->schemas}], - [qw(data://main/recursiveRef.json data://main/tree.json urn:recursiveRef urn:tree)], 'schemas in the store'; +subtest 'anchor' => sub { + $schema->data({'$ref' => '#foo', '$defs' => {'A' => {'$anchor' => 'foo', 'type' => 'integer'}}})->resolve; + is $schema->data->{type}, 'integer', 'foo anchor type'; +}; + +subtest 'recursiveRef, without recursiveAnchor' => sub { + my $jv = JSON::Validator->new->schema('data://main/tree.json'); + $jv->schema('data://main/recursiveRef.json'); + isa_ok $jv->schema, 'JSON::Validator::Schema::Draft201909'; + is $jv->schema->data->{type}, 'object', 'recursiveRef type'; + is $jv->schema->data->{properties}{data}, true, 'recursiveRef properties data'; + is $jv->schema->data->{properties}{children}{items}{type}, 'object', 'recursiveRef properties data items'; + is $jv->schema->data->{properties}{children}{items}{properties}{children}{items}{type}, 'object', 'recursive'; + is_deeply [sort keys %{$jv->store->schemas}], + [qw(data://main/recursiveRef.json data://main/tree.json urn:recursiveRef urn:tree)], 'schemas in the store'; +}; -{ +subtest 'test caching' => sub { no warnings 'redefine'; local *JSON::Validator::_load_from_data = sub { die 'not cached' }; ok eval { JSON::Validator->new->schema('data://main/tree.json') }, 'cached' or diag $@; -} +}; done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/draft4.t new/JSON-Validator-4.13/t/draft4.t --- old/JSON-Validator-4.12/t/draft4.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/draft4.t 2021-01-28 01:01:06.000000000 +0100 @@ -9,16 +9,19 @@ t::Helper->test(object => qw(basic properties)); t::Helper->test(object => qw(additional_properties pattern_properties min_max)); -note 'exclusiveMaximum'; -schema_validate_ok 2.4, {exclusiveMaximum => true, maximum => 2.4}, E('/', '2.4 >= maximum(2.4)'); +subtest 'exclusiveMaximum' => sub { + schema_validate_ok 2.4, {exclusiveMaximum => true, maximum => 2.4}, E('/', '2.4 >= maximum(2.4)'); +}; -note 'exclusiveMinimum'; -schema_validate_ok 0, {exclusiveMaximum => true, maximum => 0}, E('/', '0 >= maximum(0)'); +subtest 'exclusiveMinimum' => sub { + schema_validate_ok 0, {exclusiveMaximum => true, maximum => 0}, E('/', '0 >= maximum(0)'); +}; -note 'bundle'; -my $bundle = JSON::Validator::Schema::Draft4->new('data://main/spec.json')->bundle; -is $bundle->data->{properties}{name}{'$ref'}, '#/definitions/_name', 'bundle ref'; -is $bundle->data->{'definitions'}{_name}{type}, 'string', 'bundled spec under definitions'; +subtest 'bundle' => sub { + my $bundle = JSON::Validator::Schema::Draft4->new('data://main/spec.json')->bundle; + is $bundle->data->{properties}{name}{'$ref'}, '#/definitions/_name', 'bundle ref'; + is $bundle->data->{'definitions'}{_name}{type}, 'string', 'bundled spec under definitions'; +}; done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/draft6.t new/JSON-Validator-4.13/t/draft6.t --- old/JSON-Validator-4.12/t/draft6.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/draft6.t 2021-01-28 01:01:06.000000000 +0100 @@ -9,12 +9,14 @@ t::Helper->test(object => qw(basic properties)); t::Helper->test(object => qw(additional_properties pattern_properties min_max names)); -note 'exclusiveMaximum'; -schema_validate_ok 2.4, {exclusiveMaximum => 2.4}, E('/', '2.4 >= maximum(2.4)'); -schema_validate_ok 0, {exclusiveMaximum => 0}, E('/', '0 >= maximum(0)'); +subtest 'exclusiveMaximum' => sub { + schema_validate_ok 2.4, {exclusiveMaximum => 2.4}, E('/', '2.4 >= maximum(2.4)'); + schema_validate_ok 0, {exclusiveMaximum => 0}, E('/', '0 >= maximum(0)'); +}; -note 'exclusiveMinimum'; -schema_validate_ok 4.2, {exclusiveMinimum => 4.2}, E('/', '4.2 <= minimum(4.2)'); -schema_validate_ok 0, {exclusiveMinimum => 0}, E('/', '0 <= minimum(0)'); +subtest 'exclusiveMinimum' => sub { + schema_validate_ok 4.2, {exclusiveMinimum => 4.2}, E('/', '4.2 <= minimum(4.2)'); + schema_validate_ok 0, {exclusiveMinimum => 0}, E('/', '0 <= minimum(0)'); +}; done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/draft7.t new/JSON-Validator-4.13/t/draft7.t --- old/JSON-Validator-4.12/t/draft7.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/draft7.t 2021-01-28 01:01:06.000000000 +0100 @@ -10,18 +10,21 @@ t::Helper->test(object => qw(basic properties)); t::Helper->test(object => qw(additional_properties pattern_properties min_max names)); -note 'exclusiveMaximum'; -schema_validate_ok 2.4, {exclusiveMaximum => 2.4}, E('/', '2.4 >= maximum(2.4)'); -schema_validate_ok 0, {exclusiveMaximum => 0}, E('/', '0 >= maximum(0)'); +subtest 'exclusiveMaximum' => sub { + schema_validate_ok 2.4, {exclusiveMaximum => 2.4}, E('/', '2.4 >= maximum(2.4)'); + schema_validate_ok 0, {exclusiveMaximum => 0}, E('/', '0 >= maximum(0)'); +}; -note 'exclusiveMinimum'; -schema_validate_ok 4.2, {exclusiveMinimum => 4.2}, E('/', '4.2 <= minimum(4.2)'); -schema_validate_ok 0, {exclusiveMinimum => 0}, E('/', '0 <= minimum(0)'); +subtest 'exclusiveMinimum' => sub { + schema_validate_ok 4.2, {exclusiveMinimum => 4.2}, E('/', '4.2 <= minimum(4.2)'); + schema_validate_ok 0, {exclusiveMinimum => 0}, E('/', '0 <= minimum(0)'); +}; -note 'bundle'; -my $bundle = JSON::Validator::Schema::Draft7->new('data://main/spec.json')->bundle; -is $bundle->data->{properties}{name}{'$ref'}, '#/$defs/_name', 'bundle ref'; -is $bundle->data->{'$defs'}{_name}{type}, 'string', 'bundled spec under $defs'; +subtest 'bundle' => sub { + my $bundle = JSON::Validator::Schema::Draft7->new('data://main/spec.json')->bundle; + is $bundle->data->{properties}{name}{'$ref'}, '#/$defs/_name', 'bundle ref'; + is $bundle->data->{'$defs'}{_name}{type}, 'string', 'bundled spec under $defs'; +}; done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/formats.t new/JSON-Validator-4.13/t/formats.t --- old/JSON-Validator-4.12/t/formats.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/formats.t 1970-01-01 01:00:00.000000000 +0100 @@ -1,53 +0,0 @@ -use Mojo::Base -strict; -use Test::More; - -BEGIN { use_ok('JSON::Validator::Formats'); } - -note 'byte'; -is JSON::Validator::Formats::check_byte('amh0aG9yc2Vu'), undef, 'byte amh0aG9yc2Vu'; -is JSON::Validator::Formats::check_byte("\0"), 'Does not match byte format.', 'byte null'; - -note 'date'; -is JSON::Validator::Formats::check_date('2019-06-11'), undef, 'date 2019-06-11'; -is JSON::Validator::Formats::check_date('0000-00-00'), 'Month out of range.', 'date 0000-00-00'; -is JSON::Validator::Formats::check_date('0000-01-00'), 'Day out of range.', 'date 0000-01-00'; -is JSON::Validator::Formats::check_date('2014-12-09T20:49:37Z'), 'Does not match date format.', - 'date 2014-12-09T20:49:37Z'; -is JSON::Validator::Formats::check_date('1-1-1'), 'Does not match date format.', 'date 1-1-1'; -is JSON::Validator::Formats::check_date('09-12-2014'), 'Does not match date format.', 'date 09-12-2014'; -is JSON::Validator::Formats::check_date('2014-DEC-09'), 'Does not match date format.', 'date 2014-DEC-09'; -is JSON::Validator::Formats::check_date('2014/04/09'), 'Does not match date format.', 'date 2014/04/09'; - -{ - note 'double'; - local $TODO = 'cannot test double, since input is already rounded'; - is JSON::Validator::Formats::check_double('1.1000000238418599085576943252817727625370025634765626'), undef, 'double'; -} - -note 'email'; -is JSON::Validator::Formats::check_email('doe@example.org'), undef, 'email doe@example.org'; -is JSON::Validator::Formats::check_email('doe'), 'Does not match email format.', 'email doe'; - -note 'float'; -is JSON::Validator::Formats::check_float(-1.10000002384186), undef, 'float -1.10000002384186'; -is JSON::Validator::Formats::check_float(1.10000002384186), undef, 'float 1.10000002384186'; - -note 'int32'; -is JSON::Validator::Formats::check_int32(-2147483648), undef, 'int32 -2147483648'; -is JSON::Validator::Formats::check_int32(2147483647), undef, 'int32 2147483647'; -is JSON::Validator::Formats::check_int32(2147483648), 'Does not match int32 format.', 'int32 2147483648'; - -SKIP: { - note 'int64'; - skip 'Not a 64 bit Perl' unless JSON::Validator::Formats::IV_SIZE >= 8; - is JSON::Validator::Formats::check_int64(-9223372036854775808), undef, 'int64 -9223372036854775808'; - is JSON::Validator::Formats::check_int64(9223372036854775807), undef, 'int64 9223372036854775807'; - is JSON::Validator::Formats::check_int64(9223372036854775808), 'Does not match int64 format.', - 'int64 9223372036854775808'; -} - -note 'time'; -is JSON::Validator::Formats::check_time($_), undef, "time $_" - for qw(23:02:55.831Z 23:02:55.01z 23:02:55-12:00 23:02:55+05:00); - -done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/jv-allof-and-not.t new/JSON-Validator-4.13/t/jv-allof-and-not.t --- old/JSON-Validator-4.12/t/jv-allof-and-not.t 2020-09-28 03:07:46.000000000 +0200 +++ new/JSON-Validator-4.13/t/jv-allof-and-not.t 2021-01-28 01:15:56.000000000 +0100 @@ -1,29 +1,31 @@ use lib '.'; use t::Helper; -note 'Property "required" must be present'; my $missing = E '/required', '/allOf/0 Missing property.'; my $schema = {type => 'object', allOf => [{required => ['required']}]}; - -my @tests = ( +my @tests = ( [{foo => 1, required => 2}, $schema], [{foo => 2, forbidden => 3}, $schema, $missing], [{foo => 3, forbidden => 3, required => 2}, $schema], [{foo => 4}, $schema, $missing] ); -validate_ok @$_ for @tests; - -note 'Property "forbidden" must not be present'; -$schema->{not} = {required => ['forbidden']}; -splice @{$tests[1]}, 2, 0, E '/', 'Should not match.'; -$tests[2][2] = E '/', 'Should not match.'; -validate_ok @$_ for @tests; - -note 'Move "not" constraint to "allOf"'; -push @{$schema->{allOf}}, {not => delete $schema->{not}}; -$tests[1][2] = $tests[2][2] = E '/', '/allOf/1 Should not match.'; -$tests[1][3] = $missing; -validate_ok @$_ for @tests; +subtest 'property "required" must be present' => sub { + validate_ok @$_ for @tests; +}; + +subtest 'Property "forbidden" must not be present' => sub { + $schema->{not} = {required => ['forbidden']}; + splice @{$tests[1]}, 2, 0, E '/', 'Should not match.'; + $tests[2][2] = E '/', 'Should not match.'; + validate_ok @$_ for @tests; +}; + +subtest 'Move "not" constraint to "allOf"' => sub { + push @{$schema->{allOf}}, {not => delete $schema->{not}}; + $tests[1][2] = $tests[2][2] = E '/', '/allOf/1 Should not match.'; + $tests[1][3] = $missing; + validate_ok @$_ for @tests; +}; done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/jv-basic.t new/JSON-Validator-4.13/t/jv-basic.t --- old/JSON-Validator-4.12/t/jv-basic.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/jv-basic.t 2021-01-28 01:28:15.000000000 +0100 @@ -3,13 +3,12 @@ sub j { Mojo::JSON::decode_json(Mojo::JSON::encode_json($_[0])); } -validate_ok j($_), {type => 'any'} for undef, [], {}, 123, 'foo'; +validate_ok j($_), {type => 'any'} for undef, [], {}, 123, 'foo'; validate_ok j(undef), {type => 'null'}; -validate_ok j(1), {type => 'null'}, E('/', 'Expected null - got number.'); +validate_ok j(1), {type => 'null'}, E('/', 'Expected null - got number.'); validate_ok($_, {}) foreach (true, false, 1, 1.2, 'a string', {a => 'b'}, [1, 2, 3]); -note 'TODO! true, false are draft 6+ only'; validate_ok($_, true) foreach (true, false, 1, 1.2, 'a string', {a => 'b'}, [1, 2, 3]); validate_ok($_, false, E('/', 'Should not match.')) foreach (true, false, 1, 1.2, 'a string', {a => 'b'}, [1, 2, 3]); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/jv-formats.t new/JSON-Validator-4.13/t/jv-formats.t --- old/JSON-Validator-4.12/t/jv-formats.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/jv-formats.t 2021-01-28 10:20:53.000000000 +0100 @@ -4,7 +4,13 @@ my $schema = {type => 'object', properties => {v => {type => 'string'}}}; -{ +subtest 'byte' => sub { + local $schema->{properties}{v}{format} = 'byte'; + validate_ok {v => 'amh0aG9yc2Vu'}, $schema; + validate_ok {v => "\0"}, $schema, E('/v', 'Does not match byte format.'); +}; + +subtest 'date' => sub { local $schema->{properties}{v}{format} = 'date'; validate_ok {v => '2014-12-09'}, $schema; validate_ok {v => '0000-00-00'}, $schema, E('/v', 'Month out of range.'); @@ -14,31 +20,48 @@ validate_ok {v => '09-12-2014'}, $schema, E('/v', 'Does not match date format.'); validate_ok {v => '09-DEC-2014'}, $schema, E('/v', 'Does not match date format.'); validate_ok {v => '09/12/2014'}, $schema, E('/v', 'Does not match date format.'); -} +}; -{ +subtest 'date-time' => sub { local $schema->{properties}{v}{format} = 'date-time'; validate_ok {v => $_}, $schema for ('2017-03-29T23:02:55.831Z', '2017-03-29t23:02:55.01z', '2017-03-29 23:02:55-12:00', - '2016-02-29T23:02:55+05:00'); + '2016-02-29T23:02:55+05:00', '2006-01-02 15:04:05+23:59', '2006-01-02 15:04:05-23:59'); - validate_ok {v => 'xxxx-xx-xxtxx:xx:xxz'}, $schema, E('/v', 'Does not match date-time format.'); - validate_ok {v => '2017-03-29\t23:02:55-12:00'}, $schema, E('/v', 'Does not match date-time format.'); - validate_ok {v => '2017-03-29T23:02:60Z'}, $schema, E('/v', 'Second out of range.'); - validate_ok {v => '2017-03-29T23:61:55Z'}, $schema, E('/v', 'Minute out of range.'); - validate_ok {v => '2017-03-29T24:02:55Z'}, $schema, E('/v', 'Hour out of range.'); - validate_ok {v => '2017-03-32T23:02:55Z'}, $schema, E('/v', 'Day out of range.'); - validate_ok {v => '2017-02-30T23:02:55Z'}, $schema, E('/v', 'Day out of range.'); - validate_ok {v => '2017-02-29T23:02:55Z'}, $schema, E('/v', 'Day out of range.'); - validate_ok {v => '2017-03-00T23:02:55Z'}, $schema, E('/v', 'Day out of range.'); - validate_ok {v => '2017-13-29T23:02:55Z'}, $schema, E('/v', 'Month out of range.'); - validate_ok {v => '2017-00-29T23:02:55Z'}, $schema, E('/v', 'Month out of range.'); -} + validate_ok {v => "2017-03-29\t23:02:55-12:00"}, $schema, E('/v', 'Does not match date-time format.'); + validate_ok {v => '2017-03-29T23:02:55+0:0'}, $schema, E('/v', 'Does not match date-time format.'); + validate_ok {v => '2017-03-29T23:02:55+123:00'}, $schema, E('/v', 'Does not match date-time format.'); + validate_ok {v => '2017-03-29\t23:02:55+0:0'}, $schema, E('/v', 'Does not match date-time format.'); + validate_ok {v => '2017-03-29\t23:02:55+123:00'}, $schema, E('/v', 'Does not match date-time format.'); + validate_ok {v => '2017-03-29\t23:02:55-12'}, $schema, E('/v', 'Does not match date-time format.'); + validate_ok {v => '2017-03-29\t23:02:55-12:00'}, $schema, E('/v', 'Does not match date-time format.'); + validate_ok {v => '2017-03-29T23:02:55-12'}, $schema, E('/v', 'Does not match date-time format.'); + validate_ok {v => 'xxxx-xx-xxtxx:xx:xxz'}, $schema, E('/v', 'Does not match date-time format.'); + + validate_ok {v => '2017-03-29T23:02:60Z'}, $schema, E('/v', 'Second out of range.'); + validate_ok {v => '2017-03-29T23:61:55Z'}, $schema, E('/v', 'Minute out of range.'); + validate_ok {v => '2017-03-29T24:02:55Z'}, $schema, E('/v', 'Hour out of range.'); + validate_ok {v => '2017-03-32T23:02:55Z'}, $schema, E('/v', 'Day out of range.'); + validate_ok {v => '2017-02-29T23:02:55Z'}, $schema, E('/v', 'Day out of range.'); + validate_ok {v => '2017-02-30T23:02:55Z'}, $schema, E('/v', 'Day out of range.'); + validate_ok {v => '2017-03-00T23:02:55Z'}, $schema, E('/v', 'Day out of range.'); + validate_ok {v => '2017-00-29T23:02:55Z'}, $schema, E('/v', 'Month out of range.'); + validate_ok {v => '2017-13-29T23:02:55Z'}, $schema, E('/v', 'Month out of range.'); + + validate_ok {v => '2017-03-29T23:02:55+23:60'}, $schema, E('/v', 'Time offset minute out of range.'); + validate_ok {v => '2017-03-29T23:02:55+24:00'}, $schema, E('/v', 'Time offset hour out of range.'); +}; + +subtest 'double' => sub { + local $schema->{properties}{v}{format} = 'double'; + local $TODO = 'cannot test double, since input is already rounded'; + validate_ok {v => '1.1000000238418599085576943252817727625370025634765626'}, $schema; +}; -{ +subtest 'duration' => sub { local $schema->{properties}{v}{format} = 'duration'; - validate_ok {v => 'foo'}, $schema, E('/v', 'Does not match duration format.'); + validate_ok {v => 'foo'}, $schema, E('/v', 'Does not match duration format.'); validate_ok {v => 'P4Y'}, $schema; validate_ok {v => 'PT0S'}, $schema; validate_ok {v => 'P1M'}, $schema; @@ -47,129 +70,151 @@ validate_ok {v => 'PT0,5M'}, $schema; validate_ok {v => 'P23DT23H'}, $schema; validate_ok {v => 'P3Y6M4DT12H30M5S'}, $schema; -} +}; -{ +subtest 'email' => sub { local $schema->{properties}{v}{format} = 'email'; validate_ok {v => 'jhthorsen@cpan.org'}, $schema; validate_ok {v => 'foo'}, $schema, E('/v', 'Does not match email format.'); validate_ok {v => '������@������.������'}, $schema, E('/v', 'Does not match email format.'); -} +}; + +subtest 'float' => sub { + local $schema->{properties}{v}{format} = 'float'; + validate_ok {v => '-1.10000002384186'}, $schema; + validate_ok {v => '1.10000002384186'}, $schema; +}; + +subtest 'int32' => sub { + local $schema->{properties}{v}{format} = 'int32'; + validate_ok {v => '-2147483648'}, $schema; + validate_ok {v => '2147483647'}, $schema; + validate_ok {v => '2147483648'}, $schema, E('/v', 'Does not match int32 format.'); +}; + +subtest 'int64' => sub { + local $schema->{properties}{v}{format} = 'int64'; + local $TODO = 'Not a 64 bit Perl' unless JSON::Validator::Formats::IV_SIZE >= 8; + validate_ok {v => '-9223372036854775808'}, $schema; + validate_ok {v => '9223372036854775807'}, $schema; + validate_ok {v => '9223372036854775808'}, $schema, E('/v', 'Does not match int64 format.'); +}; -{ +subtest 'hostname' => sub { local $TODO = eval 'require Data::Validate::Domain;1' ? undef : 'Missing module'; local $schema->{properties}{v}{format} = 'hostname'; validate_ok {v => 'mojolicio.us'}, $schema; validate_ok {v => '[]'}, $schema, E('/v', 'Does not match hostname format.'); -} +}; -{ +subtest 'idn-email' => sub { validate_ok {v => decode('UTF-8', '������@������.������')}, $schema; local $TODO = eval 'require Net::IDN::Encode;1' ? undef : 'Missing module'; local $schema->{properties}{v}{format} = 'idn-email'; validate_ok {v => decode('UTF-8', '������@')}, $schema, E('/v', 'Does not match idn-email format.'); -} +}; -{ +subtest 'idn-hostname' => sub { local $schema->{properties}{v}{format} = 'idn-hostname'; validate_ok {v => decode('UTF-8', '������.������')}, $schema; -} +}; -{ +subtest 'iri' => sub { local $schema->{properties}{v}{format} = 'iri'; validate_ok {v => 'http://mojolicio.us/?��=123'}, $schema; validate_ok {v => decode('UTF-8', 'https://������.������/�����������')}, $schema; validate_ok {v => '/�����������'}, $schema, E('/v', 'Scheme missing.'); -} +}; -{ +subtest 'iri-reference' => sub { local $schema->{properties}{v}{format} = 'iri-reference'; validate_ok {v => '/�����������'}, $schema; validate_ok {v => '�����������'}, $schema; - validate_ok {v => 'http:///�����������'}, $schema, -} + validate_ok {v => 'http:///�����������'}, $schema,; +}; -{ +subtest 'ipv4' => sub { local $TODO = eval 'require Data::Validate::IP;1' ? undef : 'Missing module'; local $schema->{properties}{v}{format} = 'ipv4'; validate_ok {v => '255.100.30.1'}, $schema; validate_ok {v => '300.0.0.0'}, $schema, E('/v', 'Does not match ipv4 format.'); -} +}; -{ +subtest 'ipv6' => sub { local $TODO = eval 'require Data::Validate::IP;1' ? undef : 'Missing module'; local $schema->{properties}{v}{format} = 'ipv6'; validate_ok {v => '::1'}, $schema; validate_ok {v => '300.0.0.0'}, $schema, E('/v', 'Does not match ipv6 format.'); -} +}; -{ +subtest 'json-pointer' => sub { local $schema->{properties}{v}{format} = 'json-pointer'; validate_ok {v => ''}, $schema; validate_ok {v => '/foo/bar'}, $schema; validate_ok {v => 'foo/bar'}, $schema, E('/v', 'Does not match json-pointer format.'); -} +}; -{ +subtest 'regex' => sub { local $schema->{properties}{v}{format} = 'regex'; validate_ok {v => '(\w+)'}, $schema; validate_ok {v => '(\w'}, $schema, E('/v', 'Does not match regex format.'); -} +}; -{ +subtest 'relative-json-pointer' => sub { local $schema->{properties}{v}{format} = 'relative-json-pointer'; validate_ok {v => '0'}, $schema; validate_ok {v => '42#'}, $schema; validate_ok {v => '100/foo/bar'}, $schema; validate_ok {v => '#'}, $schema, E('/v', 'Relative JSON Pointer must start with a non-negative-integer.'); validate_ok {v => '42foo/bar'}, $schema, E('/v', 'Does not match relative-json-pointer format.'); -} +}; -{ +subtest 'time' => sub { local $schema->{properties}{v}{format} = 'time'; validate_ok {v => $_}, $schema for qw(23:02:55.831Z 23:02:55.01z 23:02:55-12:00 23:02:55+05:00); validate_ok {v => 'xx:xx:xxz'}, $schema, E('/v', 'Does not match time format.'); validate_ok {v => '23:02:60Z'}, $schema, E('/v', 'Second out of range.'); validate_ok {v => '23:61:55Z'}, $schema, E('/v', 'Minute out of range.'); validate_ok {v => '24:02:55Z'}, $schema, E('/v', 'Hour out of range.'); -} +}; -{ +subtest 'uri' => sub { local $schema->{properties}{v}{format} = 'uri'; - validate_ok {v => '//example.com/no-scheme'}, $schema, E('/v', 'Scheme missing.'); - validate_ok {v => ''}, $schema, E('/v', 'Scheme, path or fragment are required.'); - validate_ok {v => '0://mojolicio.us/?x=123'}, $schema, E('/v', 'Scheme must begin with a letter.'); - validate_ok {v => 'http://example.com/%z'}, $schema, E('/v', 'Invalid hex escape.'); - validate_ok {v => 'http://example.com/%a'}, $schema, E('/v', 'Hex escapes are not complete.'); - validate_ok {v => 'http:////'}, $schema, E('/v', 'Path cannot not start with //.'); + validate_ok {v => '//example.com/no-scheme'}, $schema, E('/v', 'Scheme missing.'); + validate_ok {v => ''}, $schema, E('/v', 'Scheme, path or fragment are required.'); + validate_ok {v => '0://mojolicio.us/?x=123'}, $schema, E('/v', 'Scheme must begin with a letter.'); + validate_ok {v => 'http://example.com/%z'}, $schema, E('/v', 'Invalid hex escape.'); + validate_ok {v => 'http://example.com/%a'}, $schema, E('/v', 'Hex escapes are not complete.'); + validate_ok {v => 'http:////'}, $schema, E('/v', 'Path cannot not start with //.'); validate_ok {v => 'http://mojolicio.us/?x=123'}, $schema; + validate_ok {v => '/relative-path'}, $schema; + validate_ok {v => 'relative-path'}, $schema; +}; - note 'TODO: relative paths should only be valid in draft4'; - validate_ok {v => '/relative-path'}, $schema; - validate_ok {v => 'relative-path'}, $schema; -} - -{ +subtest 'uri-reference' => sub { local $schema->{properties}{v}{format} = 'uri-reference'; validate_ok {v => 'http:///whatever'}, $schema; validate_ok {v => '/relative-path'}, $schema; validate_ok {v => 'relative-path'}, $schema; -} +}; -{ +subtest 'uri-template' => sub { local $schema->{properties}{v}{format} = 'uri-template'; validate_ok {v => 'http://mojolicio.us/?x={x}'}, $schema; -} +}; -{ +subtest 'unknown' => sub { + my $warn = 'no warnings seen'; + local $SIG{__WARN__} = sub { $warn = shift }; local $schema->{properties}{v}{format} = 'unknown'; validate_ok {v => 'whatever'}, $schema; -} + like $warn, qr{Format rule for 'unknown' is missing}, 'unknown format cause a warning'; +}; -{ +subtest 'uuid' => sub { local $schema->{properties}{v}{format} = 'uuid'; validate_ok {v => '5782165B-6BB6-A72F-B3DD-369D707D6C72'}, $schema, E('/v', 'Does not match uuid format.'); validate_ok {v => '5782165B-6BB6-472F-B3DD-369D707D6C72'}, $schema; -} +}; done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/jv-object.t new/JSON-Validator-4.13/t/jv-object.t --- old/JSON-Validator-4.12/t/jv-object.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/jv-object.t 2021-01-28 01:24:49.000000000 +0100 @@ -3,13 +3,13 @@ my $schema; -{ +subtest 'basic' => sub { $schema = {type => 'object'}; validate_ok {mynumber => 1}, $schema; validate_ok [1], $schema, E('/', 'Expected object - got array.'); -} +}; -{ +subtest 'patternProperties' => sub { $schema->{properties} = { number => {type => 'number'}, street_name => {type => 'string'}, @@ -24,41 +24,34 @@ validate_ok {number => 1600, street_name => 'Pennsylvania', street_type => 'Avenue', direction => 'NW'}, $schema; validate_ok {'S_25' => 'This is a string', 'I_0' => 42}, $schema; validate_ok {'S_0' => 42}, $schema, E('/S_0', 'Expected string - got number.'); -} +}; -{ - local $TODO = 't/openapi-set-request.t fails because of some oneOf logic'; - my $data = {}; - validate_ok $data, {type => 'object', properties => {number => {type => 'number', default => 42}}}; - is $data->{number}, 42, 'default value was set'; -} - -{ +subtest 'additionalProperties' => sub { local $schema->{additionalProperties} = 0; validate_ok {number => 1600, street_name => 'Pennsylvania', street_type => 'Avenue', direction => 'NW', foo => 'nope'}, $schema, E('/', 'Properties not allowed: direction, foo.'); $schema->{additionalProperties} = {type => 'string'}; validate_ok {number => 1600, street_name => 'Pennsylvania', street_type => 'Avenue', direction => 'NW'}, $schema; -} +}; -{ +subtest 'required' => sub { local $schema->{required} = ['number', 'street_name']; validate_ok {number => 1600, street_type => 'Avenue'}, $schema, E('/street_name', 'Missing property.'); -} +}; -{ +subtest 'minProperties maxProperties' => sub { $schema = {type => 'object', minProperties => 1}; validate_ok {}, $schema, E('/', 'Not enough properties: 0/1.'); $schema = {type => 'object', minProperties => 2, maxProperties => 3}; validate_ok {a => 1}, $schema, E('/', 'Not enough properties: 1/2.'); validate_ok {a => 1, b => 2}, $schema; validate_ok {a => 1, b => 2, c => 3, d => 4}, $schema, E('/', 'Too many properties: 4/3.'); -} +}; -{ +subtest 'dependencies' => sub { $schema = { - type => 'object', + type => 'object', properties => {name => {type => 'string'}, credit_card => {type => 'number'}, billing_address => {type => 'string'}}, required => ['name'], @@ -71,9 +64,9 @@ E('/billing_address', 'Missing property. Dependee: credit_card.'); $schema = { - type => 'object', - properties => {name => {type => 'string'}, credit_card => {type => 'number'}}, - required => ['name'], + type => 'object', + properties => {name => {type => 'string'}, credit_card => {type => 'number'}}, + required => ['name'], dependencies => {credit_card => {properties => {billing_address => {type => 'string'}}, required => ['billing_address']}}, }; @@ -82,70 +75,82 @@ validate_ok {name => 'John Doe', billing_address => '123 Main St'}, $schema; validate_ok {name => 'John Doe', credit_card => 5555555555555555}, $schema, E('/billing_address', 'Missing property.'); -} -{ + $schema = {dependencies => {bar => ['foo']}}; + validate_ok {bar => 2}, $schema, E('/foo', 'Missing property. Dependee: bar.'); + + validate_ok {FOO => 1}, + { + type => 'object', + propertyNames => + {anyOf => [{type => 'string', enum => ['foo', 'bar', 'baz']}, {type => 'string', enum => ['hello']}]}, + additionalProperties => {type => 'integer'}, + }, + E('/', '/propertyName/FOO /anyOf/0 Not in enum list: foo, bar, baz.'), + E('/', '/propertyName/FOO /anyOf/1 Not in enum list: hello.'); +}; + +subtest 'patternProperties' => sub { my $schema = {type => 'object', properties => {name => {type => 'string'}}}; validate_ok {}, $schema; # does not matter ok !$schema->{patternProperties}, 'patternProperties was not added issue#47'; -} +}; -{ +subtest 'propertyNames' => sub { my $schema = {propertyNames => {minLength => 3, maxLength => 5}}; validate_ok {name => 'John', surname => 'Doe'}, $schema, E('/', '/propertyName/surname String is too long: 7/5.'); $schema->{propertyNames}{maxLength} = 7; validate_ok {name => 'John', surname => 'Doe'}, $schema; -} +}; -sub TO_JSON { return {age => shift->{age}} } -my $obj = bless {age => 'not_a_string'}, 'main'; -validate_ok $obj, {properties => {age => {type => 'integer'}}}, - E('/age', 'Expected integer - got string.', 'age is not a string'); - -my $object_constant = {type => 'object', const => {a => 1}}; -validate_ok {a => 1}, $object_constant; -validate_ok {b => 1}, $object_constant, E('/', q{Does not match const: {"a":1}.}); - - -validate_ok {foo => 'bar'}, {type => 'object', required => ['foo'], %$_} foreach { properties => {foo => {}} } -, {additionalProperties => {}}, {patternProperties => {foo => {}}}; - -validate_ok {foo => 'bar'}, {definitions => {my_true_ref => {}}, type => 'object', required => ['foo'], %$_} - foreach { properties => {foo => {'$ref' => '#/definitions/my_true_ref'}} } -, {additionalProperties => {'$ref' => '#/definitions/my_true_ref'}}, - {patternProperties => {foo => {'$ref' => '#/definitions/my_true_ref'}}}; - -# TODO! true, false are draft 6+ only -validate_ok {foo => 'bar'}, {type => 'object', required => ['foo'], %$_} foreach { properties => {foo => true} } -, {additionalProperties => true}, {patternProperties => {foo => true}}; - -validate_ok {foo => 'bar'}, {definitions => {my_true_ref => true}, type => 'object', required => ['foo'], %$_} - foreach { properties => {foo => {'$ref' => '#/definitions/my_true_ref'}} } -, {additionalProperties => {'$ref' => '#/definitions/my_true_ref'}}, - {patternProperties => {foo => {'$ref' => '#/definitions/my_true_ref'}}}; - -validate_ok {foo => 'bar'}, {type => 'object', required => ['foo'], %$_}, E('/foo', 'Should not match.') - foreach { properties => {foo => false} } -, {patternProperties => {foo => false}}; - -validate_ok {foo => 'bar'}, {definitions => {my_false_ref => false}, type => 'object', required => ['foo'], %$_}, - E('/foo', 'Should not match.') - foreach { properties => {foo => {'$ref' => '#/definitions/my_false_ref'}} } -, {additionalProperties => {'$ref' => '#/definitions/my_false_ref'}}, - {patternProperties => {foo => {'$ref' => '#/definitions/my_false_ref'}}}; - -$schema = {dependencies => {bar => ['foo']}}; -validate_ok {bar => 2}, $schema, E('/foo', 'Missing property. Dependee: bar.'); - -validate_ok {FOO => 1}, - { - type => 'object', - propertyNames => - {anyOf => [{type => 'string', enum => ['foo', 'bar', 'baz']}, {type => 'string', enum => ['hello']}]}, - additionalProperties => {type => 'integer'}, - }, - E('/', '/propertyName/FOO /anyOf/0 Not in enum list: foo, bar, baz.'), - E('/', '/propertyName/FOO /anyOf/1 Not in enum list: hello.'); +subtest 'TO_JSON' => sub { + my $obj = bless {age => 'not_a_string'}, 'main'; + validate_ok $obj, {properties => {age => {type => 'integer'}}}, + E('/age', 'Expected integer - got string.', 'age is not a string'); +}; + +subtest 'const' => sub { + my $object_constant = {type => 'object', const => {a => 1}}; + validate_ok {a => 1}, $object_constant; + validate_ok {b => 1}, $object_constant, E('/', q{Does not match const: {"a":1}.}); +}; + +subtest 'boolean schemas' => sub { + validate_ok {foo => 'bar'}, {type => 'object', required => ['foo'], %$_} + for ({properties => {foo => {}}}, {additionalProperties => {}}, {patternProperties => {foo => {}}}); + + validate_ok {foo => 'bar'}, + {definitions => {my_true_ref => {}}, type => 'object', required => ['foo'], %$_} + for ( + {properties => {foo => {'$ref' => '#/definitions/my_true_ref'}}}, + {additionalProperties => {'$ref' => '#/definitions/my_true_ref'}}, + {patternProperties => {foo => {'$ref' => '#/definitions/my_true_ref'}}}, + ); + + validate_ok {foo => 'bar'}, {type => 'object', required => ['foo'], %$_} + for ({properties => {foo => true}}, {additionalProperties => true}, {patternProperties => {foo => true}}); + + validate_ok {foo => 'bar'}, + {definitions => {my_true_ref => true}, type => 'object', required => ['foo'], %$_} + for ( + {properties => {foo => {'$ref' => '#/definitions/my_true_ref'}}}, + {additionalProperties => {'$ref' => '#/definitions/my_true_ref'}}, + {patternProperties => {foo => {'$ref' => '#/definitions/my_true_ref'}}}, + ); + + validate_ok {foo => 'bar'}, {type => 'object', required => ['foo'], %$_}, E('/foo', 'Should not match.') + for ({properties => {foo => false}}, {patternProperties => {foo => false}}); + + validate_ok {foo => 'bar'}, {definitions => {my_false_ref => false}, type => 'object', required => ['foo'], %$_}, + E('/foo', 'Should not match.') + for ( + {properties => {foo => {'$ref' => '#/definitions/my_false_ref'}}}, + {additionalProperties => {'$ref' => '#/definitions/my_false_ref'}}, + {patternProperties => {foo => {'$ref' => '#/definitions/my_false_ref'}}}, + ); +}; done_testing; + +sub TO_JSON { return {age => shift->{age}} } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/load-from-app.t new/JSON-Validator-4.13/t/load-from-app.t --- old/JSON-Validator-4.12/t/load-from-app.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/load-from-app.t 2021-01-28 00:50:27.000000000 +0100 @@ -5,6 +5,7 @@ my $jv = JSON::Validator->new; $jv->ua->server->app(Mojolicious->new); +$jv->ua->server->app->log(Mojo::Log->new->level('fatal')); $jv->ua->server->app->routes->get( '/spec' => sub { my $c = shift; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/openapiv2-basic.t new/JSON-Validator-4.13/t/openapiv2-basic.t --- old/JSON-Validator-4.12/t/openapiv2-basic.t 2021-01-24 05:50:55.000000000 +0100 +++ new/JSON-Validator-4.13/t/openapiv2-basic.t 2021-01-28 01:30:45.000000000 +0100 @@ -7,90 +7,104 @@ my $schema = JSON::Validator::Schema::OpenAPIv2->new; my ($body, @errors); -is $schema->specification, 'http://swagger.io/v2/schema.json', 'specification'; -is_deeply $schema->coerce, {booleans => 1, numbers => 1, strings => 1}, 'default coercion'; +subtest 'basic' => sub { + is $schema->specification, 'http://swagger.io/v2/schema.json', 'specification'; + is_deeply $schema->coerce, {booleans => 1, numbers => 1, strings => 1}, 'default coercion'; + + eval { + my $s = JSON::Validator->new->schema('data://main/spec-resolve-refs.json')->schema->resolve; + is $s->get([qw(paths /user get responses 200 schema type)]), 'object', 'resolved "User"'; + } or do { + diag $@; + ok 0, 'Could not resolve "User"'; + }; -note 'jv->schema'; -$schema = JSON::Validator->new->schema($cwd->child(qw(spec v2-petstore.json)))->schema->resolve; -isa_ok $schema, 'JSON::Validator::Schema::OpenAPIv2'; - -note 'validate schema'; -@errors = @{JSON::Validator->new->schema({swagger => '2.0', paths => {}})->schema->errors}; -is "@errors", '/info: Missing property.', 'invalid schema'; - -note 'parameters_for_request'; -is $schema->parameters_for_request([GET => '/pets/nope']), undef, 'no such path'; -cmp_deeply $schema->parameters_for_request([GET => '/pets']), [superhashof({in => 'query', name => 'limit'})], - 'parameters_for_request inside path'; -cmp_deeply $schema->parameters_for_request([post => '/pets']), - [superhashof({in => 'body', name => 'body', accepts => ['application/json']})], 'parameters_for_request for body'; -cmp_deeply $schema->parameters_for_request([get => '/pets/{petId}']), [superhashof({in => 'path', name => 'petId'})], - 'parameters_for_request inside method'; - -note 'parameters_for_response'; -is $schema->parameters_for_response([GET => '/pets/nope']), undef, 'no such path'; -cmp_deeply $schema->parameters_for_response([GET => '/pets']), - [ - superhashof({in => 'header', name => 'x-next'}), - superhashof({in => 'body', name => 'body', accepts => ['application/json']}), - ], - 'parameters_for_request inside path and default response code'; -cmp_deeply $schema->parameters_for_response([GET => '/pets', 404]), - [superhashof({in => 'body', name => 'body', accepts => ['application/json']})], 'default response'; - -note 'validate_request'; -@errors = $schema->validate_request([get => '/pets'], {query => {limit => 10, foo => '42'}}); -is "@errors", '', 'limit ok, even as string'; - -@errors = $schema->validate_request([get => '/pets'], {query => {limit => 'foo'}}); -is "@errors", '/limit: Expected integer - got string.', 'limit failed'; - -$body = {exists => 0}; -@errors = $schema->validate_request([POST => '/pets'], {body => \&body}); -is "@errors", '/body: Missing property.', 'default content type, but missing body'; -is_deeply $body, {content_type => 'application/json', exists => 0, in => 'body', name => 'body', valid => 0}, - 'input was mutated'; - -$body = {exists => 1, value => {name => 'kitty'}}; -@errors = $schema->validate_request([POST => '/pets'], {body => \&body}); -is "@errors", '/body/id: Missing property.', 'missing id in body'; - -$body = {exists => 1, value => {id => 42, name => 'kitty'}}; -@errors = $schema->validate_request([POST => '/pets'], {body => \&body}); -is "@errors", '', 'valid request body'; -is_deeply $body, - {content_type => 'application/json', exists => 1, in => 'body', name => 'body', valid => 1, value => $body->{value}}, - 'input was mutated'; - -note 'validate_response'; -$body = {exists => 1, value => {id => 42, name => 'kitty'}}; -@errors = $schema->validate_response([POST => '/pets', 201], {}); -is "@errors", '', 'valid response body 201'; - -$body = {exists => 1, value => {code => 42}}; -@errors = $schema->validate_response([post => '/pets', 200], {body => \&body}); -is "@errors", '/body/message: Missing property.', 'valid response body default'; - -note 'validate_response - accept'; -$body = {accept => 'text/plain'}; -@errors = $schema->validate_response([get => '/pets'], {body => \&body}); -is "@errors", '/header/Accept: Expected application/json - got text/plain.', 'invalid accept'; -is_deeply $body, {accept => 'text/plain', content_type => '', in => 'body', name => 'body', valid => 0}, - 'failed to negotiate content type'; - -$body = {accept => 'application/*'}; -@errors = $schema->validate_response([get => '/pets'], {body => \&body}); -is "@errors", '', 'valid accept'; -is_deeply $body, - {accept => 'application/*', content_type => 'application/json', in => 'body', name => 'body', valid => 1}, - 'negotiated content type'; - -eval { - my $schema = JSON::Validator->new->schema('data://main/spec-resolve-refs.json')->schema->resolve; - is $schema->get([qw(paths /user get responses 200 schema type)]), 'object', 'resolved "User"'; -} or do { - diag $@; - ok 0, 'Could not resolve "User"'; + $schema = JSON::Validator->new->schema($cwd->child(qw(spec v2-petstore.json)))->schema->resolve; + isa_ok $schema, 'JSON::Validator::Schema::OpenAPIv2'; +}; + +subtest 'validate schema' => sub { + @errors = @{JSON::Validator->new->schema({swagger => '2.0', paths => {}})->schema->errors}; + is "@errors", '/info: Missing property.', 'invalid schema'; +}; + +subtest 'parameters_for_request' => sub { + is $schema->parameters_for_request([GET => '/pets/nope']), undef, 'no such path'; + cmp_deeply $schema->parameters_for_request([GET => '/pets']), [superhashof({in => 'query', name => 'limit'})], + 'parameters_for_request inside path'; + cmp_deeply $schema->parameters_for_request([post => '/pets']), + [superhashof({in => 'body', name => 'body', accepts => ['application/json']})], 'parameters_for_request for body'; + cmp_deeply $schema->parameters_for_request([get => '/pets/{petId}']), [superhashof({in => 'path', name => 'petId'})], + 'parameters_for_request inside method'; +}; + +subtest 'parameters_for_response' => sub { + is $schema->parameters_for_response([GET => '/pets/nope']), undef, 'no such path'; + cmp_deeply $schema->parameters_for_response([GET => '/pets']), + [ + superhashof({in => 'header', name => 'x-next'}), + superhashof({in => 'body', name => 'body', accepts => ['application/json']}), + ], + 'parameters_for_request inside path and default response code'; + cmp_deeply $schema->parameters_for_response([GET => '/pets', 404]), + [superhashof({in => 'body', name => 'body', accepts => ['application/json']})], 'default response'; +}; + +subtest 'validate_request' => sub { + @errors = $schema->validate_request([get => '/pets'], {query => {limit => 10, foo => '42'}}); + is "@errors", '', 'limit ok, even as string'; + + @errors = $schema->validate_request([get => '/pets'], {query => {limit => 'foo'}}); + is "@errors", '/limit: Expected integer - got string.', 'limit failed'; + + $body = {exists => 0}; + @errors = $schema->validate_request([POST => '/pets'], {body => \&body}); + is "@errors", '/body: Missing property.', 'default content type, but missing body'; + is_deeply $body, {content_type => 'application/json', exists => 0, in => 'body', name => 'body', valid => 0}, + 'input was mutated'; + + $body = {exists => 1, value => {name => 'kitty'}}; + @errors = $schema->validate_request([POST => '/pets'], {body => \&body}); + is "@errors", '/body/id: Missing property.', 'missing id in body'; + + $body = {exists => 1, value => {id => 42, name => 'kitty'}}; + @errors = $schema->validate_request([POST => '/pets'], {body => \&body}); + is "@errors", '', 'valid request body'; + is_deeply $body, + { + content_type => 'application/json', + exists => 1, + in => 'body', + name => 'body', + valid => 1, + value => $body->{value} + }, + 'input was mutated'; +}; + +subtest 'validate_response' => sub { + $body = {exists => 1, value => {id => 42, name => 'kitty'}}; + @errors = $schema->validate_response([POST => '/pets', 201], {}); + is "@errors", '', 'valid response body 201'; + + $body = {exists => 1, value => {code => 42}}; + @errors = $schema->validate_response([post => '/pets', 200], {body => \&body}); + is "@errors", '/body/message: Missing property.', 'valid response body default'; +}; + +subtest 'validate_response - accept' => sub { + $body = {accept => 'text/plain'}; + @errors = $schema->validate_response([get => '/pets'], {body => \&body}); + is "@errors", '/header/Accept: Expected application/json - got text/plain.', 'invalid accept'; + is_deeply $body, {accept => 'text/plain', content_type => '', in => 'body', name => 'body', valid => 0}, + 'failed to negotiate content type'; + + $body = {accept => 'application/*'}; + @errors = $schema->validate_response([get => '/pets'], {body => \&body}); + is "@errors", '', 'valid accept'; + is_deeply $body, + {accept => 'application/*', content_type => 'application/json', in => 'body', name => 'body', valid => 1}, + 'negotiated content type'; }; done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/openapiv3-basic.t new/JSON-Validator-4.13/t/openapiv3-basic.t --- old/JSON-Validator-4.12/t/openapiv3-basic.t 2021-01-24 05:50:55.000000000 +0100 +++ new/JSON-Validator-4.13/t/openapiv3-basic.t 2021-01-28 01:30:45.000000000 +0100 @@ -8,89 +8,102 @@ my $schema = JSON::Validator::Schema::OpenAPIv3->new; my ($body, $p, @errors); -is $schema->specification, 'https://spec.openapis.org/oas/3.0/schema/2019-04-02', 'specification'; -is_deeply $schema->coerce, {booleans => 1, numbers => 1, strings => 1}, 'default coercion'; - -note 'jv->schema'; -$schema = JSON::Validator->new->schema($cwd->child(qw(spec v3-petstore.json)))->schema; -isa_ok $schema, 'JSON::Validator::Schema::OpenAPIv3'; - -note 'validate schema'; -@errors = @{JSON::Validator->new->schema({openapi => '3.0.0', paths => {}})->schema->errors}; -is "@errors", '/info: Missing property.', 'invalid schema'; - -note 'parameters_for_request'; -is $schema->parameters_for_request([GET => '/pets/nope']), undef, 'no such path'; -cmp_deeply $schema->parameters_for_request([GET => '/pets']), [superhashof({in => 'query', name => 'limit'})], - 'parameters_for_request inside path'; - -cmp_deeply $schema->parameters_for_request([post => '/pets']), - [ - superhashof({in => 'cookie', name => 'debug'}), - superhashof({in => 'body', name => 'body', accepts => [qw(application/json application/x-www-form-urlencoded)]}) - ], - 'parameters_for_request for body'; -cmp_deeply $schema->parameters_for_request([get => '/pets/{petId}']), - [superhashof({in => 'path', name => 'petId'}), superhashof({in => 'query', name => 'wantAge'})], - 'parameters_for_request inside method'; - -note 'parameters_for_response'; -is $schema->parameters_for_response([GET => '/pets/nope']), undef, 'no such path'; -cmp_deeply $schema->parameters_for_response([GET => '/pets']), - [ - superhashof({in => 'header', name => 'x-next'}), - superhashof({in => 'body', name => 'body', accepts => [qw(application/json application/xml)]}), - ], - 'parameters_for_request inside path and default response code'; -cmp_deeply $schema->parameters_for_response([GET => '/pets', 404]), - [superhashof({in => 'body', name => 'body', accepts => [qw(application/json application/xml)]})], 'default response'; - -note 'validate_request'; -$p = Mojo::Parameters->new('limit=10&foo=42'); -@errors = $schema->validate_request([get => '/pets'], {query => $p->to_hash}); -is "@errors", '', 'limit ok, even as string'; - -@errors = $schema->validate_request([get => '/pets'], {query => {limit => 'foo'}}); -is "@errors", '/limit: Expected integer - got string.', 'limit failed'; - -$body = {exists => 0}; -@errors = $schema->validate_request([POST => '/pets'], {body => \&body}); -is "@errors", '/body: Missing property.', 'default content type, but missing body'; -is_deeply $body, {content_type => 'application/json', exists => 0, in => 'body', name => 'body'}, 'input was mutated'; - -$body = {exists => 1, value => {name => 'kitty'}}; -@errors = $schema->validate_request([POST => '/pets'], {body => \&body}); -is "@errors", '/body/id: Missing property.', 'missing id in body'; - -$body = {exists => 1, value => {id => 42, name => 'kitty'}}; -@errors = $schema->validate_request([POST => '/pets'], {body => \&body}); -is "@errors", '', 'valid request body'; -is_deeply $body, - {content_type => 'application/json', exists => 1, in => 'body', name => 'body', valid => 1, value => $body->{value}}, - 'input was mutated'; - -note 'validate_response'; -$body = {exists => 1, value => {id => 42, name => 'kitty'}}; -@errors = $schema->validate_response([POST => '/pets', 201], {}); -is "@errors", '', 'valid response body 201'; - -$body = {exists => 1, value => {code => 42}}; -@errors = $schema->validate_response([post => '/pets', 200], {body => \&body}); -is "@errors", '/body/message: Missing property.', 'valid response body default'; - -note 'validate_response - accept'; -$body = {accept => 'text/plain'}; -@errors = $schema->validate_response([get => '/pets'], {body => \&body}); -is "@errors", '/header/Accept: Expected application/json, application/xml - got text/plain.', 'invalid accept'; -is_deeply $body, {accept => 'text/plain', content_type => '', in => 'body', name => 'body', valid => 0}, - 'failed to negotiate content type'; - -$body = {accept => 'application/*'}; -@errors = $schema->validate_response([get => '/pets'], {body => \&body}); -is "@errors", '', 'valid accept'; -is_deeply $body, - {accept => 'application/*', content_type => 'application/json', in => 'body', name => 'body', valid => 1}, - 'negotiated content type'; +subtest 'basic' => sub { + is $schema->specification, 'https://spec.openapis.org/oas/3.0/schema/2019-04-02', 'specification'; + is_deeply $schema->coerce, {booleans => 1, numbers => 1, strings => 1}, 'default coercion'; + + $schema = JSON::Validator->new->schema($cwd->child(qw(spec v3-petstore.json)))->schema; + isa_ok $schema, 'JSON::Validator::Schema::OpenAPIv3'; + + @errors = @{JSON::Validator->new->schema({openapi => '3.0.0', paths => {}})->schema->errors}; + is "@errors", '/info: Missing property.', 'invalid schema'; +}; + +subtest 'parameters_for_request' => sub { + is $schema->parameters_for_request([GET => '/pets/nope']), undef, 'no such path'; + cmp_deeply $schema->parameters_for_request([GET => '/pets']), [superhashof({in => 'query', name => 'limit'})], + 'parameters_for_request inside path'; + + cmp_deeply $schema->parameters_for_request([post => '/pets']), + [ + superhashof({in => 'cookie', name => 'debug'}), + superhashof({in => 'body', name => 'body', accepts => [qw(application/json application/x-www-form-urlencoded)]}) + ], + 'parameters_for_request for body'; + cmp_deeply $schema->parameters_for_request([get => '/pets/{petId}']), + [superhashof({in => 'path', name => 'petId'}), superhashof({in => 'query', name => 'wantAge'})], + 'parameters_for_request inside method'; +}; + +subtest 'parameters_for_response' => sub { + is $schema->parameters_for_response([GET => '/pets/nope']), undef, 'no such path'; + cmp_deeply $schema->parameters_for_response([GET => '/pets']), + [ + superhashof({in => 'header', name => 'x-next'}), + superhashof({in => 'body', name => 'body', accepts => [qw(application/json application/xml)]}), + ], + 'parameters_for_request inside path and default response code'; + cmp_deeply $schema->parameters_for_response([GET => '/pets', 404]), + [superhashof({in => 'body', name => 'body', accepts => [qw(application/json application/xml)]})], + 'default response'; +}; + +subtest 'validate_request' => sub { + $p = Mojo::Parameters->new('limit=10&foo=42'); + @errors = $schema->validate_request([get => '/pets'], {query => $p->to_hash}); + is "@errors", '', 'limit ok, even as string'; + + @errors = $schema->validate_request([get => '/pets'], {query => {limit => 'foo'}}); + is "@errors", '/limit: Expected integer - got string.', 'limit failed'; + + $body = {exists => 0}; + @errors = $schema->validate_request([POST => '/pets'], {body => \&body}); + is "@errors", '/body: Missing property.', 'default content type, but missing body'; + is_deeply $body, {content_type => 'application/json', exists => 0, in => 'body', name => 'body'}, 'input was mutated'; + + $body = {exists => 1, value => {name => 'kitty'}}; + @errors = $schema->validate_request([POST => '/pets'], {body => \&body}); + is "@errors", '/body/id: Missing property.', 'missing id in body'; + + $body = {exists => 1, value => {id => 42, name => 'kitty'}}; + @errors = $schema->validate_request([POST => '/pets'], {body => \&body}); + is "@errors", '', 'valid request body'; + is_deeply $body, + { + content_type => 'application/json', + exists => 1, + in => 'body', + name => 'body', + valid => 1, + value => $body->{value} + }, + 'input was mutated'; +}; + +subtest 'validate_response' => sub { + $body = {exists => 1, value => {id => 42, name => 'kitty'}}; + @errors = $schema->validate_response([POST => '/pets', 201], {}); + is "@errors", '', 'valid response body 201'; + + $body = {exists => 1, value => {code => 42}}; + @errors = $schema->validate_response([post => '/pets', 200], {body => \&body}); + is "@errors", '/body/message: Missing property.', 'valid response body default'; +}; + +subtest 'validate_response - accept' => sub { + $body = {accept => 'text/plain'}; + @errors = $schema->validate_response([get => '/pets'], {body => \&body}); + is "@errors", '/header/Accept: Expected application/json, application/xml - got text/plain.', 'invalid accept'; + is_deeply $body, {accept => 'text/plain', content_type => '', in => 'body', name => 'body', valid => 0}, + 'failed to negotiate content type'; + + $body = {accept => 'application/*'}; + @errors = $schema->validate_response([get => '/pets'], {body => \&body}); + is "@errors", '', 'valid accept'; + is_deeply $body, + {accept => 'application/*', content_type => 'application/json', in => 'body', name => 'body', valid => 1}, + 'negotiated content type'; +}; done_testing; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/random-errors.t new/JSON-Validator-4.13/t/random-errors.t --- old/JSON-Validator-4.12/t/random-errors.t 2020-10-13 05:31:27.000000000 +0200 +++ new/JSON-Validator-4.13/t/random-errors.t 2021-01-28 01:32:29.000000000 +0100 @@ -12,10 +12,10 @@ prop1 => {type => [qw(string null)]}, prop2 => {type => [qw(string null)], format => 'ipv4'}, prop3 => {type => [qw(string null)], format => 'ipv4'}, - prop4 => {type => 'string', enum => [qw(foo bar)]}, + prop4 => {type => 'string', enum => [qw(foo bar)]}, prop5 => {type => [qw(string null)]}, prop6 => {type => 'string'}, - prop7 => {type => 'string', enum => [qw(foo bar)]}, + prop7 => {type => 'string', enum => [qw(foo bar)]}, prop8 => {type => [qw(string null)], format => 'ipv4'}, prop9 => {type => [qw(string null)]}, }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/JSON-Validator-4.12/t/ref.t new/JSON-Validator-4.13/t/ref.t --- old/JSON-Validator-4.12/t/ref.t 2020-10-31 01:53:05.000000000 +0100 +++ new/JSON-Validator-4.13/t/ref.t 2021-01-28 00:50:27.000000000 +0100 @@ -25,6 +25,18 @@ } ); +test( + 'ref clear', + {'$ref' => '#/inner', b => 2, foo => 44}, + {'$ref' => '#/main', a => 1, foo => 42}, + undef, + sub { + my ($ref, $tied) = @_; + %$ref = (); + pass 'still alive'; + } +); + done_testing; sub test {