Rewriting the argument mapping to handle keyword arguments, stop dropping unused URL parts, and prevent GET/POST params from overriding URL parts

This commit is contained in:
Yoann Roman
2011-01-12 17:01:32 -05:00
parent 1decad3c3d
commit d2a80823e8
2 changed files with 350 additions and 165 deletions

View File

@@ -98,7 +98,321 @@ class TestBase(object):
r = app.get('/100/name')
assert r.status_int == 200
assert r.body == '/100/name'
def test_controller_args(self):
class RootController(object):
@expose()
def index(self, id):
return 'index: %s' % id
@expose()
def multiple(self, one, two):
return 'multiple: %s, %s' % (one, two)
@expose()
def optional(self, id=None):
return 'optional: %s' % str(id)
@expose()
def variable_args(self, *args):
return 'variable_args: %s' % ', '.join(args)
@expose()
def variable_kwargs(self, **kwargs):
data = ['%s=%s' % (key, kwargs[key]) for key in sorted(kwargs.keys())]
return 'variable_kwargs: %s' % ', '.join(data)
@expose()
def variable_all(self, *args, **kwargs):
data = ['%s=%s' % (key, kwargs[key]) for key in sorted(kwargs.keys())]
return 'variable_all: %s' % ', '.join(list(args) + data)
@expose()
def eater(self, id, dummy=None, *args, **kwargs):
data = ['%s=%s' % (key, kwargs[key]) for key in sorted(kwargs.keys())]
return 'eater: %s, %s, %s' % (id, dummy, ', '.join(list(args) + data))
@expose()
def _route(self, args):
if hasattr(self, args[0]):
return getattr(self, args[0]), args[1:]
else:
return self.index, args
app = TestApp(Pecan(RootController()))
# required arg
try:
r = app.get('/')
assert r.status_int != 200
except Exception, ex:
assert type(ex) == TypeError
assert ex.args[0] == 'index() takes exactly 2 arguments (1 given)'
r = app.get('/1')
assert r.status_int == 200
assert r.body == 'index: 1'
r = app.get('/1/dummy', status=404)
assert r.status_int == 404
r = app.get('/?id=2')
assert r.status_int == 200
assert r.body == 'index: 2'
r = app.get('/3?id=three')
assert r.status_int == 200
assert r.body == 'index: 3'
r = app.post('/', {'id': '4'})
assert r.status_int == 200
assert r.body == 'index: 4'
r = app.post('/4', {'id': 'four'})
assert r.status_int == 200
assert r.body == 'index: 4'
r = app.get('/?id=5&dummy=dummy')
assert r.status_int == 200
assert r.body == 'index: 5'
r = app.post('/', {'id': '6', 'dummy': 'dummy'})
assert r.status_int == 200
assert r.body == 'index: 6'
# multiple args
r = app.get('/multiple/one/two')
assert r.status_int == 200
assert r.body == 'multiple: one, two'
r = app.get('/multiple?one=three&two=four')
assert r.status_int == 200
assert r.body == 'multiple: three, four'
r = app.post('/multiple', {'one': 'five', 'two': 'six'})
assert r.status_int == 200
assert r.body == 'multiple: five, six'
# optional arg
r = app.get('/optional')
assert r.status_int == 200
assert r.body == 'optional: None'
r = app.get('/optional/1')
assert r.status_int == 200
assert r.body == 'optional: 1'
r = app.get('/optional/2/dummy', status=404)
assert r.status_int == 404
r = app.get('/optional?id=2')
assert r.status_int == 200
assert r.body == 'optional: 2'
r = app.get('/optional/3?id=three')
assert r.status_int == 200
assert r.body == 'optional: 3'
r = app.post('/optional', {'id': '4'})
assert r.status_int == 200
assert r.body == 'optional: 4'
r = app.post('/optional/5', {'id': 'five'})
assert r.status_int == 200
assert r.body == 'optional: 5'
r = app.get('/optional?id=6&dummy=dummy')
assert r.status_int == 200
assert r.body == 'optional: 6'
r = app.post('/optional', {'id': '7', 'dummy': 'dummy'})
assert r.status_int == 200
assert r.body == 'optional: 7'
# variable args
r = app.get('/variable_args')
assert r.status_int == 200
assert r.body == 'variable_args: '
r = app.get('/variable_args/1/dummy')
assert r.status_int == 200
assert r.body == 'variable_args: 1, dummy'
r = app.get('/variable_args?id=2&dummy=dummy')
assert r.status_int == 200
assert r.body == 'variable_args: '
r = app.post('/variable_args', {'id': '3', 'dummy': 'dummy'})
assert r.status_int == 200
assert r.body == 'variable_args: '
# variable keyword args
r = app.get('/variable_kwargs')
assert r.status_int == 200
assert r.body == 'variable_kwargs: '
r = app.get('/variable_kwargs/1/dummy', status=404)
assert r.status_int == 404
r = app.get('/variable_kwargs?id=2&dummy=dummy')
assert r.status_int == 200
assert r.body == 'variable_kwargs: dummy=dummy, id=2'
r = app.post('/variable_kwargs', {'id': '3', 'dummy': 'dummy'})
assert r.status_int == 200
assert r.body == 'variable_kwargs: dummy=dummy, id=3'
# variable args & keyword args
r = app.get('/variable_all')
assert r.status_int == 200
assert r.body == 'variable_all: '
r = app.get('/variable_all/1')
assert r.status_int == 200
assert r.body == 'variable_all: 1'
r = app.get('/variable_all/2/dummy')
assert r.status_int == 200
assert r.body == 'variable_all: 2, dummy'
r = app.get('/variable_all/3?month=1&day=12')
assert r.status_int == 200
assert r.body == 'variable_all: 3, day=12, month=1'
r = app.get('/variable_all/4?id=four&month=1&day=12')
assert r.status_int == 200
assert r.body == 'variable_all: 4, day=12, id=four, month=1'
r = app.post('/variable_all/5/dummy')
assert r.status_int == 200
assert r.body == 'variable_all: 5, dummy'
r = app.post('/variable_all/6', {'month': '1', 'day': '12'})
assert r.status_int == 200
assert r.body == 'variable_all: 6, day=12, month=1'
r = app.post('/variable_all/7', {'id': 'seven', 'month': '1', 'day': '12'})
assert r.status_int == 200
assert r.body == 'variable_all: 7, day=12, id=seven, month=1'
# the "everything" controller
try:
r = app.get('/eater')
assert r.status_int != 200
except Exception, ex:
assert type(ex) == TypeError
assert ex.args[0] == 'eater() takes at least 2 arguments (1 given)'
r = app.get('/eater/1')
assert r.status_int == 200
assert r.body == 'eater: 1, None, '
r = app.get('/eater/2/dummy')
assert r.status_int == 200
assert r.body == 'eater: 2, dummy, '
r = app.get('/eater/3/dummy/foo/bar')
assert r.status_int == 200
assert r.body == 'eater: 3, dummy, foo, bar'
r = app.get('/eater/4?month=1&day=12')
assert r.status_int == 200
assert r.body == 'eater: 4, None, day=12, month=1'
r = app.get('/eater/5?id=five&month=1&day=12&dummy=dummy')
assert r.status_int == 200
assert r.body == 'eater: 5, dummy, day=12, month=1'
r = app.post('/eater/6')
assert r.status_int == 200
assert r.body == 'eater: 6, None, '
r = app.post('/eater/7/dummy')
assert r.status_int == 200
assert r.body == 'eater: 7, dummy, '
r = app.post('/eater/8/dummy/foo/bar')
assert r.status_int == 200
assert r.body == 'eater: 8, dummy, foo, bar'
r = app.post('/eater/9', {'month': '1', 'day': '12'})
assert r.status_int == 200
assert r.body == 'eater: 9, None, day=12, month=1'
r = app.post('/eater/10', {'id': 'ten', 'month': '1', 'day': '12', 'dummy': 'dummy'})
assert r.status_int == 200
assert r.body == 'eater: 10, dummy, day=12, month=1'
def test_abort(self):
class RootController(object):
@expose()
def index(self):
abort(404)
app = TestApp(Pecan(RootController()))
r = app.get('/', status=404)
assert r.status_int == 404
def test_redirect(self):
class RootController(object):
@expose()
def index(self):
redirect('/testing')
@expose()
def permanent(self):
redirect('/testing', code=301)
@expose()
def testing(self):
return 'it worked!'
app = TestApp(Pecan(RootController()))
r = app.get('/')
assert r.status_int == 302
r = r.follow()
assert r.status_int == 200
assert r.body == 'it worked!'
r = app.get('/permanent')
assert r.status_int == 301
r = r.follow()
assert r.status_int == 200
assert r.body == 'it worked!'
def test_streaming_response(self):
import StringIO
class RootController(object):
@expose(content_type='text/plain')
def test(self, foo):
if foo == 'stream':
# mimic large file
contents = StringIO.StringIO('stream')
response.content_type='application/octet-stream'
contents.seek(0, os.SEEK_END)
response.content_length = contents.tell()
contents.seek(0, os.SEEK_SET)
response.app_iter = contents
return response
else:
return 'plain text'
app = TestApp(Pecan(RootController()))
r = app.get('/test/stream')
assert r.content_type == 'application/octet-stream'
assert r.body == 'stream'
r = app.get('/test/plain')
assert r.content_type == 'text/plain'
assert r.body == 'plain text'
def test_request_state_cleanup(self):
"""
After a request, the state local() should be totally clean
@@ -193,140 +507,3 @@ class TestEngines(object):
assert r.status_int == 200
result = dict(loads(r.body))
assert result == expected_result
def test_controller_parameters(self):
class RootController(object):
@expose('json')
def index(self, argument=None):
assert argument == 'value'
return dict()
# arguments should get passed appropriately
app = TestApp(Pecan(RootController()))
r = app.get('/?argument=value')
assert r.status_int == 200
# extra arguments get stripped off
r = app.get('/?argument=value&extra=not')
assert r.status_int == 200
def test_abort(self):
class RootController(object):
@expose()
def index(self):
abort(404)
app = TestApp(Pecan(RootController()))
r = app.get('/', status=404)
assert r.status_int == 404
def test_redirect(self):
class RootController(object):
@expose()
def index(self):
redirect('/testing')
@expose()
def permanent(self):
redirect('/testing', code=301)
@expose()
def testing(self):
return 'it worked!'
app = TestApp(Pecan(RootController()))
r = app.get('/')
assert r.status_int == 302
r = r.follow()
assert r.status_int == 200
assert r.body == 'it worked!'
r = app.get('/permanent')
assert r.status_int == 301
r = r.follow()
assert r.status_int == 200
assert r.body == 'it worked!'
def test_uri_to_parameter_mapping(self):
class RootController(object):
@expose()
def test(self, one, two):
assert one == '1'
assert two == '2'
return 'it worked'
app = TestApp(Pecan(RootController()))
r = app.get('/test/1/2')
assert r.status_int == 200
assert r.body == 'it worked'
def test_uri_to_parameter_mapping_with_validation(self):
class TestSchema(Schema):
one = validators.Int(not_empty=True)
two = validators.Int(not_empty=True)
class RootController(object):
@expose(schema=TestSchema())
def test(self, one, two):
assert request.validation_error is None
assert one == 1
assert two == 2
return 'it worked'
@expose(schema=TestSchema())
def fail(self, one, two):
assert request.validation_error is not None
assert one == 'one'
assert two == 'two'
return 'it failed'
app = TestApp(Pecan(RootController()))
r = app.get('/test/1/2')
assert r.status_int == 200
assert r.body == 'it worked'
r = app.get('/fail/one/two')
assert r.status_int == 200
assert r.body == 'it failed'
def test_uri_to_parameter_mapping_with_varargs(self):
class RootController(object):
@expose()
def test(self, *args):
assert len(args) == 4
assert args[0] == '1'
assert args[1] == '2'
assert args[2] == '3'
assert args[3] == '4'
return 'it worked'
app = TestApp(Pecan(RootController()))
r = app.get('/test/1/2/3/4')
assert r.status_int == 200
assert r.body == 'it worked'
def test_streaming_response(self):
import StringIO
class RootController(object):
@expose(content_type='text/plain')
def test(self, foo):
if foo == 'stream':
# mimic large file
contents = StringIO.StringIO('stream')
response.content_type='application/octet-stream'
contents.seek(0, os.SEEK_END)
response.content_length = contents.tell()
contents.seek(0, os.SEEK_SET)
response.app_iter = contents
return response
else:
return 'plain text'
app = TestApp(Pecan(RootController()))
r = app.get('/test/stream/')
assert r.content_type == 'application/octet-stream'
assert r.body == 'stream'
r = app.get('/test/plain/')
assert r.content_type == 'text/plain'
assert r.body == 'plain text'