Database-Join
view release on metacpan or search on metacpan
t/transition.t view on Meta::CPAN
#!/usr/bin/perl
# t/transition.t â Finite State Machine transition tests for Database::Join.
#
# Validates every documented state transition derived from the Z calculus
# FORMAL SPECIFICATION in lib/Database/Join.pm:
#
# FSM 1 â Object Lifecycle (ÎDatabase_Join / ÎDatabase_Join schemas)
# FSM 2 â SQLite Cache Lifecycle (_cache_fresh / _build_sqlite_cache)
# FSM 3 â Column Visibility (ÎDatabase_Join RemoveColumn schema)
#
# Each subtest is named after the transition it covers:
# "State: <source> -> Trigger: <op> -> State: <destination>"
use strict;
use warnings;
use Test::Most tests => 54;
use Readonly;
use Scalar::Util qw(blessed refaddr);
use_ok('Database::Join');
# ---------------------------------------------------------------------------
# Inline test doubles
# ---------------------------------------------------------------------------
{
package TransDA;
use parent -norequire, 'Database::Abstraction';
sub new {
my ($class, %a) = @_;
return bless {
cols => $a{cols} // ['entry'],
rows => $a{rows} // [],
id => $a{id} // 'entry',
schema => $a{schema} // {},
updated => $a{updated} // 1,
_calls => 0,
_logger => undef,
}, $class;
}
sub columns { return $_[0]->{cols} }
sub schema { return $_[0]->{schema} // {} }
sub updated { return $_[0]->{updated} }
sub call_count { return $_[0]->{_calls} }
sub set_logger { $_[0]->{_logger} = $_[1]; return $_[0] }
sub selectall_arrayref {
my ($self, $crit) = @_;
$self->{_calls}++;
$crit //= {};
my @out;
ROW: for my $row (@{ $self->{rows} }) {
for my $col (keys %{$crit}) {
my $v = $crit->{$col};
if (ref($v) eq 'HASH') {
for my $op (keys %{$v}) {
my $rhs = $v->{$op};
if ($op eq '>') { next ROW unless defined $row->{$col} && $row->{$col} > $rhs }
elsif ($op eq '<') { next ROW unless defined $row->{$col} && $row->{$col} < $rhs }
}
} elsif (defined $v) {
next ROW unless defined $row->{$col} && $row->{$col} eq $v;
}
}
push @out, { %{$row} };
}
return \@out;
}
sub DESTROY {}
}
# DA with mutable updated() â exercises FRESHâSTALEâFRESH cache transitions
{
package TransUpdDA;
use parent -norequire, 'TransDA';
sub set_updated { $_[0]->{updated} = $_[1]; return $_[0] }
sub DESTROY {}
}
# WhiteBox subclass to call _cache_fresh() (Sub::Protected method)
{
package Database::Join::TransBox;
use parent -norequire, 'Database::Join';
sub expose_cache_fresh { my $self = shift; return $self->_cache_fresh(@_) }
}
# ---------------------------------------------------------------------------
# Shared constants
# ---------------------------------------------------------------------------
Readonly::Scalar my $JC => 'entry';
Readonly::Hash my %ERR => (
no_dbs => qr/At least one Database::Abstraction object is required/,
remove_join_col => qr/Cannot remove join_column/,
invalid_db => qr/databases\[\d+\] does not support/,
join_col_absent => qr/join_column "[^"]*" is absent from databases/,
);
# Standard two-DA fixture: primary (name), secondary (score), left join.
sub _mk_join {
my %o = @_;
my $p = TransDA->new(
cols => [$JC, 'name'],
( run in 0.362 second using v1.01-cache-2.11-cpan-7da0f45c409 )