#!/usr/bin/perl -w
# Formal testing for Class::Autouse.
# While this isn't a particularly exhaustive unit test like script,
# it does test every known bug and corner case discovered. As new bugs
# are found, tests are added to this test script.
# So if everything works for all the nasty corner cases, it should all work
# as advertised... we hope ;)
use strict;
use lib ();
use File::Spec::Functions ':ALL';
BEGIN {
$| = 1;
if ( $ENV{HARNESS_ACTIVE} ) {
lib->import( catdir( curdir(), 't', 'modules' ) );
} else {
require FindBin;
chdir ($FindBin::Bin = $FindBin::Bin); # Avoid a warning
lib->import( 'modules' );
}
}
use Test::More tests => 29;
use Scalar::Util 'refaddr';
use Class::Autouse ();
# Test the class_exists class detector
ok( Class::Autouse->class_exists( 'Class::Autouse' ), '->class_exists works for existing class' );
ok( ! Class::Autouse->class_exists( 'Class::Autouse::Nonexistant' ), '->class_exists works for non-existant class' );
#####################################################################
# Regression Test
# This should fail in 0.8, 0.9 and 1.0
# Does ->can for an autoused class correctly load the class and find the method.
my $class = 'D';
ok( refaddr(*UNIVERSAL::can{CODE}), "We know which version of UNIVERSAL::can we are using" );
is( refaddr(*UNIVERSAL::can{CODE}), refaddr($Class::Autouse::orig_can),
"Before autoloading, UNIVERSAL::can is in it's original state, and has been backed up");
is( refaddr(*UNIVERSAL::isa{CODE}), refaddr($Class::Autouse::orig_isa),
"Before autoloading, UNIVERSAL::isa is in it's original state, and has been backed up");
ok( Class::Autouse->autouse( $class ), "Test class '$class' autoused ok" );
is( refaddr(*UNIVERSAL::can{CODE}), refaddr(*Class::Autouse::_can{CODE}),
"After autoloading, UNIVERSAL::can has been correctly hijacked");
is( refaddr(*UNIVERSAL::isa{CODE}), refaddr(*Class::Autouse::_isa{CODE}),
"After autoloading, UNIVERSAL::isa has been correctly hijacked");
ok( $class->can('method2'), "'can' found sub 'method2' in autoused class '$class'" );
ok( $Class::Autouse::LOADED{$class}, "'can' loaded class '$class' while looking for 'method2'" );
is( refaddr(*UNIVERSAL::can{CODE}), refaddr($Class::Autouse::orig_can),
"When all classes are loaded, UNIVERSAL::can reverts back to the original state");
is( refaddr(*UNIVERSAL::isa{CODE}), refaddr($Class::Autouse::orig_isa),
"Whan all classes are loaded, UNIVERSAL::isa reverts back to the original state");
# Use the loaded hash again to avoid a warning
$_ = $Class::Autouse::LOADED{$class};
#####################################################################
# Regression Test
# This may fail below Class::Autouse 0.8. If the above tests fail, ignore any failure.
# Does ->can follow the inheritance tree correctly when finding a method.
ok( $class->can('method'), "'can' found sub 'method' in '$class' ( from parent class 'C' )" );
#####################################################################
# Regression Test
# This should fail below Class::Autouse 0.8
# If class 'F' isa 'E' and method 'foo' in F uses SUPER::foo, make sure it find the method 'foo' in E.
ok( Class::Autouse->autouse( 'E' ), 'Test class E autouses ok' );
ok( Class::Autouse->autouse( 'F' ), 'Test class F autouses ok' );
ok( F->foo eq 'Return value from E->foo', 'Class->SUPER::method works safely' );
#####################################################################
# Regression Test
# This should fail for Class::Autouse 0.8 and 0.9
# If an non package based class is empty, except for an ISA to an existing class,
# and method 'foo' exists in the parent class, UNIVERSAL::can SHOULD return true.
# After the addition of the UNIVERSAL::can replacement Class::Autouse::_can, it didn't.
# In particular, this was causing problems with MakeMaker.
@G::ISA = 'E';
ok( G->can('foo'), "_can handles the empty class with \@ISA case correctly" );
# Catch additional bad uses of _can early.
is( Class::Autouse::_can( undef, 'foo' ), undef,
'Giving bad stuff to _can returns expected' );
is( Class::Autouse::_can( 'something/random/that/isnt/c/class', 'paths' ), undef,
'Giving bad stuff to _can returns OK' );
#####################################################################
# Regression Test
# Class::Autouse 1.18 does not pass on errors incurred during ->can calls.
# This is expected behaviour and worked in 1.18 already.
ok( Class::Autouse->autouse( 'G' ), 'Test class G autouses ok' );
ok( Class::Autouse->autouse( 'H' ), 'Test class H autouses ok' );
my $coderef = G->can('foo');
is( ref($coderef), 'CODE', 'Good existant ->can autoloads correctly and returns a CODE ref' );
is( refaddr(&$coderef), refaddr(&G::foo), '->can returns the expected function' );
is( H->can('foo'), undef, 'Good non-existant ->can autoloads correctly' );
use_ok( 'J' );
$coderef = 'foobar';
eval {
J->can('foo');
};
like( $@, qr/^J\-\>can threw an exception/, 'A normal ->can call can throw an exception' );
# This initially failed in 1.18 and was fixed for 1.20
ok( Class::Autouse->autouse( 'I' ), 'Test class I autouses ok' );
$coderef = 'foobar';
eval {
$coderef = I->can('foo');
};
like( $@, qr/^This is an expected error/, 'Bad existant ->can throws the expected error' );
is( $coderef, 'foobar', 'Assigned value from autoloading ->can remains unchanged' );
syntax highlighted by Code2HTML, v. 0.9.1