示例#1
0
def test_match_entire_path(uri_template, path):
    router = DefaultRouter()

    router.add_route(uri_template, {}, ResourceWithId(1))

    route = router.find(path)
    assert route is None
示例#2
0
def test_capture_path_complex(template):
    router = DefaultRouter()
    with pytest.raises(
            ValueError,
            match='Cannot use converter "path" of variable "bar" in a template '
    ):
        router.add_route(template, ResourceWithId(1))
示例#3
0
def test_match_entire_path(uri_template, path):
    router = DefaultRouter()

    router.add_route(uri_template, ResourceWithId(1))

    route = router.find(path)
    assert route is None
示例#4
0
def test_user_regression_special_chars(uri_template, path, expected_params):
    router = DefaultRouter()

    router.add_route(uri_template, ResourceWithId(1))

    route = router.find(path)
    assert route is not None

    resource, __, params, __ = route
    assert resource.resource_id == 1
    assert params == expected_params
示例#5
0
def test_user_regression_special_chars(uri_template, path, expected_params):
    router = DefaultRouter()

    router.add_route(uri_template, {}, ResourceWithId(1))

    route = router.find(path)
    assert route is not None

    resource, __, params, __ = route
    assert resource.resource_id == 1
    assert params == expected_params
示例#6
0
def test_user_regression_recipes():
    router = DefaultRouter()
    router.add_route('/recipes/{activity}/{type_id}', ResourceWithId(1))
    router.add_route('/recipes/baking', ResourceWithId(2))

    resource, __, __, __ = router.find('/recipes/baking/4242')
    assert resource.resource_id == 1

    resource, __, __, __ = router.find('/recipes/baking')
    assert resource.resource_id == 2

    route = router.find('/recipes/grilling')
    assert route is None
示例#7
0
def test_user_regression_recipes():
    router = DefaultRouter()
    router.add_route(
        '/recipes/{activity}/{type_id}',
        ResourceWithId(1)
    )
    router.add_route(
        '/recipes/baking',
        ResourceWithId(2)
    )

    resource, __, __, __ = router.find('/recipes/baking/4242')
    assert resource.resource_id == 1

    resource, __, __, __ = router.find('/recipes/baking')
    assert resource.resource_id == 2

    route = router.find('/recipes/grilling')
    assert route is None
示例#8
0
def test_root_path():
    router = DefaultRouter()
    router.add_route('/', {}, ResourceWithId(42))

    resource, __, __, __ = router.find('/')
    assert resource.resource_id == 42

    expected_src = textwrap.dedent("""
        def find(path, return_values, patterns, converters, params):
            path_len = len(path)
            if path_len > 0:
                if path[0] == '':
                    if path_len == 1:
                        return return_values[0]
                    return None
                return None
            return None
    """).strip()

    assert router.finder_src == expected_src
示例#9
0
def test_user_regression_versioned_url():
    router = DefaultRouter()
    router.add_route('/{version}/messages', {}, ResourceWithId(2))

    resource, __, __, __ = router.find('/v2/messages')
    assert resource.resource_id == 2

    router.add_route('/v2', {}, ResourceWithId(1))

    resource, __, __, __ = router.find('/v2')
    assert resource.resource_id == 1

    resource, __, __, __ = router.find('/v2/messages')
    assert resource.resource_id == 2

    resource, __, __, __ = router.find('/v1/messages')
    assert resource.resource_id == 2

    route = router.find('/v1')
    assert route is None
示例#10
0
def test_user_regression_versioned_url():
    router = DefaultRouter()
    router.add_route('/{version}/messages', ResourceWithId(2))

    resource, __, __, __ = router.find('/v2/messages')
    assert resource.resource_id == 2

    router.add_route('/v2', ResourceWithId(1))

    resource, __, __, __ = router.find('/v2')
    assert resource.resource_id == 1

    resource, __, __, __ = router.find('/v2/messages')
    assert resource.resource_id == 2

    resource, __, __, __ = router.find('/v1/messages')
    assert resource.resource_id == 2

    route = router.find('/v1')
    assert route is None
示例#11
0
def test_root_path():
    router = DefaultRouter()
    router.add_route('/', ResourceWithId(42))

    resource, __, __, __ = router.find('/')
    assert resource.resource_id == 42

    expected_src = textwrap.dedent("""
        def find(path, return_values, patterns, converters, params):
            path_len = len(path)
            if path_len > 0:
                if path[0] == '':
                    if path_len == 1:
                        return return_values[0]
                    return None
                return None
            return None
    """).strip()

    assert router.finder_src == expected_src
示例#12
0
def test_capture_path_no_match():
    router = DefaultRouter()

    router.add_route('/foo/bar/baz', ResourceWithId(1))
    router.add_route('/foo/{bar:path}', ResourceWithId(2))
    router.add_route('/foo/bar/{foo:path}', ResourceWithId(3))

    assert router.find('/foo') is None
示例#13
0
class TestRegressionCases(testing.TestBase):
    """Test specific repros reported by users of the framework."""

    def before(self):
        self.router = DefaultRouter()

    def test_versioned_url(self):
        self.router.add_route('/{version}/messages', {}, ResourceWithId(2))

        resource, __, __, __ = self.router.find('/v2/messages')
        self.assertEqual(resource.resource_id, 2)

        self.router.add_route('/v2', {}, ResourceWithId(1))

        resource, __, __, __ = self.router.find('/v2')
        self.assertEqual(resource.resource_id, 1)

        resource, __, __, __ = self.router.find('/v2/messages')
        self.assertEqual(resource.resource_id, 2)

        resource, __, __, __ = self.router.find('/v1/messages')
        self.assertEqual(resource.resource_id, 2)

        route = self.router.find('/v1')
        self.assertIs(route, None)

    def test_recipes(self):
        self.router.add_route(
            '/recipes/{activity}/{type_id}', {}, ResourceWithId(1))
        self.router.add_route(
            '/recipes/baking', {}, ResourceWithId(2))

        resource, __, __, __ = self.router.find('/recipes/baking/4242')
        self.assertEqual(resource.resource_id, 1)

        resource, __, __, __ = self.router.find('/recipes/baking')
        self.assertEqual(resource.resource_id, 2)

        route = self.router.find('/recipes/grilling')
        self.assertIs(route, None)
