From bbbe0d80486d2bd07691271ac34a247be3da7cf7 Mon Sep 17 00:00:00 2001 From: Anthony Sottile Date: Sun, 14 Nov 2021 20:36:32 -0800 Subject: [PATCH] improve integration tests --- src/flake8/main/application.py | 9 +++--- src/flake8/main/cli.py | 4 +-- tests/integration/test_main.py | 53 ++++++++++++++----------------- tests/integration/test_plugins.py | 30 +++++++++++++++++ 4 files changed, 61 insertions(+), 35 deletions(-) diff --git a/src/flake8/main/application.py b/src/flake8/main/application.py index 61e22a8..70165c0 100644 --- a/src/flake8/main/application.py +++ b/src/flake8/main/application.py @@ -6,6 +6,7 @@ import time from typing import Dict from typing import List from typing import Optional +from typing import Sequence from typing import Set from typing import Tuple from typing import Type @@ -96,7 +97,7 @@ class Application: self.parsed_diff: Dict[str, Set[int]] = {} def parse_preliminary_options( - self, argv: List[str] + self, argv: Sequence[str] ) -> Tuple[argparse.Namespace, List[str]]: """Get preliminary options from the CLI, pre-plugin-loading. @@ -318,7 +319,7 @@ class Application: assert self.guide is not None 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. This finds the plugins, registers their options, and parses the @@ -353,12 +354,12 @@ class Application: self.report_benchmarks() self.formatter.stop() - def _run(self, argv: List[str]) -> None: + def _run(self, argv: Sequence[str]) -> None: self.initialize(argv) self.run_checks() self.report() - def run(self, argv: List[str]) -> None: + def run(self, argv: Sequence[str]) -> None: """Run our application. This method will also handle KeyboardInterrupt exceptions for the diff --git a/src/flake8/main/cli.py b/src/flake8/main/cli.py index 6c0b1ad..8d7ea9a 100644 --- a/src/flake8/main/cli.py +++ b/src/flake8/main/cli.py @@ -1,12 +1,12 @@ """Command-line implementation of flake8.""" import sys -from typing import List from typing import Optional +from typing import Sequence 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. This handles the creation of an instance of :class:`Application`, runs it, diff --git a/tests/integration/test_main.py b/tests/integration/test_main.py index bc78c8b..27acab5 100644 --- a/tests/integration/test_main.py +++ b/tests/integration/test_main.py @@ -10,11 +10,6 @@ from flake8 import utils 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): """Ensure that `flake8 --diff` works.""" t_py_contents = """\ @@ -44,7 +39,7 @@ index d64ac39..7d943de 100644 with mock.patch.object(utils, "stdin_get_value", return_value=diff): with tmpdir.as_cwd(): tmpdir.join("t.py").write(t_py_contents) - _call_main(["--diff"], retv=1) + assert cli.main(["--diff"]) == 1 out, err = capsys.readouterr() 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) 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() assert out == expected_out assert err == "" - _call_main(["t.py"], retv=1) + assert cli.main(["t.py"]) == 1 out, err = capsys.readouterr() assert out == expected_out assert err == "" @@ -90,14 +85,14 @@ if True: with tmpdir.as_cwd(): tmpdir.join("t.py").write(t_py_contents) - _call_main(["t.py"]) + assert cli.main(["t.py"]) == 0 def test_statistics_option(tmpdir, capsys): """Ensure that `flake8 --statistics` works.""" with tmpdir.as_cwd(): 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 = """\ t.py:1:1: F401 'os' imported but unused @@ -114,7 +109,7 @@ def test_show_source_option(tmpdir, capsys): with tmpdir.as_cwd(): tmpdir.join("tox.ini").write("[flake8]\nshow_source = true\n") tmpdir.join("t.py").write("import os\n") - _call_main(["t.py"], retv=1) + assert cli.main(["t.py"]) == 1 expected = """\ t.py:1:1: F401 'os' imported but unused @@ -126,7 +121,7 @@ import os assert err == "" with tmpdir.as_cwd(): - _call_main(["t.py", "--no-show-source"], retv=1) + assert cli.main(["t.py", "--no-show-source"]) == 1 expected = """\ 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") with tmpdir.as_cwd(): - _call_main(["--extend-exclude=vendor,legacy/"], retv=1) + assert cli.main(["--extend-exclude=vendor,legacy/"]) == 1 out, err = capsys.readouterr() expected_out = """\ @@ -173,7 +168,7 @@ Configured `per-file-ignores` setting: with tmpdir.as_cwd(): tmpdir.join("setup.cfg").write(setup_cfg) - _call_main(["."], retv=1) + assert cli.main(["."]) == 1 out, err = capsys.readouterr() assert out == expected @@ -184,7 +179,7 @@ def test_tokenization_error_but_not_syntax_error(tmpdir, capsys): with tmpdir.as_cwd(): # this is a crash in the tokenizer, but not in the ast 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) 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.""" with tmpdir.as_cwd(): 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) 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): """Test that --bug-report does not crash.""" with pytest.raises(SystemExit) as excinfo: - _call_main(["--bug-report"]) + cli.main(["--bug-report"]) assert excinfo.value.args[0] == 0 out, err = capsys.readouterr() assert json.loads(out) @@ -233,7 +228,7 @@ def test_benchmark_successful(tmp_path, capsys): fname = tmp_path.joinpath("t.py") fname.write_text("print('hello world')\n") - _call_main(["--benchmark", str(fname)]) + assert cli.main(["--benchmark", str(fname)]) == 0 out, err = capsys.readouterr() 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.""" with tmpdir.as_cwd(): tmpdir.join("t.py").write("test = ('ABC' == None) # noqa: E501\n") - _call_main(["t.py"], retv=1) + assert cli.main(["t.py"]) == 1 expected = """\ t.py:1:15: E711 comparison to None should be 'if cond is None:' @@ -277,7 +272,7 @@ x = """ with tmpdir.as_cwd(): tmpdir.join("t.py").write(t_py_src) - _call_main(["t.py"], retv=0) + assert cli.main(["t.py"]) == 0 out, err = capsys.readouterr() assert out == err == "" @@ -289,7 +284,7 @@ def test_physical_line_file_not_ending_in_newline(tmpdir, capsys): with tmpdir.as_cwd(): tmpdir.join("t.py").write(t_py_src) - _call_main(["t.py"], retv=1) + assert cli.main(["t.py"]) == 1 expected = """\ 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(): tmpdir.join("t.py").write(t_py_src) - _call_main(["t.py"], retv=1) + assert cli.main(["t.py"]) == 1 expected = """\ 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): """Test that arguments are obtained from 'sys.argv'.""" - with pytest.raises(SystemExit) as excinfo: - with mock.patch("sys.argv", ["flake8", "--help"]): - _call_main(None) + with mock.patch("sys.argv", ["flake8", "--help"]): + with pytest.raises(SystemExit) as excinfo: + cli.main() assert excinfo.value.args[0] == 0 out, err = capsys.readouterr() @@ -340,7 +335,7 @@ ignore = F401 py_file = tmp_path / "t.py" 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): @@ -356,13 +351,13 @@ ignore = F401 py_file = tmp_path / "t.py" 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): """Ensure that a not-found file / directory is an error.""" with tmpdir.as_cwd(): - _call_main(["i-do-not-exist"], retv=1) + assert cli.main(["i-do-not-exist"]) == 1 out, err = capsys.readouterr() assert out.startswith("i-do-not-exist:0:1: E902") assert err == "" @@ -373,7 +368,7 @@ def test_output_file(tmpdir, capsys): tmpdir.join("t.py").write("import os\n") 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() assert out == err == "" diff --git a/tests/integration/test_plugins.py b/tests/integration/test_plugins.py index 7fff9df..dd7b9b7 100644 --- a/tests/integration/test_plugins.py +++ b/tests/integration/test_plugins.py @@ -1,5 +1,6 @@ """Integration tests for plugin loading.""" from flake8.main import application +from flake8.main.cli import main LOCAL_PLUGIN_CONFIG = "tests/fixtures/config_files/local-plugin.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["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 == ""