Files
deb-python-pecan/pecan/tests/test_validation.py
Jonathan LaCour bed5cbfa14 After a full-scale scan with pep8.py and pyflakes, identified and
resolved most of our PEP8 compliance issues.
2012-03-11 09:52:25 -07:00

886 lines
29 KiB
Python

from formencode import ForEach, Schema, validators
from webtest import TestApp
from unittest import TestCase
import os.path
from pecan import make_app, expose, request, ValidationException
from pecan.templating import _builtin_renderers as builtin_renderers
try:
from simplejson import dumps
except ImportError:
from json import dumps # noqa
class TestValidation(TestCase):
template_path = os.path.join(os.path.dirname(__file__), 'templates')
def test_simple_validation(self):
class RegistrationSchema(Schema):
first_name = validators.String(not_empty=True)
last_name = validators.String(not_empty=True)
email = validators.Email()
username = validators.PlainText()
password = validators.String()
password_confirm = validators.String()
age = validators.Int()
chained_validators = [
validators.FieldsMatch('password', 'password_confirm')
]
class RootController(object):
@expose(schema=RegistrationSchema())
def index(self, first_name,
last_name,
email,
username,
password,
password_confirm,
age):
assert isinstance(last_name, unicode)
assert isinstance(first_name, unicode)
assert age == 31
assert isinstance(age, int)
return 'Success!'
@expose(json_schema=RegistrationSchema())
def json(self, data):
assert data['age'] == 31
assert isinstance(data['age'], int)
return 'Success!'
# test form submissions
app = TestApp(make_app(RootController()))
r = app.post('/', dict(
first_name='Jonathan',
last_name='LaCour',
email='jonathan@cleverdevil.org',
username='jlacour',
password='123456',
password_confirm='123456',
age='31'
))
assert r.status_int == 200
assert r.body == 'Success!'
# test JSON submissions
r = app.post('/json', dumps(dict(
first_name='Jonathan',
last_name='LaCour',
email='jonathan@cleverdevil.org',
username='jlacour',
password='123456',
password_confirm='123456',
age='31'
)), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Success!'
def test_validation_with_none_type(self):
"""
formencode schemas can be configured to return NoneType in some
circumstances. We use the output of formencode's validate() to
determine wildcard arguments, so we should protect ourselves
from this scenario.
"""
class RegistrationSchema(Schema):
if_empty = None
first_name = validators.String(not_empty=True)
last_name = validators.String(not_empty=True)
class RootController(object):
@expose(schema=RegistrationSchema())
def index(self, **kw):
assert 'first_name' not in kw
assert 'last_name' not in kw
return 'Success!'
# test form submissions
app = TestApp(make_app(RootController()))
r = app.post('/', dict())
assert r.status_int == 200
assert r.body == 'Success!'
def test_simple_failure(self):
class RegistrationSchema(Schema):
first_name = validators.String(not_empty=True)
last_name = validators.String(not_empty=True)
email = validators.Email()
username = validators.PlainText()
password = validators.String()
password_confirm = validators.String()
age = validators.Int()
chained_validators = [
validators.FieldsMatch('password', 'password_confirm')
]
class RootController(object):
@expose()
def errors(self, *args, **kwargs):
assert len(request.pecan['validation_errors']) > 0
return 'There was an error!'
@expose(schema=RegistrationSchema())
def index(self, first_name,
last_name,
email,
username,
password,
password_confirm,
age):
assert len(request.pecan['validation_errors']) > 0
return 'Success!'
@expose(schema=RegistrationSchema(), error_handler='/errors')
def with_handler(self, first_name,
last_name,
email,
username,
password,
password_confirm,
age):
assert len(request.pecan['validation_errors']) > 0
return 'Success!'
@expose(json_schema=RegistrationSchema())
def json(self, data):
assert len(request.pecan['validation_errors']) > 0
return 'Success!'
@expose(json_schema=RegistrationSchema(), error_handler='/errors')
def json_with_handler(self, data):
assert len(request.pecan['validation_errors']) > 0
return 'Success!'
# test without error handler
app = TestApp(make_app(RootController()))
r = app.post('/', dict(
first_name='Jonathan',
last_name='LaCour',
email='jonathan@cleverdevil.org',
username='jlacour',
password='123456',
password_confirm='654321',
age='31'
))
assert r.status_int == 200
assert r.body == 'Success!'
# test with error handler
r = app.post('/with_handler', dict(
first_name='Jonathan',
last_name='LaCour',
email='jonathan@cleverdevil.org',
username='jlacour',
password='123456',
password_confirm='654321',
age='31'
))
assert r.status_int == 200
assert r.body == 'There was an error!'
# test JSON without error handler
r = app.post('/json', dumps(dict(
first_name='Jonathan',
last_name='LaCour',
email='jonathan@cleverdevil.org',
username='jlacour',
password='123456',
password_confirm='654321',
age='31'
)), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Success!'
# test JSON with error handler
r = app.post('/json_with_handler', dumps(dict(
first_name='Jonathan',
last_name='LaCour',
email='jonathan@cleverdevil.org',
username='jlacour',
password='123456',
password_confirm='654321',
age='31'
)), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'There was an error!'
def test_with_variable_decode(self):
class ColorSchema(Schema):
colors = ForEach(validators.String(not_empty=True))
class RootController(object):
@expose()
def errors(self, *args, **kwargs):
errs = ', '.join(request.pecan['validation_errors'].keys())
return 'Error with %s!' % errs
@expose(schema=ColorSchema(),
variable_decode=True)
def index(self, **kwargs):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(schema=ColorSchema(),
error_handler='/errors',
variable_decode=True)
def with_handler(self, **kwargs):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(json_schema=ColorSchema(),
variable_decode=True)
def json(self, data):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(json_schema=ColorSchema(),
error_handler='/errors',
variable_decode=True)
def json_with_handler(self, data):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(schema=ColorSchema(),
variable_decode=dict())
def custom(self, **kwargs):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(schema=ColorSchema(),
error_handler='/errors',
variable_decode=dict())
def custom_with_handler(self, **kwargs):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(json_schema=ColorSchema(),
variable_decode=dict())
def custom_json(self, data):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(json_schema=ColorSchema(),
error_handler='/errors',
variable_decode=dict())
def custom_json_with_handler(self, data):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(schema=ColorSchema(),
variable_decode=dict(dict_char='-', list_char='.'))
def alternate(self, **kwargs):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(schema=ColorSchema(),
error_handler='/errors',
variable_decode=dict(dict_char='-', list_char='.'))
def alternate_with_handler(self, **kwargs):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(json_schema=ColorSchema(),
variable_decode=dict(dict_char='-', list_char='.'))
def alternate_json(self, data):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
@expose(json_schema=ColorSchema(),
error_handler='/errors',
variable_decode=dict(dict_char='-', list_char='.'))
def alternate_json_with_handler(self, data):
if request.pecan['validation_errors']:
return ', '.join(request.pecan['validation_errors'].keys())
else:
return 'Success!'
# test without error handler
app = TestApp(make_app(RootController()))
r = app.post('/', {
'colors-0': 'blue',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == 'Success!'
# test failure without error handler
r = app.post('/', {
'colors-0': 'blue',
'colors-1': ''
})
assert r.status_int == 200
assert r.body == 'colors-1'
# test with error handler
r = app.post('/with_handler', {
'colors-0': 'blue',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == 'Success!'
# test failure with error handler
r = app.post('/with_handler', {
'colors-0': '',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == 'Error with colors-0!'
# test JSON without error handler
r = app.post('/json', dumps({
'colors-0': 'blue',
'colors-1': 'red'
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Success!'
# test JSON failure without error handler
r = app.post('/json', dumps({
'colors-0': 'blue',
'colors-1': ''
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'colors-1'
# test JSON with error handler
r = app.post('/json_with_handler', dumps({
'colors-0': 'blue',
'colors-1': 'red'
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Success!'
# test JSON failure with error handler
r = app.post('/json_with_handler', dumps({
'colors-0': '',
'colors-1': 'red'
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Error with colors-0!'
# test custom without error handler
r = app.post('/custom', {
'colors-0': 'blue',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == 'Success!'
# test custom failure without error handler
r = app.post('/custom', {
'colors-0': 'blue',
'colors-1': ''
})
assert r.status_int == 200
assert r.body == 'colors-1'
# test custom with error handler
r = app.post('/custom_with_handler', {
'colors-0': 'blue',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == 'Success!'
# test custom failure with error handler
r = app.post('/custom_with_handler', {
'colors-0': '',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == 'Error with colors-0!'
# test custom JSON without error handler
r = app.post('/custom_json', dumps({
'colors-0': 'blue',
'colors-1': 'red'
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Success!'
# test custom JSON failure without error handler
r = app.post('/custom_json', dumps({
'colors-0': 'blue',
'colors-1': ''
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'colors-1'
# test custom JSON with error handler
r = app.post('/custom_json_with_handler', dumps({
'colors-0': 'blue',
'colors-1': 'red'
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Success!'
# test custom JSON failure with error handler
r = app.post('/custom_json_with_handler', dumps({
'colors-0': '',
'colors-1': 'red'
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Error with colors-0!'
# test alternate without error handler
r = app.post('/alternate', {
'colors.0': 'blue',
'colors.1': 'red'
})
assert r.status_int == 200
assert r.body == 'Success!'
# test alternate failure without error handler
r = app.post('/alternate', {
'colors.0': 'blue',
'colors.1': ''
})
assert r.status_int == 200
assert r.body == 'colors.1'
# test alternate with error handler
r = app.post('/alternate_with_handler', {
'colors.0': 'blue',
'colors.1': 'red'
})
assert r.status_int == 200
assert r.body == 'Success!'
# test alternate failure with error handler
r = app.post('/alternate_with_handler', {
'colors.0': '',
'colors.1': 'red'
})
assert r.status_int == 200
assert r.body == 'Error with colors.0!'
# test alternate JSON without error handler
r = app.post('/alternate_json', dumps({
'colors.0': 'blue',
'colors.1': 'red'
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Success!'
# test alternate JSON failure without error handler
r = app.post('/alternate_json', dumps({
'colors.0': 'blue',
'colors.1': ''
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'colors.1'
# test alternate JSON with error handler
r = app.post('/alternate_json_with_handler', dumps({
'colors.0': 'blue',
'colors.1': 'red'
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Success!'
# test alternate JSON failure with error handler
r = app.post('/alternate_json_with_handler', dumps({
'colors.0': '',
'colors.1': 'red'
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Error with colors.0!'
def test_htmlfill(self):
if 'mako' not in builtin_renderers:
return
class ColorSchema(Schema):
colors = ForEach(validators.String(not_empty=True))
class NameSchema(Schema):
name = validators.String(not_empty=True)
class RootController(object):
@expose(template='mako:form_colors.html',
schema=ColorSchema(),
variable_decode=True)
def index(self, **kwargs):
if request.pecan['validation_errors']:
return dict()
else:
return dict(data=kwargs)
@expose(schema=ColorSchema(),
error_handler='/errors_with_handler',
variable_decode=True)
def with_handler(self, **kwargs):
return ', '.join(kwargs['colors'])
@expose('mako:form_colors.html')
def errors_with_handler(self):
return dict()
@expose(template='mako:form_name.html',
schema=NameSchema(),
htmlfill=dict(auto_insert_errors=True))
def with_errors(self, **kwargs):
return kwargs
@expose(schema=NameSchema(),
error_handler='/errors_with_handler_and_errors',
htmlfill=dict(auto_insert_errors=True))
def with_handler_and_errors(self, **kwargs):
return kwargs['name']
@expose('mako:form_name.html')
def errors_with_handler_and_errors(self):
return dict()
@expose(template='json',
schema=NameSchema(),
htmlfill=dict(auto_insert_errors=True))
def json(self, **kwargs):
if request.pecan['validation_errors']:
return dict(
error_with=request.pecan['validation_errors'].keys()
)
else:
return kwargs
def _get_contents(filename):
return open(os.path.join(self.template_path, filename), 'r').read()
# test without error handler
app = TestApp(
make_app(RootController(), template_path=self.template_path)
)
r = app.post('/', {
'colors-0': 'blue',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == _get_contents('form_colors_valid.html')
# test failure without error handler
r = app.post('/', {
'colors-0': 'blue',
'colors-1': ''
})
assert r.status_int == 200
assert r.body == _get_contents('form_colors_invalid.html')
# test with error handler
r = app.post('/with_handler', {
'colors-0': 'blue',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == 'blue, red'
# test failure with error handler
r = app.post('/with_handler', {
'colors-0': 'blue',
'colors-1': ''
})
assert r.status_int == 200
assert r.body == _get_contents('form_colors_invalid.html')
# test with errors
r = app.post('/with_errors', {
'name': 'Yoann'
})
assert r.status_int == 200
assert r.body == _get_contents('form_name_valid.html')
# test failure with errors
r = app.post('/with_errors', {
'name': ''
})
assert r.status_int == 200
assert r.body == _get_contents('form_name_invalid.html')
# test with error handler and errors
r = app.post('/with_handler_and_errors', {
'name': 'Yoann'
})
assert r.status_int == 200
assert r.body == 'Yoann'
# test failure with error handler and errors
r = app.post('/with_handler_and_errors', {
'name': ''
})
assert r.status_int == 200
assert r.body == _get_contents('form_name_invalid.html')
# test JSON
r = app.post('/json', {
'name': 'Yoann'
})
assert r.status_int == 200
assert r.body == dumps(dict(name='Yoann'))
# test JSON failure
r = app.post('/json', {
'name': ''
})
assert r.status_int == 200
assert r.body == dumps(dict(error_with=['name']))
def test_htmlfill_static(self):
if 'mako' not in builtin_renderers:
return
class LoginSchema(Schema):
username = validators.String(not_empty=True)
password = validators.String(not_empty=True)
class RootController(object):
@expose(template='mako:form_login.html',
schema=LoginSchema())
def index(self, **kwargs):
if request.pecan['validation_errors']:
return dict()
else:
return dict(data=kwargs)
@expose(schema=LoginSchema(),
error_handler='/errors_with_handler')
def with_handler(self, **kwargs):
return '%s:%s' % (kwargs['username'], kwargs['password'])
@expose('mako:form_login.html')
def errors_with_handler(self):
return dict()
def _get_contents(filename):
return open(os.path.join(self.template_path, filename), 'r').read()
# test without error handler
app = TestApp(
make_app(RootController(), template_path=self.template_path)
)
r = app.post('/', {
'username': 'ryan',
'password': 'password'
})
assert r.status_int == 200
assert r.body == _get_contents('form_login_valid.html')
# test failure without error handler
r = app.post('/', {
'username': 'ryan',
'password': ''
})
assert r.status_int == 200
assert r.body == _get_contents('form_login_invalid.html')
# test with error handler
r = app.post('/with_handler', {
'username': 'ryan',
'password': 'password'
})
assert r.status_int == 200
assert r.body == 'ryan:password'
# test failure with error handler
r = app.post('/with_handler', {
'username': 'ryan',
'password': ''
})
assert r.status_int == 200
assert r.body == _get_contents('form_login_invalid.html')
def test_error_for(self):
if 'mako' not in builtin_renderers:
return
class ColorSchema(Schema):
colors = ForEach(validators.String(not_empty=True))
class RootController(object):
@expose(template='mako:error_for.html')
def errors(self, *args, **kwargs):
return dict()
@expose(template='mako:error_for.html',
schema=ColorSchema(),
variable_decode=True)
def index(self, **kwargs):
return dict()
@expose(schema=ColorSchema(),
error_handler='/errors',
variable_decode=True)
def with_handler(self, **kwargs):
return dict()
@expose(template='mako:error_for.html',
json_schema=ColorSchema(),
variable_decode=True)
def json(self, data):
return dict()
@expose(json_schema=ColorSchema(),
error_handler='/errors',
variable_decode=True)
def json_with_handler(self, data):
return dict()
# test without error handler
app = TestApp(
make_app(RootController(), template_path=self.template_path)
)
r = app.post('/', {
'colors-0': 'blue',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == ''
# test failure without error handler
r = app.post('/', {
'colors-0': 'blue',
'colors-1': ''
})
assert r.status_int == 200
assert r.body == 'Please enter a value'
# test failure with error handler
r = app.post('/with_handler', {
'colors-0': 'blue',
'colors-1': ''
})
assert r.status_int == 200
assert r.body == 'Please enter a value'
# test JSON failure without error handler
r = app.post('/json', dumps({
'colors-0': 'blue',
'colors-1': ''
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Please enter a value'
# test JSON failure with error handler
r = app.post('/json_with_handler', dumps({
'colors-0': 'blue',
'colors-1': ''
}), [('content-type', 'application/json')])
assert r.status_int == 200
assert r.body == 'Please enter a value'
def test_callable_error_handler(self):
class ColorSchema(Schema):
colors = ForEach(validators.String(not_empty=True))
class RootController(object):
@expose()
def errors(self, *args, **kwargs):
return 'There was an error!'
@expose(schema=ColorSchema(),
error_handler=lambda: '/errors',
variable_decode=True)
def index(self, **kwargs):
return 'Success!'
# test with error handler
app = TestApp(make_app(RootController()))
r = app.post('/', {
'colors-0': 'blue',
'colors-1': 'red'
})
assert r.status_int == 200
assert r.body == 'Success!'
# test with error handler
r = app.post('/', {
'colors-0': 'blue',
'colors-1': ''
})
assert r.status_int == 200
assert r.body == 'There was an error!'
def test_validation_exception(self):
if 'mako' not in builtin_renderers:
return
class NameSchema(Schema):
name = validators.String(not_empty=True)
class SubController(object):
@expose()
def _route(self, *args):
raise ValidationException('/success')
class RootController(object):
sub = SubController()
@expose('mako:form_name.html')
def errors_name(self):
return dict()
@expose(schema=NameSchema(),
error_handler='/errors_name',
htmlfill=dict(auto_insert_errors=True))
def name(self, name):
raise ValidationException(
errors={'name': 'Names must be unique'}
)
@expose()
def success(self):
return 'Success!'
def _get_contents(filename):
return open(os.path.join(self.template_path, filename), 'r').read()
# test exception with no controller
app = TestApp(
make_app(RootController(), template_path=self.template_path)
)
r = app.get('/sub')
assert r.status_int == 200
assert r.body == 'Success!'
# test exception with additional errors
r = app.post('/name', {'name': 'Yoann'})
assert r.status_int == 200
assert r.body == _get_contents('form_name_invalid_custom.html')