ACC SHELL

Path : /srv/www/vhosts/printeco/vendor/klein/klein/tests/Klein/Tests/
File Upload :
Current File : /srv/www/vhosts/printeco/vendor/klein/klein/tests/Klein/Tests/RoutingTest.php

<?php
/**
 * Klein (klein.php) - A fast & flexible router for PHP
 *
 * @author      Chris O'Hara <cohara87@gmail.com>
 * @author      Trevor Suarez (Rican7) (contributor and v2 refactorer)
 * @copyright   (c) Chris O'Hara
 * @link        https://github.com/klein/klein.php
 * @license     MIT
 */

namespace Klein\Tests;

use Klein\App;
use Klein\DataCollection\RouteCollection;
use Klein\Exceptions\DispatchHaltedException;
use Klein\Exceptions\HttpException;
use Klein\Exceptions\RoutePathCompilationException;
use Klein\Klein;
use Klein\Request;
use Klein\Response;
use Klein\Route;
use Klein\ServiceProvider;
use Klein\Tests\Mocks\HeadersEcho;
use Klein\Tests\Mocks\HeadersSave;
use Klein\Tests\Mocks\MockRequestFactory;

/**
 * RoutingTest
 */
class RoutingTest extends AbstractKleinTest
{

    public function testBasic()
    {
        $this->expectOutputString('x');

        $this->klein_app->respond(
            '/',
            function () {
                echo 'x';
            }
        );
        $this->klein_app->respond(
            '/something',
            function () {
                echo 'y';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/')
        );
    }

    public function testCallable()
    {
        $this->expectOutputString('okok');

        $this->klein_app->respond('/', array(__NAMESPACE__ . '\Mocks\TestClass', 'GET'));
        $this->klein_app->respond('/', __NAMESPACE__ . '\Mocks\TestClass::GET');

        $this->klein_app->dispatch(
            MockRequestFactory::create('/')
        );
    }

    public function testCallbackArguments()
    {
        // Create expected objects
        $expected_objects = array(
            'request'         => null,
            'response'        => null,
            'service'         => null,
            'app'             => null,
            'klein'           => null,
            'matched'         => null,
            'methods_matched' => null,
        );

        $this->klein_app->respond(
            function ($a, $b, $c, $d, $e, $f, $g) use (&$expected_objects) {
                $expected_objects['request']         = $a;
                $expected_objects['response']        = $b;
                $expected_objects['service']         = $c;
                $expected_objects['app']             = $d;
                $expected_objects['klein']           = $e;
                $expected_objects['matched']         = $f;
                $expected_objects['methods_matched'] = $g;
            }
        );

        $this->klein_app->dispatch();

        $this->assertTrue($expected_objects['request'] instanceof Request);
        $this->assertTrue($expected_objects['response'] instanceof Response);
        $this->assertTrue($expected_objects['service'] instanceof ServiceProvider);
        $this->assertTrue($expected_objects['app'] instanceof App);
        $this->assertTrue($expected_objects['klein'] instanceof Klein);
        $this->assertTrue($expected_objects['matched'] instanceof RouteCollection);
        $this->assertTrue(is_array($expected_objects['methods_matched']));

        $this->assertSame($expected_objects['request'], $this->klein_app->request());
        $this->assertSame($expected_objects['response'], $this->klein_app->response());
        $this->assertSame($expected_objects['service'], $this->klein_app->service());
        $this->assertSame($expected_objects['app'], $this->klein_app->app());
        $this->assertSame($expected_objects['klein'], $this->klein_app);
    }

    public function testAppReference()
    {
        $this->expectOutputString('ab');

        $this->klein_app->respond(
            '/',
            function ($request, $response, $service, $app) {
                $app->state = 'a';
            }
        );
        $this->klein_app->respond(
            '/',
            function ($request, $response, $service, $app) {
                $app->state .= 'b';
            }
        );
        $this->klein_app->respond(
            '/',
            function ($request, $response, $service, $app) {
                print $app->state;
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/')
        );
    }

    public function testDispatchOutput()
    {
        $expected_output = array(
            'returned1' => 'alright!',
            'returned2' => 'woot!',
        );

        $this->klein_app->respond(
            function () use ($expected_output) {
                return $expected_output['returned1'];
            }
        );
        $this->klein_app->respond(
            function () use ($expected_output) {
                return $expected_output['returned2'];
            }
        );

        $this->klein_app->dispatch();

        // Expect our output to match our ECHO'd output
        $this->expectOutputString(
            $expected_output['returned1'] . $expected_output['returned2']
        );

        // Make sure our response body matches the concatenation of what we returned in each callback
        $this->assertSame(
            $expected_output['returned1'] . $expected_output['returned2'],
            $this->klein_app->response()->body()
        );
    }

    public function testDispatchOutputNotSent()
    {
        $this->klein_app->respond(
            function () {
                return 'test output';
            }
        );

        $this->klein_app->dispatch(null, null, false);

        $this->expectOutputString('');

        $this->assertSame(
            'test output',
            $this->klein_app->response()->body()
        );
    }

    public function testDispatchOutputCaptured()
    {
        $expected_output = array(
            'echoed' => 'yup',
            'returned' => 'nope',
        );

        $this->klein_app->respond(
            function () use ($expected_output) {
                echo $expected_output['echoed'];
            }
        );
        $this->klein_app->respond(
            function () use ($expected_output) {
                return $expected_output['returned'];
            }
        );

        $output = $this->klein_app->dispatch(null, null, true, Klein::DISPATCH_CAPTURE_AND_RETURN);

        // Make sure nothing actually printed to the screen
        $this->expectOutputString('');

        // Make sure our returned output matches what we ECHO'd
        $this->assertSame($expected_output['echoed'], $output);

        // Make sure our response body matches what we returned
        $this->assertSame($expected_output['returned'], $this->klein_app->response()->body());
    }

    public function testDispatchOutputReplaced()
    {
        $expected_output = array(
            'echoed' => 'yup',
            'returned' => 'nope',
        );

        $this->klein_app->respond(
            function () use ($expected_output) {
                echo $expected_output['echoed'];
            }
        );
        $this->klein_app->respond(
            function () use ($expected_output) {
                return $expected_output['returned'];
            }
        );

        $this->klein_app->dispatch(null, null, false, Klein::DISPATCH_CAPTURE_AND_REPLACE);

        // Make sure nothing actually printed to the screen
        $this->expectOutputString('');

        // Make sure our response body matches what we echoed
        $this->assertSame($expected_output['echoed'], $this->klein_app->response()->body());
    }

    public function testDispatchOutputPrepended()
    {
        $expected_output = array(
            'echoed' => 'yup',
            'returned' => 'nope',
            'echoed2' => 'sure',
        );

        $this->klein_app->respond(
            function () use ($expected_output) {
                echo $expected_output['echoed'];
            }
        );
        $this->klein_app->respond(
            function () use ($expected_output) {
                return $expected_output['returned'];
            }
        );
        $this->klein_app->respond(
            function () use ($expected_output) {
                echo $expected_output['echoed2'];
            }
        );

        $this->klein_app->dispatch(null, null, false, Klein::DISPATCH_CAPTURE_AND_PREPEND);

        // Make sure nothing actually printed to the screen
        $this->expectOutputString('');

        // Make sure our response body matches what we echoed
        $this->assertSame(
            $expected_output['echoed'] . $expected_output['echoed2'] . $expected_output['returned'],
            $this->klein_app->response()->body()
        );
    }

    public function testDispatchOutputAppended()
    {
        $expected_output = array(
            'echoed' => 'yup',
            'returned' => 'nope',
            'echoed2' => 'sure',
        );

        $this->klein_app->respond(
            function () use ($expected_output) {
                echo $expected_output['echoed'];
            }
        );
        $this->klein_app->respond(
            function () use ($expected_output) {
                return $expected_output['returned'];
            }
        );
        $this->klein_app->respond(
            function () use ($expected_output) {
                echo $expected_output['echoed2'];
            }
        );

        $this->klein_app->dispatch(null, null, false, Klein::DISPATCH_CAPTURE_AND_APPEND);

        // Make sure nothing actually printed to the screen
        $this->expectOutputString('');

        // Make sure our response body matches what we echoed
        $this->assertSame(
            $expected_output['returned'] . $expected_output['echoed'] . $expected_output['echoed2'],
            $this->klein_app->response()->body()
        );
    }

    public function testDispatchResponseReplaced()
    {
        $expected_body = 'You SHOULD see this';
        $expected_code = 201;

        $expected_append = 'This should be appended?';

        $this->klein_app->respond(
            '/',
            function ($request, $response) {
                // Set our response code
                $response->code(569);

                return 'This should disappear';
            }
        );
        $this->klein_app->respond(
            '/',
            function () use ($expected_body, $expected_code) {
                return new Response($expected_body, $expected_code);
            }
        );
        $this->klein_app->respond(
            '/',
            function () use ($expected_append) {
                return $expected_append;
            }
        );

        $this->klein_app->dispatch(null, null, false, Klein::DISPATCH_CAPTURE_AND_RETURN);

        // Make sure our response body and code match up
        $this->assertSame(
            $expected_body . $expected_append,
            $this->klein_app->response()->body()
        );
        $this->assertSame(
            $expected_code,
            $this->klein_app->response()->code()
        );
    }

    public function testRespondReturn()
    {
        $return_one = $this->klein_app->respond(
            function () {
                return 1337;
            }
        );
        $return_two = $this->klein_app->respond(
            function () {
                return 'dog';
            }
        );

        $this->klein_app->dispatch(null, null, false);

        $this->assertTrue(is_callable($return_one));
        $this->assertTrue(is_callable($return_two));
    }

    public function testRespondReturnChaining()
    {
        $return_one = $this->klein_app->respond(
            function () {
                return 1337;
            }
        );
        $return_two = $this->klein_app->respond(
            function () {
                return 1337;
            }
        )->getPath();

        $this->assertSame($return_one->getPath(), $return_two);
    }

    public function testCatchallImplicit()
    {
        $this->expectOutputString('b');

        $this->klein_app->respond(
            '/one',
            function () {
                echo 'a';
            }
        );
        $this->klein_app->respond(
            function () {
                echo 'b';
            }
        );
        $this->klein_app->respond(
            '/two',
            function () {

            }
        );
        $this->klein_app->respond(
            '/three',
            function () {
                echo 'c';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/two')
        );
    }

    public function testCatchallAsterisk()
    {
        $this->expectOutputString('b');

        $this->klein_app->respond(
            '/one',
            function () {
                echo 'a';
            }
        );
        $this->klein_app->respond(
            '*',
            function () {
                echo 'b';
            }
        );
        $this->klein_app->respond(
            '/two',
            function () {

            }
        );
        $this->klein_app->respond(
            '/three',
            function () {
                echo 'c';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/two')
        );
    }

    public function testCatchallImplicitTriggers404()
    {
        $this->expectOutputString("b404\n");

        $this->klein_app->onHttpError(
            function ($code) {
                if (404 === $code) {
                    echo "404\n";
                }
            }
        );

        $this->klein_app->respond(
            function () {
                echo 'b';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/')
        );
    }

    public function testRegex()
    {
        $this->expectOutputString('zz');

        $this->klein_app->respond(
            '@/bar',
            function () {
                echo 'z';
            }
        );

        $this->klein_app->respond(
            '@/[0-9]s',
            function () {
                echo 'z';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/bar')
        );
        $this->klein_app->dispatch(
            MockRequestFactory::create('/8s')
        );
        $this->klein_app->dispatch(
            MockRequestFactory::create('/88s')
        );
    }

    public function testRegexNegate()
    {
        $this->expectOutputString("y");

        $this->klein_app->respond(
            '!@/foo',
            function () {
                echo 'y';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/bar')
        );
    }

    public function testNormalNegate()
    {
        $this->expectOutputString('');

        $this->klein_app->respond(
            '!/foo',
            function () {
                echo 'y';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/foo')
        );
    }

    public function test404()
    {
        $this->expectOutputString("404\n");

        $this->klein_app->onHttpError(
            function ($code) {
                if (404 === $code) {
                    echo "404\n";
                }
            }
        );

        $this->klein_app->respond(
            '/',
            function () {
                echo 'a';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/foo')
        );

        $this->assertSame(404, $this->klein_app->response()->code());
    }

    public function testParamsBasic()
    {
        $this->expectOutputString('blue');

        $this->klein_app->respond(
            '/[:color]',
            function ($request) {
                echo $request->param('color');
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/blue')
        );
    }

    public function testParamsIntegerSuccess()
    {
        $this->expectOutputString("string(3) \"987\"");

        $this->klein_app->respond(
            '/[i:age]',
            function ($request) {
                $age = $request->param('age');

                printf('%s(%d) "%s"', gettype($age), strlen($age), $age);
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/987')
        );
    }

    public function testParamsIntegerFail()
    {
        $this->expectOutputString('404 Code');

        $this->klein_app->onHttpError(
            function ($code) {
                if (404 === $code) {
                    echo '404 Code';
                }
            }
        );

        $this->klein_app->respond(
            '/[i:age]',
            function ($request) {
                echo $request->param('age');
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/blue')
        );
    }

    public function testParamsAlphaNum()
    {
        $this->klein_app->respond(
            '/[a:audible]',
            function ($request) {
                echo $request->param('audible');
            }
        );


        $this->assertSame(
            'blue42',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/blue42')
            )
        );
        $this->assertSame(
            '',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/texas-29')
            )
        );
        $this->assertSame(
            '',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/texas29!')
            )
        );
    }

    public function testParamsHex()
    {
        $this->klein_app->respond(
            '/[h:hexcolor]',
            function ($request) {
                echo $request->param('hexcolor');
            }
        );


        $this->assertSame(
            '00f',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/00f')
            )
        );
        $this->assertSame(
            'abc123',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/abc123')
            )
        );
        $this->assertSame(
            '',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/876zih')
            )
        );
        $this->assertSame(
            '',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/00g')
            )
        );
        $this->assertSame(
            '',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/hi23')
            )
        );
    }

    public function testParamsSlug()
    {
        $this->klein_app->respond(
            '/[s:slug_name]',
            function ($request) {
                echo $request->param('slug_name');
            }
        );


        $this->assertSame(
            'dog-thing',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/dog-thing')
            )
        );
        $this->assertSame(
            'a_badass_slug',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/a_badass_slug')
            )
        );
        $this->assertSame(
            'AN_UPERCASE_SLUG',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/AN_UPERCASE_SLUG')
            )
        );
        $this->assertSame(
            'sample-wordpress-like-post-slug-based-on-the-title-2013-edition',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/sample-wordpress-like-post-slug-based-on-the-title-2013-edition')
            )
        );
        $this->assertSame(
            '',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/%!@#')
            )
        );
        $this->assertSame(
            '',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/')
            )
        );
        $this->assertSame(
            '',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/dog-%thing')
            )
        );
    }

    public function testPathParamsAreUrlDecoded()
    {
        $this->klein_app->respond(
            '/[:test]',
            function ($request) {
                echo $request->param('test');
            }
        );

        $this->assertSame(
            'Knife Party',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/Knife%20Party')
            )
        );

        $this->assertSame(
            'and/or',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/and%2For')
            )
        );
    }

    public function testPathParamsAreUrlDecodedToRFC3986Spec()
    {
        $this->klein_app->respond(
            '/[:test]',
            function ($request) {
                echo $request->param('test');
            }
        );

        $this->assertNotSame(
            'Knife Party',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/Knife+Party')
            )
        );

        $this->assertSame(
            'Knife+Party',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/Knife+Party')
            )
        );
    }

    public function test404TriggersOnce()
    {
        $this->expectOutputString('d404 Code');

        $this->klein_app->onHttpError(
            function ($code) {
                if (404 === $code) {
                    echo '404 Code';
                }
            }
        );

        $this->klein_app->respond(
            function () {
                echo "d";
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/notroute')
        );
    }

    public function test404RouteDefinitionOrderDoesntEffectWhen404HandlersCalled()
    {
        $this->expectOutputString('onetwo404 Code');

        $this->klein_app->respond(
            function () {
                echo 'one';
            }
        );
        $this->klein_app->respond(
            '404',
            function () {
                echo '404 Code';
            }
        );
        $this->klein_app->respond(
            function () {
                echo 'two';
            }
        );

        // Ignore our deprecation error
        $old_error_val = error_reporting();
        error_reporting(E_ALL ^ E_USER_DEPRECATED);

        $this->klein_app->dispatch(
            MockRequestFactory::create('/notroute')
        );

        error_reporting($old_error_val);
    }

    public function testMethodCatchAll()
    {
        $this->expectOutputString('yup!123');

        $this->klein_app->respond(
            'POST',
            null,
            function ($request) {
                echo 'yup!';
            }
        );
        $this->klein_app->respond(
            'POST',
            '*',
            function ($request) {
                echo '1';
            }
        );
        $this->klein_app->respond(
            'POST',
            '/',
            function ($request) {
                echo '2';
            }
        );
        $this->klein_app->respond(
            function ($request) {
                echo '3';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'POST')
        );
    }

    public function testLazyTrailingMatch()
    {
        $this->expectOutputString('this-is-a-title-123');

        $this->klein_app->respond(
            '/posts/[*:title][i:id]',
            function ($request) {
                echo $request->param('title')
                . $request->param('id');
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/posts/this-is-a-title-123')
        );
    }

    public function testFormatMatch()
    {
        $this->expectOutputString('xml');

        $this->klein_app->respond(
            '/output.[xml|json:format]',
            function ($request) {
                echo $request->param('format');
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/output.xml')
        );
    }

    public function testDotSeparator()
    {
        $this->expectOutputString('matchA:slug=ABCD_E--matchB:slug=ABCD_E--');

        $this->klein_app->respond(
            '/[*:cpath]/[:slug].[:format]',
            function ($rq) {
                echo 'matchA:slug='.$rq->param("slug").'--';
            }
        );
        $this->klein_app->respond(
            '/[*:cpath]/[:slug].[:format]?',
            function ($rq) {
                echo 'matchB:slug='.$rq->param("slug").'--';
            }
        );
        $this->klein_app->respond(
            '/[*:cpath]/[a:slug].[:format]?',
            function ($rq) {
                echo 'matchC:slug='.$rq->param("slug").'--';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create("/category1/categoryX/ABCD_E.php")
        );

        $this->assertSame(
            'matchA:slug=ABCD_E--matchB:slug=ABCD_E--',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/category1/categoryX/ABCD_E.php')
            )
        );
        $this->assertSame(
            'matchB:slug=ABCD_E--',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/category1/categoryX/ABCD_E')
            )
        );
    }

    public function testControllerActionStyleRouteMatch()
    {
        $this->expectOutputString('donkey-kick');

        $this->klein_app->respond(
            '/[:controller]?/[:action]?',
            function ($request) {
                echo $request->param('controller')
                     . '-' . $request->param('action');
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/donkey/kick')
        );
    }

    public function testRespondArgumentOrder()
    {
        $this->expectOutputString('abcdef');

        $this->klein_app->respond(
            function () {
                echo 'a';
            }
        );
        $this->klein_app->respond(
            null,
            function () {
                echo 'b';
            }
        );
        $this->klein_app->respond(
            '/endpoint',
            function () {
                echo 'c';
            }
        );
        $this->klein_app->respond(
            'GET',
            null,
            function () {
                echo 'd';
            }
        );
        $this->klein_app->respond(
            array('GET', 'POST'),
            null,
            function () {
                echo 'e';
            }
        );
        $this->klein_app->respond(
            array('GET', 'POST'),
            '/endpoint',
            function () {
                echo 'f';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/endpoint')
        );
    }

    public function testTrailingMatch()
    {
        $this->klein_app->respond(
            '/?[*:trailing]/dog/?',
            function ($request) {
                echo 'yup';
            }
        );


        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/cat/dog')
            )
        );
        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/cat/cheese/dog')
            )
        );
        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/cat/ball/cheese/dog/')
            )
        );
        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/cat/ball/cheese/dog')
            )
        );
        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('cat/ball/cheese/dog/')
            )
        );
        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('cat/ball/cheese/dog')
            )
        );
    }

    public function testTrailingPossessiveMatch()
    {
        $this->klein_app->respond(
            '/sub-dir/[**:trailing]',
            function ($request) {
                echo 'yup';
            }
        );


        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/sub-dir/dog')
            )
        );

        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/sub-dir/cheese/dog')
            )
        );

        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/sub-dir/ball/cheese/dog/')
            )
        );

        $this->assertSame(
            'yup',
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create('/sub-dir/ball/cheese/dog')
            )
        );
    }

    public function testNSDispatch()
    {
        $this->klein_app->with(
            '/u',
            function ($klein_app) {
                $klein_app->respond(
                    'GET',
                    '/?',
                    function ($request, $response) {
                        echo "slash";
                    }
                );
                $klein_app->respond(
                    'GET',
                    '/[:id]',
                    function ($request, $response) {
                        echo "id";
                    }
                );
            }
        );

        $this->klein_app->onHttpError(
            function ($code) {
                if (404 === $code) {
                    echo "404";
                }
            }
        );


        $this->assertSame(
            "slash",
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create("/u")
            )
        );
        $this->assertSame(
            "slash",
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create("/u/")
            )
        );
        $this->assertSame(
            "id",
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create("/u/35")
            )
        );
        $this->assertSame(
            "404",
            $this->dispatchAndReturnOutput(
                MockRequestFactory::create("/35")
            )
        );
    }

    public function testNSDispatchExternal()
    {
        $ext_namespaces = $this->loadExternalRoutes();

        $this->klein_app->respond(
            404,
            function ($request, $response) {
                echo "404";
            }
        );

        foreach ($ext_namespaces as $namespace) {

            $this->assertSame(
                'yup',
                $this->dispatchAndReturnOutput(
                    MockRequestFactory::create($namespace . '/')
                )
            );

            $this->assertSame(
                'yup',
                $this->dispatchAndReturnOutput(
                    MockRequestFactory::create($namespace . '/testing/')
                )
            );
        }
    }

    public function testNSDispatchExternalRerequired()
    {
        $ext_namespaces = $this->loadExternalRoutes();

        $this->klein_app->respond(
            404,
            function ($request, $response) {
                echo "404";
            }
        );

        foreach ($ext_namespaces as $namespace) {

            $this->assertSame(
                'yup',
                $this->dispatchAndReturnOutput(
                    MockRequestFactory::create($namespace . '/')
                )
            );

            $this->assertSame(
                'yup',
                $this->dispatchAndReturnOutput(
                    MockRequestFactory::create($namespace . '/testing/')
                )
            );
        }
    }

    public function test405DefaultRequest()
    {
        $this->klein_app->respond(
            array('GET', 'POST'),
            '/',
            function () {
                echo 'fail';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'DELETE')
        );

        $this->assertEquals('405 Method Not Allowed', $this->klein_app->response()->status()->getFormattedString());
        $this->assertEquals('GET, POST', $this->klein_app->response()->headers()->get('Allow'));
    }

    public function testNo405OnNonMatchRoutes()
    {
        $this->klein_app->respond(
            array('GET', 'POST'),
            null,
            function () {
                echo 'this shouldn\'t cause a 405 since this route doesn\'t count as a match anyway';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'DELETE')
        );

        $this->assertEquals(404, $this->klein_app->response()->code());
    }

    public function test405Routes()
    {
        $result_array = array();

        $this->expectOutputString('_');

        $this->klein_app->respond(
            function () {
                echo '_';
            }
        );
        $this->klein_app->respond(
            'GET',
            '/sure',
            function () {
                echo 'fail';
            }
        );
        $this->klein_app->respond(
            array('GET', 'POST'),
            '/sure',
            function () {
                echo 'fail';
            }
        );
        $this->klein_app->respond(
            405,
            function ($a, $b, $c, $d, $e, $f, $methods) use (&$result_array) {
                $result_array = $methods;
            }
        );

        // Ignore our deprecation error
        $old_error_val = error_reporting();
        error_reporting(E_ALL ^ E_USER_DEPRECATED);

        $this->klein_app->dispatch(
            MockRequestFactory::create('/sure', 'DELETE')
        );

        error_reporting($old_error_val);

        $this->assertCount(2, $result_array);
        $this->assertContains('GET', $result_array);
        $this->assertContains('POST', $result_array);
        $this->assertSame(405, $this->klein_app->response()->code());
    }

    public function test405ErrorHandler()
    {
        $result_array = array();

        $this->expectOutputString('_');

        $this->klein_app->respond(
            function () {
                echo '_';
            }
        );
        $this->klein_app->respond(
            'GET',
            '/sure',
            function () {
                echo 'fail';
            }
        );
        $this->klein_app->respond(
            array('GET', 'POST'),
            '/sure',
            function () {
                echo 'fail';
            }
        );
        $this->klein_app->onHttpError(
            function ($code, $klein, $matched, $methods, $exception) use (&$result_array) {
                $result_array = $methods;
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/sure', 'DELETE')
        );

        $this->assertCount(2, $result_array);
        $this->assertContains('GET', $result_array);
        $this->assertContains('POST', $result_array);
        $this->assertSame(405, $this->klein_app->response()->code());
    }

    public function testOptionsDefaultRequest()
    {
        $this->klein_app->respond(
            function ($request, $response) {
                $response->code(200);
            }
        );
        $this->klein_app->respond(
            array('GET', 'POST'),
            '/',
            function () {
                echo 'fail';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'OPTIONS')
        );

        $this->assertEquals('200 OK', $this->klein_app->response()->status()->getFormattedString());
        $this->assertEquals('GET, POST', $this->klein_app->response()->headers()->get('Allow'));
    }

    public function testOptionsRoutes()
    {
        $access_control_headers = array(
            array(
                'key' => 'Access-Control-Allow-Origin',
                'val' => 'http://example.com',
            ),
            array(
                'key' => 'Access-Control-Allow-Methods',
                'val' => 'POST, GET, DELETE, OPTIONS, HEAD',
            ),
        );

        $this->klein_app->respond(
            'GET',
            '/',
            function () {
                echo 'fail';
            }
        );
        $this->klein_app->respond(
            array('GET', 'POST'),
            '/',
            function () {
                echo 'fail';
            }
        );
        $this->klein_app->respond(
            'OPTIONS',
            null,
            function ($request, $response) use ($access_control_headers) {
                // Add access control headers
                foreach ($access_control_headers as $header) {
                    $response->header($header['key'], $header['val']);
                }
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'OPTIONS')
        );


        // Assert headers were passed
        $this->assertEquals('GET, POST', $this->klein_app->response()->headers()->get('Allow'));

        foreach ($access_control_headers as $header) {
            $this->assertEquals($header['val'], $this->klein_app->response()->headers()->get($header['key']));
        }
    }

    public function testHeadDefaultRequest()
    {
        $expected_headers = array(
            array(
                'key' => 'X-Some-Random-Header',
                'val' => 'This was a GET route',
            ),
        );

        $this->klein_app->respond(
            'GET',
            null,
            function ($request, $response) use ($expected_headers) {
                $response->code(200);

                // Add access control headers
                foreach ($expected_headers as $header) {
                    $response->header($header[ 'key' ], $header[ 'val' ]);
                }
            }
        );
        $this->klein_app->respond(
            'GET',
            '/',
            function () {
                echo 'GET!';
                return 'more text';
            }
        );
        $this->klein_app->respond(
            'POST',
            '/',
            function () {
                echo 'POST!';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'HEAD')
        );

        // Make sure we don't get a response body
        $this->expectOutputString('');

        // Assert headers were passed
        foreach ($expected_headers as $header) {
            $this->assertEquals($header['val'], $this->klein_app->response()->headers()->get($header['key']));
        }
    }

    public function testHeadMethodMatch()
    {
        $test_strings = array(
            'oh, hello',
            'yea',
        );

        $test_result = null;

        $this->klein_app->respond(
            array('GET', 'HEAD'),
            null,
            function ($request, $response) use ($test_strings, &$test_result) {
                $test_result .= $test_strings[0];
            }
        );
        $this->klein_app->respond(
            'GET',
            '/',
            function ($request, $response) use ($test_strings, &$test_result) {
                $test_result .= $test_strings[1];
            }
        );
        $this->klein_app->respond(
            'POST',
            '/',
            function ($request, $response) use ($test_strings, &$test_result) {
                $test_result .= 'nope';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'HEAD')
        );

        $this->assertSame(
            implode('', $test_strings),
            $test_result
        );
    }

    public function testGetPathFor()
    {
        $this->klein_app->respond(
            '/dogs',
            function () {
            }
        )->setName('dogs');

        $this->klein_app->respond(
            '/dogs/[i:dog_id]/collars',
            function () {
            }
        )->setName('dog-collars');

        $this->klein_app->respond(
            '/dogs/[i:dog_id]/collars/[a:collar_slug]/?',
            function () {
            }
        )->setName('dog-collar-details');

        $this->klein_app->respond(
            '/dog/foo',
            function () {
            }
        )->setName('dog-foo');

        $this->klein_app->respond(
            '/dog/[i:dog_id]?',
            function () {
            }
        )->setName('dog-optional-details');

        $this->klein_app->respond(
            '@/dog/regex',
            function () {
            }
        )->setName('dog-regex');

        $this->klein_app->respond(
            '!@/dog/regex',
            function () {
            }
        )->setName('dog-neg-regex');

        $this->klein_app->respond(
            '@\.(json|csv)$',
            function () {
            }
        )->setName('complex-regex');

        $this->klein_app->respond(
            '!@^/admin/',
            function () {
            }
        )->setName('complex-neg-regex');

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'HEAD')
        );

        $this->assertSame(
            '/dogs',
            $this->klein_app->getPathFor('dogs')
        );
        $this->assertSame(
            '/dogs/[i:dog_id]/collars',
            $this->klein_app->getPathFor('dog-collars')
        );
        $this->assertSame(
            '/dogs/idnumberandstuff/collars',
            $this->klein_app->getPathFor(
                'dog-collars',
                array(
                    'dog_id' => 'idnumberandstuff',
                )
            )
        );
        $this->assertSame(
            '/dogs/[i:dog_id]/collars/[a:collar_slug]/?',
            $this->klein_app->getPathFor('dog-collar-details')
        );
        $this->assertSame(
            '/dogs/idnumberandstuff/collars/d12f3d1f2d3/?',
            $this->klein_app->getPathFor(
                'dog-collar-details',
                array(
                    'dog_id' => 'idnumberandstuff',
                    'collar_slug' => 'd12f3d1f2d3',
                )
            )
        );
        $this->assertSame(
            '/dog/foo',
            $this->klein_app->getPathFor('dog-foo')
        );
        $this->assertSame(
            '/dog',
            $this->klein_app->getPathFor('dog-optional-details')
        );
        $this->assertSame(
            '/',
            $this->klein_app->getPathFor('dog-regex')
        );
        $this->assertSame(
            '/',
            $this->klein_app->getPathFor('dog-neg-regex')
        );
        $this->assertSame(
            '@/dog/regex',
            $this->klein_app->getPathFor('dog-regex', null, false)
        );
        $this->assertNotSame(
            '/',
            $this->klein_app->getPathFor('dog-neg-regex', null, false)
        );
        $this->assertSame(
            '/',
            $this->klein_app->getPathFor('complex-regex')
        );
        $this->assertSame(
            '/',
            $this->klein_app->getPathFor('complex-neg-regex')
        );
        $this->assertSame(
            '@\.(json|csv)$',
            $this->klein_app->getPathFor('complex-regex', null, false)
        );
        $this->assertNotSame(
            '/',
            $this->klein_app->getPathFor('complex-neg-regex', null, false)
        );
    }

    public function testDispatchHalt()
    {
        $this->expectOutputString('2,4,7,8,');

        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                $klein_app->skipThis();
                echo '1,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '2,';
                $klein_app->skipNext();
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '3,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '4,';
                $klein_app->skipNext(2);
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '5,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '6,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '7,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '8,';
                $klein_app->skipRemaining();
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '9,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '10,';
            }
        );

        $this->klein_app->dispatch();
    }

    public function testDispatchSkipCauses404()
    {
        $this->expectOutputString('404');

        $this->klein_app->onHttpError(
            function ($code) {
                if (404 === $code) {
                    echo '404';
                }
            }
        );

        $this->klein_app->respond(
            'POST',
            '/steez',
            function ($a, $b, $c, $d, $klein_app) {
                $klein_app->skipThis();
                echo 'Style... with ease';
            }
        );
        $this->klein_app->respond(
            'GET',
            '/nope',
            function ($a, $b, $c, $d, $klein_app) {
                echo 'How did I get here?!';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/steez', 'POST')
        );
    }

    public function testDispatchAbort()
    {
        $this->expectOutputString('1,');

        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '1,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                $klein_app->abort();
                echo '2,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '3,';
            }
        );

        $this->klein_app->dispatch();

        $this->assertSame(404, $this->klein_app->response()->code());
    }

    public function testDispatchAbortWithCode()
    {
        $this->expectOutputString('1,');

        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '1,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                $klein_app->abort(404);
                echo '2,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '3,';
            }
        );

        $this->klein_app->dispatch();

        $this->assertSame(404, $this->klein_app->response()->code());
    }

    public function testDispatchAbortCallsHttpError()
    {
        $test_code = 666;
        $this->expectOutputString('1,aborted,'. $test_code);

        $this->klein_app->onHttpError(
            function ($code, $klein_app) {
                echo 'aborted,';
                echo $code;
            }
        );

        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '1,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) use ($test_code) {
                $klein_app->abort($test_code);
                echo '2,';
            }
        );
        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) {
                echo '3,';
            }
        );

        $this->klein_app->dispatch();

        $this->assertSame($test_code, $this->klein_app->response()->code());
    }

    /**
     * @expectedException Klein\Exceptions\UnhandledException
     */
    public function testDispatchExceptionRethrowsUnknownCode()
    {
        $this->expectOutputString('');

        $test_message = 'whatever';
        $test_code = 666;

        $this->klein_app->respond(
            function ($a, $b, $c, $d, $klein_app) use ($test_message, $test_code) {
                throw new DispatchHaltedException($test_message, $test_code);
            }
        );

        $this->klein_app->dispatch();

        $this->assertSame(404, $this->klein_app->response()->code());
    }

    public function testThrowHttpExceptionHandledProperly()
    {
        $this->expectOutputString('');

        $this->klein_app->respond(
            '/',
            function ($a, $b, $c, $d, $klein_app) {
                throw HttpException::createFromCode(400);

                echo 'hi!';
            }
        );

        $this->klein_app->dispatch();

        $this->assertSame(400, $this->klein_app->response()->code());
    }

    public function testHttpExceptionStopsRouteMatching()
    {
        $this->expectOutputString('one');

        $this->klein_app->respond(
            function () {
                echo 'one';

                throw HttpException::createFromCode(404);
            }
        );
        $this->klein_app->respond(
            function () {
                echo 'two';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/notroute')
        );
    }

    public function testOptionsAlias()
    {
        $this->expectOutputString('1,2,');

        // With path
        $this->klein_app->options(
            '/',
            function () {
                echo '1,';
            }
        );

        // Without path
        $this->klein_app->options(
            function () {
                echo '2,';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'OPTIONS')
        );
    }

    public function testHeadAlias()
    {
        // HEAD requests shouldn't return data
        $this->expectOutputString('');

        // With path
        $this->klein_app->head(
            '/',
            function ($request, $response) {
                echo '1,';
                $response->headers()->set('Test-1', 'yup');
            }
        );

        // Without path
        $this->klein_app->head(
            function ($request, $response) {
                echo '2,';
                $response->headers()->set('Test-2', 'yup');
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'HEAD')
        );

        $this->assertTrue($this->klein_app->response()->headers()->exists('Test-1'));
        $this->assertTrue($this->klein_app->response()->headers()->exists('Test-2'));
        $this->assertFalse($this->klein_app->response()->headers()->exists('Test-3'));
    }

    public function testGetAlias()
    {
        $this->expectOutputString('1,2,');

        // With path
        $this->klein_app->get(
            '/',
            function () {
                echo '1,';
            }
        );

        // Without path
        $this->klein_app->get(
            function () {
                echo '2,';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/')
        );
    }

    public function testPostAlias()
    {
        $this->expectOutputString('1,2,');

        // With path
        $this->klein_app->post(
            '/',
            function () {
                echo '1,';
            }
        );

        // Without path
        $this->klein_app->post(
            function () {
                echo '2,';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'POST')
        );
    }

    public function testPutAlias()
    {
        $this->expectOutputString('1,2,');

        // With path
        $this->klein_app->put(
            '/',
            function () {
                echo '1,';
            }
        );

        // Without path
        $this->klein_app->put(
            function () {
                echo '2,';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'PUT')
        );
    }

    public function testDeleteAlias()
    {
        $this->expectOutputString('1,2,');

        // With path
        $this->klein_app->delete(
            '/',
            function () {
                echo '1,';
            }
        );

        // Without path
        $this->klein_app->delete(
            function () {
                echo '2,';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/', 'DELETE')
        );
    }


    /**
     * Advanced string route matching tests
     *
     * As the original Klein project was designed as a PHP version of Sinatra,
     * many of the following tests are ports of the Sinatra ruby equivalents:
     * https://github.com/sinatra/sinatra/blob/cd82a57154d57c18acfadbfefbefc6ea6a5035af/test/routing_test.rb
     */

    public function testMatchesEncodedSlashes()
    {
        $this->klein_app->respond(
            '/[:a]',
            function ($request) {
                return $request->param('a');
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/foo%2Fbar'),
            null,
            true,
            Klein::DISPATCH_CAPTURE_AND_RETURN
        );

        $this->assertSame(200, $this->klein_app->response()->code());
        $this->assertSame('foo/bar', $this->klein_app->response()->body());
    }

    public function testMatchesDotAsNamedParam()
    {
        $this->klein_app->respond(
            '/[:foo]/[:bar]',
            function ($request) {
                return $request->param('foo');
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/user@example.com/name'),
            null,
            true,
            Klein::DISPATCH_CAPTURE_AND_RETURN
        );

        $this->assertSame(200, $this->klein_app->response()->code());
        $this->assertSame('user@example.com', $this->klein_app->response()->body());
    }

    public function testMatchesDotOutsideOfNamedParam()
    {
        $file = null;
        $ext  = null;

        $this->klein_app->respond(
            '/[:file].[:ext]',
            function ($request) use (&$file, &$ext) {
                $file = $request->param('file');
                $ext = $request->param('ext');

                return 'woot!';
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/unicorn.png'),
            null,
            true,
            Klein::DISPATCH_CAPTURE_AND_RETURN
        );

        $this->assertSame(200, $this->klein_app->response()->code());
        $this->assertSame('woot!', $this->klein_app->response()->body());
        $this->assertSame('unicorn', $file);
        $this->assertSame('png', $ext);
    }

    public function testMatchesLiteralDotsInPaths()
    {
        $this->klein_app->respond(
            '/file.ext',
            function () {
            }
        );

        // Should match
        $this->klein_app->dispatch(
            MockRequestFactory::create('/file.ext')
        );
        $this->assertSame(200, $this->klein_app->response()->code());

        // Shouldn't match
        $this->klein_app->dispatch(
            MockRequestFactory::create('/file0ext')
        );
        $this->assertSame(404, $this->klein_app->response()->code());
    }

    public function testMatchesLiteralDotsInPathBeforeNamedParam()
    {
        $this->klein_app->respond(
            '/file.[:ext]',
            function () {
            }
        );

        // Should match
        $this->klein_app->dispatch(
            MockRequestFactory::create('/file.ext')
        );
        $this->assertSame(200, $this->klein_app->response()->code());

        // Shouldn't match
        $this->klein_app->dispatch(
            MockRequestFactory::create('/file0ext')
        );
        $this->assertSame(404, $this->klein_app->response()->code());
    }

    public function testMultipleUnsafeCharactersArentOverQuoted()
    {
        $this->klein_app->respond(
            '/[a:site].[:format]?/[:id].[:format2]?',
            function () {
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/site.main/id.json')
        );
        $this->assertSame(200, $this->klein_app->response()->code());
    }

    public function testMatchesLiteralPlusSignsInPaths()
    {
        $this->klein_app->respond(
            '/te+st',
            function () {
            }
        );

        // Should match
        $this->klein_app->dispatch(
            MockRequestFactory::create('/te+st')
        );
        $this->assertSame(200, $this->klein_app->response()->code());

        // Shouldn't match
        $this->klein_app->dispatch(
            MockRequestFactory::create('/teeeeeeeeest')
        );
        $this->assertSame(404, $this->klein_app->response()->code());
    }

    public function testMatchesParenthesesInPaths()
    {
        $this->klein_app->respond(
            '/test(bar)',
            function () {
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/test(bar)')
        );
        $this->assertSame(200, $this->klein_app->response()->code());
    }

    public function testMatchesAdvancedRegularExpressions()
    {
        $this->klein_app->respond(
            '@^/foo.../bar$',
            function () {
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/foooom/bar')
        );
        $this->assertSame(200, $this->klein_app->response()->code());
    }

    public function testApcDependencyFailsGracefully()
    {
        // Custom apc function
        implement_custom_apc_cache_functions();

        $this->klein_app->respond(
            '/test',
            function () {
            }
        );

        $this->klein_app->dispatch(
            MockRequestFactory::create('/test')
        );
        $this->assertSame(200, $this->klein_app->response()->code());
    }

    public function testRoutePathCompilationFailure()
    {
        $this->klein_app->respond(
            '/users/[i:id]/friends/[i:id]/',
            function () {
                echo 'yup';
            }
        );

        $exception = null;

        try {
            $this->klein_app->dispatch(
                MockRequestFactory::create('/users/1738197/friends/7828316')
            );
        } catch (\Exception $e) {
            $exception = $e->getPrevious();
        }

        $this->assertTrue($exception instanceof RoutePathCompilationException);
        $this->assertTrue($exception->getRoute() instanceof Route);
    }

    public function testRoutePathCompilationFailureWithoutWarnings()
    {
        $old_error_val = error_reporting();
        error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);

        $this->testRoutePathCompilationFailure();

        error_reporting($old_error_val);
    }
}

ACC SHELL 2018