示例#14
0
class TestRegressionCases(testing.TestBase):
    """Test specific repros reported by users of the framework."""

    def before(self):
        self.router = DefaultRouter()

    def test_versioned_url(self):
        self.router.add_route('/{version}/messages', {}, ResourceWithId(2))

        resource, method_map, params = self.router.find('/v2/messages')
        self.assertEqual(resource.resource_id, 2)

        self.router.add_route('/v2', {}, ResourceWithId(1))

        resource, method_map, params = self.router.find('/v2')
        self.assertEqual(resource.resource_id, 1)

        resource, method_map, params = self.router.find('/v2/messages')
        self.assertEqual(resource.resource_id, 2)

        resource, method_map, params = self.router.find('/v1/messages')
        self.assertEqual(resource.resource_id, 2)

        route = self.router.find('/v1')
        self.assertIs(route, None)

    def test_recipes(self):
        self.router.add_route(
            '/recipes/{activity}/{type_id}', {}, ResourceWithId(1))
        self.router.add_route(
            '/recipes/baking', {}, ResourceWithId(2))

        resource, method_map, params = self.router.find('/recipes/baking/4242')
        self.assertEqual(resource.resource_id, 1)

        resource, method_map, params = self.router.find('/recipes/baking')
        self.assertEqual(resource.resource_id, 2)

        route = self.router.find('/recipes/grilling')
        self.assertIs(route, None)
示例#15
0
def test_capture_path_no_children():
    router = DefaultRouter()
    router.add_route('/foo/{bar:path}', ResourceWithId(1))
    res = router.finder_src
    with pytest.raises(
            ValueError,
            match='Cannot add route with template "/foo/{bar:path}/child". '
            'Field name "bar" uses the converter "path"',
    ):
        router.add_route('/foo/{bar:path}/child', ResourceWithId(1))
    with pytest.raises(
            ValueError,
            match='Cannot add route with template "/{bar:path}/child". '
            'Field name "bar" uses the converter "path"',
    ):
        router.add_route('/{bar:path}/child', ResourceWithId(1))
    assert res == router.finder_src
示例#16
0
class TestStandaloneRouter(testing.TestBase):
    def before(self):
        from falcon.routing import DefaultRouter
        self.router = DefaultRouter()
        setup_routes(self.router)

    @ddt.data(
        '/teams/{collision}',  # simple vs simple
        '/emojis/signs/{id_too}',  # another simple vs simple
        '/repos/{org}/{repo}/compare/{complex}:{vs}...{complex2}:{collision}',
    )
    def test_collision(self, template):
        self.assertRaises(
            ValueError,
            self.router.add_route, template, {}, ResourceWithId(-1)
        )

    @ddt.data(
        '/repos/{org}/{repo}/compare/{simple-vs-complex}',
        '/repos/{complex}.{vs}.{simple}',
        '/repos/{org}/{repo}/compare/{complex}:{vs}...{complex2}/full',
    )
    def test_non_collision(self, template):
        self.router.add_route(template, {}, ResourceWithId(-1))

    def test_dump(self):
        print(self.router._src)

    def test_override(self):
        self.router.add_route('/emojis/signs/0', {}, ResourceWithId(-1))

        resource, method_map, params = self.router.find('/emojis/signs/0')
        self.assertEqual(resource.resource_id, -1)

    def test_missing(self):
        resource, method_map, params = self.router.find('/this/does/not/exist')
        self.assertIs(resource, None)

        resource, method_map, params = self.router.find('/user/bogus')
        self.assertIs(resource, None)

        resource, method_map, params = self.router.find('/teams/1234/bogus')
        self.assertIs(resource, None)

        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/johndoe:master...janedoe:dev/bogus')
        self.assertIs(resource, None)

    def test_literal_segment(self):
        resource, method_map, params = self.router.find('/emojis/signs/0')
        self.assertEqual(resource.resource_id, 12)

        resource, method_map, params = self.router.find('/emojis/signs/1')
        self.assertEqual(resource.resource_id, 13)

        resource, method_map, params = self.router.find('/emojis/signs/42')
        self.assertEqual(resource.resource_id, 14)

        resource, method_map, params = self.router.find('/emojis/signs/42/small')
        self.assertEqual(resource.resource_id, 14.1)

        resource, method_map, params = self.router.find('/emojis/signs/1/small')
        self.assertEqual(resource, None)

    @ddt.data(
        '/teams',
        '/emojis/signs',
        '/gists',
        '/gists/42',
    )
    def test_dead_segment(self, template):
        resource, method_map, params = self.router.find(template)
        self.assertIs(resource, None)

    def test_malformed_pattern(self):
        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/foo')
        self.assertIs(resource, None)

        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/foo/full')
        self.assertIs(resource, None)

    def test_literal(self):
        resource, method_map, params = self.router.find('/user/memberships')
        self.assertEqual(resource.resource_id, 8)

    def test_variable(self):
        resource, method_map, params = self.router.find('/teams/42')
        self.assertEqual(resource.resource_id, 6)
        self.assertEqual(params, {'id': '42'})

        resource, method_map, params = self.router.find('/emojis/signs/stop')
        self.assertEqual(params, {'id': 'stop'})

        resource, method_map, params = self.router.find('/gists/42/raw')
        self.assertEqual(params, {'id': '42'})

    def test_subsegment_not_found(self):
        resource, method_map, params = self.router.find('/emojis/signs/0/x')
        self.assertIs(resource, None)

    def test_multivar(self):
        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/commits')
        self.assertEqual(resource.resource_id, 4)
        self.assertEqual(params, {'org': 'racker', 'repo': 'falcon'})

        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/all')
        self.assertEqual(resource.resource_id, 11)
        self.assertEqual(params, {'org': 'racker', 'repo': 'falcon'})

    @ddt.data(('', 5), ('/full', 10), ('/part', 15))
    @ddt.unpack
    def test_complex(self, url_postfix, resource_id):
        uri = '/repos/racker/falcon/compare/johndoe:master...janedoe:dev'
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(params, {
            'org': 'racker',
            'repo': 'falcon',
            'usr0': 'johndoe',
            'branch0': 'master',
            'usr1': 'janedoe',
            'branch1': 'dev'
        })

    @ddt.data(('', 16), ('/full', 17))
    @ddt.unpack
    def test_complex_alt(self, url_postfix, resource_id):
        uri = '/repos/falconry/falcon/compare/johndoe:master'
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(params, {
            'org': 'falconry',
            'repo': 'falcon',
            'usr0': 'johndoe',
            'branch0': 'master',
        })
