#!/usr/bin/perl
use strict;
use warnings;
use Test::More;
use Scalar::Util qw(refaddr reftype blessed);
use ok 'KiokuDB::TypeMap::Entry::StorableHook';
use ok 'KiokuDB::TypeMap::Resolver';
use ok 'KiokuDB::Collapser';
use ok 'KiokuDB::Linker';
use ok 'KiokuDB::LiveObjects';
use ok 'KiokuDB::Backend::Hash';
BEGIN { eval 'use Test::Memory::Cycle; 1' or eval 'sub memory_cycle_ok {}' }
{
package KiokuDB_Test_Foo;
use Moose;
has foo => ( is => "rw" );
has bar => ( is => "rw", isa => "KiokuDB_Test_Bar", predicate => "has_bar" );
sub STORABLE_freeze {
my ( $self, $cloning ) = @_;
return ( $self->foo, $self->has_bar ? $self->bar : () );
}
sub STORABLE_thaw {
my ( $self, $cloning, $foo, $bar ) = @_;
$self->foo($foo);
$self->bar($bar) if ref $bar;
}
package KiokuDB_Test_Bar;
use Moose;
has blah => ( is => "rw" );
has foo => ( is => "rw", weak_ref => 1 );
package KiokuDB_Test_Gorch;
use Moose;
has name => ( is => "rw" );
sub STORABLE_freeze {
my ( $self, $cloning );
return $self->name;
}
sub STORABLE_attach {
my ( $class, $cloning, $name ) = @_;
$class->new( name => $name );
}
}
my $obj = KiokuDB_Test_Foo->new( foo => "HALLO" );
my $deep = KiokuDB_Test_Foo->new( foo => "la", bar => KiokuDB_Test_Bar->new( blah => "hai" ) );
my $circular = KiokuDB_Test_Foo->new( foo => "oink", bar => KiokuDB_Test_Bar->new( blah => "three" ) );
$circular->bar->foo($circular);
my $attach = KiokuDB_Test_Gorch->new( name => "blah" );
my $s = KiokuDB::TypeMap::Entry::StorableHook->new;
my $tr = KiokuDB::TypeMap::Resolver->new(
typemap => KiokuDB::TypeMap->new(
entries => {
KiokuDB_Test_Foo => $s,
},
),
);
my $v = KiokuDB::Collapser->new(
backend => KiokuDB::Backend::Hash->new,
live_objects => KiokuDB::LiveObjects->new,
typemap_resolver => $tr,
);
my $l = KiokuDB::Linker->new(
backend => KiokuDB::Backend::Hash->new,
live_objects => KiokuDB::LiveObjects->new,
typemap_resolver => $tr,
);
{
my $s = $v->live_objects->new_scope;
my ( $buffer ) = $v->collapse( objects => [ $obj ], );
my $entries = $buffer->_entries;
is( scalar(keys %$entries), 1, "one entry" );
my $entry = ( values %$entries )[0];
isnt( refaddr($entry->data), refaddr($obj), "refaddr doesn't equal" );
ok( !blessed($entry->data), "entry data is not blessed" );
my $sl = $l->live_objects->new_scope;
my $expanded = $l->expand_object($entry);
isa_ok( $expanded, "KiokuDB_Test_Foo", "expanded object" );
isnt( refaddr($expanded), refaddr($obj), "refaddr doesn't equal" );
isnt( refaddr($expanded), refaddr($entry->data), "refaddr doesn't entry data refaddr" );
is_deeply( $expanded, $obj, "is_deeply" );
}
{
my $s = $v->live_objects->new_scope;
my $bar = $deep->bar;
my ( $buffer, $id ) = $v->collapse( objects => [ $deep ], );
my $entries = $buffer->_entries;
is( scalar(keys %$entries), 2, "two entries" );
$l->backend->insert(values %$entries);
my $entry = $entries->{$id};
isnt( refaddr($entry->data), refaddr($deep), "refaddr doesn't equal" );
ok( !blessed($entry->data), "entry data is not blessed" );
my $sl = $l->live_objects->new_scope;
my $expanded = $l->expand_object($entry);
isa_ok( $expanded, "KiokuDB_Test_Foo", "expanded object" );
isnt( refaddr($expanded), refaddr($deep), "refaddr doesn't equal" );
isnt( refaddr($expanded), refaddr($entry->data), "refaddr doesn't entry data refaddr" );
is_deeply( $expanded, $deep, "is_deeply" );
}
{
my $s = $v->live_objects->new_scope;
my $bar = $deep->bar;
my ( $buffer, $id ) = $v->collapse( objects => [ $circular ], );
my $entries = $buffer->_entries;
is( scalar(keys %$entries), 2, "two entries" );
$l->backend->insert(values %$entries);
my $entry = $entries->{$id};
isnt( refaddr($entry->data), refaddr($circular), "refaddr doesn't equal" );
ok( !blessed($entry->data), "entry data is not blessed" );
my $sl = $l->live_objects->new_scope;
my $expanded = $l->expand_object($entry);
isa_ok( $expanded, "KiokuDB_Test_Foo", "expanded object" );
isnt( refaddr($expanded), refaddr($circular), "refaddr doesn't equal" );
isnt( refaddr($expanded), refaddr($entry->data), "refaddr doesn't entry data refaddr" );
is_deeply( $expanded, $circular, "is_deeply" );
is( refaddr($expanded->bar->foo), refaddr($expanded), "circular ref" );
memory_cycle_ok($expanded, "weakened");
}
is_deeply( [ $l->live_objects->live_objects ], [], "no live objects" );
{
my $s = $v->live_objects->new_scope;
my ( $buffer ) = $v->collapse( objects => [ $attach ], );
my $entries = $buffer->_entries;
is( scalar(keys %$entries), 1, "one entry" );
my $entry = ( values %$entries )[0];
isnt( refaddr($entry->data), refaddr($attach), "refaddr doesn't equal" );
ok( !blessed($entry->data), "entry data is not blessed" );
my $sl = $l->live_objects->new_scope;
my $expanded = $l->expand_object($entry);
isa_ok( $expanded, "KiokuDB_Test_Gorch", "expanded object" );
isnt( refaddr($expanded), refaddr($obj), "refaddr doesn't equal" );
isnt( refaddr($expanded), refaddr($entry->data), "refaddr doesn't entry data refaddr" );
is_deeply( $expanded, $attach, "is_deeply" );
}
done_testing;