no
warnings
qw(once)
;
use
lib
qw( ./lib ./t/lib ../inc ./inc )
;
note
"The basics"
;
{
has
small
=> (
is
=>
"ro"
,
isa
=> SmallInteger);
has
big
=> (
is
=>
"ro"
,
isa
=> BigInteger);
}
is(
exception {
"Local::Class"
->new(
small
=> 9,
big
=> 12) },
undef
,
"some values that should pass their type constraint"
,
);
is(
exception {
"Local::Class"
->new(
small
=> 100) },
matchfor(
'Moose::Exception::ValidationFailedForTypeConstraint'
,
qr{^Attribute \(small\) does not pass the type constraint}
),
"direct violation of type constraint"
,
);
is(
exception {
"Local::Class"
->new(
small
=> 5.5) },
matchfor(
'Moose::Exception::ValidationFailedForTypeConstraint'
,
qr{^Attribute \(small\) does not pass the type constraint}
),
"violation of parent type constraint"
,
);
is(
exception {
"Local::Class"
->new(
small
=>
"five point five"
) },
matchfor(
'Moose::Exception::ValidationFailedForTypeConstraint'
,
qr{^Attribute \(small\) does not pass the type constraint}
),
"violation of grandparent type constraint"
,
);
is(
exception {
"Local::Class"
->new(
small
=> []) },
matchfor(
'Moose::Exception::ValidationFailedForTypeConstraint'
,
qr{^Attribute \(small\) does not pass the type constraint}
),
"violation of great-grandparent type constraint"
,
);
note
"Coercion..."
;
my
$coercion
;
{
subtype
'MyInt'
, as
'Int'
;
coerce
'MyInt'
, from
'ArrayRef'
, via {
scalar
(
@$_
) };
my
$orig
= find_type_constraint(
'MyInt'
);
my
$type
= Types::TypeTiny::to_TypeTiny(
$orig
);
::ok(
$type
->has_coercion,
'types converted from Moose retain coercions'
);
::is(
$type
->coerce([
qw/a b c/
]), 3,
'... which work'
);
::is(refaddr(
$type
->moose_type), refaddr(
$orig
),
'... refaddr matches'
);
::is(refaddr(
$type
->coercion->moose_coercion), refaddr(
$orig
->coercion),
'... coercion refaddr matches'
);
$coercion
=
$type
->coercion;
}
note
"Introspection, comparisons, conversions..."
;
isa_ok(
Types::Standard::Int(),
'Class::MOP::Object'
,
'Int'
,
);
isa_ok(
Types::Standard::ArrayRef(),
'Moose::Meta::TypeConstraint'
,
'ArrayRef'
,
);
isa_ok(
Types::Standard::ArrayRef(),
'Moose::Meta::TypeConstraint::Parameterizable'
,
'ArrayRef'
,
);
isa_ok(
Types::Standard::ArrayRef()->of(Types::Standard::Int()),
'Moose::Meta::TypeConstraint'
,
'ArrayRef[Int]'
,
);
isa_ok(
Types::Standard::ArrayRef()->of(Types::Standard::Int()),
'Moose::Meta::TypeConstraint::Parameterized'
,
'ArrayRef[Int]'
,
);
isa_ok(
Types::Standard::ArrayRef() | Types::Standard::Int(),
'Moose::Meta::TypeConstraint'
,
'ArrayRef|Int'
,
);
isa_ok(
Types::Standard::ArrayRef() | Types::Standard::Int(),
'Moose::Meta::TypeConstraint::Union'
,
'ArrayRef|Int'
,
);
isa_ok(
$coercion
,
'Moose::Meta::TypeCoercion'
,
'MyInt->coercion'
,
);
$coercion
=
do
{
my
$arrayref
= Types::Standard::ArrayRef()->plus_coercions(
Types::Standard::ScalarRef(),
sub
{ [
$$_
] },
);
my
$int
= Types::Standard::Int()->plus_coercions(
Types::Standard::Num(),
sub
{
int
(
$_
) },
);
my
$array_or_int
=
$arrayref
|
$int
;
$array_or_int
->coercion;
};
isa_ok(
$coercion
,
'Moose::Meta::TypeCoercion'
,
'(ArrayRef|Int)->coercion'
,
);
isa_ok(
$coercion
,
'Moose::Meta::TypeCoercion::Union'
,
'(ArrayRef|Int)->coercion'
,
);
ok(
Types::Standard::ArrayRef->moose_type->equals(
Moose::Util::TypeConstraints::find_type_constraint(
"ArrayRef"
)
),
"equivalence between Types::Standard types and core Moose types"
,
);
my
$classtype
= Type::Utils::class_type(
LocalClass
=> {
class
=>
"Local::Class"
})->moose_type;
isa_ok(
$classtype
,
"Moose::Meta::TypeConstraint::Class"
,
'$classtype'
,
);
is(
$classtype
->class,
"Local::Class"
,
"Type::Tiny::Class provides meta information to Moose::Meta::TypeConstraint::Class"
,
);
isa_ok(
$classtype
->Types::TypeTiny::to_TypeTiny,
'Type::Tiny::Class'
,
'$classtype->Types::TypeTiny::to_TypeTiny'
,
);
my
$roletype
= Type::Utils::role_type(
LocalRole
=> {
class
=>
"Local::Role"
})->moose_type;
isa_ok(
$roletype
,
"Moose::Meta::TypeConstraint"
,
'$roletype'
,
);
ok(
!
$roletype
->isa(
"Moose::Meta::TypeConstraint::Role"
),
"NB! Type::Tiny::Role does not inflate to Moose::Meta::TypeConstraint::Role because of differing notions as to what constitutes a role."
,
);
isa_ok(
$roletype
->Types::TypeTiny::to_TypeTiny,
'Type::Tiny::Role'
,
'$roletype->Types::TypeTiny::to_TypeTiny'
,
);
my
$ducktype
= Type::Utils::duck_type(
Darkwing
=> [
qw/ foo bar baz /
])->moose_type;
isa_ok(
$ducktype
,
"Moose::Meta::TypeConstraint::DuckType"
,
'$ducktype'
,
);
is_deeply(
[
sort
@{
$ducktype
->methods}],
[
sort
qw/ foo bar baz /
],
"Type::Tiny::Duck provides meta information to Moose::Meta::TypeConstraint::DuckType"
,
);
isa_ok(
$ducktype
->Types::TypeTiny::to_TypeTiny,
'Type::Tiny::Duck'
,
'$ducktype->Types::TypeTiny::to_TypeTiny'
,
);
my
$enumtype
= Type::Utils::enum(
MyEnum
=> [
qw/ foo bar baz /
])->moose_type;
isa_ok(
$enumtype
,
"Moose::Meta::TypeConstraint::Enum"
,
'$classtype'
,
);
is_deeply(
[
sort
@{
$enumtype
->
values
}],
[
sort
qw/ foo bar baz /
],
"Type::Tiny::Enum provides meta information to Moose::Meta::TypeConstraint::Enum"
,
);
isa_ok(
$enumtype
->Types::TypeTiny::to_TypeTiny,
'Type::Tiny::Enum'
,
'$enumtype->Types::TypeTiny::to_TypeTiny'
,
);
my
$union
= Type::Utils::union(
ICU
=> [
$classtype
->Types::TypeTiny::to_TypeTiny,
$roletype
->Types::TypeTiny::to_TypeTiny])->moose_type;
isa_ok(
$union
,
"Moose::Meta::TypeConstraint::Union"
,
'$union'
,
);
is_deeply(
[
sort
@{
$union
->type_constraints}],
[
sort
$classtype
,
$roletype
],
"Type::Tiny::Union provides meta information to Moose::Meta::TypeConstraint::Union"
,
);
isa_ok(
$union
->Types::TypeTiny::to_TypeTiny,
'Type::Tiny::Union'
,
'$union->Types::TypeTiny::to_TypeTiny'
,
);
is(
[
sort
@{
$union
->type_constraints}]->[0]->Types::TypeTiny::to_TypeTiny->{uniq},
$classtype
->Types::TypeTiny::to_TypeTiny->{uniq},
'$union->type_constraints->[$i]->Types::TypeTiny::to_TypeTiny provides access to underlying Type::Tiny objects'
);
my
$intersect
= Type::Utils::intersection(
Chuck
=> [
$classtype
->Types::TypeTiny::to_TypeTiny,
$roletype
->Types::TypeTiny::to_TypeTiny])->moose_type;
isa_ok(
$intersect
,
"Moose::Meta::TypeConstraint"
,
'$intersect'
,
);
isa_ok(
$intersect
->Types::TypeTiny::to_TypeTiny,
'Type::Tiny::Intersection'
,
'$intersect->Types::TypeTiny::to_TypeTiny'
,
);
is(
Scalar::Util::refaddr(
$intersect
->Types::TypeTiny::to_TypeTiny ),
Scalar::Util::refaddr(
$intersect
->Types::TypeTiny::to_TypeTiny->moose_type->Types::TypeTiny::to_TypeTiny->moose_type->Types::TypeTiny::to_TypeTiny ),
'round-tripping between ->moose_type and ->Types::TypeTiny::to_TypeTiny preserves reference address'
);
note
"Method pass-through"
;
{
local
*Moose::Meta::TypeConstraint::dummy_1
=
sub
{
42;
};
local
*Moose::Meta::TypeCoercion::dummy_3
=
sub
{
666;
};
is(Types::Standard::Int()->dummy_1, 42,
'method pass-through'
);
like(
exception { Types::Standard::Int()->dummy_2 },
qr/^Can't locate object method "dummy_2"/
,
'... but not non-existant method'
,
);
ok(
Types::Standard::Int()->can(
'dummy_1'
) && !Types::Standard::Int()->can(
'dummy_2'
),
'... and `can` works ok'
,
);
my
$int
= Types::Standard::Int()->plus_coercions(Types::Standard::Any(),
q[999]
);
is(
$int
->coercion->dummy_3, 666,
'method pass-through for coercions'
);
like(
exception {
$int
->coercion->dummy_4 },
qr/^Can't locate object method "dummy_4"/
,
'... but not non-existant method'
,
);
ok(
$int
->coercion->can(
'dummy_3'
) && !
$int
->coercion->can(
'dummy_4'
),
'... and `can` works ok'
,
);
}
done_testing;