diff --git a/tests/__init__.py b/tests/__init__.py index 30024d10..aa52c18a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -90,25 +90,6 @@ class TestFlask(object): consistency. """ - @pytest.fixture(autouse=True) - def setup_path(self, monkeypatch): - monkeypatch.syspath_prepend( - os.path.abspath(os.path.join( - os.path.dirname(__file__), 'test_apps')) - ) - - @pytest.fixture(autouse=True) - def leak_detector(self, request): - request.addfinalizer(self.ensure_clean_request_context) - - def ensure_clean_request_context(self): - # make sure we're not leaking a request context since we are - # testing flask internally in debug mode in a few cases - leaks = [] - while flask._request_ctx_stack.top is not None: - leaks.append(flask._request_ctx_stack.pop()) - assert leaks == [] - def setup_method(self, method): self.setup() diff --git a/tests/conftest.py b/tests/conftest.py index ed11084b..cd3fe46e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,12 +6,34 @@ :copyright: (c) 2014 by the Flask Team, see AUTHORS for more details. :license: BSD, see LICENSE for more details. """ +import flask +import os +import sys import pkgutil import pytest -import sys import textwrap +@pytest.fixture(autouse=True) +def setup_path(monkeypatch): + monkeypatch.syspath_prepend( + os.path.abspath(os.path.join( + os.path.dirname(__file__), 'test_apps')) + ) + +@pytest.fixture(autouse=True) +def leak_detector(request): + def ensure_clean_request_context(): + # make sure we're not leaking a request context since we are + # testing flask internally in debug mode in a few cases + leaks = [] + while flask._request_ctx_stack.top is not None: + leaks.append(flask._request_ctx_stack.pop()) + assert leaks == [] + request.addfinalizer(ensure_clean_request_context) + + + @pytest.fixture(params=(True, False)) def limit_loader(request, monkeypatch): """Patch pkgutil.get_loader to give loader without get_filename or archive. diff --git a/tests/test_appctx.py b/tests/test_appctx.py index 0146583f..57b4ede8 100644 --- a/tests/test_appctx.py +++ b/tests/test_appctx.py @@ -16,106 +16,98 @@ import unittest from tests import TestFlask -class TestAppContext(TestFlask): - - def test_basic_url_generation(self): - app = flask.Flask(__name__) - app.config['SERVER_NAME'] = 'localhost' - app.config['PREFERRED_URL_SCHEME'] = 'https' - - @app.route('/') - def index(): - pass - - with app.app_context(): - rv = flask.url_for('index') - assert rv == 'https://localhost/' - - def test_url_generation_requires_server_name(self): - app = flask.Flask(__name__) - with app.app_context(): - with pytest.raises(RuntimeError): - flask.url_for('index') - - def test_url_generation_without_context_fails(self): +def test_basic_url_generation(): + app = flask.Flask(__name__) + app.config['SERVER_NAME'] = 'localhost' + app.config['PREFERRED_URL_SCHEME'] = 'https' + + @app.route('/') + def index(): + pass + + with app.app_context(): + rv = flask.url_for('index') + assert rv == 'https://localhost/' + +def test_url_generation_requires_server_name(): + app = flask.Flask(__name__) + with app.app_context(): with pytest.raises(RuntimeError): flask.url_for('index') - def test_request_context_means_app_context(self): - app = flask.Flask(__name__) - with app.test_request_context(): - assert flask.current_app._get_current_object() == app - assert flask._app_ctx_stack.top == None - - def test_app_context_provides_current_app(self): - app = flask.Flask(__name__) - with app.app_context(): - assert flask.current_app._get_current_object() == app - assert flask._app_ctx_stack.top == None - - def test_app_tearing_down(self): - cleanup_stuff = [] - app = flask.Flask(__name__) - @app.teardown_appcontext - def cleanup(exception): - cleanup_stuff.append(exception) - - with app.app_context(): - pass - - assert cleanup_stuff == [None] - - def test_app_tearing_down_with_previous_exception(self): - cleanup_stuff = [] - app = flask.Flask(__name__) - @app.teardown_appcontext - def cleanup(exception): - cleanup_stuff.append(exception) - - try: - raise Exception('dummy') - except Exception: - pass - - with app.app_context(): - pass - - assert cleanup_stuff == [None] - - def test_custom_app_ctx_globals_class(self): - class CustomRequestGlobals(object): - def __init__(self): - self.spam = 'eggs' - app = flask.Flask(__name__) - app.app_ctx_globals_class = CustomRequestGlobals - with app.app_context(): - assert flask.render_template_string('{{ g.spam }}') == 'eggs' - - def test_context_refcounts(self): - called = [] - app = flask.Flask(__name__) - @app.teardown_request - def teardown_req(error=None): - called.append('request') - @app.teardown_appcontext - def teardown_app(error=None): - called.append('app') - @app.route('/') - def index(): - with flask._app_ctx_stack.top: - with flask._request_ctx_stack.top: - pass - env = flask._request_ctx_stack.top.request.environ - assert env['werkzeug.request'] is not None - return u'' - c = app.test_client() - res = c.get('/') - assert res.status_code == 200 - assert res.data == b'' - assert called == ['request', 'app'] - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestAppContext)) - return suite +def test_url_generation_without_context_fails(): + with pytest.raises(RuntimeError): + flask.url_for('index') + +def test_request_context_means_app_context(): + app = flask.Flask(__name__) + with app.test_request_context(): + assert flask.current_app._get_current_object() == app + assert flask._app_ctx_stack.top == None + +def test_app_context_provides_current_app(): + app = flask.Flask(__name__) + with app.app_context(): + assert flask.current_app._get_current_object() == app + assert flask._app_ctx_stack.top == None + +def test_app_tearing_down(): + cleanup_stuff = [] + app = flask.Flask(__name__) + @app.teardown_appcontext + def cleanup(exception): + cleanup_stuff.append(exception) + + with app.app_context(): + pass + + assert cleanup_stuff == [None] + +def test_app_tearing_down_with_previous_exception(): + cleanup_stuff = [] + app = flask.Flask(__name__) + @app.teardown_appcontext + def cleanup(exception): + cleanup_stuff.append(exception) + + try: + raise Exception('dummy') + except Exception: + pass + + with app.app_context(): + pass + + assert cleanup_stuff == [None] + +def test_custom_app_ctx_globals_class(): + class CustomRequestGlobals(object): + def __init__(self): + self.spam = 'eggs' + app = flask.Flask(__name__) + app.app_ctx_globals_class = CustomRequestGlobals + with app.app_context(): + assert flask.render_template_string('{{ g.spam }}') == 'eggs' + +def test_context_refcounts(): + called = [] + app = flask.Flask(__name__) + @app.teardown_request + def teardown_req(error=None): + called.append('request') + @app.teardown_appcontext + def teardown_app(error=None): + called.append('app') + @app.route('/') + def index(): + with flask._app_ctx_stack.top: + with flask._request_ctx_stack.top: + pass + env = flask._request_ctx_stack.top.request.environ + assert env['werkzeug.request'] is not None + return u'' + c = app.test_client() + res = c.get('/') + assert res.status_code == 200 + assert res.data == b'' + assert called == ['request', 'app'] diff --git a/tests/test_ext.py b/tests/test_ext.py index 1bec1b62..dad0d585 100644 --- a/tests/test_ext.py +++ b/tests/test_ext.py @@ -20,120 +20,118 @@ except ImportError: from tests import TestFlask from flask._compat import PY2 -class TestExtImportHook(TestFlask): - - def setup(self): - # we clear this out for various reasons. The most important one is - # that a real flaskext could be in there which would disable our - # fake package. Secondly we want to make sure that the flaskext - # import hook does not break on reloading. - for entry, value in list(sys.modules.items()): - if (entry.startswith('flask.ext.') or - entry.startswith('flask_') or - entry.startswith('flaskext.') or - entry == 'flaskext') and value is not None: - sys.modules.pop(entry, None) - from flask import ext - reload_module(ext) - - # reloading must not add more hooks - import_hooks = 0 - for item in sys.meta_path: - cls = type(item) - if cls.__module__ == 'flask.exthook' and \ - cls.__name__ == 'ExtensionImporter': - import_hooks += 1 - assert import_hooks == 1 - - def teardown(self): + +@pytest.fixture(autouse=True) +def importhook_setup(monkeypatch, request): + # we clear this out for various reasons. The most important one is + # that a real flaskext could be in there which would disable our + # fake package. Secondly we want to make sure that the flaskext + # import hook does not break on reloading. + for entry, value in list(sys.modules.items()): + if (entry.startswith('flask.ext.') or + entry.startswith('flask_') or + entry.startswith('flaskext.') or + entry == 'flaskext') and value is not None: + monkeypatch.delitem(sys.modules, entry) + from flask import ext + reload_module(ext) + + # reloading must not add more hooks + import_hooks = 0 + for item in sys.meta_path: + cls = type(item) + if cls.__module__ == 'flask.exthook' and \ + cls.__name__ == 'ExtensionImporter': + import_hooks += 1 + assert import_hooks == 1 + + def teardown(): from flask import ext for key in ext.__dict__: assert '.' not in key - def test_flaskext_new_simple_import_normal(self): - from flask.ext.newext_simple import ext_id - assert ext_id == 'newext_simple' - - def test_flaskext_new_simple_import_module(self): - from flask.ext import newext_simple - assert newext_simple.ext_id == 'newext_simple' - assert newext_simple.__name__ == 'flask_newext_simple' - - def test_flaskext_new_package_import_normal(self): - from flask.ext.newext_package import ext_id - assert ext_id == 'newext_package' - - def test_flaskext_new_package_import_module(self): - from flask.ext import newext_package - assert newext_package.ext_id == 'newext_package' - assert newext_package.__name__ == 'flask_newext_package' - - def test_flaskext_new_package_import_submodule_function(self): - from flask.ext.newext_package.submodule import test_function - assert test_function() == 42 - - def test_flaskext_new_package_import_submodule(self): - from flask.ext.newext_package import submodule - assert submodule.__name__ == 'flask_newext_package.submodule' - assert submodule.test_function() == 42 - - def test_flaskext_old_simple_import_normal(self): - from flask.ext.oldext_simple import ext_id - assert ext_id == 'oldext_simple' - - def test_flaskext_old_simple_import_module(self): - from flask.ext import oldext_simple - assert oldext_simple.ext_id == 'oldext_simple' - assert oldext_simple.__name__ == 'flaskext.oldext_simple' - - def test_flaskext_old_package_import_normal(self): - from flask.ext.oldext_package import ext_id - assert ext_id == 'oldext_package' - - def test_flaskext_old_package_import_module(self): - from flask.ext import oldext_package - assert oldext_package.ext_id == 'oldext_package' - assert oldext_package.__name__ == 'flaskext.oldext_package' - - def test_flaskext_old_package_import_submodule(self): - from flask.ext.oldext_package import submodule - assert submodule.__name__ == 'flaskext.oldext_package.submodule' - assert submodule.test_function() == 42 - - def test_flaskext_old_package_import_submodule_function(self): - from flask.ext.oldext_package.submodule import test_function - assert test_function() == 42 - - def test_flaskext_broken_package_no_module_caching(self): - for x in range(2): - with pytest.raises(ImportError): - import flask.ext.broken - - def test_no_error_swallowing(self): - try: + request.addfinalizer(teardown) + +def test_flaskext_new_simple_import_normal(): + from flask.ext.newext_simple import ext_id + assert ext_id == 'newext_simple' + +def test_flaskext_new_simple_import_module(): + from flask.ext import newext_simple + assert newext_simple.ext_id == 'newext_simple' + assert newext_simple.__name__ == 'flask_newext_simple' + +def test_flaskext_new_package_import_normal(): + from flask.ext.newext_package import ext_id + assert ext_id == 'newext_package' + +def test_flaskext_new_package_import_module(): + from flask.ext import newext_package + assert newext_package.ext_id == 'newext_package' + assert newext_package.__name__ == 'flask_newext_package' + +def test_flaskext_new_package_import_submodule_function(): + from flask.ext.newext_package.submodule import test_function + assert test_function() == 42 + +def test_flaskext_new_package_import_submodule(): + from flask.ext.newext_package import submodule + assert submodule.__name__ == 'flask_newext_package.submodule' + assert submodule.test_function() == 42 + +def test_flaskext_old_simple_import_normal(): + from flask.ext.oldext_simple import ext_id + assert ext_id == 'oldext_simple' + +def test_flaskext_old_simple_import_module(): + from flask.ext import oldext_simple + assert oldext_simple.ext_id == 'oldext_simple' + assert oldext_simple.__name__ == 'flaskext.oldext_simple' + +def test_flaskext_old_package_import_normal(): + from flask.ext.oldext_package import ext_id + assert ext_id == 'oldext_package' + +def test_flaskext_old_package_import_module(): + from flask.ext import oldext_package + assert oldext_package.ext_id == 'oldext_package' + assert oldext_package.__name__ == 'flaskext.oldext_package' + +def test_flaskext_old_package_import_submodule(): + from flask.ext.oldext_package import submodule + assert submodule.__name__ == 'flaskext.oldext_package.submodule' + assert submodule.test_function() == 42 + +def test_flaskext_old_package_import_submodule_function(): + from flask.ext.oldext_package.submodule import test_function + assert test_function() == 42 + +def test_flaskext_broken_package_no_module_caching(): + for x in range(2): + with pytest.raises(ImportError): import flask.ext.broken - except ImportError: - exc_type, exc_value, tb = sys.exc_info() - assert exc_type is ImportError - if PY2: - message = 'No module named missing_module' - else: - message = 'No module named \'missing_module\'' - assert str(exc_value) == message - assert tb.tb_frame.f_globals is globals() - - # reraise() adds a second frame so we need to skip that one too. - # On PY3 we even have another one :( - next = tb.tb_next.tb_next - if not PY2: - next = next.tb_next - - import os.path - assert os.path.join('flask_broken', '__init__.py') in \ - next.tb_frame.f_code.co_filename - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestExtImportHook)) - return suite + +def test_no_error_swallowing(): + try: + import flask.ext.broken + except ImportError: + exc_type, exc_value, tb = sys.exc_info() + assert exc_type is ImportError + if PY2: + message = 'No module named missing_module' + else: + message = 'No module named \'missing_module\'' + assert str(exc_value) == message + assert tb.tb_frame.f_globals is globals() + + # reraise() adds a second frame so we need to skip that one too. + # On PY3 we even have another one :( + next = tb.tb_next.tb_next + if not PY2: + next = next.tb_next + + import os.path + assert os.path.join('flask_broken', '__init__.py') in \ + next.tb_frame.f_code.co_filename + else: + 1/0 # XXX diff --git a/tests/test_subclassing.py b/tests/test_subclassing.py index 88df7d94..bd953781 100644 --- a/tests/test_subclassing.py +++ b/tests/test_subclassing.py @@ -16,31 +16,23 @@ from tests import TestFlask from flask._compat import StringIO -class TestFlaskSubclassing(TestFlask): - - def test_suppressed_exception_logging(self): - class SuppressedFlask(flask.Flask): - def log_exception(self, exc_info): - pass - - out = StringIO() - app = SuppressedFlask(__name__) - app.logger_name = 'flask_tests/test_suppressed_exception_logging' - app.logger.addHandler(StreamHandler(out)) - - @app.route('/') - def index(): - 1 // 0 - - rv = app.test_client().get('/') - assert rv.status_code == 500 - assert b'Internal Server Error' in rv.data - - err = out.getvalue() - assert err == '' - - -def suite(): - suite = unittest.TestSuite() - suite.addTest(unittest.makeSuite(TestFlaskSubclassing)) - return suite +def test_suppressed_exception_logging(): + class SuppressedFlask(flask.Flask): + def log_exception(self, exc_info): + pass + + out = StringIO() + app = SuppressedFlask(__name__) + app.logger_name = 'flask_tests/test_suppressed_exception_logging' + app.logger.addHandler(StreamHandler(out)) + + @app.route('/') + def index(): + 1 // 0 + + rv = app.test_client().get('/') + assert rv.status_code == 500 + assert b'Internal Server Error' in rv.data + + err = out.getvalue() + assert err == '' diff --git a/tests/test_templating.py b/tests/test_templating.py index 6ba6541e..f05418fb 100644 --- a/tests/test_templating.py +++ b/tests/test_templating.py @@ -9,6 +9,8 @@ :license: BSD, see LICENSE for more details. """ +import pytest + import flask import unittest import logging @@ -17,334 +19,324 @@ from jinja2 import TemplateNotFound from tests import TestFlask -class TestTemplating(TestFlask): - - def test_context_processing(self): - app = flask.Flask(__name__) - @app.context_processor - def context_processor(): - return {'injected_value': 42} - @app.route('/') - def index(): - return flask.render_template('context_template.html', value=23) - rv = app.test_client().get('/') - assert rv.data == b'
23|42' - - def test_original_win(self): - app = flask.Flask(__name__) - @app.route('/') - def index(): - return flask.render_template_string('{{ config }}', config=42) - rv = app.test_client().get('/') - assert rv.data == b'42' - - def test_request_less_rendering(self): - app = flask.Flask(__name__) - app.config['WORLD_NAME'] = 'Special World' - @app.context_processor - def context_processor(): - return dict(foo=42) - - with app.app_context(): - rv = flask.render_template_string('Hello {{ config.WORLD_NAME }} ' - '{{ foo }}') - assert rv == 'Hello Special World 42' - - def test_standard_context(self): - app = flask.Flask(__name__) - app.secret_key = 'development key' - @app.route('/') - def index(): - flask.g.foo = 23 - flask.session['test'] = 'aha' - return flask.render_template_string(''' - {{ request.args.foo }} - {{ g.foo }} - {{ config.DEBUG }} - {{ session.test }} - ''') - rv = app.test_client().get('/?foo=42') - assert rv.data.split() == [b'42', b'23', b'False', b'aha'] - - def test_escaping(self): - text = '
Hello World!' - app = flask.Flask(__name__) - @app.route('/') - def index(): - return flask.render_template('escaping_template.html', text=text, - html=flask.Markup(text)) - lines = app.test_client().get('/').data.splitlines() - assert lines == [ - b'<p>Hello World!', - b'
Hello World!', - b'
Hello World!', - b'
Hello World!', - b'<p>Hello World!', - b'
Hello World!'
- ]
-
- def test_no_escaping(self):
- app = flask.Flask(__name__)
- with app.test_request_context():
- assert flask.render_template_string(
- '{{ foo }}', foo=' 23|42'
+
+def test_original_win():
+ app = flask.Flask(__name__)
+ @app.route('/')
+ def index():
+ return flask.render_template_string('{{ config }}', config=42)
+ rv = app.test_client().get('/')
+ assert rv.data == b'42'
+
+def test_request_less_rendering():
+ app = flask.Flask(__name__)
+ app.config['WORLD_NAME'] = 'Special World'
+ @app.context_processor
+ def context_processor():
+ return dict(foo=42)
+
+ with app.app_context():
+ rv = flask.render_template_string('Hello {{ config.WORLD_NAME }} '
+ '{{ foo }}')
+ assert rv == 'Hello Special World 42'
+
+def test_standard_context():
+ app = flask.Flask(__name__)
+ app.secret_key = 'development key'
+ @app.route('/')
+ def index():
+ flask.g.foo = 23
+ flask.session['test'] = 'aha'
+ return flask.render_template_string('''
+ {{ request.args.foo }}
+ {{ g.foo }}
+ {{ config.DEBUG }}
+ {{ session.test }}
+ ''')
+ rv = app.test_client().get('/?foo=42')
+ assert rv.data.split() == [b'42', b'23', b'False', b'aha']
+
+def test_escaping():
+ text = ' Hello World!'
+ app = flask.Flask(__name__)
+ @app.route('/')
+ def index():
+ return flask.render_template('escaping_template.html', text=text,
+ html=flask.Markup(text))
+ lines = app.test_client().get('/').data.splitlines()
+ assert lines == [
+ b'<p>Hello World!',
+ b' Hello World!',
+ b' Hello World!',
+ b' Hello World!',
+ b'<p>Hello World!',
+ b' Hello World!'
+ ]
+
+def test_no_escaping():
+ app = flask.Flask(__name__)
+ with app.test_request_context():
+ assert flask.render_template_string(
+ '{{ foo }}', foo='Jameson
'
-
- def test_templates_auto_reload(self):
- app = flask.Flask(__name__)
- assert app.config['TEMPLATES_AUTO_RELOAD']
- assert app.jinja_env.auto_reload
- app = flask.Flask(__name__)
- app.config['TEMPLATES_AUTO_RELOAD'] = False
- assert not app.jinja_env.auto_reload
-
- def test_template_loader_debugging(self):
- from blueprintapp import app
-
- called = []
- class _TestHandler(logging.Handler):
- def handle(x, record):
- called.append(True)
- text = str(record.msg)
- assert '1: trying loader of application "blueprintapp"' in text
- assert ('2: trying loader of blueprint "admin" '
- '(blueprintapp.apps.admin)') in text
- assert ('trying loader of blueprint "frontend" '
- '(blueprintapp.apps.frontend)') in text
- assert 'Error: the template could not be found' in text
- assert ('looked up from an endpoint that belongs to '
- 'the blueprint "frontend"') in text
- assert 'See http://flask.pocoo.org/docs/blueprints/#templates' in text
-
- with app.test_client() as c:
- try:
- old_load_setting = app.config['EXPLAIN_TEMPLATE_LOADING']
- old_handlers = app.logger.handlers[:]
- app.logger.handlers = [_TestHandler()]
- app.config['EXPLAIN_TEMPLATE_LOADING'] = True
-
- try:
- c.get('/missing')
- except TemplateNotFound as e:
- assert 'missing_template.html' in str(e)
- else:
- self.fail('Expected template not found exception.')
- finally:
- app.logger.handlers[:] = old_handlers
- app.config['EXPLAIN_TEMPLATE_LOADING'] = old_load_setting
-
- assert len(called) == 1
-
-
-def suite():
- suite = unittest.TestSuite()
- suite.addTest(unittest.makeSuite(TestTemplating))
- return suite
+def test_context_processing():
+ app = flask.Flask(__name__)
+ @app.context_processor
+ def context_processor():
+ return {'injected_value': 42}
+ @app.route('/')
+ def index():
+ return flask.render_template('context_template.html', value=23)
+ rv = app.test_client().get('/')
+ assert rv.data == b'Jameson
'
+
+def test_templates_auto_reload():
+ app = flask.Flask(__name__)
+ assert app.config['TEMPLATES_AUTO_RELOAD']
+ assert app.jinja_env.auto_reload
+ app = flask.Flask(__name__)
+ app.config['TEMPLATES_AUTO_RELOAD'] = False
+ assert not app.jinja_env.auto_reload
+
+def test_template_loader_debugging():
+ from blueprintapp import app
+
+ called = []
+ class _TestHandler(logging.Handler):
+ def handle(x, record):
+ called.append(True)
+ text = str(record.msg)
+ assert '1: trying loader of application "blueprintapp"' in text
+ assert ('2: trying loader of blueprint "admin" '
+ '(blueprintapp.apps.admin)') in text
+ assert ('trying loader of blueprint "frontend" '
+ '(blueprintapp.apps.frontend)') in text
+ assert 'Error: the template could not be found' in text
+ assert ('looked up from an endpoint that belongs to '
+ 'the blueprint "frontend"') in text
+ assert 'See http://flask.pocoo.org/docs/blueprints/#templates' in text
+
+ with app.test_client() as c:
+ try:
+ old_load_setting = app.config['EXPLAIN_TEMPLATE_LOADING']
+ old_handlers = app.logger.handlers[:]
+ app.logger.handlers = [_TestHandler()]
+ app.config['EXPLAIN_TEMPLATE_LOADING'] = True
+
+ with pytest.raises(TemplateNotFound) as excinfo:
+ c.get('/missing')
+
+ assert 'missing_template.html' in str(excinfo.value)
+ finally:
+ app.logger.handlers[:] = old_handlers
+ app.config['EXPLAIN_TEMPLATE_LOADING'] = old_load_setting
+
+ assert len(called) == 1