示例#17
0
 def add_route(self, uri_template, method_map, resource, name=None):
     if name:
         self.url_map[name] = uri_template
     DefaultRouter.add_route(self, uri_template, method_map, resource)
示例#18
0
def router():
    router = DefaultRouter()

    router.add_route('/repos', ResourceWithId(1))
    router.add_route('/repos/{org}', ResourceWithId(2))
    router.add_route('/repos/{org}/{repo}', ResourceWithId(3))
    router.add_route('/repos/{org}/{repo}/commits', ResourceWithId(4))
    router.add_route(
        '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}',
        ResourceWithId(5))

    router.add_route('/teams/{id}', ResourceWithId(6))
    router.add_route('/teams/{id}/members', ResourceWithId(7))

    router.add_route('/teams/default', ResourceWithId(19))
    router.add_route('/teams/default/members/thing', ResourceWithId(19))

    router.add_route('/user/memberships', ResourceWithId(8))
    router.add_route('/emojis', ResourceWithId(9))
    router.add_route(
        '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/full',
        ResourceWithId(10))
    router.add_route('/repos/{org}/{repo}/compare/all', ResourceWithId(11))

    # NOTE(kgriffs): The ordering of these calls is significant; we
    # need to test that the {id} field does not match the other routes,
    # regardless of the order they are added.
    router.add_route('/emojis/signs/0', ResourceWithId(12))
    router.add_route('/emojis/signs/{id}', ResourceWithId(13))
    router.add_route('/emojis/signs/42', ResourceWithId(14))
    router.add_route('/emojis/signs/42/small.jpg', ResourceWithId(23))
    router.add_route('/emojis/signs/78/small.png', ResourceWithId(24))

    # Test some more special chars
    router.add_route('/emojis/signs/78/small(png)', ResourceWithId(25))
    router.add_route('/emojis/signs/78/small_png', ResourceWithId(26))
    router.add_route('/images/{id}.gif', ResourceWithId(27))

    router.add_route(
        '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/part',
        ResourceWithId(15))
    router.add_route('/repos/{org}/{repo}/compare/{usr0}:{branch0}',
                     ResourceWithId(16))
    router.add_route('/repos/{org}/{repo}/compare/{usr0}:{branch0}/full',
                     ResourceWithId(17))

    router.add_route('/gists/{id}/{representation}', ResourceWithId(21))
    router.add_route('/gists/{id}/raw', ResourceWithId(18))
    router.add_route('/gists/first', ResourceWithId(20))

    router.add_route('/item/{q}', ResourceWithId(28))

    # ----------------------------------------------------------------
    # Routes with field converters
    # ----------------------------------------------------------------

    router.add_route('/cvt/teams/{id:int(min=7)}', ResourceWithId(29))
    router.add_route('/cvt/teams/{id:int(min=7)}/members', ResourceWithId(30))
    router.add_route('/cvt/teams/default', ResourceWithId(31))
    router.add_route('/cvt/teams/default/members/{id:int}-{tenure:int}',
                     ResourceWithId(32))

    router.add_route(
        '/cvt/repos/{org}/{repo}/compare/{usr0}:{branch0:int}...{usr1}:{branch1:int}/part',
        ResourceWithId(33))
    router.add_route('/cvt/repos/{org}/{repo}/compare/{usr0}:{branch0:int}',
                     ResourceWithId(34))
    router.add_route(
        '/cvt/repos/{org}/{repo}/compare/{usr0}:{branch0:int}/full',
        ResourceWithId(35))

    return router
