#!/usr/bin/perl # Filename: tb # Author: David Ljung Madison # See License: http://MarginalHacks.com/License # Description: testbench for comparing two commands use strict; use IO::File; use IPC::Open3; ################################################## # Setup the variables ################################################## my $PROGNAME = $0; $PROGNAME =~ s|.*/||; my $REDO = 0; $SIG{PIPE} = sub { $REDO = 1; }; sub run { my ($cmd,$in) = @_; my ($iH,$oH,$eH) = (new IO::File,new IO::File,new IO::File); my $pid = open3($iH,$oH,$eH, $cmd); die("Couldn't run [$cmd]\n") if $pid==-1; print $iH $in; close $iH; my @out = <$oH>; close $oH; my @err = <$eH>; close $eH; waitpid($pid,0); my $ret = $?; return (\@out,\@err,$ret) unless $REDO; $REDO = 0; run($cmd,$in); } sub diff { my ($a,$b) = @_; return 1 if ref($a) ne ref($b); #if (!ref($a) && $a ne $b) { chomp($a); chomp($b); print "compare difference:\n[$a]\n[$b]\n"; } return ($a ne $b ? 1 : 0) unless ref($a); return ($$a ne $$b) if ref($a) eq "SCALAR"; if (ref($a) eq "ARRAY") { return 1 unless $#$a == $#$b; for(my $i=0; $i<=$#$a; $i++) { return 1 if diff($a->[$i],$b->[$i]); } return 0; } if (ref($a) eq "HASH") { my @ak = keys %$a; my @bk = keys %$b; return 1 if diff(\@ak,\@bk); foreach my $k ( @ak ) { return 1 if diff($a->{$k},$b->{$k}); } return 0; } die("diff() doesn't do ".ref($a)." today.."); } my $IGNORE; # Kludge sub cmp_run { my ($a,$b,@opt) = @_; my $in = pop @opt; foreach my $opt ( @opt ) { print "$a,$b [$opt]\n"; my $errors = 0; my ($oa,$ea,$ra) = run("$a $opt",$in); my ($ob,$eb,$rb) = run("$b $opt",$in); # KLUDGE: Replace occurences of $b in out to $a (for print of PROGNAME,...) @$ob = map {s/$b/$a/g; $_} @$ob; @$eb = map {s/$b/$a/g; $_} @$eb; # KLUDGE: Pull out $IGNORE lines @$ob = grep(!/$IGNORE/, @$ob) if $IGNORE; @$eb = grep(!/$IGNORE/, @$eb) if $IGNORE; if (diff($oa,$ob)) { print "OUTPUT DIFF: [$a,$b] [$opt]:\n"; print "- $a ","-"x30,"\n"; print @$oa; print "- $b ","-"x30,"\n"; print @$ob; print "-"x70,"\n"; $errors++; } if (diff($ea,$eb)) { print "ERROR DIFF: [$a,$b] [$opt]:\n"; print "- $a ","-"x30,"\n"; print @$ea; print "- $b ","-"x30,"\n"; print @$eb; print "-"x70,"\n"; $errors++; } if ($ra != $rb) { print "EXITCODE DIFF: [$a,$b] [$opt]:\n"; print "error:\n@$ea\n" unless $errors; print "$a -> [$ra]\n"; print "$b -> [$rb]\n"; $errors++; } die("\n") if $errors; } } # All permutations of arrays sub combine { my $a1 = shift @_; $a1 = [$a1] unless ref $a1; return @$a1 unless @_; my $a2 = shift @_; $a2 = [$a2] unless ref $a2; my @n; foreach my $e1 (@$a1) { foreach my $e2 (@$a2) { push(@n,"$e1 $e2"); } } return @n unless @_; combine(\@n,@_); } ################################################## $IGNORE = "--nosplit-lines"; # New feature shows up in usage.. # Can't test: # --interactive # --max-procs my @usage = ("--help", "-bad_arg", "--bad_arg"); my @eof = ("-e5","-e6","-e8","-ezog","-e","--eof=5","--eof=8","--eof=zog","--eof"); my @maxargs = ("-n 1","-n 2","-n 3","-n 99","-n 0","--max-args=1","--max-args=2"); my @maxlines = ("-l1","-l2","-l3","-l99","-l0","--max-lines=1","--max-lines=2"); my $in_count = "1\n2\n__\n4 4\n 5\n66\n777\n8\n_\n9\na\n"; my $Z = chr(0x0); my $in_zero = "1${Z}2 '3 4${Z}5 6${Z}7${Z}${Z}"; my $in_blank = "\n \n\n \n\n "; ## Basic args and eof tests #cmp_run("xargs","xags", @usage, $in_count); cmp_run("xargs","xags", combine(\@eof,\@maxargs), $in_count); #cmp_run("xargs","xags", combine("-t",\@maxargs), $in_count); cmp_run("xargs","xags", combine(\@eof,\@maxlines), $in_count); ### Basic maxchars test ### For some reason, xargs doesn't print the last possible argument line ##cmp_run("xargs","xags", combine("-s",[1,2,10..18]), $in_count); # Doesn't seem to be passing the -0 properly?? ## Basic \0 divider test cmp_run("xargs","xags", combine("-0",\@maxargs,"e"), $in_zero); cmp_run("xargs","xags", combine("-0",\@maxlines,"e"), $in_zero); # Basic --no-run-if-empty test #cmp_run("xargs","xags", combine(["--no-run-if-empty",""],\@maxlines), $in_blank); #cmp_run("xargs","xags", combine(["--no-run-if-empty",""],\@maxlines), $in_blank); print STDERR "PASS\n";