|
Packit |
14c646 |
#!./perl -w
|
|
Packit |
14c646 |
#
|
|
Packit |
14c646 |
# Copyright 2005, Adam Kennedy.
|
|
Packit |
14c646 |
#
|
|
Packit |
14c646 |
# You may redistribute only under the same terms as Perl 5, as specified
|
|
Packit |
14c646 |
# in the README file that comes with the distribution.
|
|
Packit |
14c646 |
#
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Man, blessed.t scared the hell out of me. For a second there I thought
|
|
Packit |
14c646 |
# I'd lose Test::More...
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# This file tests several known-error cases relating to STORABLE_attach, in
|
|
Packit |
14c646 |
# which Storable should (correctly) throw errors.
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub BEGIN {
|
|
Packit |
14c646 |
unshift @INC, 't';
|
|
Packit |
14c646 |
unshift @INC, 't/compat' if $] < 5.006002;
|
|
Packit |
14c646 |
require Config; import Config;
|
|
Packit |
14c646 |
if ($ENV{PERL_CORE} and $Config{'extensions'} !~ /\bStorable\b/) {
|
|
Packit |
14c646 |
print "1..0 # Skip: Storable was not built\n";
|
|
Packit |
14c646 |
exit 0;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
use Test::More tests => 40;
|
|
Packit |
14c646 |
use Storable ();
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
#####################################################################
|
|
Packit |
14c646 |
# Error 1
|
|
Packit |
14c646 |
#
|
|
Packit |
14c646 |
# Classes that implement STORABLE_thaw _cannot_ have references
|
|
Packit |
14c646 |
# returned by their STORABLE_freeze method. When they do, Storable
|
|
Packit |
14c646 |
# should throw an exception
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Good Case - should not die
|
|
Packit |
14c646 |
{
|
|
Packit |
14c646 |
my $goodfreeze = bless {}, 'My::GoodFreeze';
|
|
Packit |
14c646 |
my $frozen = undef;
|
|
Packit |
14c646 |
eval {
|
|
Packit |
14c646 |
$frozen = Storable::freeze( $goodfreeze );
|
|
Packit |
14c646 |
};
|
|
Packit |
14c646 |
ok( ! $@, 'Storable does not die when STORABLE_freeze does not return references' );
|
|
Packit |
14c646 |
ok( $frozen, 'Storable freezes to a string successfully' );
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package My::GoodFreeze;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_freeze {
|
|
Packit |
14c646 |
my ($self, $clone) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Illegally include a reference in this return
|
|
Packit |
14c646 |
return ('');
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_attach {
|
|
Packit |
14c646 |
my ($class, $clone, $string) = @_;
|
|
Packit |
14c646 |
return bless { }, 'My::GoodFreeze';
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Error Case - should die on freeze
|
|
Packit |
14c646 |
{
|
|
Packit |
14c646 |
my $badfreeze = bless {}, 'My::BadFreeze';
|
|
Packit |
14c646 |
eval {
|
|
Packit |
14c646 |
Storable::freeze( $badfreeze );
|
|
Packit |
14c646 |
};
|
|
Packit |
14c646 |
ok( $@, 'Storable dies correctly when STORABLE_freeze returns a reference' );
|
|
Packit |
14c646 |
# Check for a unique substring of the error message
|
|
Packit |
14c646 |
ok( $@ =~ /cannot return references/, 'Storable dies with the expected error' );
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package My::BadFreeze;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_freeze {
|
|
Packit |
14c646 |
my ($self, $clone) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Illegally include a reference in this return
|
|
Packit |
14c646 |
return ('', []);
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_attach {
|
|
Packit |
14c646 |
my ($class, $clone, $string) = @_;
|
|
Packit |
14c646 |
return bless { }, 'My::BadFreeze';
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
#####################################################################
|
|
Packit |
14c646 |
# Error 2
|
|
Packit |
14c646 |
#
|
|
Packit |
14c646 |
# If, for some reason, a STORABLE_attach object is accidentally stored
|
|
Packit |
14c646 |
# with references, this should be checked and and error should be throw.
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Good Case - should not die
|
|
Packit |
14c646 |
{
|
|
Packit |
14c646 |
my $goodthaw = bless {}, 'My::GoodThaw';
|
|
Packit |
14c646 |
my $frozen = undef;
|
|
Packit |
14c646 |
eval {
|
|
Packit |
14c646 |
$frozen = Storable::freeze( $goodthaw );
|
|
Packit |
14c646 |
};
|
|
Packit |
14c646 |
ok( $frozen, 'Storable freezes to a string as expected' );
|
|
Packit |
14c646 |
my $thawed = eval {
|
|
Packit |
14c646 |
Storable::thaw( $frozen );
|
|
Packit |
14c646 |
};
|
|
Packit |
14c646 |
isa_ok( $thawed, 'My::GoodThaw' );
|
|
Packit |
14c646 |
is( $thawed->{foo}, 'bar', 'My::GoodThaw thawed correctly as expected' );
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package My::GoodThaw;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_freeze {
|
|
Packit |
14c646 |
my ($self, $clone) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
return ('');
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_attach {
|
|
Packit |
14c646 |
my ($class, $clone, $string) = @_;
|
|
Packit |
14c646 |
return bless { 'foo' => 'bar' }, 'My::GoodThaw';
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Bad Case - should die on thaw
|
|
Packit |
14c646 |
{
|
|
Packit |
14c646 |
# Create the frozen string normally
|
|
Packit |
14c646 |
my $badthaw = bless { }, 'My::BadThaw';
|
|
Packit |
14c646 |
my $frozen = undef;
|
|
Packit |
14c646 |
eval {
|
|
Packit |
14c646 |
$frozen = Storable::freeze( $badthaw );
|
|
Packit |
14c646 |
};
|
|
Packit |
14c646 |
ok( $frozen, 'BadThaw was frozen with references correctly' );
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Set up the error condition by deleting the normal STORABLE_thaw,
|
|
Packit |
14c646 |
# and creating a STORABLE_attach.
|
|
Packit |
14c646 |
*My::BadThaw::STORABLE_attach = *My::BadThaw::STORABLE_thaw;
|
|
Packit |
14c646 |
*My::BadThaw::STORABLE_attach = *My::BadThaw::STORABLE_thaw; # Suppress a warning
|
|
Packit |
14c646 |
delete ${'My::BadThaw::'}{STORABLE_thaw};
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Trigger the error condition
|
|
Packit |
14c646 |
my $thawed = undef;
|
|
Packit |
14c646 |
eval {
|
|
Packit |
14c646 |
$thawed = Storable::thaw( $frozen );
|
|
Packit |
14c646 |
};
|
|
Packit |
14c646 |
ok( $@, 'My::BadThaw object dies when thawing as expected' );
|
|
Packit |
14c646 |
# Check for a snippet from the error message
|
|
Packit |
14c646 |
ok( $@ =~ /unexpected references/, 'Dies with the expected error message' );
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package My::BadThaw;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_freeze {
|
|
Packit |
14c646 |
my ($self, $clone) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
return ('', []);
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Start with no STORABLE_attach method so we can get a
|
|
Packit |
14c646 |
# frozen object-containing-a-reference into the freeze string.
|
|
Packit |
14c646 |
sub STORABLE_thaw {
|
|
Packit |
14c646 |
my ($class, $clone, $string) = @_;
|
|
Packit |
14c646 |
return bless { 'foo' => 'bar' }, 'My::BadThaw';
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
#####################################################################
|
|
Packit |
14c646 |
# Error 3
|
|
Packit |
14c646 |
#
|
|
Packit |
14c646 |
# Die if what is returned by STORABLE_attach is not something of that class
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Good Case - should not die
|
|
Packit |
14c646 |
{
|
|
Packit |
14c646 |
my $goodattach = bless { }, 'My::GoodAttach';
|
|
Packit |
14c646 |
my $frozen = Storable::freeze( $goodattach );
|
|
Packit |
14c646 |
ok( $frozen, 'My::GoodAttach return as expected' );
|
|
Packit |
14c646 |
my $thawed = eval {
|
|
Packit |
14c646 |
Storable::thaw( $frozen );
|
|
Packit |
14c646 |
};
|
|
Packit |
14c646 |
isa_ok( $thawed, 'My::GoodAttach' );
|
|
Packit |
14c646 |
is( ref($thawed), 'My::GoodAttach::Subclass',
|
|
Packit |
14c646 |
'The slightly-tricky good "returns a subclass" case returns as expected' );
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package My::GoodAttach;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_freeze {
|
|
Packit |
14c646 |
my ($self, $cloning) = @_;
|
|
Packit |
14c646 |
return ('');
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_attach {
|
|
Packit |
14c646 |
my ($class, $cloning, $string) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
return bless { }, 'My::GoodAttach::Subclass';
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package My::GoodAttach::Subclass;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
BEGIN {
|
|
Packit |
14c646 |
@ISA = 'My::GoodAttach';
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Good case - multiple references to the same object should be attached properly
|
|
Packit |
14c646 |
{
|
|
Packit |
14c646 |
my $obj = bless { id => 111 }, 'My::GoodAttach::MultipleReferences';
|
|
Packit |
14c646 |
my $arr = [$obj];
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
push @$arr, $obj;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
my $frozen = Storable::freeze($arr);
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
ok( $frozen, 'My::GoodAttach return as expected' );
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
my $thawed = eval {
|
|
Packit |
14c646 |
Storable::thaw( $frozen );
|
|
Packit |
14c646 |
};
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
isa_ok( $thawed->[0], 'My::GoodAttach::MultipleReferences' );
|
|
Packit |
14c646 |
isa_ok( $thawed->[1], 'My::GoodAttach::MultipleReferences' );
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
is($thawed->[0], $thawed->[1], 'References to the same object are attached properly');
|
|
Packit |
14c646 |
is($thawed->[1]{id}, $obj->{id}, 'Object with multiple references attached properly');
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package My::GoodAttach::MultipleReferences;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_freeze {
|
|
Packit |
14c646 |
my ($obj) = @_;
|
|
Packit |
14c646 |
$obj->{id}
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_attach {
|
|
Packit |
14c646 |
my ($class, $cloning, $id) = @_;
|
|
Packit |
14c646 |
bless { id => $id }, $class;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Bad Cases - die on thaw
|
|
Packit |
14c646 |
{
|
|
Packit |
14c646 |
my $returnvalue = undef;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Create and freeze the object
|
|
Packit |
14c646 |
my $badattach = bless { }, 'My::BadAttach';
|
|
Packit |
14c646 |
my $frozen = Storable::freeze( $badattach );
|
|
Packit |
14c646 |
ok( $frozen, 'BadAttach freezes as expected' );
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
# Try a number of different return values, all of which
|
|
Packit |
14c646 |
# should cause Storable to die.
|
|
Packit |
14c646 |
my @badthings = (
|
|
Packit |
14c646 |
undef,
|
|
Packit |
14c646 |
'',
|
|
Packit |
14c646 |
1,
|
|
Packit |
14c646 |
[],
|
|
Packit |
14c646 |
{},
|
|
Packit |
14c646 |
\"foo",
|
|
Packit |
14c646 |
(bless { }, 'Foo'),
|
|
Packit |
14c646 |
);
|
|
Packit |
14c646 |
foreach ( @badthings ) {
|
|
Packit |
14c646 |
$returnvalue = $_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
my $thawed = undef;
|
|
Packit |
14c646 |
eval {
|
|
Packit |
14c646 |
$thawed = Storable::thaw( $frozen );
|
|
Packit |
14c646 |
};
|
|
Packit |
14c646 |
ok( $@, 'BadAttach dies on thaw' );
|
|
Packit |
14c646 |
ok( $@ =~ /STORABLE_attach did not return a My::BadAttach object/,
|
|
Packit |
14c646 |
'BadAttach dies on thaw with the expected error message' );
|
|
Packit |
14c646 |
is( $thawed, undef, 'Double checking $thawed was not set' );
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
package My::BadAttach;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_freeze {
|
|
Packit |
14c646 |
my ($self, $cloning) = @_;
|
|
Packit |
14c646 |
return ('');
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
sub STORABLE_attach {
|
|
Packit |
14c646 |
my ($class, $cloning, $string) = @_;
|
|
Packit |
14c646 |
|
|
Packit |
14c646 |
return $returnvalue;
|
|
Packit |
14c646 |
}
|
|
Packit |
14c646 |
}
|