示例#19
0
class TestComplexRouting(testing.TestBase):
    def before(self):
        self.router = DefaultRouter()

        self.router.add_route(
            '/repos', {}, ResourceWithId(1))
        self.router.add_route(
            '/repos/{org}', {}, ResourceWithId(2))
        self.router.add_route(
            '/repos/{org}/{repo}', {}, ResourceWithId(3))
        self.router.add_route(
            '/repos/{org}/{repo}/commits', {}, ResourceWithId(4))
        self.router.add_route(
            '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}',
            {}, ResourceWithId(5))

        self.router.add_route(
            '/teams/{id}', {}, ResourceWithId(6))
        self.router.add_route(
            '/teams/{id}/members', {}, ResourceWithId(7))

        self.router.add_route(
            '/teams/default', {}, ResourceWithId(19))
        self.router.add_route(
            '/teams/default/members/thing', {}, ResourceWithId(19))

        self.router.add_route(
            '/user/memberships', {}, ResourceWithId(8))
        self.router.add_route(
            '/emojis', {}, ResourceWithId(9))
        self.router.add_route(
            '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/full',
            {}, ResourceWithId(10))
        self.router.add_route(
            '/repos/{org}/{repo}/compare/all', {}, ResourceWithId(11))

        # NOTE(kgriffs): The ordering of these calls is significant; we
        # need to test that the {id} field does not match the other routes,
        # regardless of the order they are added.
        self.router.add_route(
            '/emojis/signs/0', {}, ResourceWithId(12))
        self.router.add_route(
            '/emojis/signs/{id}', {}, ResourceWithId(13))
        self.router.add_route(
            '/emojis/signs/42', {}, ResourceWithId(14))
        self.router.add_route(
            '/emojis/signs/42/small', {}, ResourceWithId(14.1))
        self.router.add_route(
            '/emojis/signs/78/small', {}, ResourceWithId(22))

        self.router.add_route(
            '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/part',
            {}, ResourceWithId(15))
        self.router.add_route(
            '/repos/{org}/{repo}/compare/{usr0}:{branch0}',
            {}, ResourceWithId(16))
        self.router.add_route(
            '/repos/{org}/{repo}/compare/{usr0}:{branch0}/full',
            {}, ResourceWithId(17))

        self.router.add_route(
            '/gists/{id}/{representation}', {}, ResourceWithId(21))
        self.router.add_route(
            '/gists/{id}/raw', {}, ResourceWithId(18))
        self.router.add_route(
            '/gists/first', {}, ResourceWithId(20))

    @ddt.data(
        '/teams/{collision}',  # simple vs simple
        '/emojis/signs/{id_too}',  # another simple vs simple
        '/repos/{org}/{repo}/compare/{complex}:{vs}...{complex2}:{collision}',
    )
    def test_collision(self, template):
        self.assertRaises(
            ValueError,
            self.router.add_route, template, {}, ResourceWithId(-1)
        )

    @ddt.data(
        '/repos/{complex}.{vs}.{simple}',
        '/repos/{org}/{repo}/compare/{complex}:{vs}...{complex2}/full',
    )
    def test_non_collision(self, template):
        self.router.add_route(template, {}, ResourceWithId(-1))

    def test_dump(self):
        print(self.router._src)

    def test_override(self):
        self.router.add_route('/emojis/signs/0', {}, ResourceWithId(-1))

        resource, method_map, params = self.router.find('/emojis/signs/0')
        self.assertEqual(resource.resource_id, -1)

    def test_literal_segment(self):
        resource, method_map, params = self.router.find('/emojis/signs/0')
        self.assertEqual(resource.resource_id, 12)

        resource, method_map, params = self.router.find('/emojis/signs/1')
        self.assertEqual(resource.resource_id, 13)

        resource, method_map, params = self.router.find('/emojis/signs/42')
        self.assertEqual(resource.resource_id, 14)

        resource, method_map, params = self.router.find('/emojis/signs/42/small')
        self.assertEqual(resource.resource_id, 14.1)

        route = self.router.find('/emojis/signs/1/small')
        self.assertEqual(route, None)

    @ddt.data(
        '/teams',
        '/emojis/signs',
        '/gists',
        '/gists/42',
    )
    def test_dead_segment(self, template):
        route = self.router.find(template)
        self.assertIs(route, None)

    def test_malformed_pattern(self):
        route = self.router.find(
            '/repos/racker/falcon/compare/foo')
        self.assertIs(route, None)

        route = self.router.find(
            '/repos/racker/falcon/compare/foo/full')
        self.assertIs(route, None)

    def test_literal(self):
        resource, method_map, params = self.router.find('/user/memberships')
        self.assertEqual(resource.resource_id, 8)

    def test_variable(self):
        resource, method_map, params = self.router.find('/teams/42')
        self.assertEqual(resource.resource_id, 6)
        self.assertEqual(params, {'id': '42'})

        resource, method_map, params = self.router.find('/emojis/signs/stop')
        self.assertEqual(params, {'id': 'stop'})

        resource, method_map, params = self.router.find('/gists/42/raw')
        self.assertEqual(params, {'id': '42'})

    @ddt.data(
        ('/teams/default', 19),
        ('/teams/default/members', 7),
        ('/teams/foo', 6),
        ('/teams/foo/members', 7),
        ('/gists/first', 20),
        ('/gists/first/raw', 18),
        ('/gists/first/pdf', 21),
        ('/gists/1776/pdf', 21),
        ('/emojis/signs/78', 13),
        ('/emojis/signs/78/small', 22),
    )
    @ddt.unpack
    def test_literal_vs_variable(self, path, expected_id):
        resource, method_map, params = self.router.find(path)
        self.assertEqual(resource.resource_id, expected_id)

    @ddt.data(
        # Misc.
        '/this/does/not/exist',
        '/user/bogus',
        '/repos/racker/falcon/compare/johndoe:master...janedoe:dev/bogus',

        # Literal vs variable (teams)
        '/teams',
        '/teams/42/members/undefined',
        '/teams/42/undefined',
        '/teams/42/undefined/segments',
        '/teams/default/members/undefined',
        '/teams/default/members/thing/undefined',
        '/teams/default/members/thing/undefined/segments',
        '/teams/default/undefined',
        '/teams/default/undefined/segments',

        # Literal vs variable (emojis)
        '/emojis/signs',
        '/emojis/signs/0/small',
        '/emojis/signs/0/undefined',
        '/emojis/signs/0/undefined/segments',
        '/emojis/signs/20/small',
        '/emojis/signs/20/undefined',
        '/emojis/signs/42/undefined',
        '/emojis/signs/78/undefined',
    )
    def test_not_found(self, path):
        route = self.router.find(path)
        self.assertIs(route, None)

    def test_subsegment_not_found(self):
        route = self.router.find('/emojis/signs/0/x')
        self.assertIs(route, None)

    def test_multivar(self):
        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/commits')
        self.assertEqual(resource.resource_id, 4)
        self.assertEqual(params, {'org': 'racker', 'repo': 'falcon'})

        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/all')
        self.assertEqual(resource.resource_id, 11)
        self.assertEqual(params, {'org': 'racker', 'repo': 'falcon'})

    @ddt.data(('', 5), ('/full', 10), ('/part', 15))
    @ddt.unpack
    def test_complex(self, url_postfix, resource_id):
        uri = '/repos/racker/falcon/compare/johndoe:master...janedoe:dev'
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(params, {
            'org': 'racker',
            'repo': 'falcon',
            'usr0': 'johndoe',
            'branch0': 'master',
            'usr1': 'janedoe',
            'branch1': 'dev',
        })

    @ddt.data(('', 16), ('/full', 17))
    @ddt.unpack
    def test_complex_alt(self, url_postfix, resource_id):
        uri = '/repos/falconry/falcon/compare/johndoe:master'
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(params, {
            'org': 'falconry',
            'repo': 'falcon',
            'usr0': 'johndoe',
            'branch0': 'master',
        })
示例#20
0
def router():
    router = DefaultRouter()
    router.add_route("/browse/{id:int}/", lambda x: x)
    return router
