The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;
use utf8;
use Test::More;
use Docopt;
use JSON::PP;
use Data::Dumper;
use boolean;

my $src = slurp('t/testcases.docopt');
my @src = grep /\S/, split /r"""/, $src;
my $json = JSON::PP->new()->allow_nonref();
for (@src) {
    note "============================================";
    my ($doc, $cmdlines) = split /"""/, $_;
    $doc =~ s/\n\z//;
    note 'q{' . $doc . '}';
    while ($cmdlines =~ m!^\$ prog(.*)\n((?:[^\n]+\n)+)!mg) {
        note "--------------------------------------------";
        my $argv = $1;
        my $expected = $2;

        $expected =~ s/\n\z//;
        $expected =~ s/\s*#.*//;
        $argv =~ s/\A\s*//;
        $argv =~ s/\s*\z//;
        my @argv = split /\s+/, $argv;
        note("ARGV: $argv");
        note("Expected:: $expected");
        my $result = eval {
            docopt(doc => $doc, argv => \@argv);
        };
        if (my $e = $@) {
            if ((Scalar::Util::blessed($e)||'') =~ /^Docopt::/) {
                note "Error: $e";
                is('"user-error"', $expected) or do { diag Dumper($e); diag Dumper(\@argv); };
            } else {
                die $e;
            }
        } else {
            my $expected_data = eval { $json->decode($expected) } or die "$@\n'''$expected'''";
            for my $k (keys %$expected_data) {
                if (ref $expected_data->{$k}) {
                    if (ref($expected_data->{$k}) eq 'JSON::PP::Boolean') {
                        $expected_data->{$k} = $expected_data->{$k} ? boolean::true() : undef;
                    }
                }
            }
            is_deeply($result, $expected_data) or do { note Dumper($result); note Dumper($expected_data); note Dumper(\@argv)};
        }
    }
}

done_testing;

sub slurp {
    my $fname = shift;
    open my $fh, '<', $fname
        or Carp::croak("Can't open '$fname' for reading: '$!'");
    scalar(do { local $/; <$fh> })
}