Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpanfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ requires 'URI::Split';
on 'test' => sub {
requires 'Test::More', '0.98';
requires 'Test::Requires';
requires 'Test::Output';
};

2 changes: 1 addition & 1 deletion lib/JSV.pm
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ JSV - A perl implementation of JSON Schema (draft-04) validator

=head1 DESCRIPTION

See e.g. L<JSV::Validator>
See L<JSV::Validator> (module) and L<jsv> (command line script).

=head1 LICENSE

Expand Down
119 changes: 119 additions & 0 deletions script/jsv
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long;
use Pod::Usage;
use JSV::Validator;
use JSON;

my %opt;
GetOptions(
\%opt,
'color|c!',
'help|h|?',
'schema|s=s',
'quiet|q!',
) or pod2usage( -exitval => 1, indent => 2 );
pod2usage( -exitval => 0, indent => 2 ) if $opt{help};

$opt{color} = -t STDOUT unless defined $opt{color}; ## no critic

sub read_json {
my $file = shift;
my $fh;
if ($file eq '-') {
$fh = *STDIN;
} elsif( !open($fh, "<", $file) ) {
print STDERR "failed to open $file\n";
exit 3;
}
local $/;
my $json = eval { JSON->new->decode(<$fh>) } or do {
print STDERR "failed to parse $file\n";
exit 2;
};
$json;
}

JSV::Validator->load_environments("draft4");
my $jsv = JSV::Validator->new( environment => "draft4" );

my $schema = $opt{schema} ? read_json($opt{schema}) : { };

my $error=0;
foreach my $file ( @ARGV ? @ARGV : '-' ) {
my $instance = read_json($file);
my $result = $jsv->validate($schema, $instance);
unless ($opt{quiet}) {
my $valid = $result ? 'valid ' : 'invalid';
if ($opt{color}) {
$valid = ($result ? "\e[0;32m" : "\e[1;31m") . $valid . "\e[0m";
}
print "$valid $file\n";
}
$error = 1 unless $result;
}

exit $error;

=head1 NAME

jsv - validate JSON files against JSON Schema

=head1 SYNOPSIS

jsv -s schema.json [ file1.json file2.json ... | < file.json ]

=head1 USAGE

This script validates JSON against a JSON Schema.

=head2 Exit codes

=over

=item 0

JSON is valid

=item 1

JSON is invalid

=item 2

JSON could not be parsed

=item 3

input file not found or not readable

=back

=head1 OPTIONS

=over

=item --schema|-s FILE

JSON Schema file to validate with. Use C<-> for STDIN

=item --color|-c

Show validation result in color (default). Disable with C<--no-color>

=item --quiet

Don't output validation result

=item --help|-h|-?

show this help

=back

=head1 SEE ALSO

L<JSV::Validator>

=cut
34 changes: 34 additions & 0 deletions t/05_script.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use strict;
use warnings;

use Test::More;
use Test::Output;

my $exit;
sub jsv {
system($^X, 'script/jsv', @_); $exit = $? >> 8
}

output_like { jsv '-h' } qr/^Usage:\n jsv /m, qr/^$/, 'help';
is $exit, 0, 'no error';

output_is { jsv 't/script/file6.json' }
"", "failed to open t/script/file6.json\n";
is $exit, 3, 'missing file';

output_is { jsv 't/script/file5.json' }
"", "failed to parse t/script/file5.json\n";
is $exit, 2, 'JSON broken';

output_is { jsv '-s', 't/script/schema.json', map { "t/script/file$_.json" } 1..4 }
"invalid t/script/file1.json\n".
"valid t/script/file2.json\n".
"valid t/script/file3.json\n".
"invalid t/script/file4.json\n",
"";
is $exit, 1, 'JSON invalid';

output_is { jsv '-s', 't/script/schema.json', 't/script/file2.json', '-q' } "", "";
is $exit, 0, 'JSON valid';

done_testing;
1 change: 1 addition & 0 deletions t/script/file1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
1 change: 1 addition & 0 deletions t/script/file2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "föö": 1 }
1 change: 1 addition & 0 deletions t/script/file3.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "föö": 10, "bar": "xyz" }
1 change: 1 addition & 0 deletions t/script/file4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "föö": 1.2, "bar": "xyz" }
1 change: 1 addition & 0 deletions t/script/file5.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{
8 changes: 8 additions & 0 deletions t/script/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "object",
"properties": {
"föö": { "type": "integer" },
"bar": { "type": "string" }
},
"required": [ "föö" ]
}