示例#21
0
def router():
    router = DefaultRouter()

    router.add_route(
        '/repos', {}, ResourceWithId(1))
    router.add_route(
        '/repos/{org}', {}, ResourceWithId(2))
    router.add_route(
        '/repos/{org}/{repo}', {}, ResourceWithId(3))
    router.add_route(
        '/repos/{org}/{repo}/commits', {}, ResourceWithId(4))
    router.add_route(
        u'/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}',
        {}, ResourceWithId(5))

    router.add_route(
        '/teams/{id}', {}, ResourceWithId(6))
    router.add_route(
        '/teams/{id}/members', {}, ResourceWithId(7))

    router.add_route(
        '/teams/default', {}, ResourceWithId(19))
    router.add_route(
        '/teams/default/members/thing', {}, ResourceWithId(19))

    router.add_route(
        '/user/memberships', {}, ResourceWithId(8))
    router.add_route(
        '/emojis', {}, ResourceWithId(9))
    router.add_route(
        '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/full',
        {}, ResourceWithId(10))
    router.add_route(
        '/repos/{org}/{repo}/compare/all', {}, ResourceWithId(11))

    # NOTE(kgriffs): The ordering of these calls is significant; we
    # need to test that the {id} field does not match the other routes,
    # regardless of the order they are added.
    router.add_route(
        '/emojis/signs/0', {}, ResourceWithId(12))
    router.add_route(
        '/emojis/signs/{id}', {}, ResourceWithId(13))
    router.add_route(
        '/emojis/signs/42', {}, ResourceWithId(14))
    router.add_route(
        '/emojis/signs/42/small.jpg', {}, ResourceWithId(23))
    router.add_route(
        '/emojis/signs/78/small.png', {}, ResourceWithId(24))

    # Test some more special chars
    router.add_route(
        '/emojis/signs/78/small(png)', {}, ResourceWithId(25))
    router.add_route(
        '/emojis/signs/78/small_png', {}, ResourceWithId(26))
    router.add_route('/images/{id}.gif', {}, ResourceWithId(27))

    router.add_route(
        '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/part',
        {}, ResourceWithId(15))
    router.add_route(
        '/repos/{org}/{repo}/compare/{usr0}:{branch0}',
        {}, ResourceWithId(16))
    router.add_route(
        '/repos/{org}/{repo}/compare/{usr0}:{branch0}/full',
        {}, ResourceWithId(17))

    router.add_route(
        '/gists/{id}/{representation}', {}, ResourceWithId(21))
    router.add_route(
        '/gists/{id}/raw', {}, ResourceWithId(18))
    router.add_route(
        '/gists/first', {}, ResourceWithId(20))

    router.add_route('/item/{q}', {}, ResourceWithId(28))

    # ----------------------------------------------------------------
    # Routes with field converters
    # ----------------------------------------------------------------

    router.add_route(
        '/cvt/teams/{id:int(min=7)}', {}, ResourceWithId(29))
    router.add_route(
        '/cvt/teams/{id:int(min=7)}/members', {}, ResourceWithId(30))
    router.add_route(
        '/cvt/teams/default', {}, ResourceWithId(31))
    router.add_route(
        '/cvt/teams/default/members/{id:int}-{tenure:int}', {}, ResourceWithId(32))

    router.add_route(
        '/cvt/repos/{org}/{repo}/compare/{usr0}:{branch0:int}...{usr1}:{branch1:int}/part',
        {}, ResourceWithId(33))
    router.add_route(
        '/cvt/repos/{org}/{repo}/compare/{usr0}:{branch0:int}',
        {}, ResourceWithId(34))
    router.add_route(
        '/cvt/repos/{org}/{repo}/compare/{usr0}:{branch0:int}/full',
        {}, ResourceWithId(35))

    return router
