Browse Source

Merge pull request #1165 from untitaker/new_testsuite

Port testsuite to py.test
pull/1175/head
Markus Unterwaditzer 10 years ago
parent
commit
bb94a612fd
  1. 6
      .travis-devel-requirements.txt
  2. 6
      .travis-lowest-requirements.txt
  3. 2
      .travis-release-requirements.txt
  4. 11
      .travis.yml
  5. 5
      MANIFEST.in
  6. 2
      Makefile
  7. 36
      examples/blueprintexample/blueprintexample_test.py
  8. 33
      examples/blueprintexample/test_blueprintexample.py
  9. 76
      examples/flaskr/flaskr_tests.py
  10. 77
      examples/flaskr/test_flaskr.py
  11. 150
      examples/minitwit/minitwit_tests.py
  12. 151
      examples/minitwit/test_minitwit.py
  13. 253
      flask/testsuite/__init__.py
  14. 118
      flask/testsuite/appctx.py
  15. 1364
      flask/testsuite/basic.py
  16. 585
      flask/testsuite/blueprints.py
  17. 384
      flask/testsuite/config.py
  18. 24
      flask/testsuite/deprecations.py
  19. 38
      flask/testsuite/examples.py
  20. 136
      flask/testsuite/ext.py
  21. 116
      flask/testsuite/regression.py
  22. 201
      flask/testsuite/reqctx.py
  23. 153
      flask/testsuite/signals.py
  24. 46
      flask/testsuite/subclassing.py
  25. 352
      flask/testsuite/templating.py
  26. 4
      flask/testsuite/test_apps/config_module_app.py
  27. 4
      flask/testsuite/test_apps/config_package_app/__init__.py
  28. 2
      flask/testsuite/test_apps/flask_broken/__init__.py
  29. 0
      flask/testsuite/test_apps/flask_broken/b.py
  30. 1
      flask/testsuite/test_apps/flask_newext_package/__init__.py
  31. 2
      flask/testsuite/test_apps/flask_newext_package/submodule.py
  32. 1
      flask/testsuite/test_apps/flask_newext_simple.py
  33. 0
      flask/testsuite/test_apps/flaskext/__init__.py
  34. 1
      flask/testsuite/test_apps/flaskext/oldext_package/__init__.py
  35. 2
      flask/testsuite/test_apps/flaskext/oldext_package/submodule.py
  36. 1
      flask/testsuite/test_apps/flaskext/oldext_simple.py
  37. 2
      flask/testsuite/test_apps/importerror.py
  38. BIN
      flask/testsuite/test_apps/lib/python2.5/site-packages/SiteEgg.egg
  39. 3
      flask/testsuite/test_apps/lib/python2.5/site-packages/site_app.py
  40. 3
      flask/testsuite/test_apps/lib/python2.5/site-packages/site_package/__init__.py
  41. 4
      flask/testsuite/test_apps/main_app.py
  42. 3
      flask/testsuite/test_apps/path/installed_package/__init__.py
  43. 257
      flask/testsuite/testing.py
  44. 169
      flask/testsuite/views.py
  45. 5
      run-tests.py
  46. 0
      scripts/flaskext_tester.py
  47. 42
      setup.py
  48. 134
      tests/conftest.py
  49. 0
      tests/static/config.json
  50. 0
      tests/static/index.html
  51. 0
      tests/templates/_macro.html
  52. 0
      tests/templates/context_template.html
  53. 0
      tests/templates/escaping_template.html
  54. 0
      tests/templates/mail.txt
  55. 0
      tests/templates/nested/nested.txt
  56. 0
      tests/templates/simple_template.html
  57. 0
      tests/templates/template_filter.html
  58. 0
      tests/templates/template_test.html
  59. 113
      tests/test_appctx.py
  60. 0
      tests/test_apps/blueprintapp/__init__.py
  61. 0
      tests/test_apps/blueprintapp/apps/__init__.py
  62. 0
      tests/test_apps/blueprintapp/apps/admin/__init__.py
  63. 0
      tests/test_apps/blueprintapp/apps/admin/static/css/test.css
  64. 0
      tests/test_apps/blueprintapp/apps/admin/static/test.txt
  65. 0
      tests/test_apps/blueprintapp/apps/admin/templates/admin/index.html
  66. 0
      tests/test_apps/blueprintapp/apps/frontend/__init__.py
  67. 0
      tests/test_apps/blueprintapp/apps/frontend/templates/frontend/index.html
  68. 0
      tests/test_apps/subdomaintestmodule/__init__.py
  69. 0
      tests/test_apps/subdomaintestmodule/static/hello.txt
  70. 1508
      tests/test_basic.py
  71. 578
      tests/test_blueprints.py
  72. 184
      tests/test_config.py
  73. 10
      tests/test_deprecations.py
  74. 187
      tests/test_ext.py
  75. 256
      tests/test_helpers.py
  76. 134
      tests/test_instance_config.py
  77. 107
      tests/test_regression.py
  78. 185
      tests/test_reqctx.py
  79. 158
      tests/test_signals.py
  80. 38
      tests/test_subclassing.py
  81. 342
      tests/test_templating.py
  82. 243
      tests/test_testing.py
  83. 163
      tests/test_views.py
  84. 22
      tox.ini

6
.travis-devel-requirements.txt

@ -1,6 +0,0 @@
git+git://github.com/mitsuhiko/werkzeug.git#egg=Werkzeug
git+git://github.com/mitsuhiko/jinja2.git#egg=Jinja2
git+git://github.com/mitsuhiko/itsdangerous.git#egg=itsdangerous
# extra dependencies
git+git://github.com/jek/blinker.git#egg=blinker

6
.travis-lowest-requirements.txt

@ -1,6 +0,0 @@
Werkzeug==0.7
Jinja2==2.4
itsdangerous==0.21
# extra dependencies
blinker==1.0

2
.travis-release-requirements.txt

@ -1,2 +0,0 @@
# extra dependencies
blinker

11
.travis.yml

@ -5,6 +5,7 @@ python:
- "2.7"
- "pypy"
- "3.3"
- "3.4"
env:
- REQUIREMENTS=lowest
@ -16,12 +17,16 @@ matrix:
# Python 3 support currently does not work with lowest requirements
- python: "3.3"
env: REQUIREMENTS=lowest
- python: "3.4"
env: REQUIREMENTS=lowest
install:
- pip install -r .travis-$REQUIREMENTS-requirements.txt
- pip install --editable .
- pip install hg+https://bitbucket.org/hpk42/tox
script: make test
script:
- tox -e \
$(echo py$TRAVIS_PYTHON_VERSION | tr -d . | sed -e 's/pypypy/pypy/')-$REQUIREMENTS
branches:
except:

5
MANIFEST.in

@ -1,4 +1,4 @@
include Makefile CHANGES LICENSE AUTHORS run-tests.py
include Makefile CHANGES LICENSE AUTHORS
recursive-include artwork *
recursive-include tests *
recursive-include examples *
@ -9,8 +9,5 @@ recursive-exclude tests *.pyc
recursive-exclude tests *.pyo
recursive-exclude examples *.pyc
recursive-exclude examples *.pyo
recursive-include flask/testsuite/static *
recursive-include flask/testsuite/templates *
recursive-include flask/testsuite/test_apps *
prune docs/_build
prune docs/_themes/.git

2
Makefile

@ -3,7 +3,7 @@
all: clean-pyc test
test:
python run-tests.py
py.test
tox-test:
tox

36
examples/blueprintexample/blueprintexample_test.py

@ -1,36 +0,0 @@
# -*- coding: utf-8 -*-
"""
Blueprint Example Tests
~~~~~~~~~~~~~~
Tests the Blueprint example app
"""
import blueprintexample
import unittest
class BlueprintExampleTestCase(unittest.TestCase):
def setUp(self):
self.app = blueprintexample.app.test_client()
def test_urls(self):
r = self.app.get('/')
self.assertEquals(r.status_code, 200)
r = self.app.get('/hello')
self.assertEquals(r.status_code, 200)
r = self.app.get('/world')
self.assertEquals(r.status_code, 200)
#second blueprint instance
r = self.app.get('/pages/hello')
self.assertEquals(r.status_code, 200)
r = self.app.get('/pages/world')
self.assertEquals(r.status_code, 200)
if __name__ == '__main__':
unittest.main()

33
examples/blueprintexample/test_blueprintexample.py

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
"""
Blueprint Example Tests
~~~~~~~~~~~~~~
Tests the Blueprint example app
"""
import pytest
import blueprintexample
@pytest.fixture
def client():
return blueprintexample.app.test_client()
def test_urls(client):
r = client.get('/')
assert r.status_code == 200
r = client.get('/hello')
assert r.status_code == 200
r = client.get('/world')
assert r.status_code == 200
# second blueprint instance
r = client.get('/pages/hello')
assert r.status_code == 200
r = client.get('/pages/world')
assert r.status_code == 200

76
examples/flaskr/flaskr_tests.py

@ -1,76 +0,0 @@
# -*- coding: utf-8 -*-
"""
Flaskr Tests
~~~~~~~~~~~~
Tests the Flaskr application.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import os
import flaskr
import unittest
import tempfile
class FlaskrTestCase(unittest.TestCase):
def setUp(self):
"""Before each test, set up a blank database"""
self.db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
flaskr.app.config['TESTING'] = True
self.app = flaskr.app.test_client()
with flaskr.app.app_context():
flaskr.init_db()
def tearDown(self):
"""Get rid of the database again after each test."""
os.close(self.db_fd)
os.unlink(flaskr.app.config['DATABASE'])
def login(self, username, password):
return self.app.post('/login', data=dict(
username=username,
password=password
), follow_redirects=True)
def logout(self):
return self.app.get('/logout', follow_redirects=True)
# testing functions
def test_empty_db(self):
"""Start with a blank database."""
rv = self.app.get('/')
assert b'No entries here so far' in rv.data
def test_login_logout(self):
"""Make sure login and logout works"""
rv = self.login(flaskr.app.config['USERNAME'],
flaskr.app.config['PASSWORD'])
assert b'You were logged in' in rv.data
rv = self.logout()
assert b'You were logged out' in rv.data
rv = self.login(flaskr.app.config['USERNAME'] + 'x',
flaskr.app.config['PASSWORD'])
assert b'Invalid username' in rv.data
rv = self.login(flaskr.app.config['USERNAME'],
flaskr.app.config['PASSWORD'] + 'x')
assert b'Invalid password' in rv.data
def test_messages(self):
"""Test that messages work"""
self.login(flaskr.app.config['USERNAME'],
flaskr.app.config['PASSWORD'])
rv = self.app.post('/add', data=dict(
title='<Hello>',
text='<strong>HTML</strong> allowed here'
), follow_redirects=True)
assert b'No entries here so far' not in rv.data
assert b'&lt;Hello&gt;' in rv.data
assert b'<strong>HTML</strong> allowed here' in rv.data
if __name__ == '__main__':
unittest.main()

77
examples/flaskr/test_flaskr.py

@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
"""
Flaskr Tests
~~~~~~~~~~~~
Tests the Flaskr application.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import pytest
import os
import flaskr
import tempfile
@pytest.fixture
def client(request):
db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp()
flaskr.app.config['TESTING'] = True
client = flaskr.app.test_client()
with flaskr.app.app_context():
flaskr.init_db()
def teardown():
os.close(db_fd)
os.unlink(flaskr.app.config['DATABASE'])
request.addfinalizer(teardown)
return client
def login(client, username, password):
return client.post('/login', data=dict(
username=username,
password=password
), follow_redirects=True)
def logout(client):
return client.get('/logout', follow_redirects=True)
def test_empty_db(client):
"""Start with a blank database."""
rv = client.get('/')
assert b'No entries here so far' in rv.data
def test_login_logout(client):
"""Make sure login and logout works"""
rv = login(client, flaskr.app.config['USERNAME'],
flaskr.app.config['PASSWORD'])
assert b'You were logged in' in rv.data
rv = logout(client)
assert b'You were logged out' in rv.data
rv = login(client, flaskr.app.config['USERNAME'] + 'x',
flaskr.app.config['PASSWORD'])
assert b'Invalid username' in rv.data
rv = login(client, flaskr.app.config['USERNAME'],
flaskr.app.config['PASSWORD'] + 'x')
assert b'Invalid password' in rv.data
def test_messages(client):
"""Test that messages work"""
login(client, flaskr.app.config['USERNAME'],
flaskr.app.config['PASSWORD'])
rv = client.post('/add', data=dict(
title='<Hello>',
text='<strong>HTML</strong> allowed here'
), follow_redirects=True)
assert b'No entries here so far' not in rv.data
assert b'&lt;Hello&gt;' in rv.data
assert b'<strong>HTML</strong> allowed here' in rv.data

150
examples/minitwit/minitwit_tests.py

@ -1,150 +0,0 @@
# -*- coding: utf-8 -*-
"""
MiniTwit Tests
~~~~~~~~~~~~~~
Tests the MiniTwit application.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import os
import minitwit
import unittest
import tempfile
class MiniTwitTestCase(unittest.TestCase):
def setUp(self):
"""Before each test, set up a blank database"""
self.db_fd, minitwit.app.config['DATABASE'] = tempfile.mkstemp()
self.app = minitwit.app.test_client()
with minitwit.app.app_context():
minitwit.init_db()
def tearDown(self):
"""Get rid of the database again after each test."""
os.close(self.db_fd)
os.unlink(minitwit.app.config['DATABASE'])
# helper functions
def register(self, username, password, password2=None, email=None):
"""Helper function to register a user"""
if password2 is None:
password2 = password
if email is None:
email = username + '@example.com'
return self.app.post('/register', data={
'username': username,
'password': password,
'password2': password2,
'email': email,
}, follow_redirects=True)
def login(self, username, password):
"""Helper function to login"""
return self.app.post('/login', data={
'username': username,
'password': password
}, follow_redirects=True)
def register_and_login(self, username, password):
"""Registers and logs in in one go"""
self.register(username, password)
return self.login(username, password)
def logout(self):
"""Helper function to logout"""
return self.app.get('/logout', follow_redirects=True)
def add_message(self, text):
"""Records a message"""
rv = self.app.post('/add_message', data={'text': text},
follow_redirects=True)
if text:
assert b'Your message was recorded' in rv.data
return rv
# testing functions
def test_register(self):
"""Make sure registering works"""
rv = self.register('user1', 'default')
assert b'You were successfully registered ' \
b'and can login now' in rv.data
rv = self.register('user1', 'default')
assert b'The username is already taken' in rv.data
rv = self.register('', 'default')
assert b'You have to enter a username' in rv.data
rv = self.register('meh', '')
assert b'You have to enter a password' in rv.data
rv = self.register('meh', 'x', 'y')
assert b'The two passwords do not match' in rv.data
rv = self.register('meh', 'foo', email='broken')
assert b'You have to enter a valid email address' in rv.data
def test_login_logout(self):
"""Make sure logging in and logging out works"""
rv = self.register_and_login('user1', 'default')
assert b'You were logged in' in rv.data
rv = self.logout()
assert b'You were logged out' in rv.data
rv = self.login('user1', 'wrongpassword')
assert b'Invalid password' in rv.data
rv = self.login('user2', 'wrongpassword')
assert b'Invalid username' in rv.data
def test_message_recording(self):
"""Check if adding messages works"""
self.register_and_login('foo', 'default')
self.add_message('test message 1')
self.add_message('<test message 2>')
rv = self.app.get('/')
assert b'test message 1' in rv.data
assert b'&lt;test message 2&gt;' in rv.data
def test_timelines(self):
"""Make sure that timelines work"""
self.register_and_login('foo', 'default')
self.add_message('the message by foo')
self.logout()
self.register_and_login('bar', 'default')
self.add_message('the message by bar')
rv = self.app.get('/public')
assert b'the message by foo' in rv.data
assert b'the message by bar' in rv.data
# bar's timeline should just show bar's message
rv = self.app.get('/')
assert b'the message by foo' not in rv.data
assert b'the message by bar' in rv.data
# now let's follow foo
rv = self.app.get('/foo/follow', follow_redirects=True)
assert b'You are now following &#34;foo&#34;' in rv.data
# we should now see foo's message
rv = self.app.get('/')
assert b'the message by foo' in rv.data
assert b'the message by bar' in rv.data
# but on the user's page we only want the user's message
rv = self.app.get('/bar')
assert b'the message by foo' not in rv.data
assert b'the message by bar' in rv.data
rv = self.app.get('/foo')
assert b'the message by foo' in rv.data
assert b'the message by bar' not in rv.data
# now unfollow and check if that worked
rv = self.app.get('/foo/unfollow', follow_redirects=True)
assert b'You are no longer following &#34;foo&#34;' in rv.data
rv = self.app.get('/')
assert b'the message by foo' not in rv.data
assert b'the message by bar' in rv.data
if __name__ == '__main__':
unittest.main()

151
examples/minitwit/test_minitwit.py

@ -0,0 +1,151 @@
# -*- coding: utf-8 -*-
"""
MiniTwit Tests
~~~~~~~~~~~~~~
Tests the MiniTwit application.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import os
import minitwit
import tempfile
import pytest
@pytest.fixture
def client(request):
db_fd, minitwit.app.config['DATABASE'] = tempfile.mkstemp()
client = minitwit.app.test_client()
with minitwit.app.app_context():
minitwit.init_db()
def teardown():
"""Get rid of the database again after each test."""
os.close(db_fd)
os.unlink(minitwit.app.config['DATABASE'])
request.addfinalizer(teardown)
return client
def register(client, username, password, password2=None, email=None):
"""Helper function to register a user"""
if password2 is None:
password2 = password
if email is None:
email = username + '@example.com'
return client.post('/register', data={
'username': username,
'password': password,
'password2': password2,
'email': email,
}, follow_redirects=True)
def login(client, username, password):
"""Helper function to login"""
return client.post('/login', data={
'username': username,
'password': password
}, follow_redirects=True)
def register_and_login(client, username, password):
"""Registers and logs in in one go"""
register(client, username, password)
return login(client, username, password)
def logout(client):
"""Helper function to logout"""
return client.get('/logout', follow_redirects=True)
def add_message(client, text):
"""Records a message"""
rv = client.post('/add_message', data={'text': text},
follow_redirects=True)
if text:
assert b'Your message was recorded' in rv.data
return rv
def test_register(client):
"""Make sure registering works"""
rv = register(client, 'user1', 'default')
assert b'You were successfully registered ' \
b'and can login now' in rv.data
rv = register(client, 'user1', 'default')
assert b'The username is already taken' in rv.data
rv = register(client, '', 'default')
assert b'You have to enter a username' in rv.data
rv = register(client, 'meh', '')
assert b'You have to enter a password' in rv.data
rv = register(client, 'meh', 'x', 'y')
assert b'The two passwords do not match' in rv.data
rv = register(client, 'meh', 'foo', email='broken')
assert b'You have to enter a valid email address' in rv.data
def test_login_logout(client):
"""Make sure logging in and logging out works"""
rv = register_and_login(client, 'user1', 'default')
assert b'You were logged in' in rv.data
rv = logout(client)
assert b'You were logged out' in rv.data
rv = login(client, 'user1', 'wrongpassword')
assert b'Invalid password' in rv.data
rv = login(client, 'user2', 'wrongpassword')
assert b'Invalid username' in rv.data
def test_message_recording(client):
"""Check if adding messages works"""
register_and_login(client, 'foo', 'default')
add_message(client, 'test message 1')
add_message(client, '<test message 2>')
rv = client.get('/')
assert b'test message 1' in rv.data
assert b'&lt;test message 2&gt;' in rv.data
def test_timelines(client):
"""Make sure that timelines work"""
register_and_login(client, 'foo', 'default')
add_message(client, 'the message by foo')
logout(client)
register_and_login(client, 'bar', 'default')
add_message(client, 'the message by bar')
rv = client.get('/public')
assert b'the message by foo' in rv.data
assert b'the message by bar' in rv.data
# bar's timeline should just show bar's message
rv = client.get('/')
assert b'the message by foo' not in rv.data
assert b'the message by bar' in rv.data
# now let's follow foo
rv = client.get('/foo/follow', follow_redirects=True)
assert b'You are now following &#34;foo&#34;' in rv.data
# we should now see foo's message
rv = client.get('/')
assert b'the message by foo' in rv.data
assert b'the message by bar' in rv.data
# but on the user's page we only want the user's message
rv = client.get('/bar')
assert b'the message by foo' not in rv.data
assert b'the message by bar' in rv.data
rv = client.get('/foo')
assert b'the message by foo' in rv.data
assert b'the message by bar' not in rv.data
# now unfollow and check if that worked
rv = client.get('/foo/unfollow', follow_redirects=True)
assert b'You are no longer following &#34;foo&#34;' in rv.data
rv = client.get('/')
assert b'the message by foo' not in rv.data
assert b'the message by bar' in rv.data

