improve integration tests

This commit is contained in:
Anthony Sottile 2021-11-14 20:36:32 -08:00
parent a7de34a90e
commit bbbe0d8048
4 changed files with 61 additions and 35 deletions

View file

@ -6,6 +6,7 @@ import time
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Sequence
from typing import Set from typing import Set
from typing import Tuple from typing import Tuple
from typing import Type from typing import Type
@ -96,7 +97,7 @@ class Application:
self.parsed_diff: Dict[str, Set[int]] = {} self.parsed_diff: Dict[str, Set[int]] = {}
def parse_preliminary_options( def parse_preliminary_options(
self, argv: List[str] self, argv: Sequence[str]
) -> Tuple[argparse.Namespace, List[str]]: ) -> Tuple[argparse.Namespace, List[str]]:
"""Get preliminary options from the CLI, pre-plugin-loading. """Get preliminary options from the CLI, pre-plugin-loading.
@ -318,7 +319,7 @@ class Application:
assert self.guide is not None assert self.guide is not None
self.formatter.show_statistics(self.guide.stats) self.formatter.show_statistics(self.guide.stats)
def initialize(self, argv: List[str]) -> None: def initialize(self, argv: Sequence[str]) -> None:
"""Initialize the application to be run. """Initialize the application to be run.
This finds the plugins, registers their options, and parses the This finds the plugins, registers their options, and parses the
@ -353,12 +354,12 @@ class Application:
self.report_benchmarks() self.report_benchmarks()
self.formatter.stop() self.formatter.stop()
def _run(self, argv: List[str]) -> None: def _run(self, argv: Sequence[str]) -> None:
self.initialize(argv) self.initialize(argv)
self.run_checks() self.run_checks()
self.report() self.report()
def run(self, argv: List[str]) -> None: def run(self, argv: Sequence[str]) -> None:
"""Run our application. """Run our application.
This method will also handle KeyboardInterrupt exceptions for the This method will also handle KeyboardInterrupt exceptions for the

View file

@ -1,12 +1,12 @@
"""Command-line implementation of flake8.""" """Command-line implementation of flake8."""
import sys import sys
from typing import List
from typing import Optional from typing import Optional
from typing import Sequence
from flake8.main import application from flake8.main import application
def main(argv: Optional[List[str]] = None) -> int: def main(argv: Optional[Sequence[str]] = None) -> int:
"""Execute the main bit of the application. """Execute the main bit of the application.
This handles the creation of an instance of :class:`Application`, runs it, This handles the creation of an instance of :class:`Application`, runs it,

View file

