Permalink
Browse files

Tagged 3.04, version bump

  • Loading branch information...
1 parent 6ad7a33 commit 4fed4ca386202705ee7250c44ee190b276154fe0 @AndyA AndyA committed Dec 2, 2007
Showing with 758 additions and 75 deletions.
  1. +1 −0 Changes
  2. +2 −0 MANIFEST
  3. +1 −0 MANIFEST.SKIP
  4. +95 −0 bin/prove
  5. +30 −68 lib/App/Prove.pm
  6. +393 −0 lib/App/Prove/State.pm
  7. +11 −3 lib/TAP/Harness.pm
  8. +2 −1 t/000-load.t
  9. +220 −0 t/state.t
  10. +3 −3 t/testargs.t
View
@@ -7,6 +7,7 @@ Revision history for Test-Harness
- Made TAP::Harness::runtests support aliases for test names.
- Made it possible to pass command line args to test programs
from prove, TAP::Harness, TAP::Parser.
+ - Added --state switch to prove.
3.03 2007-11-17
- Fixed some little bugs-waiting-to-happen inside
View
@@ -16,6 +16,7 @@ examples/test_urls.txt
HACKING.pod
inc/MyBuilder.pm
lib/App/Prove.pm
+lib/App/Prove/State.pm
lib/TAP/Base.pm
lib/TAP/Formatter/Color.pm
lib/TAP/Formatter/Console.pm
@@ -148,6 +149,7 @@ t/source_tests/harness_directives
t/source_tests/harness_failure
t/source_tests/source
t/spool.t
+t/state.t
t/streams.t
t/taint.t
t/testargs.t
View
@@ -5,6 +5,7 @@
\..*\.swp
\..*\.swo
^_build/
+^\.prove$
# Makemaker generated files and dirs.
^MANIFEST\.
View
@@ -55,6 +55,7 @@ Options that take arguments:
--formatter Result formatter to use. See TAP::Harness.
-a, --archive Store the resulting TAP in an archive file.
-j, --jobs N Run N test jobs in parallel (try 9.)
+ --state=opts Control prove's persistent state.
=head2 Reading from C<STDIN>
@@ -118,6 +119,100 @@ that appears on STDERR looks like a test result the test harness will
get confused. Use this option only if you understand the consequences
and can live with the risk.
+=head2 C<--state>
+
+You can ask C<prove> to remember the state of previous test runs and
+select and/or order the tests to be run this time based on that
+saved state.
+
+The C<--state> switch requires an argument which must be a comma
+separated list of one or more of the following options.
+
+=over
+
+=item C<last>
+
+Run the same tests as the last time the state was saved. This makes it
+possible, for example, to recreate the ordering of a shuffled test.
+
+ # Run all tests in random order
+ $ prove -b --state=save --shuffle
+
+ # Run them again in the same order
+ $ prove -b --state=last
+
+=item C<failed>
+
+Run only the tests that failed on the last run.
+
+ # Run all tests
+e $ prove -b --state=save
+
+ # Run failures
+ $ prove -b --state=failed
+
+If you also specify the C<save> option newly passing tests will be
+excluded from subsequent runs.
+
+ # Repeat until no more failures
+ $ prove -b --state=failed,save
+
+=item C<passed>
+
+Run only the passed tests from last time. Useful to make sure that no
+new problems have been introduced.
+
+=item C<all>
+
+Run all tests in normal order. Multple options may be specified, so to
+run all tests with the failures from last time first:
+
+ $ prove -b --state=failed,all,save
+
+=item C<hot>
+
+Run the tests that most recently failed first. The last failure time of
+each test is stored. The C<hot> option causes tests to be run in most-recent-
+failure order.
+
+ $ prove -b --state=hot,save
+
+Tests that have never failed will not be selected. To run all tests with
+the most recently failed first use
+
+ $ prove -b --state=hot,all,save
+
+This combination of options may also be specified thus
+
+ $ prove -b --state=adrian
+
+=item C<todo>
+
+Run any tests with todos.
+
+=item C<slow>
+
+Run the tests in slowest to fastest order. This is useful in conjunction
+with the C<-j> parallel testing switch to ensure that your slowest tests
+start running first.
+
+ $ prove -b --state=slow -j9
+
+=item C<fast>
+
+Run test tests in fastest to slowest order.
+
+=item C<save>
+
+Save the state on exit. The state is stored in a file called F<.prove>
+(F<_prove> on Windows and VMS) in the current directory.
+
+=back
+
+The C<--state> switch may be used more than once.
+
+ $ prove -b --state=hot --state=all,save
+
=head1 PERFORMANCE
Because of its design, C<TAP::Parser> collects more information than
View
@@ -2,9 +2,9 @@ package App::Prove;
use strict;
use TAP::Harness;
-use File::Find;
use File::Spec;
use Getopt::Long;
+use App::Prove::State;
use Carp;
use vars qw($VERSION);
@@ -37,8 +37,9 @@ wrapper around an instance of this module.
=cut
-my $IS_WIN32 = ( $^O =~ /^(MS)?Win32$/ );
-my $NEED_GLOB = $IS_WIN32;
+use constant IS_WIN32 => ( $^O =~ /^(MS)?Win32$/ );
+use constant IS_VMS => $^O eq 'VMS';
+use constant STATE_FILE => ( IS_WIN32 || IS_VMS ) ? '_prove' : '.prove';
use constant PLUGINS => 'App::Prove::Plugin';
@@ -47,9 +48,10 @@ my @ATTR;
BEGIN {
@ATTR = qw(
archive argv blib color directives exec failures fork formatter
- harness includes modules plugins jobs lib merge parse quiet really_quiet recurse
- backwards shuffle taint_fail taint_warn timer verbose
- warnings_fail warnings_warn show_help show_man show_version test_args
+ harness includes modules plugins jobs lib merge parse quiet
+ really_quiet recurse backwards shuffle taint_fail taint_warn timer
+ verbose warnings_fail warnings_warn show_help show_man
+ show_version test_args state
);
for my $attr (@ATTR) {
no strict 'refs';
@@ -80,8 +82,10 @@ sub new {
argv => [],
includes => [],
modules => [],
+ state => [],
plugins => [],
- harness_class => 'TAP::Harness'
+ harness_class => 'TAP::Harness',
+ _state => App::Prove::State->new( { store => STATE_FILE } ),
}, $class;
for my $attr (@ATTR) {
@@ -108,7 +112,7 @@ Dies on invalid arguments.
sub process_args {
my ( $self, @args ) = @_;
- if ( defined( my $stop_at = _first_pos( '--', @args ) ) ) {
+ if ( defined( my $stop_at = _first_pos( '::', @args ) ) ) {
my @test_args = splice @args, $stop_at;
shift @test_args;
$self->{test_args} = \@test_args;
@@ -148,6 +152,7 @@ sub process_args {
'I=s@' => $self->{includes},
'M=s@' => $self->{modules},
'P=s@' => $self->{plugins},
+ 'state=s@' => $self->{state},
'directives' => \$self->{directives},
'h|help|?' => \$self->{show_help},
'H|man' => \$self->{show_man},
@@ -196,7 +201,7 @@ sub _help {
sub _color_default {
my $self = shift;
- return -t STDOUT && !$IS_WIN32;
+ return -t STDOUT && !IS_WIN32;
}
sub _get_args {
@@ -341,7 +346,12 @@ sub run {
$self->_load_extensions( $self->modules );
$self->_load_extensions( $self->plugins, PLUGINS );
- my @tests = $self->_get_tests( @{ $self->argv } );
+ my $state = $self->{_state};
+ if ( defined( my $state_switch = $self->state ) ) {
+ $state->apply_switch(@$state_switch);
+ }
+
+ my @tests = $state->get_tests( $self->recurse, @{ $self->argv } );
$self->_shuffle(@tests) if $self->shuffle;
@tests = reverse @tests if $self->backwards;
@@ -354,7 +364,14 @@ sub run {
sub _runtests {
my ( $self, $args, $harness_class, @tests ) = @_;
- my $harness = $harness_class->new($args);
+ my $harness = $harness_class->new($args);
+
+ $harness->callback(
+ after_test => sub {
+ $self->{_state}->observe_test(@_);
+ }
+ );
+
my $aggregator = $harness->runtests(@tests);
$self->_exit( $aggregator->has_problems ? 1 : 0 );
@@ -403,63 +420,6 @@ sub _get_lib {
return @libs ? \@libs : ();
}
-sub _get_tests {
- my $self = shift;
- my @argv = @_;
- my ( @tests, %tests );
-
- unless (@argv) {
- croak q{No tests named and 't' directory not found}
- unless -d 't';
- @argv = 't';
- }
-
- # Do globbing on Win32.
- if ($NEED_GLOB) {
- @argv = map { glob "$_" } @argv;
- }
-
- foreach my $arg (@argv) {
- if ( '-' eq $arg ) {
- push @argv => <STDIN>;
- chomp(@argv);
- next;
- }
-
- if ( -d $arg ) {
- my @files = $self->_expand_dir($arg);
- foreach my $file (@files) {
- push @tests => $file unless exists $tests{$file};
- }
- @tests{@files} = (1) x @files;
- }
- else {
- push @tests => $arg unless exists $tests{$arg};
- $tests{$arg} = 1;
- }
- }
- return @tests;
-}
-
-sub _expand_dir {
- my $self = shift;
- my $dir = shift;
- my @tests;
- if ( $self->recurse ) {
- find(
- { follow => 1, #21938
- wanted =>
- sub { -f && /\.t$/ && push @tests => $File::Find::name }
- },
- $dir
- );
- }
- else {
- @tests = glob( File::Spec->catfile( $dir, '*.t' ) );
- }
- return sort @tests;
-}
-
sub _shuffle {
my $self = shift;
@@ -572,6 +532,8 @@ calling C<run>.
=item C<shuffle>
+=item C<state>
+
=item C<taint_fail>
=item C<taint_warn>
Oops, something went wrong.

0 comments on commit 4fed4ca

Please sign in to comment.