253
flask/testsuite/__init__.py

@ -1,253 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite
~~~~~~~~~~~~~~~
Tests Flask itself. The majority of Flask is already tested
as part of Werkzeug.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
from __future__ import print_function
import os
import sys
import flask
import warnings
import unittest
from functools import update_wrapper
from contextlib import contextmanager
from werkzeug.utils import import_string, find_modules
from flask._compat import reraise, StringIO
def add_to_path(path):
"""Adds an entry to sys.path if it's not already there. This does
not append it but moves it to the front so that we can be sure it
is loaded.
"""
if not os.path.isdir(path):
raise RuntimeError('Tried to add nonexisting path')
def _samefile(x, y):
if x == y:
return True
try:
return os.path.samefile(x, y)
except (IOError, OSError, AttributeError):
# Windows has no samefile
return False
sys.path[:] = [x for x in sys.path if not _samefile(path, x)]
sys.path.insert(0, path)
def iter_suites():
"""Yields all testsuites."""
for module in find_modules(__name__):
mod = import_string(module)
if hasattr(mod, 'suite'):
yield mod.suite()
def find_all_tests(suite):
"""Yields all the tests and their names from a given suite."""
suites = [suite]
while suites:
s = suites.pop()
try:
suites.extend(s)
except TypeError:
yield s, '%s.%s.%s' % (
s.__class__.__module__,
s.__class__.__name__,
s._testMethodName
)
@contextmanager
def catch_warnings():
"""Catch warnings in a with block in a list"""
# make sure deprecation warnings are active in tests
warnings.simplefilter('default', category=DeprecationWarning)
filters = warnings.filters
warnings.filters = filters[:]
old_showwarning = warnings.showwarning
log = []
def showwarning(message, category, filename, lineno, file=None, line=None):
log.append(locals())
try:
warnings.showwarning = showwarning
yield log
finally:
warnings.filters = filters
warnings.showwarning = old_showwarning
@contextmanager
def catch_stderr():
"""Catch stderr in a StringIO"""
old_stderr = sys.stderr
sys.stderr = rv = StringIO()
try:
yield rv
finally:
sys.stderr = old_stderr
def emits_module_deprecation_warning(f):
def new_f(self, *args, **kwargs):
with catch_warnings() as log:
f(self, *args, **kwargs)
self.assert_true(log, 'expected deprecation warning')
for entry in log:
self.assert_in('Modules are deprecated', str(entry['message']))
return update_wrapper(new_f, f)
class FlaskTestCase(unittest.TestCase):
"""Baseclass for all the tests that Flask uses. Use these methods
for testing instead of the camelcased ones in the baseclass for
consistency.
"""
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())
self.assert_equal(leaks, [])
def setup(self):
pass
def teardown(self):
pass
def setUp(self):
self.setup()
def tearDown(self):
unittest.TestCase.tearDown(self)
self.ensure_clean_request_context()
self.teardown()
def assert_equal(self, x, y):
return self.assertEqual(x, y)
def assert_raises(self, exc_type, callable=None, *args, **kwargs):
catcher = _ExceptionCatcher(self, exc_type)
if callable is None:
return catcher
with catcher:
callable(*args, **kwargs)
def assert_true(self, x, msg=None):
self.assertTrue(x, msg)
assert_ = assert_true
def assert_false(self, x, msg=None):
self.assertFalse(x, msg)
def assert_in(self, x, y):
self.assertIn(x, y)
def assert_not_in(self, x, y):
self.assertNotIn(x, y)
def assert_isinstance(self, obj, cls):
self.assertIsInstance(obj, cls)
if sys.version_info[:2] == (2, 6):
def assertIn(self, x, y):
assert x in y, "%r unexpectedly not in %r" % (x, y)
def assertNotIn(self, x, y):
assert x not in y, "%r unexpectedly in %r" % (x, y)
def assertIsInstance(self, x, y):
assert isinstance(x, y), "not isinstance(%r, %r)" % (x, y)
class _ExceptionCatcher(object):
def __init__(self, test_case, exc_type):
self.test_case = test_case
self.exc_type = exc_type
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, tb):
exception_name = self.exc_type.__name__
if exc_type is None:
self.test_case.fail('Expected exception of type %r' %
exception_name)
elif not issubclass(exc_type, self.exc_type):
reraise(exc_type, exc_value, tb)
return True
class BetterLoader(unittest.TestLoader):
"""A nicer loader that solves two problems. First of all we are setting
up tests from different sources and we're doing this programmatically
which breaks the default loading logic so this is required anyways.
Secondly this loader has a nicer interpolation for test names than the
default one so you can just do ``run-tests.py ViewTestCase`` and it
will work.
"""
def getRootSuite(self):
return suite()
def loadTestsFromName(self, name, module=None):
root = self.getRootSuite()
if name == 'suite':
return root
all_tests = []
for testcase, testname in find_all_tests(root):
if testname == name or \
testname.endswith('.' + name) or \
('.' + name + '.') in testname or \
testname.startswith(name + '.'):
all_tests.append(testcase)
if not all_tests:
raise LookupError('could not find test case for "%s"' % name)
if len(all_tests) == 1:
return all_tests[0]
rv = unittest.TestSuite()
for test in all_tests:
rv.addTest(test)
return rv
def setup_path():
add_to_path(os.path.abspath(os.path.join(
os.path.dirname(__file__), 'test_apps')))
def suite():
"""A testsuite that has all the Flask tests. You can use this
function to integrate the Flask tests into your own testsuite
in case you want to test that monkeypatches to Flask do not
break it.
"""
setup_path()
suite = unittest.TestSuite()
for other_suite in iter_suites():
suite.addTest(other_suite)
return suite
def main():
"""Runs the testsuite as command line application."""
try:
unittest.main(testLoader=BetterLoader(), defaultTest='suite')
except Exception as e:
print('Error: %s' % e)

118
flask/testsuite/appctx.py

@ -1,118 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.appctx
~~~~~~~~~~~~~~~~~~~~~~
Tests the application context.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import unittest
from flask.testsuite import FlaskTestCase
class AppContextTestCase(FlaskTestCase):
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')
self.assert_equal(rv, 'https://localhost/')
def test_url_generation_requires_server_name(self):
app = flask.Flask(__name__)
with app.app_context():
with self.assert_raises(RuntimeError):
flask.url_for('index')
def test_url_generation_without_context_fails(self):
with self.assert_raises(RuntimeError):
flask.url_for('index')
def test_request_context_means_app_context(self):
app = flask.Flask(__name__)
with app.test_request_context():
self.assert_equal(flask.current_app._get_current_object(), app)
self.assert_equal(flask._app_ctx_stack.top, None)
def test_app_context_provides_current_app(self):
app = flask.Flask(__name__)
with app.app_context():
self.assert_equal(flask.current_app._get_current_object(), app)
self.assert_equal(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
self.assert_equal(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
self.assert_equal(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():
self.assert_equal(
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
self.assert_true(flask._request_ctx_stack.top.request.environ
['werkzeug.request'] is not None)
return u''
c = app.test_client()
c.get('/')
self.assertEqual(called, ['request', 'app'])
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(AppContextTestCase))
return suite

1364
flask/testsuite/basic.py

File diff suppressed because it is too large Load Diff

585
flask/testsuite/blueprints.py

@ -1,585 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.blueprints
~~~~~~~~~~~~~~~~~~~~~~~~~~
Blueprints (and currently modules)
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import unittest
from flask.testsuite import FlaskTestCase
from flask._compat import text_type
from werkzeug.http import parse_cache_control_header
from jinja2 import TemplateNotFound
class BlueprintTestCase(FlaskTestCase):
def test_blueprint_specific_error_handling(self):
frontend = flask.Blueprint('frontend', __name__)
backend = flask.Blueprint('backend', __name__)
sideend = flask.Blueprint('sideend', __name__)
@frontend.errorhandler(403)
def frontend_forbidden(e):
return 'frontend says no', 403
@frontend.route('/frontend-no')
def frontend_no():
flask.abort(403)
@backend.errorhandler(403)
def backend_forbidden(e):
return 'backend says no', 403
@backend.route('/backend-no')
def backend_no():
flask.abort(403)
@sideend.route('/what-is-a-sideend')
def sideend_no():
flask.abort(403)
app = flask.Flask(__name__)
app.register_blueprint(frontend)
app.register_blueprint(backend)
app.register_blueprint(sideend)
@app.errorhandler(403)
def app_forbidden(e):
return 'application itself says no', 403
c = app.test_client()
self.assert_equal(c.get('/frontend-no').data, b'frontend says no')
self.assert_equal(c.get('/backend-no').data, b'backend says no')
self.assert_equal(c.get('/what-is-a-sideend').data, b'application itself says no')
def test_blueprint_specific_user_error_handling(self):
class MyDecoratorException(Exception):
pass
class MyFunctionException(Exception):
pass
blue = flask.Blueprint('blue', __name__)
@blue.errorhandler(MyDecoratorException)
def my_decorator_exception_handler(e):
self.assert_true(isinstance(e, MyDecoratorException))
return 'boom'
def my_function_exception_handler(e):
self.assert_true(isinstance(e, MyFunctionException))
return 'bam'
blue.register_error_handler(MyFunctionException, my_function_exception_handler)
@blue.route('/decorator')
def blue_deco_test():
raise MyDecoratorException()
@blue.route('/function')
def blue_func_test():
raise MyFunctionException()
app = flask.Flask(__name__)
app.register_blueprint(blue)
c = app.test_client()
self.assert_equal(c.get('/decorator').data, b'boom')
self.assert_equal(c.get('/function').data, b'bam')
def test_blueprint_url_definitions(self):
bp = flask.Blueprint('test', __name__)
@bp.route('/foo', defaults={'baz': 42})
def foo(bar, baz):
return '%s/%d' % (bar, baz)
@bp.route('/bar')
def bar(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='/2', url_defaults={'bar': 19})
c = app.test_client()
self.assert_equal(c.get('/1/foo').data, b'23/42')
self.assert_equal(c.get('/2/foo').data, b'19/42')
self.assert_equal(c.get('/1/bar').data, b'23')
self.assert_equal(c.get('/2/bar').data, b'19')
def test_blueprint_url_processors(self):
bp = flask.Blueprint('frontend', __name__, url_prefix='/<lang_code>')
@bp.url_defaults
def add_language_code(endpoint, values):
values.setdefault('lang_code', flask.g.lang_code)
@bp.url_value_preprocessor
def pull_lang_code(endpoint, values):
flask.g.lang_code = values.pop('lang_code')
@bp.route('/')
def index():
return flask.url_for('.about')
@bp.route('/about')
def about():
return flask.url_for('.index')
app = flask.Flask(__name__)
app.register_blueprint(bp)
c = app.test_client()
self.assert_equal(c.get('/de/').data, b'/de/about')
self.assert_equal(c.get('/de/about').data, b'/de/')
def test_templates_and_static(self):
from blueprintapp import app
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.data, b'Hello from the Frontend')
rv = c.get('/admin/')
self.assert_equal(rv.data, b'Hello from the Admin')
rv = c.get('/admin/index2')
self.assert_equal(rv.data, b'Hello from the Admin')
rv = c.get('/admin/static/test.txt')
self.assert_equal(rv.data.strip(), b'Admin File')
rv.close()
rv = c.get('/admin/static/css/test.css')
self.assert_equal(rv.data.strip(), b'/* nested file */')
rv.close()
# try/finally, in case other tests use this app for Blueprint tests.
max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT']
try:
expected_max_age = 3600
if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == expected_max_age:
expected_max_age = 7200
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = expected_max_age
rv = c.get('/admin/static/css/test.css')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, expected_max_age)
rv.close()
finally:
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default
with app.test_request_context():
self.assert_equal(flask.url_for('admin.static', filename='test.txt'),
'/admin/static/test.txt')
with app.test_request_context():
try:
flask.render_template('missing.html')
except TemplateNotFound as e:
self.assert_equal(e.name, 'missing.html')
else:
self.assert_true(0, 'expected exception')
with flask.Flask(__name__).test_request_context():
self.assert_equal(flask.render_template('nested/nested.txt'), 'I\'m nested')
def test_default_static_cache_timeout(self):
app = flask.Flask(__name__)
class MyBlueprint(flask.Blueprint):
def get_send_file_max_age(self, filename):
return 100
blueprint = MyBlueprint('blueprint', __name__, static_folder='static')
app.register_blueprint(blueprint)
# try/finally, in case other tests use this app for Blueprint tests.
max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT']
try:
with app.test_request_context():
unexpected_max_age = 3600
if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == unexpected_max_age:
unexpected_max_age = 7200
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = unexpected_max_age
rv = blueprint.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 100)
rv.close()
finally:
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default
def test_templates_list(self):
from blueprintapp import app
templates = sorted(app.jinja_env.list_templates())
self.assert_equal(templates, ['admin/index.html',
'frontend/index.html'])
def test_dotted_names(self):
frontend = flask.Blueprint('myapp.frontend', __name__)
backend = flask.Blueprint('myapp.backend', __name__)
@frontend.route('/fe')
def frontend_index():
return flask.url_for('myapp.backend.backend_index')
@frontend.route('/fe2')
def frontend_page2():
return flask.url_for('.frontend_index')
@backend.route('/be')
def backend_index():
return flask.url_for('myapp.frontend.frontend_index')
app = flask.Flask(__name__)
app.register_blueprint(frontend)
app.register_blueprint(backend)
c = app.test_client()
self.assert_equal(c.get('/fe').data.strip(), b'/be')
self.assert_equal(c.get('/fe2').data.strip(), b'/fe')
self.assert_equal(c.get('/be').data.strip(), b'/fe')
def test_dotted_names_from_app(self):
app = flask.Flask(__name__)
app.testing = True
test = flask.Blueprint('test', __name__)
@app.route('/')
def app_index():
return flask.url_for('test.index')
@test.route('/test/')
def index():
return flask.url_for('app_index')
app.register_blueprint(test)
with app.test_client() as c:
rv = c.get('/')
self.assert_equal(rv.data, b'/test/')
def test_empty_url_defaults(self):
bp = flask.Blueprint('bp', __name__)
@bp.route('/', defaults={'page': 1})
@bp.route('/page/<int:page>')
def something(page):
return str(page)
app = flask.Flask(__name__)
app.register_blueprint(bp)
c = app.test_client()
self.assert_equal(c.get('/').data, b'1')
self.assert_equal(c.get('/page/2').data, b'2')
def test_route_decorator_custom_endpoint(self):
bp = flask.Blueprint('bp', __name__)
@bp.route('/foo')
def foo():
return flask.request.endpoint
@bp.route('/bar', endpoint='bar')
def foo_bar():
return flask.request.endpoint
@bp.route('/bar/123', endpoint='123')
def foo_bar_foo():
return flask.request.endpoint
@bp.route('/bar/foo')
def bar_foo():
return flask.request.endpoint
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.request.endpoint
c = app.test_client()
self.assertEqual(c.get('/').data, b'index')
self.assertEqual(c.get('/py/foo').data, b'bp.foo')
self.assertEqual(c.get('/py/bar').data, b'bp.bar')
self.assertEqual(c.get('/py/bar/123').data, b'bp.123')
self.assertEqual(c.get('/py/bar/foo').data, b'bp.bar_foo')
def test_route_decorator_custom_endpoint_with_dots(self):
bp = flask.Blueprint('bp', __name__)
@bp.route('/foo')
def foo():
return flask.request.endpoint
try:
@bp.route('/bar', endpoint='bar.bar')
def foo_bar():
return flask.request.endpoint
except AssertionError:
pass
else:
raise AssertionError('expected AssertionError not raised')
try:
@bp.route('/bar/123', endpoint='bar.123')
def foo_bar_foo():
return flask.request.endpoint
except AssertionError:
pass
else:
raise AssertionError('expected AssertionError not raised')
def foo_foo_foo():
pass
self.assertRaises(
AssertionError,
lambda: bp.add_url_rule(
'/bar/123', endpoint='bar.123', view_func=foo_foo_foo
)
)
self.assertRaises(
AssertionError,
bp.route('/bar/123', endpoint='bar.123'),
lambda: None
)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
c = app.test_client()
self.assertEqual(c.get('/py/foo').data, b'bp.foo')
# The rule's didn't actually made it through
rv = c.get('/py/bar')
assert rv.status_code == 404
rv = c.get('/py/bar/123')
assert rv.status_code == 404
def test_template_filter(self):
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter()
def my_reverse(s):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_in('my_reverse', app.jinja_env.filters.keys())
self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse)
self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba')
def test_add_template_filter(self):
bp = flask.Blueprint('bp', __name__)
def my_reverse(s):
return s[::-1]
bp.add_app_template_filter(my_reverse)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_in('my_reverse', app.jinja_env.filters.keys())
self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse)
self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba')
def test_template_filter_with_name(self):
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter('strrev')
def my_reverse(s):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_in('strrev', app.jinja_env.filters.keys())
self.assert_equal(app.jinja_env.filters['strrev'], my_reverse)
self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba')
def test_add_template_filter_with_name(self):
bp = flask.Blueprint('bp', __name__)
def my_reverse(s):
return s[::-1]
bp.add_app_template_filter(my_reverse, 'strrev')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_in('strrev', app.jinja_env.filters.keys())
self.assert_equal(app.jinja_env.filters['strrev'], my_reverse)
self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba')
def test_template_filter_with_template(self):
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter()
def super_reverse(s):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'dcba')
def test_template_filter_after_route_with_template(self):
app = flask.Flask(__name__)
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter()
def super_reverse(s):
return s[::-1]
app.register_blueprint(bp, url_prefix='/py')
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'dcba')
def test_add_template_filter_with_template(self):
bp = flask.Blueprint('bp', __name__)
def super_reverse(s):
return s[::-1]
bp.add_app_template_filter(super_reverse)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'dcba')
def test_template_filter_with_name_and_template(self):
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter('super_reverse')
def my_reverse(s):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'dcba')
def test_add_template_filter_with_name_and_template(self):
bp = flask.Blueprint('bp', __name__)
def my_reverse(s):
return s[::-1]
bp.add_app_template_filter(my_reverse, 'super_reverse')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'dcba')
def test_template_test(self):
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test()
def is_boolean(value):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_in('is_boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['is_boolean'], is_boolean)
self.assert_true(app.jinja_env.tests['is_boolean'](False))
def test_add_template_test(self):
bp = flask.Blueprint('bp', __name__)
def is_boolean(value):
return isinstance(value, bool)
bp.add_app_template_test(is_boolean)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_in('is_boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['is_boolean'], is_boolean)
self.assert_true(app.jinja_env.tests['is_boolean'](False))
def test_template_test_with_name(self):
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test('boolean')
def is_boolean(value):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
self.assert_true(app.jinja_env.tests['boolean'](False))
def test_add_template_test_with_name(self):
bp = flask.Blueprint('bp', __name__)
def is_boolean(value):
return isinstance(value, bool)
bp.add_app_template_test(is_boolean, 'boolean')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
self.assert_true(app.jinja_env.tests['boolean'](False))
def test_template_test_with_template(self):
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test()
def boolean(value):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_in(b'Success!', rv.data)
def test_template_test_after_route_with_template(self):
app = flask.Flask(__name__)
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test()
def boolean(value):
return isinstance(value, bool)
app.register_blueprint(bp, url_prefix='/py')
rv = app.test_client().get('/')
self.assert_in(b'Success!', rv.data)
def test_add_template_test_with_template(self):
bp = flask.Blueprint('bp', __name__)
def boolean(value):
return isinstance(value, bool)
bp.add_app_template_test(boolean)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_in(b'Success!', rv.data)
def test_template_test_with_name_and_template(self):
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test('boolean')
def is_boolean(value):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_in(b'Success!', rv.data)
def test_add_template_test_with_name_and_template(self):
bp = flask.Blueprint('bp', __name__)
def is_boolean(value):
return isinstance(value, bool)
bp.add_app_template_test(is_boolean, 'boolean')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_in(b'Success!', rv.data)
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(BlueprintTestCase))
return suite

384
flask/testsuite/config.py

@ -1,384 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.config
~~~~~~~~~~~~~~~~~~~~~~
Configuration and instances.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import os
import sys
import flask
import pkgutil
import unittest
from contextlib import contextmanager
from flask.testsuite import FlaskTestCase
from flask._compat import PY2
# config keys used for the ConfigTestCase
TEST_KEY = 'foo'
SECRET_KEY = 'devkey'
class ConfigTestCase(FlaskTestCase):
def common_object_test(self, app):
self.assert_equal(app.secret_key, 'devkey')
self.assert_equal(app.config['TEST_KEY'], 'foo')
self.assert_not_in('ConfigTestCase', app.config)
def test_config_from_file(self):
app = flask.Flask(__name__)
app.config.from_pyfile(__file__.rsplit('.', 1)[0] + '.py')
self.common_object_test(app)
def test_config_from_object(self):
app = flask.Flask(__name__)
app.config.from_object(__name__)
self.common_object_test(app)
def test_config_from_json(self):
app = flask.Flask(__name__)
current_dir = os.path.dirname(os.path.abspath(__file__))
app.config.from_json(os.path.join(current_dir, 'static', 'config.json'))
self.common_object_test(app)
def test_config_from_mapping(self):
app = flask.Flask(__name__)
app.config.from_mapping({
'SECRET_KEY': 'devkey',
'TEST_KEY': 'foo'
})
self.common_object_test(app)
app = flask.Flask(__name__)
app.config.from_mapping([
('SECRET_KEY', 'devkey'),
('TEST_KEY', 'foo')
])
self.common_object_test(app)
app = flask.Flask(__name__)
app.config.from_mapping(
SECRET_KEY='devkey',
TEST_KEY='foo'
)
self.common_object_test(app)
app = flask.Flask(__name__)
with self.assert_raises(TypeError):
app.config.from_mapping(
{}, {}
)
def test_config_from_class(self):
class Base(object):
TEST_KEY = 'foo'
class Test(Base):
SECRET_KEY = 'devkey'
app = flask.Flask(__name__)
app.config.from_object(Test)
self.common_object_test(app)
def test_config_from_envvar(self):
env = os.environ
try:
os.environ = {}
app = flask.Flask(__name__)
try:
app.config.from_envvar('FOO_SETTINGS')
except RuntimeError as e:
self.assert_true("'FOO_SETTINGS' is not set" in str(e))
else:
self.assert_true(0, 'expected exception')
self.assert_false(app.config.from_envvar('FOO_SETTINGS', silent=True))
os.environ = {'FOO_SETTINGS': __file__.rsplit('.', 1)[0] + '.py'}
self.assert_true(app.config.from_envvar('FOO_SETTINGS'))
self.common_object_test(app)
finally:
os.environ = env
def test_config_from_envvar_missing(self):
env = os.environ
try:
os.environ = {'FOO_SETTINGS': 'missing.cfg'}
try:
app = flask.Flask(__name__)
app.config.from_envvar('FOO_SETTINGS')
except IOError as e:
msg = str(e)
self.assert_true(msg.startswith('[Errno 2] Unable to load configuration '
'file (No such file or directory):'))
self.assert_true(msg.endswith("missing.cfg'"))
else:
self.fail('expected IOError')
self.assertFalse(app.config.from_envvar('FOO_SETTINGS', silent=True))
finally:
os.environ = env
def test_config_missing(self):
app = flask.Flask(__name__)
try:
app.config.from_pyfile('missing.cfg')
except IOError as e:
msg = str(e)
self.assert_true(msg.startswith('[Errno 2] Unable to load configuration '
'file (No such file or directory):'))
self.assert_true(msg.endswith("missing.cfg'"))
else:
self.assert_true(0, 'expected config')
self.assert_false(app.config.from_pyfile('missing.cfg', silent=True))
def test_config_missing_json(self):
app = flask.Flask(__name__)
try:
app.config.from_json('missing.json')
except IOError as e:
msg = str(e)
self.assert_true(msg.startswith('[Errno 2] Unable to load configuration '
'file (No such file or directory):'))
self.assert_true(msg.endswith("missing.json'"))
else:
self.assert_true(0, 'expected config')
self.assert_false(app.config.from_json('missing.json', silent=True))
def test_custom_config_class(self):
class Config(flask.Config):
pass
class Flask(flask.Flask):
config_class = Config
app = Flask(__name__)
self.assert_isinstance(app.config, Config)
app.config.from_object(__name__)
self.common_object_test(app)
def test_session_lifetime(self):
app = flask.Flask(__name__)
app.config['PERMANENT_SESSION_LIFETIME'] = 42
self.assert_equal(app.permanent_session_lifetime.seconds, 42)
def test_get_namespace(self):
app = flask.Flask(__name__)
app.config['FOO_OPTION_1'] = 'foo option 1'
app.config['FOO_OPTION_2'] = 'foo option 2'
app.config['BAR_STUFF_1'] = 'bar stuff 1'
app.config['BAR_STUFF_2'] = 'bar stuff 2'
foo_options = app.config.get_namespace('FOO_')
self.assert_equal(2, len(foo_options))
self.assert_equal('foo option 1', foo_options['option_1'])
self.assert_equal('foo option 2', foo_options['option_2'])
bar_options = app.config.get_namespace('BAR_', lowercase=False)
self.assert_equal(2, len(bar_options))
self.assert_equal('bar stuff 1', bar_options['STUFF_1'])
self.assert_equal('bar stuff 2', bar_options['STUFF_2'])
class LimitedLoaderMockWrapper(object):
def __init__(self, loader):
self.loader = loader
def __getattr__(self, name):
if name in ('archive', 'get_filename'):
msg = 'Mocking a loader which does not have `%s.`' % name
raise AttributeError(msg)
return getattr(self.loader, name)
@contextmanager
def patch_pkgutil_get_loader(wrapper_class=LimitedLoaderMockWrapper):
"""Patch pkgutil.get_loader to give loader without get_filename or archive.
This provides for tests where a system has custom loaders, e.g. Google App
Engine's HardenedModulesHook, which have neither the `get_filename` method
nor the `archive` attribute.
"""
old_get_loader = pkgutil.get_loader
def get_loader(*args, **kwargs):
return wrapper_class(old_get_loader(*args, **kwargs))
try:
pkgutil.get_loader = get_loader
yield
finally:
pkgutil.get_loader = old_get_loader
class InstanceTestCase(FlaskTestCase):
def test_explicit_instance_paths(self):
here = os.path.abspath(os.path.dirname(__file__))
try:
flask.Flask(__name__, instance_path='instance')
except ValueError as e:
self.assert_in('must be absolute', str(e))
else:
self.fail('Expected value error')
app = flask.Flask(__name__, instance_path=here)
self.assert_equal(app.instance_path, here)
def test_main_module_paths(self):
# Test an app with '__main__' as the import name, uses cwd.
from main_app import app
here = os.path.abspath(os.getcwd())
self.assert_equal(app.instance_path, os.path.join(here, 'instance'))
if 'main_app' in sys.modules:
del sys.modules['main_app']
def test_uninstalled_module_paths(self):
from config_module_app import app
here = os.path.abspath(os.path.dirname(__file__))
self.assert_equal(app.instance_path, os.path.join(here, 'test_apps', 'instance'))
def test_uninstalled_package_paths(self):
from config_package_app import app
here = os.path.abspath(os.path.dirname(__file__))
self.assert_equal(app.instance_path, os.path.join(here, 'test_apps', 'instance'))
def test_installed_module_paths(self):
here = os.path.abspath(os.path.dirname(__file__))
expected_prefix = os.path.join(here, 'test_apps')
real_prefix, sys.prefix = sys.prefix, expected_prefix
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
sys.path.append(site_packages)
try:
import site_app
self.assert_equal(site_app.app.instance_path,
os.path.join(expected_prefix, 'var',
'site_app-instance'))
finally:
sys.prefix = real_prefix
sys.path.remove(site_packages)
if 'site_app' in sys.modules:
del sys.modules['site_app']
def test_installed_module_paths_with_limited_loader(self):
here = os.path.abspath(os.path.dirname(__file__))
expected_prefix = os.path.join(here, 'test_apps')
real_prefix, sys.prefix = sys.prefix, expected_prefix
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
sys.path.append(site_packages)
with patch_pkgutil_get_loader():
try:
import site_app
self.assert_equal(site_app.app.instance_path,
os.path.join(expected_prefix, 'var',
'site_app-instance'))
finally:
sys.prefix = real_prefix
sys.path.remove(site_packages)
if 'site_app' in sys.modules:
del sys.modules['site_app']
def test_installed_package_paths(self):
here = os.path.abspath(os.path.dirname(__file__))
expected_prefix = os.path.join(here, 'test_apps')
real_prefix, sys.prefix = sys.prefix, expected_prefix
installed_path = os.path.join(expected_prefix, 'path')
sys.path.append(installed_path)
try:
import installed_package
self.assert_equal(installed_package.app.instance_path,
os.path.join(expected_prefix, 'var',
'installed_package-instance'))
finally:
sys.prefix = real_prefix
sys.path.remove(installed_path)
if 'installed_package' in sys.modules:
del sys.modules['installed_package']
def test_installed_package_paths_with_limited_loader(self):
here = os.path.abspath(os.path.dirname(__file__))
expected_prefix = os.path.join(here, 'test_apps')
real_prefix, sys.prefix = sys.prefix, expected_prefix
installed_path = os.path.join(expected_prefix, 'path')
sys.path.append(installed_path)
with patch_pkgutil_get_loader():
try:
import installed_package
self.assert_equal(installed_package.app.instance_path,
os.path.join(expected_prefix, 'var',
'installed_package-instance'))
finally:
sys.prefix = real_prefix
sys.path.remove(installed_path)
if 'installed_package' in sys.modules:
del sys.modules['installed_package']
def test_prefix_package_paths(self):
here = os.path.abspath(os.path.dirname(__file__))
expected_prefix = os.path.join(here, 'test_apps')
real_prefix, sys.prefix = sys.prefix, expected_prefix
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
sys.path.append(site_packages)
try:
import site_package
self.assert_equal(site_package.app.instance_path,
os.path.join(expected_prefix, 'var',
'site_package-instance'))
finally:
sys.prefix = real_prefix
sys.path.remove(site_packages)
if 'site_package' in sys.modules:
del sys.modules['site_package']
def test_prefix_package_paths_with_limited_loader(self):
here = os.path.abspath(os.path.dirname(__file__))
expected_prefix = os.path.join(here, 'test_apps')
real_prefix, sys.prefix = sys.prefix, expected_prefix
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
sys.path.append(site_packages)
with patch_pkgutil_get_loader():
try:
import site_package
self.assert_equal(site_package.app.instance_path,
os.path.join(expected_prefix, 'var',
'site_package-instance'))
finally:
sys.prefix = real_prefix
sys.path.remove(site_packages)
if 'site_package' in sys.modules:
del sys.modules['site_package']
def test_egg_installed_paths(self):
here = os.path.abspath(os.path.dirname(__file__))
expected_prefix = os.path.join(here, 'test_apps')
real_prefix, sys.prefix = sys.prefix, expected_prefix
site_packages = os.path.join(expected_prefix, 'lib', 'python2.5', 'site-packages')
egg_path = os.path.join(site_packages, 'SiteEgg.egg')
sys.path.append(site_packages)
sys.path.append(egg_path)
try:
import site_egg # in SiteEgg.egg
self.assert_equal(site_egg.app.instance_path,
os.path.join(expected_prefix, 'var',
'site_egg-instance'))
finally:
sys.prefix = real_prefix
sys.path.remove(site_packages)
sys.path.remove(egg_path)
if 'site_egg' in sys.modules:
del sys.modules['site_egg']
if PY2:
def test_meta_path_loader_without_is_package(self):
class Loader(object):
def find_module(self, name):
return self
sys.meta_path.append(Loader())
try:
with self.assert_raises(AttributeError):
flask.Flask(__name__)
finally:
sys.meta_path.pop()
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(ConfigTestCase))
suite.addTest(unittest.makeSuite(InstanceTestCase))
return suite

