summaryrefslogtreecommitdiff
path: root/t/lib
diff options
context:
space:
mode:
authorRadu Greab <radu@netsoft.ro>2000-08-21 06:10:05 +0300
committerJarkko Hietaniemi <jhi@iki.fi>2000-08-21 02:57:03 +0000
commit7a6a85bf4acedfcba42e5cccce98ec9a408bc69e (patch)
tree7635e7cdf2c917f07f4ca813e96bcf77858c3620 /t/lib
parentb37ebb13f6aaa3a1b8a20b4a97e08bf9427d7e2f (diff)
downloadperl-7a6a85bf4acedfcba42e5cccce98ec9a408bc69e.tar.gz
Add Storable 0.7.2 from Raphael Manfredi,
plus the patch from Subject: Re: someone with too much time and a 64-bit box and interest in Storable? Message-ID: <Pine.LNX.4.10.10008210258160.1292-100000@busy.netsoft.ro> plus changes to get Storable to compile with picky ANSI compilers. p4raw-id: //depot/perl@6734
Diffstat (limited to 't/lib')
-rw-r--r--t/lib/st-06compat.t123
-rw-r--r--t/lib/st-blessed.t98
-rw-r--r--t/lib/st-canonical.t147
-rw-r--r--t/lib/st-dclone.t76
-rw-r--r--t/lib/st-dump.pl146
-rw-r--r--t/lib/st-forgive.t58
-rw-r--r--t/lib/st-freeze.t113
-rw-r--r--t/lib/st-overload.t49
-rw-r--r--t/lib/st-recurse.t177
-rw-r--r--t/lib/st-retrieve.t72
-rw-r--r--t/lib/st-store.t114
-rw-r--r--t/lib/st-tied.t210
-rw-r--r--t/lib/st-tiedhook.t209
-rw-r--r--t/lib/st-tieditems.t65
14 files changed, 1657 insertions, 0 deletions
diff --git a/t/lib/st-06compat.t b/t/lib/st-06compat.t
new file mode 100644
index 0000000000..23245d5bd7
--- /dev/null
+++ b/t/lib/st-06compat.t
@@ -0,0 +1,123 @@
+#!./perl
+
+# $Id: compat-0.6.t,v 0.7 2000/08/03 22:04:44 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: compat-0.6.t,v $
+# Revision 0.7 2000/08/03 22:04:44 ram
+# Baseline for second beta release.
+#
+
+BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+sub ok;
+
+print "1..8\n";
+
+use Storable qw(freeze nfreeze thaw);
+
+package TIED_HASH;
+
+sub TIEHASH {
+ my $self = bless {}, shift;
+ return $self;
+}
+
+sub FETCH {
+ my $self = shift;
+ my ($key) = @_;
+ $main::hash_fetch++;
+ return $self->{$key};
+}
+
+sub STORE {
+ my $self = shift;
+ my ($key, $val) = @_;
+ $self->{$key} = $val;
+}
+
+package SIMPLE;
+
+sub make {
+ my $self = bless [], shift;
+ my ($x) = @_;
+ $self->[0] = $x;
+ return $self;
+}
+
+package ROOT;
+
+sub make {
+ my $self = bless {}, shift;
+ my $h = tie %hash, TIED_HASH;
+ $self->{h} = $h;
+ $self->{ref} = \%hash;
+ my @pool;
+ for (my $i = 0; $i < 5; $i++) {
+ push(@pool, SIMPLE->make($i));
+ }
+ $self->{obj} = \@pool;
+ my @a = ('string', $h, $self);
+ $self->{a} = \@a;
+ $self->{num} = [1, 0, -3, -3.14159, 456, 4.5];
+ $h->{key1} = 'val1';
+ $h->{key2} = 'val2';
+ return $self;
+};
+
+sub num { $_[0]->{num} }
+sub h { $_[0]->{h} }
+sub ref { $_[0]->{ref} }
+sub obj { $_[0]->{obj} }
+
+package main;
+
+my $r = ROOT->make;
+
+my $data = '';
+while (<DATA>) {
+ next if /^#/;
+ $data .= unpack("u", $_);
+}
+
+ok 1, length $data == 278;
+
+my $y = thaw($data);
+ok 2, 1;
+ok 3, ref $y eq 'ROOT';
+
+$Storable::canonical = 1; # Prevent "used once" warning
+$Storable::canonical = 1;
+ok 4, nfreeze($y) eq nfreeze($r);
+
+ok 5, $y->ref->{key1} eq 'val1';
+ok 6, $y->ref->{key2} eq 'val2';
+ok 7, $hash_fetch == 2;
+
+my $num = $r->num;
+my $ok = 1;
+for (my $i = 0; $i < @$num; $i++) {
+ do { $ok = 0; last } unless $num->[$i] == $y->num->[$i];
+}
+ok 8, $ok;
+
+__END__
+#
+# using Storable-0.6@11, output of: print pack("u", nfreeze(ROOT->make));
+# original size: 278 bytes
+#
+M`P,````%!`(````&"(%8"(!8"'U8"@@M,RXQ-#$U.5@)```!R%@*`S0N-5A8
+M6`````-N=6T$`P````(*!'9A;#%8````!&ME>3$*!'9A;#)8````!&ME>3)B
+M"51)141?2$%32%A8`````6@$`@````,*!G-T<FEN9U@$``````I8!```````
+M6%A8`````6$$`@````4$`@````$(@%AB!E-)35!,15A8!`(````!"(%88@93
+M24U03$586`0"`````0B"6&(&4TE-4$Q%6%@$`@````$(@UAB!E-)35!,15A8
+M!`(````!"(188@9324U03$586%A8`````V]B:@0,!``````*6%A8`````W)E
+(9F($4D]/5%@`
diff --git a/t/lib/st-blessed.t b/t/lib/st-blessed.t
new file mode 100644
index 0000000000..22fc5263d0
--- /dev/null
+++ b/t/lib/st-blessed.t
@@ -0,0 +1,98 @@
+#!./perl
+
+# $Id: blessed.t,v 0.7 2000/08/03 22:04:44 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: blessed.t,v $
+# Revision 0.7 2000/08/03 22:04:44 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+sub ok;
+
+use Storable qw(freeze thaw);
+
+print "1..10\n";
+
+package SHORT_NAME;
+
+sub make { bless [], shift }
+
+package SHORT_NAME_WITH_HOOK;
+
+sub make { bless [], shift }
+
+sub STORABLE_freeze {
+ my $self = shift;
+ return ("", $self);
+}
+
+sub STORABLE_thaw {
+ my $self = shift;
+ my $cloning = shift;
+ my ($x, $obj) = @_;
+ die "STORABLE_thaw" unless $obj eq $self;
+}
+
+package main;
+
+# Still less than 256 bytes, so long classname logic not fully exercised
+# Wait until Perl removes the restriction on identifier lengths.
+my $name = "LONG_NAME_" . 'xxxxxxxxxxxxx::' x 14 . "final";
+
+eval <<EOC;
+package $name;
+
+\@ISA = ("SHORT_NAME");
+EOC
+die $@ if $@;
+ok 1, $@ eq '';
+
+eval <<EOC;
+package ${name}_WITH_HOOK;
+
+\@ISA = ("SHORT_NAME_WITH_HOOK");
+EOC
+ok 2, $@ eq '';
+
+# Construct a pool of objects
+my @pool;
+
+for (my $i = 0; $i < 10; $i++) {
+ push(@pool, SHORT_NAME->make);
+ push(@pool, SHORT_NAME_WITH_HOOK->make);
+ push(@pool, $name->make);
+ push(@pool, "${name}_WITH_HOOK"->make);
+}
+
+my $x = freeze \@pool;
+ok 3, 1;
+
+my $y = thaw $x;
+ok 4, ref $y eq 'ARRAY';
+ok 5, @{$y} == @pool;
+
+ok 6, ref $y->[0] eq 'SHORT_NAME';
+ok 7, ref $y->[1] eq 'SHORT_NAME_WITH_HOOK';
+ok 8, ref $y->[2] eq $name;
+ok 9, ref $y->[3] eq "${name}_WITH_HOOK";
+
+my $good = 1;
+for (my $i = 0; $i < 10; $i++) {
+ do { $good = 0; last } unless ref $y->[4*$i] eq 'SHORT_NAME';
+ do { $good = 0; last } unless ref $y->[4*$i+1] eq 'SHORT_NAME_WITH_HOOK';
+ do { $good = 0; last } unless ref $y->[4*$i+2] eq $name;
+ do { $good = 0; last } unless ref $y->[4*$i+3] eq "${name}_WITH_HOOK";
+}
+ok 10, $good;
+
diff --git a/t/lib/st-canonical.t b/t/lib/st-canonical.t
new file mode 100644
index 0000000000..67cd72d4da
--- /dev/null
+++ b/t/lib/st-canonical.t
@@ -0,0 +1,147 @@
+#!./perl
+
+# $Id: canonical.t,v 0.7 2000/08/03 22:04:44 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: canonical.t,v $
+# Revision 0.7 2000/08/03 22:04:44 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+}
+
+
+use Storable qw(freeze thaw dclone);
+use vars qw($debugging $verbose);
+
+print "1..8\n";
+
+sub ok {
+ my($testno, $ok) = @_;
+ print "not " unless $ok;
+ print "ok $testno\n";
+}
+
+
+# Uncomment the folowing line to get a dump of the constructed data structure
+# (you may want to reduce the size of the hashes too)
+# $debugging = 1;
+
+$hashsize = 100;
+$maxhash2size = 100;
+$maxarraysize = 100;
+
+# Use MD5 if its available to make random string keys
+
+eval { require "MD5.pm" };
+$gotmd5 = !$@;
+
+# Use Data::Dumper if debugging and it is available to create an ASCII dump
+
+if ($debugging) {
+ eval { require "Data/Dumper.pm" };
+ $gotdd = !$@;
+}
+
+@fixed_strings = ("January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December" );
+
+# Build some arbitrarily complex data structure starting with a top level hash
+# (deeper levels contain scalars, references to hashes or references to arrays);
+
+for (my $i = 0; $i < $hashsize; $i++) {
+ my($k) = int(rand(1_000_000));
+ $k = MD5->hexhash($k) if $gotmd5 and int(rand(2));
+ $a1{$k} = { key => "$k", value => $i };
+
+ # A third of the elements are references to further hashes
+
+ if (int(rand(1.5))) {
+ my($hash2) = {};
+ my($hash2size) = int(rand($maxhash2size));
+ while ($hash2size--) {
+ my($k2) = $k . $i . int(rand(100));
+ $hash2->{$k2} = $fixed_strings[rand(int(@fixed_strings))];
+ }
+ $a1{$k}->{value} = $hash2;
+ }
+
+ # A further third are references to arrays
+
+ elsif (int(rand(2))) {
+ my($arr_ref) = [];
+ my($arraysize) = int(rand($maxarraysize));
+ while ($arraysize--) {
+ push(@$arr_ref, $fixed_strings[rand(int(@fixed_strings))]);
+ }
+ $a1{$k}->{value} = $arr_ref;
+ }
+}
+
+
+print STDERR Data::Dumper::Dumper(\%a1) if ($verbose and $gotdd);
+
+
+# Copy the hash, element by element in order of the keys
+
+foreach $k (sort keys %a1) {
+ $a2{$k} = { key => "$k", value => $a1{$k}->{value} };
+}
+
+# Deep clone the hash
+
+$a3 = dclone(\%a1);
+
+# In canonical mode the frozen representation of each of the hashes
+# should be identical
+
+$Storable::canonical = 1;
+
+$x1 = freeze(\%a1);
+$x2 = freeze(\%a2);
+$x3 = freeze($a3);
+
+ok 1, (length($x1) > $hashsize); # sanity check
+ok 2, length($x1) == length($x2); # idem
+ok 3, $x1 eq $x2;
+ok 4, $x1 eq $x3;
+
+# In normal mode it is exceedingly unlikely that the frozen
+# representaions of all the hashes will be the same (normally the hash
+# elements are frozen in the order they are stored internally,
+# i.e. pseudo-randomly).
+
+$Storable::canonical = 0;
+
+$x1 = freeze(\%a1);
+$x2 = freeze(\%a2);
+$x3 = freeze($a3);
+
+
+# Two out of three the same may be a coincidence, all three the same
+# is much, much more unlikely. Still it could happen, so this test
+# may report a false negative.
+
+ok 5, ($x1 ne $x2) || ($x1 ne $x3);
+
+
+# Ensure refs to "undef" values are properly shared
+# Same test as in t/dclone.t to ensure the "canonical" code is also correct
+
+my $hash;
+push @{$$hash{''}}, \$$hash{a};
+ok 6, $$hash{''}[0] == \$$hash{a};
+
+my $cloned = dclone(dclone($hash));
+ok 7, $$cloned{''}[0] == \$$cloned{a};
+
+$$cloned{a} = "blah";
+ok 8, $$cloned{''}[0] == \$$cloned{a};
+
diff --git a/t/lib/st-dclone.t b/t/lib/st-dclone.t
new file mode 100644
index 0000000000..95407950bc
--- /dev/null
+++ b/t/lib/st-dclone.t
@@ -0,0 +1,76 @@
+#!./perl
+
+# $Id: dclone.t,v 0.7 2000/08/03 22:04:44 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: dclone.t,v $
+# Revision 0.7 2000/08/03 22:04:44 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+
+use Storable qw(dclone);
+
+print "1..9\n";
+
+$a = 'toto';
+$b = \$a;
+$c = bless {}, CLASS;
+$c->{attribute} = 'attrval';
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$c);
+@a = ('first', undef, 3, -4, -3.14159, 456, 4.5,
+ $b, \$a, $a, $c, \$c, \%a);
+
+print "not " unless defined ($aref = dclone(\@a));
+print "ok 1\n";
+
+$dumped = &dump(\@a);
+print "ok 2\n";
+
+$got = &dump($aref);
+print "ok 3\n";
+
+print "not " unless $got eq $dumped;
+print "ok 4\n";
+
+package FOO; @ISA = qw(Storable);
+
+sub make {
+ my $self = bless {};
+ $self->{key} = \%main::a;
+ return $self;
+};
+
+package main;
+
+$foo = FOO->make;
+print "not " unless defined($r = $foo->dclone);
+print "ok 5\n";
+
+print "not " unless &dump($foo) eq &dump($r);
+print "ok 6\n";
+
+# Ensure refs to "undef" values are properly shared during cloning
+my $hash;
+push @{$$hash{''}}, \$$hash{a};
+print "not " unless $$hash{''}[0] == \$$hash{a};
+print "ok 7\n";
+
+my $cloned = dclone(dclone($hash));
+print "not " unless $$cloned{''}[0] == \$$cloned{a};
+print "ok 8\n";
+
+$$cloned{a} = "blah";
+print "not " unless $$cloned{''}[0] == \$$cloned{a};
+print "ok 9\n";
+
diff --git a/t/lib/st-dump.pl b/t/lib/st-dump.pl
new file mode 100644
index 0000000000..b9f64a450d
--- /dev/null
+++ b/t/lib/st-dump.pl
@@ -0,0 +1,146 @@
+;# $Id: dump.pl,v 0.7 2000/08/03 22:04:45 ram Exp $
+;#
+;# Copyright (c) 1995-2000, Raphael Manfredi
+;#
+;# You may redistribute only under the terms of the Artistic License,
+;# as specified in the README file that comes with the distribution.
+;#
+;# $Log: dump.pl,v $
+;# Revision 0.7 2000/08/03 22:04:45 ram
+;# Baseline for second beta release.
+;#
+
+sub ok {
+ my ($num, $ok) = @_;
+ print "not " unless $ok;
+ print "ok $num\n";
+}
+
+package dump;
+use Carp;
+
+%dump = (
+ 'SCALAR' => 'dump_scalar',
+ 'ARRAY' => 'dump_array',
+ 'HASH' => 'dump_hash',
+ 'REF' => 'dump_ref',
+);
+
+# Given an object, dump its transitive data closure
+sub main'dump {
+ my ($object) = @_;
+ croak "Not a reference!" unless ref($object);
+ local %dumped;
+ local %object;
+ local $count = 0;
+ local $dumped = '';
+ &recursive_dump($object, 1);
+ return $dumped;
+}
+
+# This is the root recursive dumping routine that may indirectly be
+# called by one of the routine it calls...
+# The link parameter is set to false when the reference passed to
+# the routine is an internal temporay variable, implying the object's
+# address is not to be dumped in the %dumped table since it's not a
+# user-visible object.
+sub recursive_dump {
+ my ($object, $link) = @_;
+
+ # Get something like SCALAR(0x...) or TYPE=SCALAR(0x...).
+ # Then extract the bless, ref and address parts of that string.
+
+ my $what = "$object"; # Stringify
+ my ($bless, $ref, $addr) = $what =~ /^(\w+)=(\w+)\((0x.*)\)$/;
+ ($ref, $addr) = $what =~ /^(\w+)\((0x.*)\)$/ unless $bless;
+
+ # Special case for references to references. When stringified,
+ # they appear as being scalars. However, ref() correctly pinpoints
+ # them as being references indirections. And that's it.
+
+ $ref = 'REF' if ref($object) eq 'REF';
+
+ # Make sure the object has not been already dumped before.
+ # We don't want to duplicate data. Retrieval will know how to
+ # relink from the previously seen object.
+
+ if ($link && $dumped{$addr}++) {
+ my $num = $object{$addr};
+ $dumped .= "OBJECT #$num seen\n";
+ return;
+ }
+
+ my $objcount = $count++;
+ $object{$addr} = $objcount;
+
+ # Call the appropriate dumping routine based on the reference type.
+ # If the referenced was blessed, we bless it once the object is dumped.
+ # The retrieval code will perform the same on the last object retrieved.
+
+ croak "Unknown simple type '$ref'" unless defined $dump{$ref};
+
+ &{$dump{$ref}}($object); # Dump object
+ &bless($bless) if $bless; # Mark it as blessed, if necessary
+
+ $dumped .= "OBJECT $objcount\n";
+}
+
+# Indicate that current object is blessed
+sub bless {
+ my ($class) = @_;
+ $dumped .= "BLESS $class\n";
+}
+
+# Dump single scalar
+sub dump_scalar {
+ my ($sref) = @_;
+ my $scalar = $$sref;
+ unless (defined $scalar) {
+ $dumped .= "UNDEF\n";
+ return;
+ }
+ my $len = length($scalar);
+ $dumped .= "SCALAR len=$len $scalar\n";
+}
+
+# Dump array
+sub dump_array {
+ my ($aref) = @_;
+ my $items = 0 + @{$aref};
+ $dumped .= "ARRAY items=$items\n";
+ foreach $item (@{$aref}) {
+ unless (defined $item) {
+ $dumped .= 'ITEM_UNDEF' . "\n";
+ next;
+ }
+ $dumped .= 'ITEM ';
+ &recursive_dump(\$item, 1);
+ }
+}
+
+# Dump hash table
+sub dump_hash {
+ my ($href) = @_;
+ my $items = scalar(keys %{$href});
+ $dumped .= "HASH items=$items\n";
+ foreach $key (sort keys %{$href}) {
+ $dumped .= 'KEY ';
+ &recursive_dump(\$key, undef);
+ unless (defined $href->{$key}) {
+ $dumped .= 'VALUE_UNDEF' . "\n";
+ next;
+ }
+ $dumped .= 'VALUE ';
+ &recursive_dump(\$href->{$key}, 1);
+ }
+}
+
+# Dump reference to reference
+sub dump_ref {
+ my ($rref) = @_;
+ my $deref = $$rref; # Follow reference to reference
+ $dumped .= 'REF ';
+ &recursive_dump($deref, 1); # $dref is a reference
+}
+
+1;
diff --git a/t/lib/st-forgive.t b/t/lib/st-forgive.t
new file mode 100644
index 0000000000..1cce7c7e3a
--- /dev/null
+++ b/t/lib/st-forgive.t
@@ -0,0 +1,58 @@
+#!./perl
+
+# $Id: forgive.t,v 0.7.1.1 2000/08/03 22:04:45 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# Original Author: Ulrich Pfeifer
+# (C) Copyright 1997, Universitat Dortmund, all rights reserved.
+#
+# $Log: forgive.t,v $
+# Revision 0.7.1.1 2000/08/03 22:04:45 ram
+# Baseline for second beta release.
+#
+# Revision 0.7 2000/08/03 22:04:45 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+}
+
+use Storable qw(store retrieve);
+
+print "1..8\n";
+
+my $test = 1;
+my $bad = ['foo', sub { 1 }, 'bar'];
+my $result;
+
+eval {$result = store ($bad , 'store')};
+print ((!defined $result)?"ok $test\n":"not ok $test\n"); $test++;
+print (($@ ne '')?"ok $test\n":"not ok $test\n"); $test++;
+
+$Storable::forgive_me=1;
+
+open(SAVEERR, ">&STDERR");
+open(STDERR, ">/dev/null") or
+ ( print SAVEERR "Unable to redirect STDERR: $!\n" and exit(1) );
+
+eval {$result = store ($bad , 'store')};
+
+open(STDERR, ">&SAVEERR");
+
+print ((defined $result)?"ok $test\n":"not ok $test\n"); $test++;
+print (($@ eq '')?"ok $test\n":"not ok $test\n"); $test++;
+
+my $ret = retrieve('store');
+print ((defined $ret)?"ok $test\n":"not ok $test\n"); $test++;
+print (($ret->[0] eq 'foo')?"ok $test\n":"not ok $test\n"); $test++;
+print (($ret->[2] eq 'bar')?"ok $test\n":"not ok $test\n"); $test++;
+print ((ref $ret->[1] eq 'SCALAR')?"ok $test\n":"not ok $test\n"); $test++;
+
+
+END { unlink 'store' }
diff --git a/t/lib/st-freeze.t b/t/lib/st-freeze.t
new file mode 100644
index 0000000000..4420f11aa5
--- /dev/null
+++ b/t/lib/st-freeze.t
@@ -0,0 +1,113 @@
+#!./perl
+
+# $Id: freeze.t,v 0.7 2000/08/03 22:04:45 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: freeze.t,v $
+# Revision 0.7 2000/08/03 22:04:45 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+
+use Storable qw(freeze nfreeze thaw);
+
+print "1..15\n";
+
+$a = 'toto';
+$b = \$a;
+$c = bless {}, CLASS;
+$c->{attribute} = $b;
+$d = {};
+$e = [];
+$d->{'a'} = $e;
+$e->[0] = $d;
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$c);
+@a = ('first', undef, 3, -4, -3.14159, 456, 4.5, $d, \$d, \$e, $e,
+ $b, \$a, $a, $c, \$c, \%a);
+
+print "not " unless defined ($f1 = freeze(\@a));
+print "ok 1\n";
+
+$dumped = &dump(\@a);
+print "ok 2\n";
+
+$root = thaw($f1);
+print "not " unless defined $root;
+print "ok 3\n";
+
+$got = &dump($root);
+print "ok 4\n";
+
+print "not " unless $got eq $dumped;
+print "ok 5\n";
+
+package FOO; @ISA = qw(Storable);
+
+sub make {
+ my $self = bless {};
+ $self->{key} = \%main::a;
+ return $self;
+};
+
+package main;
+
+$foo = FOO->make;
+print "not " unless $f2 = $foo->freeze;
+print "ok 6\n";
+
+print "not " unless $f3 = $foo->nfreeze;
+print "ok 7\n";
+
+$root3 = thaw($f3);
+print "not " unless defined $root3;
+print "ok 8\n";
+
+print "not " unless &dump($foo) eq &dump($root3);
+print "ok 9\n";
+
+$root = thaw($f2);
+print "not " unless &dump($foo) eq &dump($root);
+print "ok 10\n";
+
+print "not " unless &dump($root3) eq &dump($root);
+print "ok 11\n";
+
+$other = freeze($root);
+print "not " unless length($other) == length($f2);
+print "ok 12\n";
+
+$root2 = thaw($other);
+print "not " unless &dump($root2) eq &dump($root);
+print "ok 13\n";
+
+$VAR1 = [
+ 'method',
+ 1,
+ 'prepare',
+ 'SELECT table_name, table_owner, num_rows FROM iitables
+ where table_owner != \'$ingres\' and table_owner != \'DBA\''
+];
+
+$x = nfreeze($VAR1);
+$VAR2 = thaw($x);
+print "not " unless $VAR2->[3] eq $VAR1->[3];
+print "ok 14\n";
+
+# Test the workaround for LVALUE bug in perl 5.004_04 -- from Gisle Aas
+sub foo { $_[0] = 1 }
+$foo = [];
+foo($foo->[1]);
+eval { freeze($foo) };
+print "not " if $@;
+print "ok 15\n";
+
diff --git a/t/lib/st-overload.t b/t/lib/st-overload.t
new file mode 100644
index 0000000000..bef265ff88
--- /dev/null
+++ b/t/lib/st-overload.t
@@ -0,0 +1,49 @@
+#!./perl
+
+# $Id: overload.t,v 0.7.1.1 2000/08/13 20:10:10 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: overload.t,v $
+# Revision 0.7.1.1 2000/08/13 20:10:10 ram
+# patch1: created
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+sub ok;
+
+use Storable qw(freeze thaw);
+
+print "1..7\n";
+
+package OVERLOADED;
+
+use overload
+ '""' => sub { $_[0][0] };
+
+package main;
+
+$a = bless [77], OVERLOADED;
+
+$b = thaw freeze $a;
+ok 1, ref $b eq 'OVERLOADED';
+ok 2, "$b" eq "77";
+
+$c = thaw freeze \$a;
+ok 3, ref $c eq 'REF';
+ok 4, ref $$c eq 'OVERLOADED';
+ok 5, "$$c" eq "77";
+
+$d = thaw freeze [$a, $a];
+ok 6, "$d->[0]" eq "77";
+$d->[0][0]++;
+ok 7, "$d->[1]" eq "78";
+
diff --git a/t/lib/st-recurse.t b/t/lib/st-recurse.t
new file mode 100644
index 0000000000..b177677819
--- /dev/null
+++ b/t/lib/st-recurse.t
@@ -0,0 +1,177 @@
+#!./perl
+
+# $Id: recurse.t,v 0.7 2000/08/03 22:04:45 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: recurse.t,v $
+# Revision 0.7 2000/08/03 22:04:45 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+sub ok;
+
+use Storable qw(freeze thaw dclone);
+
+print "1..23\n";
+
+package OBJ_REAL;
+
+use Storable qw(freeze thaw);
+
+@x = ('a', 1);
+
+sub make { bless [], shift }
+
+sub STORABLE_freeze {
+ my $self = shift;
+ my $cloning = shift;
+ die "STORABLE_freeze" unless Storable::is_storing;
+ return (freeze(\@x), $self);
+}
+
+sub STORABLE_thaw {
+ my $self = shift;
+ my $cloning = shift;
+ my ($x, $obj) = @_;
+ die "STORABLE_thaw #1" unless $obj eq $self;
+ my $len = length $x;
+ my $a = thaw $x;
+ die "STORABLE_thaw #2" unless ref $a eq 'ARRAY';
+ die "STORABLE_thaw #3" unless @$a == 2 && $a->[0] eq 'a' && $a->[1] == 1;
+ @$self = @$a;
+ die "STORABLE_thaw #4" unless Storable::is_retrieving;
+}
+
+package OBJ_SYNC;
+
+@x = ('a', 1);
+
+sub make { bless {}, shift }
+
+sub STORABLE_freeze {
+ my $self = shift;
+ my ($cloning) = @_;
+ return if $cloning;
+ return ("", \@x, $self);
+}
+
+sub STORABLE_thaw {
+ my $self = shift;
+ my ($cloning, $undef, $a, $obj) = @_;
+ die "STORABLE_thaw #1" unless $obj eq $self;
+ die "STORABLE_thaw #2" unless ref $a eq 'ARRAY' || @$a != 2;
+ $self->{ok} = $self;
+}
+
+package OBJ_SYNC2;
+
+use Storable qw(dclone);
+
+sub make {
+ my $self = bless {}, shift;
+ my ($ext) = @_;
+ $self->{sync} = OBJ_SYNC->make;
+ $self->{ext} = $ext;
+ return $self;
+}
+
+sub STORABLE_freeze {
+ my $self = shift;
+ my $t = dclone($self->{sync});
+ return ("", [$t, $self->{ext}], $self, $self->{ext});
+}
+
+sub STORABLE_thaw {
+ my $self = shift;
+ my ($cloning, $undef, $a, $obj, $ext) = @_;
+ die "STORABLE_thaw #1" unless $obj eq $self;
+ die "STORABLE_thaw #2" unless ref $a eq 'ARRAY';
+ $self->{ok} = $self;
+ ($self->{sync}, $self->{ext}) = @$a;
+}
+
+package OBJ_REAL2;
+
+use Storable qw(freeze thaw);
+
+$MAX = 20;
+$recursed = 0;
+$hook_called = 0;
+
+sub make { bless [], shift }
+
+sub STORABLE_freeze {
+ my $self = shift;
+ $hook_called++;
+ return (freeze($self), $self) if ++$recursed < $MAX;
+ return ("no", $self);
+}
+
+sub STORABLE_thaw {
+ my $self = shift;
+ my $cloning = shift;
+ my ($x, $obj) = @_;
+ die "STORABLE_thaw #1" unless $obj eq $self;
+ $self->[0] = thaw($x) if $x ne "no";
+ $recursed--;
+}
+
+package main;
+
+my $real = OBJ_REAL->make;
+my $x = freeze $real;
+ok 1, 1;
+
+my $y = thaw $x;
+ok 2, 1;
+ok 3, $y->[0] eq 'a';
+ok 4, $y->[1] == 1;
+
+my $sync = OBJ_SYNC->make;
+$x = freeze $sync;
+ok 5, 1;
+
+$y = thaw $x;
+ok 6, 1;
+ok 7, $y->{ok} == $y;
+
+my $ext = [1, 2];
+$sync = OBJ_SYNC2->make($ext);
+$x = freeze [$sync, $ext];
+ok 8, 1;
+
+my $z = thaw $x;
+$y = $z->[0];
+ok 9, 1;
+ok 10, $y->{ok} == $y;
+ok 11, ref $y->{sync} eq 'OBJ_SYNC';
+ok 12, $y->{ext} == $z->[1];
+
+$real = OBJ_REAL2->make;
+$x = freeze $real;
+ok 13, 1;
+ok 14, $OBJ_REAL2::recursed == $OBJ_REAL2::MAX;
+ok 15, $OBJ_REAL2::hook_called == $OBJ_REAL2::MAX;
+
+$y = thaw $x;
+ok 16, 1;
+ok 17, $OBJ_REAL2::recursed == 0;
+
+$x = dclone $real;
+ok 18, 1;
+ok 19, ref $x eq 'OBJ_REAL2';
+ok 20, $OBJ_REAL2::recursed == 0;
+ok 21, $OBJ_REAL2::hook_called == 2 * $OBJ_REAL2::MAX;
+
+ok 22, !Storable::is_storing;
+ok 23, !Storable::is_retrieving;
diff --git a/t/lib/st-retrieve.t b/t/lib/st-retrieve.t
new file mode 100644
index 0000000000..463262f9d8
--- /dev/null
+++ b/t/lib/st-retrieve.t
@@ -0,0 +1,72 @@
+#!./perl
+
+# $Id: retrieve.t,v 0.7 2000/08/03 22:04:45 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: retrieve.t,v $
+# Revision 0.7 2000/08/03 22:04:45 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+
+use Storable qw(store retrieve nstore);
+
+print "1..14\n";
+
+$a = 'toto';
+$b = \$a;
+$c = bless {}, CLASS;
+$c->{attribute} = 'attrval';
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$c);
+@a = ('first', '', undef, 3, -4, -3.14159, 456, 4.5,
+ $b, \$a, $a, $c, \$c, \%a);
+
+print "not " unless defined store(\@a, 'store');
+print "ok 1\n";
+print "not " if Storable::last_op_in_netorder();
+print "ok 2\n";
+print "not " unless defined nstore(\@a, 'nstore');
+print "ok 3\n";
+print "not " unless Storable::last_op_in_netorder();
+print "ok 4\n";
+print "not " unless Storable::last_op_in_netorder();
+print "ok 5\n";
+
+$root = retrieve('store');
+print "not " unless defined $root;
+print "ok 6\n";
+print "not " if Storable::last_op_in_netorder();
+print "ok 7\n";
+
+$nroot = retrieve('nstore');
+print "not " unless defined $nroot;
+print "ok 8\n";
+print "not " unless Storable::last_op_in_netorder();
+print "ok 9\n";
+
+$d1 = &dump($root);
+print "ok 10\n";
+$d2 = &dump($nroot);
+print "ok 11\n";
+
+print "not " unless $d1 eq $d2;
+print "ok 12\n";
+
+# Make sure empty string is defined at retrieval time
+print "not " unless defined $root->[1];
+print "ok 13\n";
+print "not " if length $root->[1];
+print "ok 14\n";
+
+END { unlink 'store', 'nstore' }
+
diff --git a/t/lib/st-store.t b/t/lib/st-store.t
new file mode 100644
index 0000000000..fe76499211
--- /dev/null
+++ b/t/lib/st-store.t
@@ -0,0 +1,114 @@
+#!./perl
+
+# $Id: store.t,v 0.7 2000/08/03 22:04:45 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: store.t,v $
+# Revision 0.7 2000/08/03 22:04:45 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+
+use Storable qw(store retrieve store_fd nstore_fd retrieve_fd);
+
+print "1..20\n";
+
+$a = 'toto';
+$b = \$a;
+$c = bless {}, CLASS;
+$c->{attribute} = 'attrval';
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$c);
+@a = ('first', undef, 3, -4, -3.14159, 456, 4.5,
+ $b, \$a, $a, $c, \$c, \%a);
+
+print "not " unless defined store(\@a, 'store');
+print "ok 1\n";
+
+$dumped = &dump(\@a);
+print "ok 2\n";
+
+$root = retrieve('store');
+print "not " unless defined $root;
+print "ok 3\n";
+
+$got = &dump($root);
+print "ok 4\n";
+
+print "not " unless $got eq $dumped;
+print "ok 5\n";
+
+unlink 'store';
+
+package FOO; @ISA = qw(Storable);
+
+sub make {
+ my $self = bless {};
+ $self->{key} = \%main::a;
+ return $self;
+};
+
+package main;
+
+$foo = FOO->make;
+print "not " unless $foo->store('store');
+print "ok 6\n";
+
+print "not " unless open(OUT, '>>store');
+print "ok 7\n";
+binmode OUT;
+
+print "not " unless defined store_fd(\@a, ::OUT);
+print "ok 8\n";
+print "not " unless defined nstore_fd($foo, ::OUT);
+print "ok 9\n";
+print "not " unless defined nstore_fd(\%a, ::OUT);
+print "ok 10\n";
+
+print "not " unless close(OUT);
+print "ok 11\n";
+
+print "not " unless open(OUT, 'store');
+binmode OUT;
+
+$r = retrieve_fd(::OUT);
+print "not " unless defined $r;
+print "ok 12\n";
+print "not " unless &dump($foo) eq &dump($r);
+print "ok 13\n";
+
+$r = retrieve_fd(::OUT);
+print "not " unless defined $r;
+print "ok 14\n";
+print "not " unless &dump(\@a) eq &dump($r);
+print "ok 15\n";
+
+$r = retrieve_fd(main::OUT);
+print "not " unless defined $r;
+print "ok 16\n";
+print "not " unless &dump($foo) eq &dump($r);
+print "ok 17\n";
+
+$r = retrieve_fd(::OUT);
+print "not " unless defined $r;
+print "ok 18\n";
+print "not " unless &dump(\%a) eq &dump($r);
+print "ok 19\n";
+
+eval { $r = retrieve_fd(::OUT); };
+print "not " unless $@;
+print "ok 20\n";
+
+close OUT;
+END { unlink 'store' }
+
+
diff --git a/t/lib/st-tied.t b/t/lib/st-tied.t
new file mode 100644
index 0000000000..52d0da919c
--- /dev/null
+++ b/t/lib/st-tied.t
@@ -0,0 +1,210 @@
+#!./perl
+
+# $Id: tied.t,v 0.7.1.1 2000/08/13 20:10:27 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: tied.t,v $
+# Revision 0.7.1.1 2000/08/13 20:10:27 ram
+# patch1: added test case for "undef" in hashes
+#
+# Revision 0.7 2000/08/03 22:04:45 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+sub ok;
+
+use Storable qw(freeze thaw);
+
+print "1..22\n";
+
+($scalar_fetch, $array_fetch, $hash_fetch) = (0, 0, 0);
+
+package TIED_HASH;
+
+sub TIEHASH {
+ my $self = bless {}, shift;
+ return $self;
+}
+
+sub FETCH {
+ my $self = shift;
+ my ($key) = @_;
+ $main::hash_fetch++;
+ return $self->{$key};
+}
+
+sub STORE {
+ my $self = shift;
+ my ($key, $value) = @_;
+ $self->{$key} = $value;
+}
+
+sub FIRSTKEY {
+ my $self = shift;
+ scalar keys %{$self};
+ return each %{$self};
+}
+
+sub NEXTKEY {
+ my $self = shift;
+ return each %{$self};
+}
+
+package TIED_ARRAY;
+
+sub TIEARRAY {
+ my $self = bless [], shift;
+ return $self;
+}
+
+sub FETCH {
+ my $self = shift;
+ my ($idx) = @_;
+ $main::array_fetch++;
+ return $self->[$idx];
+}
+
+sub STORE {
+ my $self = shift;
+ my ($idx, $value) = @_;
+ $self->[$idx] = $value;
+}
+
+sub FETCHSIZE {
+ my $self = shift;
+ return @{$self};
+}
+
+package TIED_SCALAR;
+
+sub TIESCALAR {
+ my $scalar;
+ my $self = bless \$scalar, shift;
+ return $self;
+}
+
+sub FETCH {
+ my $self = shift;
+ $main::scalar_fetch++;
+ return $$self;
+}
+
+sub STORE {
+ my $self = shift;
+ my ($value) = @_;
+ $$self = $value;
+}
+
+package FAULT;
+
+$fault = 0;
+
+sub TIESCALAR {
+ my $pkg = shift;
+ return bless [@_], $pkg;
+}
+
+sub FETCH {
+ my $self = shift;
+ my ($href, $key) = @$self;
+ $fault++;
+ untie $href->{$key};
+ return $href->{$key} = 1;
+}
+
+package main;
+
+$a = 'toto';
+$b = \$a;
+
+$c = tie %hash, TIED_HASH;
+$d = tie @array, TIED_ARRAY;
+tie $scalar, TIED_SCALAR;
+
+#$scalar = 'foo';
+#$hash{'attribute'} = \$d;
+#$array[0] = $c;
+#$array[1] = \$scalar;
+
+### If I say
+### $hash{'attribute'} = $d;
+### below, then dump() incorectly dumps the hash value as a string the second
+### time it is reached. I have not investigated enough to tell whether it's
+### a bug in my dump() routine or in the Perl tieing mechanism.
+$scalar = 'foo';
+$hash{'attribute'} = 'plain value';
+$array[0] = \$scalar;
+$array[1] = $c;
+$array[2] = \@array;
+
+@tied = (\$scalar, \@array, \%hash);
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$a, 'scalarref', \$scalar);
+@a = ('first', 3, -4, -3.14159, 456, 4.5, $d, \$d,
+ $b, \$a, $a, $c, \$c, \%a, \@array, \%hash, \@tied);
+
+ok 1, defined($f = freeze(\@a));
+
+$dumped = &dump(\@a);
+ok 2, 1;
+
+$root = thaw($f);
+ok 3, defined $root;
+
+$got = &dump($root);
+ok 4, 1;
+
+### Used to see the manifestation of the bug documented above.
+### print "original: $dumped";
+### print "--------\n";
+### print "got: $got";
+### print "--------\n";
+
+ok 5, $got eq $dumped;
+
+$g = freeze($root);
+ok 6, length($f) == length($g);
+
+# Ensure the tied items in the retrieved image work
+@old = ($scalar_fetch, $array_fetch, $hash_fetch);
+@tied = ($tscalar, $tarray, $thash) = @{$root->[$#{$root}]};
+@type = qw(SCALAR ARRAY HASH);
+
+ok 7, tied $$tscalar;
+ok 8, tied @{$tarray};
+ok 9, tied %{$thash};
+
+@new = ($$tscalar, $tarray->[0], $thash->{'attribute'});
+@new = ($scalar_fetch, $array_fetch, $hash_fetch);
+
+# Tests 10..15
+for ($i = 0; $i < @new; $i++) {
+ print "not " unless $new[$i] == $old[$i] + 1;
+ printf "ok %d\n", 10 + 2*$i; # Tests 10,12,14
+ print "not " unless ref $tied[$i] eq $type[$i];
+ printf "ok %d\n", 11 + 2*$i; # Tests 11,13,15
+}
+
+# Check undef ties
+my $h = {};
+tie $h->{'x'}, 'FAULT', $h, 'x';
+my $hf = freeze($h);
+ok 16, defined $hf;
+ok 17, $FAULT::fault == 0;
+ok 18, $h->{'x'} == 1;
+ok 19, $FAULT::fault == 1;
+
+my $ht = thaw($hf);
+ok 20, defined $ht;
+ok 21, $ht->{'x'} == 1;
+ok 22, $FAULT::fault == 2;
+
diff --git a/t/lib/st-tiedhook.t b/t/lib/st-tiedhook.t
new file mode 100644
index 0000000000..3f1b7fd875
--- /dev/null
+++ b/t/lib/st-tiedhook.t
@@ -0,0 +1,209 @@
+#!./perl
+
+# $Id: tied_hook.t,v 0.7 2000/08/03 22:04:45 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: tied_hook.t,v $
+# Revision 0.7 2000/08/03 22:04:45 ram
+# Baseline for second beta release.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+sub ok;
+
+use Storable qw(freeze thaw);
+
+print "1..21\n";
+
+($scalar_fetch, $array_fetch, $hash_fetch) = (0, 0, 0);
+
+package TIED_HASH;
+
+sub TIEHASH {
+ my $self = bless {}, shift;
+ return $self;
+}
+
+sub FETCH {
+ my $self = shift;
+ my ($key) = @_;
+ $main::hash_fetch++;
+ return $self->{$key};
+}
+
+sub STORE {
+ my $self = shift;
+ my ($key, $value) = @_;
+ $self->{$key} = $value;
+}
+
+sub FIRSTKEY {
+ my $self = shift;
+ scalar keys %{$self};
+ return each %{$self};
+}
+
+sub NEXTKEY {
+ my $self = shift;
+ return each %{$self};
+}
+
+sub STORABLE_freeze {
+ my $self = shift;
+ $main::hash_hook1++;
+ return join(":", keys %$self) . ";" . join(":", values %$self);
+}
+
+sub STORABLE_thaw {
+ my ($self, $cloning, $frozen) = @_;
+ my ($keys, $values) = split(/;/, $frozen);
+ my @keys = split(/:/, $keys);
+ my @values = split(/:/, $values);
+ for (my $i = 0; $i < @keys; $i++) {
+ $self->{$keys[$i]} = $values[$i];
+ }
+ $main::hash_hook2++;
+}
+
+package TIED_ARRAY;
+
+sub TIEARRAY {
+ my $self = bless [], shift;
+ return $self;
+}
+
+sub FETCH {
+ my $self = shift;
+ my ($idx) = @_;
+ $main::array_fetch++;
+ return $self->[$idx];
+}
+
+sub STORE {
+ my $self = shift;
+ my ($idx, $value) = @_;
+ $self->[$idx] = $value;
+}
+
+sub FETCHSIZE {
+ my $self = shift;
+ return @{$self};
+}
+
+sub STORABLE_freeze {
+ my $self = shift;
+ $main::array_hook1++;
+ return join(":", @$self);
+}
+
+sub STORABLE_thaw {
+ my ($self, $cloning, $frozen) = @_;
+ @$self = split(/:/, $frozen);
+ $main::array_hook2++;
+}
+
+package TIED_SCALAR;
+
+sub TIESCALAR {
+ my $scalar;
+ my $self = bless \$scalar, shift;
+ return $self;
+}
+
+sub FETCH {
+ my $self = shift;
+ $main::scalar_fetch++;
+ return $$self;
+}
+
+sub STORE {
+ my $self = shift;
+ my ($value) = @_;
+ $$self = $value;
+}
+
+sub STORABLE_freeze {
+ my $self = shift;
+ $main::scalar_hook1++;
+ return $$self;
+}
+
+sub STORABLE_thaw {
+ my ($self, $cloning, $frozen) = @_;
+ $$self = $frozen;
+ $main::scalar_hook2++;
+}
+
+package main;
+
+$a = 'toto';
+$b = \$a;
+
+$c = tie %hash, TIED_HASH;
+$d = tie @array, TIED_ARRAY;
+tie $scalar, TIED_SCALAR;
+
+$scalar = 'foo';
+$hash{'attribute'} = 'plain value';
+$array[0] = \$scalar;
+$array[1] = $c;
+$array[2] = \@array;
+$array[3] = "plaine scalaire";
+
+@tied = (\$scalar, \@array, \%hash);
+%a = ('key', 'value', 1, 0, $a, $b, 'cvar', \$a, 'scalarref', \$scalar);
+@a = ('first', 3, -4, -3.14159, 456, 4.5, $d, \$d,
+ $b, \$a, $a, $c, \$c, \%a, \@array, \%hash, \@tied);
+
+ok 1, defined($f = freeze(\@a));
+
+$dumped = &dump(\@a);
+ok 2, 1;
+
+$root = thaw($f);
+ok 3, defined $root;
+
+$got = &dump($root);
+ok 4, 1;
+
+ok 5, $got ne $dumped; # our hooks did not handle refs in array
+
+$g = freeze($root);
+ok 6, length($f) == length($g);
+
+# Ensure the tied items in the retrieved image work
+@old = ($scalar_fetch, $array_fetch, $hash_fetch);
+@tied = ($tscalar, $tarray, $thash) = @{$root->[$#{$root}]};
+@type = qw(SCALAR ARRAY HASH);
+
+ok 7, tied $$tscalar;
+ok 8, tied @{$tarray};
+ok 9, tied %{$thash};
+
+@new = ($$tscalar, $tarray->[0], $thash->{'attribute'});
+@new = ($scalar_fetch, $array_fetch, $hash_fetch);
+
+# Tests 10..15
+for ($i = 0; $i < @new; $i++) {
+ ok 10 + 2*$i, $new[$i] == $old[$i] + 1; # Tests 10,12,14
+ ok 11 + 2*$i, ref $tied[$i] eq $type[$i]; # Tests 11,13,15
+}
+
+ok 16, $$tscalar eq 'foo';
+ok 17, $tarray->[3] eq 'plaine scalaire';
+ok 18, $thash->{'attribute'} eq 'plain value';
+
+# Ensure hooks were called
+ok 19, ($scalar_hook1 && $scalar_hook2);
+ok 20, ($array_hook1 && $array_hook2);
+ok 21, ($hash_hook1 && $hash_hook2);
+
diff --git a/t/lib/st-tieditems.t b/t/lib/st-tieditems.t
new file mode 100644
index 0000000000..e8b127de45
--- /dev/null
+++ b/t/lib/st-tieditems.t
@@ -0,0 +1,65 @@
+#!./perl
+
+# $Id: tied_items.t,v 0.7.1.2 2000/08/14 07:20:35 ram Exp $
+#
+# Copyright (c) 1995-2000, Raphael Manfredi
+#
+# You may redistribute only under the terms of the Artistic License,
+# as specified in the README file that comes with the distribution.
+#
+# $Log: tied_items.t,v $
+# Revision 0.7.1.2 2000/08/14 07:20:35 ram
+# patch2: removed spurious dependency to Devel::Peek, used for testing only
+#
+# Revision 0.7.1.1 2000/08/13 20:10:31 ram
+# patch1: created
+#
+
+#
+# Tests ref to items in tied hash/array structures.
+#
+
+sub BEGIN {
+ chdir('t') if -d 't';
+ unshift @INC, '../lib';
+ require 'lib/st-dump.pl';
+}
+
+sub ok;
+$^W = 0;
+
+print "1..8\n";
+
+use Storable qw(dclone);
+
+$h_fetches = 0;
+
+sub H::TIEHASH { bless \(my $x), "H" }
+sub H::FETCH { $h_fetches++; $_[1] - 70 }
+
+tie %h, "H";
+
+$ref = \$h{77};
+$ref2 = dclone $ref;
+
+ok 1, $h_fetches == 0;
+ok 2, $$ref2 eq $$ref;
+ok 3, $$ref2 == 7;
+ok 4, $h_fetches == 2;
+
+$a_fetches = 0;
+
+sub A::TIEARRAY { bless \(my $x), "A" }
+sub A::FETCH { $a_fetches++; $_[1] - 70 }
+
+tie @a, "A";
+
+$ref = \$a[78];
+$ref2 = dclone $ref;
+
+ok 5, $a_fetches == 0;
+ok 6, $$ref2 eq $$ref;
+ok 7, $$ref2 == 8;
+# I don't understand why it's 3 and not 2
+ok 8, $a_fetches == 3;
+