File Coverage

blib/lib/JSV/Keyword/Draft4/Properties.pm
Criterion Covered Total %
statement 47 47 100.0
branch 10 10 100.0
condition 9 10 90.0
subroutine 7 7 100.0
pod 0 2 0.0
total 73 76 96.0


line stmt bran cond sub pod time code
1             package JSV::Keyword::Draft4::Properties;
2              
3 47     47   38421 use strict;
  47         104  
  47         1371  
4 47     47   285 use warnings;
  47         97  
  47         1459  
5 47     47   242 use parent qw(JSV::Keyword);
  47         100  
  47         279  
6              
7 47     47   2794 use JSV::Keyword qw(:constants);
  47         106  
  47         5986  
8 47     47   263 use JSV::Util::Type qw(detect_instance_type escape_json_pointer);
  47         97  
  47         28882  
9              
10             sub instance_type() { INSTANCE_TYPE_OBJECT(); }
11             sub keyword() { 'properties' }
12 328     328 0 1162 sub additional_keywords() { [qw/additionalProperties patternProperties/]; }
13             sub keyword_priority() { 10; }
14              
15             sub validate {
16 226     226 0 430 my ($class, $context, $schema, $instance) = @_;
17              
18 226   100     702 my $properties = $class->keyword_value($schema) || {};
19 226   100     687 my $pattern_properties = $class->keyword_value($schema, "patternProperties") || {};
20              
21 226         425 my @patterns = ();
22 226         351 my @pattern_schemas = ();
23 226         389 my @original_patterns = ();
24 226         713 for my $pattern (keys %$pattern_properties) {
25 49         473 push(@patterns, qr/$pattern/);
26 49         108 push(@pattern_schemas, $pattern_properties->{$pattern});
27 49         108 push(@original_patterns, $pattern);
28             }
29              
30 226         743 my $additional_properties = $class->keyword_value($schema, "additionalProperties");
31 226         908 my $additional_properties_type = detect_instance_type($schema->{additionalProperties});
32 226         836 my %s = map { $_ => undef } keys %$instance;
  403         1127  
33              
34 226         659 for my $property (keys %$instance) {
35 403         1438 local $context->{current_pointer} = $context->{current_pointer} . "/" . escape_json_pointer( $property );
36              
37 403 100       1102 if (exists $properties->{$property}) {
38             local $context->{current_schema_pointer} =
39 283         869 $context->{current_schema_pointer} . "/properties/" . escape_json_pointer( $property );
40 283         1164 $context->validate($properties->{$property}, $instance->{$property});
41 283         769 delete $s{$property};
42             }
43              
44 403         1302 for (my $i = 0, my $l = scalar(@patterns); $i < $l; $i++) {
45 49 100       324 next unless ($property =~ m/$patterns[$i]/);
46             local $context->{current_schema_pointer} =
47 19         71 $context->{current_schema_pointer} . "/patternProperties/" . escape_json_pointer( $original_patterns[$i] );
48 19         99 $context->validate($pattern_schemas[$i], $instance->{$property});
49 19         79 delete $s{$property};
50             }
51              
52 403 100 100     1892 if (exists $s{$property} && $additional_properties_type eq "object") {
53             local $context->{current_schema_pointer} =
54 13         44 $context->{current_schema_pointer} . "/additionalProperties";
55 13         63 $context->validate($additional_properties, $instance->{$property});
56             }
57             }
58              
59 226 100 66     1369 if ($additional_properties_type eq "boolean" && !$additional_properties) {
60 16 100       174 if (keys %s > 0) {
61             # TODO: provide pointer for each extra property
62             # (to avoid parsing error message and don't depend on its format)
63 6         54 $context->log_error(sprintf("Not allowed properties exist (properties: %s)", join(", ", keys %s)));
64             }
65             }
66             }
67              
68             1;