示例#22
0
class TestComplexRouting(testing.TestBase):
    def before(self):
        self.router = DefaultRouter()

        self.router.add_route('/repos', {}, ResourceWithId(1))
        self.router.add_route('/repos/{org}', {}, ResourceWithId(2))
        self.router.add_route('/repos/{org}/{repo}', {}, ResourceWithId(3))
        self.router.add_route('/repos/{org}/{repo}/commits', {},
                              ResourceWithId(4))
        self.router.add_route(
            '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}',
            {}, ResourceWithId(5))

        self.router.add_route('/teams/{id}', {}, ResourceWithId(6))
        self.router.add_route('/teams/{id}/members', {}, ResourceWithId(7))

        self.router.add_route('/teams/default', {}, ResourceWithId(19))
        self.router.add_route('/teams/default/members/thing', {},
                              ResourceWithId(19))

        self.router.add_route('/user/memberships', {}, ResourceWithId(8))
        self.router.add_route('/emojis', {}, ResourceWithId(9))
        self.router.add_route(
            '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/full',
            {}, ResourceWithId(10))
        self.router.add_route('/repos/{org}/{repo}/compare/all', {},
                              ResourceWithId(11))

        # NOTE(kgriffs): The ordering of these calls is significant; we
        # need to test that the {id} field does not match the other routes,
        # regardless of the order they are added.
        self.router.add_route('/emojis/signs/0', {}, ResourceWithId(12))
        self.router.add_route('/emojis/signs/{id}', {}, ResourceWithId(13))
        self.router.add_route('/emojis/signs/42', {}, ResourceWithId(14))
        self.router.add_route('/emojis/signs/42/small', {},
                              ResourceWithId(14.1))
        self.router.add_route('/emojis/signs/78/small', {}, ResourceWithId(22))

        self.router.add_route(
            '/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/part',
            {}, ResourceWithId(15))
        self.router.add_route('/repos/{org}/{repo}/compare/{usr0}:{branch0}',
                              {}, ResourceWithId(16))
        self.router.add_route(
            '/repos/{org}/{repo}/compare/{usr0}:{branch0}/full', {},
            ResourceWithId(17))

        self.router.add_route('/gists/{id}/{representation}', {},
                              ResourceWithId(21))
        self.router.add_route('/gists/{id}/raw', {}, ResourceWithId(18))
        self.router.add_route('/gists/first', {}, ResourceWithId(20))

    @ddt.data(
        '/teams/{collision}',  # simple vs simple
        '/emojis/signs/{id_too}',  # another simple vs simple
        '/repos/{org}/{repo}/compare/{complex}:{vs}...{complex2}:{collision}',
    )
    def test_collision(self, template):
        self.assertRaises(ValueError, self.router.add_route, template, {},
                          ResourceWithId(-1))

    @ddt.data(
        '/repos/{org}/{repo}/compare/{simple_vs_complex}',
        '/repos/{complex}.{vs}.{simple}',
        '/repos/{org}/{repo}/compare/{complex}:{vs}...{complex2}/full',
    )
    def test_non_collision(self, template):
        self.router.add_route(template, {}, ResourceWithId(-1))

    @ddt.data(
        '/{}',
        '/{9v}',
        '/{@kgriffs}',
        '/repos/{simple-thing}/etc',
        '/repos/{or g}/{repo}/compare/{thing}',
        '/repos/{org}/{repo}/compare/{}',
        '/repos/{complex}.{}.{thing}',
        '/repos/{complex}.{9v}.{thing}/etc',
    )
    def test_invalid_field_name(self, template):
        self.assertRaises(ValueError, self.router.add_route, template, {},
                          ResourceWithId(-1))

    def test_dump(self):
        print(self.router._src)

    def test_override(self):
        self.router.add_route('/emojis/signs/0', {}, ResourceWithId(-1))

        resource, method_map, params = self.router.find('/emojis/signs/0')
        self.assertEqual(resource.resource_id, -1)

    def test_literal_segment(self):
        resource, method_map, params = self.router.find('/emojis/signs/0')
        self.assertEqual(resource.resource_id, 12)

        resource, method_map, params = self.router.find('/emojis/signs/1')
        self.assertEqual(resource.resource_id, 13)

        resource, method_map, params = self.router.find('/emojis/signs/42')
        self.assertEqual(resource.resource_id, 14)

        resource, method_map, params = self.router.find(
            '/emojis/signs/42/small')
        self.assertEqual(resource.resource_id, 14.1)

        route = self.router.find('/emojis/signs/1/small')
        self.assertEqual(route, None)

    @ddt.data(
        '/teams',
        '/emojis/signs',
        '/gists',
        '/gists/42',
    )
    def test_dead_segment(self, template):
        route = self.router.find(template)
        self.assertIs(route, None)

    def test_malformed_pattern(self):
        route = self.router.find('/repos/racker/falcon/compare/foo')
        self.assertIs(route, None)

        route = self.router.find('/repos/racker/falcon/compare/foo/full')
        self.assertIs(route, None)

    def test_literal(self):
        resource, method_map, params = self.router.find('/user/memberships')
        self.assertEqual(resource.resource_id, 8)

    def test_variable(self):
        resource, method_map, params = self.router.find('/teams/42')
        self.assertEqual(resource.resource_id, 6)
        self.assertEqual(params, {'id': '42'})

        resource, method_map, params = self.router.find('/emojis/signs/stop')
        self.assertEqual(params, {'id': 'stop'})

        resource, method_map, params = self.router.find('/gists/42/raw')
        self.assertEqual(params, {'id': '42'})

    @ddt.data(
        ('/teams/default', 19),
        ('/teams/default/members', 7),
        ('/teams/foo', 6),
        ('/teams/foo/members', 7),
        ('/gists/first', 20),
        ('/gists/first/raw', 18),
        ('/gists/first/pdf', 21),
        ('/gists/1776/pdf', 21),
        ('/emojis/signs/78', 13),
        ('/emojis/signs/78/small', 22),
    )
    @ddt.unpack
    def test_literal_vs_variable(self, path, expected_id):
        resource, method_map, params = self.router.find(path)
        self.assertEqual(resource.resource_id, expected_id)

    @ddt.data(
        # Misc.
        '/this/does/not/exist',
        '/user/bogus',
        '/repos/racker/falcon/compare/johndoe:master...janedoe:dev/bogus',

        # Literal vs variable (teams)
        '/teams',
        '/teams/42/members/undefined',
        '/teams/42/undefined',
        '/teams/42/undefined/segments',
        '/teams/default/members/undefined',
        '/teams/default/members/thing/undefined',
        '/teams/default/members/thing/undefined/segments',
        '/teams/default/undefined',
        '/teams/default/undefined/segments',

        # Literal vs variable (emojis)
        '/emojis/signs',
        '/emojis/signs/0/small',
        '/emojis/signs/0/undefined',
        '/emojis/signs/0/undefined/segments',
        '/emojis/signs/20/small',
        '/emojis/signs/20/undefined',
        '/emojis/signs/42/undefined',
        '/emojis/signs/78/undefined',
    )
    def test_not_found(self, path):
        route = self.router.find(path)
        self.assertIs(route, None)

    def test_subsegment_not_found(self):
        route = self.router.find('/emojis/signs/0/x')
        self.assertIs(route, None)

    def test_multivar(self):
        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/commits')
        self.assertEqual(resource.resource_id, 4)
        self.assertEqual(params, {'org': 'racker', 'repo': 'falcon'})

        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/all')
        self.assertEqual(resource.resource_id, 11)
        self.assertEqual(params, {'org': 'racker', 'repo': 'falcon'})

    @ddt.data(('', 5), ('/full', 10), ('/part', 15))
    @ddt.unpack
    def test_complex(self, url_postfix, resource_id):
        uri = '/repos/racker/falcon/compare/johndoe:master...janedoe:dev'
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(
            params, {
                'org': 'racker',
                'repo': 'falcon',
                'usr0': 'johndoe',
                'branch0': 'master',
                'usr1': 'janedoe',
                'branch1': 'dev',
            })

    @ddt.data(('', 16), ('/full', 17))
    @ddt.unpack
    def test_complex_alt(self, url_postfix, resource_id):
        uri = '/repos/falconry/falcon/compare/johndoe:master'
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(
            params, {
                'org': 'falconry',
                'repo': 'falcon',
                'usr0': 'johndoe',
                'branch0': 'master',
            })
示例#23
0
def capture_path_router():
    router = DefaultRouter()

    router.add_route('/foo/bar/baz', ResourceWithId(1))
    router.add_route('/foo/{bar:path}', ResourceWithId(2))
    router.add_route('/foo/bar/{foo:path}', ResourceWithId(3))
    router.add_route('/{baz:path}', ResourceWithId(4))
    router.add_route('/x/{v1:int}/{v2}/{other:path}', ResourceWithId(5))
    router.add_route('/y/{v1:int}/{v2:int}/{other:path}', ResourceWithId(6))
    return router
示例#24
0
def test_root_path():
    router = DefaultRouter()
    router.add_route('/', {}, ResourceWithId(42))

    resource, __, __, __ = router.find('/')
    assert resource.resource_id == 42
示例#25
0
def test_duplicate_field_names(uri_template):
    router = DefaultRouter()
    with pytest.raises(ValueError):
        router.add_route(uri_template, {}, ResourceWithId(1))
示例#26
0
def test_duplicate_field_names(uri_template):
    router = DefaultRouter()
    with pytest.raises(ValueError):
        router.add_route(uri_template, ResourceWithId(1))
