2021-11-06 15:36:51 +01:00
|
|
|
# pylint: disable=redefined-outer-name,missing-function-docstring,protected-access,global-statement
|
2023-01-06 22:13:28 +01:00
|
|
|
# pylint: disable=global-variable-not-assigned
|
2021-11-06 15:36:51 +01:00
|
|
|
""" Tests on config lib """
|
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
import configparser
|
2023-01-06 18:18:55 +01:00
|
|
|
import logging
|
2023-01-09 13:33:14 +01:00
|
|
|
import os
|
|
|
|
|
|
|
|
import pytest
|
2023-01-06 18:18:55 +01:00
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
from mylib.config import BooleanOption, Config, ConfigSection, StringOption
|
2021-11-06 15:36:51 +01:00
|
|
|
|
2024-03-15 09:52:23 +01:00
|
|
|
tested = {}
|
2021-11-06 15:36:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_config_init_default_args():
|
2023-01-16 12:56:12 +01:00
|
|
|
appname = "Test app"
|
2021-11-06 15:36:51 +01:00
|
|
|
config = Config(appname)
|
|
|
|
assert config.appname == appname
|
2023-01-16 12:56:12 +01:00
|
|
|
assert config.version == "0.0"
|
|
|
|
assert config.encoding == "utf-8"
|
2021-11-06 15:36:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_config_init_custom_args():
|
2023-01-16 12:56:12 +01:00
|
|
|
appname = "Test app"
|
|
|
|
version = "1.43"
|
|
|
|
encoding = "ISO-8859-1"
|
2021-11-06 15:36:51 +01:00
|
|
|
config = Config(appname, version=version, encoding=encoding)
|
|
|
|
assert config.appname == appname
|
|
|
|
assert config.version == version
|
|
|
|
assert config.encoding == encoding
|
|
|
|
|
|
|
|
|
|
|
|
def test_add_section_default_args():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
name = "test_section"
|
2021-11-06 15:36:51 +01:00
|
|
|
section = config.add_section(name)
|
|
|
|
assert isinstance(section, ConfigSection)
|
|
|
|
assert config.sections[name] == section
|
|
|
|
assert section.name == name
|
|
|
|
assert section.comment is None
|
|
|
|
assert section.order == 10
|
|
|
|
|
|
|
|
|
|
|
|
def test_add_section_custom_args():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
name = "test_section"
|
|
|
|
comment = "Test"
|
2021-11-06 15:36:51 +01:00
|
|
|
order = 20
|
|
|
|
section = config.add_section(name, comment=comment, order=order)
|
|
|
|
assert isinstance(section, ConfigSection)
|
|
|
|
assert section.name == name
|
|
|
|
assert section.comment == comment
|
|
|
|
assert section.order == order
|
|
|
|
|
|
|
|
|
|
|
|
def test_add_section_with_callback():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
name = "test_section"
|
2021-11-06 15:36:51 +01:00
|
|
|
|
2024-03-15 09:52:23 +01:00
|
|
|
global tested
|
|
|
|
tested["test_add_section_with_callback"] = False
|
2021-11-06 15:36:51 +01:00
|
|
|
|
|
|
|
def test_callback(loaded_config):
|
2024-03-15 09:52:23 +01:00
|
|
|
global tested
|
2021-11-06 15:36:51 +01:00
|
|
|
assert loaded_config == config
|
2024-03-15 09:52:23 +01:00
|
|
|
assert tested["test_add_section_with_callback"] is False
|
|
|
|
tested["test_add_section_with_callback"] = True
|
2021-11-06 15:36:51 +01:00
|
|
|
|
|
|
|
section = config.add_section(name, loaded_callback=test_callback)
|
|
|
|
assert isinstance(section, ConfigSection)
|
|
|
|
assert test_callback in config._loaded_callbacks
|
2024-03-15 09:52:23 +01:00
|
|
|
assert tested["test_add_section_with_callback"] is False
|
2021-11-06 15:36:51 +01:00
|
|
|
|
|
|
|
config.parse_arguments_options(argv=[], create=False)
|
2024-03-15 09:52:23 +01:00
|
|
|
assert tested["test_add_section_with_callback"] is True
|
2021-11-06 15:36:51 +01:00
|
|
|
assert test_callback in config._loaded_callbacks_executed
|
2024-03-15 09:52:23 +01:00
|
|
|
# Try to execute again to verify callback is not tested again
|
2021-11-06 15:36:51 +01:00
|
|
|
config._loaded()
|
|
|
|
|
|
|
|
|
|
|
|
def test_add_section_with_callback_already_loaded():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
name = "test_section"
|
2021-11-06 15:36:51 +01:00
|
|
|
config.parse_arguments_options(argv=[], create=False)
|
|
|
|
|
2024-03-15 09:52:23 +01:00
|
|
|
global tested
|
|
|
|
tested["test_add_section_with_callback_already_loaded"] = False
|
2021-11-06 15:36:51 +01:00
|
|
|
|
|
|
|
def test_callback(loaded_config):
|
2024-03-15 09:52:23 +01:00
|
|
|
global tested
|
2021-11-06 15:36:51 +01:00
|
|
|
assert loaded_config == config
|
2024-03-15 09:52:23 +01:00
|
|
|
assert tested["test_add_section_with_callback_already_loaded"] is False
|
|
|
|
tested["test_add_section_with_callback_already_loaded"] = True
|
2021-11-06 15:36:51 +01:00
|
|
|
|
|
|
|
section = config.add_section(name, loaded_callback=test_callback)
|
|
|
|
assert isinstance(section, ConfigSection)
|
2024-03-15 09:52:23 +01:00
|
|
|
assert tested["test_add_section_with_callback_already_loaded"] is True
|
2021-11-06 15:36:51 +01:00
|
|
|
assert test_callback in config._loaded_callbacks
|
|
|
|
assert test_callback in config._loaded_callbacks_executed
|
2024-03-15 09:52:23 +01:00
|
|
|
# Try to execute again to verify callback is not tested again
|
2021-11-06 15:36:51 +01:00
|
|
|
config._loaded()
|
|
|
|
|
|
|
|
|
|
|
|
def test_add_option_default_args():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
section = config.add_section("my_section")
|
2021-11-06 15:36:51 +01:00
|
|
|
assert isinstance(section, ConfigSection)
|
2023-01-16 12:56:12 +01:00
|
|
|
name = "my_option"
|
2021-11-06 15:36:51 +01:00
|
|
|
option = section.add_option(StringOption, name)
|
|
|
|
assert isinstance(option, StringOption)
|
|
|
|
assert name in section.options and section.options[name] == option
|
|
|
|
assert option.config == config
|
|
|
|
assert option.section == section
|
|
|
|
assert option.name == name
|
|
|
|
assert option.default is None
|
|
|
|
assert option.comment is None
|
|
|
|
assert option.no_arg is False
|
|
|
|
assert option.arg is None
|
|
|
|
assert option.short_arg is None
|
|
|
|
assert option.arg_help is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_add_option_custom_args():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
section = config.add_section("my_section")
|
2021-11-06 15:36:51 +01:00
|
|
|
assert isinstance(section, ConfigSection)
|
2023-01-16 12:56:12 +01:00
|
|
|
name = "my_option"
|
2023-10-27 13:35:59 +02:00
|
|
|
kwargs = {
|
|
|
|
"default": "default value",
|
|
|
|
"comment": "my comment",
|
|
|
|
"no_arg": True,
|
|
|
|
"arg": "--my-option",
|
|
|
|
"short_arg": "-M",
|
|
|
|
"arg_help": "My help",
|
|
|
|
}
|
2021-11-06 15:36:51 +01:00
|
|
|
option = section.add_option(StringOption, name, **kwargs)
|
|
|
|
assert isinstance(option, StringOption)
|
|
|
|
assert name in section.options and section.options[name] == option
|
|
|
|
|
|
|
|
assert option.config == config
|
|
|
|
assert option.section == section
|
|
|
|
assert option.name == name
|
|
|
|
for arg, value in kwargs.items():
|
|
|
|
assert getattr(option, arg) == value
|
|
|
|
|
|
|
|
|
|
|
|
def test_defined():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
section_name = "my_section"
|
|
|
|
opt_name = "my_option"
|
2021-11-06 15:36:51 +01:00
|
|
|
assert not config.defined(section_name, opt_name)
|
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
section = config.add_section("my_section")
|
2021-11-06 15:36:51 +01:00
|
|
|
assert isinstance(section, ConfigSection)
|
|
|
|
section.add_option(StringOption, opt_name)
|
|
|
|
|
|
|
|
assert config.defined(section_name, opt_name)
|
|
|
|
|
|
|
|
|
|
|
|
def test_isset():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
section_name = "my_section"
|
|
|
|
opt_name = "my_option"
|
2021-11-06 15:36:51 +01:00
|
|
|
assert not config.isset(section_name, opt_name)
|
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
section = config.add_section("my_section")
|
2021-11-06 15:36:51 +01:00
|
|
|
assert isinstance(section, ConfigSection)
|
|
|
|
option = section.add_option(StringOption, opt_name)
|
|
|
|
|
|
|
|
assert not config.isset(section_name, opt_name)
|
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
config.parse_arguments_options(argv=[option.parser_argument_name, "value"], create=False)
|
2021-11-06 15:36:51 +01:00
|
|
|
|
|
|
|
assert config.isset(section_name, opt_name)
|
|
|
|
|
|
|
|
|
|
|
|
def test_not_isset():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
section_name = "my_section"
|
|
|
|
opt_name = "my_option"
|
2021-11-06 15:36:51 +01:00
|
|
|
assert not config.isset(section_name, opt_name)
|
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
section = config.add_section("my_section")
|
2021-11-06 15:36:51 +01:00
|
|
|
assert isinstance(section, ConfigSection)
|
2023-01-06 19:36:14 +01:00
|
|
|
section.add_option(StringOption, opt_name)
|
2021-11-06 15:36:51 +01:00
|
|
|
|
|
|
|
assert not config.isset(section_name, opt_name)
|
|
|
|
|
|
|
|
config.parse_arguments_options(argv=[], create=False)
|
|
|
|
|
|
|
|
assert not config.isset(section_name, opt_name)
|
|
|
|
|
|
|
|
|
|
|
|
def test_get():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
section_name = "my_section"
|
|
|
|
opt_name = "my_option"
|
|
|
|
opt_value = "value"
|
|
|
|
section = config.add_section("my_section")
|
2021-11-06 15:36:51 +01:00
|
|
|
option = section.add_option(StringOption, opt_name)
|
|
|
|
config.parse_arguments_options(argv=[option.parser_argument_name, opt_value], create=False)
|
|
|
|
|
|
|
|
assert config.get(section_name, opt_name) == opt_value
|
|
|
|
|
|
|
|
|
|
|
|
def test_get_default():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
section_name = "my_section"
|
|
|
|
opt_name = "my_option"
|
|
|
|
opt_default_value = "value"
|
|
|
|
section = config.add_section("my_section")
|
2023-01-06 19:36:14 +01:00
|
|
|
section.add_option(StringOption, opt_name, default=opt_default_value)
|
2021-11-06 15:36:51 +01:00
|
|
|
config.parse_arguments_options(argv=[], create=False)
|
|
|
|
|
|
|
|
assert config.get(section_name, opt_name) == opt_default_value
|
2023-01-06 18:18:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_logging_splited_stdout_stderr(capsys):
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
config.parse_arguments_options(argv=["-C", "-v"], create=False)
|
2023-01-06 18:18:55 +01:00
|
|
|
info_msg = "[info]"
|
|
|
|
err_msg = "[error]"
|
|
|
|
logging.getLogger().info(info_msg)
|
|
|
|
logging.getLogger().error(err_msg)
|
|
|
|
captured = capsys.readouterr()
|
|
|
|
assert info_msg in captured.out
|
|
|
|
assert info_msg not in captured.err
|
|
|
|
assert err_msg in captured.err
|
|
|
|
assert err_msg not in captured.out
|
2023-01-09 13:33:14 +01:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Test option types
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture()
|
|
|
|
def config_with_file(tmpdir):
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
config_dir = tmpdir.mkdir("config")
|
|
|
|
config_file = config_dir.join("config.ini")
|
2023-01-09 13:33:14 +01:00
|
|
|
config.save(os.path.join(config_file.dirname, config_file.basename))
|
|
|
|
return config
|
|
|
|
|
|
|
|
|
|
|
|
def generate_mock_input(expected_prompt, input_value):
|
|
|
|
def mock_input(self, prompt): # pylint: disable=unused-argument
|
|
|
|
assert prompt == expected_prompt
|
|
|
|
return input_value
|
2023-01-16 12:56:12 +01:00
|
|
|
|
2023-01-09 13:33:14 +01:00
|
|
|
return mock_input
|
|
|
|
|
|
|
|
|
|
|
|
# Boolean option
|
|
|
|
|
|
|
|
|
|
|
|
def test_boolean_option_from_config(config_with_file):
|
2023-01-16 12:56:12 +01:00
|
|
|
section = config_with_file.add_section("test")
|
2023-01-09 13:33:14 +01:00
|
|
|
default = True
|
2023-01-16 12:56:12 +01:00
|
|
|
option = section.add_option(BooleanOption, "test_bool", default=default)
|
2023-01-09 13:33:14 +01:00
|
|
|
config_with_file.save()
|
|
|
|
|
|
|
|
option.set(not default)
|
|
|
|
assert option._from_config is not default
|
|
|
|
|
|
|
|
option.set(default)
|
|
|
|
assert not option._isset_in_config_file
|
|
|
|
with pytest.raises(configparser.NoOptionError):
|
|
|
|
assert option._from_config is default
|
|
|
|
|
|
|
|
|
|
|
|
def test_boolean_option_ask_value(mocker):
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
section = config.add_section("test")
|
|
|
|
name = "test_bool"
|
|
|
|
option = section.add_option(BooleanOption, name, default=True)
|
2023-01-09 13:33:14 +01:00
|
|
|
|
|
|
|
mocker.patch(
|
2023-01-16 12:56:12 +01:00
|
|
|
"mylib.config.BooleanOption._get_user_input", generate_mock_input(f"{name}: [Y/n] ", "y")
|
2023-01-09 13:33:14 +01:00
|
|
|
)
|
|
|
|
assert option.ask_value(set_it=False) is True
|
|
|
|
|
|
|
|
mocker.patch(
|
2023-01-16 12:56:12 +01:00
|
|
|
"mylib.config.BooleanOption._get_user_input", generate_mock_input(f"{name}: [Y/n] ", "Y")
|
2023-01-09 13:33:14 +01:00
|
|
|
)
|
|
|
|
assert option.ask_value(set_it=False) is True
|
|
|
|
|
|
|
|
mocker.patch(
|
2023-01-16 12:56:12 +01:00
|
|
|
"mylib.config.BooleanOption._get_user_input", generate_mock_input(f"{name}: [Y/n] ", "")
|
2023-01-09 13:33:14 +01:00
|
|
|
)
|
|
|
|
assert option.ask_value(set_it=False) is True
|
|
|
|
|
|
|
|
mocker.patch(
|
2023-01-16 12:56:12 +01:00
|
|
|
"mylib.config.BooleanOption._get_user_input", generate_mock_input(f"{name}: [Y/n] ", "n")
|
2023-01-09 13:33:14 +01:00
|
|
|
)
|
|
|
|
assert option.ask_value(set_it=False) is False
|
|
|
|
|
|
|
|
mocker.patch(
|
2023-01-16 12:56:12 +01:00
|
|
|
"mylib.config.BooleanOption._get_user_input", generate_mock_input(f"{name}: [Y/n] ", "N")
|
2023-01-09 13:33:14 +01:00
|
|
|
)
|
|
|
|
assert option.ask_value(set_it=False) is False
|
|
|
|
|
|
|
|
|
|
|
|
def test_boolean_option_to_config():
|
2023-01-16 12:56:12 +01:00
|
|
|
config = Config("Test app")
|
|
|
|
section = config.add_section("test")
|
2023-01-09 13:33:14 +01:00
|
|
|
default = True
|
2023-01-16 12:56:12 +01:00
|
|
|
option = section.add_option(BooleanOption, "test_bool", default=default)
|
|
|
|
assert option.to_config(True) == "true"
|
|
|
|
assert option.to_config(False) == "false"
|
2023-01-09 13:33:14 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_boolean_option_export_to_config(config_with_file):
|
2023-01-16 12:56:12 +01:00
|
|
|
section = config_with_file.add_section("test")
|
|
|
|
name = "test_bool"
|
|
|
|
comment = "Test boolean"
|
2023-01-09 13:33:14 +01:00
|
|
|
default = True
|
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
option = section.add_option(BooleanOption, name, default=default, comment=comment)
|
2023-01-09 13:33:14 +01:00
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
assert (
|
|
|
|
option.export_to_config()
|
|
|
|
== f"""# {comment}
|
2023-01-09 13:33:14 +01:00
|
|
|
# Default: {str(default).lower()}
|
|
|
|
# {name} =
|
|
|
|
"""
|
2023-01-16 12:56:12 +01:00
|
|
|
)
|
2023-01-09 13:33:14 +01:00
|
|
|
|
|
|
|
option.set(not default)
|
2023-01-16 12:56:12 +01:00
|
|
|
assert (
|
|
|
|
option.export_to_config()
|
|
|
|
== f"""# {comment}
|
2023-01-09 13:33:14 +01:00
|
|
|
# Default: {str(default).lower()}
|
|
|
|
{name} = {str(not default).lower()}
|
|
|
|
"""
|
2023-01-16 12:56:12 +01:00
|
|
|
)
|
2023-01-09 13:33:14 +01:00
|
|
|
|
|
|
|
option.set(default)
|
2023-01-16 12:56:12 +01:00
|
|
|
assert (
|
|
|
|
option.export_to_config()
|
|
|
|
== f"""# {comment}
|
2023-01-09 13:33:14 +01:00
|
|
|
# Default: {str(default).lower()}
|
|
|
|
# {name} =
|
|
|
|
"""
|
2023-01-16 12:56:12 +01:00
|
|
|
)
|