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+p...@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('d...@example.org'), undef,           
               'email d...@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 => 'jhthor...@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 {

Reply via email to