24
flask/testsuite/deprecations.py

@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.deprecations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tests deprecation support.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import unittest
from flask.testsuite import FlaskTestCase, catch_warnings
class DeprecationsTestCase(FlaskTestCase):
"""not used currently"""
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(DeprecationsTestCase))
return suite

38
flask/testsuite/examples.py

@ -1,38 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.examples
~~~~~~~~~~~~~~~~~~~~~~~~
Tests the examples.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import os
import unittest
from flask.testsuite import add_to_path
def setup_path():
example_path = os.path.join(os.path.dirname(__file__),
os.pardir, os.pardir, 'examples')
add_to_path(os.path.join(example_path, 'flaskr'))
add_to_path(os.path.join(example_path, 'minitwit'))
def suite():
setup_path()
suite = unittest.TestSuite()
try:
from minitwit_tests import MiniTwitTestCase
except ImportError:
pass
else:
suite.addTest(unittest.makeSuite(MiniTwitTestCase))
try:
from flaskr_tests import FlaskrTestCase
except ImportError:
pass
else:
suite.addTest(unittest.makeSuite(FlaskrTestCase))
return suite

136
flask/testsuite/ext.py

@ -1,136 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.ext
~~~~~~~~~~~~~~~~~~~
Tests the extension import thing.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import sys
import unittest
try:
from imp import reload as reload_module
except ImportError:
reload_module = reload
from flask.testsuite import FlaskTestCase
from flask._compat import PY2
class ExtImportHookTestCase(FlaskTestCase):
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
self.assert_equal(import_hooks, 1)
def teardown(self):
from flask import ext
for key in ext.__dict__:
self.assert_not_in('.', key)
def test_flaskext_new_simple_import_normal(self):
from flask.ext.newext_simple import ext_id
self.assert_equal(ext_id, 'newext_simple')
def test_flaskext_new_simple_import_module(self):
from flask.ext import newext_simple
self.assert_equal(newext_simple.ext_id, 'newext_simple')
self.assert_equal(newext_simple.__name__, 'flask_newext_simple')
def test_flaskext_new_package_import_normal(self):
from flask.ext.newext_package import ext_id
self.assert_equal(ext_id, 'newext_package')
def test_flaskext_new_package_import_module(self):
from flask.ext import newext_package
self.assert_equal(newext_package.ext_id, 'newext_package')
self.assert_equal(newext_package.__name__, 'flask_newext_package')
def test_flaskext_new_package_import_submodule_function(self):
from flask.ext.newext_package.submodule import test_function
self.assert_equal(test_function(), 42)
def test_flaskext_new_package_import_submodule(self):
from flask.ext.newext_package import submodule
self.assert_equal(submodule.__name__, 'flask_newext_package.submodule')
self.assert_equal(submodule.test_function(), 42)
def test_flaskext_old_simple_import_normal(self):
from flask.ext.oldext_simple import ext_id
self.assert_equal(ext_id, 'oldext_simple')
def test_flaskext_old_simple_import_module(self):
from flask.ext import oldext_simple
self.assert_equal(oldext_simple.ext_id, 'oldext_simple')
self.assert_equal(oldext_simple.__name__, 'flaskext.oldext_simple')
def test_flaskext_old_package_import_normal(self):
from flask.ext.oldext_package import ext_id
self.assert_equal(ext_id, 'oldext_package')
def test_flaskext_old_package_import_module(self):
from flask.ext import oldext_package
self.assert_equal(oldext_package.ext_id, 'oldext_package')
self.assert_equal(oldext_package.__name__, 'flaskext.oldext_package')
def test_flaskext_old_package_import_submodule(self):
from flask.ext.oldext_package import submodule
self.assert_equal(submodule.__name__, 'flaskext.oldext_package.submodule')
self.assert_equal(submodule.test_function(), 42)
def test_flaskext_old_package_import_submodule_function(self):
from flask.ext.oldext_package.submodule import test_function
self.assert_equal(test_function(), 42)
def test_flaskext_broken_package_no_module_caching(self):
for x in range(2):
with self.assert_raises(ImportError):
import flask.ext.broken
def test_no_error_swallowing(self):
try:
import flask.ext.broken
except ImportError:
exc_type, exc_value, tb = sys.exc_info()
self.assert_true(exc_type is ImportError)
if PY2:
message = 'No module named missing_module'
else:
message = 'No module named \'missing_module\''
self.assert_equal(str(exc_value), message)
self.assert_true(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
self.assert_in(os.path.join('flask_broken', '__init__.py'), next.tb_frame.f_code.co_filename)
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(ExtImportHookTestCase))
return suite

116
flask/testsuite/regression.py

@ -1,116 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.regression
~~~~~~~~~~~~~~~~~~~~~~~~~~
Tests regressions.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import os
import gc
import sys
import flask
import threading
import unittest
from werkzeug.exceptions import NotFound
from flask.testsuite import FlaskTestCase
_gc_lock = threading.Lock()
class _NoLeakAsserter(object):
def __init__(self, testcase):
self.testcase = testcase
def __enter__(self):
gc.disable()
_gc_lock.acquire()
loc = flask._request_ctx_stack._local
# Force Python to track this dictionary at all times.
# This is necessary since Python only starts tracking
# dicts if they contain mutable objects. It's a horrible,
# horrible hack but makes this kinda testable.
loc.__storage__['FOOO'] = [1, 2, 3]
gc.collect()
self.old_objects = len(gc.get_objects())
def __exit__(self, exc_type, exc_value, tb):
if not hasattr(sys, 'getrefcount'):
gc.collect()
new_objects = len(gc.get_objects())
if new_objects > self.old_objects:
self.testcase.fail('Example code leaked')
_gc_lock.release()
gc.enable()
class MemoryTestCase(FlaskTestCase):
def assert_no_leak(self):
return _NoLeakAsserter(self)
def test_memory_consumption(self):
app = flask.Flask(__name__)
@app.route('/')
def index():
return flask.render_template('simple_template.html', whiskey=42)
def fire():
with app.test_client() as c:
rv = c.get('/')
self.assert_equal(rv.status_code, 200)
self.assert_equal(rv.data, b'<h1>42</h1>')
# Trigger caches
fire()
# This test only works on CPython 2.7.
if sys.version_info >= (2, 7) and \
not hasattr(sys, 'pypy_translation_info'):
with self.assert_no_leak():
for x in range(10):
fire()
def test_safe_join_toplevel_pardir(self):
from flask.helpers import safe_join
with self.assert_raises(NotFound):
safe_join('/foo', '..')
class ExceptionTestCase(FlaskTestCase):
def test_aborting(self):
class Foo(Exception):
whatever = 42
app = flask.Flask(__name__)
app.testing = True
@app.errorhandler(Foo)
def handle_foo(e):
return str(e.whatever)
@app.route('/')
def index():
raise flask.abort(flask.redirect(flask.url_for('test')))
@app.route('/test')
def test():
raise Foo()
with app.test_client() as c:
rv = c.get('/')
self.assertEqual(rv.headers['Location'], 'http://localhost/test')
rv = c.get('/test')
self.assertEqual(rv.data, b'42')
def suite():
suite = unittest.TestSuite()
if os.environ.get('RUN_FLASK_MEMORY_TESTS') == '1':
suite.addTest(unittest.makeSuite(MemoryTestCase))
suite.addTest(unittest.makeSuite(ExceptionTestCase))
return suite

201
flask/testsuite/reqctx.py

