The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;

use Test::More 0.88;

use Type::Declare;
use Type::Library::Builtins;

{
    my $arrayref = t('ArrayRef');

    ok(
        $arrayref->value_is_valid( [ {}, 42, 'foo' ] ),
        'ArrayRef does not care about member types'
    );

    my $from_method = t1($arrayref);

    for my $pair (
        [ filename   => __FILE__ ],
        [ line       => 42 ],
        [ package    => 'main' ],
        [ subroutine => 'main::t1' ],
        ) {

        my ( $key, $expect ) = @{$pair};
        is(
            $from_method->declared_at()->$key(),
            $expect,
            "declared_at $key is the expected value for parameterized type made from ->parameterize"
        );
    }

    my $from_t = t2();

    for my $pair (
        [ filename   => __FILE__ ],
        [ line       => 84 ],
        [ package    => 'main' ],
        [ subroutine => 'main::t2' ],
        ) {

        my ( $key, $expect ) = @{$pair};
        is(
            $from_t->declared_at()->$key(),
            $expect,
            "declared_at $key is the expected value for parameterized type made from calling t()"
        );
    }

    declare(
        'ArrayRefOfInt',
        parent => t( 'ArrayRef', of => t('Int') ),
    );

    ok(
        t('ArrayRefOfInt'),
        'there is an ArrayRefOfInt type declared'
    );

    my $anon = anon(
        parent => t( 'ArrayRef', of => t('Int') ),
    );

    for my $pair (
        [ $from_method,       '->parameterize()' ],
        [ $from_t,            't(...)' ],
        [ t('ArrayRefOfInt'), 'named type' ],
        [ $anon,              'anon type' ],
        ) {

        my ( $arrayref_of_int, $desc ) = @{$pair};

        ok(
            !$arrayref_of_int->value_is_valid( [ {}, 42, 'foo' ] ),
            "ArrayRef of Int [$desc] does care about member types"
        );

        ok(
            $arrayref_of_int->value_is_valid( [ -1, 42, 1_000_000 ] ),
            "ArrayRef of Int [$desc] accepts array ref of all integers"
        );

        ok(
            !$arrayref_of_int->value_is_valid( 42 ),
            "ArrayRef of Int [$desc] rejects integer"
        );

        ok(
            !$arrayref_of_int->value_is_valid( {} ),
            "ArrayRef of Int [$desc] rejects hashref"
        );
    }
}

done_testing();

sub t1 {
    my $arrayref = shift;
# line 42
    return $arrayref->parameterize( of => t('Int') );
}

sub t2 {
# line 84
    return t( 'ArrayRef', of => t('Int') ),;
}