| <file url="file://$PROJECT_DIR$/calender/auth.py" dialect="GenericSQL" /> | <file url="file://$PROJECT_DIR$/calender/auth.py" dialect="GenericSQL" /> | ||||
| <file url="file://$PROJECT_DIR$/calender/calender.py" dialect="GenericSQL" /> | <file url="file://$PROJECT_DIR$/calender/calender.py" dialect="GenericSQL" /> | ||||
| <file url="file://$PROJECT_DIR$/calender/schema.sql" dialect="SQLite" /> | <file url="file://$PROJECT_DIR$/calender/schema.sql" dialect="SQLite" /> | ||||
| <file url="file://$PROJECT_DIR$/tests/data.sql" dialect="GenericSQL" /> | |||||
| </component> | </component> | ||||
| </project> | </project> |
| include calender/schema.sql | |||||
| graft calender/static | |||||
| graft calender/templates | |||||
| global-exclude *.pyc |
| [tool:pytest] | |||||
| testpaths = tests | |||||
| [coverage:run] | |||||
| branch = True | |||||
| source = | |||||
| calender |
| from setuptools import find_packages, setup | |||||
| setup( | |||||
| name='calender', | |||||
| version='3.0.1', | |||||
| packages=find_packages(), | |||||
| include_package_data=True, | |||||
| zip_safe=False, | |||||
| install_requires=[ | |||||
| 'flask', | |||||
| ], | |||||
| ) |
| import os | |||||
| import tempfile | |||||
| import pytest | |||||
| from calender import create_app | |||||
| from calender.db import get_db, init_db | |||||
| with open(os.path.join(os.path.dirname(__file__), 'data.sql'), 'rb') as f: | |||||
| _data_sql = f.read().decode('utf8') | |||||
| @pytest.fixture | |||||
| def app(): | |||||
| db_fd, db_path = tempfile.mkstemp() | |||||
| app = create_app({ | |||||
| 'TESTING': True, | |||||
| 'DATABASE': db_path, | |||||
| }) | |||||
| with app.app_context(): | |||||
| init_db() | |||||
| get_db().executescript(_data_sql) | |||||
| yield app | |||||
| os.close(db_fd) | |||||
| os.unlink(db_path) | |||||
| @pytest.fixture | |||||
| def client(app): | |||||
| return app.test_client() | |||||
| @pytest.fixture | |||||
| def runner(app): | |||||
| return app.test_cli_runner() | |||||
| class AuthActions(object): | |||||
| def __init__(self, client): | |||||
| self._client = client | |||||
| def login(self, username='test', password='test'): | |||||
| return self._client.post( | |||||
| '/auth/login', | |||||
| data={'username': username, 'password': password} | |||||
| ) | |||||
| def logout(self): | |||||
| return self._client.get('/auth/logout') | |||||
| @pytest.fixture | |||||
| def auth(client): | |||||
| return AuthActions(client) |
| INSERT INTO user (username, password) | |||||
| VALUES | |||||
| ('test', 'pbkdf2:sha256:50000$TCI4GzcX$0de171a4f4dac32e3364c7ddc7c14f3e2fa61f2d17574483f7ffbb431b4acb2f'), | |||||
| ('other', 'pbkdf2:sha256:50000$kJPKsz6N$d2d4784f1b030a9761f5ccaeeaca413f27f2ecb76d6168407af962ddce849f79'); | |||||
| INSERT INTO post (title, body, author_id, created) | |||||
| VALUES | |||||
| ('test title', 'test' || x'0a' || 'body', 1, '2018-01-01 00:00:00'); |
| import pytest | |||||
| from flask import g, session | |||||
| from calender.db import get_db | |||||
| def test_register(client, app): | |||||
| assert client.get('/auth/register').status_code == 200 | |||||
| response = client.post( | |||||
| '/auth/register', data={'username': 'a', 'password': 'a'} | |||||
| ) | |||||
| assert 'http://localhost/auth/login' == response.headers['Location'] | |||||
| with app.app_context(): | |||||
| assert get_db().execute( | |||||
| "select * from user where username = 'a'", | |||||
| ).fetchone() is not None | |||||
| @pytest.mark.parametrize(('username', 'password', 'message'), ( | |||||
| ('', '', b'Username is required.'), | |||||
| ('a', '', b'Password is required.'), | |||||
| ('test', 'test', b'already registered'), | |||||
| )) | |||||
| def test_register_validate_input(client, username, password, message): | |||||
| response = client.post( | |||||
| '/auth/register', | |||||
| data={'username': username, 'password': password} | |||||
| ) | |||||
| assert message in response.data | |||||
| def test_login(client, auth): | |||||
| assert client.get('/auth/login').status_code == 200 | |||||
| response = auth.login() | |||||
| assert response.headers['Location'] == 'http://localhost/' | |||||
| with client: | |||||
| client.get('/') | |||||
| assert session['user_id'] == 1 | |||||
| assert g.user['username'] == 'test' | |||||
| @pytest.mark.parametrize(('username', 'password', 'message'), ( | |||||
| ('a', 'test', b'Incorrect username.'), | |||||
| ('test', 'a', b'Incorrect password.'), | |||||
| )) | |||||
| def test_login_validate_input(auth, username, password, message): | |||||
| response = auth.login(username, password) | |||||
| assert message in response.data | |||||
| def test_logout(client, auth): | |||||
| auth.login() | |||||
| with client: | |||||
| auth.logout() | |||||
| assert 'user_id' not in session |
| import pytest | |||||
| from calender.db import get_db | |||||
| def test_index(client, auth): | |||||
| response = client.get('/') | |||||
| assert b"Log In" in response.data | |||||
| assert b"Register" in response.data | |||||
| auth.login() | |||||
| response = client.get('/') | |||||
| assert b'Log Out' in response.data | |||||
| assert b'test title' in response.data | |||||
| assert b'by test on 2018-01-01' in response.data | |||||
| assert b'test\nbody' in response.data | |||||
| assert b'href="/1/update"' in response.data | |||||
| @pytest.mark.parametrize('path', ( | |||||
| '/create', | |||||
| '/1/update', | |||||
| '/1/delete', | |||||
| )) | |||||
| def test_login_required(client, path): | |||||
| response = client.post(path) | |||||
| assert response.headers['Location'] == 'http://localhost/auth/login' | |||||
| def test_author_required(app, client, auth): | |||||
| # change the post author to another user | |||||
| with app.app_context(): | |||||
| db = get_db() | |||||
| db.execute('UPDATE post SET author_id = 2 WHERE id = 1') | |||||
| db.commit() | |||||
| auth.login() | |||||
| # current user can't modify other user's post | |||||
| assert client.post('/1/update').status_code == 403 | |||||
| assert client.post('/1/delete').status_code == 403 | |||||
| # current user doesn't see edit link | |||||
| assert b'href="/1/update"' not in client.get('/').data | |||||
| @pytest.mark.parametrize('path', ( | |||||
| '/2/update', | |||||
| '/2/delete', | |||||
| )) | |||||
| def test_exists_required(client, auth, path): | |||||
| auth.login() | |||||
| assert client.post(path).status_code == 404 | |||||
| def test_create(client, auth, app): | |||||
| auth.login() | |||||
| assert client.get('/create').status_code == 200 | |||||
| client.post('/create', data={'title': 'created', 'body': ''}) | |||||
| with app.app_context(): | |||||
| db = get_db() | |||||
| count = db.execute('SELECT COUNT(id) FROM post').fetchone()[0] | |||||
| assert count == 2 | |||||
| def test_update(client, auth, app): | |||||
| auth.login() | |||||
| assert client.get('/1/update').status_code == 200 | |||||
| client.post('/1/update', data={'title': 'updated', 'body': ''}) | |||||
| with app.app_context(): | |||||
| db = get_db() | |||||
| post = db.execute('SELECT * FROM post WHERE id = 1').fetchone() | |||||
| assert post['title'] == 'updated' | |||||
| @pytest.mark.parametrize('path', ( | |||||
| '/create', | |||||
| '/1/update', | |||||
| )) | |||||
| def test_create_update_validate(client, auth, path): | |||||
| auth.login() | |||||
| response = client.post(path, data={'title': '', 'body': ''}) | |||||
| assert b'Title is required.' in response.data | |||||
| def test_delete(client, auth, app): | |||||
| auth.login() | |||||
| response = client.post('/1/delete') | |||||
| assert response.headers['Location'] == 'http://localhost/' | |||||
| with app.app_context(): | |||||
| db = get_db() | |||||
| post = db.execute('SELECT * FROM post WHERE id = 1').fetchone() | |||||
| assert post is None |
| import sqlite3 | |||||
| import pytest | |||||
| from calender.db import get_db | |||||
| def test_get_close_db(app): | |||||
| with app.app_context(): | |||||
| db = get_db() | |||||
| assert db is get_db() | |||||
| with pytest.raises(sqlite3.ProgrammingError) as e: | |||||
| db.execute('SELECT 1') | |||||
| assert 'closed' in str(e.value) | |||||
| def test_init_db_command(runner, monkeypatch): | |||||
| class Recorder(object): | |||||
| called = False | |||||
| def fake_init_db(): | |||||
| Recorder.called = True | |||||
| monkeypatch.setattr('calender.db.init_db', fake_init_db) | |||||
| result = runner.invoke(args=['init-db']) | |||||
| assert 'Initialized' in result.output | |||||
| assert Recorder.called |
| from calender import create_app | |||||
| def test_config(): | |||||
| assert not create_app().testing | |||||
| assert create_app({'TESTING': True}).testing | |||||
| def test_hello(client): | |||||
| response = client.get('/hello') | |||||
| assert response.data == b'Hello, World!' |