t/regress: integrate cmddiff in line
[barcat.git] / t / regress.t
index 177cc8dfa1f22c0f99208e60d7fa104bcfcabdd9..c9107486b6fd710461bd851d3522c0e2fc0e310f 100755 (executable)
@@ -1,71 +1,95 @@
-#!/bin/sh
+#!/usr/bin/env perl
+use 5.014;
+use warnings;
+use re '/ms';
+use Getopt::Long qw(2.32 :config gnu_getopt);
+use Test::More;
+use File::Basename;
 
-cd "${0%/*}" || exit 1
+chdir dirname($0) or exit 1;
 
-test_count=0
-fail_count=0
+GetOptions(\my %opt,
+       'regenerate|G!',
+) or do {
+       say "Usage: $0 [-G] [<files>...]";
+       exit 64;  # EX_USAGE
+};
 
-colorize=
-test -t 1 && colorize=1
-color () {
-       test -n "$colorize" &&
-       printf '\33[%sm' $@
+local $ENV{COLUMNS} = 40;
+
+my @params = @ARGV ? @ARGV : glob 't*.out';
+plan(tests => int @params);
+
+for my $candidate (@params) {
+       my $name = basename($candidate, '.out');
+       $name =~ tr/_/ /;
+       my $todo = $name =~ s/ #TODO$//;
+       local $TODO = $todo ? ' ' : undef;
+
+       if (!-e $candidate) {
+               local $TODO = 'missing output';
+               fail($name);
+               next;
+       }
+
+       open my $fh, '<', $candidate or die "missing $candidate: $!\n";
+       !!(my $spec = readline $fh)
+               or die "input lacks a script on the first line\n";
+
+       my $script = $spec;
+       chomp $script;
+       my $wantexit = $script =~ s/\h+[?](\d+)\z// ? $1 : 0;
+       my $wantwarn = $script !~ s/[?]\z//;
+       my $shell = $script;
+       if ($script =~ /\|/) {
+               # explicit shell wrapper to capture all warnings
+               $script =~ s/'/'\\''/g;
+               $shell = "sh -c '$shell'";
+       }
+       $shell .= ' 2>' . ($wantwarn ? '&1' : '/dev/null');
+
+       open my $cmd, '-|', $shell or do {
+               fail($name);
+               diag("open failure: $!");
+               diag("command: $script");
+               next;
+       };
+       my @lines = readline $cmd;
+       close $cmd;
+       my $error = $? >> 8;
+
+       if ($opt{regenerate}) {
+               #TODO: error
+               open my $rewrite, '>', $candidate;
+               print {$rewrite} $_ for $spec, @lines;
+       }
+
+       if ($error != $wantexit) {
+               fail($name);
+               diag("unexpected exit status $error");
+               diag("command: $script");
+               next;
+       }
+
+       my @diff;
+       my @wanted = readline $fh;
+
+       while (@lines or @wanted) {
+               my $was = shift @wanted;
+               my $is  = shift @lines;
+               next if defined $was and defined $is and $was eq $is;
+               push @diff, color(32) . "< " . color(0) . $_ for $was // ();
+               push @diff, color(31) . "> " . color(0) . $_ for $is  // ();
+       }
+
+       ok(!@diff, $name) or do {
+               diag(@diff);
+               diag("command: $script");
+       };
 }
 
-for option in "$@"
-do
-       case "$option" in
-       -*) echo "Usage: $0 [<files>...]"; exit 64;;
-       esac
-done
-
-params="${@:-t*.out}"
-color 0\;36
-echo "1..$(echo $params | wc -w)"
-color 0
-
-for candidate in $params
-do
-       test_count=$((test_count+1))
-       file="${candidate%.out}"
-       name="$(echo ${file#*-} | tr _ \ )"
-
-       if test -e "$file.out"
-       then
-               ./cmddiff "$file.out"
-       else
-               color 33
-               echo "not ok $test_count - $name # TODO"
-               color 0
-               continue
-       fi
-
-       if test 0 != $?
-       then
-               case "$name" in
-               *' #TODO')
-                       color 33
-                       ;;
-               *)
-                       fail_count=$((fail_count+1))
-                       color 1\;31
-               esac
-
-               printf 'not '
-       fi
-       echo "ok $test_count - $name"
-       color 0
-done
-
-if test $fail_count = 0
-then
-       color 32
-       echo "# passed all $test_count test(s)"
-else
-       color 31
-       echo "# failed $fail_count among $test_count test(s)"
-       fail_count=1  # exit code
-fi
-color 0
-
-exit $fail_count
+done_testing();
+
+sub color {
+       return !$ENV{NOCOLOR} && "\e[@{_}m";
+}