1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
#!/usr/local/bin/perl -w
use strict;
#use Test::More 'no_plan';
use Test::More tests => 28;
use Test::Exception;
my $CLASS;
{
package Foo;
sub bar {
return 'original value';
}
sub baz {
return 'original baz value';
}
}
BEGIN {
chdir 't' if -d 't';
use lib '../lib';
$CLASS = 'Sub::Override';
use_ok($CLASS) || die;
}
can_ok($CLASS, 'new');
my $override = $CLASS->new;
isa_ok($override, $CLASS, '... and the object it returns');
can_ok($override, 'replace');
throws_ok { $override->replace('No::Such::Sub', '') }
qr/^\QCannot replace non-existent sub (No::Such::Sub)\E/,
"... and we can't replace a sub which doesn't exist";
throws_ok { $override->replace('Foo::bar', 'not a subref') }
qr/\(not a subref\) must be a code reference/,
'... and only a code reference may replace a subroutine';
ok($override->replace('Foo::bar', sub { 'new subroutine' }),
'... and replacing a subroutine should succeed');
is(Foo::bar(), 'new subroutine',
'... and the subroutine should exhibit the new behavior');
ok($override->replace('Foo::bar' => sub { 'new subroutine 2' }),
'... and we should be able to replace a sub more than once');
is(Foo::bar(), 'new subroutine 2',
'... and still have the sub exhibit the new behavior');
can_ok($override, 'override');
ok($override->override('Foo::bar' => sub { 'new subroutine 3' }),
'... and it should also replace a subroutine');
is(Foo::bar(), 'new subroutine 3',
'... and act just like replace()');
can_ok($override, 'restore');
throws_ok { $override->restore('Did::Not::Override') }
qr/^\QCannot restore a sub that was not replaced (Did::Not::Override)/,
'... and it should fail if the subroutine had not been replaced';
$override->restore('Foo::bar');
is(Foo::bar(), 'original value',
'... and the subroutine should exhibit the original behavior');
throws_ok { $override->restore('Foo::bar') }
qr/^\QCannot restore a sub that was not replaced (Foo::bar)/,
'... but we should not be able to restore it twice';
{
my $new_override = $CLASS->new;
ok($new_override->replace('Foo::bar', sub { 'lexical value' }),
'A new override object should be able to replace a subroutine');
is(Foo::bar(), 'lexical value',
'... and the subroutine should exhibit the new behavior');
}
is(Foo::bar(), 'original value',
'... but should revert to the original behavior when the object falls out of scope');
{
my $new_override = $CLASS->new('Foo::bar', sub { 'lexical value' });
ok($new_override, 'We should be able to override a sub from the constructor');
is(Foo::bar(), 'lexical value',
'... and the subroutine should exhibit the new behavior');
ok($new_override->restore,
'... and we do not need an argument to restore if only one sub is overridden');
is(Foo::bar(), 'original value',
'... and the subroutine should exhibit its original behavior');
$new_override->replace('Foo::bar', sub {});
$new_override->replace('Foo::baz', sub {});
throws_ok { $new_override->restore }
qr/You must provide the name of a sub to restore: \(Foo::bar, Foo::baz\)/,
'... but we must explicitly provide the sub name if more than one was replaced';
}
{
package Temp;
sub foo { 23 }
sub bar { 42 }
my $override = Sub::Override->new('foo', sub { 42 });
$override->replace('bar', sub { 'barbar' });
main::is(foo(), 42, 'Not fully qualifying a sub name will assume the current package');
$override->restore('foo');
main::is(foo(), 23, '... and we should be able to restore said sub');
$override->restore('Temp::bar');
main::is(bar(), 42, '... even if we use a full qualified sub name');
}
|