Browse Source

DRYing up the test suite using pytest fixtures (#2306)

* add fixtures to conftest.py

* use fixtures in test_appctx.py

* use fixtures in test_blueprints.py

* use fixtures in test_depreciations.py

* use fixtures in test_regressions.py

* use fixtures in test_reqctx.py

* use fixtures in test_templating.py

* use fixtures in test_user_error_handler.py

* use fixtures in test_views.py

* use fixtures in test_basics.py

* use fixtures in test_helpers.py

* use fixtures in test_testing.py

* update conftest.py

* make docstrings  PEP-257 compliant

* cleanup

* switch dictonary format

* use pytest parameterization for test_json_as_unicode
pull/2324/head
Christian Stade-Schuldt 8 years ago committed by David Lord
parent
commit
5b0b9717da
  1. 52
      tests/conftest.py
  2. 58
      tests/test_appctx.py
  3. 429
      tests/test_basic.py
  4. 278
      tests/test_blueprints.py
  5. 13
      tests/test_deprecations.py
  6. 319
      tests/test_helpers.py
  7. 7
      tests/test_regression.py
  8. 47
      tests/test_reqctx.py
  9. 188
      tests/test_templating.py
  10. 76
      tests/test_testing.py
  11. 22
      tests/test_user_error_handler.py
  12. 44
      tests/test_views.py

52
tests/conftest.py

@ -13,6 +13,40 @@ import sys
import pkgutil import pkgutil
import pytest import pytest
import textwrap import textwrap
from flask import Flask as _Flask
class Flask(_Flask):
testing = True
secret_key = __name__
def make_response(self, rv):
if rv is None:
rv = ''
return super(Flask, self).make_response(rv)
@pytest.fixture
def app():
app = Flask(__name__)
return app
@pytest.fixture
def app_ctx(app):
with app.app_context() as ctx:
yield ctx
@pytest.fixture
def req_ctx(app):
with app.test_request_context() as ctx:
yield ctx
@pytest.fixture
def client(app):
return app.test_client()
@pytest.fixture @pytest.fixture
@ -63,12 +97,13 @@ def limit_loader(request, monkeypatch):
def get_loader(*args, **kwargs): def get_loader(*args, **kwargs):
return LimitedLoader(old_get_loader(*args, **kwargs)) return LimitedLoader(old_get_loader(*args, **kwargs))
monkeypatch.setattr(pkgutil, 'get_loader', get_loader) monkeypatch.setattr(pkgutil, 'get_loader', get_loader)
@pytest.fixture @pytest.fixture
def modules_tmpdir(tmpdir, monkeypatch): def modules_tmpdir(tmpdir, monkeypatch):
'''A tmpdir added to sys.path''' """A tmpdir added to sys.path."""
rv = tmpdir.mkdir('modules_tmpdir') rv = tmpdir.mkdir('modules_tmpdir')
monkeypatch.syspath_prepend(str(rv)) monkeypatch.syspath_prepend(str(rv))
return rv return rv
@ -82,10 +117,10 @@ def modules_tmpdir_prefix(modules_tmpdir, monkeypatch):
@pytest.fixture @pytest.fixture
def site_packages(modules_tmpdir, monkeypatch): def site_packages(modules_tmpdir, monkeypatch):
'''Create a fake site-packages''' """Create a fake site-packages."""
rv = modules_tmpdir \ rv = modules_tmpdir \
.mkdir('lib')\ .mkdir('lib') \
.mkdir('python{x[0]}.{x[1]}'.format(x=sys.version_info))\ .mkdir('python{x[0]}.{x[1]}'.format(x=sys.version_info)) \
.mkdir('site-packages') .mkdir('site-packages')
monkeypatch.syspath_prepend(str(rv)) monkeypatch.syspath_prepend(str(rv))
return rv return rv
@ -93,8 +128,9 @@ def site_packages(modules_tmpdir, monkeypatch):
@pytest.fixture @pytest.fixture
def install_egg(modules_tmpdir, monkeypatch): def install_egg(modules_tmpdir, monkeypatch):
'''Generate egg from package name inside base and put the egg into """Generate egg from package name inside base and put the egg into
sys.path''' sys.path."""
def inner(name, base=modules_tmpdir): def inner(name, base=modules_tmpdir):
if not isinstance(name, str): if not isinstance(name, str):
raise ValueError(name) raise ValueError(name)
@ -118,6 +154,7 @@ def install_egg(modules_tmpdir, monkeypatch):
egg_path, = modules_tmpdir.join('dist/').listdir() egg_path, = modules_tmpdir.join('dist/').listdir()
monkeypatch.syspath_prepend(str(egg_path)) monkeypatch.syspath_prepend(str(egg_path))
return egg_path return egg_path
return inner return inner
@ -125,6 +162,7 @@ def install_egg(modules_tmpdir, monkeypatch):
def purge_module(request): def purge_module(request):
def inner(name): def inner(name):
request.addfinalizer(lambda: sys.modules.pop(name, None)) request.addfinalizer(lambda: sys.modules.pop(name, None))
return inner return inner
@ -132,4 +170,4 @@ def purge_module(request):
def catch_deprecation_warnings(recwarn): def catch_deprecation_warnings(recwarn):
yield yield
gc.collect() gc.collect()
assert not recwarn.list assert not recwarn.list, '\n'.join(str(w.message) for w in recwarn.list)

58
tests/test_appctx.py

@ -14,8 +14,7 @@ import pytest
import flask import flask
def test_basic_url_generation(): def test_basic_url_generation(app):
app = flask.Flask(__name__)
app.config['SERVER_NAME'] = 'localhost' app.config['SERVER_NAME'] = 'localhost'
app.config['PREFERRED_URL_SCHEME'] = 'https' app.config['PREFERRED_URL_SCHEME'] = 'https'
@ -27,31 +26,33 @@ def test_basic_url_generation():
rv = flask.url_for('index') rv = flask.url_for('index')
assert rv == 'https://localhost/' assert rv == 'https://localhost/'
def test_url_generation_requires_server_name():
app = flask.Flask(__name__) def test_url_generation_requires_server_name(app):
with app.app_context(): with app.app_context():
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError):
flask.url_for('index') flask.url_for('index')
def test_url_generation_without_context_fails(): def test_url_generation_without_context_fails():
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError):
flask.url_for('index') flask.url_for('index')
def test_request_context_means_app_context():
app = flask.Flask(__name__) def test_request_context_means_app_context(app):
with app.test_request_context(): with app.test_request_context():
assert flask.current_app._get_current_object() == app assert flask.current_app._get_current_object() == app
assert flask._app_ctx_stack.top is None assert flask._app_ctx_stack.top is None
def test_app_context_provides_current_app():
app = flask.Flask(__name__) def test_app_context_provides_current_app(app):
with app.app_context(): with app.app_context():
assert flask.current_app._get_current_object() == app assert flask.current_app._get_current_object() == app
assert flask._app_ctx_stack.top is None assert flask._app_ctx_stack.top is None
def test_app_tearing_down():
def test_app_tearing_down(app):
cleanup_stuff = [] cleanup_stuff = []
app = flask.Flask(__name__)
@app.teardown_appcontext @app.teardown_appcontext
def cleanup(exception): def cleanup(exception):
cleanup_stuff.append(exception) cleanup_stuff.append(exception)
@ -61,9 +62,10 @@ def test_app_tearing_down():
assert cleanup_stuff == [None] assert cleanup_stuff == [None]
def test_app_tearing_down_with_previous_exception():
def test_app_tearing_down_with_previous_exception(app):
cleanup_stuff = [] cleanup_stuff = []
app = flask.Flask(__name__)
@app.teardown_appcontext @app.teardown_appcontext
def cleanup(exception): def cleanup(exception):
cleanup_stuff.append(exception) cleanup_stuff.append(exception)
@ -78,9 +80,10 @@ def test_app_tearing_down_with_previous_exception():
assert cleanup_stuff == [None] assert cleanup_stuff == [None]
def test_app_tearing_down_with_handled_exception():
def test_app_tearing_down_with_handled_exception(app):
cleanup_stuff = [] cleanup_stuff = []
app = flask.Flask(__name__)
@app.teardown_appcontext @app.teardown_appcontext
def cleanup(exception): def cleanup(exception):
cleanup_stuff.append(exception) cleanup_stuff.append(exception)
@ -93,9 +96,8 @@ def test_app_tearing_down_with_handled_exception():
assert cleanup_stuff == [None] assert cleanup_stuff == [None]
def test_app_ctx_globals_methods():
app = flask.Flask(__name__) def test_app_ctx_globals_methods(app, app_ctx):
with app.app_context():
# get # get
assert flask.g.get('foo') is None assert flask.g.get('foo') is None
assert flask.g.get('foo', 'bar') == 'bar' assert flask.g.get('foo', 'bar') == 'bar'
@ -115,24 +117,28 @@ def test_app_ctx_globals_methods():
# __iter__ # __iter__
assert list(flask.g) == ['foo'] assert list(flask.g) == ['foo']
def test_custom_app_ctx_globals_class():
def test_custom_app_ctx_globals_class(app):
class CustomRequestGlobals(object): class CustomRequestGlobals(object):
def __init__(self): def __init__(self):
self.spam = 'eggs' self.spam = 'eggs'
app = flask.Flask(__name__)
app.app_ctx_globals_class = CustomRequestGlobals app.app_ctx_globals_class = CustomRequestGlobals
with app.app_context(): with app.app_context():
assert flask.render_template_string('{{ g.spam }}') == 'eggs' assert flask.render_template_string('{{ g.spam }}') == 'eggs'
def test_context_refcounts():
def test_context_refcounts(app, client):
called = [] called = []
app = flask.Flask(__name__)
@app.teardown_request @app.teardown_request
def teardown_req(error=None): def teardown_req(error=None):
called.append('request') called.append('request')
@app.teardown_appcontext @app.teardown_appcontext
def teardown_app(error=None): def teardown_app(error=None):
called.append('app') called.append('app')
@app.route('/') @app.route('/')
def index(): def index():
with flask._app_ctx_stack.top: with flask._app_ctx_stack.top:
@ -141,16 +147,16 @@ def test_context_refcounts():
env = flask._request_ctx_stack.top.request.environ env = flask._request_ctx_stack.top.request.environ
assert env['werkzeug.request'] is not None assert env['werkzeug.request'] is not None
return u'' return u''
c = app.test_client()
res = c.get('/') res = client.get('/')
assert res.status_code == 200 assert res.status_code == 200
assert res.data == b'' assert res.data == b''
assert called == ['request', 'app'] assert called == ['request', 'app']
def test_clean_pop(): def test_clean_pop(app):
app.testing = False
called = [] called = []
app = flask.Flask(__name__)
@app.teardown_request @app.teardown_request
def teardown_req(error=None): def teardown_req(error=None):
@ -166,5 +172,5 @@ def test_clean_pop():
except ZeroDivisionError: except ZeroDivisionError:
pass pass
assert called == ['test_appctx', 'TEARDOWN'] assert called == ['conftest', 'TEARDOWN']
assert not flask.current_app assert not flask.current_app

429
tests/test_basic.py

File diff suppressed because it is too large Load Diff

278
tests/test_blueprints.py

@ -18,7 +18,7 @@ from werkzeug.http import parse_cache_control_header
from jinja2 import TemplateNotFound from jinja2 import TemplateNotFound
def test_blueprint_specific_error_handling(): def test_blueprint_specific_error_handling(app, client):
frontend = flask.Blueprint('frontend', __name__) frontend = flask.Blueprint('frontend', __name__)
backend = flask.Blueprint('backend', __name__) backend = flask.Blueprint('backend', __name__)
sideend = flask.Blueprint('sideend', __name__) sideend = flask.Blueprint('sideend', __name__)
@ -43,7 +43,6 @@ def test_blueprint_specific_error_handling():
def sideend_no(): def sideend_no():
flask.abort(403) flask.abort(403)
app = flask.Flask(__name__)
app.register_blueprint(frontend) app.register_blueprint(frontend)
app.register_blueprint(backend) app.register_blueprint(backend)
app.register_blueprint(sideend) app.register_blueprint(sideend)
@ -52,15 +51,15 @@ def test_blueprint_specific_error_handling():
def app_forbidden(e): def app_forbidden(e):
return 'application itself says no', 403 return 'application itself says no', 403
c = app.test_client() assert client.get('/frontend-no').data == b'frontend says no'
assert client.get('/backend-no').data == b'backend says no'
assert client.get('/what-is-a-sideend').data == b'application itself says no'
assert c.get('/frontend-no').data == b'frontend says no'
assert c.get('/backend-no').data == b'backend says no'
assert c.get('/what-is-a-sideend').data == b'application itself says no'
def test_blueprint_specific_user_error_handling(): def test_blueprint_specific_user_error_handling(app, client):
class MyDecoratorException(Exception): class MyDecoratorException(Exception):
pass pass
class MyFunctionException(Exception): class MyFunctionException(Exception):
pass pass
@ -74,32 +73,30 @@ def test_blueprint_specific_user_error_handling():
def my_function_exception_handler(e): def my_function_exception_handler(e):
assert isinstance(e, MyFunctionException) assert isinstance(e, MyFunctionException)
return 'bam' return 'bam'
blue.register_error_handler(MyFunctionException, my_function_exception_handler) blue.register_error_handler(MyFunctionException, my_function_exception_handler)
@blue.route('/decorator') @blue.route('/decorator')
def blue_deco_test(): def blue_deco_test():
raise MyDecoratorException() raise MyDecoratorException()
@blue.route('/function') @blue.route('/function')
def blue_func_test(): def blue_func_test():
raise MyFunctionException() raise MyFunctionException()
app = flask.Flask(__name__)
app.register_blueprint(blue) app.register_blueprint(blue)
c = app.test_client() assert client.get('/decorator').data == b'boom'
assert client.get('/function').data == b'bam'
assert c.get('/decorator').data == b'boom'
assert c.get('/function').data == b'bam'
def test_blueprint_app_error_handling(): def test_blueprint_app_error_handling(app, client):
errors = flask.Blueprint('errors', __name__) errors = flask.Blueprint('errors', __name__)
@errors.app_errorhandler(403) @errors.app_errorhandler(403)
def forbidden_handler(e): def forbidden_handler(e):
return 'you shall not pass', 403 return 'you shall not pass', 403
app = flask.Flask(__name__)
@app.route('/forbidden') @app.route('/forbidden')
def app_forbidden(): def app_forbidden():
flask.abort(403) flask.abort(403)
@ -113,12 +110,11 @@ def test_blueprint_app_error_handling():
app.register_blueprint(errors) app.register_blueprint(errors)
app.register_blueprint(forbidden_bp) app.register_blueprint(forbidden_bp)
c = app.test_client() assert client.get('/forbidden').data == b'you shall not pass'
assert client.get('/nope').data == b'you shall not pass'
assert c.get('/forbidden').data == b'you shall not pass'
assert c.get('/nope').data == b'you shall not pass'
def test_blueprint_url_definitions(): def test_blueprint_url_definitions(app, client):
bp = flask.Blueprint('test', __name__) bp = flask.Blueprint('test', __name__)
@bp.route('/foo', defaults={'baz': 42}) @bp.route('/foo', defaults={'baz': 42})
@ -129,17 +125,16 @@ def test_blueprint_url_definitions():
def bar(bar): def bar(bar):
return text_type(bar) return text_type(bar)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/1', url_defaults={'bar': 23}) app.register_blueprint(bp, url_prefix='/1', url_defaults={'bar': 23})
app.register_blueprint(bp, url_prefix='/2', url_defaults={'bar': 19}) app.register_blueprint(bp, url_prefix='/2', url_defaults={'bar': 19})
c = app.test_client() assert client.get('/1/foo').data == b'23/42'
assert c.get('/1/foo').data == b'23/42' assert client.get('/2/foo').data == b'19/42'
assert c.get('/2/foo').data == b'19/42' assert client.get('/1/bar').data == b'23'
assert c.get('/1/bar').data == b'23' assert client.get('/2/bar').data == b'19'
assert c.get('/2/bar').data == b'19'
def test_blueprint_url_processors():
def test_blueprint_url_processors(app, client):
bp = flask.Blueprint('frontend', __name__, url_prefix='/<lang_code>') bp = flask.Blueprint('frontend', __name__, url_prefix='/<lang_code>')
@bp.url_defaults @bp.url_defaults
@ -158,28 +153,26 @@ def test_blueprint_url_processors():
def about(): def about():
return flask.url_for('.index') return flask.url_for('.index')
app = flask.Flask(__name__)
app.register_blueprint(bp) app.register_blueprint(bp)
c = app.test_client() assert client.get('/de/').data == b'/de/about'
assert client.get('/de/about').data == b'/de/'
assert c.get('/de/').data == b'/de/about'
assert c.get('/de/about').data == b'/de/'
def test_templates_and_static(test_apps): def test_templates_and_static(test_apps):
from blueprintapp import app from blueprintapp import app
c = app.test_client() client = app.test_client()
rv = c.get('/') rv = client.get('/')
assert rv.data == b'Hello from the Frontend' assert rv.data == b'Hello from the Frontend'
rv = c.get('/admin/') rv = client.get('/admin/')
assert rv.data == b'Hello from the Admin' assert rv.data == b'Hello from the Admin'
rv = c.get('/admin/index2') rv = client.get('/admin/index2')
assert rv.data == b'Hello from the Admin' assert rv.data == b'Hello from the Admin'
rv = c.get('/admin/static/test.txt') rv = client.get('/admin/static/test.txt')
assert rv.data.strip() == b'Admin File' assert rv.data.strip() == b'Admin File'
rv.close() rv.close()
rv = c.get('/admin/static/css/test.css') rv = client.get('/admin/static/css/test.css')
assert rv.data.strip() == b'/* nested file */' assert rv.data.strip() == b'/* nested file */'
rv.close() rv.close()
@ -190,7 +183,7 @@ def test_templates_and_static(test_apps):
if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == expected_max_age: if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == expected_max_age:
expected_max_age = 7200 expected_max_age = 7200
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = expected_max_age app.config['SEND_FILE_MAX_AGE_DEFAULT'] = expected_max_age
rv = c.get('/admin/static/css/test.css') rv = client.get('/admin/static/css/test.css')
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
assert cc.max_age == expected_max_age assert cc.max_age == expected_max_age
rv.close() rv.close()
@ -208,8 +201,10 @@ def test_templates_and_static(test_apps):
with flask.Flask(__name__).test_request_context(): with flask.Flask(__name__).test_request_context():
assert flask.render_template('nested/nested.txt') == 'I\'m nested' assert flask.render_template('nested/nested.txt') == 'I\'m nested'
def test_default_static_cache_timeout(): def test_default_static_cache_timeout():
app = flask.Flask(__name__) app = flask.Flask(__name__)
class MyBlueprint(flask.Blueprint): class MyBlueprint(flask.Blueprint):
def get_send_file_max_age(self, filename): def get_send_file_max_age(self, filename):
return 100 return 100
@ -232,12 +227,14 @@ def test_default_static_cache_timeout():
finally: finally:
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default
def test_templates_list(test_apps): def test_templates_list(test_apps):
from blueprintapp import app from blueprintapp import app
templates = sorted(app.jinja_env.list_templates()) templates = sorted(app.jinja_env.list_templates())
assert templates == ['admin/index.html', 'frontend/index.html'] assert templates == ['admin/index.html', 'frontend/index.html']
def test_dotted_names():
def test_dotted_names(app, client):
frontend = flask.Blueprint('myapp.frontend', __name__) frontend = flask.Blueprint('myapp.frontend', __name__)
backend = flask.Blueprint('myapp.backend', __name__) backend = flask.Blueprint('myapp.backend', __name__)
@ -253,18 +250,15 @@ def test_dotted_names():
def backend_index(): def backend_index():
return flask.url_for('myapp.frontend.frontend_index') return flask.url_for('myapp.frontend.frontend_index')
app = flask.Flask(__name__)
app.register_blueprint(frontend) app.register_blueprint(frontend)
app.register_blueprint(backend) app.register_blueprint(backend)
c = app.test_client() assert client.get('/fe').data.strip() == b'/be'
assert c.get('/fe').data.strip() == b'/be' assert client.get('/fe2').data.strip() == b'/fe'
assert c.get('/fe2').data.strip() == b'/fe' assert client.get('/be').data.strip() == b'/fe'
assert c.get('/be').data.strip() == b'/fe'
def test_dotted_names_from_app():
app = flask.Flask(__name__) def test_dotted_names_from_app(app, client):
app.testing = True
test = flask.Blueprint('test', __name__) test = flask.Blueprint('test', __name__)
@app.route('/') @app.route('/')
@ -277,11 +271,11 @@ def test_dotted_names_from_app():
app.register_blueprint(test) app.register_blueprint(test)
with app.test_client() as c: rv = client.get('/')
rv = c.get('/')
assert rv.data == b'/test/' assert rv.data == b'/test/'
def test_empty_url_defaults():
def test_empty_url_defaults(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.route('/', defaults={'page': 1}) @bp.route('/', defaults={'page': 1})
@ -289,15 +283,13 @@ def test_empty_url_defaults():
def something(page): def something(page):
return str(page) return str(page)
app = flask.Flask(__name__)
app.register_blueprint(bp) app.register_blueprint(bp)
c = app.test_client() assert client.get('/').data == b'1'
assert c.get('/').data == b'1' assert client.get('/page/2').data == b'2'
assert c.get('/page/2').data == b'2'
def test_route_decorator_custom_endpoint():
def test_route_decorator_custom_endpoint(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.route('/foo') @bp.route('/foo')
@ -316,21 +308,20 @@ def test_route_decorator_custom_endpoint():
def bar_foo(): def bar_foo():
return flask.request.endpoint return flask.request.endpoint
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
@app.route('/') @app.route('/')
def index(): def index():
return flask.request.endpoint return flask.request.endpoint
c = app.test_client() assert client.get('/').data == b'index'
assert c.get('/').data == b'index' assert client.get('/py/foo').data == b'bp.foo'
assert c.get('/py/foo').data == b'bp.foo' assert client.get('/py/bar').data == b'bp.bar'
assert c.get('/py/bar').data == b'bp.bar' assert client.get('/py/bar/123').data == b'bp.123'
assert c.get('/py/bar/123').data == b'bp.123' assert client.get('/py/bar/foo').data == b'bp.bar_foo'
assert c.get('/py/bar/foo').data == b'bp.bar_foo'
def test_route_decorator_custom_endpoint_with_dots(): def test_route_decorator_custom_endpoint_with_dots(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.route('/foo') @bp.route('/foo')
@ -371,21 +362,18 @@ def test_route_decorator_custom_endpoint_with_dots():
lambda: None lambda: None
) )
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
c = app.test_client() assert client.get('/py/foo').data == b'bp.foo'
assert c.get('/py/foo').data == b'bp.foo'
# The rule's didn't actually made it through # The rule's didn't actually made it through
rv = c.get('/py/bar') rv = client.get('/py/bar')
assert rv.status_code == 404 assert rv.status_code == 404
rv = c.get('/py/bar/123') rv = client.get('/py/bar/123')
assert rv.status_code == 404 assert rv.status_code == 404
def test_endpoint_decorator(): def test_endpoint_decorator(app, client):
from werkzeug.routing import Rule from werkzeug.routing import Rule
app = flask.Flask(__name__)
app.url_map.add(Rule('/foo', endpoint='bar')) app.url_map.add(Rule('/foo', endpoint='bar'))
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@ -396,229 +384,282 @@ def test_endpoint_decorator():
app.register_blueprint(bp, url_prefix='/bp_prefix') app.register_blueprint(bp, url_prefix='/bp_prefix')
c = app.test_client() assert client.get('/foo').data == b'bar'
assert c.get('/foo').data == b'bar' assert client.get('/bp_prefix/bar').status_code == 404
assert c.get('/bp_prefix/bar').status_code == 404
def test_template_filter(): def test_template_filter(app):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter() @bp.app_template_filter()
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
assert 'my_reverse' in app.jinja_env.filters.keys() assert 'my_reverse' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['my_reverse'] == my_reverse assert app.jinja_env.filters['my_reverse'] == my_reverse
assert app.jinja_env.filters['my_reverse']('abcd') == 'dcba' assert app.jinja_env.filters['my_reverse']('abcd') == 'dcba'
def test_add_template_filter():
def test_add_template_filter(app):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
bp.add_app_template_filter(my_reverse) bp.add_app_template_filter(my_reverse)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
assert 'my_reverse' in app.jinja_env.filters.keys() assert 'my_reverse' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['my_reverse'] == my_reverse assert app.jinja_env.filters['my_reverse'] == my_reverse
assert app.jinja_env.filters['my_reverse']('abcd') == 'dcba' assert app.jinja_env.filters['my_reverse']('abcd') == 'dcba'
def test_template_filter_with_name():
def test_template_filter_with_name(app):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter('strrev') @bp.app_template_filter('strrev')
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
assert 'strrev' in app.jinja_env.filters.keys() assert 'strrev' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['strrev'] == my_reverse assert app.jinja_env.filters['strrev'] == my_reverse
assert app.jinja_env.filters['strrev']('abcd') == 'dcba' assert app.jinja_env.filters['strrev']('abcd') == 'dcba'
def test_add_template_filter_with_name():
def test_add_template_filter_with_name(app):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
bp.add_app_template_filter(my_reverse, 'strrev') bp.add_app_template_filter(my_reverse, 'strrev')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
assert 'strrev' in app.jinja_env.filters.keys() assert 'strrev' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['strrev'] == my_reverse assert app.jinja_env.filters['strrev'] == my_reverse
assert app.jinja_env.filters['strrev']('abcd') == 'dcba' assert app.jinja_env.filters['strrev']('abcd') == 'dcba'
def test_template_filter_with_template():
def test_template_filter_with_template(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter() @bp.app_template_filter()
def super_reverse(s): def super_reverse(s):
return s[::-1] return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_filter.html', value='abcd') return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
rv = client.get('/')
assert rv.data == b'dcba' assert rv.data == b'dcba'
def test_template_filter_after_route_with_template():
app = flask.Flask(__name__) def test_template_filter_after_route_with_template(app, client):
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_filter.html', value='abcd') return flask.render_template('template_filter.html', value='abcd')
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter() @bp.app_template_filter()
def super_reverse(s): def super_reverse(s):
return s[::-1] return s[::-1]
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
rv = app.test_client().get('/') rv = client.get('/')
assert rv.data == b'dcba' assert rv.data == b'dcba'
def test_add_template_filter_with_template():
def test_add_template_filter_with_template(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
def super_reverse(s): def super_reverse(s):
return s[::-1] return s[::-1]
bp.add_app_template_filter(super_reverse) bp.add_app_template_filter(super_reverse)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_filter.html', value='abcd') return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
rv = client.get('/')
assert rv.data == b'dcba' assert rv.data == b'dcba'
def test_template_filter_with_name_and_template():
def test_template_filter_with_name_and_template(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter('super_reverse') @bp.app_template_filter('super_reverse')
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_filter.html', value='abcd') return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
rv = client.get('/')
assert rv.data == b'dcba' assert rv.data == b'dcba'
def test_add_template_filter_with_name_and_template():
def test_add_template_filter_with_name_and_template(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
bp.add_app_template_filter(my_reverse, 'super_reverse') bp.add_app_template_filter(my_reverse, 'super_reverse')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_filter.html', value='abcd') return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
rv = client.get('/')
assert rv.data == b'dcba' assert rv.data == b'dcba'
def test_template_test():
def test_template_test(app):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_test() @bp.app_template_test()
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
assert 'is_boolean' in app.jinja_env.tests.keys() assert 'is_boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['is_boolean'] == is_boolean assert app.jinja_env.tests['is_boolean'] == is_boolean
assert app.jinja_env.tests['is_boolean'](False) assert app.jinja_env.tests['is_boolean'](False)
def test_add_template_test():
def test_add_template_test(app):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
bp.add_app_template_test(is_boolean) bp.add_app_template_test(is_boolean)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
assert 'is_boolean' in app.jinja_env.tests.keys() assert 'is_boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['is_boolean'] == is_boolean assert app.jinja_env.tests['is_boolean'] == is_boolean
assert app.jinja_env.tests['is_boolean'](False) assert app.jinja_env.tests['is_boolean'](False)
def test_template_test_with_name():
def test_template_test_with_name(app):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_test('boolean') @bp.app_template_test('boolean')
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
assert 'boolean' in app.jinja_env.tests.keys() assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == is_boolean assert app.jinja_env.tests['boolean'] == is_boolean
assert app.jinja_env.tests['boolean'](False) assert app.jinja_env.tests['boolean'](False)
def test_add_template_test_with_name():
def test_add_template_test_with_name(app):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
bp.add_app_template_test(is_boolean, 'boolean') bp.add_app_template_test(is_boolean, 'boolean')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
assert 'boolean' in app.jinja_env.tests.keys() assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == is_boolean assert app.jinja_env.tests['boolean'] == is_boolean
assert app.jinja_env.tests['boolean'](False) assert app.jinja_env.tests['boolean'](False)
def test_template_test_with_template():
def test_template_test_with_template(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_test() @bp.app_template_test()
def boolean(value): def boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_test.html', value=False) return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
rv = client.get('/')
assert b'Success!' in rv.data assert b'Success!' in rv.data
def test_template_test_after_route_with_template():
app = flask.Flask(__name__) def test_template_test_after_route_with_template(app, client):
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_test.html', value=False) return flask.render_template('template_test.html', value=False)
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_test() @bp.app_template_test()
def boolean(value): def boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
rv = app.test_client().get('/') rv = client.get('/')
assert b'Success!' in rv.data assert b'Success!' in rv.data
def test_add_template_test_with_template():
def test_add_template_test_with_template(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
def boolean(value): def boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
bp.add_app_template_test(boolean) bp.add_app_template_test(boolean)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_test.html', value=False) return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
rv = client.get('/')
assert b'Success!' in rv.data assert b'Success!' in rv.data
def test_template_test_with_name_and_template():
def test_template_test_with_name_and_template(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_test('boolean') @bp.app_template_test('boolean')
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_test.html', value=False) return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
rv = client.get('/')
assert b'Success!' in rv.data assert b'Success!' in rv.data
def test_add_template_test_with_name_and_template():
def test_add_template_test_with_name_and_template(app, client):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
bp.add_app_template_test(is_boolean, 'boolean') bp.add_app_template_test(is_boolean, 'boolean')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py') app.register_blueprint(bp, url_prefix='/py')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_test.html', value=False) return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
rv = client.get('/')
assert b'Success!' in rv.data assert b'Success!' in rv.data
def test_context_processing(): def test_context_processing():
app = flask.Flask(__name__) app = flask.Flask(__name__)
answer_bp = flask.Blueprint('answer_bp', __name__) answer_bp = flask.Blueprint('answer_bp', __name__)
@ -661,12 +702,15 @@ def test_context_processing():
assert b'42' in answer_page_bytes assert b'42' in answer_page_bytes
assert b'43' in answer_page_bytes assert b'43' in answer_page_bytes
def test_template_global(): def test_template_global():
app = flask.Flask(__name__) app = flask.Flask(__name__)
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.app_template_global() @bp.app_template_global()
def get_answer(): def get_answer():
return 42 return 42
# Make sure the function is not in the jinja_env already # Make sure the function is not in the jinja_env already
assert 'get_answer' not in app.jinja_env.globals.keys() assert 'get_answer' not in app.jinja_env.globals.keys()
app.register_blueprint(bp) app.register_blueprint(bp)

13
tests/test_deprecations.py

@ -15,10 +15,8 @@ import flask
class TestRequestDeprecation(object): class TestRequestDeprecation(object):
def test_request_json(self, recwarn, app, client):
def test_request_json(self, recwarn):
"""Request.json is deprecated""" """Request.json is deprecated"""
app = flask.Flask(__name__)
app.testing = True app.testing = True
@app.route('/', methods=['POST']) @app.route('/', methods=['POST'])
@ -27,13 +25,11 @@ class TestRequestDeprecation(object):
print(flask.request.json) print(flask.request.json)
return 'OK' return 'OK'
c = app.test_client() client.post('/', data='{"spam": 42}', content_type='application/json')
c.post('/', data='{"spam": 42}', content_type='application/json')
recwarn.pop(DeprecationWarning) recwarn.pop(DeprecationWarning)
def test_request_module(self, recwarn): def test_request_module(self, recwarn, app, client):
"""Request.module is deprecated""" """Request.module is deprecated"""
app = flask.Flask(__name__)
app.testing = True app.testing = True
@app.route('/') @app.route('/')
@ -41,6 +37,5 @@ class TestRequestDeprecation(object):
assert flask.request.module is None assert flask.request.module is None
return 'OK' return 'OK'
c = app.test_client() client.get('/')
c.get('/')
recwarn.pop(DeprecationWarning) recwarn.pop(DeprecationWarning)

319
tests/test_helpers.py

@ -35,192 +35,174 @@ def has_encoding(name):
class TestJSON(object): class TestJSON(object):
def test_ignore_cached_json(self, app):
def test_ignore_cached_json(self):
app = flask.Flask(__name__)
with app.test_request_context('/', method='POST', data='malformed', with app.test_request_context('/', method='POST', data='malformed',
content_type='application/json'): content_type='application/json'):
assert flask.request.get_json(silent=True, cache=True) is None assert flask.request.get_json(silent=True, cache=True) is None
with pytest.raises(BadRequest): with pytest.raises(BadRequest):
flask.request.get_json(silent=False, cache=False) flask.request.get_json(silent=False, cache=False)
def test_post_empty_json_adds_exception_to_response_content_in_debug(self): def test_post_empty_json_adds_exception_to_response_content_in_debug(self, app, client):
app = flask.Flask(__name__)
app.config['DEBUG'] = True app.config['DEBUG'] = True
@app.route('/json', methods=['POST']) @app.route('/json', methods=['POST'])
def post_json(): def post_json():
flask.request.get_json() flask.request.get_json()
return None return None
c = app.test_client()
rv = c.post('/json', data=None, content_type='application/json') rv = client.post('/json', data=None, content_type='application/json')
assert rv.status_code == 400 assert rv.status_code == 400
assert b'Failed to decode JSON object' in rv.data assert b'Failed to decode JSON object' in rv.data
def test_post_empty_json_wont_add_exception_to_response_if_no_debug(self): def test_post_empty_json_wont_add_exception_to_response_if_no_debug(self, app, client):
app = flask.Flask(__name__)
app.config['DEBUG'] = False app.config['DEBUG'] = False
@app.route('/json', methods=['POST']) @app.route('/json', methods=['POST'])
def post_json(): def post_json():
flask.request.get_json() flask.request.get_json()
return None return None
c = app.test_client()
rv = c.post('/json', data=None, content_type='application/json') rv = client.post('/json', data=None, content_type='application/json')
assert rv.status_code == 400 assert rv.status_code == 400
assert b'Failed to decode JSON object' not in rv.data assert b'Failed to decode JSON object' not in rv.data
def test_json_bad_requests(self): def test_json_bad_requests(self, app, client):
app = flask.Flask(__name__)
@app.route('/json', methods=['POST']) @app.route('/json', methods=['POST'])
def return_json(): def return_json():
return flask.jsonify(foo=text_type(flask.request.get_json())) return flask.jsonify(foo=text_type(flask.request.get_json()))
c = app.test_client()
rv = c.post('/json', data='malformed', content_type='application/json') rv = client.post('/json', data='malformed', content_type='application/json')
assert rv.status_code == 400 assert rv.status_code == 400
def test_json_custom_mimetypes(self): def test_json_custom_mimetypes(self, app, client):
app = flask.Flask(__name__)
@app.route('/json', methods=['POST']) @app.route('/json', methods=['POST'])
def return_json(): def return_json():
return flask.request.get_json() return flask.request.get_json()
c = app.test_client()
rv = c.post('/json', data='"foo"', content_type='application/x+json') rv = client.post('/json', data='"foo"', content_type='application/x+json')
assert rv.data == b'foo' assert rv.data == b'foo'
def test_json_body_encoding(self): def test_json_body_encoding(self, app, client):
app = flask.Flask(__name__)
app.testing = True app.testing = True
@app.route('/') @app.route('/')
def index(): def index():
return flask.request.get_json() return flask.request.get_json()
c = app.test_client() resp = client.get('/', data=u'"Hällo Wörld"'.encode('iso-8859-15'),
resp = c.get('/', data=u'"Hällo Wörld"'.encode('iso-8859-15'),
content_type='application/json; charset=iso-8859-15') content_type='application/json; charset=iso-8859-15')
assert resp.data == u'Hällo Wörld'.encode('utf-8') assert resp.data == u'Hällo Wörld'.encode('utf-8')
def test_json_as_unicode(self): @pytest.mark.parametrize('test_value,expected', [(True, '"\\u2603"'), (False, u'"\u2603"')])
app = flask.Flask(__name__) def test_json_as_unicode(self, test_value, expected, app, app_ctx):
app.config['JSON_AS_ASCII'] = True app.config['JSON_AS_ASCII'] = test_value
with app.app_context():
rv = flask.json.dumps(u'\N{SNOWMAN}') rv = flask.json.dumps(u'\N{SNOWMAN}')
assert rv == '"\\u2603"' assert rv == expected
app.config['JSON_AS_ASCII'] = False def test_json_dump_to_file(self, app, app_ctx):
with app.app_context():
rv = flask.json.dumps(u'\N{SNOWMAN}')
assert rv == u'"\u2603"'
def test_json_dump_to_file(self):
app = flask.Flask(__name__)
test_data = {'name': 'Flask'} test_data = {'name': 'Flask'}
out = StringIO() out = StringIO()
with app.app_context():
flask.json.dump(test_data, out) flask.json.dump(test_data, out)
out.seek(0) out.seek(0)
rv = flask.json.load(out) rv = flask.json.load(out)
assert rv == test_data assert rv == test_data
@pytest.mark.parametrize('test_value', [0, -1, 1, 23, 3.14, 's', "longer string", True, False, None]) @pytest.mark.parametrize('test_value', [0, -1, 1, 23, 3.14, 's', "longer string", True, False, None])
def test_jsonify_basic_types(self, test_value): def test_jsonify_basic_types(self, test_value, app, client):
"""Test jsonify with basic types.""" """Test jsonify with basic types."""
app = flask.Flask(__name__)
c = app.test_client()
url = '/jsonify_basic_types' url = '/jsonify_basic_types'
app.add_url_rule(url, url, lambda x=test_value: flask.jsonify(x)) app.add_url_rule(url, url, lambda x=test_value: flask.jsonify(x))
rv = c.get(url) rv = client.get(url)
assert rv.mimetype == 'application/json' assert rv.mimetype == 'application/json'
assert flask.json.loads(rv.data) == test_value assert flask.json.loads(rv.data) == test_value
def test_jsonify_dicts(self): def test_jsonify_dicts(self, app, client):
"""Test jsonify with dicts and kwargs unpacking.""" """Test jsonify with dicts and kwargs unpacking."""
d = dict( d = {'a': 0, 'b': 23, 'c': 3.14, 'd': 't',
a=0, b=23, c=3.14, d='t', e='Hi', f=True, g=False, 'e': 'Hi', 'f': True, 'g': False,
h=['test list', 10, False], 'h': ['test list', 10, False],
i={'test':'dict'} 'i': {'test': 'dict'}}
)
app = flask.Flask(__name__)
@app.route('/kw') @app.route('/kw')
def return_kwargs(): def return_kwargs():
return flask.jsonify(**d) return flask.jsonify(**d)
@app.route('/dict') @app.route('/dict')
def return_dict(): def return_dict():
return flask.jsonify(d) return flask.jsonify(d)
c = app.test_client()
for url in '/kw', '/dict': for url in '/kw', '/dict':
rv = c.get(url) rv = client.get(url)
assert rv.mimetype == 'application/json' assert rv.mimetype == 'application/json'
assert flask.json.loads(rv.data) == d assert flask.json.loads(rv.data) == d
def test_jsonify_arrays(self): def test_jsonify_arrays(self, app, client):
"""Test jsonify of lists and args unpacking.""" """Test jsonify of lists and args unpacking."""
l = [ l = [
0, 42, 3.14, 't', 'hello', True, False, 0, 42, 3.14, 't', 'hello', True, False,
['test list', 2, False], ['test list', 2, False],
{'test':'dict'} {'test': 'dict'}
] ]
app = flask.Flask(__name__)
@app.route('/args_unpack') @app.route('/args_unpack')
def return_args_unpack(): def return_args_unpack():
return flask.jsonify(*l) return flask.jsonify(*l)
@app.route('/array') @app.route('/array')
def return_array(): def return_array():
return flask.jsonify(l) return flask.jsonify(l)
c = app.test_client()
for url in '/args_unpack', '/array': for url in '/args_unpack', '/array':
rv = c.get(url) rv = client.get(url)
assert rv.mimetype == 'application/json' assert rv.mimetype == 'application/json'
assert flask.json.loads(rv.data) == l assert flask.json.loads(rv.data) == l
def test_jsonify_date_types(self): def test_jsonify_date_types(self, app, client):
"""Test jsonify with datetime.date and datetime.datetime types.""" """Test jsonify with datetime.date and datetime.datetime types."""
test_dates = ( test_dates = (
datetime.datetime(1973, 3, 11, 6, 30, 45), datetime.datetime(1973, 3, 11, 6, 30, 45),
datetime.date(1975, 1, 5) datetime.date(1975, 1, 5)
) )
app = flask.Flask(__name__)
c = app.test_client()
for i, d in enumerate(test_dates): for i, d in enumerate(test_dates):
url = '/datetest{0}'.format(i) url = '/datetest{0}'.format(i)
app.add_url_rule(url, str(i), lambda val=d: flask.jsonify(x=val)) app.add_url_rule(url, str(i), lambda val=d: flask.jsonify(x=val))
rv = c.get(url) rv = client.get(url)
assert rv.mimetype == 'application/json' assert rv.mimetype == 'application/json'
assert flask.json.loads(rv.data)['x'] == http_date(d.timetuple()) assert flask.json.loads(rv.data)['x'] == http_date(d.timetuple())
def test_jsonify_uuid_types(self): def test_jsonify_uuid_types(self, app, client):
"""Test jsonify with uuid.UUID types""" """Test jsonify with uuid.UUID types"""
test_uuid = uuid.UUID(bytes=b'\xDE\xAD\xBE\xEF' * 4) test_uuid = uuid.UUID(bytes=b'\xDE\xAD\xBE\xEF' * 4)
app = flask.Flask(__name__)
url = '/uuid_test' url = '/uuid_test'
app.add_url_rule(url, url, lambda: flask.jsonify(x=test_uuid)) app.add_url_rule(url, url, lambda: flask.jsonify(x=test_uuid))
c = app.test_client() rv = client.get(url)
rv = c.get(url)
rv_x = flask.json.loads(rv.data)['x'] rv_x = flask.json.loads(rv.data)['x']
assert rv_x == str(test_uuid) assert rv_x == str(test_uuid)
rv_uuid = uuid.UUID(rv_x) rv_uuid = uuid.UUID(rv_x)
assert rv_uuid == test_uuid assert rv_uuid == test_uuid
def test_json_attr(self): def test_json_attr(self, app, client):
app = flask.Flask(__name__)
@app.route('/add', methods=['POST']) @app.route('/add', methods=['POST'])
def add(): def add():
json = flask.request.get_json() json = flask.request.get_json()
return text_type(json['a'] + json['b']) return text_type(json['a'] + json['b'])
c = app.test_client()
rv = c.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}), rv = client.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}),
content_type='application/json') content_type='application/json')
assert rv.data == b'3' assert rv.data == b'3'
def test_template_escaping(self): def test_template_escaping(self, app, req_ctx):
app = flask.Flask(__name__)
render = flask.render_template_string render = flask.render_template_string
with app.test_request_context():
rv = flask.json.htmlsafe_dumps('</script>') rv = flask.json.htmlsafe_dumps('</script>')
assert rv == u'"\\u003c/script\\u003e"' assert rv == u'"\\u003c/script\\u003e"'
assert type(rv) == text_type assert type(rv) == text_type
@ -238,37 +220,41 @@ class TestJSON(object):
data={'x': ["foo", "bar", "baz'"]}) data={'x': ["foo", "bar", "baz'"]})
assert rv == '<a ng-data=\'{"x": ["foo", "bar", "baz\\u0027"]}\'></a>' assert rv == '<a ng-data=\'{"x": ["foo", "bar", "baz\\u0027"]}\'></a>'
def test_json_customization(self): def test_json_customization(self, app, client):
class X(object): class X(object):
def __init__(self, val): def __init__(self, val):
self.val = val self.val = val
class MyEncoder(flask.json.JSONEncoder): class MyEncoder(flask.json.JSONEncoder):
def default(self, o): def default(self, o):
if isinstance(o, X): if isinstance(o, X):
return '<%d>' % o.val return '<%d>' % o.val
return flask.json.JSONEncoder.default(self, o) return flask.json.JSONEncoder.default(self, o)
class MyDecoder(flask.json.JSONDecoder): class MyDecoder(flask.json.JSONDecoder):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs.setdefault('object_hook', self.object_hook) kwargs.setdefault('object_hook', self.object_hook)
flask.json.JSONDecoder.__init__(self, *args, **kwargs) flask.json.JSONDecoder.__init__(self, *args, **kwargs)
def object_hook(self, obj): def object_hook(self, obj):
if len(obj) == 1 and '_foo' in obj: if len(obj) == 1 and '_foo' in obj:
return X(obj['_foo']) return X(obj['_foo'])
return obj return obj
app = flask.Flask(__name__)
app.testing = True app.testing = True
app.json_encoder = MyEncoder app.json_encoder = MyEncoder
app.json_decoder = MyDecoder app.json_decoder = MyDecoder
@app.route('/', methods=['POST']) @app.route('/', methods=['POST'])
def index(): def index():
return flask.json.dumps(flask.request.get_json()['x']) return flask.json.dumps(flask.request.get_json()['x'])
c = app.test_client()
rv = c.post('/', data=flask.json.dumps({ rv = client.post('/', data=flask.json.dumps({
'x': {'_foo': 42} 'x': {'_foo': 42}
}), content_type='application/json') }), content_type='application/json')
assert rv.data == b'"<42>"' assert rv.data == b'"<42>"'
def test_blueprint_json_customization(self): def test_blueprint_json_customization(self, app, client):
class X(object): class X(object):
def __init__(self, val): def __init__(self, val):
self.val = val self.val = val
@ -299,20 +285,18 @@ class TestJSON(object):
def index(): def index():
return flask.json.dumps(flask.request.get_json()['x']) return flask.json.dumps(flask.request.get_json()['x'])
app = flask.Flask(__name__)
app.testing = True app.testing = True
app.register_blueprint(bp) app.register_blueprint(bp)
c = app.test_client() rv = client.post('/bp', data=flask.json.dumps({
rv = c.post('/bp', data=flask.json.dumps({
'x': {'_foo': 42} 'x': {'_foo': 42}
}), content_type='application/json') }), content_type='application/json')
assert rv.data == b'"<42>"' assert rv.data == b'"<42>"'
def test_modified_url_encoding(self): def test_modified_url_encoding(self, app):
class ModifiedRequest(flask.Request): class ModifiedRequest(flask.Request):
url_charset = 'euc-kr' url_charset = 'euc-kr'
app = flask.Flask(__name__)
app.testing = True app.testing = True
app.request_class = ModifiedRequest app.request_class = ModifiedRequest
app.url_map.charset = 'euc-kr' app.url_map.charset = 'euc-kr'
@ -328,8 +312,7 @@ class TestJSON(object):
if not has_encoding('euc-kr'): if not has_encoding('euc-kr'):
test_modified_url_encoding = None test_modified_url_encoding = None
def test_json_key_sorting(self): def test_json_key_sorting(self, app, client):
app = flask.Flask(__name__)
app.testing = True app.testing = True
app.debug = True app.debug = True
@ -340,8 +323,7 @@ class TestJSON(object):
def index(): def index():
return flask.jsonify(values=d) return flask.jsonify(values=d)
c = app.test_client() rv = client.get('/')
rv = c.get('/')
lines = [x.strip() for x in rv.data.strip().decode('utf-8').splitlines()] lines = [x.strip() for x in rv.data.strip().decode('utf-8').splitlines()]
sorted_by_str = [ sorted_by_str = [
'{', '{',
@ -401,11 +383,9 @@ class TestJSON(object):
except AssertionError: except AssertionError:
assert lines == sorted_by_str assert lines == sorted_by_str
class TestSendfile(object):
def test_send_file_regular(self): class TestSendfile(object):
app = flask.Flask(__name__) def test_send_file_regular(self, app, req_ctx):
with app.test_request_context():
rv = flask.send_file('static/index.html') rv = flask.send_file('static/index.html')
assert rv.direct_passthrough assert rv.direct_passthrough
assert rv.mimetype == 'text/html' assert rv.mimetype == 'text/html'
@ -414,10 +394,8 @@ class TestSendfile(object):
assert rv.data == f.read() assert rv.data == f.read()
rv.close() rv.close()
def test_send_file_xsendfile(self, catch_deprecation_warnings): def test_send_file_xsendfile(self, app, req_ctx, catch_deprecation_warnings):
app = flask.Flask(__name__)
app.use_x_sendfile = True app.use_x_sendfile = True
with app.test_request_context():
rv = flask.send_file('static/index.html') rv = flask.send_file('static/index.html')
assert rv.direct_passthrough assert rv.direct_passthrough
assert 'x-sendfile' in rv.headers assert 'x-sendfile' in rv.headers
@ -426,8 +404,7 @@ class TestSendfile(object):
assert rv.mimetype == 'text/html' assert rv.mimetype == 'text/html'
rv.close() rv.close()
def test_send_file_last_modified(self): def test_send_file_last_modified(self, app, client):
app = flask.Flask(__name__)
last_modified = datetime.datetime(1999, 1, 1) last_modified = datetime.datetime(1999, 1, 1)
@app.route('/') @app.route('/')
@ -436,26 +413,18 @@ class TestSendfile(object):
last_modified=last_modified, last_modified=last_modified,
mimetype='text/plain') mimetype='text/plain')
c = app.test_client() rv = client.get('/')
rv = c.get('/')
assert rv.last_modified == last_modified assert rv.last_modified == last_modified
def test_send_file_object_without_mimetype(self): def test_send_file_object_without_mimetype(self, app, req_ctx):
app = flask.Flask(__name__)
with app.test_request_context():
with pytest.raises(ValueError) as excinfo: with pytest.raises(ValueError) as excinfo:
flask.send_file(StringIO("LOL")) flask.send_file(StringIO("LOL"))
assert 'Unable to infer MIME-type' in str(excinfo) assert 'Unable to infer MIME-type' in str(excinfo)
assert 'no filename is available' in str(excinfo) assert 'no filename is available' in str(excinfo)
with app.test_request_context():
flask.send_file(StringIO("LOL"), attachment_filename='filename') flask.send_file(StringIO("LOL"), attachment_filename='filename')
def test_send_file_object(self): def test_send_file_object(self, app, req_ctx):
app = flask.Flask(__name__)
with app.test_request_context():
with open(os.path.join(app.root_path, 'static/index.html'), mode='rb') as f: with open(os.path.join(app.root_path, 'static/index.html'), mode='rb') as f:
rv = flask.send_file(f, mimetype='text/html') rv = flask.send_file(f, mimetype='text/html')
rv.direct_passthrough = False rv.direct_passthrough = False
@ -466,7 +435,6 @@ class TestSendfile(object):
app.use_x_sendfile = True app.use_x_sendfile = True
with app.test_request_context():
with open(os.path.join(app.root_path, 'static/index.html')) as f: with open(os.path.join(app.root_path, 'static/index.html')) as f:
rv = flask.send_file(f, mimetype='text/html') rv = flask.send_file(f, mimetype='text/html')
assert rv.mimetype == 'text/html' assert rv.mimetype == 'text/html'
@ -474,7 +442,6 @@ class TestSendfile(object):
rv.close() rv.close()
app.use_x_sendfile = False app.use_x_sendfile = False
with app.test_request_context():
f = StringIO('Test') f = StringIO('Test')
rv = flask.send_file(f, mimetype='application/octet-stream') rv = flask.send_file(f, mimetype='application/octet-stream')
rv.direct_passthrough = False rv.direct_passthrough = False
@ -485,8 +452,10 @@ class TestSendfile(object):
class PyStringIO(object): class PyStringIO(object):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._io = StringIO(*args, **kwargs) self._io = StringIO(*args, **kwargs)
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self._io, name) return getattr(self._io, name)
f = PyStringIO('Test') f = PyStringIO('Test')
f.name = 'test.txt' f.name = 'test.txt'
rv = flask.send_file(f, attachment_filename=f.name) rv = flask.send_file(f, attachment_filename=f.name)
@ -504,7 +473,6 @@ class TestSendfile(object):
app.use_x_sendfile = True app.use_x_sendfile = True
with app.test_request_context():
f = StringIO('Test') f = StringIO('Test')
rv = flask.send_file(f, mimetype='text/html') rv = flask.send_file(f, mimetype='text/html')
assert 'x-sendfile' not in rv.headers assert 'x-sendfile' not in rv.headers
@ -514,48 +482,44 @@ class TestSendfile(object):
not callable(getattr(Range, 'to_content_range_header', None)), not callable(getattr(Range, 'to_content_range_header', None)),
reason="not implement within werkzeug" reason="not implement within werkzeug"
) )
def test_send_file_range_request(self): def test_send_file_range_request(self, app, client):
app = flask.Flask(__name__)
@app.route('/') @app.route('/')
def index(): def index():
return flask.send_file('static/index.html', conditional=True) return flask.send_file('static/index.html', conditional=True)
c = app.test_client() rv = client.get('/', headers={'Range': 'bytes=4-15'})
rv = c.get('/', headers={'Range': 'bytes=4-15'})
assert rv.status_code == 206 assert rv.status_code == 206
with app.open_resource('static/index.html') as f: with app.open_resource('static/index.html') as f:
assert rv.data == f.read()[4:16] assert rv.data == f.read()[4:16]
rv.close() rv.close()
rv = c.get('/', headers={'Range': 'bytes=4-'}) rv = client.get('/', headers={'Range': 'bytes=4-'})
assert rv.status_code == 206 assert rv.status_code == 206
with app.open_resource('static/index.html') as f: with app.open_resource('static/index.html') as f:
assert rv.data == f.read()[4:] assert rv.data == f.read()[4:]
rv.close() rv.close()
rv = c.get('/', headers={'Range': 'bytes=4-1000'}) rv = client.get('/', headers={'Range': 'bytes=4-1000'})
assert rv.status_code == 206 assert rv.status_code == 206
with app.open_resource('static/index.html') as f: with app.open_resource('static/index.html') as f:
assert rv.data == f.read()[4:] assert rv.data == f.read()[4:]
rv.close() rv.close()
rv = c.get('/', headers={'Range': 'bytes=-10'}) rv = client.get('/', headers={'Range': 'bytes=-10'})
assert rv.status_code == 206 assert rv.status_code == 206
with app.open_resource('static/index.html') as f: with app.open_resource('static/index.html') as f:
assert rv.data == f.read()[-10:] assert rv.data == f.read()[-10:]
rv.close() rv.close()
rv = c.get('/', headers={'Range': 'bytes=1000-'}) rv = client.get('/', headers={'Range': 'bytes=1000-'})
assert rv.status_code == 416 assert rv.status_code == 416
rv.close() rv.close()
rv = c.get('/', headers={'Range': 'bytes=-'}) rv = client.get('/', headers={'Range': 'bytes=-'})
assert rv.status_code == 416 assert rv.status_code == 416
rv.close() rv.close()
rv = c.get('/', headers={'Range': 'somethingsomething'}) rv = client.get('/', headers={'Range': 'somethingsomething'})
assert rv.status_code == 416 assert rv.status_code == 416
rv.close() rv.close()
@ -563,19 +527,19 @@ class TestSendfile(object):
os.path.join(app.root_path, 'static/index.html'))).replace( os.path.join(app.root_path, 'static/index.html'))).replace(
microsecond=0) microsecond=0)
rv = c.get('/', headers={'Range': 'bytes=4-15', rv = client.get('/', headers={'Range': 'bytes=4-15',
'If-Range': http_date(last_modified)}) 'If-Range': http_date(last_modified)})
assert rv.status_code == 206 assert rv.status_code == 206
rv.close() rv.close()
rv = c.get('/', headers={'Range': 'bytes=4-15', 'If-Range': http_date( rv = client.get('/', headers={'Range': 'bytes=4-15', 'If-Range': http_date(
datetime.datetime(1999, 1, 1))}) datetime.datetime(1999, 1, 1))})
assert rv.status_code == 200 assert rv.status_code == 200
rv.close() rv.close()
def test_attachment(self): def test_attachment(self, app, req_ctx):
app = flask.Flask(__name__) app = flask.Flask(__name__)
with app.test_request_context():
with open(os.path.join(app.root_path, 'static/index.html')) as f: with open(os.path.join(app.root_path, 'static/index.html')) as f:
rv = flask.send_file(f, as_attachment=True, rv = flask.send_file(f, as_attachment=True,
attachment_filename='index.html') attachment_filename='index.html')
@ -586,14 +550,12 @@ class TestSendfile(object):
assert 'filename*' not in rv.headers['Content-Disposition'] assert 'filename*' not in rv.headers['Content-Disposition']
rv.close() rv.close()
with app.test_request_context():
rv = flask.send_file('static/index.html', as_attachment=True) rv = flask.send_file('static/index.html', as_attachment=True)
value, options = parse_options_header(rv.headers['Content-Disposition']) value, options = parse_options_header(rv.headers['Content-Disposition'])
assert value == 'attachment' assert value == 'attachment'
assert options['filename'] == 'index.html' assert options['filename'] == 'index.html'
rv.close() rv.close()
with app.test_request_context():
rv = flask.send_file(StringIO('Test'), as_attachment=True, rv = flask.send_file(StringIO('Test'), as_attachment=True,
attachment_filename='index.txt', attachment_filename='index.txt',
add_etags=False) add_etags=False)
@ -603,10 +565,7 @@ class TestSendfile(object):
assert options['filename'] == 'index.txt' assert options['filename'] == 'index.txt'
rv.close() rv.close()
def test_attachment_with_utf8_filename(self): def test_attachment_with_utf8_filename(self, app, req_ctx):
app = flask.Flask(__name__)
with app.test_request_context():
rv = flask.send_file('static/index.html', as_attachment=True, attachment_filename=u'Ñandú/pingüino.txt') rv = flask.send_file('static/index.html', as_attachment=True, attachment_filename=u'Ñandú/pingüino.txt')
content_disposition = set(rv.headers['Content-Disposition'].split('; ')) content_disposition = set(rv.headers['Content-Disposition'].split('; '))
assert content_disposition == set(( assert content_disposition == set((
@ -616,10 +575,9 @@ class TestSendfile(object):
)) ))
rv.close() rv.close()
def test_static_file(self): def test_static_file(self, app, req_ctx):
app = flask.Flask(__name__)
# default cache timeout is 12 hours # default cache timeout is 12 hours
with app.test_request_context():
# Test with static file handler. # Test with static file handler.
rv = app.send_static_file('index.html') rv = app.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
@ -631,7 +589,7 @@ class TestSendfile(object):
assert cc.max_age == 12 * 60 * 60 assert cc.max_age == 12 * 60 * 60
rv.close() rv.close()
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600 app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600
with app.test_request_context():
# Test with static file handler. # Test with static file handler.
rv = app.send_static_file('index.html') rv = app.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
@ -642,9 +600,11 @@ class TestSendfile(object):
cc = parse_cache_control_header(rv.headers['Cache-Control']) cc = parse_cache_control_header(rv.headers['Cache-Control'])
assert cc.max_age == 3600 assert cc.max_age == 3600
rv.close() rv.close()
class StaticFileApp(flask.Flask): class StaticFileApp(flask.Flask):
def get_send_file_max_age(self, filename): def get_send_file_max_age(self, filename):
return 10 return 10
app = StaticFileApp(__name__) app = StaticFileApp(__name__)
with app.test_request_context(): with app.test_request_context():
# Test with static file handler. # Test with static file handler.
@ -658,28 +618,25 @@ class TestSendfile(object):
assert cc.max_age == 10 assert cc.max_age == 10
rv.close() rv.close()
def test_send_from_directory(self): def test_send_from_directory(self, app, req_ctx):
app = flask.Flask(__name__)
app.testing = True app.testing = True
app.root_path = os.path.join(os.path.dirname(__file__), app.root_path = os.path.join(os.path.dirname(__file__),
'test_apps', 'subdomaintestmodule') 'test_apps', 'subdomaintestmodule')
with app.test_request_context():
rv = flask.send_from_directory('static', 'hello.txt') rv = flask.send_from_directory('static', 'hello.txt')
rv.direct_passthrough = False rv.direct_passthrough = False
assert rv.data.strip() == b'Hello Subdomain' assert rv.data.strip() == b'Hello Subdomain'
rv.close() rv.close()
def test_send_from_directory_bad_request(self): def test_send_from_directory_bad_request(self, app, req_ctx):
app = flask.Flask(__name__)
app.testing = True app.testing = True
app.root_path = os.path.join(os.path.dirname(__file__), app.root_path = os.path.join(os.path.dirname(__file__),
'test_apps', 'subdomaintestmodule') 'test_apps', 'subdomaintestmodule')
with app.test_request_context():
with pytest.raises(BadRequest): with pytest.raises(BadRequest):
flask.send_from_directory('static', 'bad\x00') flask.send_from_directory('static', 'bad\x00')
class TestLogging(object):
class TestLogging(object):
def test_logger_cache(self): def test_logger_cache(self):
app = flask.Flask(__name__) app = flask.Flask(__name__)
logger1 = app.logger logger1 = app.logger
@ -713,19 +670,18 @@ class TestLogging(object):
with pytest.raises(ZeroDivisionError): with pytest.raises(ZeroDivisionError):
c.get('/exc') c.get('/exc')
def test_debug_log_override(self): def test_debug_log_override(self, app):
app = flask.Flask(__name__)
app.debug = True app.debug = True
app.logger_name = 'flask_tests/test_debug_log_override' app.logger_name = 'flask_tests/test_debug_log_override'
app.logger.level = 10 app.logger.level = 10
assert app.logger.level == 10 assert app.logger.level == 10
def test_exception_logging(self): def test_exception_logging(self, app):
out = StringIO() out = StringIO()
app = flask.Flask(__name__)
app.config['LOGGER_HANDLER_POLICY'] = 'never' app.config['LOGGER_HANDLER_POLICY'] = 'never'
app.logger_name = 'flask_tests/test_exception_logging' app.logger_name = 'flask_tests/test_exception_logging'
app.logger.addHandler(StreamHandler(out)) app.logger.addHandler(StreamHandler(out))
app.testing = False
@app.route('/') @app.route('/')
def index(): def index():
@ -741,76 +697,83 @@ class TestLogging(object):
assert '1 // 0' in err assert '1 // 0' in err
assert 'ZeroDivisionError:' in err assert 'ZeroDivisionError:' in err
def test_processor_exceptions(self): def test_processor_exceptions(self, app, client):
app = flask.Flask(__name__)
app.config['LOGGER_HANDLER_POLICY'] = 'never' app.config['LOGGER_HANDLER_POLICY'] = 'never'
app.testing = False
@app.before_request @app.before_request
def before_request(): def before_request():
if trigger == 'before': if trigger == 'before':
1 // 0 1 // 0
@app.after_request @app.after_request
def after_request(response): def after_request(response):
if trigger == 'after': if trigger == 'after':
1 // 0 1 // 0
return response return response
@app.route('/') @app.route('/')
def index(): def index():
return 'Foo' return 'Foo'
@app.errorhandler(500) @app.errorhandler(500)
def internal_server_error(e): def internal_server_error(e):
return 'Hello Server Error', 500 return 'Hello Server Error', 500
for trigger in 'before', 'after': for trigger in 'before', 'after':
rv = app.test_client().get('/') rv = client.get('/')
assert rv.status_code == 500 assert rv.status_code == 500
assert rv.data == b'Hello Server Error' assert rv.data == b'Hello Server Error'
def test_url_for_with_anchor(self): def test_url_for_with_anchor(self, app, req_ctx):
app = flask.Flask(__name__)
@app.route('/') @app.route('/')
def index(): def index():
return '42' return '42'
with app.test_request_context():
assert flask.url_for('index', _anchor='x y') == '/#x%20y' assert flask.url_for('index', _anchor='x y') == '/#x%20y'
def test_url_for_with_scheme(self): def test_url_for_with_scheme(self, app, req_ctx):
app = flask.Flask(__name__)
@app.route('/') @app.route('/')
def index(): def index():
return '42' return '42'
with app.test_request_context():
assert flask.url_for('index', _external=True, _scheme='https') == 'https://localhost/' assert flask.url_for('index', _external=True, _scheme='https') == 'https://localhost/'
def test_url_for_with_scheme_not_external(self): def test_url_for_with_scheme_not_external(self, app, req_ctx):
app = flask.Flask(__name__)
@app.route('/') @app.route('/')
def index(): def index():
return '42' return '42'
with app.test_request_context():
pytest.raises(ValueError, pytest.raises(ValueError,
flask.url_for, flask.url_for,
'index', 'index',
_scheme='https') _scheme='https')
def test_url_for_with_alternating_schemes(self): def test_url_for_with_alternating_schemes(self, app, req_ctx):
app = flask.Flask(__name__)
@app.route('/') @app.route('/')
def index(): def index():
return '42' return '42'
with app.test_request_context():
assert flask.url_for('index', _external=True) == 'http://localhost/' assert flask.url_for('index', _external=True) == 'http://localhost/'
assert flask.url_for('index', _external=True, _scheme='https') == 'https://localhost/' assert flask.url_for('index', _external=True, _scheme='https') == 'https://localhost/'
assert flask.url_for('index', _external=True) == 'http://localhost/' assert flask.url_for('index', _external=True) == 'http://localhost/'
def test_url_with_method(self): def test_url_with_method(self, app, req_ctx):
from flask.views import MethodView from flask.views import MethodView
app = flask.Flask(__name__)
class MyView(MethodView): class MyView(MethodView):
def get(self, id=None): def get(self, id=None):
if id is None: if id is None:
return 'List' return 'List'
return 'Get %d' % id return 'Get %d' % id
def post(self): def post(self):
return 'Create' return 'Create'
myview = MyView.as_view('myview') myview = MyView.as_view('myview')
app.add_url_rule('/myview/', methods=['GET'], app.add_url_rule('/myview/', methods=['GET'],
view_func=myview) view_func=myview)
@ -819,7 +782,6 @@ class TestLogging(object):
app.add_url_rule('/myview/create', methods=['POST'], app.add_url_rule('/myview/create', methods=['POST'],
view_func=myview) view_func=myview)
with app.test_request_context():
assert flask.url_for('myview', _method='GET') == '/myview/' assert flask.url_for('myview', _method='GET') == '/myview/'
assert flask.url_for('myview', id=42, _method='GET') == '/myview/42' assert flask.url_for('myview', id=42, _method='GET') == '/myview/42'
assert flask.url_for('myview', _method='POST') == '/myview/create' assert flask.url_for('myview', _method='POST') == '/myview/create'
@ -845,24 +807,24 @@ class TestNoImports(object):
class TestStreaming(object): class TestStreaming(object):
def test_streaming_with_context(self, app, client):
def test_streaming_with_context(self):
app = flask.Flask(__name__)
app.testing = True app.testing = True
@app.route('/') @app.route('/')
def index(): def index():
def generate(): def generate():
yield 'Hello ' yield 'Hello '
yield flask.request.args['name'] yield flask.request.args['name']
yield '!' yield '!'
return flask.Response(flask.stream_with_context(generate())) return flask.Response(flask.stream_with_context(generate()))
c = app.test_client()
rv = c.get('/?name=World') rv = client.get('/?name=World')
assert rv.data == b'Hello World!' assert rv.data == b'Hello World!'
def test_streaming_with_context_as_decorator(self): def test_streaming_with_context_as_decorator(self, app, client):
app = flask.Flask(__name__)
app.testing = True app.testing = True
@app.route('/') @app.route('/')
def index(): def index():
@flask.stream_with_context @flask.stream_with_context
@ -870,35 +832,42 @@ class TestStreaming(object):
yield hello yield hello
yield flask.request.args['name'] yield flask.request.args['name']
yield '!' yield '!'
return flask.Response(generate('Hello ')) return flask.Response(generate('Hello '))
c = app.test_client()
rv = c.get('/?name=World') rv = client.get('/?name=World')
assert rv.data == b'Hello World!' assert rv.data == b'Hello World!'
def test_streaming_with_context_and_custom_close(self): def test_streaming_with_context_and_custom_close(self, app, client):
app = flask.Flask(__name__)
app.testing = True app.testing = True
called = [] called = []
class Wrapper(object): class Wrapper(object):
def __init__(self, gen): def __init__(self, gen):
self._gen = gen self._gen = gen
def __iter__(self): def __iter__(self):
return self return self
def close(self): def close(self):
called.append(42) called.append(42)
def __next__(self): def __next__(self):
return next(self._gen) return next(self._gen)
next = __next__ next = __next__
@app.route('/') @app.route('/')
def index(): def index():
def generate(): def generate():
yield 'Hello ' yield 'Hello '
yield flask.request.args['name'] yield flask.request.args['name']
yield '!' yield '!'
return flask.Response(flask.stream_with_context( return flask.Response(flask.stream_with_context(
Wrapper(generate()))) Wrapper(generate())))
c = app.test_client()
rv = c.get('/?name=World') rv = client.get('/?name=World')
assert rv.data == b'Hello World!' assert rv.data == b'Hello World!'
assert called == [42] assert called == [42]
@ -920,7 +889,7 @@ class TestSafeJoin(object):
(('a/b/c', 'X/..'), 'a/b/c/.'), (('a/b/c', 'X/..'), 'a/b/c/.'),
# Base directory is always considered safe # Base directory is always considered safe
(('../', 'a/b/c'), '../a/b/c'), (('../', 'a/b/c'), '../a/b/c'),
(('/..', ), '/..'), (('/..',), '/..'),
) )
for args, expected in passing: for args, expected in passing:

7
tests/test_regression.py

@ -9,15 +9,14 @@
:license: BSD, see LICENSE for more details. :license: BSD, see LICENSE for more details.
""" """
import pytest
import os
import gc import gc
import sys import sys
import flask
import threading import threading
import pytest
from werkzeug.exceptions import NotFound from werkzeug.exceptions import NotFound
import flask
_gc_lock = threading.Lock() _gc_lock = threading.Lock()

47
tests/test_reqctx.py

@ -20,9 +20,9 @@ except ImportError:
greenlet = None greenlet = None
def test_teardown_on_pop(): def test_teardown_on_pop(app):
buffer = [] buffer = []
app = flask.Flask(__name__)
@app.teardown_request @app.teardown_request
def end_of_request(exception): def end_of_request(exception):
buffer.append(exception) buffer.append(exception)
@ -33,9 +33,10 @@ def test_teardown_on_pop():
ctx.pop() ctx.pop()
assert buffer == [None] assert buffer == [None]
def test_teardown_with_previous_exception():
def test_teardown_with_previous_exception(app):
buffer = [] buffer = []
app = flask.Flask(__name__)
@app.teardown_request @app.teardown_request
def end_of_request(exception): def end_of_request(exception):
buffer.append(exception) buffer.append(exception)
@ -49,9 +50,10 @@ def test_teardown_with_previous_exception():
assert buffer == [] assert buffer == []
assert buffer == [None] assert buffer == [None]
def test_teardown_with_handled_exception():
def test_teardown_with_handled_exception(app):
buffer = [] buffer = []
app = flask.Flask(__name__)
@app.teardown_request @app.teardown_request
def end_of_request(exception): def end_of_request(exception):
buffer.append(exception) buffer.append(exception)
@ -64,8 +66,8 @@ def test_teardown_with_handled_exception():
pass pass
assert buffer == [None] assert buffer == [None]
def test_proper_test_request_context():
app = flask.Flask(__name__) def test_proper_test_request_context(app):
app.config.update( app.config.update(
SERVER_NAME='localhost.localdomain:5000' SERVER_NAME='localhost.localdomain:5000'
) )
@ -104,11 +106,12 @@ def test_proper_test_request_context():
with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost:80'}): with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost:80'}):
pass pass
def test_context_binding():
app = flask.Flask(__name__) def test_context_binding(app):
@app.route('/') @app.route('/')
def index(): def index():
return 'Hello %s!' % flask.request.args['name'] return 'Hello %s!' % flask.request.args['name']
@app.route('/meh') @app.route('/meh')
def meh(): def meh():
return flask.request.url return flask.request.url
@ -119,8 +122,8 @@ def test_context_binding():
assert meh() == 'http://localhost/meh' assert meh() == 'http://localhost/meh'
assert flask._request_ctx_stack.top is None assert flask._request_ctx_stack.top is None
def test_context_test():
app = flask.Flask(__name__) def test_context_test(app):
assert not flask.request assert not flask.request
assert not flask.has_request_context() assert not flask.has_request_context()
ctx = app.test_request_context() ctx = app.test_request_context()
@ -131,8 +134,8 @@ def test_context_test():
finally: finally:
ctx.pop() ctx.pop()
def test_manual_context_binding():
app = flask.Flask(__name__) def test_manual_context_binding(app):
@app.route('/') @app.route('/')
def index(): def index():
return 'Hello %s!' % flask.request.args['name'] return 'Hello %s!' % flask.request.args['name']
@ -144,14 +147,15 @@ def test_manual_context_binding():
with pytest.raises(RuntimeError): with pytest.raises(RuntimeError):
index() index()
@pytest.mark.skipif(greenlet is None, reason='greenlet not installed') @pytest.mark.skipif(greenlet is None, reason='greenlet not installed')
def test_greenlet_context_copying(): def test_greenlet_context_copying(app, client):
app = flask.Flask(__name__)
greenlets = [] greenlets = []
@app.route('/') @app.route('/')
def index(): def index():
reqctx = flask._request_ctx_stack.top.copy() reqctx = flask._request_ctx_stack.top.copy()
def g(): def g():
assert not flask.request assert not flask.request
assert not flask.current_app assert not flask.current_app
@ -162,23 +166,25 @@ def test_greenlet_context_copying():
assert flask.request.args['foo'] == 'bar' assert flask.request.args['foo'] == 'bar'
assert not flask.request assert not flask.request
return 42 return 42
greenlets.append(greenlet(g)) greenlets.append(greenlet(g))
return 'Hello World!' return 'Hello World!'
rv = app.test_client().get('/?foo=bar') rv = client.get('/?foo=bar')
assert rv.data == b'Hello World!' assert rv.data == b'Hello World!'
result = greenlets[0].run() result = greenlets[0].run()
assert result == 42 assert result == 42
@pytest.mark.skipif(greenlet is None, reason='greenlet not installed') @pytest.mark.skipif(greenlet is None, reason='greenlet not installed')
def test_greenlet_context_copying_api(): def test_greenlet_context_copying_api(app, client):
app = flask.Flask(__name__)
greenlets = [] greenlets = []
@app.route('/') @app.route('/')
def index(): def index():
reqctx = flask._request_ctx_stack.top.copy() reqctx = flask._request_ctx_stack.top.copy()
@flask.copy_current_request_context @flask.copy_current_request_context
def g(): def g():
assert flask.request assert flask.request
@ -186,10 +192,11 @@ def test_greenlet_context_copying_api():
assert flask.request.path == '/' assert flask.request.path == '/'
assert flask.request.args['foo'] == 'bar' assert flask.request.args['foo'] == 'bar'
return 42 return 42
greenlets.append(greenlet(g)) greenlets.append(greenlet(g))
return 'Hello World!' return 'Hello World!'
rv = app.test_client().get('/?foo=bar') rv = client.get('/?foo=bar')
assert rv.data == b'Hello World!' assert rv.data == b'Hello World!'
result = greenlets[0].run() result = greenlets[0].run()

188
tests/test_templating.py

@ -16,40 +16,43 @@ import logging
from jinja2 import TemplateNotFound from jinja2 import TemplateNotFound
def test_context_processing(): def test_context_processing(app):
app = flask.Flask(__name__)
@app.context_processor @app.context_processor
def context_processor(): def context_processor():
return {'injected_value': 42} return {'injected_value': 42}
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('context_template.html', value=23) return flask.render_template('context_template.html', value=23)
rv = app.test_client().get('/') rv = app.test_client().get('/')
assert rv.data == b'<p>23|42' assert rv.data == b'<p>23|42'
def test_original_win():
app = flask.Flask(__name__) def test_original_win(app, client):
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template_string('{{ config }}', config=42) return flask.render_template_string('{{ config }}', config=42)
rv = app.test_client().get('/')
rv = client.get('/')
assert rv.data == b'42' assert rv.data == b'42'
def test_request_less_rendering():
app = flask.Flask(__name__) def test_request_less_rendering(app, app_ctx):
app.config['WORLD_NAME'] = 'Special World' app.config['WORLD_NAME'] = 'Special World'
@app.context_processor @app.context_processor
def context_processor(): def context_processor():
return dict(foo=42) return dict(foo=42)
with app.app_context():
rv = flask.render_template_string('Hello {{ config.WORLD_NAME }} ' rv = flask.render_template_string('Hello {{ config.WORLD_NAME }} '
'{{ foo }}') '{{ foo }}')
assert rv == 'Hello Special World 42' assert rv == 'Hello Special World 42'
def test_standard_context():
app = flask.Flask(__name__) def test_standard_context(app, client):
app.secret_key = 'development key' app.secret_key = 'development key'
@app.route('/') @app.route('/')
def index(): def index():
flask.g.foo = 23 flask.g.foo = 23
@ -60,17 +63,20 @@ def test_standard_context():
{{ config.DEBUG }} {{ config.DEBUG }}
{{ session.test }} {{ session.test }}
''') ''')
rv = app.test_client().get('/?foo=42')
rv = client.get('/?foo=42')
assert rv.data.split() == [b'42', b'23', b'False', b'aha'] assert rv.data.split() == [b'42', b'23', b'False', b'aha']
def test_escaping():
def test_escaping(app, client):
text = '<p>Hello World!' text = '<p>Hello World!'
app = flask.Flask(__name__)
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('escaping_template.html', text=text, return flask.render_template('escaping_template.html', text=text,
html=flask.Markup(text)) html=flask.Markup(text))
lines = app.test_client().get('/').data.splitlines()
lines = client.get('/').data.splitlines()
assert lines == [ assert lines == [
b'&lt;p&gt;Hello World!', b'&lt;p&gt;Hello World!',
b'<p>Hello World!', b'<p>Hello World!',
@ -80,14 +86,16 @@ def test_escaping():
b'<p>Hello World!' b'<p>Hello World!'
] ]
def test_no_escaping():
def test_no_escaping(app, client):
text = '<p>Hello World!' text = '<p>Hello World!'
app = flask.Flask(__name__)
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('non_escaping_template.txt', text=text, return flask.render_template('non_escaping_template.txt', text=text,
html=flask.Markup(text)) html=flask.Markup(text))
lines = app.test_client().get('/').data.splitlines()
lines = client.get('/').data.splitlines()
assert lines == [ assert lines == [
b'<p>Hello World!', b'<p>Hello World!',
b'<p>Hello World!', b'<p>Hello World!',
@ -99,210 +107,241 @@ def test_no_escaping():
b'<p>Hello World!' b'<p>Hello World!'
] ]
def test_escaping_without_template_filename():
app = flask.Flask(__name__) def test_escaping_without_template_filename(app, client, req_ctx):
with app.test_request_context():
assert flask.render_template_string( assert flask.render_template_string(
'{{ foo }}', foo='<test>') == '&lt;test&gt;' '{{ foo }}', foo='<test>') == '&lt;test&gt;'
assert flask.render_template('mail.txt', foo='<test>') == \ assert flask.render_template('mail.txt', foo='<test>') == '<test> Mail'
'<test> Mail'
def test_macros():
app = flask.Flask(__name__) def test_macros(app, req_ctx):
with app.test_request_context():
macro = flask.get_template_attribute('_macro.html', 'hello') macro = flask.get_template_attribute('_macro.html', 'hello')
assert macro('World') == 'Hello World!' assert macro('World') == 'Hello World!'
def test_template_filter():
app = flask.Flask(__name__) def test_template_filter(app):
@app.template_filter() @app.template_filter()
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
assert 'my_reverse' in app.jinja_env.filters.keys() assert 'my_reverse' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['my_reverse'] == my_reverse assert app.jinja_env.filters['my_reverse'] == my_reverse
assert app.jinja_env.filters['my_reverse']('abcd') == 'dcba' assert app.jinja_env.filters['my_reverse']('abcd') == 'dcba'
def test_add_template_filter():
app = flask.Flask(__name__) def test_add_template_filter(app):
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
app.add_template_filter(my_reverse) app.add_template_filter(my_reverse)
assert 'my_reverse' in app.jinja_env.filters.keys() assert 'my_reverse' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['my_reverse'] == my_reverse assert app.jinja_env.filters['my_reverse'] == my_reverse
assert app.jinja_env.filters['my_reverse']('abcd') == 'dcba' assert app.jinja_env.filters['my_reverse']('abcd') == 'dcba'
def test_template_filter_with_name():
app = flask.Flask(__name__) def test_template_filter_with_name(app):
@app.template_filter('strrev') @app.template_filter('strrev')
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
assert 'strrev' in app.jinja_env.filters.keys() assert 'strrev' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['strrev'] == my_reverse assert app.jinja_env.filters['strrev'] == my_reverse
assert app.jinja_env.filters['strrev']('abcd') == 'dcba' assert app.jinja_env.filters['strrev']('abcd') == 'dcba'
def test_add_template_filter_with_name():
app = flask.Flask(__name__) def test_add_template_filter_with_name(app):
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
app.add_template_filter(my_reverse, 'strrev') app.add_template_filter(my_reverse, 'strrev')
assert 'strrev' in app.jinja_env.filters.keys() assert 'strrev' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['strrev'] == my_reverse assert app.jinja_env.filters['strrev'] == my_reverse
assert app.jinja_env.filters['strrev']('abcd') == 'dcba' assert app.jinja_env.filters['strrev']('abcd') == 'dcba'
def test_template_filter_with_template():
app = flask.Flask(__name__) def test_template_filter_with_template(app, client):
@app.template_filter() @app.template_filter()
def super_reverse(s): def super_reverse(s):
return s[::-1] return s[::-1]
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_filter.html', value='abcd') return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
rv = client.get('/')
assert rv.data == b'dcba' assert rv.data == b'dcba'
def test_add_template_filter_with_template():
app = flask.Flask(__name__) def test_add_template_filter_with_template(app, client):
def super_reverse(s): def super_reverse(s):
return s[::-1] return s[::-1]
app.add_template_filter(super_reverse) app.add_template_filter(super_reverse)
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_filter.html', value='abcd') return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
rv = client.get('/')
assert rv.data == b'dcba' assert rv.data == b'dcba'
def test_template_filter_with_name_and_template():
app = flask.Flask(__name__) def test_template_filter_with_name_and_template(app, client):
@app.template_filter('super_reverse') @app.template_filter('super_reverse')
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_filter.html', value='abcd') return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
rv = client.get('/')
assert rv.data == b'dcba' assert rv.data == b'dcba'
def test_add_template_filter_with_name_and_template():
app = flask.Flask(__name__) def test_add_template_filter_with_name_and_template(app, client):
def my_reverse(s): def my_reverse(s):
return s[::-1] return s[::-1]
app.add_template_filter(my_reverse, 'super_reverse') app.add_template_filter(my_reverse, 'super_reverse')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_filter.html', value='abcd') return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
rv = client.get('/')
assert rv.data == b'dcba' assert rv.data == b'dcba'
def test_template_test():
app = flask.Flask(__name__) def test_template_test(app):
@app.template_test() @app.template_test()
def boolean(value): def boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
assert 'boolean' in app.jinja_env.tests.keys() assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == boolean assert app.jinja_env.tests['boolean'] == boolean
assert app.jinja_env.tests['boolean'](False) assert app.jinja_env.tests['boolean'](False)
def test_add_template_test():
app = flask.Flask(__name__) def test_add_template_test(app):
def boolean(value): def boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
app.add_template_test(boolean) app.add_template_test(boolean)
assert 'boolean' in app.jinja_env.tests.keys() assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == boolean assert app.jinja_env.tests['boolean'] == boolean
assert app.jinja_env.tests['boolean'](False) assert app.jinja_env.tests['boolean'](False)
def test_template_test_with_name():
app = flask.Flask(__name__) def test_template_test_with_name(app):
@app.template_test('boolean') @app.template_test('boolean')
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
assert 'boolean' in app.jinja_env.tests.keys() assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == is_boolean assert app.jinja_env.tests['boolean'] == is_boolean
assert app.jinja_env.tests['boolean'](False) assert app.jinja_env.tests['boolean'](False)
def test_add_template_test_with_name():
app = flask.Flask(__name__) def test_add_template_test_with_name(app):
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
app.add_template_test(is_boolean, 'boolean') app.add_template_test(is_boolean, 'boolean')
assert 'boolean' in app.jinja_env.tests.keys() assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == is_boolean assert app.jinja_env.tests['boolean'] == is_boolean
assert app.jinja_env.tests['boolean'](False) assert app.jinja_env.tests['boolean'](False)
def test_template_test_with_template():
app = flask.Flask(__name__) def test_template_test_with_template(app):
@app.template_test() @app.template_test()
def boolean(value): def boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_test.html', value=False) return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/') rv = app.test_client().get('/')
assert b'Success!' in rv.data assert b'Success!' in rv.data
def test_add_template_test_with_template():
app = flask.Flask(__name__) def test_add_template_test_with_template(app, client):
def boolean(value): def boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
app.add_template_test(boolean) app.add_template_test(boolean)
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_test.html', value=False) return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
rv = client.get('/')
assert b'Success!' in rv.data assert b'Success!' in rv.data
def test_template_test_with_name_and_template():
app = flask.Flask(__name__) def test_template_test_with_name_and_template(app, client):
@app.template_test('boolean') @app.template_test('boolean')
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_test.html', value=False) return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
rv = client.get('/')
assert b'Success!' in rv.data assert b'Success!' in rv.data
def test_add_template_test_with_name_and_template():
app = flask.Flask(__name__) def test_add_template_test_with_name_and_template(app, client):
def is_boolean(value): def is_boolean(value):
return isinstance(value, bool) return isinstance(value, bool)
app.add_template_test(is_boolean, 'boolean') app.add_template_test(is_boolean, 'boolean')
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('template_test.html', value=False) return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
rv = client.get('/')
assert b'Success!' in rv.data assert b'Success!' in rv.data
def test_add_template_global():
app = flask.Flask(__name__) def test_add_template_global(app, app_ctx):
@app.template_global() @app.template_global()
def get_stuff(): def get_stuff():
return 42 return 42
assert 'get_stuff' in app.jinja_env.globals.keys() assert 'get_stuff' in app.jinja_env.globals.keys()
assert app.jinja_env.globals['get_stuff'] == get_stuff assert app.jinja_env.globals['get_stuff'] == get_stuff
assert app.jinja_env.globals['get_stuff'](), 42 assert app.jinja_env.globals['get_stuff'](), 42
with app.app_context():
rv = flask.render_template_string('{{ get_stuff() }}') rv = flask.render_template_string('{{ get_stuff() }}')
assert rv == '42' assert rv == '42'
def test_custom_template_loader():
def test_custom_template_loader(client):
class MyFlask(flask.Flask): class MyFlask(flask.Flask):
def create_global_jinja_loader(self): def create_global_jinja_loader(self):
from jinja2 import DictLoader from jinja2 import DictLoader
return DictLoader({'index.html': 'Hello Custom World!'}) return DictLoader({'index.html': 'Hello Custom World!'})
app = MyFlask(__name__) app = MyFlask(__name__)
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template('index.html') return flask.render_template('index.html')
c = app.test_client() c = app.test_client()
rv = c.get('/') rv = c.get('/')
assert rv.data == b'Hello Custom World!' assert rv.data == b'Hello Custom World!'
def test_iterable_loader():
app = flask.Flask(__name__) def test_iterable_loader(app, client):
@app.context_processor @app.context_processor
def context_processor(): def context_processor():
return {'whiskey': 'Jameson'} return {'whiskey': 'Jameson'}
@app.route('/') @app.route('/')
def index(): def index():
return flask.render_template( return flask.render_template(
@ -311,12 +350,12 @@ def test_iterable_loader():
'context_template.html'], 'context_template.html'],
value=23) value=23)
rv = app.test_client().get('/') rv = client.get('/')
assert rv.data == b'<h1>Jameson</h1>' assert rv.data == b'<h1>Jameson</h1>'
def test_templates_auto_reload():
def test_templates_auto_reload(app):
# debug is False, config option is None # debug is False, config option is None
app = flask.Flask(__name__)
assert app.debug is False assert app.debug is False
assert app.config['TEMPLATES_AUTO_RELOAD'] is None assert app.config['TEMPLATES_AUTO_RELOAD'] is None
assert app.jinja_env.auto_reload is False assert app.jinja_env.auto_reload is False
@ -346,10 +385,12 @@ def test_templates_auto_reload():
app.config['TEMPLATES_AUTO_RELOAD'] = True app.config['TEMPLATES_AUTO_RELOAD'] = True
assert app.jinja_env.auto_reload is True assert app.jinja_env.auto_reload is True
def test_template_loader_debugging(test_apps): def test_template_loader_debugging(test_apps):
from blueprintapp import app from blueprintapp import app
called = [] called = []
class _TestHandler(logging.Handler): class _TestHandler(logging.Handler):
def handle(x, record): def handle(x, record):
called.append(True) called.append(True)
@ -381,6 +422,7 @@ def test_template_loader_debugging(test_apps):
assert len(called) == 1 assert len(called) == 1
def test_custom_jinja_env(): def test_custom_jinja_env():
class CustomEnvironment(flask.templating.Environment): class CustomEnvironment(flask.templating.Environment):
pass pass

76
tests/test_testing.py

@ -16,24 +16,22 @@ import werkzeug
from flask._compat import text_type from flask._compat import text_type
def test_environ_defaults_from_config(): def test_environ_defaults_from_config(app, client):
app = flask.Flask(__name__)
app.testing = True
app.config['SERVER_NAME'] = 'example.com:1234' app.config['SERVER_NAME'] = 'example.com:1234'
app.config['APPLICATION_ROOT'] = '/foo' app.config['APPLICATION_ROOT'] = '/foo'
@app.route('/') @app.route('/')
def index(): def index():
return flask.request.url return flask.request.url
ctx = app.test_request_context() ctx = app.test_request_context()
assert ctx.request.url == 'http://example.com:1234/foo/' assert ctx.request.url == 'http://example.com:1234/foo/'
with app.test_client() as c:
rv = c.get('/') rv = client.get('/')
assert rv.data == b'http://example.com:1234/foo/' assert rv.data == b'http://example.com:1234/foo/'
def test_environ_defaults():
app = flask.Flask(__name__) def test_environ_defaults(app, client, app_ctx, req_ctx):
app.testing = True
@app.route('/') @app.route('/')
def index(): def index():
return flask.request.url return flask.request.url
@ -44,42 +42,40 @@ def test_environ_defaults():
rv = c.get('/') rv = c.get('/')
assert rv.data == b'http://localhost/' assert rv.data == b'http://localhost/'
def test_environ_base_default():
app = flask.Flask(__name__) def test_environ_base_default(app, client, app_ctx):
app.testing = True app.testing = True
@app.route('/') @app.route('/')
def index(): def index():
flask.g.user_agent = flask.request.headers["User-Agent"] flask.g.user_agent = flask.request.headers["User-Agent"]
return flask.request.remote_addr return flask.request.remote_addr
with app.test_client() as c: rv = client.get('/')
rv = c.get('/')
assert rv.data == b'127.0.0.1' assert rv.data == b'127.0.0.1'
assert flask.g.user_agent == 'werkzeug/' + werkzeug.__version__ assert flask.g.user_agent == 'werkzeug/' + werkzeug.__version__
def test_environ_base_modified():
app = flask.Flask(__name__) def test_environ_base_modified(app, client, app_ctx):
app.testing = True
@app.route('/') @app.route('/')
def index(): def index():
flask.g.user_agent = flask.request.headers["User-Agent"] flask.g.user_agent = flask.request.headers["User-Agent"]
return flask.request.remote_addr return flask.request.remote_addr
with app.test_client() as c: client.environ_base['REMOTE_ADDR'] = '0.0.0.0'
c.environ_base['REMOTE_ADDR'] = '0.0.0.0' client.environ_base['HTTP_USER_AGENT'] = 'Foo'
c.environ_base['HTTP_USER_AGENT'] = 'Foo' rv = client.get('/')
rv = c.get('/')
assert rv.data == b'0.0.0.0' assert rv.data == b'0.0.0.0'
assert flask.g.user_agent == 'Foo' assert flask.g.user_agent == 'Foo'
c.environ_base['REMOTE_ADDR'] = '0.0.0.1' client.environ_base['REMOTE_ADDR'] = '0.0.0.1'
c.environ_base['HTTP_USER_AGENT'] = 'Bar' client.environ_base['HTTP_USER_AGENT'] = 'Bar'
rv = c.get('/') rv = client.get('/')
assert rv.data == b'0.0.0.1' assert rv.data == b'0.0.0.1'
assert flask.g.user_agent == 'Bar' assert flask.g.user_agent == 'Bar'
def test_redirect_keep_session():
app = flask.Flask(__name__) def test_redirect_keep_session(app, client, app_ctx):
app.secret_key = 'testing' app.secret_key = 'testing'
@app.route('/', methods=['GET', 'POST']) @app.route('/', methods=['GET', 'POST'])
@ -93,7 +89,7 @@ def test_redirect_keep_session():
def get_session(): def get_session():
return flask.session.get('data', '<missing>') return flask.session.get('data', '<missing>')
with app.test_client() as c: with client as c:
rv = c.get('/getsession') rv = c.get('/getsession')
assert rv.data == b'<missing>' assert rv.data == b'<missing>'
@ -110,9 +106,8 @@ def test_redirect_keep_session():
rv = c.get('/getsession') rv = c.get('/getsession')
assert rv.data == b'foo' assert rv.data == b'foo'
def test_session_transactions():
app = flask.Flask(__name__) def test_session_transactions(app):
app.testing = True
app.secret_key = 'testing' app.secret_key = 'testing'
@app.route('/') @app.route('/')
@ -130,6 +125,7 @@ def test_session_transactions():
assert len(sess) == 1 assert len(sess) == 1
assert sess['foo'] == [42] assert sess['foo'] == [42]
def test_session_transactions_no_null_sessions(): def test_session_transactions_no_null_sessions():
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.testing = True app.testing = True
@ -140,30 +136,28 @@ def test_session_transactions_no_null_sessions():
pass pass
assert 'Session backend did not open a session' in str(e.value) assert 'Session backend did not open a session' in str(e.value)
def test_session_transactions_keep_context():
app = flask.Flask(__name__) def test_session_transactions_keep_context(app, client, req_ctx):
app.testing = True
app.secret_key = 'testing' app.secret_key = 'testing'
with app.test_client() as c: rv = client.get('/')
rv = c.get('/')
req = flask.request._get_current_object() req = flask.request._get_current_object()
assert req is not None assert req is not None
with c.session_transaction(): with client.session_transaction():
assert req is flask.request._get_current_object() assert req is flask.request._get_current_object()
def test_session_transaction_needs_cookies(): def test_session_transaction_needs_cookies(app):
app = flask.Flask(__name__)
app.testing = True
c = app.test_client(use_cookies=False) c = app.test_client(use_cookies=False)
with pytest.raises(RuntimeError) as e: with pytest.raises(RuntimeError) as e:
with c.session_transaction() as s: with c.session_transaction() as s:
pass pass
assert 'cookies' in str(e.value) assert 'cookies' in str(e.value)
def test_test_client_context_binding(): def test_test_client_context_binding():
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config['LOGGER_HANDLER_POLICY'] = 'never' app.config['LOGGER_HANDLER_POLICY'] = 'never'
@app.route('/') @app.route('/')
def index(): def index():
flask.g.value = 42 flask.g.value = 42
@ -192,6 +186,7 @@ def test_test_client_context_binding():
else: else:
raise AssertionError('some kind of exception expected') raise AssertionError('some kind of exception expected')
def test_reuse_client(): def test_reuse_client():
app = flask.Flask(__name__) app = flask.Flask(__name__)
c = app.test_client() c = app.test_client()
@ -202,9 +197,11 @@ def test_reuse_client():
with c: with c:
assert c.get('/').status_code == 404 assert c.get('/').status_code == 404
def test_test_client_calls_teardown_handlers(): def test_test_client_calls_teardown_handlers():
app = flask.Flask(__name__) app = flask.Flask(__name__)
called = [] called = []
@app.teardown_request @app.teardown_request
def remember(error): def remember(error):
called.append(error) called.append(error)
@ -224,6 +221,7 @@ def test_test_client_calls_teardown_handlers():
assert called == [None] assert called == [None]
assert called == [None, None] assert called == [None, None]
def test_full_url_request(): def test_full_url_request():
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.testing = True app.testing = True
@ -238,9 +236,11 @@ def test_full_url_request():
assert 'gin' in flask.request.form assert 'gin' in flask.request.form
assert 'vodka' in flask.request.args assert 'vodka' in flask.request.args
def test_subdomain(): def test_subdomain():
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config['SERVER_NAME'] = 'example.com' app.config['SERVER_NAME'] = 'example.com'
@app.route('/', subdomain='<company_id>') @app.route('/', subdomain='<company_id>')
def view(company_id): def view(company_id):
return company_id return company_id
@ -254,9 +254,11 @@ def test_subdomain():
assert 200 == response.status_code assert 200 == response.status_code
assert b'xxx' == response.data assert b'xxx' == response.data
def test_nosubdomain(): def test_nosubdomain():
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config['SERVER_NAME'] = 'example.com' app.config['SERVER_NAME'] = 'example.com'
@app.route('/<company_id>') @app.route('/<company_id>')
def view(company_id): def view(company_id):
return company_id return company_id

22
tests/test_user_error_handler.py

@ -8,8 +8,7 @@ from werkzeug.exceptions import (
import flask import flask
def test_error_handler_no_match(): def test_error_handler_no_match(app, client):
app = flask.Flask(__name__)
class CustomException(Exception): class CustomException(Exception):
pass pass
@ -31,15 +30,12 @@ def test_error_handler_no_match():
def key_error(): def key_error():
raise KeyError() raise KeyError()
c = app.test_client() app.testing = False
assert client.get('/custom').data == b'custom'
assert c.get('/custom').data == b'custom' assert client.get('/keyerror').data == b'KeyError'
assert c.get('/keyerror').data == b'KeyError'
def test_error_handler_subclass(): def test_error_handler_subclass(app):
app = flask.Flask(__name__)
class ParentException(Exception): class ParentException(Exception):
pass pass
@ -78,9 +74,7 @@ def test_error_handler_subclass():
assert c.get('/child-registered').data == b'child-registered' assert c.get('/child-registered').data == b'child-registered'
def test_error_handler_http_subclass(): def test_error_handler_http_subclass(app):
app = flask.Flask(__name__)
class ForbiddenSubclassRegistered(Forbidden): class ForbiddenSubclassRegistered(Forbidden):
pass pass
@ -116,7 +110,7 @@ def test_error_handler_http_subclass():
assert c.get('/forbidden-registered').data == b'forbidden-registered' assert c.get('/forbidden-registered').data == b'forbidden-registered'
def test_error_handler_blueprint(): def test_error_handler_blueprint(app):
bp = flask.Blueprint('bp', __name__) bp = flask.Blueprint('bp', __name__)
@bp.errorhandler(500) @bp.errorhandler(500)
@ -127,8 +121,6 @@ def test_error_handler_blueprint():
def bp_test(): def bp_test():
raise InternalServerError() raise InternalServerError()
app = flask.Flask(__name__)
@app.errorhandler(500) @app.errorhandler(500)
def app_exception_handler(e): def app_exception_handler(e):
return 'app-error' return 'app-error'

44
tests/test_views.py

@ -16,6 +16,7 @@ import flask.views
from werkzeug.http import parse_set_header from werkzeug.http import parse_set_header
def common_test(app): def common_test(app):
c = app.test_client() c = app.test_client()
@ -25,23 +26,23 @@ def common_test(app):
meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow']) meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow'])
assert sorted(meths) == ['GET', 'HEAD', 'OPTIONS', 'POST'] assert sorted(meths) == ['GET', 'HEAD', 'OPTIONS', 'POST']
def test_basic_view():
app = flask.Flask(__name__)
def test_basic_view(app):
class Index(flask.views.View): class Index(flask.views.View):
methods = ['GET', 'POST'] methods = ['GET', 'POST']
def dispatch_request(self): def dispatch_request(self):
return flask.request.method return flask.request.method
app.add_url_rule('/', view_func=Index.as_view('index')) app.add_url_rule('/', view_func=Index.as_view('index'))
common_test(app) common_test(app)
def test_method_based_view():
app = flask.Flask(__name__)
def test_method_based_view(app):
class Index(flask.views.MethodView): class Index(flask.views.MethodView):
def get(self): def get(self):
return 'GET' return 'GET'
def post(self): def post(self):
return 'POST' return 'POST'
@ -49,18 +50,19 @@ def test_method_based_view():
common_test(app) common_test(app)
def test_view_patching():
app = flask.Flask(__name__)
def test_view_patching(app):
class Index(flask.views.MethodView): class Index(flask.views.MethodView):
def get(self): def get(self):
1 // 0 1 // 0
def post(self): def post(self):
1 // 0 1 // 0
class Other(Index): class Other(Index):
def get(self): def get(self):
return 'GET' return 'GET'
def post(self): def post(self):
return 'POST' return 'POST'
@ -69,12 +71,12 @@ def test_view_patching():
app.add_url_rule('/', view_func=view) app.add_url_rule('/', view_func=view)
common_test(app) common_test(app)
def test_view_inheritance():
app = flask.Flask(__name__)
def test_view_inheritance(app):
class Index(flask.views.MethodView): class Index(flask.views.MethodView):
def get(self): def get(self):
return 'GET' return 'GET'
def post(self): def post(self):
return 'POST' return 'POST'
@ -88,18 +90,19 @@ def test_view_inheritance():
meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow']) meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow'])
assert sorted(meths) == ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST'] assert sorted(meths) == ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST']
def test_view_decorators():
app = flask.Flask(__name__)
def test_view_decorators(app):
def add_x_parachute(f): def add_x_parachute(f):
def new_function(*args, **kwargs): def new_function(*args, **kwargs):
resp = flask.make_response(f(*args, **kwargs)) resp = flask.make_response(f(*args, **kwargs))
resp.headers['X-Parachute'] = 'awesome' resp.headers['X-Parachute'] = 'awesome'
return resp return resp
return new_function return new_function
class Index(flask.views.View): class Index(flask.views.View):
decorators = [add_x_parachute] decorators = [add_x_parachute]
def dispatch_request(self): def dispatch_request(self):
return 'Awesome' return 'Awesome'
@ -109,11 +112,13 @@ def test_view_decorators():
assert rv.headers['X-Parachute'] == 'awesome' assert rv.headers['X-Parachute'] == 'awesome'
assert rv.data == b'Awesome' assert rv.data == b'Awesome'
def test_view_provide_automatic_options_attr(): def test_view_provide_automatic_options_attr():
app = flask.Flask(__name__) app = flask.Flask(__name__)
class Index1(flask.views.View): class Index1(flask.views.View):
provide_automatic_options = False provide_automatic_options = False
def dispatch_request(self): def dispatch_request(self):
return 'Hello World!' return 'Hello World!'
@ -127,6 +132,7 @@ def test_view_provide_automatic_options_attr():
class Index2(flask.views.View): class Index2(flask.views.View):
methods = ['OPTIONS'] methods = ['OPTIONS']
provide_automatic_options = True provide_automatic_options = True
def dispatch_request(self): def dispatch_request(self):
return 'Hello World!' return 'Hello World!'
@ -146,9 +152,8 @@ def test_view_provide_automatic_options_attr():
rv = c.open('/', method='OPTIONS') rv = c.open('/', method='OPTIONS')
assert 'OPTIONS' in rv.allow assert 'OPTIONS' in rv.allow
def test_implicit_head():
app = flask.Flask(__name__)
def test_implicit_head(app):
class Index(flask.views.MethodView): class Index(flask.views.MethodView):
def get(self): def get(self):
return flask.Response('Blub', headers={ return flask.Response('Blub', headers={
@ -164,12 +169,12 @@ def test_implicit_head():
assert rv.data == b'' assert rv.data == b''
assert rv.headers['X-Method'] == 'HEAD' assert rv.headers['X-Method'] == 'HEAD'
def test_explicit_head():
app = flask.Flask(__name__)
def test_explicit_head(app):
class Index(flask.views.MethodView): class Index(flask.views.MethodView):
def get(self): def get(self):
return 'GET' return 'GET'
def head(self): def head(self):
return flask.Response('', headers={'X-Method': 'HEAD'}) return flask.Response('', headers={'X-Method': 'HEAD'})
@ -181,12 +186,13 @@ def test_explicit_head():
assert rv.data == b'' assert rv.data == b''
assert rv.headers['X-Method'] == 'HEAD' assert rv.headers['X-Method'] == 'HEAD'
def test_endpoint_override():
app = flask.Flask(__name__) def test_endpoint_override(app):
app.debug = True app.debug = True
class Index(flask.views.View): class Index(flask.views.View):
methods = ['GET', 'POST'] methods = ['GET', 'POST']
def dispatch_request(self): def dispatch_request(self):
return flask.request.method return flask.request.method
@ -198,9 +204,8 @@ def test_endpoint_override():
# But these tests should still pass. We just log a warning. # But these tests should still pass. We just log a warning.
common_test(app) common_test(app)
def test_multiple_inheritance():
app = flask.Flask(__name__)
def test_multiple_inheritance(app):
class GetView(flask.views.MethodView): class GetView(flask.views.MethodView):
def get(self): def get(self):
return 'GET' return 'GET'
@ -219,9 +224,8 @@ def test_multiple_inheritance():
assert c.delete('/').data == b'DELETE' assert c.delete('/').data == b'DELETE'
assert sorted(GetDeleteView.methods) == ['DELETE', 'GET'] assert sorted(GetDeleteView.methods) == ['DELETE', 'GET']
def test_remove_method_from_parent():
app = flask.Flask(__name__)
def test_remove_method_from_parent(app):
class GetView(flask.views.MethodView): class GetView(flask.views.MethodView):
def get(self): def get(self):
return 'GET' return 'GET'

Loading…
Cancel
Save