Skip to content

Commit f290e5a

Browse files
extend stringy_numbers to enum, const, uniqueItems
1 parent d9d6a5e commit f290e5a

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

lib/JSON/Schema/Tiny.pm

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,13 @@ sub is_equal ($x, $y, $state = {}) {
11191119
($y, $types[1]) = (0+!!$$y, 'boolean') if $types[1] eq 'reference to SCALAR';
11201120
}
11211121

1122+
if ($STRINGY_NUMBERS) {
1123+
($x, $types[0]) = (0+$x, int(0+$x) == $x ? 'integer' : 'number')
1124+
if $types[0] eq 'string' and looks_like_number($x);
1125+
($y, $types[1]) = (0+$y, int(0+$y) == $y ? 'integer' : 'number')
1126+
if $types[1] eq 'string' and looks_like_number($y);
1127+
}
1128+
11221129
return 0 if $types[0] ne $types[1];
11231130
return 1 if $types[0] eq 'null';
11241131
return $x eq $y if $types[0] eq 'string';
@@ -1387,11 +1394,13 @@ Defaults to false.
13871394
=head2 C<$STRINGY_NUMBERS>
13881395
13891396
When true, any value that is expected to be a number or integer B<in the instance data> may also be
1390-
expressed as a string. This does B<not> apply to the C<const> or C<enum> keywords, but only
1391-
the following keywords:
1397+
expressed as a string. This applies only to the following keywords:
13921398
13931399
=for :list
13941400
* C<type> (where both C<string> and C<number> (and possibly C<integer>) are considered types
1401+
* C<const> and C<enum> (where the string C<"1"> will match with C<"const": 1>)
1402+
* C<uniqueItems> (where strings and numbers are compared numerically to each other, if either or
1403+
both are numeric)
13951404
* C<multipleOf>
13961405
* C<maximum>
13971406
* C<exclusiveMaximum>

t/equality.t

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,33 @@ subtest 'equality, using scalarref booleans' => sub {
122122
}
123123
};
124124

125+
subtest 'equality, using stringy numbers' => sub {
126+
local $JSON::Schema::Tiny::STRINGY_NUMBERS = 1;
127+
128+
foreach my $test (
129+
[ 1, 1, true ],
130+
[ 1, 1.0, true ],
131+
[ 1, '1.0', true ],
132+
[ '1.1', 1.1, true ],
133+
[ '1', 1, true ],
134+
[ '1.1', 1.1, true ],
135+
[ '1', '1.00', true ],
136+
[ '1.10', '1.1000', true ],
137+
[ 'x', 'x', true ],
138+
[ 'x', 'y', false ],
139+
) {
140+
my ($x, $y, $expected, $diff_path) = @$test;
141+
my @types = map JSON::Schema::Tiny::get_type($_), $x, $y;
142+
my $result = JSON::Schema::Tiny::is_equal($x, $y, my $state = {});
143+
144+
ok(!($result xor $expected), json_sprintf('%s == %s is %s', $x, $y, $expected));
145+
is($state->{path}, $diff_path // '', 'two instances differ at the expected place') if not $expected;
146+
147+
ok(JSON::Schema::Tiny::is_type($types[0], $x), 'type of arg 0 was not mutated while making equality check');
148+
ok(JSON::Schema::Tiny::is_type($types[1], $y), 'type of arg 1 was not mutated while making equality check');
149+
150+
note '';
151+
}
152+
};
153+
125154
done_testing;

t/stringy-numbers.t

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,40 @@ foreach my $config (0, 1) {
184184
) if $config == 1;
185185

186186
is(JSON::Schema::Tiny::get_type($data), 'string', 'data was not mutated');
187+
188+
189+
$schema = {
190+
enum => [11, 12],
191+
const => 11,
192+
};
193+
194+
cmp_deeply(
195+
evaluate($data, $schema),
196+
{
197+
valid => false,
198+
errors => [
199+
{
200+
instanceLocation => '',
201+
keywordLocation => '/enum',
202+
error => 'value does not match',
203+
},
204+
{
205+
instanceLocation => '',
206+
keywordLocation => '/const',
207+
error => 'value does not match',
208+
},
209+
],
210+
},
211+
'by default, stringy numbers are not the same as numbers using comparison keywords',
212+
) if $config == 0;
213+
214+
cmp_deeply(
215+
evaluate($data, $schema),
216+
{ valid => true },
217+
'with the config enabled, stringy numbers are the same as numbers using comparison keywords',
218+
) if $config == 1;
219+
220+
is(JSON::Schema::Tiny::get_type($data), 'string', 'data was not mutated');
187221
}
188222

189223
done_testing;

0 commit comments

Comments
 (0)