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;

use Routes::Tiny;

subtest 'basic' => sub {
    my $r1 = Routes::Tiny->new;
    $r1->add_route('/',         name => 'r1_root');
    $r1->add_route('/bla/:id/', name => 'r1_id');

    my $r2 = Routes::Tiny->new;
    $r2->add_route('/',           name => 'r2_root');
    $r2->add_route('/bar/:id/',   name => 'r2_bar');
    $r2->add_route('/bar/*path/', name => 'r2_path');
    ok($r2->mount('/r1/', $r1));

    my $r3 = Routes::Tiny->new;
    $r3->add_route('/bar/:id/', name => 'r3_bar');

    my $ro = Routes::Tiny->new;
    ok($ro->mount('/r2/', $r2));
    ok($ro->mount('/r3/:parent_id/', $r3, name => 'r3_inc'));
    $ro->add_route('/r2/*path/', name => 'parent_foo_path');
    $ro->add_route('/*path',     name => 'fallback');

    $r2->add_route('/late_route/', name => 'late-route');

    my $m1 = $ro->match('/r2/');
    ok($m1 && $m1->{name} eq 'r2_root');

    my $m2 = $ro->match('/r2/bla/bla/');
    ok($m2 && $m2->{name} eq 'parent_foo_path');
    ok($m2->{captures}->{path} eq 'bla/bla');

    my $m3 = $ro->match('/r2/bar/3/');
    ok($m3 && $m3->{name} eq 'r2_bar');
    is($m3->{captures}->{id}, 3);

    my $m4 = $ro->match('/r2/r1/');
    ok($m4 && $m4->{name} eq 'r1_root');

    my $m5 = $ro->match('/r2/r1/bla/3/');
    ok($m5 && $m5->{name} eq 'r1_id');

    my $m6 = $ro->match('/r3/5/bar/7/');
    ok($m6 && $m6->{name} eq 'r3_bar');
    is($m6->{captures}->{id}, 7);
    ok($m6->{parent} && $m6->{parent}->{name} eq 'r3_inc');
    is($m6->{parent}->{captures}->{parent_id}, 5);

    my $m7 = $ro->match('/r3/5/baz/7/');
    ok($m7 && $m7->{name} eq 'fallback');

    my $p1 = $ro->build_path('r2_bar', id => 3);
    is($p1, '/r2/bar/3/');

    my $p2 = $ro->build_path('r3_bar', parent_id => 1, id => 2);
    is($p2, '/r3/1/bar/2/');

    my $p3 = $ro->build_path('late-route');
    is($p3, '/r2/late_route/');
};

subtest 'pass params to subroutes' => sub {
    my $r1 = Routes::Tiny->new;
    $r1->add_route('/foo', method => 'POST');

    my $ro = Routes::Tiny->new;
    $ro->mount('/subroute/', $r1);

    ok !$ro->match('/subroute/foo', method => 'GET');
    ok $ro->match('/subroute/foo', method => 'POST');
};

subtest 'saves captures' => sub {
    my $last = Routes::Tiny->new;
    $last->add_route('/last/:id/');

    my $second = Routes::Tiny->new;
    $second->mount('/second/:parent_id/', $last);

    my $top = Routes::Tiny->new;
    $top->mount('/top/:topic', $second);

    my $top_match = $top->match('/top/rainbows/second/5/last/7/');

    my $second_match = $top_match->parent;
    is($second_match->captures->{parent_id}, 5);

    my $last_match = $second_match->parent;
    is($last_match->captures->{topic}, 'rainbows');
};

subtest 'cascading captures' => sub {
    my $last = Routes::Tiny->new;
    $last->add_route('/last/:id/');

    my $second = Routes::Tiny->new;
    $second->mount('/second/:parent_id/', $last);

    my $top = Routes::Tiny->new;
    $top->mount('/top/:topic', $second);

    my $match = $top->match('/top/rainbows/second/5/last/7/');

    is_deeply $match->captures,
      {
        topic     => 'rainbows',
        parent_id => 5,
        id        => 7
      };
};

subtest 'merges arguments' => sub {
    my $last = Routes::Tiny->new;
    $last->add_route('/last/:id/', arguments => {foo => 'bar3', bar => 'baz'});

    my $second = Routes::Tiny->new;
    $second->mount('/second/:parent_id/', $last, arguments => {second => 'argument', foo => 'bar2'});

    my $top = Routes::Tiny->new;
    $top->mount('/top/:topic', $second, arguments => {top => 'argument', foo => 'bar'});

    my $match = $top->match('/top/rainbows/second/5/last/7/');

    is_deeply $match->arguments,
      {
        top    => 'argument',
        second => 'argument',
        foo    => 'bar3',
        bar    => 'baz',
      };
};

subtest 'merges arguments pushing' => sub {
    my $last = Routes::Tiny->new;
    $last->add_route('/last/:id/', '+arguments' => {foo => 'bar3', bar => 'baz'});

    my $second = Routes::Tiny->new;
    $second->mount('/second/:parent_id/', $last, '+arguments' => {second => 'argument', foo => 'bar2'});

    my $top = Routes::Tiny->new;
    $top->mount('/top/:topic', $second, arguments => {top => 'argument', foo => 'bar'});

    my $match = $top->match('/top/rainbows/second/5/last/7/');

    is_deeply $match->arguments,
      {
        top    => 'argument',
        second => 'argument',
        foo    => ['bar', 'bar2', 'bar3'],
        bar    => 'baz',
      };
};

done_testing;