@ -1,201 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.reqctx
~~~~~~~~~~~~~~~~~~~~~~
Tests the request context.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import unittest
try:
from greenlet import greenlet
except ImportError:
greenlet = None
from flask.testsuite import FlaskTestCase
class RequestContextTestCase(FlaskTestCase):
def test_teardown_on_pop(self):
buffer = []
app = flask.Flask(__name__)
@app.teardown_request
def end_of_request(exception):
buffer.append(exception)
ctx = app.test_request_context()
ctx.push()
self.assert_equal(buffer, [])
ctx.pop()
self.assert_equal(buffer, [None])
def test_teardown_with_previous_exception(self):
buffer = []
app = flask.Flask(__name__)
@app.teardown_request
def end_of_request(exception):
buffer.append(exception)
try:
raise Exception('dummy')
except Exception:
pass
with app.test_request_context():
self.assert_equal(buffer, [])
self.assert_equal(buffer, [None])
def test_proper_test_request_context(self):
app = flask.Flask(__name__)
app.config.update(
SERVER_NAME='localhost.localdomain:5000'
)
@app.route('/')
def index():
return None
@app.route('/', subdomain='foo')
def sub():
return None
with app.test_request_context('/'):
self.assert_equal(flask.url_for('index', _external=True), 'http://localhost.localdomain:5000/')
with app.test_request_context('/'):
self.assert_equal(flask.url_for('sub', _external=True), 'http://foo.localhost.localdomain:5000/')
try:
with app.test_request_context('/', environ_overrides={'HTTP_HOST': 'localhost'}):
pass
except Exception as e:
self.assert_true(isinstance(e, ValueError))
self.assert_equal(str(e), "the server name provided " +
"('localhost.localdomain:5000') does not match the " + \
"server name from the WSGI environment ('localhost')")
try:
app.config.update(SERVER_NAME='localhost')
with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost'}):
pass
except ValueError as e:
raise ValueError(
"No ValueError exception should have been raised \"%s\"" % e
)
try:
app.config.update(SERVER_NAME='localhost:80')
with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost:80'}):
pass
except ValueError as e:
raise ValueError(
"No ValueError exception should have been raised \"%s\"" % e
)
def test_context_binding(self):
app = flask.Flask(__name__)
@app.route('/')
def index():
return 'Hello %s!' % flask.request.args['name']
@app.route('/meh')
def meh():
return flask.request.url
with app.test_request_context('/?name=World'):
self.assert_equal(index(), 'Hello World!')
with app.test_request_context('/meh'):
self.assert_equal(meh(), 'http://localhost/meh')
self.assert_true(flask._request_ctx_stack.top is None)
def test_context_test(self):
app = flask.Flask(__name__)
self.assert_false(flask.request)
self.assert_false(flask.has_request_context())
ctx = app.test_request_context()
ctx.push()
try:
self.assert_true(flask.request)
self.assert_true(flask.has_request_context())
finally:
ctx.pop()
def test_manual_context_binding(self):
app = flask.Flask(__name__)
@app.route('/')
def index():
return 'Hello %s!' % flask.request.args['name']
ctx = app.test_request_context('/?name=World')
ctx.push()
self.assert_equal(index(), 'Hello World!')
ctx.pop()
try:
index()
except RuntimeError:
pass
else:
self.assert_true(0, 'expected runtime error')
def test_greenlet_context_copying(self):
app = flask.Flask(__name__)
greenlets = []
@app.route('/')
def index():
reqctx = flask._request_ctx_stack.top.copy()
def g():
self.assert_false(flask.request)
self.assert_false(flask.current_app)
with reqctx:
self.assert_true(flask.request)
self.assert_equal(flask.current_app, app)
self.assert_equal(flask.request.path, '/')
self.assert_equal(flask.request.args['foo'], 'bar')
self.assert_false(flask.request)
return 42
greenlets.append(greenlet(g))
return 'Hello World!'
rv = app.test_client().get('/?foo=bar')
self.assert_equal(rv.data, b'Hello World!')
result = greenlets[0].run()
self.assert_equal(result, 42)
def test_greenlet_context_copying_api(self):
app = flask.Flask(__name__)
greenlets = []
@app.route('/')
def index():
reqctx = flask._request_ctx_stack.top.copy()
@flask.copy_current_request_context
def g():
self.assert_true(flask.request)
self.assert_equal(flask.current_app, app)
self.assert_equal(flask.request.path, '/')
self.assert_equal(flask.request.args['foo'], 'bar')
return 42
greenlets.append(greenlet(g))
return 'Hello World!'
rv = app.test_client().get('/?foo=bar')
self.assert_equal(rv.data, b'Hello World!')
result = greenlets[0].run()
self.assert_equal(result, 42)
# Disable test if we don't have greenlets available
if greenlet is None:
test_greenlet_context_copying = None
test_greenlet_context_copying_api = None
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(RequestContextTestCase))
return suite

153
flask/testsuite/signals.py

@ -1,153 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.signals
~~~~~~~~~~~~~~~~~~~~~~~
Signalling.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import unittest
from flask.testsuite import FlaskTestCase
class SignalsTestCase(FlaskTestCase):
def test_template_rendered(self):
app = flask.Flask(__name__)
@app.route('/')
def index():
return flask.render_template('simple_template.html', whiskey=42)
recorded = []
def record(sender, template, context):
recorded.append((template, context))
flask.template_rendered.connect(record, app)
try:
app.test_client().get('/')
self.assert_equal(len(recorded), 1)
template, context = recorded[0]
self.assert_equal(template.name, 'simple_template.html')
self.assert_equal(context['whiskey'], 42)
finally:
flask.template_rendered.disconnect(record, app)
def test_request_signals(self):
app = flask.Flask(__name__)
calls = []
def before_request_signal(sender):
calls.append('before-signal')
def after_request_signal(sender, response):
self.assert_equal(response.data, b'stuff')
calls.append('after-signal')
@app.before_request
def before_request_handler():
calls.append('before-handler')
@app.after_request
def after_request_handler(response):
calls.append('after-handler')
response.data = 'stuff'
return response
@app.route('/')
def index():
calls.append('handler')
return 'ignored anyway'
flask.request_started.connect(before_request_signal, app)
flask.request_finished.connect(after_request_signal, app)
try:
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'stuff')
self.assert_equal(calls, ['before-signal', 'before-handler',
'handler', 'after-handler',
'after-signal'])
finally:
flask.request_started.disconnect(before_request_signal, app)
flask.request_finished.disconnect(after_request_signal, app)
def test_request_exception_signal(self):
app = flask.Flask(__name__)
recorded = []
@app.route('/')
def index():
1 // 0
def record(sender, exception):
recorded.append(exception)
flask.got_request_exception.connect(record, app)
try:
self.assert_equal(app.test_client().get('/').status_code, 500)
self.assert_equal(len(recorded), 1)
self.assert_true(isinstance(recorded[0], ZeroDivisionError))
finally:
flask.got_request_exception.disconnect(record, app)
def test_appcontext_signals(self):
app = flask.Flask(__name__)
recorded = []
def record_push(sender, **kwargs):
recorded.append('push')
def record_pop(sender, **kwargs):
recorded.append('pop')
@app.route('/')
def index():
return 'Hello'
flask.appcontext_pushed.connect(record_push, app)
flask.appcontext_popped.connect(record_pop, app)
try:
with app.test_client() as c:
rv = c.get('/')
self.assert_equal(rv.data, b'Hello')
self.assert_equal(recorded, ['push'])
self.assert_equal(recorded, ['push', 'pop'])
finally:
flask.appcontext_pushed.disconnect(record_push, app)
flask.appcontext_popped.disconnect(record_pop, app)
def test_flash_signal(self):
app = flask.Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
@app.route('/')
def index():
flask.flash('This is a flash message', category='notice')
return flask.redirect('/other')
recorded = []
def record(sender, message, category):
recorded.append((message, category))
flask.message_flashed.connect(record, app)
try:
client = app.test_client()
with client.session_transaction():
client.get('/')
self.assert_equal(len(recorded), 1)
message, category = recorded[0]
self.assert_equal(message, 'This is a flash message')
self.assert_equal(category, 'notice')
finally:
flask.message_flashed.disconnect(record, app)
def suite():
suite = unittest.TestSuite()
if flask.signals_available:
suite.addTest(unittest.makeSuite(SignalsTestCase))
return suite

46
flask/testsuite/subclassing.py

@ -1,46 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.subclassing
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Test that certain behavior of flask can be customized by
subclasses.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import unittest
from logging import StreamHandler
from flask.testsuite import FlaskTestCase
from flask._compat import StringIO
class FlaskSubclassingTestCase(FlaskTestCase):
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('/')
self.assert_equal(rv.status_code, 500)
self.assert_in(b'Internal Server Error', rv.data)
err = out.getvalue()
self.assert_equal(err, '')
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(FlaskSubclassingTestCase))
return suite

352
flask/testsuite/templating.py

@ -1,352 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.templating
~~~~~~~~~~~~~~~~~~~~~~~~~~
Template functionality
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import unittest
import logging
from jinja2 import TemplateNotFound
from flask.testsuite import FlaskTestCase
class TemplatingTestCase(FlaskTestCase):
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('/')
self.assert_equal(rv.data, b'<p>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('/')
self.assert_equal(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 }}')
self.assert_equal(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')
self.assert_equal(rv.data.split(), [b'42', b'23', b'False', b'aha'])
def test_escaping(self):
text = '<p>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()
self.assert_equal(lines, [
b'&lt;p&gt;Hello World!',
b'<p>Hello World!',
b'<p>Hello World!',
b'<p>Hello World!',
b'&lt;p&gt;Hello World!',
b'<p>Hello World!'
])
def test_no_escaping(self):
app = flask.Flask(__name__)
with app.test_request_context():
self.assert_equal(flask.render_template_string('{{ foo }}',
foo='<test>'), '<test>')
self.assert_equal(flask.render_template('mail.txt', foo='<test>'),
'<test> Mail')
def test_macros(self):
app = flask.Flask(__name__)
with app.test_request_context():
macro = flask.get_template_attribute('_macro.html', 'hello')
self.assert_equal(macro('World'), 'Hello World!')
def test_template_filter(self):
app = flask.Flask(__name__)
@app.template_filter()
def my_reverse(s):
return s[::-1]
self.assert_in('my_reverse', app.jinja_env.filters.keys())
self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse)
self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba')
def test_add_template_filter(self):
app = flask.Flask(__name__)
def my_reverse(s):
return s[::-1]
app.add_template_filter(my_reverse)
self.assert_in('my_reverse', app.jinja_env.filters.keys())
self.assert_equal(app.jinja_env.filters['my_reverse'], my_reverse)
self.assert_equal(app.jinja_env.filters['my_reverse']('abcd'), 'dcba')
def test_template_filter_with_name(self):
app = flask.Flask(__name__)
@app.template_filter('strrev')
def my_reverse(s):
return s[::-1]
self.assert_in('strrev', app.jinja_env.filters.keys())
self.assert_equal(app.jinja_env.filters['strrev'], my_reverse)
self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba')
def test_add_template_filter_with_name(self):
app = flask.Flask(__name__)
def my_reverse(s):
return s[::-1]
app.add_template_filter(my_reverse, 'strrev')
self.assert_in('strrev', app.jinja_env.filters.keys())
self.assert_equal(app.jinja_env.filters['strrev'], my_reverse)
self.assert_equal(app.jinja_env.filters['strrev']('abcd'), 'dcba')
def test_template_filter_with_template(self):
app = flask.Flask(__name__)
@app.template_filter()
def super_reverse(s):
return s[::-1]
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'dcba')
def test_add_template_filter_with_template(self):
app = flask.Flask(__name__)
def super_reverse(s):
return s[::-1]
app.add_template_filter(super_reverse)
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'dcba')
def test_template_filter_with_name_and_template(self):
app = flask.Flask(__name__)
@app.template_filter('super_reverse')
def my_reverse(s):
return s[::-1]
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'dcba')
def test_add_template_filter_with_name_and_template(self):
app = flask.Flask(__name__)
def my_reverse(s):
return s[::-1]
app.add_template_filter(my_reverse, 'super_reverse')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'dcba')
def test_template_test(self):
app = flask.Flask(__name__)
@app.template_test()
def boolean(value):
return isinstance(value, bool)
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], boolean)
self.assert_true(app.jinja_env.tests['boolean'](False))
def test_add_template_test(self):
app = flask.Flask(__name__)
def boolean(value):
return isinstance(value, bool)
app.add_template_test(boolean)
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], boolean)
self.assert_true(app.jinja_env.tests['boolean'](False))
def test_template_test_with_name(self):
app = flask.Flask(__name__)
@app.template_test('boolean')
def is_boolean(value):
return isinstance(value, bool)
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
self.assert_true(app.jinja_env.tests['boolean'](False))
def test_add_template_test_with_name(self):
app = flask.Flask(__name__)
def is_boolean(value):
return isinstance(value, bool)
app.add_template_test(is_boolean, 'boolean')
self.assert_in('boolean', app.jinja_env.tests.keys())
self.assert_equal(app.jinja_env.tests['boolean'], is_boolean)
self.assert_true(app.jinja_env.tests['boolean'](False))
def test_template_test_with_template(self):
app = flask.Flask(__name__)
@app.template_test()
def boolean(value):
return isinstance(value, bool)
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_in(b'Success!', rv.data)
def test_add_template_test_with_template(self):
app = flask.Flask(__name__)
def boolean(value):
return isinstance(value, bool)
app.add_template_test(boolean)
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_in(b'Success!', rv.data)
def test_template_test_with_name_and_template(self):
app = flask.Flask(__name__)
@app.template_test('boolean')
def is_boolean(value):
return isinstance(value, bool)
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_in(b'Success!', rv.data)
def test_add_template_test_with_name_and_template(self):
app = flask.Flask(__name__)
def is_boolean(value):
return isinstance(value, bool)
app.add_template_test(is_boolean, 'boolean')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
self.assert_in(b'Success!', rv.data)
def test_add_template_global(self):
app = flask.Flask(__name__)
@app.template_global()
def get_stuff():
return 42
self.assert_in('get_stuff', app.jinja_env.globals.keys())
self.assert_equal(app.jinja_env.globals['get_stuff'], get_stuff)
self.assert_true(app.jinja_env.globals['get_stuff'](), 42)
with app.app_context():
rv = flask.render_template_string('{{ get_stuff() }}')
self.assert_equal(rv, '42')
def test_custom_template_loader(self):
class MyFlask(flask.Flask):
def create_global_jinja_loader(self):
from jinja2 import DictLoader
return DictLoader({'index.html': 'Hello Custom World!'})
app = MyFlask(__name__)
@app.route('/')
def index():
return flask.render_template('index.html')
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.data, b'Hello Custom World!')
def test_iterable_loader(self):
app = flask.Flask(__name__)
@app.context_processor
def context_processor():
return {'whiskey': 'Jameson'}
@app.route('/')
def index():
return flask.render_template(
['no_template.xml', # should skip this one
'simple_template.html', # should render this
'context_template.html'],
value=23)
rv = app.test_client().get('/')
self.assert_equal(rv.data, b'<h1>Jameson</h1>')
def test_templates_auto_reload(self):
app = flask.Flask(__name__)
self.assert_true(app.config['TEMPLATES_AUTO_RELOAD'])
self.assert_true(app.jinja_env.auto_reload)
app = flask.Flask(__name__)
app.config['TEMPLATES_AUTO_RELOAD'] = False
self.assert_false(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)
self.assert_('1: trying loader of application '
'"blueprintapp"' in text)
self.assert_('2: trying loader of blueprint "admin" '
'(blueprintapp.apps.admin)' in text)
self.assert_('trying loader of blueprint "frontend" '
'(blueprintapp.apps.frontend)' in text)
self.assert_('Error: the template could not be found' in text)
self.assert_('looked up from an endpoint that belongs to '
'the blueprint "frontend"' in text)
self.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:
self.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
self.assert_equal(len(called), 1)
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TemplatingTestCase))
return suite

4
flask/testsuite/test_apps/config_module_app.py

@ -1,4 +0,0 @@
import os
import flask
here = os.path.abspath(os.path.dirname(__file__))
app = flask.Flask(__name__)

4
flask/testsuite/test_apps/config_package_app/__init__.py

@ -1,4 +0,0 @@
import os
import flask
here = os.path.abspath(os.path.dirname(__file__))
app = flask.Flask(__name__)

2
flask/testsuite/test_apps/flask_broken/__init__.py

@ -1,2 +0,0 @@
import flask.ext.broken.b
import missing_module

0
flask/testsuite/test_apps/flask_broken/b.py

1
flask/testsuite/test_apps/flask_newext_package/__init__.py

@ -1 +0,0 @@
ext_id = 'newext_package'

2
flask/testsuite/test_apps/flask_newext_package/submodule.py

@ -1,2 +0,0 @@
def test_function():
return 42

1
flask/testsuite/test_apps/flask_newext_simple.py

@ -1 +0,0 @@
ext_id = 'newext_simple'

0
flask/testsuite/test_apps/flaskext/__init__.py

1
flask/testsuite/test_apps/flaskext/oldext_package/__init__.py

@ -1 +0,0 @@
ext_id = 'oldext_package'

2
flask/testsuite/test_apps/flaskext/oldext_package/submodule.py

@ -1,2 +0,0 @@
def test_function():
return 42

1
flask/testsuite/test_apps/flaskext/oldext_simple.py

@ -1 +0,0 @@
ext_id = 'oldext_simple'

2
flask/testsuite/test_apps/importerror.py

@ -1,2 +0,0 @@
# NoImportsTestCase
raise NotImplementedError

BIN
flask/testsuite/test_apps/lib/python2.5/site-packages/SiteEgg.egg

Binary file not shown.

3
flask/testsuite/test_apps/lib/python2.5/site-packages/site_app.py

@ -1,3 +0,0 @@
import flask
app = flask.Flask(__name__)

3
flask/testsuite/test_apps/lib/python2.5/site-packages/site_package/__init__.py

@ -1,3 +0,0 @@
import flask
app = flask.Flask(__name__)

4
flask/testsuite/test_apps/main_app.py

@ -1,4 +0,0 @@
import flask
# Test Flask initialization with main module.
app = flask.Flask('__main__')

3
flask/testsuite/test_apps/path/installed_package/__init__.py

@ -1,3 +0,0 @@
import flask
app = flask.Flask(__name__)

257
flask/testsuite/testing.py

@ -1,257 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.testing
~~~~~~~~~~~~~~~~~~~~~~~
Test client and more.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import unittest
from flask.testsuite import FlaskTestCase
from flask._compat import text_type
class TestToolsTestCase(FlaskTestCase):
def test_environ_defaults_from_config(self):
app = flask.Flask(__name__)
app.testing = True
app.config['SERVER_NAME'] = 'example.com:1234'
app.config['APPLICATION_ROOT'] = '/foo'
@app.route('/')
def index():
return flask.request.url
ctx = app.test_request_context()
self.assert_equal(ctx.request.url, 'http://example.com:1234/foo/')
with app.test_client() as c:
rv = c.get('/')
self.assert_equal(rv.data, b'http://example.com:1234/foo/')
def test_environ_defaults(self):
app = flask.Flask(__name__)
app.testing = True
@app.route('/')
def index():
return flask.request.url
ctx = app.test_request_context()
self.assert_equal(ctx.request.url, 'http://localhost/')
with app.test_client() as c:
rv = c.get('/')
self.assert_equal(rv.data, b'http://localhost/')
def test_redirect_keep_session(self):
app = flask.Flask(__name__)
app.secret_key = 'testing'
@app.route('/', methods=['GET', 'POST'])
def index():
if flask.request.method == 'POST':
return flask.redirect('/getsession')
flask.session['data'] = 'foo'
return 'index'
@app.route('/getsession')
def get_session():
return flask.session.get('data', '<missing>')
with app.test_client() as c:
rv = c.get('/getsession')
assert rv.data == b'<missing>'
rv = c.get('/')
assert rv.data == b'index'
assert flask.session.get('data') == 'foo'
rv = c.post('/', data={}, follow_redirects=True)
assert rv.data == b'foo'
# This support requires a new Werkzeug version
if not hasattr(c, 'redirect_client'):
assert flask.session.get('data') == 'foo'
rv = c.get('/getsession')
assert rv.data == b'foo'
def test_session_transactions(self):
app = flask.Flask(__name__)
app.testing = True
app.secret_key = 'testing'
@app.route('/')
def index():
return text_type(flask.session['foo'])
with app.test_client() as c:
with c.session_transaction() as sess:
self.assert_equal(len(sess), 0)
sess['foo'] = [42]
self.assert_equal(len(sess), 1)
rv = c.get('/')
self.assert_equal(rv.data, b'[42]')
with c.session_transaction() as sess:
self.assert_equal(len(sess), 1)
self.assert_equal(sess['foo'], [42])
def test_session_transactions_no_null_sessions(self):
app = flask.Flask(__name__)
app.testing = True
with app.test_client() as c:
try:
with c.session_transaction() as sess:
pass
except RuntimeError as e:
self.assert_in('Session backend did not open a session', str(e))
else:
self.fail('Expected runtime error')
def test_session_transactions_keep_context(self):
app = flask.Flask(__name__)
app.testing = True
app.secret_key = 'testing'
with app.test_client() as c:
rv = c.get('/')
req = flask.request._get_current_object()
self.assert_true(req is not None)
with c.session_transaction():
self.assert_true(req is flask.request._get_current_object())
def test_session_transaction_needs_cookies(self):
app = flask.Flask(__name__)
app.testing = True
c = app.test_client(use_cookies=False)
try:
with c.session_transaction() as s:
pass
except RuntimeError as e:
self.assert_in('cookies', str(e))
else:
self.fail('Expected runtime error')
def test_test_client_context_binding(self):
app = flask.Flask(__name__)
app.config['LOGGER_HANDLER_POLICY'] = 'never'
@app.route('/')
def index():
flask.g.value = 42
return 'Hello World!'
@app.route('/other')
def other():
1 // 0
with app.test_client() as c:
resp = c.get('/')
self.assert_equal(flask.g.value, 42)
self.assert_equal(resp.data, b'Hello World!')
self.assert_equal(resp.status_code, 200)
resp = c.get('/other')
self.assert_false(hasattr(flask.g, 'value'))
self.assert_in(b'Internal Server Error', resp.data)
self.assert_equal(resp.status_code, 500)
flask.g.value = 23
try:
flask.g.value
except (AttributeError, RuntimeError):
pass
else:
raise AssertionError('some kind of exception expected')
def test_reuse_client(self):
app = flask.Flask(__name__)
c = app.test_client()
with c:
self.assert_equal(c.get('/').status_code, 404)
with c:
self.assert_equal(c.get('/').status_code, 404)
def test_test_client_calls_teardown_handlers(self):
app = flask.Flask(__name__)
called = []
@app.teardown_request
def remember(error):
called.append(error)
with app.test_client() as c:
self.assert_equal(called, [])
c.get('/')
self.assert_equal(called, [])
self.assert_equal(called, [None])
del called[:]
with app.test_client() as c:
self.assert_equal(called, [])
c.get('/')
self.assert_equal(called, [])
c.get('/')
self.assert_equal(called, [None])
self.assert_equal(called, [None, None])
def test_full_url_request(self):
app = flask.Flask(__name__)
app.testing = True
@app.route('/action', methods=['POST'])
def action():
return 'x'
with app.test_client() as c:
rv = c.post('http://domain.com/action?vodka=42', data={'gin': 43})
self.assert_equal(rv.status_code, 200)
self.assert_true('gin' in flask.request.form)
self.assert_true('vodka' in flask.request.args)
class SubdomainTestCase(FlaskTestCase):
def setUp(self):
self.app = flask.Flask(__name__)
self.app.config['SERVER_NAME'] = 'example.com'
self.client = self.app.test_client()
self._ctx = self.app.test_request_context()
self._ctx.push()
def tearDown(self):
if self._ctx is not None:
self._ctx.pop()
def test_subdomain(self):
@self.app.route('/', subdomain='<company_id>')
def view(company_id):
return company_id
url = flask.url_for('view', company_id='xxx')
response = self.client.get(url)
self.assert_equal(200, response.status_code)
self.assert_equal(b'xxx', response.data)
def test_nosubdomain(self):
@self.app.route('/<company_id>')
def view(company_id):
return company_id
url = flask.url_for('view', company_id='xxx')
response = self.client.get(url)
self.assert_equal(200, response.status_code)
self.assert_equal(b'xxx', response.data)
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestToolsTestCase))
suite.addTest(unittest.makeSuite(SubdomainTestCase))
return suite