@ -10,11 +10,6 @@ from flake8 import utils
from flake8.main import cli from flake8.main import cli
def _call_main(argv, retv=0):
exit_code = cli.main(argv)
assert exit_code == retv
def test_diff_option(tmpdir, capsys): def test_diff_option(tmpdir, capsys):
"""Ensure that `flake8 --diff` works.""" """Ensure that `flake8 --diff` works."""
t_py_contents = """\ t_py_contents = """\
@ -44,7 +39,7 @@ index d64ac39..7d943de 100644
with mock.patch.object(utils, "stdin_get_value", return_value=diff): with mock.patch.object(utils, "stdin_get_value", return_value=diff):
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("t.py").write(t_py_contents) tmpdir.join("t.py").write(t_py_contents)
_call_main(["--diff"], retv=1) assert cli.main(["--diff"]) == 1
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == "t.py:8:1: F821 undefined name 'y'\n" assert out == "t.py:8:1: F821 undefined name 'y'\n"
@ -63,12 +58,12 @@ t.py:3:2: E225 missing whitespace around operator
tmpdir.join("t.py").write(src) tmpdir.join("t.py").write(src)
with mock.patch.object(utils, "stdin_get_value", return_value=src): with mock.patch.object(utils, "stdin_get_value", return_value=src):
_call_main(["-", "--stdin-display-name=t.py"], retv=1) assert cli.main(["-", "--stdin-display-name=t.py"]) == 1
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == expected_out assert out == expected_out
assert err == "" assert err == ""
_call_main(["t.py"], retv=1) assert cli.main(["t.py"]) == 1
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == expected_out assert out == expected_out
assert err == "" assert err == ""
@ -90,14 +85,14 @@ if True:
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("t.py").write(t_py_contents) tmpdir.join("t.py").write(t_py_contents)
_call_main(["t.py"]) assert cli.main(["t.py"]) == 0
def test_statistics_option(tmpdir, capsys): def test_statistics_option(tmpdir, capsys):
"""Ensure that `flake8 --statistics` works.""" """Ensure that `flake8 --statistics` works."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("t.py").write("import os\nimport sys\n") tmpdir.join("t.py").write("import os\nimport sys\n")
_call_main(["--statistics", "t.py"], retv=1) assert cli.main(["--statistics", "t.py"]) == 1
expected = """\ expected = """\
t.py:1:1: F401 'os' imported but unused t.py:1:1: F401 'os' imported but unused
@ -114,7 +109,7 @@ def test_show_source_option(tmpdir, capsys):
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("tox.ini").write("[flake8]\nshow_source = true\n") tmpdir.join("tox.ini").write("[flake8]\nshow_source = true\n")
tmpdir.join("t.py").write("import os\n") tmpdir.join("t.py").write("import os\n")
_call_main(["t.py"], retv=1) assert cli.main(["t.py"]) == 1
expected = """\ expected = """\
t.py:1:1: F401 'os' imported but unused t.py:1:1: F401 'os' imported but unused
@ -126,7 +121,7 @@ import os
assert err == "" assert err == ""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
_call_main(["t.py", "--no-show-source"], retv=1) assert cli.main(["t.py", "--no-show-source"]) == 1
expected = """\ expected = """\
t.py:1:1: F401 'os' imported but unused t.py:1:1: F401 'os' imported but unused
@ -142,7 +137,7 @@ def test_extend_exclude(tmpdir, capsys):
tmpdir.mkdir(d).join("t.py").write("import os\nimport sys\n") tmpdir.mkdir(d).join("t.py").write("import os\nimport sys\n")
with tmpdir.as_cwd(): with tmpdir.as_cwd():
_call_main(["--extend-exclude=vendor,legacy/"], retv=1) assert cli.main(["--extend-exclude=vendor,legacy/"]) == 1
out, err = capsys.readouterr() out, err = capsys.readouterr()
expected_out = """\ expected_out = """\
@ -173,7 +168,7 @@ Configured `per-file-ignores` setting:
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("setup.cfg").write(setup_cfg) tmpdir.join("setup.cfg").write(setup_cfg)
_call_main(["."], retv=1) assert cli.main(["."]) == 1
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == expected assert out == expected
@ -184,7 +179,7 @@ def test_tokenization_error_but_not_syntax_error(tmpdir, capsys):
with tmpdir.as_cwd(): with tmpdir.as_cwd():
# this is a crash in the tokenizer, but not in the ast # this is a crash in the tokenizer, but not in the ast
tmpdir.join("t.py").write("b'foo' \\\n") tmpdir.join("t.py").write("b'foo' \\\n")
_call_main(["t.py"], retv=1) assert cli.main(["t.py"]) == 1
if hasattr(sys, "pypy_version_info"): # pragma: no cover (pypy) if hasattr(sys, "pypy_version_info"): # pragma: no cover (pypy)
expected = "t.py:2:1: E999 SyntaxError: end of file (EOF) in multi-line statement\n" # noqa: E501 expected = "t.py:2:1: E999 SyntaxError: end of file (EOF) in multi-line statement\n" # noqa: E501
@ -204,7 +199,7 @@ def test_tokenization_error_is_a_syntax_error(tmpdir, capsys):
"""Test when tokenize raises a SyntaxError.""" """Test when tokenize raises a SyntaxError."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("t.py").write("if True:\n pass\n pass\n") tmpdir.join("t.py").write("if True:\n pass\n pass\n")
_call_main(["t.py"], retv=1) assert cli.main(["t.py"]) == 1
if hasattr(sys, "pypy_version_info"): # pragma: no cover (pypy) if hasattr(sys, "pypy_version_info"): # pragma: no cover (pypy)
expected = "t.py:3:2: E999 IndentationError: unindent does not match any outer indentation level\n" # noqa: E501 expected = "t.py:3:2: E999 IndentationError: unindent does not match any outer indentation level\n" # noqa: E501
@ -221,7 +216,7 @@ def test_tokenization_error_is_a_syntax_error(tmpdir, capsys):
def test_bug_report_successful(capsys): def test_bug_report_successful(capsys):
"""Test that --bug-report does not crash.""" """Test that --bug-report does not crash."""
with pytest.raises(SystemExit) as excinfo: with pytest.raises(SystemExit) as excinfo:
_call_main(["--bug-report"]) cli.main(["--bug-report"])
assert excinfo.value.args[0] == 0 assert excinfo.value.args[0] == 0
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert json.loads(out) assert json.loads(out)
@ -233,7 +228,7 @@ def test_benchmark_successful(tmp_path, capsys):
fname = tmp_path.joinpath("t.py") fname = tmp_path.joinpath("t.py")
fname.write_text("print('hello world')\n") fname.write_text("print('hello world')\n")
_call_main(["--benchmark", str(fname)]) assert cli.main(["--benchmark", str(fname)]) == 0
out, err = capsys.readouterr() out, err = capsys.readouterr()
parts = [line.split(maxsplit=1) for line in out.splitlines()] parts = [line.split(maxsplit=1) for line in out.splitlines()]
@ -255,7 +250,7 @@ def test_specific_noqa_does_not_clobber_pycodestyle_noqa(tmpdir, capsys):
"""See https://github.com/pycqa/flake8/issues/1104.""" """See https://github.com/pycqa/flake8/issues/1104."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("t.py").write("test = ('ABC' == None) # noqa: E501\n") tmpdir.join("t.py").write("test = ('ABC' == None) # noqa: E501\n")
_call_main(["t.py"], retv=1) assert cli.main(["t.py"]) == 1
expected = """\ expected = """\
t.py:1:15: E711 comparison to None should be 'if cond is None:' t.py:1:15: E711 comparison to None should be 'if cond is None:'
@ -277,7 +272,7 @@ x = """
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("t.py").write(t_py_src) tmpdir.join("t.py").write(t_py_src)
_call_main(["t.py"], retv=0) assert cli.main(["t.py"]) == 0
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == err == "" assert out == err == ""
@ -289,7 +284,7 @@ def test_physical_line_file_not_ending_in_newline(tmpdir, capsys):
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("t.py").write(t_py_src) tmpdir.join("t.py").write(t_py_src)
_call_main(["t.py"], retv=1) assert cli.main(["t.py"]) == 1
expected = """\ expected = """\
t.py:2:1: W191 indentation contains tabs t.py:2:1: W191 indentation contains tabs
@ -305,7 +300,7 @@ def test_physical_line_file_not_ending_in_newline_trailing_ws(tmpdir, capsys):
with tmpdir.as_cwd(): with tmpdir.as_cwd():
tmpdir.join("t.py").write(t_py_src) tmpdir.join("t.py").write(t_py_src)
_call_main(["t.py"], retv=1) assert cli.main(["t.py"]) == 1
expected = """\ expected = """\
t.py:1:6: W291 trailing whitespace t.py:1:6: W291 trailing whitespace
@ -317,9 +312,9 @@ t.py:1:9: W292 no newline at end of file
def test_obtaining_args_from_sys_argv_when_not_explicity_provided(capsys): def test_obtaining_args_from_sys_argv_when_not_explicity_provided(capsys):
"""Test that arguments are obtained from 'sys.argv'.""" """Test that arguments are obtained from 'sys.argv'."""
with pytest.raises(SystemExit) as excinfo: with mock.patch("sys.argv", ["flake8", "--help"]):
with mock.patch("sys.argv", ["flake8", "--help"]): with pytest.raises(SystemExit) as excinfo:
_call_main(None) cli.main()
assert excinfo.value.args[0] == 0 assert excinfo.value.args[0] == 0
out, err = capsys.readouterr() out, err = capsys.readouterr()
@ -340,7 +335,7 @@ ignore = F401
py_file = tmp_path / "t.py" py_file = tmp_path / "t.py"
py_file.write_text("import os\n") py_file.write_text("import os\n")
_call_main(["--config", str(config), str(py_file)]) assert cli.main(["--config", str(config), str(py_file)]) == 0
def test_cli_isolated_overrides_config_option(tmp_path): def test_cli_isolated_overrides_config_option(tmp_path):
@ -356,13 +351,13 @@ ignore = F401
py_file = tmp_path / "t.py" py_file = tmp_path / "t.py"
py_file.write_text("import os\n") py_file.write_text("import os\n")
_call_main(["--isolated", "--config", str(config), str(py_file)], retv=1) assert cli.main(["--isolated", "--config", str(config), str(py_file)]) == 1
def test_file_not_found(tmpdir, capsys): def test_file_not_found(tmpdir, capsys):
"""Ensure that a not-found file / directory is an error.""" """Ensure that a not-found file / directory is an error."""
with tmpdir.as_cwd(): with tmpdir.as_cwd():
_call_main(["i-do-not-exist"], retv=1) assert cli.main(["i-do-not-exist"]) == 1
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out.startswith("i-do-not-exist:0:1: E902") assert out.startswith("i-do-not-exist:0:1: E902")
assert err == "" assert err == ""
@ -373,7 +368,7 @@ def test_output_file(tmpdir, capsys):
tmpdir.join("t.py").write("import os\n") tmpdir.join("t.py").write("import os\n")
with tmpdir.as_cwd(): with tmpdir.as_cwd():
_call_main(["t.py", "--output-file=a/b/f"], retv=1) assert cli.main(["t.py", "--output-file=a/b/f"]) == 1
out, err = capsys.readouterr() out, err = capsys.readouterr()
assert out == err == "" assert out == err == ""

