Class-Abstract
view release on metacpan or search on metacpan
t/integration.t view on Meta::CPAN
my $dog = IT::Dog->new();
my $cat = IT::Cat->new();
my $sparrow;
enforcement_on { lives_ok { $sparrow = IT::Sparrow->new() } 'sparrow created' };
# Every object must be blessed (confirmed via Scalar::Util::blessed)
ok blessed($car), 'IT::Car object satisfies blessed()';
ok blessed($truck), 'IT::Truck object satisfies blessed()';
ok blessed($dog), 'IT::Dog object satisfies blessed()';
ok blessed($cat), 'IT::Cat object satisfies blessed()';
};
# ===========================================================================
# INTEGRATION: blessed abstract-class object used as new() invocant
#
# When an existing object of an abstract class is used as invocant to new(),
# new() extracts the class via blessed() and then checks if that class is
# abstract. With enforcement on, the croak fires because the extracted
# class IS the abstract class.
# ===========================================================================
subtest 'end-to-end: blessed abstract instance as new() invocant causes croak' => sub {
plan tests => 3;
# Create an abstract instance using bypass (to get past enforcement)
my $abstract_obj;
{
local $Class::Abstract::BYPASS = 1;
$abstract_obj = IT::Vehicle->new();
}
ok blessed($abstract_obj), 'precondition: abstract instance created under bypass';
is ref($abstract_obj), 'IT::Vehicle',
'precondition: instance is blessed into IT::Vehicle (abstract)';
# With enforcement on, passing this object to new() must croak
enforcement_on {
throws_ok { Class::Abstract::new($abstract_obj) }
qr/Cannot instantiate abstract class IT::Vehicle directly/,
'new(blessed abstract obj) croaks after extracting abstract class from blessed ref';
};
};
# ===========================================================================
# INTEGRATION: production context across full hierarchy
#
# Simulates running outside a harness (HARNESS_ACTIVE unset, harness_bypass=1)
# with no BYPASS. This is the default deployment scenario.
# ===========================================================================
subtest 'end-to-end: enforcement in production context (no harness, default settings)' => sub {
plan tests => 3;
# Production: BYPASS=0, harness_bypass=1 (default), HARNESS_ACTIVE='' (no harness)
{
local $Class::Abstract::BYPASS = 0;
local $Class::Abstract::config{harness_bypass} = 1;
local $ENV{HARNESS_ACTIVE} = '';
# Abstract class must be blocked
throws_ok { IT::Vehicle->new() }
qr/Cannot instantiate abstract class IT::Vehicle directly/,
'abstract IT::Vehicle blocked in production context';
# Concrete subclass must succeed
lives_ok { IT::Car->new() }
'concrete IT::Car succeeds in production context';
}
# Multi-level: IT::Animal (abstract), IT::Mammal (also abstract), IT::Dog (concrete)
{
local $Class::Abstract::BYPASS = 0;
local $Class::Abstract::config{harness_bypass} = 1;
local $ENV{HARNESS_ACTIVE} = '';
lives_ok { IT::Dog->new() }
'IT::Dog (two levels from abstract) succeeds in production context';
}
};
done_testing;
( run in 0.584 second using v1.01-cache-2.11-cpan-800906f7e73 )