169
flask/testsuite/views.py

@ -1,169 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.views
~~~~~~~~~~~~~~~~~~~~~
Pluggable views.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import flask.views
import unittest
from flask.testsuite import FlaskTestCase
from werkzeug.http import parse_set_header
class ViewTestCase(FlaskTestCase):
def common_test(self, app):
c = app.test_client()
self.assert_equal(c.get('/').data, b'GET')
self.assert_equal(c.post('/').data, b'POST')
self.assert_equal(c.put('/').status_code, 405)
meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow'])
self.assert_equal(sorted(meths), ['GET', 'HEAD', 'OPTIONS', 'POST'])
def test_basic_view(self):
app = flask.Flask(__name__)
class Index(flask.views.View):
methods = ['GET', 'POST']
def dispatch_request(self):
return flask.request.method
app.add_url_rule('/', view_func=Index.as_view('index'))
self.common_test(app)
def test_method_based_view(self):
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
return 'GET'
def post(self):
return 'POST'
app.add_url_rule('/', view_func=Index.as_view('index'))
self.common_test(app)
def test_view_patching(self):
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
1 // 0
def post(self):
1 // 0
class Other(Index):
def get(self):
return 'GET'
def post(self):
return 'POST'
view = Index.as_view('index')
view.view_class = Other
app.add_url_rule('/', view_func=view)
self.common_test(app)
def test_view_inheritance(self):
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
return 'GET'
def post(self):
return 'POST'
class BetterIndex(Index):
def delete(self):
return 'DELETE'
app.add_url_rule('/', view_func=BetterIndex.as_view('index'))
c = app.test_client()
meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow'])
self.assert_equal(sorted(meths), ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST'])
def test_view_decorators(self):
app = flask.Flask(__name__)
def add_x_parachute(f):
def new_function(*args, **kwargs):
resp = flask.make_response(f(*args, **kwargs))
resp.headers['X-Parachute'] = 'awesome'
return resp
return new_function
class Index(flask.views.View):
decorators = [add_x_parachute]
def dispatch_request(self):
return 'Awesome'
app.add_url_rule('/', view_func=Index.as_view('index'))
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.headers['X-Parachute'], 'awesome')
self.assert_equal(rv.data, b'Awesome')
def test_implicit_head(self):
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
return flask.Response('Blub', headers={
'X-Method': flask.request.method
})
app.add_url_rule('/', view_func=Index.as_view('index'))
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.data, b'Blub')
self.assert_equal(rv.headers['X-Method'], 'GET')
rv = c.head('/')
self.assert_equal(rv.data, b'')
self.assert_equal(rv.headers['X-Method'], 'HEAD')
def test_explicit_head(self):
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
return 'GET'
def head(self):
return flask.Response('', headers={'X-Method': 'HEAD'})
app.add_url_rule('/', view_func=Index.as_view('index'))
c = app.test_client()
rv = c.get('/')
self.assert_equal(rv.data, b'GET')
rv = c.head('/')
self.assert_equal(rv.data, b'')
self.assert_equal(rv.headers['X-Method'], 'HEAD')
def test_endpoint_override(self):
app = flask.Flask(__name__)
app.debug = True
class Index(flask.views.View):
methods = ['GET', 'POST']
def dispatch_request(self):
return flask.request.method
app.add_url_rule('/', view_func=Index.as_view('index'))
with self.assert_raises(AssertionError):
app.add_url_rule('/', view_func=Index.as_view('index'))
# But these tests should still pass. We just log a warning.
self.common_test(app)
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(ViewTestCase))
return suite

5
run-tests.py

@ -1,5 +0,0 @@
#!/usr/bin/env python
import sys, os
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
from flask.testsuite import main
main()

0
scripts/flaskext_test.py → scripts/flaskext_tester.py

42
setup.py

