Skip to content

Commit

Permalink
Handle revision strings with leading "r"s. (RT #57837)
Browse files Browse the repository at this point in the history
  • Loading branch information
Infinoid committed Jul 29, 2010
1 parent 703fb0f commit 4b0afa7
Show file tree
Hide file tree
Showing 2 changed files with 306 additions and 0 deletions.
5 changes: 5 additions & 0 deletions lib/App/SVN/Bisect.pm
Expand Up @@ -128,6 +128,7 @@ sub start {
$$self{config}{orig} = $self->find_cur();
my $max = $self->find_max();
if(defined($$self{args}{Max})) {
$$self{args}{Max} = substr($$self{args}{Max},1) if substr($$self{args}{Max},0,1) eq 'r';
$$self{config}{max} = $$self{args}{Max};
die("Given 'max' value is greater than the working directory maximum $max!\n")
if $$self{config}{max} > $max;
Expand Down Expand Up @@ -221,6 +222,7 @@ sub skip {
my @rev = @_;
@rev = $$self{config}{cur} unless scalar @rev;
foreach my $rev (@rev) {
$rev = substr($rev, 1) if substr($rev, 0, 1) eq 'r';
die("\"$rev\" is not a revision or is out of range.\n")
unless exists($$self{config}{extant}{$rev});
$$self{config}{skip}{$rev} = 1;
Expand All @@ -243,6 +245,7 @@ sub unskip {
my @rev = @_;
die("Usage: unskip <revision>\n") unless scalar @rev;
foreach my $rev (@rev) {
$rev = substr($rev, 1) if substr($rev, 0, 1) eq 'r';
die("\"$rev\" is not a revision or is out of range.\n")
unless exists($$self{config}{extant}{$rev});
delete($$self{config}{skip}{$rev});
Expand Down Expand Up @@ -504,6 +507,8 @@ sub ready {
my $self = shift;
return 0 unless defined $$self{config}{min};
return 0 unless defined $$self{config}{max};
$$self{config}{min} = substr($$self{config}{min},1) if substr($$self{config}{min},0,1) eq 'r';
$$self{config}{max} = substr($$self{config}{max},1) if substr($$self{config}{max},0,1) eq 'r';
$$self{config}{extant} = $self->fetch_log_revs()
unless defined $$self{config}{extant};
return 1;
Expand Down
301 changes: 301 additions & 0 deletions t/02_revisions_with_leading_rs.t
@@ -0,0 +1,301 @@
use strict;
use warnings;

use File::Temp qw(tempdir);
use Cwd qw(getcwd);
use Test::More;
use Test::Exception;
use Test::Output;
use App::SVN::Bisect;
use File::Spec::Functions;

my $tests;
BEGIN { $tests = 0; };
plan tests => $tests;

my $curdir = getcwd();
my $tempdir = tempdir( CLEANUP => 1 );
chdir($tempdir);
mkdir(".svn");

package test;
use Test::More;
our @ISA = qw(test2);
sub cmd {
my ($self, $cmd) = @_;
$$self{cmds} = [] unless exists $$self{cmds};
push(@{$$self{cmds}}, $cmd);
return $$self{rvs}{$cmd} if exists $$self{rvs}{$cmd};
return '';
}

sub stdout {
my ($self, @lines) = @_;
my $text = join("", @lines);
@lines = split(/[\r\n]+/, $text);
$$self{stdout} = [] unless exists $$self{stdout};
push(@{$$self{stdout}}, @lines);
}

sub exit {
my $self = shift;
die("exit");
}

package test2;
use Test::More;
our @ISA = qw(App::SVN::Bisect);
sub cmd {
my ($self, $cmd) = @_;
$$self{cmds} = [] unless exists $$self{cmds};
push(@{$$self{cmds}}, $cmd);
return $$self{rvs}{$cmd} if exists $$self{rvs}{$cmd};
return '';
}

sub exit {
my $self = shift;
die("exit");
}

package main;

# constructor
throws_ok(sub { test->new() }, qr/specify an action/, "no Action");
throws_ok(sub { test->new(Action => 'unknown') }, qr/Unknown action/, "bad Action");
throws_ok(sub { test->new(Action => 'good') }, qr/not in progress/, "bad environment");
BEGIN { $tests += 3; };


my $test_responses = {
"svn info" => <<EOF,
Blah: foo
Last Changed Rev: 16
Bar: baz
EOF
"svn log -q -rHEAD:PREV" => <<EOF,
------------------------------------------------------------------------
r31 | foo | 2008-05-01 04:34:41 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
r24 | bar | 2008-05-01 04:01:17 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
r18 | baz | 2008-05-01 03:08:32 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
r16 | quux | 2008-05-01 03:08:32 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
r15 | bing | 2008-05-01 03:08:32 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
EOF
"svn log -q -r0:31" => <<EOF,
------------------------------------------------------------------------
r31 | foo | 2008-05-01 04:34:41 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
r24 | bar | 2008-05-01 04:01:17 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
r18 | baz | 2008-05-01 03:08:32 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
r16 | quux | 2008-05-01 03:08:32 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
r15 | bing | 2008-05-01 03:08:32 -0700 (Thu, 01 May 2008)
------------------------------------------------------------------------
r12 | bing | 2008-04-01 03:08:32 -0700 (Thu, 01 Apr 2008)
------------------------------------------------------------------------
r8 | bob | 2008-04-01 03:08:31 -0700 (Thu, 01 Apr 2008)
------------------------------------------------------------------------
r1 | bob | 2008-04-01 03:08:30 -0700 (Thu, 01 Apr 2008)
------------------------------------------------------------------------
EOF
};

# so, the initial revspace is: (1 8 12 15 16 18 24 31)

# test default args
my $bisect = test->new(Action => "start", Verbose => 0);
ok(defined($bisect), "new() returns an object");
is(ref($bisect), "test", "new() blesses object into specified class");
ok(!-f catfile(".svn", "bisect.yaml"), "metadata file not created yet");
BEGIN { $tests += 3; };

# test readiness
ok(!$bisect->ready, "not ready yet");
$$bisect{config}{min} = 'r0';
ok(!$bisect->ready, "still not ready");
$$bisect{config}{max} = 'r31';
ok($bisect->ready , "ready now");
BEGIN { $tests += 3; };

# test "start"
$bisect = test->new(Action => "start", Min => 'r0', Max => 'r35', Verbose => 0);
$$bisect{rvs} = $test_responses;
throws_ok(sub { $bisect->do_something_intelligent() }, qr/working directory maximum/, "Max exceeds log");
$bisect = test->new(Action => "start", Min => 'r0', Max => 'r18', Verbose => 0);
$$bisect{rvs} = $test_responses;
lives_ok(sub { $bisect->do_something_intelligent() }, "Max in range lives");
unlink(catfile(".svn", "bisect.yaml"));
$bisect = test->new(Action => "start", Min => 'r0', Max => 'r31', Verbose => 0);
$$bisect{rvs} = $test_responses;
$bisect->do_something_intelligent();
ok(-f catfile(".svn", "bisect.yaml"), "metadata file created");
is($$bisect{config}{max}, 31, "biggest svn revision was autodetected");
is($$bisect{config}{min}, 0 , "minimum is 0 by default");
is($$bisect{config}{orig},16, "Last Changed Rev: is parsed correctly");
is($$bisect{config}{cur}, 15, "first step: test r15");
is(scalar @{$$bisect{stdout}}, 1, "1 line written");
like($$bisect{stdout}[0], qr/Choosing r15/, "Choosing r15");
$bisect = test->new(Action => "start", Min => 'r0', Verbose => 0);
throws_ok(sub { $bisect->do_something_intelligent() }, qr/already in progress/, "re-start");
BEGIN { $tests += 10; };

# test "skip" and "unskip"
$bisect = test->new(Action => "skip", Min => 'r0', Verbose => 0);
$$bisect{rvs} = $test_responses;
throws_ok(sub {$bisect->do_something_intelligent("r3") }, qr/out of range/, "invalid input");
$bisect->do_something_intelligent("r15");
is($$bisect{config}{cur}, 16, "next step: test r16");
is(scalar @{$$bisect{stdout}}, 1, "1 line written");
like($$bisect{stdout}[0], qr/Choosing r16/, "Choosing r16");
$bisect = test->new(Action => "unskip", Min => 'r0', Verbose => 0);
$$bisect{rvs} = $test_responses;
throws_ok(sub {$bisect->do_something_intelligent() }, qr/Usage/, "missing param");
throws_ok(sub {$bisect->do_something_intelligent("r3") }, qr/out of range/, "invalid input");
$bisect->do_something_intelligent("r15");
is($$bisect{config}{cur}, 15, "first step: test r15");
is(scalar @{$$bisect{stdout}}, 1, "1 line written");
like($$bisect{stdout}[0], qr/Choosing r15/, "Choosing r15");
$bisect = test->new(Action => "skip", Min => 0, Verbose => 0);
$$bisect{rvs} = $test_responses;
$bisect->do_something_intelligent();
is($$bisect{config}{cur}, 16, "next step: test r16");
is(scalar @{$$bisect{stdout}}, 1, "1 line written");
like($$bisect{stdout}[0], qr/Choosing r16/, "Choosing r16");
BEGIN { $tests += 12; };

# test "view"
$bisect = test->new(Action => "view", Min => 'r0', Max => 'r31', Verbose => 0);
$$bisect{rvs} = $test_responses;
throws_ok( sub { $bisect->do_something_intelligent() }, qr/exit/, "normal exit");
is(scalar @{$$bisect{stdout}}, 6, "6 lines written");
is(join("\n", @{$$bisect{stdout}}, ""), <<EOF, "view output");
There are currently 6 revisions under scrutiny.
The last known unaffected rev is: 0.
The first known affected rev is: 31.
Currently testing 16.
Revision chart:
0] 1 8 12 16 18 24 [31
EOF
BEGIN { $tests += 3; };

# test "after"
$bisect = test->new(Action => "after", Min => 'r0', Verbose => 0);
$$bisect{rvs} = $test_responses;
throws_ok(sub {$bisect->do_something_intelligent("r3") }, qr/out of range/, "invalid input");
$bisect->do_something_intelligent("r16");
is($$bisect{config}{cur}, 8, "next step: test r8");
is(scalar @{$$bisect{stdout}}, 1, "1 line written");
like($$bisect{stdout}[0], qr/Choosing r8/, "Choosing r8");
$bisect = test->new(Action => "after", Min => 'r0', Verbose => 0);
$$bisect{config}{cur} = 16;
$$bisect{rvs} = $test_responses;
$bisect->do_something_intelligent();
is($$bisect{config}{cur}, 8, "next step: test r8");
is(scalar @{$$bisect{stdout}}, 1, "1 line written");
like($$bisect{stdout}[0], qr/Choosing r8/, "Choosing r8");
BEGIN { $tests += 7; };

# test "before"
$bisect = test->new(Action => "before", Min => 'r0', Verbose => 0);
$$bisect{rvs} = $test_responses;
throws_ok(sub {$bisect->do_something_intelligent("r3") }, qr/out of range/, "invalid input");
$bisect = test->new(Action => "before", Min => 'r0', Verbose => 0);
$$bisect{rvs} = $test_responses;
$bisect->do_something_intelligent("r8");
is($$bisect{config}{cur}, 12, "next step: test r12");
is(scalar @{$$bisect{stdout}}, 1, "1 line written");
like($$bisect{stdout}[0], qr/Choosing r12/, "Choosing r12");
$bisect = test->new(Action => "before", Min => 'r0', Verbose => 0);
$$bisect{config}{cur} = 8;
$$bisect{rvs} = $test_responses;
$bisect->do_something_intelligent();
is($$bisect{config}{cur}, 12, "next step: test r12");
is(scalar @{$$bisect{stdout}}, 1, "1 line written");
like($$bisect{stdout}[0], qr/Choosing r12/, "Choosing r12");
BEGIN { $tests += 7; };

# test endgame with skipped revs
$bisect = test->new(Action => "skip", Min => 'r0', Verbose => 0);
$$bisect{config}{cur} = 12;
$$bisect{rvs} = $test_responses;
$bisect->do_something_intelligent();
is($$bisect{config}{cur}, 16, "next step: test r16");
is(scalar @{$$bisect{stdout}}, 2, "2 lines written");
like($$bisect{stdout}[0], qr/This is the end of the road/, "road end");
like($$bisect{stdout}[1], qr/ 2 skipped revs preceding/, "counted skips");
BEGIN { $tests += 4; };

# test "reset"
ok(-f catfile(".svn", "bisect.yaml"), "metadata file still exists");
$bisect = test->new(Action => "reset", Min => 'r0', Verbose => 0);
$$bisect{rvs} = $test_responses;
$bisect->do_something_intelligent();
is(scalar @{$$bisect{stdout}}, 1, "1 line of output");
ok(!-f catfile(".svn", "bisect.yaml"), "metadata file removed");
BEGIN { $tests += 3; };

# test "help"
$bisect = test->new(Action => "help");
$$bisect{rvs} = $test_responses;
throws_ok(sub {$bisect->do_something_intelligent() }, qr/exit/, "help runs");
is(scalar @{$$bisect{stdout}}, 12, "several lines written");
like($$bisect{stdout}[0], qr/Usage:/, "first line is a Usage:");
throws_ok(sub {$bisect->do_something_intelligent('_') }, qr/exit/, "help runs");
is(scalar @{$$bisect{stdout}}, 24, "several lines written");
like($$bisect{stdout}[12], qr/Usage:/, "first line is a Usage:");
throws_ok(sub {$bisect->do_something_intelligent('nonexistent') }, qr/No known help topic/, "help dies");
BEGIN { $tests += 7; };


# test ->cmd()
$? = 0;
$$bisect{stdout} = [];
my $version = eval { App::SVN::Bisect::cmd($bisect, "svn --version") };
SKIP: {
skip "no svn command found!", 4 if $?;

like($version, qr/Subversion/, "svn --version output matches /Subversion/");
throws_ok(sub { App::SVN::Bisect::cmd($bisect, "svn --unknown-arg 2>/dev/null") },
qr/exit/, "handles error");
is(scalar @{$$bisect{stdout}}, 2, "two lines written");
like($$bisect{stdout}[1], qr/Please fix that/, "informative message");
};
BEGIN { $tests += 4; };


# test ->find_max()
is($bisect->find_max(), 31, 'find_max');
$$bisect{rvs}{'svn log -q -rHEAD:PREV'} = '';
throws_ok(sub { $bisect->find_max() }, qr/Cannot find/, 'find_max barfs');
BEGIN { $tests += 2; };


# test ->find_cur()
is($bisect->find_cur(), 16, 'find_cur');
$$bisect{rvs}{'svn info'} = '';
throws_ok(sub { $bisect->find_cur() }, qr/Cannot find/, 'find_cur barfs');
BEGIN { $tests += 2; };


# test ->stdout()
$bisect = test2->new(Action => "help", Verbose => 1);
stdout_like(sub { eval { $bisect->do_something_intelligent() } }, qr/^Usage:/, "stdout");
BEGIN { $tests += 1; };


# test ->verbose()
stdout_like(sub { $bisect->verbose("foo bar") }, qr/^foo bar$/, "verbose");
BEGIN { $tests += 1; };


# test ->exit()
chdir $curdir;
App::SVN::Bisect->exit(0);
exit(1);

0 comments on commit 4b0afa7

Please sign in to comment.