示例#27
0
class TestStandaloneRouter(testing.TestBase):
    def before(self):
        from falcon.routing import DefaultRouter
        self.router = DefaultRouter()
        setup_routes(self.router)

    @ddt.data(
        '/teams/{collision}',
        '/repos/{org}/{repo}/compare/{simple-collision}',
        '/emojis/signs/{id_too}',
    )
    def test_collision(self, template):
        self.assertRaises(
            ValueError,
            self.router.add_route, template, {}, ResourceWithId(-1)
        )

    def test_dump(self):
        print(self.router._src)

    def test_override(self):
        self.router.add_route('/emojis/signs/0', {}, ResourceWithId(-1))

        resource, method_map, params = self.router.find('/emojis/signs/0')
        self.assertEqual(resource.resource_id, -1)

    def test_missing(self):
        resource, method_map, params = self.router.find('/this/does/not/exist')
        self.assertIs(resource, None)

        resource, method_map, params = self.router.find('/user/bogus')
        self.assertIs(resource, None)

        resource, method_map, params = self.router.find('/teams/1234/bogus')
        self.assertIs(resource, None)

        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/johndoe:master...janedoe:dev/bogus')
        self.assertIs(resource, None)

    def test_literal_segment(self):
        resource, method_map, params = self.router.find('/emojis/signs/0')
        self.assertEqual(resource.resource_id, 12)

        resource, method_map, params = self.router.find('/emojis/signs/1')
        self.assertEqual(resource.resource_id, 13)

        resource, method_map, params = self.router.find('/emojis/signs/42')
        self.assertEqual(resource.resource_id, 14)

        resource, method_map, params = self.router.find('/emojis/signs/42/small')
        self.assertEqual(resource.resource_id, 14.1)

        resource, method_map, params = self.router.find('/emojis/signs/1/small')
        self.assertEqual(resource, None)

    @ddt.data(
        '/teams',
        '/emojis/signs',
        '/gists',
        '/gists/42',
    )
    def test_dead_segment(self, template):
        resource, method_map, params = self.router.find(template)
        self.assertIs(resource, None)

    def test_malformed_pattern(self):
        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/foo')
        self.assertIs(resource, None)

        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/foo/full')
        self.assertIs(resource, None)

    def test_literal(self):
        resource, method_map, params = self.router.find('/user/memberships')
        self.assertEqual(resource.resource_id, 8)

    def test_variable(self):
        resource, method_map, params = self.router.find('/teams/42')
        self.assertEqual(resource.resource_id, 6)
        self.assertEqual(params, {'id': '42'})

        resource, method_map, params = self.router.find('/emojis/signs/stop')
        self.assertEqual(params, {'id': 'stop'})

        resource, method_map, params = self.router.find('/gists/42/raw')
        self.assertEqual(params, {'id': '42'})

    def test_subsegment_not_found(self):
        resource, method_map, params = self.router.find('/emojis/signs/0/x')
        self.assertIs(resource, None)

    def test_multivar(self):
        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/commits')
        self.assertEqual(resource.resource_id, 4)
        self.assertEqual(params, {'org': 'racker', 'repo': 'falcon'})

        resource, method_map, params = self.router.find(
            '/repos/racker/falcon/compare/all')
        self.assertEqual(resource.resource_id, 11)
        self.assertEqual(params, {'org': 'racker', 'repo': 'falcon'})

    @ddt.data(('', 5), ('/full', 10), ('/part', 15))
    @ddt.unpack
    def test_complex(self, url_postfix, resource_id):
        uri = '/repos/racker/falcon/compare/johndoe:master...janedoe:dev'
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(params, {
            'org': 'racker',
            'repo': 'falcon',
            'usr0': 'johndoe',
            'branch0': 'master',
            'usr1': 'janedoe',
            'branch1': 'dev'
        })

    @ddt.data(('', 16), ('/full', 17))
    @ddt.unpack
    def test_complex_alt(self, url_postfix, resource_id):
        uri = '/repos/falconry/falcon/compare/johndoe:master'
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(params, {
            'org': 'falconry',
            'repo': 'falcon',
            'usr0': 'johndoe',
            'branch0': 'master',
        })
示例#28
0
def param_router():
    r = DefaultRouter()

    r.add_route('/c/foo/{bar}/baz', ResourceWithId(1))
    r.add_route('/c/{foo}/bar/other', ResourceWithId(2))
    r.add_route('/c/foo/{a:int}-{b}/a', ResourceWithId(3))
    r.add_route('/upload/{service}/auth/token', ResourceWithId(4))
    r.add_route('/upload/youtube/{project_id}/share', ResourceWithId(5))
    r.add_route('/x/y/{a}.{b}/z', ResourceWithId(6))
    r.add_route('/x/{y}/o.o/w', ResourceWithId(7))
    return r
