File Coverage

blib/lib/JSON/Validator/Error.pm
Criterion Covered Total %
statement 15 16 93.7
branch 6 6 100.0
condition 2 2 100.0
subroutine 5 6 83.3
pod 2 3 66.6
total 30 33 90.9


line stmt bran cond sub pod time code
1             package JSON::Validator::Error;
2 48     48   272 use Mojo::Base -base;
  48         78  
  48         244  
3              
4 48     48   7385 use overload q("") => \&to_string, bool => sub {1}, fallback => 1;
  48     0   78  
  48         494  
  0         0  
5              
6             our $MESSAGES = {
7             allOf => {type => '/allOf Expected %3 - got %4.'},
8             anyOf => {type => '/anyOf Expected %3 - got %4.'},
9             array => {
10             additionalItems => 'Invalid number of items: %3/%4.',
11             maxItems => 'Too many items: %3/%4.',
12             minItems => 'Not enough items: %3/%4.',
13             uniqueItems => 'Unique items required.',
14             },
15             const => {const => 'Does not match const: %3.'},
16             enum => {enum => 'Not in enum list: %3.'},
17             integer => {
18             ex_maximum => '%3 >= maximum(%4)',
19             ex_minimum => '%3 <= minimum(%4)',
20             maximum => '%3 > maximum(%4)',
21             minimum => '%3 < minimum(%4)',
22             multipleOf => 'Not multiple of %3.',
23             },
24             not => {not => 'Should not match.'},
25             null => {null => 'Not null.'},
26             number => {
27             ex_maximum => '%3 >= maximum(%4)',
28             ex_minimum => '%3 <= minimum(%4)',
29             maximum => '%3 > maximum(%4)',
30             minimum => '%3 < minimum(%4)',
31             multipleOf => 'Not multiple of %3.',
32             },
33             object => {
34             additionalProperties => 'Properties not allowed: %3.',
35             maxProperties => 'Too many properties: %3/%4.',
36             minProperties => 'Not enough properties: %3/%4.',
37             required => 'Missing property.',
38             },
39             oneOf => {
40             all_rules_match => 'All of the oneOf rules match.',
41             n_rules_match => 'oneOf rules %3 match.',
42             type => '/oneOf Expected %3 - got %4.',
43             },
44             string => {
45             pattern => 'String does not match %3.',
46             maxLength => 'String is too long: %3/%4.',
47             minLength => 'String is too short: %3/%4.',
48             }
49             };
50              
51             has details => sub { [qw(generic generic)] };
52              
53             has message => sub {
54             my $self = shift;
55             my $details = $self->details;
56             my $message;
57              
58             if (($details->[0] || '') eq 'format') {
59             $message = '%3';
60             }
61             elsif (($details->[1] || '') eq 'type' and @$details == 3) {
62             $message = 'Expected %1 - got %3.';
63             }
64             elsif (my $group = $MESSAGES->{$details->[0]}) {
65             $message = $group->{$details->[1] || 'default'};
66             }
67              
68             return join ' ', Failed => @$details unless defined $message;
69              
70             $message =~ s!\%(\d)\b!{$details->[$1 - 1] // ''}!ge;
71             return $message;
72             };
73              
74             has path => '/';
75              
76             sub new {
77 665     665 1 2043 my $class = shift;
78              
79             # Constructed with attributes
80 665 100       1912 return $class->SUPER::new($_[0]) if ref $_[0] eq 'HASH';
81              
82             # Constructed with ($path, ...)
83 664         1968 my $self = $class->SUPER::new;
84 664   100     5867 $self->{path} = shift || '/';
85              
86             # Constructed with ($path, $message)
87 664 100       1972 $self->message(shift) unless ref $_[0];
88              
89             # Constructed with ($path, \@details)
90 664 100       3619 $self->details(shift) if ref $_[0];
91              
92 664         4189 return $self;
93             }
94              
95 311     311 1 4441 sub to_string { sprintf '%s: %s', $_[0]->path, $_[0]->message }
96 335     335 0 3190 sub TO_JSON { {message => $_[0]->message, path => $_[0]->path} }
97              
98             1;
99              
100             =encoding utf8
101              
102             =head1 NAME
103              
104             JSON::Validator::Error - JSON::Validator error object
105              
106             =head1 SYNOPSIS
107              
108             use JSON::Validator::Error;
109             my $err = JSON::Validator::Error->new($path, $message);
110              
111             =head1 DESCRIPTION
112              
113             L is a class representing validation errors from
114             L.
115              
116             =head1 ATTRIBUTES
117              
118             =head2 details
119              
120             my $error = $error->details(["generic", "generic"]);
121             my $error = $error->details([qw(array type object)]);
122             my $error = $error->details([qw(format date-time Invalid)]);
123             my $array_ref = $error->details;
124              
125             Details about the error:
126              
127             =over 2
128              
129             =item 1.
130              
131             Often the category of tests that was run. Example values: allOf, anyOf, array,
132             const, enum, format, integer, not, null, number, object, oneOf and string.
133              
134             =item 2.
135              
136             Often the test that failed. Example values: additionalItems,
137             additionalProperties, const, enum, maxItems, maxLength, maxProperties, maximum,
138             minItems, minLength. minProperties, minimum, multipleOf, not, null, pattern,
139             required, type and uniqueItems,
140              
141             =item 3.
142              
143             The rest of the list contains parameters for the test that failed. It can be a
144             plain human-readable string or numbers indicating things such as max/min
145             values.
146              
147             =back
148              
149             =head2 message
150              
151             my $str = $error->message;
152              
153             A human readable description of the error. Defaults to being being constructed
154             from L. See the C<$MESSAGES> variable in the source code for more
155             details.
156              
157             As an EXPERIMENTAL hack you can localize C<$JSON::Validator::Error::MESSAGES>
158             to get i18n support. Example:
159              
160             sub validate_i18n {
161             local $JSON::Validator::Error::MESSAGES = {
162             allOf => {type => '/allOf Forventet %3 - fikk %4.'},
163             };
164              
165             my @error_norwegian = $jv->validate({age => 42});
166             }
167              
168             Note that the error messages might contain a mix of English and the local
169             language. Run some tests to see how it looks.
170              
171             =head2 path
172              
173             my $str = $error->path;
174              
175             A JSON pointer to where the error occurred. Defaults to "/".
176              
177             =head1 METHODS
178              
179             =head2 new
180              
181             my $error = JSON::Validator::Error->new(\%attributes);
182             my $error = JSON::Validator::Error->new($path, \@details);
183             my $error = JSON::Validator::Error->new($path, \@details);
184              
185             Object constructor.
186              
187             =head2 to_string
188              
189             my $str = $error->to_string;
190              
191             Returns the "path" and "message" part as a string: "$path: $message".
192              
193             =head1 OPERATORS
194              
195             L overloads the following operators:
196              
197             =head2 bool
198              
199             my $bool = !!$error;
200              
201             Always true.
202              
203             =head2 stringify
204              
205             my $str = "$error";
206              
207             Alias for L.
208              
209             =head1 SEE ALSO
210              
211             L.
212              
213             =cut