Database-Join
view release on metacpan or search on metacpan
#!/usr/bin/perl
# Domain tests for Database::Join using Equivalence Partitioning (EP) and
# Boundary Value Analysis (BVA). Each parameter's valid and invalid partitions
# are tested with representative values; exact boundary edges are exercised
# wherever a numerical range, array size, or string length applies.
use strict;
use warnings;
use Test::Most tests => 202;
use Readonly;
use Scalar::Util qw(blessed);
use File::Spec;
use_ok('Database::Join');
# ---------------------------------------------------------------------------
# Inline test double: configurable in-memory Database::Abstraction subclass.
# Supports equality filtering and operator hashrefs (>, <, >=, <=, !=).
# ---------------------------------------------------------------------------
{
package DomainDA;
use parent -norequire, 'Database::Abstraction';
Readonly::Scalar my $UPDATED => '2026-01-01';
sub new {
my ($class, %args) = @_;
return bless {
cols => $args{cols} // ['entry'],
rows => $args{rows} // [],
id => $args{id} // 'entry',
updated => $args{updated} // $UPDATED,
schema => $args{schema} // {},
}, $class;
}
sub columns { return $_[0]->{cols} }
sub schema { return $_[0]->{schema} }
sub updated { return $_[0]->{updated} }
sub selectall_arrayref {
my ($self, $criteria) = @_;
$criteria //= {};
my @results;
ROW: for my $row (@{ $self->{rows} }) {
for my $col (keys %{$criteria}) {
my $val = $criteria->{$col};
if (ref $val eq 'HASH') {
for my $op (keys %{$val}) {
my $rhs = $val->{$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 ($op eq '>=') { next ROW unless defined $row->{$col} && $row->{$col} >= $rhs }
elsif ($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 $val) {
next ROW if defined $row->{$col};
} else {
next ROW unless defined $row->{$col} && $row->{$col} eq $val;
}
}
push @results, { %{$row} };
}
return \@results;
}
sub DESTROY {}
}
# ---------------------------------------------------------------------------
# Wrong-class sentinel: blessed but not a Database::Abstraction subclass.
# ---------------------------------------------------------------------------
{
package WrongClass;
sub new { return bless {}, shift }
}
# ---------------------------------------------------------------------------
# DomainCountDA: subclass of DomainDA that defines count() directly in its
# own package stash. Required for the 'auto' threshold probe in _sqlite_join,
# which checks `defined &{"${pkg}::count"}` and rejects inherited methods.
# Without this, the probe cannot obtain a row count and falls back to the
# array path regardless of max_array_rows, defeating threshold domain tests.
# ---------------------------------------------------------------------------
{
package DomainCountDA;
use parent -norequire, 'DomainDA';
# count() is defined here (not inherited) so the auto-threshold check finds it.
sub count { return scalar @{ $_[0]->{rows} } }
}
# ---------------------------------------------------------------------------
# Constants â no magic strings in test bodies.
# ---------------------------------------------------------------------------
Readonly::Scalar my $JC => 'entry';
Readonly::Scalar my $LONG_COLNAME => 'x' x 255; # 255-char boundary for join_column length
( run in 0.328 second using v1.01-cache-2.11-cpan-7da0f45c409 )