Blame t/attach_errors.t

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
}