diff --git a/bin/prove b/bin/prove index 3d41db06..5d292dd7 100755 --- a/bin/prove +++ b/bin/prove @@ -75,6 +75,7 @@ Options that take arguments: --statefile=file Use `file` instead of `.prove` for state --rc=rcfile Process options from rcfile --rules Rules for parallel vs sequential processing. + --stdin=list|tap STDIN is list of tests or raw TAP output. =head1 NOTES @@ -103,6 +104,24 @@ file, you can add them to your tests by using a '-': See the C in the C directory of this distribution. +If you have raw TAP output in a file, you can likewise add them to +your tests by using a '-': + + prove - < my_raw_tap_output.txt + +Or from a command: + + ruby test.rb | prove - + +Use the C<--stdin> switch to explicitly set C to a list of +tests: + + prove --stdin=list - < my_list_of_things_to_test.txt + +Or raw TAP output: + + ruby test.rb | prove --stdin=tap - + =head2 Default Test Directory If no files or directories are supplied, C looks for all files diff --git a/lib/App/Prove.pm b/lib/App/Prove.pm index 9298726d..74ced8e7 100644 --- a/lib/App/Prove.pm +++ b/lib/App/Prove.pm @@ -55,7 +55,7 @@ BEGIN { @ATTR = qw( archive argv blib show_count color directives exec failures comments formatter harness includes modules plugins jobs lib merge parse quiet - really_quiet recurse backwards shuffle taint_fail taint_warn timer + really_quiet recurse stdin backwards shuffle taint_fail taint_warn timer verbose warnings_fail warnings_warn show_help show_man show_version state_class test_args state dry extensions ignore_exit rules state_manager normalize sources tapversion trap @@ -220,6 +220,7 @@ sub process_args { 'source=s@' => $self->{sources}, 'formatter=s' => \$self->{formatter}, 'r|recurse' => \$self->{recurse}, + 'stdin=s' => \$self->{stdin}, 'reverse' => \$self->{backwards}, 'p|parse' => \$self->{parse}, 'q|quiet' => \$self->{quiet}, @@ -519,7 +520,7 @@ sub _get_tests { $state->apply_switch(@$state_switch); } - my @tests = $state->get_tests( $self->recurse, @{ $self->argv } ); + my @tests = $state->get_tests( $self, @{ $self->argv } ); $self->_shuffle(@tests) if $self->shuffle; @tests = reverse @tests if $self->backwards; @@ -723,6 +724,8 @@ calling C. =item C +=item C + =item C =item C diff --git a/lib/App/Prove/State.pm b/lib/App/Prove/State.pm index 0b61a824..234055b9 100644 --- a/lib/App/Prove/State.pm +++ b/lib/App/Prove/State.pm @@ -313,11 +313,13 @@ Given a list of args get the names of tests that should run =cut sub get_tests { - my $self = shift; - my $recurse = shift; - my @argv = @_; + my $self = shift; + my $app = shift; + my @argv = @_; my %seen; + my $recurse = ref $app ? $app->recurse : $app; + my @selected = $self->_query; unless ( @argv || @{ $self->{select} } ) { @@ -326,7 +328,7 @@ sub get_tests { unless -d $argv[0]; } - push @selected, $self->_get_raw_tests( $recurse, @argv ) if @argv; + push @selected, $self->_get_raw_tests( $app, @argv ) if @argv; return grep { !$seen{$_}++ } @selected; } @@ -374,11 +376,14 @@ sub _query_clause { } sub _get_raw_tests { - my $self = shift; - my $recurse = shift; - my @argv = @_; + my $self = shift; + my $app = shift; + my @argv = @_; my @tests; + my $recurse = ref $app ? $app->recurse : $app; + my $stdin = ref $app && $app->stdin || ''; + # Do globbing on Win32. if (NEED_GLOB) { eval "use File::Glob::Windows"; # [49732] @@ -388,8 +393,35 @@ sub _get_raw_tests { for my $arg (@argv) { if ( '-' eq $arg ) { - push @argv => ; - chomp(@argv); + local $/; + my $in = ; + if ( + $stdin eq 'tap' + or !$stdin && $in =~ / + \A # Beginning of first line + TAP\s+version\s+\d+ # TAP version line + | + ^ # Beginning of any line + \s* # Indented subtests + (?: + [#] # A comment + | + (?: + 1\.\.\d+ | # A plan line + ok | # A test line - pass + not\s+ok # A test line - fail + ) + \b # End of word or number + (?!\S) # Space if anything else on line + ) + /xm + ) { + # Raw TAP output. + push @tests => [$in, '*STDIN']; + } else { + # List of tests. + push @argv => split /\n/, $in; + } next; } diff --git a/t/prove.t b/t/prove.t index 75718f62..0915cca0 100644 --- a/t/prove.t +++ b/t/prove.t @@ -84,7 +84,7 @@ BEGIN { # START PLAN @ATTR = qw( archive argv blib color directives exec extensions failures formatter harness includes lib merge parse quiet really_quiet - recurse backwards shuffle taint_fail taint_warn verbose + recurse stdin backwards shuffle taint_fail taint_warn verbose warnings_fail warnings_warn ); @@ -116,8 +116,9 @@ BEGIN { # START PLAN }, { name => 'Set all options via constructor', args => { - archive => 1, + archive => 0, argv => [qw(one two three)], + backwards => 1, blib => 2, color => 3, directives => 4, @@ -132,8 +133,8 @@ BEGIN { # START PLAN quiet => 14, really_quiet => 15, recurse => 16, - backwards => 17, - shuffle => 18, + shuffle => 17, + stdin => 18, taint_fail => 19, taint_warn => 20, verbose => 21, @@ -141,8 +142,9 @@ BEGIN { # START PLAN warnings_warn => 23, }, expect => { - archive => 1, + archive => 0, argv => [qw(one two three)], + backwards => 1, blib => 2, color => 3, directives => 4, @@ -157,8 +159,8 @@ BEGIN { # START PLAN quiet => 14, really_quiet => 15, recurse => 16, - backwards => 17, - shuffle => 18, + shuffle => 17, + stdin => 18, taint_fail => 19, taint_warn => 20, verbose => 21, @@ -1458,6 +1460,140 @@ BEGIN { # START PLAN # ], # }, + + # STDIN + { name => 'STDIN (file names)', + stdin => "uno\ndos\ntres\n", + args => { + argv => ['-'], + }, + expect => { + argv => ['-'], + }, + runlog => [ + [ '_runtests', + { verbosity => 0, show_count => 1 }, + 'uno', 'dos', 'tres' + ] + ], + }, + (map +{ + name => "STDIN (file - $_)", + stdin => "$_\ndos\ntres\n", + args => { + argv => ['-'], + }, + expect => { + argv => ['-'], + }, + runlog => [ + [ '_runtests', + { verbosity => 0, show_count => 1 }, + $_, 'dos', 'tres', + ] + ], + } => split /\n/, <<'FILES' +1..2.t +1..2a +ok.t +okay +OK +not ok.t +not oklahoma +NOT OK +FILES + ), + (map +{ + name => "STDIN (TAP - $_)", + stdin => "\n$_\n", + args => { + argv => ['-'], + }, + expect => { + argv => ['-'], + }, + runlog => [ + [ '_runtests', + { verbosity => 0, show_count => 1 }, + ["\n$_\n", '*STDIN'], + ] + ], + } => split /\n/, <<'TAP' +1..42 +1..4 # Skipped: Win32 not supported +ok +ok 2 +not ok +not ok 3 +# comment + 1..4 + 1..4 # Skipped: Win32 not supported + ok + ok 2 + not ok + not ok 3 + # comment +TAP + ), + { + name => "STDIN (TAP - TAP version 13)", + stdin => "TAP version 13\n", + args => { + argv => ['-'], + }, + expect => { + argv => ['-'], + }, + runlog => [ + [ '_runtests', + { verbosity => 0, show_count => 1 }, + ["TAP version 13\n", '*STDIN'], + ] + ], + }, + (map +{ + name => 'Switch --stdin=list', + stdin => $_, + switches => [ '--stdin=list', '-' ], + expect => { + stdin => 'list', + }, + runlog => [ + [ '_runtests', + { verbosity => 0, show_count => 1 }, + split /\n/ + ] + ], + } => <<'NOT_TAP' +TAP version 13 +1..4 +# comment +ok 1 +ok 2 +not ok 3 +not ok 4 +NOT_TAP + ), + (map +{ + name => 'Switch --stdin=tap', + stdin => $_, + switches => [ '--stdin=tap', '-' ], + expect => { + stdin => 'tap', + }, + runlog => [ + [ '_runtests', + { verbosity => 0, show_count => 1 }, + [$_, '*STDIN'], + ] + ], + } => <<'NOT_LIST' +alpha.t +beta.t +charlie.t +NOT_LIST + ), + ); # END SCHEDULE @@ -1536,6 +1672,9 @@ for my $test (@SCHEDULE) { } if ( my $runlog = $test->{runlog} ) { + local *STDIN; + open STDIN, '<', \$test->{stdin} or die "No open STDIN: $!" + if $test->{stdin}; eval { $app->run }; if ( my $err_pattern = $test->{run_error} ) { like $@, $err_pattern, "$name: expected error OK";