@ -46,42 +46,6 @@ from __future__ import print_function
from setuptools import Command, setup
class run_audit(Command):
"""Audits source code using PyFlakes for following issues:
- Names which are used but not defined or used before they are defined.
- Names which are redefined without having been used.
"""
description = "Audit source code with PyFlakes"
user_options = []
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
import os
import sys
try:
import pyflakes.scripts.pyflakes as flakes
except ImportError:
print("Audit requires PyFlakes installed in your system.")
sys.exit(-1)
warns = 0
# Define top-level directories
dirs = ('flask', 'examples', 'scripts')
for dir in dirs:
for root, _, files in os.walk(dir):
for file in files:
if file != '__init__.py' and file.endswith('.py'):
warns += flakes.checkPath(os.path.join(root, file))
if warns > 0:
print("Audit finished with total %d warnings." % warns)
else:
print("No problems found in sourcecode.")
setup(
name='Flask',
version='0.11-dev',
@ -92,7 +56,7 @@ setup(
description='A microframework based on Werkzeug, Jinja2 '
'and good intentions',
long_description=__doc__,
packages=['flask', 'flask.ext', 'flask.testsuite'],
packages=['flask', 'flask.ext'],
include_package_data=True,
zip_safe=False,
platforms='any',
@ -116,7 +80,5 @@ setup(
entry_points='''
[console_scripts]
flask=flask.cli:main
''',
cmdclass={'audit': run_audit},
test_suite='flask.testsuite.suite'
'''
)

134
tests/conftest.py

@ -0,0 +1,134 @@
# -*- coding: utf-8 -*-
"""
tests.conftest
~~~~~~~~~~~~~~
: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 textwrap
@pytest.fixture
def test_apps(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.
This provides for tests where a system has custom loaders, e.g. Google App
Engine's HardenedModulesHook, which have neither the `get_filename` method
nor the `archive` attribute.
This fixture will run the testcase twice, once with and once without the
limitation/mock.
"""
if not request.param:
return
class LimitedLoader(object):
def __init__(self, loader):
self.loader = loader
def __getattr__(self, name):
if name in ('archive', 'get_filename'):
msg = 'Mocking a loader which does not have `%s.`' % name
raise AttributeError(msg)
return getattr(self.loader, name)
old_get_loader = pkgutil.get_loader
def get_loader(*args, **kwargs):
return LimitedLoader(old_get_loader(*args, **kwargs))
monkeypatch.setattr(pkgutil, 'get_loader', get_loader)
@pytest.fixture
def modules_tmpdir(tmpdir, monkeypatch):
'''A tmpdir added to sys.path'''
rv = tmpdir.mkdir('modules_tmpdir')
monkeypatch.syspath_prepend(str(rv))
return rv
@pytest.fixture
def modules_tmpdir_prefix(modules_tmpdir, monkeypatch):
monkeypatch.setattr(sys, 'prefix', str(modules_tmpdir))
return modules_tmpdir
@pytest.fixture
def site_packages(modules_tmpdir, monkeypatch):
'''Create a fake site-packages'''
rv = modules_tmpdir \
.mkdir('lib')\
.mkdir('python{x[0]}.{x[1]}'.format(x=sys.version_info))\
.mkdir('site-packages')
monkeypatch.syspath_prepend(str(rv))
return rv
@pytest.fixture
def install_egg(modules_tmpdir, monkeypatch):
'''Generate egg from package name inside base and put the egg into
sys.path'''
def inner(name, base=modules_tmpdir):
if not isinstance(name, str):
raise ValueError(name)
base.join(name).ensure_dir()
base.join(name).join('__init__.py').ensure()
egg_setup = base.join('setup.py')
egg_setup.write(textwrap.dedent("""
from setuptools import setup
setup(name='{0}',
version='1.0',
packages=['site_egg'],
zip_safe=True)
""".format(name)))
import subprocess
subprocess.check_call(
[sys.executable, 'setup.py', 'bdist_egg'],
cwd=str(modules_tmpdir)
)
egg_path, = modules_tmpdir.join('dist/').listdir()
monkeypatch.syspath_prepend(str(egg_path))
return egg_path
return inner
@pytest.fixture
def purge_module(request):
def inner(name):
request.addfinalizer(lambda: sys.modules.pop(name, None))
return inner
@pytest.fixture
def catch_deprecation_warnings():
import warnings
warnings.simplefilter('default', category=DeprecationWarning)
return lambda: warnings.catch_warnings(record=True)

0
flask/testsuite/static/config.json → tests/static/config.json

0
flask/testsuite/static/index.html → tests/static/index.html

0
flask/testsuite/templates/_macro.html → tests/templates/_macro.html

0
flask/testsuite/templates/context_template.html → tests/templates/context_template.html

0
flask/testsuite/templates/escaping_template.html → tests/templates/escaping_template.html

0
flask/testsuite/templates/mail.txt → tests/templates/mail.txt

0
flask/testsuite/templates/nested/nested.txt → tests/templates/nested/nested.txt

0
flask/testsuite/templates/simple_template.html → tests/templates/simple_template.html

0
flask/testsuite/templates/template_filter.html → tests/templates/template_filter.html

0
flask/testsuite/templates/template_test.html → tests/templates/template_test.html

113
tests/test_appctx.py

@ -0,0 +1,113 @@
# -*- coding: utf-8 -*-
"""
tests.appctx
~~~~~~~~~~~~~~~~~~~~~~
Tests the application context.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import pytest
import flask
import unittest
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_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']

0
flask/testsuite/test_apps/blueprintapp/__init__.py → tests/test_apps/blueprintapp/__init__.py

0
flask/testsuite/test_apps/blueprintapp/apps/__init__.py → tests/test_apps/blueprintapp/apps/__init__.py

0
flask/testsuite/test_apps/blueprintapp/apps/admin/__init__.py → tests/test_apps/blueprintapp/apps/admin/__init__.py

0
flask/testsuite/test_apps/blueprintapp/apps/admin/static/css/test.css → tests/test_apps/blueprintapp/apps/admin/static/css/test.css

0
flask/testsuite/test_apps/blueprintapp/apps/admin/static/test.txt → tests/test_apps/blueprintapp/apps/admin/static/test.txt

0
flask/testsuite/test_apps/blueprintapp/apps/admin/templates/admin/index.html → tests/test_apps/blueprintapp/apps/admin/templates/admin/index.html

0
flask/testsuite/test_apps/blueprintapp/apps/frontend/__init__.py → tests/test_apps/blueprintapp/apps/frontend/__init__.py

0
flask/testsuite/test_apps/blueprintapp/apps/frontend/templates/frontend/index.html → tests/test_apps/blueprintapp/apps/frontend/templates/frontend/index.html

0
flask/testsuite/test_apps/subdomaintestmodule/__init__.py → tests/test_apps/subdomaintestmodule/__init__.py

0
flask/testsuite/test_apps/subdomaintestmodule/static/hello.txt → tests/test_apps/subdomaintestmodule/static/hello.txt

1508
tests/test_basic.py

File diff suppressed because it is too large Load Diff

578
tests/test_blueprints.py

@ -0,0 +1,578 @@
# -*- coding: utf-8 -*-
"""
tests.blueprints
~~~~~~~~~~~~~~~~~~~~~~~~~~
Blueprints (and currently modules)
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import pytest
import flask
import unittest
from flask._compat import text_type
from werkzeug.http import parse_cache_control_header
from jinja2 import TemplateNotFound
def test_blueprint_specific_error_handling():
frontend = flask.Blueprint('frontend', __name__)
backend = flask.Blueprint('backend', __name__)
sideend = flask.Blueprint('sideend', __name__)
@frontend.errorhandler(403)
def frontend_forbidden(e):
return 'frontend says no', 403
@frontend.route('/frontend-no')
def frontend_no():
flask.abort(403)
@backend.errorhandler(403)
def backend_forbidden(e):
return 'backend says no', 403
@backend.route('/backend-no')
def backend_no():
flask.abort(403)
@sideend.route('/what-is-a-sideend')
def sideend_no():
flask.abort(403)
app = flask.Flask(__name__)
app.register_blueprint(frontend)
app.register_blueprint(backend)
app.register_blueprint(sideend)
@app.errorhandler(403)
def app_forbidden(e):
return 'application itself says no', 403
c = app.test_client()
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():
class MyDecoratorException(Exception):
pass
class MyFunctionException(Exception):
pass
blue = flask.Blueprint('blue', __name__)
@blue.errorhandler(MyDecoratorException)
def my_decorator_exception_handler(e):
assert isinstance(e, MyDecoratorException)
return 'boom'
def my_function_exception_handler(e):
assert isinstance(e, MyFunctionException)
return 'bam'
blue.register_error_handler(MyFunctionException, my_function_exception_handler)
@blue.route('/decorator')
def blue_deco_test():
raise MyDecoratorException()
@blue.route('/function')
def blue_func_test():
raise MyFunctionException()
app = flask.Flask(__name__)
app.register_blueprint(blue)
c = app.test_client()
assert c.get('/decorator').data == b'boom'
assert c.get('/function').data == b'bam'
def test_blueprint_url_definitions():
bp = flask.Blueprint('test', __name__)
@bp.route('/foo', defaults={'baz': 42})
def foo(bar, baz):
return '%s/%d' % (bar, baz)
@bp.route('/bar')
def bar(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='/2', url_defaults={'bar': 19})
c = app.test_client()
assert c.get('/1/foo').data == b'23/42'
assert c.get('/2/foo').data == b'19/42'
assert c.get('/1/bar').data == b'23'
assert c.get('/2/bar').data == b'19'
def test_blueprint_url_processors():
bp = flask.Blueprint('frontend', __name__, url_prefix='/<lang_code>')
@bp.url_defaults
def add_language_code(endpoint, values):
values.setdefault('lang_code', flask.g.lang_code)
@bp.url_value_preprocessor
def pull_lang_code(endpoint, values):
flask.g.lang_code = values.pop('lang_code')
@bp.route('/')
def index():
return flask.url_for('.about')
@bp.route('/about')
def about():
return flask.url_for('.index')
app = flask.Flask(__name__)
app.register_blueprint(bp)
c = app.test_client()
assert c.get('/de/').data == b'/de/about'
assert c.get('/de/about').data == b'/de/'
def test_templates_and_static(test_apps):
from blueprintapp import app
c = app.test_client()
rv = c.get('/')
assert rv.data == b'Hello from the Frontend'
rv = c.get('/admin/')
assert rv.data == b'Hello from the Admin'
rv = c.get('/admin/index2')
assert rv.data == b'Hello from the Admin'
rv = c.get('/admin/static/test.txt')
assert rv.data.strip() == b'Admin File'
rv.close()
rv = c.get('/admin/static/css/test.css')
assert rv.data.strip() == b'/* nested file */'
rv.close()
# try/finally, in case other tests use this app for Blueprint tests.
max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT']
try:
expected_max_age = 3600
if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == expected_max_age:
expected_max_age = 7200
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = expected_max_age
rv = c.get('/admin/static/css/test.css')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
assert cc.max_age == expected_max_age
rv.close()
finally:
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default
with app.test_request_context():
assert flask.url_for('admin.static', filename='test.txt') == '/admin/static/test.txt'
with app.test_request_context():
try:
flask.render_template('missing.html')
except TemplateNotFound as e:
assert e.name == 'missing.html'
else:
assert 0, 'expected exception'
with flask.Flask(__name__).test_request_context():
assert flask.render_template('nested/nested.txt') == 'I\'m nested'
def test_default_static_cache_timeout():
app = flask.Flask(__name__)
class MyBlueprint(flask.Blueprint):
def get_send_file_max_age(self, filename):
return 100
blueprint = MyBlueprint('blueprint', __name__, static_folder='static')
app.register_blueprint(blueprint)
# try/finally, in case other tests use this app for Blueprint tests.
max_age_default = app.config['SEND_FILE_MAX_AGE_DEFAULT']
try:
with app.test_request_context():
unexpected_max_age = 3600
if app.config['SEND_FILE_MAX_AGE_DEFAULT'] == unexpected_max_age:
unexpected_max_age = 7200
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = unexpected_max_age
rv = blueprint.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
assert cc.max_age == 100
rv.close()
finally:
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = max_age_default
def test_templates_list(test_apps):
from blueprintapp import app
templates = sorted(app.jinja_env.list_templates())
assert templates == ['admin/index.html', 'frontend/index.html']
def test_dotted_names():
frontend = flask.Blueprint('myapp.frontend', __name__)
backend = flask.Blueprint('myapp.backend', __name__)
@frontend.route('/fe')
def frontend_index():
return flask.url_for('myapp.backend.backend_index')
@frontend.route('/fe2')
def frontend_page2():
return flask.url_for('.frontend_index')
@backend.route('/be')
def backend_index():
return flask.url_for('myapp.frontend.frontend_index')
app = flask.Flask(__name__)
app.register_blueprint(frontend)
app.register_blueprint(backend)
c = app.test_client()
assert c.get('/fe').data.strip() == b'/be'
assert c.get('/fe2').data.strip() == b'/fe'
assert c.get('/be').data.strip() == b'/fe'
def test_dotted_names_from_app():
app = flask.Flask(__name__)
app.testing = True
test = flask.Blueprint('test', __name__)
@app.route('/')
def app_index():
return flask.url_for('test.index')
@test.route('/test/')
def index():
return flask.url_for('app_index')
app.register_blueprint(test)
with app.test_client() as c:
rv = c.get('/')
assert rv.data == b'/test/'
def test_empty_url_defaults():
bp = flask.Blueprint('bp', __name__)
@bp.route('/', defaults={'page': 1})
@bp.route('/page/<int:page>')
def something(page):
return str(page)
app = flask.Flask(__name__)
app.register_blueprint(bp)
c = app.test_client()
assert c.get('/').data == b'1'
assert c.get('/page/2').data == b'2'
def test_route_decorator_custom_endpoint():
bp = flask.Blueprint('bp', __name__)
@bp.route('/foo')
def foo():
return flask.request.endpoint
@bp.route('/bar', endpoint='bar')
def foo_bar():
return flask.request.endpoint
@bp.route('/bar/123', endpoint='123')
def foo_bar_foo():
return flask.request.endpoint
@bp.route('/bar/foo')
def bar_foo():
return flask.request.endpoint
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.request.endpoint
c = app.test_client()
assert c.get('/').data == b'index'
assert c.get('/py/foo').data == b'bp.foo'
assert c.get('/py/bar').data == b'bp.bar'
assert c.get('/py/bar/123').data == b'bp.123'
assert c.get('/py/bar/foo').data == b'bp.bar_foo'
def test_route_decorator_custom_endpoint_with_dots():
bp = flask.Blueprint('bp', __name__)
@bp.route('/foo')
def foo():
return flask.request.endpoint
try:
@bp.route('/bar', endpoint='bar.bar')
def foo_bar():
return flask.request.endpoint
except AssertionError:
pass
else:
raise AssertionError('expected AssertionError not raised')
try:
@bp.route('/bar/123', endpoint='bar.123')
def foo_bar_foo():
return flask.request.endpoint
except AssertionError:
pass
else:
raise AssertionError('expected AssertionError not raised')
def foo_foo_foo():
pass
pytest.raises(
AssertionError,
lambda: bp.add_url_rule(
'/bar/123', endpoint='bar.123', view_func=foo_foo_foo
)
)
pytest.raises(
AssertionError,
bp.route('/bar/123', endpoint='bar.123'),
lambda: None
)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
c = app.test_client()
assert c.get('/py/foo').data == b'bp.foo'
# The rule's didn't actually made it through
rv = c.get('/py/bar')
assert rv.status_code == 404
rv = c.get('/py/bar/123')
assert rv.status_code == 404
def test_template_filter():
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter()
def my_reverse(s):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
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']('abcd') == 'dcba'
def test_add_template_filter():
bp = flask.Blueprint('bp', __name__)
def my_reverse(s):
return s[::-1]
bp.add_app_template_filter(my_reverse)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
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']('abcd') == 'dcba'
def test_template_filter_with_name():
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter('strrev')
def my_reverse(s):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
assert 'strrev' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['strrev'] == my_reverse
assert app.jinja_env.filters['strrev']('abcd') == 'dcba'
def test_add_template_filter_with_name():
bp = flask.Blueprint('bp', __name__)
def my_reverse(s):
return s[::-1]
bp.add_app_template_filter(my_reverse, 'strrev')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
assert 'strrev' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['strrev'] == my_reverse
assert app.jinja_env.filters['strrev']('abcd') == 'dcba'
def test_template_filter_with_template():
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter()
def super_reverse(s):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
assert rv.data == b'dcba'
def test_template_filter_after_route_with_template():
app = flask.Flask(__name__)
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter()
def super_reverse(s):
return s[::-1]
app.register_blueprint(bp, url_prefix='/py')
rv = app.test_client().get('/')
assert rv.data == b'dcba'
def test_add_template_filter_with_template():
bp = flask.Blueprint('bp', __name__)
def super_reverse(s):
return s[::-1]
bp.add_app_template_filter(super_reverse)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
assert rv.data == b'dcba'
def test_template_filter_with_name_and_template():
bp = flask.Blueprint('bp', __name__)
@bp.app_template_filter('super_reverse')
def my_reverse(s):
return s[::-1]
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
assert rv.data == b'dcba'
def test_add_template_filter_with_name_and_template():
bp = flask.Blueprint('bp', __name__)
def my_reverse(s):
return s[::-1]
bp.add_app_template_filter(my_reverse, 'super_reverse')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
assert rv.data == b'dcba'
def test_template_test():
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test()
def is_boolean(value):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
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'](False)
def test_add_template_test():
bp = flask.Blueprint('bp', __name__)
def is_boolean(value):
return isinstance(value, bool)
bp.add_app_template_test(is_boolean)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
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'](False)
def test_template_test_with_name():
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test('boolean')
def is_boolean(value):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == is_boolean
assert app.jinja_env.tests['boolean'](False)
def test_add_template_test_with_name():
bp = flask.Blueprint('bp', __name__)
def is_boolean(value):
return isinstance(value, bool)
bp.add_app_template_test(is_boolean, 'boolean')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == is_boolean
assert app.jinja_env.tests['boolean'](False)
def test_template_test_with_template():
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test()
def boolean(value):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
assert b'Success!' in rv.data
def test_template_test_after_route_with_template():
app = flask.Flask(__name__)
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test()
def boolean(value):
return isinstance(value, bool)
app.register_blueprint(bp, url_prefix='/py')
rv = app.test_client().get('/')
assert b'Success!' in rv.data
def test_add_template_test_with_template():
bp = flask.Blueprint('bp', __name__)
def boolean(value):
return isinstance(value, bool)
bp.add_app_template_test(boolean)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
assert b'Success!' in rv.data
def test_template_test_with_name_and_template():
bp = flask.Blueprint('bp', __name__)
@bp.app_template_test('boolean')
def is_boolean(value):
return isinstance(value, bool)
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
assert b'Success!' in rv.data
def test_add_template_test_with_name_and_template():
bp = flask.Blueprint('bp', __name__)
def is_boolean(value):
return isinstance(value, bool)
bp.add_app_template_test(is_boolean, 'boolean')
app = flask.Flask(__name__)
app.register_blueprint(bp, url_prefix='/py')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
assert b'Success!' in rv.data

184
tests/test_config.py

@ -0,0 +1,184 @@
# -*- coding: utf-8 -*-
"""
tests.test_config
~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 by the Flask Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
import pytest
import os
import flask
# config keys used for the TestConfig
TEST_KEY = 'foo'
SECRET_KEY = 'devkey'
def common_object_test(app):
assert app.secret_key == 'devkey'
assert app.config['TEST_KEY'] == 'foo'
assert 'TestConfig' not in app.config
def test_config_from_file():
app = flask.Flask(__name__)
app.config.from_pyfile(__file__.rsplit('.', 1)[0] + '.py')
common_object_test(app)
def test_config_from_object():
app = flask.Flask(__name__)
app.config.from_object(__name__)
common_object_test(app)
def test_config_from_json():
app = flask.Flask(__name__)
current_dir = os.path.dirname(os.path.abspath(__file__))
app.config.from_json(os.path.join(current_dir, 'static', 'config.json'))
common_object_test(app)
def test_config_from_mapping():
app = flask.Flask(__name__)
app.config.from_mapping({
'SECRET_KEY': 'devkey',
'TEST_KEY': 'foo'
})
common_object_test(app)
app = flask.Flask(__name__)
app.config.from_mapping([
('SECRET_KEY', 'devkey'),
('TEST_KEY', 'foo')
])
common_object_test(app)
app = flask.Flask(__name__)
app.config.from_mapping(
SECRET_KEY='devkey',
TEST_KEY='foo'
)
common_object_test(app)
app = flask.Flask(__name__)
with pytest.raises(TypeError):
app.config.from_mapping(
{}, {}
)
def test_config_from_class():
class Base(object):
TEST_KEY = 'foo'
class Test(Base):
SECRET_KEY = 'devkey'
app = flask.Flask(__name__)
app.config.from_object(Test)
common_object_test(app)
def test_config_from_envvar():
env = os.environ
try:
os.environ = {}
app = flask.Flask(__name__)
try:
app.config.from_envvar('FOO_SETTINGS')
except RuntimeError as e:
assert "'FOO_SETTINGS' is not set" in str(e)
else:
assert 0, 'expected exception'
assert not app.config.from_envvar('FOO_SETTINGS', silent=True)
os.environ = {'FOO_SETTINGS': __file__.rsplit('.', 1)[0] + '.py'}
assert app.config.from_envvar('FOO_SETTINGS')
common_object_test(app)
finally:
os.environ = env
def test_config_from_envvar_missing():
env = os.environ
try:
os.environ = {'FOO_SETTINGS': 'missing.cfg'}
try:
app = flask.Flask(__name__)
app.config.from_envvar('FOO_SETTINGS')
except IOError as e:
msg = str(e)
assert msg.startswith('[Errno 2] Unable to load configuration '
'file (No such file or directory):')
assert msg.endswith("missing.cfg'")
else:
assert False, 'expected IOError'
assert not app.config.from_envvar('FOO_SETTINGS', silent=True)
finally:
os.environ = env
def test_config_missing():
app = flask.Flask(__name__)
try:
app.config.from_pyfile('missing.cfg')
except IOError as e:
msg = str(e)
assert msg.startswith('[Errno 2] Unable to load configuration '
'file (No such file or directory):')
assert msg.endswith("missing.cfg'")
else:
assert 0, 'expected config'
assert not app.config.from_pyfile('missing.cfg', silent=True)
def test_config_missing_json():
app = flask.Flask(__name__)
try:
app.config.from_json('missing.json')
except IOError as e:
msg = str(e)
assert msg.startswith('[Errno 2] Unable to load configuration '
'file (No such file or directory):')
assert msg.endswith("missing.json'")
else:
assert 0, 'expected config'
assert not app.config.from_json('missing.json', silent=True)
def test_custom_config_class():
class Config(flask.Config):
pass
class Flask(flask.Flask):
config_class = Config
app = Flask(__name__)
assert isinstance(app.config, Config)
app.config.from_object(__name__)
common_object_test(app)
def test_session_lifetime():
app = flask.Flask(__name__)
app.config['PERMANENT_SESSION_LIFETIME'] = 42
assert app.permanent_session_lifetime.seconds == 42
def test_get_namespace():
app = flask.Flask(__name__)
app.config['FOO_OPTION_1'] = 'foo option 1'
app.config['FOO_OPTION_2'] = 'foo option 2'
app.config['BAR_STUFF_1'] = 'bar stuff 1'
app.config['BAR_STUFF_2'] = 'bar stuff 2'
foo_options = app.config.get_namespace('FOO_')
assert 2 == len(foo_options)
assert 'foo option 1' == foo_options['option_1']
assert 'foo option 2' == foo_options['option_2']
bar_options = app.config.get_namespace('BAR_', lowercase=False)
assert 2 == len(bar_options)
assert 'bar stuff 1' == bar_options['STUFF_1']
assert 'bar stuff 2' == bar_options['STUFF_2']

10
tests/test_deprecations.py

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
"""
tests.deprecations
~~~~~~~~~~~~~~~~~~
Tests deprecation support. Not used currently.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""

187
tests/test_ext.py

@ -0,0 +1,187 @@
# -*- coding: utf-8 -*-
"""
tests.ext
~~~~~~~~~~~~~~~~~~~
Tests the extension import thing.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import sys
import pytest
try:
from imp import reload as reload_module
except ImportError:
reload_module = reload
from flask._compat import PY2
@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
request.addfinalizer(teardown)
@pytest.fixture
def newext_simple(modules_tmpdir):
x = modules_tmpdir.join('flask_newext_simple.py')
x.write('ext_id = "newext_simple"')
@pytest.fixture
def oldext_simple(modules_tmpdir):
flaskext = modules_tmpdir.mkdir('flaskext')
flaskext.join('__init__.py').write('\n')
flaskext.join('oldext_simple.py').write('ext_id = "oldext_simple"')
@pytest.fixture
def newext_package(modules_tmpdir):
pkg = modules_tmpdir.mkdir('flask_newext_package')
pkg.join('__init__.py').write('ext_id = "newext_package"')
pkg.join('submodule.py').write('def test_function():\n return 42\n')
@pytest.fixture
def oldext_package(modules_tmpdir):
flaskext = modules_tmpdir.mkdir('flaskext')
flaskext.join('__init__.py').write('\n')
oldext = flaskext.mkdir('oldext_package')
oldext.join('__init__.py').write('ext_id = "oldext_package"')
oldext.join('submodule.py').write('def test_function():\n'
' return 42')
@pytest.fixture
def flaskext_broken(modules_tmpdir):
ext = modules_tmpdir.mkdir('flask_broken')
ext.join('b.py').write('\n')
ext.join('__init__.py').write('import flask.ext.broken.b\n'
'import missing_module')
def test_flaskext_new_simple_import_normal(newext_simple):
from flask.ext.newext_simple import ext_id
assert ext_id == 'newext_simple'
def test_flaskext_new_simple_import_module(newext_simple):
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(newext_package):
from flask.ext.newext_package import ext_id
assert ext_id == 'newext_package'
def test_flaskext_new_package_import_module(newext_package):
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(newext_package):
from flask.ext.newext_package.submodule import test_function
assert test_function() == 42
def test_flaskext_new_package_import_submodule(newext_package):
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(oldext_simple):
from flask.ext.oldext_simple import ext_id
assert ext_id == 'oldext_simple'
def test_flaskext_old_simple_import_module(oldext_simple):
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(oldext_package):
from flask.ext.oldext_package import ext_id
assert ext_id == 'oldext_package'
def test_flaskext_old_package_import_module(oldext_package):
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(oldext_package):
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(oldext_package):
from flask.ext.oldext_package.submodule import test_function
assert test_function() == 42
def test_flaskext_broken_package_no_module_caching(flaskext_broken):
for x in range(2):
with pytest.raises(ImportError):
import flask.ext.broken
def test_no_error_swallowing(flaskext_broken):
with pytest.raises(ImportError) as excinfo:
import flask.ext.broken
assert excinfo.type is ImportError
if PY2:
message = 'No module named missing_module'
else:
message = 'No module named \'missing_module\''
assert str(excinfo.value) == message
assert excinfo.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 = excinfo.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

256
flask/testsuite/helpers.py → tests/test_helpers.py

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""
flask.testsuite.helpers
tests.helpers
~~~~~~~~~~~~~~~~~~~~~~~
Various helpers.
@ -9,11 +9,11 @@
:license: BSD, see LICENSE for more details.
"""
import pytest
import os
import flask
import unittest
from logging import StreamHandler
from flask.testsuite import FlaskTestCase, catch_warnings, catch_stderr
from werkzeug.http import parse_cache_control_header, parse_options_header
from flask._compat import StringIO, text_type
@ -27,7 +27,7 @@ def has_encoding(name):
return False
class JSONTestCase(FlaskTestCase):
class TestJSON(object):
def test_json_bad_requests(self):
app = flask.Flask(__name__)
@ -36,7 +36,7 @@ class JSONTestCase(FlaskTestCase):
return flask.jsonify(foo=text_type(flask.request.get_json()))
c = app.test_client()
rv = c.post('/json', data='malformed', content_type='application/json')
self.assert_equal(rv.status_code, 400)
assert rv.status_code == 400
def test_json_custom_mimetypes(self):
app = flask.Flask(__name__)
@ -45,7 +45,7 @@ class JSONTestCase(FlaskTestCase):
return flask.request.get_json()
c = app.test_client()
rv = c.post('/json', data='"foo"', content_type='application/x+json')
self.assert_equal(rv.data, b'foo')
assert rv.data == b'foo'
def test_json_body_encoding(self):
app = flask.Flask(__name__)
@ -57,7 +57,7 @@ class JSONTestCase(FlaskTestCase):
c = app.test_client()
resp = c.get('/', data=u'"Hällo Wörld"'.encode('iso-8859-15'),
content_type='application/json; charset=iso-8859-15')
self.assert_equal(resp.data, u'Hällo Wörld'.encode('utf-8'))
assert resp.data == u'Hällo Wörld'.encode('utf-8')
def test_jsonify(self):
d = dict(a=23, b=42, c=[1, 2, 3])
@ -71,8 +71,8 @@ class JSONTestCase(FlaskTestCase):
c = app.test_client()
for url in '/kw', '/dict':
rv = c.get(url)
self.assert_equal(rv.mimetype, 'application/json')
self.assert_equal(flask.json.loads(rv.data), d)
assert rv.mimetype == 'application/json'
assert flask.json.loads(rv.data) == d
def test_json_as_unicode(self):
app = flask.Flask(__name__)
@ -80,12 +80,12 @@ class JSONTestCase(FlaskTestCase):
app.config['JSON_AS_ASCII'] = True
with app.app_context():
rv = flask.json.dumps(u'\N{SNOWMAN}')
self.assert_equal(rv, '"\\u2603"')
assert rv == '"\\u2603"'
app.config['JSON_AS_ASCII'] = False
with app.app_context():
rv = flask.json.dumps(u'\N{SNOWMAN}')
self.assert_equal(rv, u'"\u2603"')
assert rv == u'"\u2603"'
def test_json_attr(self):
app = flask.Flask(__name__)
@ -96,29 +96,28 @@ class JSONTestCase(FlaskTestCase):
c = app.test_client()
rv = c.post('/add', data=flask.json.dumps({'a': 1, 'b': 2}),
content_type='application/json')
self.assert_equal(rv.data, b'3')
assert rv.data == b'3'
def test_template_escaping(self):
app = flask.Flask(__name__)
render = flask.render_template_string
with app.test_request_context():
rv = flask.json.htmlsafe_dumps('</script>')
self.assert_equal(rv, u'"\\u003c/script\\u003e"')
self.assert_equal(type(rv), text_type)
assert rv == u'"\\u003c/script\\u003e"'
assert type(rv) == text_type
rv = render('{{ "</script>"|tojson }}')
self.assert_equal(rv, '"\\u003c/script\\u003e"')
assert rv == '"\\u003c/script\\u003e"'
rv = render('{{ "<\0/script>"|tojson }}')
self.assert_equal(rv, '"\\u003c\\u0000/script\\u003e"')
assert rv == '"\\u003c\\u0000/script\\u003e"'
rv = render('{{ "<!--<script>"|tojson }}')
self.assert_equal(rv, '"\\u003c!--\\u003cscript\\u003e"')
assert rv == '"\\u003c!--\\u003cscript\\u003e"'
rv = render('{{ "&"|tojson }}')
self.assert_equal(rv, '"\\u0026"')
assert rv == '"\\u0026"'
rv = render('{{ "\'"|tojson }}')
self.assert_equal(rv, '"\\u0027"')
assert rv == '"\\u0027"'
rv = render("<a ng-data='{{ data|tojson }}'></a>",
data={'x': ["foo", "bar", "baz'"]})
self.assert_equal(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):
class X(object):
@ -148,7 +147,7 @@ class JSONTestCase(FlaskTestCase):
rv = c.post('/', data=flask.json.dumps({
'x': {'_foo': 42}
}), content_type='application/json')
self.assertEqual(rv.data, b'"<42>"')
assert rv.data == b'"<42>"'
def test_modified_url_encoding(self):
class ModifiedRequest(flask.Request):
@ -163,8 +162,8 @@ class JSONTestCase(FlaskTestCase):
return flask.request.args['foo']
rv = app.test_client().get(u'/?foo=정상처리'.encode('euc-kr'))
self.assert_equal(rv.status_code, 200)
self.assert_equal(rv.data, u'정상처리'.encode('utf-8'))
assert rv.status_code == 200
assert rv.data == u'정상처리'.encode('utf-8')
if not has_encoding('euc-kr'):
test_modified_url_encoding = None
@ -172,7 +171,7 @@ class JSONTestCase(FlaskTestCase):
def test_json_key_sorting(self):
app = flask.Flask(__name__)
app.testing = True
self.assert_equal(app.config['JSON_SORT_KEYS'], True)
assert app.config['JSON_SORT_KEYS'] == True
d = dict.fromkeys(range(20), 'foo')
@app.route('/')
@ -236,21 +235,21 @@ class JSONTestCase(FlaskTestCase):
]
try:
self.assert_equal(lines, sorted_by_int)
assert lines == sorted_by_int
except AssertionError:
self.assert_equal(lines, sorted_by_str)
assert lines == sorted_by_str
class SendfileTestCase(FlaskTestCase):
class TestSendfile(object):
def test_send_file_regular(self):
app = flask.Flask(__name__)
with app.test_request_context():
rv = flask.send_file('static/index.html')
self.assert_true(rv.direct_passthrough)
self.assert_equal(rv.mimetype, 'text/html')
assert rv.direct_passthrough
assert rv.mimetype == 'text/html'
with app.open_resource('static/index.html') as f:
rv.direct_passthrough = False
self.assert_equal(rv.data, f.read())
assert rv.data == f.read()
rv.close()
def test_send_file_xsendfile(self):
@ -258,52 +257,52 @@ class SendfileTestCase(FlaskTestCase):
app.use_x_sendfile = True
with app.test_request_context():
rv = flask.send_file('static/index.html')
self.assert_true(rv.direct_passthrough)
self.assert_in('x-sendfile', rv.headers)
self.assert_equal(rv.headers['x-sendfile'],
os.path.join(app.root_path, 'static/index.html'))
self.assert_equal(rv.mimetype, 'text/html')
assert rv.direct_passthrough
assert 'x-sendfile' in rv.headers
assert rv.headers['x-sendfile'] == \
os.path.join(app.root_path, 'static/index.html')
assert rv.mimetype == 'text/html'
rv.close()
def test_send_file_object(self):
def test_send_file_object(self, catch_deprecation_warnings):
app = flask.Flask(__name__)
with catch_warnings() as captured:
with catch_deprecation_warnings() as captured:
with app.test_request_context():
f = open(os.path.join(app.root_path, 'static/index.html'), mode='rb')
rv = flask.send_file(f)
rv.direct_passthrough = False
with app.open_resource('static/index.html') as f:
self.assert_equal(rv.data, f.read())
self.assert_equal(rv.mimetype, 'text/html')
assert rv.data == f.read()
assert rv.mimetype == 'text/html'
rv.close()
# mimetypes + etag
self.assert_equal(len(captured), 2)
assert len(captured) == 2
app.use_x_sendfile = True
with catch_warnings() as captured:
with catch_deprecation_warnings() as captured:
with app.test_request_context():
f = open(os.path.join(app.root_path, 'static/index.html'))
rv = flask.send_file(f)
self.assert_equal(rv.mimetype, 'text/html')
self.assert_in('x-sendfile', rv.headers)
self.assert_equal(rv.headers['x-sendfile'],
os.path.join(app.root_path, 'static/index.html'))
assert rv.mimetype == 'text/html'
assert 'x-sendfile' in rv.headers
assert rv.headers['x-sendfile'] == \
os.path.join(app.root_path, 'static/index.html')
rv.close()
# mimetypes + etag
self.assert_equal(len(captured), 2)
assert len(captured) == 2
app.use_x_sendfile = False
with app.test_request_context():
with catch_warnings() as captured:
with catch_deprecation_warnings() as captured:
f = StringIO('Test')
rv = flask.send_file(f)
rv.direct_passthrough = False
self.assert_equal(rv.data, b'Test')
self.assert_equal(rv.mimetype, 'application/octet-stream')
assert rv.data == b'Test'
assert rv.mimetype == 'application/octet-stream'
rv.close()
# etags
self.assert_equal(len(captured), 1)
with catch_warnings() as captured:
assert len(captured) == 1
with catch_deprecation_warnings() as captured:
class PyStringIO(object):
def __init__(self, *args, **kwargs):
self._io = StringIO(*args, **kwargs)
@ -313,59 +312,59 @@ class SendfileTestCase(FlaskTestCase):
f.name = 'test.txt'
rv = flask.send_file(f)
rv.direct_passthrough = False
self.assert_equal(rv.data, b'Test')
self.assert_equal(rv.mimetype, 'text/plain')
assert rv.data == b'Test'
assert rv.mimetype == 'text/plain'
rv.close()
# attachment_filename and etags
self.assert_equal(len(captured), 3)
with catch_warnings() as captured:
assert len(captured) == 3
with catch_deprecation_warnings() as captured:
f = StringIO('Test')
rv = flask.send_file(f, mimetype='text/plain')
rv.direct_passthrough = False
self.assert_equal(rv.data, b'Test')
self.assert_equal(rv.mimetype, 'text/plain')
assert rv.data == b'Test'
assert rv.mimetype == 'text/plain'
rv.close()
# etags
self.assert_equal(len(captured), 1)
assert len(captured) == 1
app.use_x_sendfile = True
with catch_warnings() as captured:
with catch_deprecation_warnings() as captured:
with app.test_request_context():
f = StringIO('Test')
rv = flask.send_file(f)
self.assert_not_in('x-sendfile', rv.headers)
assert 'x-sendfile' not in rv.headers
rv.close()
# etags
self.assert_equal(len(captured), 1)
assert len(captured) == 1
def test_attachment(self):
def test_attachment(self, catch_deprecation_warnings):
app = flask.Flask(__name__)
with catch_warnings() as captured:
with catch_deprecation_warnings() as captured:
with app.test_request_context():
f = open(os.path.join(app.root_path, 'static/index.html'))
rv = flask.send_file(f, as_attachment=True)
value, options = parse_options_header(rv.headers['Content-Disposition'])
self.assert_equal(value, 'attachment')
assert value == 'attachment'
rv.close()
# mimetypes + etag
self.assert_equal(len(captured), 2)
assert len(captured) == 2
with app.test_request_context():
self.assert_equal(options['filename'], 'index.html')
assert options['filename'] == 'index.html'
rv = flask.send_file('static/index.html', as_attachment=True)
value, options = parse_options_header(rv.headers['Content-Disposition'])
self.assert_equal(value, 'attachment')
self.assert_equal(options['filename'], 'index.html')
assert value == 'attachment'
assert options['filename'] == 'index.html'
rv.close()
with app.test_request_context():
rv = flask.send_file(StringIO('Test'), as_attachment=True,
attachment_filename='index.txt',
add_etags=False)
self.assert_equal(rv.mimetype, 'text/plain')
assert rv.mimetype == 'text/plain'
value, options = parse_options_header(rv.headers['Content-Disposition'])
self.assert_equal(value, 'attachment')
self.assert_equal(options['filename'], 'index.txt')
assert value == 'attachment'
assert options['filename'] == 'index.txt'
rv.close()
def test_static_file(self):
@ -375,24 +374,24 @@ class SendfileTestCase(FlaskTestCase):
# Test with static file handler.
rv = app.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 12 * 60 * 60)
assert cc.max_age == 12 * 60 * 60
rv.close()
# Test again with direct use of send_file utility.
rv = flask.send_file('static/index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 12 * 60 * 60)
assert cc.max_age == 12 * 60 * 60
rv.close()
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 3600
with app.test_request_context():
# Test with static file handler.
rv = app.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 3600)
assert cc.max_age == 3600
rv.close()
# Test again with direct use of send_file utility.
rv = flask.send_file('static/index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 3600)
assert cc.max_age == 3600
rv.close()
class StaticFileApp(flask.Flask):
def get_send_file_max_age(self, filename):
@ -402,12 +401,12 @@ class SendfileTestCase(FlaskTestCase):
# Test with static file handler.
rv = app.send_static_file('index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 10)
assert cc.max_age == 10
rv.close()
# Test again with direct use of send_file utility.
rv = flask.send_file('static/index.html')
cc = parse_cache_control_header(rv.headers['Cache-Control'])
self.assert_equal(cc.max_age, 10)
assert cc.max_age == 10
rv.close()
def test_send_from_directory(self):
@ -418,21 +417,21 @@ class SendfileTestCase(FlaskTestCase):
with app.test_request_context():
rv = flask.send_from_directory('static', 'hello.txt')
rv.direct_passthrough = False
self.assert_equal(rv.data.strip(), b'Hello Subdomain')
assert rv.data.strip() == b'Hello Subdomain'
rv.close()
class LoggingTestCase(FlaskTestCase):
class TestLogging(object):
def test_logger_cache(self):
app = flask.Flask(__name__)
logger1 = app.logger
self.assert_true(app.logger is logger1)
self.assert_equal(logger1.name, __name__)
assert app.logger is logger1
assert logger1.name == __name__
app.logger_name = __name__ + '/test_logger_cache'
self.assert_true(app.logger is not logger1)
assert app.logger is not logger1
def test_debug_log(self):
def test_debug_log(self, capsys):
app = flask.Flask(__name__)
app.debug = True
@ -447,28 +446,22 @@ class LoggingTestCase(FlaskTestCase):
1 // 0
with app.test_client() as c:
with catch_stderr() as err:
c.get('/')
out = err.getvalue()
self.assert_in('WARNING in helpers [', out)
self.assert_in(os.path.basename(__file__.rsplit('.', 1)[0] + '.py'), out)
self.assert_in('the standard library is dead', out)
self.assert_in('this is a debug statement', out)
with catch_stderr() as err:
try:
c.get('/exc')
except ZeroDivisionError:
pass
else:
self.assert_true(False, 'debug log ate the exception')
c.get('/')
out, err = capsys.readouterr()
assert 'WARNING in test_helpers [' in err
assert os.path.basename(__file__.rsplit('.', 1)[0] + '.py') in err
assert 'the standard library is dead' in err
assert 'this is a debug statement' in err
with pytest.raises(ZeroDivisionError):
c.get('/exc')
def test_debug_log_override(self):
app = flask.Flask(__name__)
app.debug = True
app.logger_name = 'flask_tests/test_debug_log_override'
app.logger.level = 10
self.assert_equal(app.logger.level, 10)
assert app.logger.level == 10
def test_exception_logging(self):
out = StringIO()
@ -482,14 +475,14 @@ class LoggingTestCase(FlaskTestCase):
1 // 0
rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 500)
self.assert_in(b'Internal Server Error', rv.data)
assert rv.status_code == 500
assert b'Internal Server Error' in rv.data
err = out.getvalue()
self.assert_in('Exception on / [GET]', err)
self.assert_in('Traceback (most recent call last):', err)
self.assert_in('1 // 0', err)
self.assert_in('ZeroDivisionError:', err)
assert 'Exception on / [GET]' in err
assert 'Traceback (most recent call last):' in err
assert '1 // 0' in err
assert 'ZeroDivisionError:' in err
def test_processor_exceptions(self):
app = flask.Flask(__name__)
@ -511,8 +504,8 @@ class LoggingTestCase(FlaskTestCase):
return 'Hello Server Error', 500
for trigger in 'before', 'after':
rv = app.test_client().get('/')
self.assert_equal(rv.status_code, 500)
self.assert_equal(rv.data, b'Hello Server Error')
assert rv.status_code == 500
assert rv.data == b'Hello Server Error'
def test_url_for_with_anchor(self):
app = flask.Flask(__name__)
@ -520,8 +513,7 @@ class LoggingTestCase(FlaskTestCase):
def index():
return '42'
with app.test_request_context():
self.assert_equal(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):
app = flask.Flask(__name__)
@ -529,10 +521,7 @@ class LoggingTestCase(FlaskTestCase):
def index():
return '42'
with app.test_request_context():
self.assert_equal(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):
app = flask.Flask(__name__)
@ -540,7 +529,7 @@ class LoggingTestCase(FlaskTestCase):
def index():
return '42'
with app.test_request_context():
self.assert_raises(ValueError,
pytest.raises(ValueError,
flask.url_for,
'index',
_scheme='https')
@ -564,15 +553,12 @@ class LoggingTestCase(FlaskTestCase):
view_func=myview)
with app.test_request_context():
self.assert_equal(flask.url_for('myview', _method='GET'),
'/myview/')
self.assert_equal(flask.url_for('myview', id=42, _method='GET'),
'/myview/42')
self.assert_equal(flask.url_for('myview', _method='POST'),
'/myview/create')
assert flask.url_for('myview', _method='GET') == '/myview/'
assert flask.url_for('myview', id=42, _method='GET') == '/myview/42'
assert flask.url_for('myview', _method='POST') == '/myview/create'
class NoImportsTestCase(FlaskTestCase):
class TestNoImports(object):
"""Test Flasks are created without import.
Avoiding ``__import__`` helps create Flask instances where there are errors
@ -583,14 +569,15 @@ class NoImportsTestCase(FlaskTestCase):
imp modules in the Python standard library.
"""
def test_name_with_import_error(self):
def test_name_with_import_error(self, modules_tmpdir):
modules_tmpdir.join('importerror.py').write('raise NotImplementedError()')
try:
flask.Flask('importerror')
except NotImplementedError:
self.fail('Flask(import_name) is importing import_name.')
assert False, 'Flask(import_name) is importing import_name.'
class StreamingTestCase(FlaskTestCase):
class TestStreaming(object):
def test_streaming_with_context(self):
app = flask.Flask(__name__)
@ -604,7 +591,7 @@ class StreamingTestCase(FlaskTestCase):
return flask.Response(flask.stream_with_context(generate()))
c = app.test_client()
rv = c.get('/?name=World')
self.assertEqual(rv.data, b'Hello World!')
assert rv.data == b'Hello World!'
def test_streaming_with_context_as_decorator(self):
app = flask.Flask(__name__)
@ -619,7 +606,7 @@ class StreamingTestCase(FlaskTestCase):
return flask.Response(generate())
c = app.test_client()
rv = c.get('/?name=World')
self.assertEqual(rv.data, b'Hello World!')
assert rv.data == b'Hello World!'
def test_streaming_with_context_and_custom_close(self):
app = flask.Flask(__name__)
@ -645,16 +632,5 @@ class StreamingTestCase(FlaskTestCase):
Wrapper(generate())))
c = app.test_client()
rv = c.get('/?name=World')
self.assertEqual(rv.data, b'Hello World!')
self.assertEqual(called, [42])
def suite():
suite = unittest.TestSuite()
if flask.json_available:
suite.addTest(unittest.makeSuite(JSONTestCase))
suite.addTest(unittest.makeSuite(SendfileTestCase))
suite.addTest(unittest.makeSuite(LoggingTestCase))
suite.addTest(unittest.makeSuite(NoImportsTestCase))
suite.addTest(unittest.makeSuite(StreamingTestCase))
return suite
assert rv.data == b'Hello World!'
assert called == [42]

134
tests/test_instance_config.py

@ -0,0 +1,134 @@
# -*- coding: utf-8 -*-
"""
tests.test_instance
~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 by the Flask Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
import os
import sys
import pytest
import flask
from flask._compat import PY2
def test_explicit_instance_paths(modules_tmpdir):
with pytest.raises(ValueError) as excinfo:
flask.Flask(__name__, instance_path='instance')
assert 'must be absolute' in str(excinfo.value)
app = flask.Flask(__name__, instance_path=str(modules_tmpdir))
assert app.instance_path == str(modules_tmpdir)
def test_main_module_paths(modules_tmpdir, purge_module):
app = modules_tmpdir.join('main_app.py')
app.write('import flask\n\napp = flask.Flask("__main__")')
purge_module('main_app')
from main_app import app
here = os.path.abspath(os.getcwd())
assert app.instance_path == os.path.join(here, 'instance')
def test_uninstalled_module_paths(modules_tmpdir, purge_module):
app = modules_tmpdir.join('config_module_app.py').write(
'import os\n'
'import flask\n'
'here = os.path.abspath(os.path.dirname(__file__))\n'
'app = flask.Flask(__name__)\n'
)
purge_module('config_module_app')
from config_module_app import app
assert app.instance_path == str(modules_tmpdir.join('instance'))
def test_uninstalled_package_paths(modules_tmpdir, purge_module):
app = modules_tmpdir.mkdir('config_package_app')
init = app.join('__init__.py')
init.write(
'import os\n'
'import flask\n'
'here = os.path.abspath(os.path.dirname(__file__))\n'
'app = flask.Flask(__name__)\n'
)
purge_module('config_package_app')
from config_package_app import app
assert app.instance_path == str(modules_tmpdir.join('instance'))
def test_installed_module_paths(modules_tmpdir, modules_tmpdir_prefix,
purge_module, site_packages, limit_loader):
site_packages.join('site_app.py').write(
'import flask\n'
'app = flask.Flask(__name__)\n'
)
purge_module('site_app')
from site_app import app
assert app.instance_path == \
modules_tmpdir.join('var').join('site_app-instance')
def test_installed_package_paths(limit_loader, modules_tmpdir,
modules_tmpdir_prefix, purge_module,
monkeypatch):
installed_path = modules_tmpdir.mkdir('path')
monkeypatch.syspath_prepend(installed_path)
app = installed_path.mkdir('installed_package')
init = app.join('__init__.py')
init.write('import flask\napp = flask.Flask(__name__)')
purge_module('installed_package')
from installed_package import app
assert app.instance_path == \
modules_tmpdir.join('var').join('installed_package-instance')
def test_prefix_package_paths(limit_loader, modules_tmpdir,
modules_tmpdir_prefix, purge_module,
site_packages):
app = site_packages.mkdir('site_package')
init = app.join('__init__.py')
init.write('import flask\napp = flask.Flask(__name__)')
purge_module('site_package')
import site_package
assert site_package.app.instance_path == \
modules_tmpdir.join('var').join('site_package-instance')
def test_egg_installed_paths(install_egg, modules_tmpdir,
modules_tmpdir_prefix):
modules_tmpdir.mkdir('site_egg').join('__init__.py').write(
'import flask\n\napp = flask.Flask(__name__)'
)
install_egg('site_egg')
try:
import site_egg
assert site_egg.app.instance_path == \
str(modules_tmpdir.join('var/').join('site_egg-instance'))
finally:
if 'site_egg' in sys.modules:
del sys.modules['site_egg']
@pytest.mark.skipif(not PY2, reason='This only works under Python 2.')
def test_meta_path_loader_without_is_package(request, modules_tmpdir):
app = modules_tmpdir.join('unimportable.py')
app.write('import flask\napp = flask.Flask(__name__)')
class Loader(object):
def find_module(self, name, path=None):
return self
sys.meta_path.append(Loader())
request.addfinalizer(sys.meta_path.pop)
with pytest.raises(AttributeError):
import unimportable

107
tests/test_regression.py

@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
"""
tests.regression
~~~~~~~~~~~~~~~~~~~~~~~~~~
Tests regressions.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import pytest
import os
import gc
import sys
import flask
import threading
from werkzeug.exceptions import NotFound
_gc_lock = threading.Lock()
class assert_no_leak(object):
def __enter__(self):
gc.disable()
_gc_lock.acquire()
loc = flask._request_ctx_stack._local
# Force Python to track this dictionary at all times.
# This is necessary since Python only starts tracking
# dicts if they contain mutable objects. It's a horrible,
# horrible hack but makes this kinda testable.
loc.__storage__['FOOO'] = [1, 2, 3]
gc.collect()
self.old_objects = len(gc.get_objects())
def __exit__(self, exc_type, exc_value, tb):
if not hasattr(sys, 'getrefcount'):
gc.collect()
new_objects = len(gc.get_objects())
if new_objects > self.old_objects:
pytest.fail('Example code leaked')
_gc_lock.release()
gc.enable()
# XXX: untitaker: These tests need to be revised. They broke around the time we
# ported Flask to Python 3.
@pytest.mark.skipif(os.environ.get('RUN_FLASK_MEMORY_TESTS') != '1',
reason='Turned off due to envvar.')
def test_memory_consumption():
app = flask.Flask(__name__)
@app.route('/')
def index():
return flask.render_template('simple_template.html', whiskey=42)
def fire():
with app.test_client() as c:
rv = c.get('/')
assert rv.status_code == 200
assert rv.data == b'<h1>42</h1>'
# Trigger caches
fire()
# This test only works on CPython 2.7.
if sys.version_info >= (2, 7) and \
not hasattr(sys, 'pypy_translation_info'):
with assert_no_leak():
for x in range(10):
fire()
def test_safe_join_toplevel_pardir():
from flask.helpers import safe_join
with pytest.raises(NotFound):
safe_join('/foo', '..')
def test_aborting():
class Foo(Exception):
whatever = 42
app = flask.Flask(__name__)
app.testing = True
@app.errorhandler(Foo)
def handle_foo(e):
return str(e.whatever)
@app.route('/')
def index():
raise flask.abort(flask.redirect(flask.url_for('test')))
@app.route('/test')
def test():
raise Foo()
with app.test_client() as c:
rv = c.get('/')
assert rv.headers['Location'] == 'http://localhost/test'
rv = c.get('/test')
assert rv.data == b'42'

185
tests/test_reqctx.py

@ -0,0 +1,185 @@
# -*- coding: utf-8 -*-
"""
tests.reqctx
~~~~~~~~~~~~~~~~~~~~~~
Tests the request context.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import pytest
import flask
import unittest
try:
from greenlet import greenlet
except ImportError:
greenlet = None
def test_teardown_on_pop():
buffer = []
app = flask.Flask(__name__)
@app.teardown_request
def end_of_request(exception):
buffer.append(exception)
ctx = app.test_request_context()
ctx.push()
assert buffer == []
ctx.pop()
assert buffer == [None]
def test_teardown_with_previous_exception():
buffer = []
app = flask.Flask(__name__)
@app.teardown_request
def end_of_request(exception):
buffer.append(exception)
try:
raise Exception('dummy')
except Exception:
pass
with app.test_request_context():
assert buffer == []
assert buffer == [None]
def test_proper_test_request_context():
app = flask.Flask(__name__)
app.config.update(
SERVER_NAME='localhost.localdomain:5000'
)
@app.route('/')
def index():
return None
@app.route('/', subdomain='foo')
def sub():
return None
with app.test_request_context('/'):
assert flask.url_for('index', _external=True) == \
'http://localhost.localdomain:5000/'
with app.test_request_context('/'):
assert flask.url_for('sub', _external=True) == \
'http://foo.localhost.localdomain:5000/'
try:
with app.test_request_context('/', environ_overrides={'HTTP_HOST': 'localhost'}):
pass
except ValueError as e:
assert str(e) == (
"the server name provided "
"('localhost.localdomain:5000') does not match the "
"server name from the WSGI environment ('localhost')"
)
app.config.update(SERVER_NAME='localhost')
with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost'}):
pass
app.config.update(SERVER_NAME='localhost:80')
with app.test_request_context('/', environ_overrides={'SERVER_NAME': 'localhost:80'}):
pass
def test_context_binding():
app = flask.Flask(__name__)
@app.route('/')
def index():
return 'Hello %s!' % flask.request.args['name']
@app.route('/meh')
def meh():
return flask.request.url
with app.test_request_context('/?name=World'):
assert index() == 'Hello World!'
with app.test_request_context('/meh'):
assert meh() == 'http://localhost/meh'
assert flask._request_ctx_stack.top is None
def test_context_test():
app = flask.Flask(__name__)
assert not flask.request
assert not flask.has_request_context()
ctx = app.test_request_context()
ctx.push()
try:
assert flask.request
assert flask.has_request_context()
finally:
ctx.pop()
def test_manual_context_binding():
app = flask.Flask(__name__)
@app.route('/')
def index():
return 'Hello %s!' % flask.request.args['name']
ctx = app.test_request_context('/?name=World')
ctx.push()
assert index() == 'Hello World!'
ctx.pop()
try:
index()
except RuntimeError:
pass
else:
assert 0, 'expected runtime error'
@pytest.mark.skipif(greenlet is None, reason='greenlet not installed')
def test_greenlet_context_copying():
app = flask.Flask(__name__)
greenlets = []
@app.route('/')
def index():
reqctx = flask._request_ctx_stack.top.copy()
def g():
assert not flask.request
assert not flask.current_app
with reqctx:
assert flask.request
assert flask.current_app == app
assert flask.request.path == '/'
assert flask.request.args['foo'] == 'bar'
assert not flask.request
return 42
greenlets.append(greenlet(g))
return 'Hello World!'
rv = app.test_client().get('/?foo=bar')
assert rv.data == b'Hello World!'
result = greenlets[0].run()
assert result == 42
@pytest.mark.skipif(greenlet is None, reason='greenlet not installed')
def test_greenlet_context_copying_api():
app = flask.Flask(__name__)
greenlets = []
@app.route('/')
def index():
reqctx = flask._request_ctx_stack.top.copy()
@flask.copy_current_request_context
def g():
assert flask.request
assert flask.current_app == app
assert flask.request.path == '/'
assert flask.request.args['foo'] == 'bar'
return 42
greenlets.append(greenlet(g))
return 'Hello World!'
rv = app.test_client().get('/?foo=bar')
assert rv.data == b'Hello World!'
result = greenlets[0].run()
assert result == 42

158
tests/test_signals.py

@ -0,0 +1,158 @@
# -*- coding: utf-8 -*-
"""
tests.signals
~~~~~~~~~~~~~~~~~~~~~~~
Signalling.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import pytest
try:
import blinker
except ImportError:
blinker = None
import flask
pytestmark = pytest.mark.skipif(
blinker is None,
reason='Signals require the blinker library.'
)
def test_template_rendered():
app = flask.Flask(__name__)
@app.route('/')
def index():
return flask.render_template('simple_template.html', whiskey=42)
recorded = []
def record(sender, template, context):
recorded.append((template, context))
flask.template_rendered.connect(record, app)
try:
app.test_client().get('/')
assert len(recorded) == 1
template, context = recorded[0]
assert template.name == 'simple_template.html'
assert context['whiskey'] == 42
finally:
flask.template_rendered.disconnect(record, app)
def test_request_signals():
app = flask.Flask(__name__)
calls = []
def before_request_signal(sender):
calls.append('before-signal')
def after_request_signal(sender, response):
assert response.data == b'stuff'
calls.append('after-signal')
@app.before_request
def before_request_handler():
calls.append('before-handler')
@app.after_request
def after_request_handler(response):
calls.append('after-handler')
response.data = 'stuff'
return response
@app.route('/')
def index():
calls.append('handler')
return 'ignored anyway'
flask.request_started.connect(before_request_signal, app)
flask.request_finished.connect(after_request_signal, app)
try:
rv = app.test_client().get('/')
assert rv.data == b'stuff'
assert calls == ['before-signal', 'before-handler', 'handler',
'after-handler', 'after-signal']
finally:
flask.request_started.disconnect(before_request_signal, app)
flask.request_finished.disconnect(after_request_signal, app)
def test_request_exception_signal():
app = flask.Flask(__name__)
recorded = []
@app.route('/')
def index():
1 // 0
def record(sender, exception):
recorded.append(exception)
flask.got_request_exception.connect(record, app)
try:
assert app.test_client().get('/').status_code == 500
assert len(recorded) == 1
assert isinstance(recorded[0], ZeroDivisionError)
finally:
flask.got_request_exception.disconnect(record, app)
def test_appcontext_signals():
app = flask.Flask(__name__)
recorded = []
def record_push(sender, **kwargs):
recorded.append('push')
def record_pop(sender, **kwargs):
recorded.append('pop')
@app.route('/')
def index():
return 'Hello'
flask.appcontext_pushed.connect(record_push, app)
flask.appcontext_popped.connect(record_pop, app)
try:
with app.test_client() as c:
rv = c.get('/')
assert rv.data == b'Hello'
assert recorded == ['push']
assert recorded == ['push', 'pop']
finally:
flask.appcontext_pushed.disconnect(record_push, app)
flask.appcontext_popped.disconnect(record_pop, app)
def test_flash_signal():
app = flask.Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
@app.route('/')
def index():
flask.flash('This is a flash message', category='notice')
return flask.redirect('/other')
recorded = []
def record(sender, message, category):
recorded.append((message, category))
flask.message_flashed.connect(record, app)
try:
client = app.test_client()
with client.session_transaction():
client.get('/')
assert len(recorded) == 1
message, category = recorded[0]
assert message == 'This is a flash message'
assert category == 'notice'
finally:
flask.message_flashed.disconnect(record, app)

38
tests/test_subclassing.py

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
"""
tests.subclassing
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Test that certain behavior of flask can be customized by
subclasses.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import flask
import unittest
from logging import StreamHandler
from flask._compat import StringIO
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 == ''

342
tests/test_templating.py

@ -0,0 +1,342 @@
# -*- coding: utf-8 -*-
"""
tests.templating
~~~~~~~~~~~~~~~~~~~~~~~~~~
Template functionality
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import pytest
import flask
import unittest
import logging
from jinja2 import TemplateNotFound
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'<p>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 = '<p>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'&lt;p&gt;Hello World!',
b'<p>Hello World!',
b'<p>Hello World!',
b'<p>Hello World!',
b'&lt;p&gt;Hello World!',
b'<p>Hello World!'
]
def test_no_escaping():
app = flask.Flask(__name__)
with app.test_request_context():
assert flask.render_template_string(
'{{ foo }}', foo='<test>') == '<test>'
assert flask.render_template('mail.txt', foo='<test>') == \
'<test> Mail'
def test_macros():
app = flask.Flask(__name__)
with app.test_request_context():
macro = flask.get_template_attribute('_macro.html', 'hello')
assert macro('World') == 'Hello World!'
def test_template_filter():
app = flask.Flask(__name__)
@app.template_filter()
def my_reverse(s):
return s[::-1]
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']('abcd') == 'dcba'
def test_add_template_filter():
app = flask.Flask(__name__)
def my_reverse(s):
return s[::-1]
app.add_template_filter(my_reverse)
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']('abcd') == 'dcba'
def test_template_filter_with_name():
app = flask.Flask(__name__)
@app.template_filter('strrev')
def my_reverse(s):
return s[::-1]
assert 'strrev' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['strrev'] == my_reverse
assert app.jinja_env.filters['strrev']('abcd') == 'dcba'
def test_add_template_filter_with_name():
app = flask.Flask(__name__)
def my_reverse(s):
return s[::-1]
app.add_template_filter(my_reverse, 'strrev')
assert 'strrev' in app.jinja_env.filters.keys()
assert app.jinja_env.filters['strrev'] == my_reverse
assert app.jinja_env.filters['strrev']('abcd') == 'dcba'
def test_template_filter_with_template():
app = flask.Flask(__name__)
@app.template_filter()
def super_reverse(s):
return s[::-1]
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
assert rv.data == b'dcba'
def test_add_template_filter_with_template():
app = flask.Flask(__name__)
def super_reverse(s):
return s[::-1]
app.add_template_filter(super_reverse)
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
assert rv.data == b'dcba'
def test_template_filter_with_name_and_template():
app = flask.Flask(__name__)
@app.template_filter('super_reverse')
def my_reverse(s):
return s[::-1]
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
assert rv.data == b'dcba'
def test_add_template_filter_with_name_and_template():
app = flask.Flask(__name__)
def my_reverse(s):
return s[::-1]
app.add_template_filter(my_reverse, 'super_reverse')
@app.route('/')
def index():
return flask.render_template('template_filter.html', value='abcd')
rv = app.test_client().get('/')
assert rv.data == b'dcba'
def test_template_test():
app = flask.Flask(__name__)
@app.template_test()
def boolean(value):
return isinstance(value, bool)
assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == boolean
assert app.jinja_env.tests['boolean'](False)
def test_add_template_test():
app = flask.Flask(__name__)
def boolean(value):
return isinstance(value, bool)
app.add_template_test(boolean)
assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == boolean
assert app.jinja_env.tests['boolean'](False)
def test_template_test_with_name():
app = flask.Flask(__name__)
@app.template_test('boolean')
def is_boolean(value):
return isinstance(value, bool)
assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == is_boolean
assert app.jinja_env.tests['boolean'](False)
def test_add_template_test_with_name():
app = flask.Flask(__name__)
def is_boolean(value):
return isinstance(value, bool)
app.add_template_test(is_boolean, 'boolean')
assert 'boolean' in app.jinja_env.tests.keys()
assert app.jinja_env.tests['boolean'] == is_boolean
assert app.jinja_env.tests['boolean'](False)
def test_template_test_with_template():
app = flask.Flask(__name__)
@app.template_test()
def boolean(value):
return isinstance(value, bool)
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
assert b'Success!' in rv.data
def test_add_template_test_with_template():
app = flask.Flask(__name__)
def boolean(value):
return isinstance(value, bool)
app.add_template_test(boolean)
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
assert b'Success!' in rv.data
def test_template_test_with_name_and_template():
app = flask.Flask(__name__)
@app.template_test('boolean')
def is_boolean(value):
return isinstance(value, bool)
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
assert b'Success!' in rv.data
def test_add_template_test_with_name_and_template():
app = flask.Flask(__name__)
def is_boolean(value):
return isinstance(value, bool)
app.add_template_test(is_boolean, 'boolean')
@app.route('/')
def index():
return flask.render_template('template_test.html', value=False)
rv = app.test_client().get('/')
assert b'Success!' in rv.data
def test_add_template_global():
app = flask.Flask(__name__)
@app.template_global()
def get_stuff():
return 42
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'](), 42
with app.app_context():
rv = flask.render_template_string('{{ get_stuff() }}')
assert rv == '42'
def test_custom_template_loader():
class MyFlask(flask.Flask):
def create_global_jinja_loader(self):
from jinja2 import DictLoader
return DictLoader({'index.html': 'Hello Custom World!'})
app = MyFlask(__name__)
@app.route('/')
def index():
return flask.render_template('index.html')
c = app.test_client()
rv = c.get('/')
assert rv.data == b'Hello Custom World!'
def test_iterable_loader():
app = flask.Flask(__name__)
@app.context_processor
def context_processor():
return {'whiskey': 'Jameson'}
@app.route('/')
def index():
return flask.render_template(
['no_template.xml', # should skip this one
'simple_template.html', # should render this
'context_template.html'],
value=23)
rv = app.test_client().get('/')
assert rv.data == b'<h1>Jameson</h1>'
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(test_apps):
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

243
tests/test_testing.py

@ -0,0 +1,243 @@
# -*- coding: utf-8 -*-
"""
tests.testing
~~~~~~~~~~~~~~~~~~~~~~~
Test client and more.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import pytest
import flask
import unittest
from flask._compat import text_type
def test_environ_defaults_from_config():
app = flask.Flask(__name__)
app.testing = True
app.config['SERVER_NAME'] = 'example.com:1234'
app.config['APPLICATION_ROOT'] = '/foo'
@app.route('/')
def index():
return flask.request.url
ctx = app.test_request_context()
assert ctx.request.url == 'http://example.com:1234/foo/'
with app.test_client() as c:
rv = c.get('/')
assert rv.data == b'http://example.com:1234/foo/'
def test_environ_defaults():
app = flask.Flask(__name__)
app.testing = True
@app.route('/')
def index():
return flask.request.url
ctx = app.test_request_context()
assert ctx.request.url == 'http://localhost/'
with app.test_client() as c:
rv = c.get('/')
assert rv.data == b'http://localhost/'
def test_redirect_keep_session():
app = flask.Flask(__name__)
app.secret_key = 'testing'
@app.route('/', methods=['GET', 'POST'])
def index():
if flask.request.method == 'POST':
return flask.redirect('/getsession')
flask.session['data'] = 'foo'
return 'index'
@app.route('/getsession')
def get_session():
return flask.session.get('data', '<missing>')
with app.test_client() as c:
rv = c.get('/getsession')
assert rv.data == b'<missing>'
rv = c.get('/')
assert rv.data == b'index'
assert flask.session.get('data') == 'foo'
rv = c.post('/', data={}, follow_redirects=True)
assert rv.data == b'foo'
# This support requires a new Werkzeug version
if not hasattr(c, 'redirect_client'):
assert flask.session.get('data') == 'foo'
rv = c.get('/getsession')
assert rv.data == b'foo'
def test_session_transactions():
app = flask.Flask(__name__)
app.testing = True
app.secret_key = 'testing'
@app.route('/')
def index():
return text_type(flask.session['foo'])
with app.test_client() as c:
with c.session_transaction() as sess:
assert len(sess) == 0
sess['foo'] = [42]
assert len(sess) == 1
rv = c.get('/')
assert rv.data == b'[42]'
with c.session_transaction() as sess:
assert len(sess) == 1
assert sess['foo'] == [42]
def test_session_transactions_no_null_sessions():
app = flask.Flask(__name__)
app.testing = True
with app.test_client() as c:
try:
with c.session_transaction() as sess:
pass
except RuntimeError as e:
assert 'Session backend did not open a session' in str(e)
else:
assert False, 'Expected runtime error'
def test_session_transactions_keep_context():
app = flask.Flask(__name__)
app.testing = True
app.secret_key = 'testing'
with app.test_client() as c:
rv = c.get('/')
req = flask.request._get_current_object()
assert req is not None
with c.session_transaction():
assert req is flask.request._get_current_object()
def test_session_transaction_needs_cookies():
app = flask.Flask(__name__)
app.testing = True
c = app.test_client(use_cookies=False)
try:
with c.session_transaction() as s:
pass
except RuntimeError as e:
assert 'cookies' in str(e)
else:
assert False, 'Expected runtime error'
def test_test_client_context_binding():
app = flask.Flask(__name__)
app.config['LOGGER_HANDLER_POLICY'] = 'never'
@app.route('/')
def index():
flask.g.value = 42
return 'Hello World!'
@app.route('/other')
def other():
1 // 0
with app.test_client() as c:
resp = c.get('/')
assert flask.g.value == 42
assert resp.data == b'Hello World!'
assert resp.status_code == 200
resp = c.get('/other')
assert not hasattr(flask.g, 'value')
assert b'Internal Server Error' in resp.data
assert resp.status_code == 500
flask.g.value = 23
try:
flask.g.value
except (AttributeError, RuntimeError):
pass
else:
raise AssertionError('some kind of exception expected')
def test_reuse_client():
app = flask.Flask(__name__)
c = app.test_client()
with c:
assert c.get('/').status_code == 404
with c:
assert c.get('/').status_code == 404
def test_test_client_calls_teardown_handlers():
app = flask.Flask(__name__)
called = []
@app.teardown_request
def remember(error):
called.append(error)
with app.test_client() as c:
assert called == []
c.get('/')
assert called == []
assert called == [None]
del called[:]
with app.test_client() as c:
assert called == []
c.get('/')
assert called == []
c.get('/')
assert called == [None]
assert called == [None, None]
def test_full_url_request():
app = flask.Flask(__name__)
app.testing = True
@app.route('/action', methods=['POST'])
def action():
return 'x'
with app.test_client() as c:
rv = c.post('http://domain.com/action?vodka=42', data={'gin': 43})
assert rv.status_code == 200
assert 'gin' in flask.request.form
assert 'vodka' in flask.request.args
def test_subdomain():
app = flask.Flask(__name__)
app.config['SERVER_NAME'] = 'example.com'
@app.route('/', subdomain='<company_id>')
def view(company_id):
return company_id
with app.test_request_context():
url = flask.url_for('view', company_id='xxx')
with app.test_client() as c:
response = c.get(url)
assert 200 == response.status_code
assert b'xxx' == response.data
def test_nosubdomain():
app = flask.Flask(__name__)
app.config['SERVER_NAME'] = 'example.com'
@app.route('/<company_id>')
def view(company_id):
return company_id
with app.test_request_context():
url = flask.url_for('view', company_id='xxx')
with app.test_client() as c:
response = c.get(url)
assert 200 == response.status_code
assert b'xxx' == response.data

163
tests/test_views.py

@ -0,0 +1,163 @@
# -*- coding: utf-8 -*-
"""
tests.views
~~~~~~~~~~~~~~~~~~~~~
Pluggable views.
:copyright: (c) 2014 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
import pytest
import flask
import flask.views
import unittest
from werkzeug.http import parse_set_header
def common_test(app):
c = app.test_client()
assert c.get('/').data == b'GET'
assert c.post('/').data == b'POST'
assert c.put('/').status_code == 405
meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow'])
assert sorted(meths) == ['GET', 'HEAD', 'OPTIONS', 'POST']
def test_basic_view():
app = flask.Flask(__name__)
class Index(flask.views.View):
methods = ['GET', 'POST']
def dispatch_request(self):
return flask.request.method
app.add_url_rule('/', view_func=Index.as_view('index'))
common_test(app)
def test_method_based_view():
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
return 'GET'
def post(self):
return 'POST'
app.add_url_rule('/', view_func=Index.as_view('index'))
common_test(app)
def test_view_patching():
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
1 // 0
def post(self):
1 // 0
class Other(Index):
def get(self):
return 'GET'
def post(self):
return 'POST'
view = Index.as_view('index')
view.view_class = Other
app.add_url_rule('/', view_func=view)
common_test(app)
def test_view_inheritance():
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
return 'GET'
def post(self):
return 'POST'
class BetterIndex(Index):
def delete(self):
return 'DELETE'
app.add_url_rule('/', view_func=BetterIndex.as_view('index'))
c = app.test_client()
meths = parse_set_header(c.open('/', method='OPTIONS').headers['Allow'])
assert sorted(meths) == ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST']
def test_view_decorators():
app = flask.Flask(__name__)
def add_x_parachute(f):
def new_function(*args, **kwargs):
resp = flask.make_response(f(*args, **kwargs))
resp.headers['X-Parachute'] = 'awesome'
return resp
return new_function
class Index(flask.views.View):
decorators = [add_x_parachute]
def dispatch_request(self):
return 'Awesome'
app.add_url_rule('/', view_func=Index.as_view('index'))
c = app.test_client()
rv = c.get('/')
assert rv.headers['X-Parachute'] == 'awesome'
assert rv.data == b'Awesome'
def test_implicit_head():
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
return flask.Response('Blub', headers={
'X-Method': flask.request.method
})
app.add_url_rule('/', view_func=Index.as_view('index'))
c = app.test_client()
rv = c.get('/')
assert rv.data == b'Blub'
assert rv.headers['X-Method'] == 'GET'
rv = c.head('/')
assert rv.data == b''
assert rv.headers['X-Method'] == 'HEAD'
def test_explicit_head():
app = flask.Flask(__name__)
class Index(flask.views.MethodView):
def get(self):
return 'GET'
def head(self):
return flask.Response('', headers={'X-Method': 'HEAD'})
app.add_url_rule('/', view_func=Index.as_view('index'))
c = app.test_client()
rv = c.get('/')
assert rv.data == b'GET'
rv = c.head('/')
assert rv.data == b''
assert rv.headers['X-Method'] == 'HEAD'
def test_endpoint_override():
app = flask.Flask(__name__)
app.debug = True
class Index(flask.views.View):
methods = ['GET', 'POST']
def dispatch_request(self):
return flask.request.method
app.add_url_rule('/', view_func=Index.as_view('index'))
with pytest.raises(AssertionError):
app.add_url_rule('/', view_func=Index.as_view('index'))
# But these tests should still pass. We just log a warning.
common_test(app)

22
tox.ini

@ -1,10 +1,26 @@
[tox]
envlist = docs, py26, py27, pypy, py33, py34
envlist = {py26,py27,pypy}-{lowest,release,devel}, {py33,py34}-{release,devel}
[testenv]
deps = blinker
commands = python run-tests.py []
commands =
py.test []
deps=
pytest
greenlet
lowest: Werkzeug==0.7
lowest: Jinja2==2.4
lowest: itsdangerous==0.21
lowest: blinker==1.0
release: blinker
devel: git+git://github.com/mitsuhiko/werkzeug.git
devel: git+git://github.com/mitsuhiko/jinja2.git
devel: git+git://github.com/mitsuhiko/itsdangerous.git
devel: git+git://github.com/jek/blinker.git
# extra dependencies
git+git://github.com/jek/blinker.git#egg=blinker
[testenv:docs]
deps = sphinx

Loading…
Cancel
Save