diff --git a/tests/test_basic.py b/tests/test_basic.py
index 3412b9ab..c66e8eac 100644
--- a/tests/test_basic.py
+++ b/tests/test_basic.py
@@ -16,1351 +16,1493 @@ import uuid
import time
import flask
import pickle
-import unittest
from datetime import datetime
from threading import Thread
-from tests import emits_module_deprecation_warning
from flask._compat import text_type
from werkzeug.exceptions import BadRequest, NotFound, Forbidden
from werkzeug.http import parse_date
from werkzeug.routing import BuildError
-class TestBasicFunctionality(object):
+def test_options_work():
+ app = flask.Flask(__name__)
- def test_options_work(self):
- app = flask.Flask(__name__)
- @app.route('/', methods=['GET', 'POST'])
- def index():
- return 'Hello World'
- rv = app.test_client().open('/', method='OPTIONS')
- assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST']
- assert rv.data == b''
+ @app.route('/', methods=['GET', 'POST'])
+ def index():
+ return 'Hello World'
+ rv = app.test_client().open('/', method='OPTIONS')
+ assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST']
+ assert rv.data == b''
- def test_options_on_multiple_rules(self):
- app = flask.Flask(__name__)
- @app.route('/', methods=['GET', 'POST'])
- def index():
- return 'Hello World'
- @app.route('/', methods=['PUT'])
- def index_put():
- return 'Aha!'
- rv = app.test_client().open('/', method='OPTIONS')
- assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']
-
- def test_options_handling_disabled(self):
- app = flask.Flask(__name__)
- def index():
- return 'Hello World!'
- index.provide_automatic_options = False
- app.route('/')(index)
- rv = app.test_client().open('/', method='OPTIONS')
- assert rv.status_code == 405
- app = flask.Flask(__name__)
- def index2():
- return 'Hello World!'
- index2.provide_automatic_options = True
- app.route('/', methods=['OPTIONS'])(index2)
- rv = app.test_client().open('/', method='OPTIONS')
- assert sorted(rv.allow) == ['OPTIONS']
-
- def test_request_dispatching(self):
- app = flask.Flask(__name__)
- @app.route('/')
- def index():
- return flask.request.method
- @app.route('/more', methods=['GET', 'POST'])
- def more():
- return flask.request.method
+def test_options_on_multiple_rules():
+ app = flask.Flask(__name__)
- c = app.test_client()
- assert c.get('/').data == b'GET'
- rv = c.post('/')
- assert rv.status_code == 405
- assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS']
- rv = c.head('/')
- assert rv.status_code == 200
- assert not rv.data # head truncates
- assert c.post('/more').data == b'POST'
- assert c.get('/more').data == b'GET'
- rv = c.delete('/more')
- assert rv.status_code == 405
- assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST']
-
- def test_disallow_string_for_allowed_methods(self):
- app = flask.Flask(__name__)
- with pytest.raises(TypeError):
- @app.route('/', methods='GET POST')
- def index():
- return "Hey"
+ @app.route('/', methods=['GET', 'POST'])
+ def index():
+ return 'Hello World'
- def test_url_mapping(self):
- app = flask.Flask(__name__)
- def index():
- return flask.request.method
- def more():
- return flask.request.method
+ @app.route('/', methods=['PUT'])
+ def index_put():
+ return 'Aha!'
+ rv = app.test_client().open('/', method='OPTIONS')
+ assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']
- app.add_url_rule('/', 'index', index)
- app.add_url_rule('/more', 'more', more, methods=['GET', 'POST'])
- c = app.test_client()
- assert c.get('/').data == b'GET'
- rv = c.post('/')
- assert rv.status_code == 405
- assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS']
- rv = c.head('/')
- assert rv.status_code == 200
- assert not rv.data # head truncates
- assert c.post('/more').data == b'POST'
- assert c.get('/more').data == b'GET'
- rv = c.delete('/more')
- assert rv.status_code == 405
- assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST']
-
- def test_werkzeug_routing(self):
- from werkzeug.routing import Submount, Rule
- app = flask.Flask(__name__)
- app.url_map.add(Submount('/foo', [
- Rule('/bar', endpoint='bar'),
- Rule('/', endpoint='index')
- ]))
- def bar():
- return 'bar'
- def index():
- return 'index'
- app.view_functions['bar'] = bar
- app.view_functions['index'] = index
+def test_options_handling_disabled():
+ app = flask.Flask(__name__)
- c = app.test_client()
- assert c.get('/foo/').data == b'index'
- assert c.get('/foo/bar').data == b'bar'
+ def index():
+ return 'Hello World!'
+ index.provide_automatic_options = False
+ app.route('/')(index)
+ rv = app.test_client().open('/', method='OPTIONS')
+ assert rv.status_code == 405
- def test_endpoint_decorator(self):
- from werkzeug.routing import Submount, Rule
- app = flask.Flask(__name__)
- app.url_map.add(Submount('/foo', [
- Rule('/bar', endpoint='bar'),
- Rule('/', endpoint='index')
- ]))
+ app = flask.Flask(__name__)
- @app.endpoint('bar')
- def bar():
- return 'bar'
+ def index2():
+ return 'Hello World!'
+ index2.provide_automatic_options = True
+ app.route('/', methods=['OPTIONS'])(index2)
+ rv = app.test_client().open('/', method='OPTIONS')
+ assert sorted(rv.allow) == ['OPTIONS']
- @app.endpoint('index')
- def index():
- return 'index'
- c = app.test_client()
- assert c.get('/foo/').data == b'index'
- assert c.get('/foo/bar').data == b'bar'
+def test_request_dispatching():
+ app = flask.Flask(__name__)
- def test_session(self):
- app = flask.Flask(__name__)
- app.secret_key = 'testkey'
- @app.route('/set', methods=['POST'])
- def set():
- flask.session['value'] = flask.request.form['value']
- return 'value set'
- @app.route('/get')
- def get():
- return flask.session['value']
+ @app.route('/')
+ def index():
+ return flask.request.method
- c = app.test_client()
- assert c.post('/set', data={'value': '42'}).data == b'value set'
- assert c.get('/get').data == b'42'
+ @app.route('/more', methods=['GET', 'POST'])
+ def more():
+ return flask.request.method
- def test_session_using_server_name(self):
- app = flask.Flask(__name__)
- app.config.update(
- SECRET_KEY='foo',
- SERVER_NAME='example.com'
- )
- @app.route('/')
- def index():
- flask.session['testing'] = 42
- return 'Hello World'
- rv = app.test_client().get('/', 'http://example.com/')
- assert 'domain=.example.com' in rv.headers['set-cookie'].lower()
- assert 'httponly' in rv.headers['set-cookie'].lower()
+ c = app.test_client()
+ assert c.get('/').data == b'GET'
+ rv = c.post('/')
+ assert rv.status_code == 405
+ assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS']
+ rv = c.head('/')
+ assert rv.status_code == 200
+ assert not rv.data # head truncates
+ assert c.post('/more').data == b'POST'
+ assert c.get('/more').data == b'GET'
+ rv = c.delete('/more')
+ assert rv.status_code == 405
+ assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST']
- def test_session_using_server_name_and_port(self):
- app = flask.Flask(__name__)
- app.config.update(
- SECRET_KEY='foo',
- SERVER_NAME='example.com:8080'
- )
- @app.route('/')
- def index():
- flask.session['testing'] = 42
- return 'Hello World'
- rv = app.test_client().get('/', 'http://example.com:8080/')
- assert 'domain=.example.com' in rv.headers['set-cookie'].lower()
- assert 'httponly' in rv.headers['set-cookie'].lower()
- def test_session_using_server_name_port_and_path(self):
- app = flask.Flask(__name__)
- app.config.update(
- SECRET_KEY='foo',
- SERVER_NAME='example.com:8080',
- APPLICATION_ROOT='/foo'
- )
- @app.route('/')
+def test_disallow_string_for_allowed_methods():
+ app = flask.Flask(__name__)
+ with pytest.raises(TypeError):
+ @app.route('/', methods='GET POST')
def index():
- flask.session['testing'] = 42
- return 'Hello World'
- rv = app.test_client().get('/', 'http://example.com:8080/foo')
- assert 'domain=example.com' in rv.headers['set-cookie'].lower()
- assert 'path=/foo' in rv.headers['set-cookie'].lower()
- assert 'httponly' in rv.headers['set-cookie'].lower()
-
- def test_session_using_application_root(self):
- class PrefixPathMiddleware(object):
- def __init__(self, app, prefix):
- self.app = app
- self.prefix = prefix
- def __call__(self, environ, start_response):
- environ['SCRIPT_NAME'] = self.prefix
- return self.app(environ, start_response)
+ return "Hey"
+
+
+def test_url_mapping():
+ app = flask.Flask(__name__)
- app = flask.Flask(__name__)
- app.wsgi_app = PrefixPathMiddleware(app.wsgi_app, '/bar')
- app.config.update(
- SECRET_KEY='foo',
- APPLICATION_ROOT='/bar'
- )
- @app.route('/')
- def index():
- flask.session['testing'] = 42
- return 'Hello World'
- rv = app.test_client().get('/', 'http://example.com:8080/')
- assert 'path=/bar' in rv.headers['set-cookie'].lower()
+ def index():
+ return flask.request.method
+
+ def more():
+ return flask.request.method
+
+ app.add_url_rule('/', 'index', index)
+ app.add_url_rule('/more', 'more', more, methods=['GET', 'POST'])
+
+ c = app.test_client()
+ assert c.get('/').data == b'GET'
+ rv = c.post('/')
+ assert rv.status_code == 405
+ assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS']
+ rv = c.head('/')
+ assert rv.status_code == 200
+ assert not rv.data # head truncates
+ assert c.post('/more').data == b'POST'
+ assert c.get('/more').data == b'GET'
+ rv = c.delete('/more')
+ assert rv.status_code == 405
+ assert sorted(rv.allow) == ['GET', 'HEAD', 'OPTIONS', 'POST']
+
+
+def test_werkzeug_routing():
+ from werkzeug.routing import Submount, Rule
+ app = flask.Flask(__name__)
+ app.url_map.add(Submount('/foo', [
+ Rule('/bar', endpoint='bar'),
+ Rule('/', endpoint='index')
+ ]))
+
+ def bar():
+ return 'bar'
+
+ def index():
+ return 'index'
+ app.view_functions['bar'] = bar
+ app.view_functions['index'] = index
+
+ c = app.test_client()
+ assert c.get('/foo/').data == b'index'
+ assert c.get('/foo/bar').data == b'bar'
+
+
+def test_endpoint_decorator():
+ from werkzeug.routing import Submount, Rule
+ app = flask.Flask(__name__)
+ app.url_map.add(Submount('/foo', [
+ Rule('/bar', endpoint='bar'),
+ Rule('/', endpoint='index')
+ ]))
+
+ @app.endpoint('bar')
+ def bar():
+ return 'bar'
+
+ @app.endpoint('index')
+ def index():
+ return 'index'
+
+ c = app.test_client()
+ assert c.get('/foo/').data == b'index'
+ assert c.get('/foo/bar').data == b'bar'
+
+
+def test_session():
+ app = flask.Flask(__name__)
+ app.secret_key = 'testkey'
+
+ @app.route('/set', methods=['POST'])
+ def set():
+ flask.session['value'] = flask.request.form['value']
+ return 'value set'
+
+ @app.route('/get')
+ def get():
+ return flask.session['value']
+
+ c = app.test_client()
+ assert c.post('/set', data={'value': '42'}).data == b'value set'
+ assert c.get('/get').data == b'42'
+
+
+def test_session_using_server_name():
+ app = flask.Flask(__name__)
+ app.config.update(
+ SECRET_KEY='foo',
+ SERVER_NAME='example.com'
+ )
+
+ @app.route('/')
+ def index():
+ flask.session['testing'] = 42
+ return 'Hello World'
+ rv = app.test_client().get('/', 'http://example.com/')
+ assert 'domain=.example.com' in rv.headers['set-cookie'].lower()
+ assert 'httponly' in rv.headers['set-cookie'].lower()
+
+
+def test_session_using_server_name_and_port():
+ app = flask.Flask(__name__)
+ app.config.update(
+ SECRET_KEY='foo',
+ SERVER_NAME='example.com:8080'
+ )
+
+ @app.route('/')
+ def index():
+ flask.session['testing'] = 42
+ return 'Hello World'
+ rv = app.test_client().get('/', 'http://example.com:8080/')
+ assert 'domain=.example.com' in rv.headers['set-cookie'].lower()
+ assert 'httponly' in rv.headers['set-cookie'].lower()
+
+
+def test_session_using_server_name_port_and_path():
+ app = flask.Flask(__name__)
+ app.config.update(
+ SECRET_KEY='foo',
+ SERVER_NAME='example.com:8080',
+ APPLICATION_ROOT='/foo'
+ )
+
+ @app.route('/')
+ def index():
+ flask.session['testing'] = 42
+ return 'Hello World'
+ rv = app.test_client().get('/', 'http://example.com:8080/foo')
+ assert 'domain=example.com' in rv.headers['set-cookie'].lower()
+ assert 'path=/foo' in rv.headers['set-cookie'].lower()
+ assert 'httponly' in rv.headers['set-cookie'].lower()
+
+
+def test_session_using_application_root():
+ class PrefixPathMiddleware(object):
+
+ def __init__(self, app, prefix):
+ self.app = app
+ self.prefix = prefix
+
+ def __call__(self, environ, start_response):
+ environ['SCRIPT_NAME'] = self.prefix
+ return self.app(environ, start_response)
+
+ app = flask.Flask(__name__)
+ app.wsgi_app = PrefixPathMiddleware(app.wsgi_app, '/bar')
+ app.config.update(
+ SECRET_KEY='foo',
+ APPLICATION_ROOT='/bar'
+ )
+
+ @app.route('/')
+ def index():
+ flask.session['testing'] = 42
+ return 'Hello World'
+ rv = app.test_client().get('/', 'http://example.com:8080/')
+ assert 'path=/bar' in rv.headers['set-cookie'].lower()
+
+
+def test_session_using_session_settings():
+ app = flask.Flask(__name__)
+ app.config.update(
+ SECRET_KEY='foo',
+ SERVER_NAME='www.example.com:8080',
+ APPLICATION_ROOT='/test',
+ SESSION_COOKIE_DOMAIN='.example.com',
+ SESSION_COOKIE_HTTPONLY=False,
+ SESSION_COOKIE_SECURE=True,
+ SESSION_COOKIE_PATH='/'
+ )
+
+ @app.route('/')
+ def index():
+ flask.session['testing'] = 42
+ return 'Hello World'
+ rv = app.test_client().get('/', 'http://www.example.com:8080/test/')
+ cookie = rv.headers['set-cookie'].lower()
+ assert 'domain=.example.com' in cookie
+ assert 'path=/' in cookie
+ assert 'secure' in cookie
+ assert 'httponly' not in cookie
+
+
+def test_missing_session():
+ app = flask.Flask(__name__)
+
+ def expect_exception(f, *args, **kwargs):
+ try:
+ f(*args, **kwargs)
+ except RuntimeError as e:
+ assert e.args and 'session is unavailable' in e.args[0]
+ else:
+ assert False, 'expected exception'
+ with app.test_request_context():
+ assert flask.session.get('missing_key') is None
+ expect_exception(flask.session.__setitem__, 'foo', 42)
+ expect_exception(flask.session.pop, 'foo')
+
+
+def test_session_expiration():
+ permanent = True
+ app = flask.Flask(__name__)
+ app.secret_key = 'testkey'
+
+ @app.route('/')
+ def index():
+ flask.session['test'] = 42
+ flask.session.permanent = permanent
+ return ''
+
+ @app.route('/test')
+ def test():
+ return text_type(flask.session.permanent)
+
+ client = app.test_client()
+ rv = client.get('/')
+ assert 'set-cookie' in rv.headers
+ match = re.search(r'\bexpires=([^;]+)(?i)', rv.headers['set-cookie'])
+ expires = parse_date(match.group())
+ expected = datetime.utcnow() + app.permanent_session_lifetime
+ assert expires.year == expected.year
+ assert expires.month == expected.month
+ assert expires.day == expected.day
+
+ rv = client.get('/test')
+ assert rv.data == b'True'
+
+ permanent = False
+ rv = app.test_client().get('/')
+ assert 'set-cookie' in rv.headers
+ match = re.search(r'\bexpires=([^;]+)', rv.headers['set-cookie'])
+ assert match is None
+
+
+def test_session_stored_last():
+ app = flask.Flask(__name__)
+ app.secret_key = 'development-key'
+ app.testing = True
+
+ @app.after_request
+ def modify_session(response):
+ flask.session['foo'] = 42
+ return response
+
+ @app.route('/')
+ def dump_session_contents():
+ return repr(flask.session.get('foo'))
+
+ c = app.test_client()
+ assert c.get('/').data == b'None'
+ assert c.get('/').data == b'42'
+
+
+def test_session_special_types():
+ app = flask.Flask(__name__)
+ app.secret_key = 'development-key'
+ app.testing = True
+ now = datetime.utcnow().replace(microsecond=0)
+ the_uuid = uuid.uuid4()
+
+ @app.after_request
+ def modify_session(response):
+ flask.session['m'] = flask.Markup('Hello!')
+ flask.session['u'] = the_uuid
+ flask.session['dt'] = now
+ flask.session['b'] = b'\xff'
+ flask.session['t'] = (1, 2, 3)
+ return response
+
+ @app.route('/')
+ def dump_session_contents():
+ return pickle.dumps(dict(flask.session))
+
+ c = app.test_client()
+ c.get('/')
+ rv = pickle.loads(c.get('/').data)
+ assert rv['m'] == flask.Markup('Hello!')
+ assert type(rv['m']) == flask.Markup
+ assert rv['dt'] == now
+ assert rv['u'] == the_uuid
+ assert rv['b'] == b'\xff'
+ assert type(rv['b']) == bytes
+ assert rv['t'] == (1, 2, 3)
+
+
+def test_session_cookie_setting():
+ app = flask.Flask(__name__)
+ app.testing = True
+ app.secret_key = 'dev key'
+ is_permanent = True
+
+ @app.route('/bump')
+ def bump():
+ rv = flask.session['foo'] = flask.session.get('foo', 0) + 1
+ flask.session.permanent = is_permanent
+ return str(rv)
+
+ @app.route('/read')
+ def read():
+ return str(flask.session.get('foo', 0))
+
+ def run_test(expect_header):
+ with app.test_client() as c:
+ assert c.get('/bump').data == b'1'
+ assert c.get('/bump').data == b'2'
+ assert c.get('/bump').data == b'3'
+
+ rv = c.get('/read')
+ set_cookie = rv.headers.get('set-cookie')
+ assert (set_cookie is not None) == expect_header
+ assert rv.data == b'3'
+
+ is_permanent = True
+ app.config['SESSION_REFRESH_EACH_REQUEST'] = True
+ run_test(expect_header=True)
+
+ is_permanent = True
+ app.config['SESSION_REFRESH_EACH_REQUEST'] = False
+ run_test(expect_header=False)
+
+ is_permanent = False
+ app.config['SESSION_REFRESH_EACH_REQUEST'] = True
+ run_test(expect_header=False)
+
+ is_permanent = False
+ app.config['SESSION_REFRESH_EACH_REQUEST'] = False
+ run_test(expect_header=False)
+
+
+def test_flashes():
+ app = flask.Flask(__name__)
+ app.secret_key = 'testkey'
+
+ with app.test_request_context():
+ assert not flask.session.modified
+ flask.flash('Zap')
+ flask.session.modified = False
+ flask.flash('Zip')
+ assert flask.session.modified
+ assert list(flask.get_flashed_messages()) == ['Zap', 'Zip']
+
+
+def test_extended_flashing():
+ # Be sure app.testing=True below, else tests can fail silently.
+ #
+ # Specifically, if app.testing is not set to True, the AssertionErrors
+ # in the view functions will cause a 500 response to the test client
+ # instead of propagating exceptions.
+
+ app = flask.Flask(__name__)
+ app.secret_key = 'testkey'
+ app.testing = True
+
+ @app.route('/')
+ def index():
+ flask.flash(u'Hello World')
+ flask.flash(u'Hello World', 'error')
+ flask.flash(flask.Markup(u'Testing'), 'warning')
+ return ''
+
+ @app.route('/test/')
+ def test():
+ messages = flask.get_flashed_messages()
+ assert list(messages) == [
+ u'Hello World',
+ u'Hello World',
+ flask.Markup(u'Testing')
+ ]
+ return ''
+
+ @app.route('/test_with_categories/')
+ def test_with_categories():
+ messages = flask.get_flashed_messages(with_categories=True)
+ assert len(messages) == 3
+ assert list(messages) == [
+ ('message', u'Hello World'),
+ ('error', u'Hello World'),
+ ('warning', flask.Markup(u'Testing'))
+ ]
+ return ''
+
+ @app.route('/test_filter/')
+ def test_filter():
+ messages = flask.get_flashed_messages(
+ category_filter=['message'], with_categories=True)
+ assert list(messages) == [('message', u'Hello World')]
+ return ''
+
+ @app.route('/test_filters/')
+ def test_filters():
+ messages = flask.get_flashed_messages(
+ category_filter=['message', 'warning'], with_categories=True)
+ assert list(messages) == [
+ ('message', u'Hello World'),
+ ('warning', flask.Markup(u'Testing'))
+ ]
+ return ''
+
+ @app.route('/test_filters_without_returning_categories/')
+ def test_filters2():
+ messages = flask.get_flashed_messages(
+ category_filter=['message', 'warning'])
+ assert len(messages) == 2
+ assert messages[0] == u'Hello World'
+ assert messages[1] == flask.Markup(u'Testing')
+ return ''
+
+ # Create new test client on each test to clean flashed messages.
+
+ c = app.test_client()
+ c.get('/')
+ c.get('/test/')
+
+ c = app.test_client()
+ c.get('/')
+ c.get('/test_with_categories/')
+
+ c = app.test_client()
+ c.get('/')
+ c.get('/test_filter/')
+
+ c = app.test_client()
+ c.get('/')
+ c.get('/test_filters/')
+
+ c = app.test_client()
+ c.get('/')
+ c.get('/test_filters_without_returning_categories/')
+
+
+def test_request_processing():
+ app = flask.Flask(__name__)
+ evts = []
+
+ @app.before_request
+ def before_request():
+ evts.append('before')
+
+ @app.after_request
+ def after_request(response):
+ response.data += b'|after'
+ evts.append('after')
+ return response
+
+ @app.route('/')
+ def index():
+ assert 'before' in evts
+ assert 'after' not in evts
+ return 'request'
+ assert 'after' not in evts
+ rv = app.test_client().get('/').data
+ assert 'after' in evts
+ assert rv == b'request|after'
+
+
+def test_after_request_processing():
+ app = flask.Flask(__name__)
+ app.testing = True
+
+ @app.route('/')
+ def index():
+ @flask.after_this_request
+ def foo(response):
+ response.headers['X-Foo'] = 'a header'
+ return response
+ return 'Test'
+ c = app.test_client()
+ resp = c.get('/')
+ assert resp.status_code == 200
+ assert resp.headers['X-Foo'] == 'a header'
+
+
+def test_teardown_request_handler():
+ called = []
+ app = flask.Flask(__name__)
+
+ @app.teardown_request
+ def teardown_request(exc):
+ called.append(True)
+ return "Ignored"
+
+ @app.route('/')
+ def root():
+ return "Response"
+ rv = app.test_client().get('/')
+ assert rv.status_code == 200
+ assert b'Response' in rv.data
+ assert len(called) == 1
+
+
+def test_teardown_request_handler_debug_mode():
+ called = []
+ app = flask.Flask(__name__)
+ app.testing = True
+
+ @app.teardown_request
+ def teardown_request(exc):
+ called.append(True)
+ return "Ignored"
+
+ @app.route('/')
+ def root():
+ return "Response"
+ rv = app.test_client().get('/')
+ assert rv.status_code == 200
+ assert b'Response' in rv.data
+ assert len(called) == 1
+
+
+def test_teardown_request_handler_error():
+ called = []
+ app = flask.Flask(__name__)
+ app.config['LOGGER_HANDLER_POLICY'] = 'never'
+
+ @app.teardown_request
+ def teardown_request1(exc):
+ assert type(exc) == ZeroDivisionError
+ called.append(True)
+ # This raises a new error and blows away sys.exc_info(), so we can
+ # test that all teardown_requests get passed the same original
+ # exception.
+ try:
+ raise TypeError()
+ except:
+ pass
- def test_session_using_session_settings(self):
- app = flask.Flask(__name__)
- app.config.update(
- SECRET_KEY='foo',
- SERVER_NAME='www.example.com:8080',
- APPLICATION_ROOT='/test',
- SESSION_COOKIE_DOMAIN='.example.com',
- SESSION_COOKIE_HTTPONLY=False,
- SESSION_COOKIE_SECURE=True,
- SESSION_COOKIE_PATH='/'
- )
- @app.route('/')
- def index():
- flask.session['testing'] = 42
- return 'Hello World'
- rv = app.test_client().get('/', 'http://www.example.com:8080/test/')
- cookie = rv.headers['set-cookie'].lower()
- assert 'domain=.example.com' in cookie
- assert 'path=/' in cookie
- assert 'secure' in cookie
- assert 'httponly' not in cookie
-
- def test_missing_session(self):
- app = flask.Flask(__name__)
- def expect_exception(f, *args, **kwargs):
- try:
- f(*args, **kwargs)
- except RuntimeError as e:
- assert e.args and 'session is unavailable' in e.args[0]
- else:
- assert False, 'expected exception'
- with app.test_request_context():
- assert flask.session.get('missing_key') is None
- expect_exception(flask.session.__setitem__, 'foo', 42)
- expect_exception(flask.session.pop, 'foo')
+ @app.teardown_request
+ def teardown_request2(exc):
+ assert type(exc) == ZeroDivisionError
+ called.append(True)
+ # This raises a new error and blows away sys.exc_info(), so we can
+ # test that all teardown_requests get passed the same original
+ # exception.
+ try:
+ raise TypeError()
+ except:
+ pass
- def test_session_expiration(self):
- permanent = True
- app = flask.Flask(__name__)
- app.secret_key = 'testkey'
- @app.route('/')
- def index():
- flask.session['test'] = 42
- flask.session.permanent = permanent
- return ''
-
- @app.route('/test')
- def test():
- return text_type(flask.session.permanent)
-
- client = app.test_client()
- rv = client.get('/')
- assert 'set-cookie' in rv.headers
- match = re.search(r'\bexpires=([^;]+)(?i)', rv.headers['set-cookie'])
- expires = parse_date(match.group())
- expected = datetime.utcnow() + app.permanent_session_lifetime
- assert expires.year == expected.year
- assert expires.month == expected.month
- assert expires.day == expected.day
-
- rv = client.get('/test')
- assert rv.data == b'True'
-
- permanent = False
- rv = app.test_client().get('/')
- assert 'set-cookie' in rv.headers
- match = re.search(r'\bexpires=([^;]+)', rv.headers['set-cookie'])
- assert match is None
-
- def test_session_stored_last(self):
- app = flask.Flask(__name__)
- app.secret_key = 'development-key'
- app.testing = True
+ @app.route('/')
+ def fails():
+ 1 // 0
+ rv = app.test_client().get('/')
+ assert rv.status_code == 500
+ assert b'Internal Server Error' in rv.data
+ assert len(called) == 2
+
+
+def test_before_after_request_order():
+ called = []
+ app = flask.Flask(__name__)
+
+ @app.before_request
+ def before1():
+ called.append(1)
+
+ @app.before_request
+ def before2():
+ called.append(2)
- @app.after_request
- def modify_session(response):
- flask.session['foo'] = 42
- return response
- @app.route('/')
- def dump_session_contents():
- return repr(flask.session.get('foo'))
+ @app.after_request
+ def after1(response):
+ called.append(4)
+ return response
- c = app.test_client()
- assert c.get('/').data == b'None'
- assert c.get('/').data == b'42'
+ @app.after_request
+ def after2(response):
+ called.append(3)
+ return response
- def test_session_special_types(self):
- app = flask.Flask(__name__)
- app.secret_key = 'development-key'
- app.testing = True
- now = datetime.utcnow().replace(microsecond=0)
- the_uuid = uuid.uuid4()
-
- @app.after_request
- def modify_session(response):
- flask.session['m'] = flask.Markup('Hello!')
- flask.session['u'] = the_uuid
- flask.session['dt'] = now
- flask.session['b'] = b'\xff'
- flask.session['t'] = (1, 2, 3)
- return response
+ @app.teardown_request
+ def finish1(exc):
+ called.append(6)
+
+ @app.teardown_request
+ def finish2(exc):
+ called.append(5)
+
+ @app.route('/')
+ def index():
+ return '42'
+ rv = app.test_client().get('/')
+ assert rv.data == b'42'
+ assert called == [1, 2, 3, 4, 5, 6]
- @app.route('/')
- def dump_session_contents():
- return pickle.dumps(dict(flask.session))
- c = app.test_client()
- c.get('/')
- rv = pickle.loads(c.get('/').data)
- assert rv['m'] == flask.Markup('Hello!')
- assert type(rv['m']) == flask.Markup
- assert rv['dt'] == now
- assert rv['u'] == the_uuid
- assert rv['b'] == b'\xff'
- assert type(rv['b']) == bytes
- assert rv['t'] == (1, 2, 3)
-
- def test_session_cookie_setting(self):
- app = flask.Flask(__name__)
- app.testing = True
- app.secret_key = 'dev key'
- is_permanent = True
-
- @app.route('/bump')
- def bump():
- rv = flask.session['foo'] = flask.session.get('foo', 0) + 1
- flask.session.permanent = is_permanent
- return str(rv)
-
- @app.route('/read')
- def read():
- return str(flask.session.get('foo', 0))
-
- def run_test(expect_header):
- with app.test_client() as c:
- assert c.get('/bump').data == b'1'
- assert c.get('/bump').data == b'2'
- assert c.get('/bump').data == b'3'
-
- rv = c.get('/read')
- set_cookie = rv.headers.get('set-cookie')
- assert (set_cookie is not None) == expect_header
- assert rv.data == b'3'
-
- is_permanent = True
- app.config['SESSION_REFRESH_EACH_REQUEST'] = True
- run_test(expect_header=True)
-
- is_permanent = True
- app.config['SESSION_REFRESH_EACH_REQUEST'] = False
- run_test(expect_header=False)
-
- is_permanent = False
- app.config['SESSION_REFRESH_EACH_REQUEST'] = True
- run_test(expect_header=False)
-
- is_permanent = False
- app.config['SESSION_REFRESH_EACH_REQUEST'] = False
- run_test(expect_header=False)
-
- def test_flashes(self):
- app = flask.Flask(__name__)
- app.secret_key = 'testkey'
+def test_error_handling():
+ app = flask.Flask(__name__)
+ app.config['LOGGER_HANDLER_POLICY'] = 'never'
+
+ @app.errorhandler(404)
+ def not_found(e):
+ return 'not found', 404
+
+ @app.errorhandler(500)
+ def internal_server_error(e):
+ return 'internal server error', 500
- with app.test_request_context():
- assert not flask.session.modified
- flask.flash('Zap')
- flask.session.modified = False
- flask.flash('Zip')
- assert flask.session.modified
- assert list(flask.get_flashed_messages()) == ['Zap', 'Zip']
-
- def test_extended_flashing(self):
- # Be sure app.testing=True below, else tests can fail silently.
- #
- # Specifically, if app.testing is not set to True, the AssertionErrors
- # in the view functions will cause a 500 response to the test client
- # instead of propagating exceptions.
+ @app.errorhandler(Forbidden)
+ def forbidden(e):
+ return 'forbidden', 403
+
+ @app.route('/')
+ def index():
+ flask.abort(404)
+
+ @app.route('/error')
+ def error():
+ 1 // 0
+
+ @app.route('/forbidden')
+ def error2():
+ flask.abort(403)
+ c = app.test_client()
+ rv = c.get('/')
+ assert rv.status_code == 404
+ assert rv.data == b'not found'
+ rv = c.get('/error')
+ assert rv.status_code == 500
+ assert b'internal server error' == rv.data
+ rv = c.get('/forbidden')
+ assert rv.status_code == 403
+ assert b'forbidden' == rv.data
+
+
+def test_before_request_and_routing_errors():
+ app = flask.Flask(__name__)
- app = flask.Flask(__name__)
- app.secret_key = 'testkey'
- app.testing = True
+ @app.before_request
+ def attach_something():
+ flask.g.something = 'value'
+
+ @app.errorhandler(404)
+ def return_something(error):
+ return flask.g.something, 404
+ rv = app.test_client().get('/')
+ assert rv.status_code == 404
+ assert rv.data == b'value'
+
+
+def test_user_error_handling():
+ class MyException(Exception):
+ pass
+
+ app = flask.Flask(__name__)
+
+ @app.errorhandler(MyException)
+ def handle_my_exception(e):
+ assert isinstance(e, MyException)
+ return '42'
+
+ @app.route('/')
+ def index():
+ raise MyException()
+
+ c = app.test_client()
+ assert c.get('/').data == b'42'
+
+
+def test_http_error_subclass_handling():
+ class ForbiddenSubclass(Forbidden):
+ pass
+
+ app = flask.Flask(__name__)
+
+ @app.errorhandler(ForbiddenSubclass)
+ def handle_forbidden_subclass(e):
+ assert isinstance(e, ForbiddenSubclass)
+ return 'banana'
+
+ @app.errorhandler(403)
+ def handle_forbidden_subclass(e):
+ assert not isinstance(e, ForbiddenSubclass)
+ assert isinstance(e, Forbidden)
+ return 'apple'
+
+ @app.route('/1')
+ def index1():
+ raise ForbiddenSubclass()
+
+ @app.route('/2')
+ def index2():
+ flask.abort(403)
- @app.route('/')
- def index():
- flask.flash(u'Hello World')
- flask.flash(u'Hello World', 'error')
- flask.flash(flask.Markup(u'Testing'), 'warning')
- return ''
-
- @app.route('/test/')
- def test():
- messages = flask.get_flashed_messages()
- assert list(messages) == [
- u'Hello World',
- u'Hello World',
- flask.Markup(u'Testing')
- ]
- return ''
-
- @app.route('/test_with_categories/')
- def test_with_categories():
- messages = flask.get_flashed_messages(with_categories=True)
- assert len(messages) == 3
- assert list(messages) == [
- ('message', u'Hello World'),
- ('error', u'Hello World'),
- ('warning', flask.Markup(u'Testing'))
- ]
- return ''
-
- @app.route('/test_filter/')
- def test_filter():
- messages = flask.get_flashed_messages(category_filter=['message'], with_categories=True)
- assert list(messages) == [('message', u'Hello World')]
- return ''
-
- @app.route('/test_filters/')
- def test_filters():
- messages = flask.get_flashed_messages(category_filter=['message', 'warning'], with_categories=True)
- assert list(messages) == [
- ('message', u'Hello World'),
- ('warning', flask.Markup(u'Testing'))
- ]
- return ''
-
- @app.route('/test_filters_without_returning_categories/')
- def test_filters2():
- messages = flask.get_flashed_messages(category_filter=['message', 'warning'])
- assert len(messages) == 2
- assert messages[0] == u'Hello World'
- assert messages[1] == flask.Markup(u'Testing')
- return ''
-
- # Create new test client on each test to clean flashed messages.
+ @app.route('/3')
+ def index3():
+ raise Forbidden()
+
+ c = app.test_client()
+ assert c.get('/1').data == b'banana'
+ assert c.get('/2').data == b'apple'
+ assert c.get('/3').data == b'apple'
+
+
+def test_trapping_of_bad_request_key_errors():
+ app = flask.Flask(__name__)
+ app.testing = True
+
+ @app.route('/fail')
+ def fail():
+ flask.request.form['missing_key']
+ c = app.test_client()
+ assert c.get('/fail').status_code == 400
+
+ app.config['TRAP_BAD_REQUEST_ERRORS'] = True
+ c = app.test_client()
+ try:
+ c.get('/fail')
+ except KeyError as e:
+ assert isinstance(e, BadRequest)
+ else:
+ assert False, 'Expected exception'
+
+
+def test_trapping_of_all_http_exceptions():
+ app = flask.Flask(__name__)
+ app.testing = True
+ app.config['TRAP_HTTP_EXCEPTIONS'] = True
- c = app.test_client()
- c.get('/')
- c.get('/test/')
+ @app.route('/fail')
+ def fail():
+ flask.abort(404)
- c = app.test_client()
- c.get('/')
- c.get('/test_with_categories/')
+ c = app.test_client()
+ with pytest.raises(NotFound):
+ c.get('/fail')
- c = app.test_client()
- c.get('/')
- c.get('/test_filter/')
- c = app.test_client()
- c.get('/')
- c.get('/test_filters/')
+def test_enctype_debug_helper():
+ from flask.debughelpers import DebugFilesKeyError
+ app = flask.Flask(__name__)
+ app.debug = True
- c = app.test_client()
- c.get('/')
- c.get('/test_filters_without_returning_categories/')
+ @app.route('/fail', methods=['POST'])
+ def index():
+ return flask.request.files['foo'].filename
- def test_request_processing(self):
- app = flask.Flask(__name__)
- evts = []
- @app.before_request
- def before_request():
- evts.append('before')
- @app.after_request
- def after_request(response):
- response.data += b'|after'
- evts.append('after')
- return response
- @app.route('/')
- def index():
- assert 'before' in evts
- assert 'after' not in evts
- return 'request'
- assert 'after' not in evts
- rv = app.test_client().get('/').data
- assert 'after' in evts
- assert rv == b'request|after'
+ # with statement is important because we leave an exception on the
+ # stack otherwise and we want to ensure that this is not the case
+ # to not negatively affect other tests.
+ with app.test_client() as c:
+ try:
+ c.post('/fail', data={'foo': 'index.txt'})
+ except DebugFilesKeyError as e:
+ assert 'no file contents were transmitted' in str(e)
+ assert 'This was submitted: "index.txt"' in str(e)
+ else:
+ assert False, 'Expected exception'
- def test_after_request_processing(self):
- app = flask.Flask(__name__)
- app.testing = True
- @app.route('/')
- def index():
- @flask.after_this_request
- def foo(response):
- response.headers['X-Foo'] = 'a header'
- return response
- return 'Test'
- c = app.test_client()
- resp = c.get('/')
- assert resp.status_code == 200
- assert resp.headers['X-Foo'] == 'a header'
- def test_teardown_request_handler(self):
- called = []
- app = flask.Flask(__name__)
- @app.teardown_request
- def teardown_request(exc):
- called.append(True)
- return "Ignored"
- @app.route('/')
- def root():
- return "Response"
- rv = app.test_client().get('/')
+def test_response_creation():
+ app = flask.Flask(__name__)
+
+ @app.route('/unicode')
+ def from_unicode():
+ return u'Hällo Wörld'
+
+ @app.route('/string')
+ def from_string():
+ return u'Hällo Wörld'.encode('utf-8')
+
+ @app.route('/args')
+ def from_tuple():
+ return 'Meh', 400, {
+ 'X-Foo': 'Testing',
+ 'Content-Type': 'text/plain; charset=utf-8'
+ }
+
+ @app.route('/two_args')
+ def from_two_args_tuple():
+ return 'Hello', {
+ 'X-Foo': 'Test',
+ 'Content-Type': 'text/plain; charset=utf-8'
+ }
+
+ @app.route('/args_status')
+ def from_status_tuple():
+ return 'Hi, status!', 400
+
+ @app.route('/args_header')
+ def from_response_instance_status_tuple():
+ return flask.Response('Hello world', 404), {
+ "X-Foo": "Bar",
+ "X-Bar": "Foo"
+ }
+
+ c = app.test_client()
+ assert c.get('/unicode').data == u'Hällo Wörld'.encode('utf-8')
+ assert c.get('/string').data == u'Hällo Wörld'.encode('utf-8')
+ rv = c.get('/args')
+ assert rv.data == b'Meh'
+ assert rv.headers['X-Foo'] == 'Testing'
+ assert rv.status_code == 400
+ assert rv.mimetype == 'text/plain'
+ rv2 = c.get('/two_args')
+ assert rv2.data == b'Hello'
+ assert rv2.headers['X-Foo'] == 'Test'
+ assert rv2.status_code == 200
+ assert rv2.mimetype == 'text/plain'
+ rv3 = c.get('/args_status')
+ assert rv3.data == b'Hi, status!'
+ assert rv3.status_code == 400
+ assert rv3.mimetype == 'text/html'
+ rv4 = c.get('/args_header')
+ assert rv4.data == b'Hello world'
+ assert rv4.headers['X-Foo'] == 'Bar'
+ assert rv4.headers['X-Bar'] == 'Foo'
+ assert rv4.status_code == 404
+
+
+def test_make_response():
+ app = flask.Flask(__name__)
+ with app.test_request_context():
+ rv = flask.make_response()
assert rv.status_code == 200
- assert b'Response' in rv.data
- assert len(called) == 1
+ assert rv.data == b''
+ assert rv.mimetype == 'text/html'
- def test_teardown_request_handler_debug_mode(self):
- called = []
- app = flask.Flask(__name__)
- app.testing = True
- @app.teardown_request
- def teardown_request(exc):
- called.append(True)
- return "Ignored"
- @app.route('/')
- def root():
- return "Response"
- rv = app.test_client().get('/')
+ rv = flask.make_response('Awesome')
assert rv.status_code == 200
- assert b'Response' in rv.data
- assert len(called) == 1
+ assert rv.data == b'Awesome'
+ assert rv.mimetype == 'text/html'
- def test_teardown_request_handler_error(self):
- called = []
- app = flask.Flask(__name__)
- app.config['LOGGER_HANDLER_POLICY'] = 'never'
- @app.teardown_request
- def teardown_request1(exc):
- assert type(exc) == ZeroDivisionError
- called.append(True)
- # This raises a new error and blows away sys.exc_info(), so we can
- # test that all teardown_requests get passed the same original
- # exception.
- try:
- raise TypeError()
- except:
- pass
- @app.teardown_request
- def teardown_request2(exc):
- assert type(exc) == ZeroDivisionError
- called.append(True)
- # This raises a new error and blows away sys.exc_info(), so we can
- # test that all teardown_requests get passed the same original
- # exception.
- try:
- raise TypeError()
- except:
- pass
- @app.route('/')
- def fails():
- 1 // 0
- rv = app.test_client().get('/')
- assert rv.status_code == 500
- assert b'Internal Server Error' in rv.data
- assert len(called) == 2
+ rv = flask.make_response('W00t', 404)
+ assert rv.status_code == 404
+ assert rv.data == b'W00t'
+ assert rv.mimetype == 'text/html'
- def test_before_after_request_order(self):
- called = []
- app = flask.Flask(__name__)
- @app.before_request
- def before1():
- called.append(1)
- @app.before_request
- def before2():
- called.append(2)
- @app.after_request
- def after1(response):
- called.append(4)
- return response
- @app.after_request
- def after2(response):
- called.append(3)
- return response
- @app.teardown_request
- def finish1(exc):
- called.append(6)
- @app.teardown_request
- def finish2(exc):
- called.append(5)
- @app.route('/')
- def index():
- return '42'
- rv = app.test_client().get('/')
- assert rv.data == b'42'
- assert called == [1, 2, 3, 4, 5, 6]
- def test_error_handling(self):
- app = flask.Flask(__name__)
- app.config['LOGGER_HANDLER_POLICY'] = 'never'
- @app.errorhandler(404)
- def not_found(e):
- return 'not found', 404
- @app.errorhandler(500)
- def internal_server_error(e):
- return 'internal server error', 500
- @app.errorhandler(Forbidden)
- def forbidden(e):
- return 'forbidden', 403
- @app.route('/')
- def index():
- flask.abort(404)
- @app.route('/error')
- def error():
- 1 // 0
- @app.route('/forbidden')
- def error2():
- flask.abort(403)
- c = app.test_client()
- rv = c.get('/')
+def test_make_response_with_response_instance():
+ app = flask.Flask(__name__)
+ with app.test_request_context():
+ rv = flask.make_response(
+ flask.jsonify({'msg': 'W00t'}), 400)
+ assert rv.status_code == 400
+ assert rv.data == b'{\n "msg": "W00t"\n}'
+ assert rv.mimetype == 'application/json'
+
+ rv = flask.make_response(
+ flask.Response(''), 400)
+ assert rv.status_code == 400
+ assert rv.data == b''
+ assert rv.mimetype == 'text/html'
+
+ rv = flask.make_response(
+ flask.Response('', headers={'Content-Type': 'text/html'}),
+ 400, [('X-Foo', 'bar')])
+ assert rv.status_code == 400
+ assert rv.headers['Content-Type'] == 'text/html'
+ assert rv.headers['X-Foo'] == 'bar'
+
+
+def test_url_generation():
+ app = flask.Flask(__name__)
+
+ @app.route('/hello/', methods=['POST'])
+ def hello():
+ pass
+ with app.test_request_context():
+ assert flask.url_for('hello', name='test x') == '/hello/test%20x'
+ assert flask.url_for('hello', name='test x', _external=True) == \
+ 'http://localhost/hello/test%20x'
+
+
+def test_build_error_handler():
+ app = flask.Flask(__name__)
+
+ # Test base case, a URL which results in a BuildError.
+ with app.test_request_context():
+ pytest.raises(BuildError, flask.url_for, 'spam')
+
+ # Verify the error is re-raised if not the current exception.
+ try:
+ with app.test_request_context():
+ flask.url_for('spam')
+ except BuildError as err:
+ error = err
+ try:
+ raise RuntimeError('Test case where BuildError is not current.')
+ except RuntimeError:
+ pytest.raises(
+ BuildError, app.handle_url_build_error, error, 'spam', {})
+
+ # Test a custom handler.
+ def handler(error, endpoint, values):
+ # Just a test.
+ return '/test_handler/'
+ app.url_build_error_handlers.append(handler)
+ with app.test_request_context():
+ assert flask.url_for('spam') == '/test_handler/'
+
+
+def test_custom_converters():
+ from werkzeug.routing import BaseConverter
+
+ class ListConverter(BaseConverter):
+
+ def to_python(self, value):
+ return value.split(',')
+
+ def to_url(self, value):
+ base_to_url = super(ListConverter, self).to_url
+ return ','.join(base_to_url(x) for x in value)
+ app = flask.Flask(__name__)
+ app.url_map.converters['list'] = ListConverter
+
+ @app.route('/')
+ def index(args):
+ return '|'.join(args)
+ c = app.test_client()
+ assert c.get('/1,2,3').data == b'1|2|3'
+
+
+def test_static_files():
+ app = flask.Flask(__name__)
+ app.testing = True
+ rv = app.test_client().get('/static/index.html')
+ assert rv.status_code == 200
+ assert rv.data.strip() == b'Hello World!
'
+ with app.test_request_context():
+ assert flask.url_for('static', filename='index.html') == \
+ '/static/index.html'
+ rv.close()
+
+
+def test_none_response():
+ app = flask.Flask(__name__)
+ app.testing = True
+
+ @app.route('/')
+ def test():
+ return None
+ try:
+ app.test_client().get('/')
+ except ValueError as e:
+ assert str(e) == 'View function did not return a response'
+ pass
+ else:
+ assert "Expected ValueError"
+
+
+def test_request_locals():
+ assert repr(flask.g) == ''
+ assert not flask.g
+
+
+def test_test_app_proper_environ():
+ app = flask.Flask(__name__)
+ app.config.update(
+ SERVER_NAME='localhost.localdomain:5000'
+ )
+
+ @app.route('/')
+ def index():
+ return 'Foo'
+
+ @app.route('/', subdomain='foo')
+ def subdomain():
+ return 'Foo SubDomain'
+
+ rv = app.test_client().get('/')
+ assert rv.data == b'Foo'
+
+ rv = app.test_client().get('/', 'http://localhost.localdomain:5000')
+ assert rv.data == b'Foo'
+
+ rv = app.test_client().get('/', 'https://localhost.localdomain:5000')
+ assert rv.data == b'Foo'
+
+ app.config.update(SERVER_NAME='localhost.localdomain')
+ rv = app.test_client().get('/', 'https://localhost.localdomain')
+ assert rv.data == b'Foo'
+
+ try:
+ app.config.update(SERVER_NAME='localhost.localdomain:443')
+ rv = app.test_client().get('/', 'https://localhost.localdomain')
+ # Werkzeug 0.8
assert rv.status_code == 404
- assert rv.data == b'not found'
- rv = c.get('/error')
- assert rv.status_code == 500
- assert b'internal server error' == rv.data
- rv = c.get('/forbidden')
- assert rv.status_code == 403
- assert b'forbidden' == rv.data
-
- def test_before_request_and_routing_errors(self):
- app = flask.Flask(__name__)
- @app.before_request
- def attach_something():
- flask.g.something = 'value'
- @app.errorhandler(404)
- def return_something(error):
- return flask.g.something, 404
- rv = app.test_client().get('/')
+ except ValueError as e:
+ # Werkzeug 0.7
+ assert str(e) == (
+ "the server name provided "
+ "('localhost.localdomain:443') does not match the "
+ "server name from the WSGI environment ('localhost.localdomain')"
+ )
+
+ try:
+ app.config.update(SERVER_NAME='localhost.localdomain')
+ rv = app.test_client().get('/', 'http://foo.localhost')
+ # Werkzeug 0.8
assert rv.status_code == 404
- assert rv.data == b'value'
+ except ValueError as e:
+ # Werkzeug 0.7
+ assert str(e) == (
+ "the server name provided "
+ "('localhost.localdomain') does not match the "
+ "server name from the WSGI environment ('foo.localhost')"
+ )
+
+ rv = app.test_client().get('/', 'http://foo.localhost.localdomain')
+ assert rv.data == b'Foo SubDomain'
- def test_user_error_handling(self):
- class MyException(Exception):
- pass
+def test_exception_propagation():
+ def apprunner(configkey):
app = flask.Flask(__name__)
- @app.errorhandler(MyException)
- def handle_my_exception(e):
- assert isinstance(e, MyException)
- return '42'
+ app.config['LOGGER_HANDLER_POLICY'] = 'never'
+
@app.route('/')
def index():
- raise MyException()
-
+ 1 // 0
c = app.test_client()
- assert c.get('/').data == b'42'
+ if config_key is not None:
+ app.config[config_key] = True
+ try:
+ c.get('/')
+ except Exception:
+ pass
+ else:
+ assert False, 'expected exception'
+ else:
+ assert c.get('/').status_code == 500
+
+ # we have to run this test in an isolated thread because if the
+ # debug flag is set to true and an exception happens the context is
+ # not torn down. This causes other tests that run after this fail
+ # when they expect no exception on the stack.
+ for config_key in 'TESTING', 'PROPAGATE_EXCEPTIONS', 'DEBUG', None:
+ t = Thread(target=apprunner, args=(config_key,))
+ t.start()
+ t.join()
- def test_http_error_subclass_handling(self):
- class ForbiddenSubclass(Forbidden):
- pass
- app = flask.Flask(__name__)
- @app.errorhandler(ForbiddenSubclass)
- def handle_forbidden_subclass(e):
- assert isinstance(e, ForbiddenSubclass)
- return 'banana'
- @app.errorhandler(403)
- def handle_forbidden_subclass(e):
- assert not isinstance(e, ForbiddenSubclass)
- assert isinstance(e, Forbidden)
- return 'apple'
-
- @app.route('/1')
- def index1():
- raise ForbiddenSubclass()
- @app.route('/2')
- def index2():
- flask.abort(403)
- @app.route('/3')
- def index3():
- raise Forbidden()
+def test_max_content_length():
+ app = flask.Flask(__name__)
+ app.config['MAX_CONTENT_LENGTH'] = 64
- c = app.test_client()
- assert c.get('/1').data == b'banana'
- assert c.get('/2').data == b'apple'
- assert c.get('/3').data == b'apple'
+ @app.before_request
+ def always_first():
+ flask.request.form['myfile']
+ assert False
- def test_trapping_of_bad_request_key_errors(self):
- app = flask.Flask(__name__)
- app.testing = True
- @app.route('/fail')
- def fail():
- flask.request.form['missing_key']
- c = app.test_client()
- assert c.get('/fail').status_code == 400
+ @app.route('/accept', methods=['POST'])
+ def accept_file():
+ flask.request.form['myfile']
+ assert False
- app.config['TRAP_BAD_REQUEST_ERRORS'] = True
- c = app.test_client()
- try:
- c.get('/fail')
- except KeyError as e:
- assert isinstance(e, BadRequest)
- else:
- assert False, 'Expected exception'
+ @app.errorhandler(413)
+ def catcher(error):
+ return '42'
- def test_trapping_of_all_http_exceptions(self):
- app = flask.Flask(__name__)
- app.testing = True
- app.config['TRAP_HTTP_EXCEPTIONS'] = True
- @app.route('/fail')
- def fail():
- flask.abort(404)
+ c = app.test_client()
+ rv = c.post('/accept', data={'myfile': 'foo' * 100})
+ assert rv.data == b'42'
- c = app.test_client()
- try:
- c.get('/fail')
- except NotFound as e:
- pass
- else:
- assert False, 'Expected exception'
- def test_enctype_debug_helper(self):
- from flask.debughelpers import DebugFilesKeyError
- app = flask.Flask(__name__)
- app.debug = True
- @app.route('/fail', methods=['POST'])
- def index():
- return flask.request.files['foo'].filename
+def test_url_processors():
+ app = flask.Flask(__name__)
- # with statement is important because we leave an exception on the
- # stack otherwise and we want to ensure that this is not the case
- # to not negatively affect other tests.
- with app.test_client() as c:
- try:
- c.post('/fail', data={'foo': 'index.txt'})
- except DebugFilesKeyError as e:
- assert 'no file contents were transmitted' in str(e)
- assert 'This was submitted: "index.txt"' in str(e)
- else:
- assert False, 'Expected exception'
+ @app.url_defaults
+ def add_language_code(endpoint, values):
+ if flask.g.lang_code is not None and \
+ app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
+ values.setdefault('lang_code', flask.g.lang_code)
- def test_response_creation(self):
- app = flask.Flask(__name__)
- @app.route('/unicode')
- def from_unicode():
- return u'Hällo Wörld'
- @app.route('/string')
- def from_string():
- return u'Hällo Wörld'.encode('utf-8')
- @app.route('/args')
- def from_tuple():
- return 'Meh', 400, {
- 'X-Foo': 'Testing',
- 'Content-Type': 'text/plain; charset=utf-8'
- }
- @app.route('/two_args')
- def from_two_args_tuple():
- return 'Hello', {
- 'X-Foo': 'Test',
- 'Content-Type': 'text/plain; charset=utf-8'
- }
- @app.route('/args_status')
- def from_status_tuple():
- return 'Hi, status!', 400
- @app.route('/args_header')
- def from_response_instance_status_tuple():
- return flask.Response('Hello world', 404), {
- "X-Foo": "Bar",
- "X-Bar": "Foo"
- }
+ @app.url_value_preprocessor
+ def pull_lang_code(endpoint, values):
+ flask.g.lang_code = values.pop('lang_code', None)
- c = app.test_client()
- assert c.get('/unicode').data == u'Hällo Wörld'.encode('utf-8')
- assert c.get('/string').data == u'Hällo Wörld'.encode('utf-8')
- rv = c.get('/args')
- assert rv.data == b'Meh'
- assert rv.headers['X-Foo'] == 'Testing'
- assert rv.status_code == 400
- assert rv.mimetype == 'text/plain'
- rv2 = c.get('/two_args')
- assert rv2.data == b'Hello'
- assert rv2.headers['X-Foo'] == 'Test'
- assert rv2.status_code == 200
- assert rv2.mimetype == 'text/plain'
- rv3 = c.get('/args_status')
- assert rv3.data == b'Hi, status!'
- assert rv3.status_code == 400
- assert rv3.mimetype == 'text/html'
- rv4 = c.get('/args_header')
- assert rv4.data == b'Hello world'
- assert rv4.headers['X-Foo'] == 'Bar'
- assert rv4.headers['X-Bar'] == 'Foo'
- assert rv4.status_code == 404
-
- def test_make_response(self):
- app = flask.Flask(__name__)
- with app.test_request_context():
- rv = flask.make_response()
- assert rv.status_code == 200
- assert rv.data == b''
- assert rv.mimetype == 'text/html'
-
- rv = flask.make_response('Awesome')
- assert rv.status_code == 200
- assert rv.data == b'Awesome'
- assert rv.mimetype == 'text/html'
-
- rv = flask.make_response('W00t', 404)
- assert rv.status_code == 404
- assert rv.data == b'W00t'
- assert rv.mimetype == 'text/html'
-
- def test_make_response_with_response_instance(self):
- app = flask.Flask(__name__)
- with app.test_request_context():
- rv = flask.make_response(
- flask.jsonify({'msg': 'W00t'}), 400)
- assert rv.status_code == 400
- assert rv.data == b'{\n "msg": "W00t"\n}'
- assert rv.mimetype == 'application/json'
-
- rv = flask.make_response(
- flask.Response(''), 400)
- assert rv.status_code == 400
- assert rv.data == b''
- assert rv.mimetype == 'text/html'
-
- rv = flask.make_response(
- flask.Response('', headers={'Content-Type': 'text/html'}),
- 400, [('X-Foo', 'bar')])
- assert rv.status_code == 400
- assert rv.headers['Content-Type'] == 'text/html'
- assert rv.headers['X-Foo'] == 'bar'
-
- def test_url_generation(self):
- app = flask.Flask(__name__)
- @app.route('/hello/', methods=['POST'])
- def hello():
- pass
- with app.test_request_context():
- assert flask.url_for('hello', name='test x') == '/hello/test%20x'
- assert flask.url_for('hello', name='test x', _external=True) == \
- 'http://localhost/hello/test%20x'
+ @app.route('//')
+ def index():
+ return flask.url_for('about')
- def test_build_error_handler(self):
- app = flask.Flask(__name__)
+ @app.route('//about')
+ def about():
+ return flask.url_for('something_else')
- # Test base case, a URL which results in a BuildError.
- with app.test_request_context():
- pytest.raises(BuildError, flask.url_for, 'spam')
+ @app.route('/foo')
+ def something_else():
+ return flask.url_for('about', lang_code='en')
- # Verify the error is re-raised if not the current exception.
- try:
- with app.test_request_context():
- flask.url_for('spam')
- except BuildError as err:
- error = err
- try:
- raise RuntimeError('Test case where BuildError is not current.')
- except RuntimeError:
- pytest.raises(BuildError, app.handle_url_build_error, error, 'spam', {})
-
- # Test a custom handler.
- def handler(error, endpoint, values):
- # Just a test.
- return '/test_handler/'
- app.url_build_error_handlers.append(handler)
- with app.test_request_context():
- assert flask.url_for('spam') == '/test_handler/'
-
- def test_custom_converters(self):
- from werkzeug.routing import BaseConverter
- class ListConverter(BaseConverter):
- def to_python(self, value):
- return value.split(',')
- def to_url(self, value):
- base_to_url = super(ListConverter, self).to_url
- return ','.join(base_to_url(x) for x in value)
- app = flask.Flask(__name__)
- app.url_map.converters['list'] = ListConverter
- @app.route('/')
- def index(args):
- return '|'.join(args)
- c = app.test_client()
- assert c.get('/1,2,3').data == b'1|2|3'
+ c = app.test_client()
- def test_static_files(self):
- app = flask.Flask(__name__)
- app.testing = True
- rv = app.test_client().get('/static/index.html')
- assert rv.status_code == 200
- assert rv.data.strip() == b'Hello World!
'
- with app.test_request_context():
- assert flask.url_for('static', filename='index.html') == \
- '/static/index.html'
- rv.close()
+ assert c.get('/de/').data == b'/de/about'
+ assert c.get('/de/about').data == b'/foo'
+ assert c.get('/foo').data == b'/en/about'
- def test_none_response(self):
- app = flask.Flask(__name__)
- app.testing = True
- @app.route('/')
- def test():
- return None
- try:
- app.test_client().get('/')
- except ValueError as e:
- assert str(e) == 'View function did not return a response'
- pass
- else:
- assert "Expected ValueError"
- def test_request_locals(self):
- assert repr(flask.g) == ''
- assert not flask.g
+def test_inject_blueprint_url_defaults():
+ app = flask.Flask(__name__)
+ bp = flask.Blueprint('foo.bar.baz', __name__,
+ template_folder='template')
- def test_test_app_proper_environ(self):
- app = flask.Flask(__name__)
- app.config.update(
- SERVER_NAME='localhost.localdomain:5000'
- )
- @app.route('/')
- def index():
- return 'Foo'
+ @bp.url_defaults
+ def bp_defaults(endpoint, values):
+ values['page'] = 'login'
- @app.route('/', subdomain='foo')
- def subdomain():
- return 'Foo SubDomain'
+ @bp.route('/')
+ def view(page):
+ pass
- rv = app.test_client().get('/')
- assert rv.data == b'Foo'
+ app.register_blueprint(bp)
- rv = app.test_client().get('/', 'http://localhost.localdomain:5000')
- assert rv.data == b'Foo'
+ values = dict()
+ app.inject_url_defaults('foo.bar.baz.view', values)
+ expected = dict(page='login')
+ assert values == expected
- rv = app.test_client().get('/', 'https://localhost.localdomain:5000')
- assert rv.data == b'Foo'
+ with app.test_request_context('/somepage'):
+ url = flask.url_for('foo.bar.baz.view')
+ expected = '/login'
+ assert url == expected
- app.config.update(SERVER_NAME='localhost.localdomain')
- rv = app.test_client().get('/', 'https://localhost.localdomain')
- assert rv.data == b'Foo'
- try:
- app.config.update(SERVER_NAME='localhost.localdomain:443')
- rv = app.test_client().get('/', 'https://localhost.localdomain')
- # Werkzeug 0.8
- assert rv.status_code == 404
- except ValueError as e:
- # Werkzeug 0.7
- assert str(e) == (
- "the server name provided "
- "('localhost.localdomain:443') does not match the "
- "server name from the WSGI environment ('localhost.localdomain')"
- )
+def test_nonascii_pathinfo():
+ app = flask.Flask(__name__)
+ app.testing = True
- try:
- app.config.update(SERVER_NAME='localhost.localdomain')
- rv = app.test_client().get('/', 'http://foo.localhost')
- # Werkzeug 0.8
- assert rv.status_code == 404
- except ValueError as e:
- # Werkzeug 0.7
- assert str(e) == (
- "the server name provided "
- "('localhost.localdomain') does not match the "
- "server name from the WSGI environment ('foo.localhost')"
- )
-
- rv = app.test_client().get('/', 'http://foo.localhost.localdomain')
- assert rv.data == b'Foo SubDomain'
-
- def test_exception_propagation(self):
- def apprunner(configkey):
- app = flask.Flask(__name__)
- app.config['LOGGER_HANDLER_POLICY'] = 'never'
- @app.route('/')
- def index():
- 1 // 0
- c = app.test_client()
- if config_key is not None:
- app.config[config_key] = True
- try:
- c.get('/')
- except Exception:
- pass
- else:
- assert False, 'expected exception'
- else:
- assert c.get('/').status_code == 500
-
- # we have to run this test in an isolated thread because if the
- # debug flag is set to true and an exception happens the context is
- # not torn down. This causes other tests that run after this fail
- # when they expect no exception on the stack.
- for config_key in 'TESTING', 'PROPAGATE_EXCEPTIONS', 'DEBUG', None:
- t = Thread(target=apprunner, args=(config_key,))
- t.start()
- t.join()
-
- def test_max_content_length(self):
- app = flask.Flask(__name__)
- app.config['MAX_CONTENT_LENGTH'] = 64
- @app.before_request
- def always_first():
- flask.request.form['myfile']
- assert False
- @app.route('/accept', methods=['POST'])
- def accept_file():
- flask.request.form['myfile']
- assert False
- @app.errorhandler(413)
- def catcher(error):
- return '42'
+ @app.route(u'/киртест')
+ def index():
+ return 'Hello World!'
- c = app.test_client()
- rv = c.post('/accept', data={'myfile': 'foo' * 100})
- assert rv.data == b'42'
+ c = app.test_client()
+ rv = c.get(u'/киртест')
+ assert rv.data == b'Hello World!'
- def test_url_processors(self):
- app = flask.Flask(__name__)
- @app.url_defaults
- def add_language_code(endpoint, values):
- if flask.g.lang_code is not None and \
- app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
- values.setdefault('lang_code', flask.g.lang_code)
+def test_debug_mode_complains_after_first_request():
+ app = flask.Flask(__name__)
+ app.debug = True
- @app.url_value_preprocessor
- def pull_lang_code(endpoint, values):
- flask.g.lang_code = values.pop('lang_code', None)
+ @app.route('/')
+ def index():
+ return 'Awesome'
+ assert not app.got_first_request
+ assert app.test_client().get('/').data == b'Awesome'
+ try:
+ @app.route('/foo')
+ def broken():
+ return 'Meh'
+ except AssertionError as e:
+ assert 'A setup function was called' in str(e)
+ else:
+ assert False, 'Expected exception'
- @app.route('//')
- def index():
- return flask.url_for('about')
+ app.debug = False
- @app.route('//about')
- def about():
- return flask.url_for('something_else')
+ @app.route('/foo')
+ def working():
+ return 'Meh'
+ assert app.test_client().get('/foo').data == b'Meh'
+ assert app.got_first_request
- @app.route('/foo')
- def something_else():
- return flask.url_for('about', lang_code='en')
- c = app.test_client()
+def test_before_first_request_functions():
+ got = []
+ app = flask.Flask(__name__)
- assert c.get('/de/').data == b'/de/about'
- assert c.get('/de/about').data == b'/foo'
- assert c.get('/foo').data == b'/en/about'
+ @app.before_first_request
+ def foo():
+ got.append(42)
+ c = app.test_client()
+ c.get('/')
+ assert got == [42]
+ c.get('/')
+ assert got == [42]
+ assert app.got_first_request
- def test_inject_blueprint_url_defaults(self):
- app = flask.Flask(__name__)
- bp = flask.Blueprint('foo.bar.baz', __name__,
- template_folder='template')
- @bp.url_defaults
- def bp_defaults(endpoint, values):
- values['page'] = 'login'
- @bp.route('/')
- def view(page): pass
+def test_before_first_request_functions_concurrent():
+ got = []
+ app = flask.Flask(__name__)
- app.register_blueprint(bp)
+ @app.before_first_request
+ def foo():
+ time.sleep(0.2)
+ got.append(42)
- values = dict()
- app.inject_url_defaults('foo.bar.baz.view', values)
- expected = dict(page='login')
- assert values == expected
+ c = app.test_client()
- with app.test_request_context('/somepage'):
- url = flask.url_for('foo.bar.baz.view')
- expected = '/login'
- assert url == expected
+ def get_and_assert():
+ c.get("/")
+ assert got == [42]
- def test_nonascii_pathinfo(self):
- app = flask.Flask(__name__)
- app.testing = True
+ t = Thread(target=get_and_assert)
+ t.start()
+ get_and_assert()
+ t.join()
+ assert app.got_first_request
- @app.route(u'/киртест')
- def index():
- return 'Hello World!'
- c = app.test_client()
- rv = c.get(u'/киртест')
- assert rv.data == b'Hello World!'
+def test_routing_redirect_debugging():
+ app = flask.Flask(__name__)
+ app.debug = True
- def test_debug_mode_complains_after_first_request(self):
- app = flask.Flask(__name__)
- app.debug = True
- @app.route('/')
- def index():
- return 'Awesome'
- assert not app.got_first_request
- assert app.test_client().get('/').data == b'Awesome'
+ @app.route('/foo/', methods=['GET', 'POST'])
+ def foo():
+ return 'success'
+ with app.test_client() as c:
try:
- @app.route('/foo')
- def broken():
- return 'Meh'
+ c.post('/foo', data={})
except AssertionError as e:
- assert 'A setup function was called' in str(e)
+ assert 'http://localhost/foo/' in str(e)
+ assert ('Make sure to directly send '
+ 'your POST-request to this URL') in str(e)
else:
assert False, 'Expected exception'
- app.debug = False
- @app.route('/foo')
- def working():
- return 'Meh'
- assert app.test_client().get('/foo').data == b'Meh'
- assert app.got_first_request
+ rv = c.get('/foo', data={}, follow_redirects=True)
+ assert rv.data == b'success'
- def test_before_first_request_functions(self):
- got = []
- app = flask.Flask(__name__)
- @app.before_first_request
- def foo():
- got.append(42)
- c = app.test_client()
- c.get('/')
- assert got == [42]
- c.get('/')
- assert got == [42]
- assert app.got_first_request
+ app.debug = False
+ with app.test_client() as c:
+ rv = c.post('/foo', data={}, follow_redirects=True)
+ assert rv.data == b'success'
- def test_before_first_request_functions_concurrent(self):
- got = []
- app = flask.Flask(__name__)
- @app.before_first_request
- def foo():
- time.sleep(0.2)
- got.append(42)
+def test_route_decorator_custom_endpoint():
+ app = flask.Flask(__name__)
+ app.debug = True
- c = app.test_client()
- def get_and_assert():
- c.get("/")
- assert got == [42]
+ @app.route('/foo/')
+ def foo():
+ return flask.request.endpoint
- t = Thread(target=get_and_assert)
- t.start()
- get_and_assert()
- t.join()
- assert app.got_first_request
+ @app.route('/bar/', endpoint='bar')
+ def for_bar():
+ return flask.request.endpoint
- def test_routing_redirect_debugging(self):
- app = flask.Flask(__name__)
- app.debug = True
- @app.route('/foo/', methods=['GET', 'POST'])
- def foo():
- return 'success'
- with app.test_client() as c:
- try:
- c.post('/foo', data={})
- except AssertionError as e:
- assert 'http://localhost/foo/' in str(e)
- assert ('Make sure to directly send '
- 'your POST-request to this URL') in str(e)
- else:
- assert False, 'Expected exception'
+ @app.route('/bar/123', endpoint='123')
+ def for_bar_foo():
+ return flask.request.endpoint
- rv = c.get('/foo', data={}, follow_redirects=True)
- assert rv.data == b'success'
+ with app.test_request_context():
+ assert flask.url_for('foo') == '/foo/'
+ assert flask.url_for('bar') == '/bar/'
+ assert flask.url_for('123') == '/bar/123'
- app.debug = False
- with app.test_client() as c:
- rv = c.post('/foo', data={}, follow_redirects=True)
- assert rv.data == b'success'
+ c = app.test_client()
+ assert c.get('/foo/').data == b'foo'
+ assert c.get('/bar/').data == b'bar'
+ assert c.get('/bar/123').data == b'123'
- def test_route_decorator_custom_endpoint(self):
- app = flask.Flask(__name__)
- app.debug = True
- @app.route('/foo/')
- def foo():
- return flask.request.endpoint
+def test_preserve_only_once():
+ app = flask.Flask(__name__)
+ app.debug = True
- @app.route('/bar/', endpoint='bar')
- def for_bar():
- return flask.request.endpoint
+ @app.route('/fail')
+ def fail_func():
+ 1 // 0
- @app.route('/bar/123', endpoint='123')
- def for_bar_foo():
- return flask.request.endpoint
+ c = app.test_client()
+ for x in range(3):
+ with pytest.raises(ZeroDivisionError):
+ c.get('/fail')
- with app.test_request_context():
- assert flask.url_for('foo') == '/foo/'
- assert flask.url_for('bar') == '/bar/'
- assert flask.url_for('123') == '/bar/123'
+ assert flask._request_ctx_stack.top is not None
+ assert flask._app_ctx_stack.top is not None
+ # implicit appctx disappears too
+ flask._request_ctx_stack.top.pop()
+ assert flask._request_ctx_stack.top is None
+ assert flask._app_ctx_stack.top is None
- c = app.test_client()
- assert c.get('/foo/').data == b'foo'
- assert c.get('/bar/').data == b'bar'
- assert c.get('/bar/123').data == b'123'
- def test_preserve_only_once(self):
- app = flask.Flask(__name__)
- app.debug = True
+def test_preserve_remembers_exception():
+ app = flask.Flask(__name__)
+ app.debug = True
+ errors = []
- @app.route('/fail')
- def fail_func():
- 1 // 0
+ @app.route('/fail')
+ def fail_func():
+ 1 // 0
- c = app.test_client()
- for x in range(3):
- with pytest.raises(ZeroDivisionError):
- c.get('/fail')
-
- assert flask._request_ctx_stack.top is not None
- assert flask._app_ctx_stack.top is not None
- # implicit appctx disappears too
- flask._request_ctx_stack.top.pop()
- assert flask._request_ctx_stack.top is None
- assert flask._app_ctx_stack.top is None
-
- def test_preserve_remembers_exception(self):
- app = flask.Flask(__name__)
- app.debug = True
- errors = []
+ @app.route('/success')
+ def success_func():
+ return 'Okay'
- @app.route('/fail')
- def fail_func():
- 1 // 0
+ @app.teardown_request
+ def teardown_handler(exc):
+ errors.append(exc)
- @app.route('/success')
- def success_func():
- return 'Okay'
+ c = app.test_client()
- @app.teardown_request
- def teardown_handler(exc):
- errors.append(exc)
+ # After this failure we did not yet call the teardown handler
+ with pytest.raises(ZeroDivisionError):
+ c.get('/fail')
+ assert errors == []
- c = app.test_client()
+ # But this request triggers it, and it's an error
+ c.get('/success')
+ assert len(errors) == 2
+ assert isinstance(errors[0], ZeroDivisionError)
- # After this failure we did not yet call the teardown handler
- with pytest.raises(ZeroDivisionError):
- c.get('/fail')
- assert errors == []
+ # At this point another request does nothing.
+ c.get('/success')
+ assert len(errors) == 3
+ assert errors[1] is None
- # But this request triggers it, and it's an error
- c.get('/success')
- assert len(errors) == 2
- assert isinstance(errors[0], ZeroDivisionError)
- # At this point another request does nothing.
- c.get('/success')
- assert len(errors) == 3
- assert errors[1] == None
+def test_get_method_on_g():
+ app = flask.Flask(__name__)
+ app.testing = True
- def test_get_method_on_g(self):
- app = flask.Flask(__name__)
- app.testing = True
+ with app.app_context():
+ assert flask.g.get('x') is None
+ assert flask.g.get('x', 11) == 11
+ flask.g.x = 42
+ assert flask.g.get('x') == 42
+ assert flask.g.x == 42
- with app.app_context():
- assert flask.g.get('x') == None
- assert flask.g.get('x', 11) == 11
- flask.g.x = 42
- assert flask.g.get('x') == 42
- assert flask.g.x == 42
- def test_g_iteration_protocol(self):
- app = flask.Flask(__name__)
- app.testing = True
+def test_g_iteration_protocol():
+ app = flask.Flask(__name__)
+ app.testing = True
- with app.app_context():
- flask.g.foo = 23
- flask.g.bar = 42
- assert 'foo' in flask.g
- assert 'foos' not in flask.g
- assert sorted(flask.g) == ['bar', 'foo']
+ with app.app_context():
+ flask.g.foo = 23
+ flask.g.bar = 42
+ assert 'foo' in flask.g
+ assert 'foos' not in flask.g
+ assert sorted(flask.g) == ['bar', 'foo']
-class TestSubdomain(object):
+def test_subdomain_basic_support():
+ app = flask.Flask(__name__)
+ app.config['SERVER_NAME'] = 'localhost'
- def test_basic_support(self):
- app = flask.Flask(__name__)
- app.config['SERVER_NAME'] = 'localhost'
- @app.route('/')
- def normal_index():
- return 'normal index'
- @app.route('/', subdomain='test')
- def test_index():
- return 'test index'
+ @app.route('/')
+ def normal_index():
+ return 'normal index'
- c = app.test_client()
- rv = c.get('/', 'http://localhost/')
- assert rv.data == b'normal index'
+ @app.route('/', subdomain='test')
+ def test_index():
+ return 'test index'
- rv = c.get('/', 'http://test.localhost/')
- assert rv.data == b'test index'
+ c = app.test_client()
+ rv = c.get('/', 'http://localhost/')
+ assert rv.data == b'normal index'
- def test_subdomain_matching(self):
- app = flask.Flask(__name__)
- app.config['SERVER_NAME'] = 'localhost'
- @app.route('/', subdomain='')
- def index(user):
- return 'index for %s' % user
+ rv = c.get('/', 'http://test.localhost/')
+ assert rv.data == b'test index'
- c = app.test_client()
- rv = c.get('/', 'http://mitsuhiko.localhost/')
- assert rv.data == b'index for mitsuhiko'
- def test_subdomain_matching_with_ports(self):
- app = flask.Flask(__name__)
- app.config['SERVER_NAME'] = 'localhost:3000'
- @app.route('/', subdomain='')
- def index(user):
- return 'index for %s' % user
+def test_subdomain_matching():
+ app = flask.Flask(__name__)
+ app.config['SERVER_NAME'] = 'localhost'
- c = app.test_client()
- rv = c.get('/', 'http://mitsuhiko.localhost:3000/')
- assert rv.data == b'index for mitsuhiko'
+ @app.route('/', subdomain='')
+ def index(user):
+ return 'index for %s' % user
- def test_multi_route_rules(self):
- app = flask.Flask(__name__)
+ c = app.test_client()
+ rv = c.get('/', 'http://mitsuhiko.localhost/')
+ assert rv.data == b'index for mitsuhiko'
- @app.route('/')
- @app.route('//')
- def index(test='a'):
- return test
- rv = app.test_client().open('/')
- assert rv.data == b'a'
- rv = app.test_client().open('/b/')
- assert rv.data == b'b'
+def test_subdomain_matching_with_ports():
+ app = flask.Flask(__name__)
+ app.config['SERVER_NAME'] = 'localhost:3000'
- def test_multi_route_class_views(self):
- class View(object):
- def __init__(self, app):
- app.add_url_rule('/', 'index', self.index)
- app.add_url_rule('//', 'index', self.index)
+ @app.route('/', subdomain='')
+ def index(user):
+ return 'index for %s' % user
- def index(self, test='a'):
- return test
+ c = app.test_client()
+ rv = c.get('/', 'http://mitsuhiko.localhost:3000/')
+ assert rv.data == b'index for mitsuhiko'
- app = flask.Flask(__name__)
- _ = View(app)
- rv = app.test_client().open('/')
- assert rv.data == b'a'
- rv = app.test_client().open('/b/')
- assert rv.data == b'b'
+
+def test_multi_route_rules():
+ app = flask.Flask(__name__)
+
+ @app.route('/')
+ @app.route('//')
+ def index(test='a'):
+ return test
+
+ rv = app.test_client().open('/')
+ assert rv.data == b'a'
+ rv = app.test_client().open('/b/')
+ assert rv.data == b'b'
+
+
+def test_multi_route_class_views():
+ class View(object):
+
+ def __init__(self, app):
+ app.add_url_rule('/', 'index', self.index)
+ app.add_url_rule('//', 'index', self.index)
+
+ def index(self, test='a'):
+ return test
+
+ app = flask.Flask(__name__)
+ _ = View(app)
+ rv = app.test_client().open('/')
+ assert rv.data == b'a'
+ rv = app.test_client().open('/b/')
+ assert rv.data == b'b'