def test_custom_processor(self):
        class RoleProcessor(Processor):
            def __call__(self, value, route):
                # prepare takes care of the `optional` part automaticly
                argument, value = self.prepare(value, route)

                # argument is the parameter with which the route was defined
                # value is the parameter which `solve` was called with

                print(value, 'in', argument)
                if not argument:
                    # processor is optional
                    return 0
                elif value in argument:
                    # value is one of the allowed roles
                    return -1
                else:
                    # you could also raise some other error and return
                    # a 403 to your users, this simply marks the route
                    # as not runnable if the role does not match
                    error = 'Role does not match, `{:s}` not in `{:s}`'.format(
                        value, ', '.join(argument))
                    raise MatchError(error)

        # create a router with the RoleProcessor
        router = Avenue([
            PathProcessor('path'),
            MethodProcessor('method', optional=True),
            RoleProcessor('role', optional=True),
        ])

        # define a route without a role
        @router.attach(path='/', method='GET')
        def hello_world():
            return 'Hallo world!'

        # define a route and use the role parameter
        @router.attach(path='/', method='GET', role=['user', 'administrator'])
        def hello_world_for_authenticated_people():
            return 'Hallo world, for users and administrators!'

        # define a route that matches the path, but accepts other roles
        @router.attach(path='/', method='GET', role=['spy'])
        def hello_world_for_spies():
            return 'Hallo world, nothing to see here!'

        # solve without a role
        route = {'path': '/', 'method': 'GET'}
        assert router.solve(**route) == 'Hallo world!'

        # solve with a role
        route = {'path': '/', 'method': 'GET', 'role': 'user'}
        assert router.solve(
            **route) == 'Hallo world, for users and administrators!'

        # solve with the spy role
        route = {'path': '/', 'method': 'GET', 'role': 'spy'}
        assert router.solve(
            **route) == 'Hallo world, nothing to see here!', router.solve(
            **route)
    def test_exceptions(self):
        avenue = Avenue()

        @avenue.attach()
        def will_never_run():
            pass

        with raises(RuntimeError):
            avenue.solve()
    def test_ordering(self):
        router = Avenue()

        @router.attach(path='/')
        def route_1():
            return 'Route 1'

        @router.attach(path='/', method='GET')
        def route_2():
            return 'Route 2'

        assert router.solve(path='/') == 'Route 1'
        assert router.solve(path='/', method='GET') == 'Route 2'
    def test_wrap(self):
        def wrap(func):
            def inner(**kwargs):
                return 'Wrapped: ' + func(**kwargs)

            return inner

        router = Avenue()

        @router.attach(path='/')
        def route():
            return 'Route 1'

        assert router.solve(path='/', wrap=wrap) == 'Wrapped: Route 1'
    def test_skipping(self):
        router = Avenue()
        toggle = 0

        @router.attach(path='/')
        def route_1():
            if toggle == 0:
                return 'Route 1'
            raise Skip()

        @router.attach(path='/')
        def route_2():
            return 'Route 2'

        assert router.solve(path='/') == 'Route 1'

        toggle = 1
        assert router.solve(path='/') == 'Route 2'
    def test_blueprinting(self):
        router = Avenue()

        sub = router.blueprint(path='/sub', method='GET')

        @sub.attach(path='/part')
        def route_1():
            return 'Route 1'

        @sub.attach(path=u'/part/§')
        def route_2():
            return 'Route 2'

        @sub.attach(path='/update', method='POST')
        def route_3():
            return 'Route 3'

        assert router.solve(path='/sub/part', method='GET') == 'Route 1'
        assert router.solve(path='/part/sub', method='GET') == 'Route 2'
        assert router.solve(path='/sub/update', method='POST') == 'Route 3'
    def test_basics(self):
        router = Avenue()

        @router.attach(path='/', method='GET')
        @router.attach(path='/welcome')
        def route_1():
            return 'Route 1'

        @router.attach(path='/', method='POST')
        def route_2():
            return 'Route 2'

        @router.attach(path='/post/<id|int>')
        def route_3(id):
            return 'Route 3 - for {:s}'.format(repr(id))

        @router.attach(path='/post/new')
        def route_4():
            return 'Route 4'

        @router.attach(path='/<page|greedy>')
        def route_5(page):
            return 'Route 5 - fallback - {:s}'.format(page)

        routing = [
            [{'path': '/', 'method': 'GET'},
             'Route 1'],
            [{'path': '/', 'method': 'POST'},
             'Route 2'],
            [{'path': '/post/12', 'method': 'GET'},
             'Route 3 - for 12'],
            [{'path': '/post/new-article-here', 'method': 'GET'},
             'Route 5 - fallback - post/new-article-here'],
            [{'path': '/post/new', 'method': 'GET'},
             'Route 4'],
            [{'path': '/any/other/page', 'method': 'GET'},
             'Route 5 - fallback - any/other/page'],
        ]

        for route, result in routing:
            assert router.solve(**route) == result
    def test_path_processor(self):
        avenue = Avenue([
            PathProcessor('path_1'),
            PathProcessor('path_2', optional=True),
        ])

        @avenue.attach(path_1='/welcome', path_2='/nl')
        def nl_welcome():
            return 'Welkom.'

        @avenue.attach(path_1='/welcome', path_2='/de-DE')
        def de_welcome():
            return 'Willkommen.'

        @avenue.attach(path_1='/welcome')
        def welcome():
            return 'Welcome.'

        assert avenue.solve(path_1='/welcome',
                            path_2='/de-DE') == 'Willkommen.'

        assert avenue.solve(path_1='/welcome') == 'Welcome.'
    def test_missing(self):
        router = Avenue()

        @router.attach(path='/', method='GET')
        @router.attach(path='/welcome')
        def route_1():
            return 'Route 1'

        with raises(NotFound):
            router.solve(path='/does/not/exist', method='GET')

        with raises(NotFound):
            router.solve()

        router = Avenue([MethodProcessor('method', optional=True)])

        @router.attach()
        def route_2():
            return 'Route 2'

        assert router.solve() == 'Route 2'