flake8/tests/unit/test_option_manager.py
2021-04-18 09:23:48 -07:00

389 lines
12 KiB
Python

"""Unit tests for flake.options.manager.OptionManager."""
import argparse
import os
from unittest import mock
import pytest
from flake8 import utils
from flake8.main.options import JobsArgument
from flake8.options import manager
TEST_VERSION = "3.0.0b1"
@pytest.fixture
def optmanager():
"""Generate a simple OptionManager with default test arguments."""
return manager.OptionManager(prog="flake8", version=TEST_VERSION)
def test_option_manager_creates_option_parser(optmanager):
"""Verify that a new manager creates a new parser."""
assert isinstance(optmanager.parser, argparse.ArgumentParser)
def test_option_manager_including_parent_options():
"""Verify parent options are included in the parsed options."""
# GIVEN
parent_parser = argparse.ArgumentParser(add_help=False)
parent_parser.add_argument("--parent")
# WHEN
optmanager = manager.OptionManager(
prog="flake8", version=TEST_VERSION, parents=[parent_parser]
)
option, _ = optmanager.parse_args(["--parent", "foo"])
# THEN
assert option.parent == "foo"
def test_parse_args_forwarding_default_values(optmanager):
"""Verify default provided values are present in the final result."""
namespace = argparse.Namespace(foo="bar")
options, args = optmanager.parse_args([], namespace)
assert options.foo == "bar"
def test_parse_args_forwarding_type_coercion(optmanager):
"""Verify default provided values are type converted from add_option."""
optmanager.add_option("--foo", type=int)
namespace = argparse.Namespace(foo="5")
options, args = optmanager.parse_args([], namespace)
assert options.foo == 5
def test_add_option_short_option_only(optmanager):
"""Verify the behaviour of adding a short-option only."""
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option("-s", help="Test short opt")
assert optmanager.options[0].short_option_name == "-s"
def test_add_option_long_option_only(optmanager):
"""Verify the behaviour of adding a long-option only."""
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option("--long", help="Test long opt")
assert optmanager.options[0].short_option_name is manager._ARG.NO
assert optmanager.options[0].long_option_name == "--long"
def test_add_short_and_long_option_names(optmanager):
"""Verify the behaviour of using both short and long option names."""
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option("-b", "--both", help="Test both opts")
assert optmanager.options[0].short_option_name == "-b"
assert optmanager.options[0].long_option_name == "--both"
def test_add_option_with_custom_args(optmanager):
"""Verify that add_option handles custom Flake8 parameters."""
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option("--parse", parse_from_config=True)
optmanager.add_option("--commas", comma_separated_list=True)
optmanager.add_option("--files", normalize_paths=True)
attrs = ["parse_from_config", "comma_separated_list", "normalize_paths"]
for option, attr in zip(optmanager.options, attrs):
assert getattr(option, attr) is True
def test_parse_args_normalize_path(optmanager):
"""Show that parse_args handles path normalization."""
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option("--config", normalize_paths=True)
options, args = optmanager.parse_args(["--config", "../config.ini"])
assert options.config == os.path.abspath("../config.ini")
def test_parse_args_handles_comma_separated_defaults(optmanager):
"""Show that parse_args handles defaults that are comma-separated."""
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option(
"--exclude", default="E123,W234", comma_separated_list=True
)
options, args = optmanager.parse_args([])
assert options.exclude == ["E123", "W234"]
def test_parse_args_handles_comma_separated_lists(optmanager):
"""Show that parse_args handles user-specified comma-separated lists."""
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option(
"--exclude", default="E123,W234", comma_separated_list=True
)
options, args = optmanager.parse_args(["--exclude", "E201,W111,F280"])
assert options.exclude == ["E201", "W111", "F280"]
def test_parse_args_normalize_paths(optmanager):
"""Verify parse_args normalizes a comma-separated list of paths."""
assert optmanager.options == []
assert optmanager.config_options_dict == {}
optmanager.add_option(
"--extra-config", normalize_paths=True, comma_separated_list=True
)
options, args = optmanager.parse_args(
["--extra-config", "../config.ini,tox.ini,flake8/some-other.cfg"]
)
assert options.extra_config == [
os.path.abspath("../config.ini"),
"tox.ini",
os.path.abspath("flake8/some-other.cfg"),
]
def test_generate_versions(optmanager):
"""Verify a comma-separated string is generated of registered plugins."""
optmanager.registered_plugins = [
manager.PluginVersion("Testing 100", "0.0.0", False),
manager.PluginVersion("Testing 101", "0.0.0", False),
manager.PluginVersion("Testing 300", "0.0.0", True),
]
assert (
optmanager.generate_versions()
== "Testing 100: 0.0.0, Testing 101: 0.0.0, Testing 300: 0.0.0"
)
def test_plugins_are_sorted_in_generate_versions(optmanager):
"""Verify we sort before joining strings in generate_versions."""
optmanager.registered_plugins = [
manager.PluginVersion("pyflakes", "1.5.0", False),
manager.PluginVersion("mccabe", "0.7.0", False),
manager.PluginVersion("pycodestyle", "2.2.0", False),
manager.PluginVersion("flake8-docstrings", "0.6.1", False),
manager.PluginVersion("flake8-bugbear", "2016.12.1", False),
]
assert (
optmanager.generate_versions() == "flake8-bugbear: 2016.12.1, "
"flake8-docstrings: 0.6.1, "
"mccabe: 0.7.0, "
"pycodestyle: 2.2.0, "
"pyflakes: 1.5.0"
)
def test_generate_versions_with_format_string(optmanager):
"""Verify a comma-separated string is generated of registered plugins."""
optmanager.registered_plugins.update(
[
manager.PluginVersion("Testing", "0.0.0", False),
manager.PluginVersion("Testing", "0.0.0", False),
manager.PluginVersion("Testing", "0.0.0", False),
]
)
assert optmanager.generate_versions() == "Testing: 0.0.0"
def test_update_version_string(optmanager):
"""Verify we update the version string idempotently."""
assert optmanager.version == TEST_VERSION
assert optmanager.version_action.version == TEST_VERSION
optmanager.registered_plugins = [
manager.PluginVersion("Testing 100", "0.0.0", False),
manager.PluginVersion("Testing 101", "0.0.0", False),
manager.PluginVersion("Testing 300", "0.0.0", False),
]
optmanager.update_version_string()
assert optmanager.version == TEST_VERSION
assert (
optmanager.version_action.version
== TEST_VERSION
+ " (Testing 100: 0.0.0, Testing 101: 0.0.0, Testing 300: 0.0.0) "
+ utils.get_python_version()
)
def test_generate_epilog(optmanager):
"""Verify how we generate the epilog for help text."""
assert optmanager.parser.epilog is None
optmanager.registered_plugins = [
manager.PluginVersion("Testing 100", "0.0.0", False),
manager.PluginVersion("Testing 101", "0.0.0", False),
manager.PluginVersion("Testing 300", "0.0.0", False),
]
expected_value = (
"Installed plugins: Testing 100: 0.0.0, Testing 101: 0.0.0, Testing"
" 300: 0.0.0"
)
optmanager.generate_epilog()
assert optmanager.parser.epilog == expected_value
def test_extend_default_ignore(optmanager):
"""Verify that we update the extended default ignore list."""
assert optmanager.extended_default_ignore == set()
optmanager.extend_default_ignore(["T100", "T101", "T102"])
assert optmanager.extended_default_ignore == {"T100", "T101", "T102"}
def test_parse_known_args(optmanager):
"""Verify we ignore unknown options."""
with mock.patch("sys.exit") as sysexit:
optmanager.parse_known_args(["--max-complexity", "5"])
assert sysexit.called is False
def test_optparse_normalize_callback_option_legacy(optmanager):
"""Test the optparse shim for `callback=`."""
callback_foo = mock.Mock()
optmanager.add_option(
"--foo",
action="callback",
callback=callback_foo,
callback_args=(1, 2),
callback_kwargs={"a": "b"},
)
callback_bar = mock.Mock()
optmanager.add_option(
"--bar",
action="callback",
type="string",
callback=callback_bar,
)
callback_baz = mock.Mock()
optmanager.add_option(
"--baz",
action="callback",
type="string",
nargs=2,
callback=callback_baz,
)
optmanager.parse_args(["--foo", "--bar", "bararg", "--baz", "1", "2"])
callback_foo.assert_called_once_with(
mock.ANY, # the option / action instance
"--foo",
None,
mock.ANY, # the OptionParser / ArgumentParser
1,
2,
a="b",
)
callback_bar.assert_called_once_with(
mock.ANY, # the option / action instance
"--bar",
"bararg",
mock.ANY, # the OptionParser / ArgumentParser
)
callback_baz.assert_called_once_with(
mock.ANY, # the option / action instance
"--baz",
("1", "2"),
mock.ANY, # the OptionParser / ArgumentParser
)
@pytest.mark.parametrize(
("type_s", "input_val", "expected"),
(
("int", "5", 5),
("long", "6", 6),
("string", "foo", "foo"),
("float", "1.5", 1.5),
("complex", "1+5j", 1 + 5j),
# optparse allows this but does not document it
("str", "foo", "foo"),
),
)
def test_optparse_normalize_types(optmanager, type_s, input_val, expected):
"""Test the optparse shim for type="typename"."""
optmanager.add_option("--foo", type=type_s)
opts, args = optmanager.parse_args(["--foo", input_val])
assert opts.foo == expected
def test_optparse_normalize_choice_type(optmanager):
"""Test the optparse shim for type="choice"."""
optmanager.add_option("--foo", type="choice", choices=("1", "2", "3"))
opts, args = optmanager.parse_args(["--foo", "1"])
assert opts.foo == "1"
# fails to parse
with pytest.raises(SystemExit):
optmanager.parse_args(["--foo", "4"])
def test_optparse_normalize_help(optmanager, capsys):
"""Test the optparse shim for %default in help text."""
optmanager.add_option("--foo", default="bar", help="default: %default")
with pytest.raises(SystemExit):
optmanager.parse_args(["--help"])
out, err = capsys.readouterr()
output = out + err
assert "default: bar" in output
def test_optmanager_group(optmanager, capsys):
"""Test that group(...) causes options to be assigned to a group."""
with optmanager.group("groupname"):
optmanager.add_option("--foo")
with pytest.raises(SystemExit):
optmanager.parse_args(["--help"])
out, err = capsys.readouterr()
output = out + err
assert "\ngroupname:\n" in output
@pytest.mark.parametrize(
("s", "is_auto", "n_jobs"),
(
("auto", True, -1),
("4", False, 4),
),
)
def test_parse_valid_jobs_argument(s, is_auto, n_jobs):
"""Test that --jobs properly parses valid arguments."""
jobs_opt = JobsArgument(s)
assert is_auto == jobs_opt.is_auto
assert n_jobs == jobs_opt.n_jobs
def test_parse_invalid_jobs_argument(optmanager, capsys):
"""Test that --jobs properly rejects invalid arguments."""
namespace = argparse.Namespace()
optmanager.add_option("--jobs", type=JobsArgument)
with pytest.raises(SystemExit):
optmanager.parse_args(["--jobs=foo"], namespace)
out, err = capsys.readouterr()
output = out + err
expected = (
"\nflake8: error: argument --jobs: "
"'foo' must be 'auto' or an integer.\n"
)
assert expected in output
def test_jobs_argument_str():
"""Test that JobsArgument has a correct __str__."""
assert str(JobsArgument("auto")) == "auto"
assert str(JobsArgument("123")) == "123"