The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl

## This test will first cause a (legitimate) error in a
## before_template_render hook
## Then it will fetch an unrelated route that should return normally.
## However, this route is now using the wrong with_return block.
## This is because the first route, errors in rendering the *error* page.
## This cause the block to die, and with_return is never unset.
## This test uses two template files 

package MyTestApp;
use Dancer2;
use Scalar::Util qw/refaddr/;

hook before_template_render => sub {
    my $path = request->path;
    my $refadd = refaddr(app->with_return);
    if ( $path =~ m!route_with_renderer_error! ) {
        die $refadd;
    }
};

get '/route_with_renderer_error' => sub {
    ## This route first gets called, then template fires the above hook.
    ## This hook errors, causing Dancer2::Core::App, to throw an error
    ## which *also* fires the hook, crashing the server.
    my $addr = refaddr(app->with_return);
    template \$addr;
};

get '/normal_route' => sub {
    ## This should issue normally
    # my $addr = refaddr(app->with_return);
    # template \$addr;
    return refaddr(app->with_return);
};

package main;
use strict;
use warnings;
use Test::More;
use Plack::Test;
use HTTP::Request::Common qw/GET/;
use Dancer2;

my $test = Plack::Test->create(Dancer2->psgi_app);

## This route works fine
my $res1 = $test->request(GET '/normal_route');
ok($res1->is_success, '/normal_route does not error');
my $refaddr1 = $res1->decoded_content;

## This route should die
my $res2 = $test->request(GET '/route_with_renderer_error');
ok(! $res2->is_success, '/route_with_renderer_error errors errors');
my ($refaddr2) = $res2->decoded_content =~ /Hook error: (\d+)/;

## The first route now errors
## I can't seem to force with_return to fail in this test, even though I have
## it failing in production.
## So instead I'll check the refaddr of the with_return
## If refaddr of with_return is the same between route2 and route3, then this
## demonstrates that with_return has not been cleared between the two routes
## And that /normal_route is now using the wrong with_return.
## Possibly the old with_return hasn't been cleaned up? not sure.
my $res3 = $test->request(GET '/normal_route');
ok($res3->is_success, '/normal_route does not error');
my $refaddr3 = $res3->decoded_content;
isnt($refaddr1, $refaddr3, 'The 3rd request has a different with_return from the first run');
isnt($refaddr2, $refaddr3, 'The 3rd request has a different with_return from the second run');

done_testing();