The Perl and Raku Conference 2025: Greenville, South Carolina - June 27-29 Learn more

=pod
=encoding utf-8
=head1 PURPOSE
Checks Type::Tiny works.
=head1 AUTHOR
Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
=head1 COPYRIGHT AND LICENCE
This software is copyright (c) 2013-2014, 2017-2025 by Toby Inkster.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
use strict;
use lib qw( ./lib ./t/lib ../inc ./inc );
ok("Type::Tiny"->can('new'), 'Type::Tiny can works for valid methods');
ok(
!"Type::Tiny"->can('will_never_be_a_method'),
'Type::Tiny can works for invalid methods'
);
my $Any = "Type::Tiny"->new(name => "Any");
ok(!$Any->is_anon, "Any is not anon");
is($Any->name, "Any", "Any is called Any");
ok($Any->can_be_inlined, 'Any can be inlined');
should_pass($_, $Any)
for 1, 1.2, "Hello World", [], {}, undef, \*STDOUT;
like(
exception { $Any->create_child_type(name => "1") },
qr{^"1" is not a valid type name},
"bad type constraint name",
);
my $Int = $Any->create_child_type(
constraint => sub { defined($_) and !ref($_) and $_ =~ /^[+-]?[0-9]+$/sm },
);
ok($Int->is_anon, "\$Int is anon");
is($Int->name, "__ANON__", "\$Int is called __ANON__");
ok(!$Int->can_be_inlined, '$Int cannot be inlined');
should_pass($_, $Int)
for 1, -1, 0, 100, 10000, 987654;
should_fail($_, $Int)
for 1.2, "Hello World", [], {}, undef, \*STDOUT;
ok_subtype($Any, $Int);
ok($Any->is_supertype_of($Int), 'Any is_supertype_of $Int');
ok($Int->is_a_type_of($Any), '$Int is_a_type_of Any');
ok($Int->is_a_type_of($Int), '$Int is_a_type_of $Int');
ok(!$Int->is_subtype_of($Int), 'not $Int is_subtype_of $Int');
my $Below = $Int->create_child_type(
name => "Below",
constraint_generator => sub {
my $param = shift;
return sub { $_ < $param };
},
);
ok($Below->is_parameterizable, 'Below is_parameterizable');
ok(!$Below->is_parameterized, 'not Below is_parameterized');
should_pass($_, $Below)
for 1, -1, 0, 100, 10000, 987654;
should_fail($_, $Below)
for 1.2, "Hello World", [], {}, undef, \*STDOUT;
my $Below5 = $Below->parameterize(5);
ok($Below5->is_anon, '$Below5 is anon');
is($Below5->display_name, 'Below[5]', '... but still has a nice display name');
should_pass($_, $Below5)
for 1, -1, 0;
should_fail($_, $Below5)
for 1.2, "Hello World", [], {}, undef, \*STDOUT, 100, 10000, 987654;
ok_subtype($_, $Below5) for $Any, $Int, $Below;
ok($Below5->is_parameterized, 'Below[5] is_parameterized');
ok(!$Below->has_parameters, 'has_parameters method works - negative');
ok($Below5->has_parameters, 'has_parameters method works - positive');
is_deeply($Below5->parameters, [5], 'parameters method works');
my $Ref = "Type::Tiny"->new(
name => "Ref",
constraint => sub { ref($_) },
inlined => sub { "ref($_)" },
);
my $ArrayRef = "Type::Tiny"->new(
name => "ArrayRef",
parent => $Ref,
constraint => sub { ref($_) eq 'ARRAY' },
inlined => sub { undef, "ref($_) eq 'ARRAY'" },
);
is(
$ArrayRef->inline_check('$xxx'),
q[(((ref($xxx))) && (ref($xxx) eq 'ARRAY'))],
'inlining stuff can return a list',
);
{
my $subtype_of_Num = Types::Standard::Num->create_child_type;
my $subtype_of_Int = Types::Standard::Int->create_child_type;
ok(
$subtype_of_Int->is_subtype_of( $subtype_of_Num ),
'loose subtype comparison 1',
);
ok(
! $subtype_of_Int->is_strictly_subtype_of( $subtype_of_Num ),
'strict subtype comparison 1',
);
ok(
$subtype_of_Num->is_supertype_of( $subtype_of_Int ),
'loose supertype comparison 1',
);
ok(
! $subtype_of_Num->is_strictly_supertype_of( $subtype_of_Int ),
'strict supertype comparison 1',
);
ok(
Types::Standard::Int->is_subtype_of( Types::Standard::Num ),
'loose subtype comparison 2',
);
ok(
Types::Standard::Int->is_strictly_subtype_of( Types::Standard::Num ),
'strict subtype comparison 2',
);
ok(
Types::Standard::Num->is_supertype_of( Types::Standard::Int ),
'loose supertype comparison 2',
);
ok(
Types::Standard::Num->is_strictly_supertype_of( Types::Standard::Int ),
'strict supertype comparison 2',
);
}
my $t1 = Types::Standard::Int;
my $t2 = $t1->create_child_type(name => 'T2');
my $t3 = $t2->create_child_type(name => 'T3');
my $t4 = $t3->create_child_type(name => 'T4');
my $t5 = $t4->create_child_type(name => 'T5');
my $t6 = $t5->create_child_type(name => 'T6');
my $found = $t6->find_parent(sub {
$_->has_parent and $_->parent->name eq 'Int'
});
is($found->name, 'T2', 'find_parent (scalar context)');
my ($found2, $n2) = $t6->find_parent(sub {
$_->has_parent and $_->parent->name eq 'Int'
});
is($found2->name, 'T2', 'find_parent (list context)');
is($n2, 4, '... includes a count');
my ($found3, $n3) = $t6->find_parent(sub { $_->name eq 'Kristoff' });
is($found3, undef, 'find_parent (null result)');
is($3, undef, '... includes an undef count');
{
my $Any = "Type::Tiny"->new(name => "Any");
my $Blah = $Any->create_child_type->create_child_type(constraint => sub { "yes" });
my $Bleh = $Blah->create_child_type(name => "Bleh")->create_child_type;
is($Bleh->find_constraining_type->{uniq}, $Blah->{uniq}, 'find_constraining_type');
}
done_testing;