示例#29
0
class TestComplexRouting(testing.TestBase):
    def before(self):
        self.router = DefaultRouter()

        self.router.add_route("/repos", {}, ResourceWithId(1))
        self.router.add_route("/repos/{org}", {}, ResourceWithId(2))
        self.router.add_route("/repos/{org}/{repo}", {}, ResourceWithId(3))
        self.router.add_route("/repos/{org}/{repo}/commits", {}, ResourceWithId(4))
        self.router.add_route("/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}", {}, ResourceWithId(5))

        self.router.add_route("/teams/{id}", {}, ResourceWithId(6))
        self.router.add_route("/teams/{id}/members", {}, ResourceWithId(7))

        self.router.add_route("/teams/default", {}, ResourceWithId(19))
        self.router.add_route("/teams/default/members/thing", {}, ResourceWithId(19))

        self.router.add_route("/user/memberships", {}, ResourceWithId(8))
        self.router.add_route("/emojis", {}, ResourceWithId(9))
        self.router.add_route(
            "/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/full", {}, ResourceWithId(10)
        )
        self.router.add_route("/repos/{org}/{repo}/compare/all", {}, ResourceWithId(11))

        # NOTE(kgriffs): The ordering of these calls is significant; we
        # need to test that the {id} field does not match the other routes,
        # regardless of the order they are added.
        self.router.add_route("/emojis/signs/0", {}, ResourceWithId(12))
        self.router.add_route("/emojis/signs/{id}", {}, ResourceWithId(13))
        self.router.add_route("/emojis/signs/42", {}, ResourceWithId(14))
        self.router.add_route("/emojis/signs/42/small", {}, ResourceWithId(14.1))
        self.router.add_route("/emojis/signs/78/small", {}, ResourceWithId(22))

        self.router.add_route(
            "/repos/{org}/{repo}/compare/{usr0}:{branch0}...{usr1}:{branch1}/part", {}, ResourceWithId(15)
        )
        self.router.add_route("/repos/{org}/{repo}/compare/{usr0}:{branch0}", {}, ResourceWithId(16))
        self.router.add_route("/repos/{org}/{repo}/compare/{usr0}:{branch0}/full", {}, ResourceWithId(17))

        self.router.add_route("/gists/{id}/{representation}", {}, ResourceWithId(21))
        self.router.add_route("/gists/{id}/raw", {}, ResourceWithId(18))
        self.router.add_route("/gists/first", {}, ResourceWithId(20))

    @ddt.data(
        "/teams/{collision}",  # simple vs simple
        "/emojis/signs/{id_too}",  # another simple vs simple
        "/repos/{org}/{repo}/compare/{complex}:{vs}...{complex2}:{collision}",
    )
    def test_collision(self, template):
        self.assertRaises(ValueError, self.router.add_route, template, {}, ResourceWithId(-1))

    @ddt.data(
        "/repos/{org}/{repo}/compare/{simple-vs-complex}",
        "/repos/{complex}.{vs}.{simple}",
        "/repos/{org}/{repo}/compare/{complex}:{vs}...{complex2}/full",
    )
    def test_non_collision(self, template):
        self.router.add_route(template, {}, ResourceWithId(-1))

    def test_dump(self):
        print(self.router._src)

    def test_override(self):
        self.router.add_route("/emojis/signs/0", {}, ResourceWithId(-1))

        resource, method_map, params = self.router.find("/emojis/signs/0")
        self.assertEqual(resource.resource_id, -1)

    def test_literal_segment(self):
        resource, method_map, params = self.router.find("/emojis/signs/0")
        self.assertEqual(resource.resource_id, 12)

        resource, method_map, params = self.router.find("/emojis/signs/1")
        self.assertEqual(resource.resource_id, 13)

        resource, method_map, params = self.router.find("/emojis/signs/42")
        self.assertEqual(resource.resource_id, 14)

        resource, method_map, params = self.router.find("/emojis/signs/42/small")
        self.assertEqual(resource.resource_id, 14.1)

        route = self.router.find("/emojis/signs/1/small")
        self.assertEqual(route, None)

    @ddt.data("/teams", "/emojis/signs", "/gists", "/gists/42")
    def test_dead_segment(self, template):
        route = self.router.find(template)
        self.assertIs(route, None)

    def test_malformed_pattern(self):
        route = self.router.find("/repos/racker/falcon/compare/foo")
        self.assertIs(route, None)

        route = self.router.find("/repos/racker/falcon/compare/foo/full")
        self.assertIs(route, None)

    def test_literal(self):
        resource, method_map, params = self.router.find("/user/memberships")
        self.assertEqual(resource.resource_id, 8)

    def test_variable(self):
        resource, method_map, params = self.router.find("/teams/42")
        self.assertEqual(resource.resource_id, 6)
        self.assertEqual(params, {"id": "42"})

        resource, method_map, params = self.router.find("/emojis/signs/stop")
        self.assertEqual(params, {"id": "stop"})

        resource, method_map, params = self.router.find("/gists/42/raw")
        self.assertEqual(params, {"id": "42"})

    @ddt.data(
        ("/teams/default", 19),
        ("/teams/default/members", 7),
        ("/teams/foo", 6),
        ("/teams/foo/members", 7),
        ("/gists/first", 20),
        ("/gists/first/raw", 18),
        ("/gists/first/pdf", 21),
        ("/gists/1776/pdf", 21),
        ("/emojis/signs/78", 13),
        ("/emojis/signs/78/small", 22),
    )
    @ddt.unpack
    def test_literal_vs_variable(self, path, expected_id):
        resource, method_map, params = self.router.find(path)
        self.assertEqual(resource.resource_id, expected_id)

    @ddt.data(
        # Misc.
        "/this/does/not/exist",
        "/user/bogus",
        "/repos/racker/falcon/compare/johndoe:master...janedoe:dev/bogus",
        # Literal vs variable (teams)
        "/teams",
        "/teams/42/members/undefined",
        "/teams/42/undefined",
        "/teams/42/undefined/segments",
        "/teams/default/members/undefined",
        "/teams/default/members/thing/undefined",
        "/teams/default/members/thing/undefined/segments",
        "/teams/default/undefined",
        "/teams/default/undefined/segments",
        # Literal vs variable (emojis)
        "/emojis/signs",
        "/emojis/signs/0/small",
        "/emojis/signs/0/undefined",
        "/emojis/signs/0/undefined/segments",
        "/emojis/signs/20/small",
        "/emojis/signs/20/undefined",
        "/emojis/signs/42/undefined",
        "/emojis/signs/78/undefined",
    )
    def test_not_found(self, path):
        route = self.router.find(path)
        self.assertIs(route, None)

    def test_subsegment_not_found(self):
        route = self.router.find("/emojis/signs/0/x")
        self.assertIs(route, None)

    def test_multivar(self):
        resource, method_map, params = self.router.find("/repos/racker/falcon/commits")
        self.assertEqual(resource.resource_id, 4)
        self.assertEqual(params, {"org": "racker", "repo": "falcon"})

        resource, method_map, params = self.router.find("/repos/racker/falcon/compare/all")
        self.assertEqual(resource.resource_id, 11)
        self.assertEqual(params, {"org": "racker", "repo": "falcon"})

    @ddt.data(("", 5), ("/full", 10), ("/part", 15))
    @ddt.unpack
    def test_complex(self, url_postfix, resource_id):
        uri = "/repos/racker/falcon/compare/johndoe:master...janedoe:dev"
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(
            params,
            {
                "org": "racker",
                "repo": "falcon",
                "usr0": "johndoe",
                "branch0": "master",
                "usr1": "janedoe",
                "branch1": "dev",
            },
        )

    @ddt.data(("", 16), ("/full", 17))
    @ddt.unpack
    def test_complex_alt(self, url_postfix, resource_id):
        uri = "/repos/falconry/falcon/compare/johndoe:master"
        resource, method_map, params = self.router.find(uri + url_postfix)

        self.assertEqual(resource.resource_id, resource_id)
        self.assertEqual(params, {"org": "falconry", "repo": "falcon", "usr0": "johndoe", "branch0": "master"})