flask/tests/test_cli.py
David Lord 7ad79583b9
add sort by match order
sort by endpoint by default
combine sort flags
sort methods
ignore HEAD and OPTIONS methods by default
rearrange columns
use format to build row format string
rework tests
add changelog
2017-04-26 10:26:59 -07:00

270 lines
7.9 KiB
Python

# -*- coding: utf-8 -*-
"""
tests.test_cli
~~~~~~~~~~~~~~
:copyright: (c) 2016 by the Flask Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
#
# This file was part of Flask-CLI and was modified under the terms its license,
# the Revised BSD License.
# Copyright (C) 2015 CERN.
#
from __future__ import absolute_import, print_function
import os
import sys
from functools import partial
import click
import pytest
from click.testing import CliRunner
from flask import Flask, current_app
from flask.cli import cli, AppGroup, FlaskGroup, NoAppException, ScriptInfo, \
find_best_app, locate_app, with_appcontext, prepare_exec_for_file, \
find_default_import_path, get_version
@pytest.fixture
def runner():
return CliRunner()
def test_cli_name(test_apps):
"""Make sure the CLI object's name is the app's name and not the app itself"""
from cliapp.app import testapp
assert testapp.cli.name == testapp.name
def test_find_best_app(test_apps):
"""Test if `find_best_app` behaves as expected with different combinations of input."""
class Module:
app = Flask('appname')
assert find_best_app(Module) == Module.app
class Module:
application = Flask('appname')
assert find_best_app(Module) == Module.application
class Module:
myapp = Flask('appname')
assert find_best_app(Module) == Module.myapp
class Module:
pass
pytest.raises(NoAppException, find_best_app, Module)
class Module:
myapp1 = Flask('appname1')
myapp2 = Flask('appname2')
pytest.raises(NoAppException, find_best_app, Module)
def test_prepare_exec_for_file(test_apps):
"""Expect the correct path to be set and the correct module name to be returned.
:func:`prepare_exec_for_file` has a side effect, where
the parent directory of given file is added to `sys.path`.
"""
realpath = os.path.realpath('/tmp/share/test.py')
dirname = os.path.dirname(realpath)
assert prepare_exec_for_file('/tmp/share/test.py') == 'test'
assert dirname in sys.path
realpath = os.path.realpath('/tmp/share/__init__.py')
dirname = os.path.dirname(os.path.dirname(realpath))
assert prepare_exec_for_file('/tmp/share/__init__.py') == 'share'
assert dirname in sys.path
with pytest.raises(NoAppException):
prepare_exec_for_file('/tmp/share/test.txt')
def test_locate_app(test_apps):
"""Test of locate_app."""
assert locate_app("cliapp.app").name == "testapp"
assert locate_app("cliapp.app:testapp").name == "testapp"
assert locate_app("cliapp.multiapp:app1").name == "app1"
pytest.raises(NoAppException, locate_app, "notanpp.py")
pytest.raises(NoAppException, locate_app, "cliapp/app")
pytest.raises(RuntimeError, locate_app, "cliapp.app:notanapp")
pytest.raises(NoAppException, locate_app, "cliapp.importerrorapp")
def test_find_default_import_path(test_apps, monkeypatch, tmpdir):
"""Test of find_default_import_path."""
monkeypatch.delitem(os.environ, 'FLASK_APP', raising=False)
assert find_default_import_path() == None
monkeypatch.setitem(os.environ, 'FLASK_APP', 'notanapp')
assert find_default_import_path() == 'notanapp'
tmpfile = tmpdir.join('testapp.py')
tmpfile.write('')
monkeypatch.setitem(os.environ, 'FLASK_APP', str(tmpfile))
expect_rv = prepare_exec_for_file(str(tmpfile))
assert find_default_import_path() == expect_rv
def test_get_version(test_apps, capsys):
"""Test of get_version."""
from flask import __version__ as flask_ver
from sys import version as py_ver
class MockCtx(object):
resilient_parsing = False
color = None
def exit(self): return
ctx = MockCtx()
get_version(ctx, None, "test")
out, err = capsys.readouterr()
assert flask_ver in out
assert py_ver in out
def test_scriptinfo(test_apps):
"""Test of ScriptInfo."""
obj = ScriptInfo(app_import_path="cliapp.app:testapp")
assert obj.load_app().name == "testapp"
assert obj.load_app().name == "testapp"
def create_app(info):
return Flask("createapp")
obj = ScriptInfo(create_app=create_app)
app = obj.load_app()
assert app.name == "createapp"
assert obj.load_app() == app
def test_with_appcontext(runner):
"""Test of with_appcontext."""
@click.command()
@with_appcontext
def testcmd():
click.echo(current_app.name)
obj = ScriptInfo(create_app=lambda info: Flask("testapp"))
result = runner.invoke(testcmd, obj=obj)
assert result.exit_code == 0
assert result.output == 'testapp\n'
def test_appgroup(runner):
"""Test of with_appcontext."""
@click.group(cls=AppGroup)
def cli():
pass
@cli.command(with_appcontext=True)
def test():
click.echo(current_app.name)
@cli.group()
def subgroup():
pass
@subgroup.command(with_appcontext=True)
def test2():
click.echo(current_app.name)
obj = ScriptInfo(create_app=lambda info: Flask("testappgroup"))
result = runner.invoke(cli, ['test'], obj=obj)
assert result.exit_code == 0
assert result.output == 'testappgroup\n'
result = runner.invoke(cli, ['subgroup', 'test2'], obj=obj)
assert result.exit_code == 0
assert result.output == 'testappgroup\n'
def test_flaskgroup(runner):
"""Test FlaskGroup."""
def create_app(info):
return Flask("flaskgroup")
@click.group(cls=FlaskGroup, create_app=create_app)
def cli(**params):
pass
@cli.command()
def test():
click.echo(current_app.name)
result = runner.invoke(cli, ['test'])
assert result.exit_code == 0
assert result.output == 'flaskgroup\n'
def test_print_exceptions(runner):
"""Print the stacktrace if the CLI."""
def create_app(info):
raise Exception("oh no")
return Flask("flaskgroup")
@click.group(cls=FlaskGroup, create_app=create_app)
def cli(**params):
pass
result = runner.invoke(cli, ['--help'])
assert result.exit_code == 0
assert 'Exception: oh no' in result.output
assert 'Traceback' in result.output
class TestRoutes:
@pytest.fixture
def invoke(self, runner):
def create_app(info):
app = Flask(__name__)
app.testing = True
@app.route('/get_post/<int:x>/<int:y>', methods=['GET', 'POST'])
def yyy_get_post(x, y):
pass
@app.route('/zzz_post', methods=['POST'])
def aaa_post():
pass
return app
cli = FlaskGroup(create_app=create_app)
return partial(runner.invoke, cli)
def expect_order(self, order, output):
# skip the header and match the start of each row
for expect, line in zip(order, output.splitlines()[2:]):
# do this instead of startswith for nicer pytest output
assert line[:len(expect)] == expect
def test_simple(self, invoke):
result = invoke(['routes'])
assert result.exit_code == 0
self.expect_order(
['aaa_post', 'static', 'yyy_get_post'],
result.output
)
def test_sort(self, invoke):
default_output = invoke(['routes']).output
endpoint_output = invoke(['routes', '-s', 'endpoint']).output
assert default_output == endpoint_output
self.expect_order(
['static', 'yyy_get_post', 'aaa_post'],
invoke(['routes', '-s', 'methods']).output
)
self.expect_order(
['yyy_get_post', 'static', 'aaa_post'],
invoke(['routes', '-s', 'rule']).output
)
self.expect_order(
['aaa_post', 'yyy_get_post', 'static'],
invoke(['routes', '-s', 'match']).output
)
def test_all_methods(self, invoke):
output = invoke(['routes']).output
assert 'GET, HEAD, OPTIONS, POST' not in output
output = invoke(['routes', '--all-methods']).output
assert 'GET, HEAD, OPTIONS, POST' in output