View file

@ -1,5 +1,6 @@
"""Integration tests for plugin loading.""" """Integration tests for plugin loading."""
from flake8.main import application from flake8.main import application
from flake8.main.cli import main
LOCAL_PLUGIN_CONFIG = "tests/fixtures/config_files/local-plugin.ini" LOCAL_PLUGIN_CONFIG = "tests/fixtures/config_files/local-plugin.ini"
LOCAL_PLUGIN_PATH_CONFIG = "tests/fixtures/config_files/local-plugin-path.ini" LOCAL_PLUGIN_PATH_CONFIG = "tests/fixtures/config_files/local-plugin-path.ini"
@ -65,3 +66,32 @@ def test_enable_local_plugin_at_non_installed_path():
assert app.check_plugins is not None assert app.check_plugins is not None
assert app.check_plugins["XE"].plugin.name == "ExtensionTestPlugin2" assert app.check_plugins["XE"].plugin.name == "ExtensionTestPlugin2"
class AlwaysErrors:
name = "AlwaysError"
version = "1"
def __init__(self, tree):
pass
def run(self):
yield 1, 0, "ABC123 error", type(self)
def test_plugin_gets_enabled_by_default(tmp_path, capsys):
cfg_s = f"""\
[flake8:local-plugins]
extension =
ABC = {AlwaysErrors.__module__}:{AlwaysErrors.__name__}
"""
cfg = tmp_path.joinpath("tox.ini")
cfg.write_text(cfg_s)
t_py = tmp_path.joinpath("t.py")
t_py.touch()
assert main((str(t_py), "--config", str(cfg))) == 1
out, err = capsys.readouterr()
assert out == f"{t_py}:1:1: ABC123 error\n"
assert err == ""