diff options
Diffstat (limited to 'tests/test_config.py')
-rw-r--r-- | tests/test_config.py | 293 |
1 files changed, 293 insertions, 0 deletions
diff --git a/tests/test_config.py b/tests/test_config.py new file mode 100644 index 0000000..131bc8c --- /dev/null +++ b/tests/test_config.py @@ -0,0 +1,293 @@ +# -*- coding: utf-8 -*- +"""Test the cli_helpers.config module.""" + +from __future__ import unicode_literals +import os + +from unittest.mock import MagicMock +import pytest + +from cli_helpers.compat import MAC, text_type, WIN +from cli_helpers.config import ( + Config, + DefaultConfigValidationError, + get_system_config_dirs, + get_user_config_dir, + _pathify, +) +from .utils import with_temp_dir + +APP_NAME, APP_AUTHOR = "Test", "Acme" +TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "config_data") +DEFAULT_CONFIG = { + "section": { + "test_boolean_default": "True", + "test_string_file": "~/myfile", + "test_option": "foobar✔", + }, + "section2": {}, +} +DEFAULT_VALID_CONFIG = { + "section": { + "test_boolean_default": True, + "test_string_file": "~/myfile", + "test_option": "foobar✔", + }, + "section2": {}, +} + + +def _mocked_user_config(temp_dir, *args, **kwargs): + config = Config(*args, **kwargs) + config.user_config_file = MagicMock( + return_value=os.path.join(temp_dir, config.filename) + ) + return config + + +def test_user_config_dir(): + """Test that the config directory is a string with the app name in it.""" + if "XDG_CONFIG_HOME" in os.environ: + del os.environ["XDG_CONFIG_HOME"] + config_dir = get_user_config_dir(APP_NAME, APP_AUTHOR) + assert isinstance(config_dir, text_type) + assert config_dir.endswith(APP_NAME) or config_dir.endswith(_pathify(APP_NAME)) + + +def test_sys_config_dirs(): + """Test that the sys config directories are returned correctly.""" + if "XDG_CONFIG_DIRS" in os.environ: + del os.environ["XDG_CONFIG_DIRS"] + config_dirs = get_system_config_dirs(APP_NAME, APP_AUTHOR) + assert isinstance(config_dirs, list) + assert config_dirs[0].endswith(APP_NAME) or config_dirs[0].endswith( + _pathify(APP_NAME) + ) + + +@pytest.mark.skipif(not WIN, reason="requires Windows") +def test_windows_user_config_dir_no_roaming(): + """Test that Windows returns the user config directory without roaming.""" + config_dir = get_user_config_dir(APP_NAME, APP_AUTHOR, roaming=False) + assert isinstance(config_dir, text_type) + assert config_dir.endswith(APP_NAME) + assert "Local" in config_dir + + +@pytest.mark.skipif(not MAC, reason="requires macOS") +def test_mac_user_config_dir_no_xdg(): + """Test that macOS returns the user config directory without XDG.""" + config_dir = get_user_config_dir(APP_NAME, APP_AUTHOR, force_xdg=False) + assert isinstance(config_dir, text_type) + assert config_dir.endswith(APP_NAME) + assert "Library" in config_dir + + +@pytest.mark.skipif(not MAC, reason="requires macOS") +def test_mac_system_config_dirs_no_xdg(): + """Test that macOS returns the system config directories without XDG.""" + config_dirs = get_system_config_dirs(APP_NAME, APP_AUTHOR, force_xdg=False) + assert isinstance(config_dirs, list) + assert config_dirs[0].endswith(APP_NAME) + assert "Library" in config_dirs[0] + + +def test_config_reading_raise_errors(): + """Test that instantiating Config will raise errors when appropriate.""" + with pytest.raises(ValueError): + Config(APP_NAME, APP_AUTHOR, "test_config", write_default=True) + + with pytest.raises(ValueError): + Config(APP_NAME, APP_AUTHOR, "test_config", validate=True) + + with pytest.raises(TypeError): + Config(APP_NAME, APP_AUTHOR, "test_config", default=b"test") + + +def test_config_user_file(): + """Test that the Config user_config_file is appropriate.""" + config = Config(APP_NAME, APP_AUTHOR, "test_config") + assert get_user_config_dir(APP_NAME, APP_AUTHOR) in config.user_config_file() + + +def test_config_reading_default_dict(): + """Test that the Config constructor will read in defaults from a dict.""" + default = {"main": {"foo": "bar"}} + config = Config(APP_NAME, APP_AUTHOR, "test_config", default=default) + assert config.data == default + + +def test_config_reading_no_default(): + """Test that the Config constructor will work without any defaults.""" + config = Config(APP_NAME, APP_AUTHOR, "test_config") + assert config.data == {} + + +def test_config_reading_default_file(): + """Test that the Config will work with a default file.""" + config = Config( + APP_NAME, + APP_AUTHOR, + "test_config", + default=os.path.join(TEST_DATA_DIR, "configrc"), + ) + config.read_default_config() + assert config.data == DEFAULT_CONFIG + + +def test_config_reading_configspec(): + """Test that the Config default file will work with a configspec.""" + config = Config( + APP_NAME, + APP_AUTHOR, + "test_config", + validate=True, + default=os.path.join(TEST_DATA_DIR, "configspecrc"), + ) + config.read_default_config() + assert config.data == DEFAULT_VALID_CONFIG + + +def test_config_reading_configspec_with_error(): + """Test that reading an invalid configspec raises and exception.""" + with pytest.raises(DefaultConfigValidationError): + config = Config( + APP_NAME, + APP_AUTHOR, + "test_config", + validate=True, + default=os.path.join(TEST_DATA_DIR, "invalid_configspecrc"), + ) + config.read_default_config() + + +@with_temp_dir +def test_write_and_read_default_config(temp_dir=None): + config_file = "test_config" + default_file = os.path.join(TEST_DATA_DIR, "configrc") + temp_config_file = os.path.join(temp_dir, config_file) + + config = _mocked_user_config( + temp_dir, APP_NAME, APP_AUTHOR, config_file, default=default_file + ) + config.read_default_config() + config.write_default_config() + + user_config = _mocked_user_config( + temp_dir, APP_NAME, APP_AUTHOR, config_file, default=default_file + ) + user_config.read() + assert temp_config_file in user_config.config_filenames + assert user_config == config + + with open(temp_config_file) as f: + contents = f.read() + assert "# Test file comment" in contents + assert "# Test section comment" in contents + assert "# Test field comment" in contents + assert "# Test field commented out" in contents + + +@with_temp_dir +def test_write_and_read_default_config_from_configspec(temp_dir=None): + config_file = "test_config" + default_file = os.path.join(TEST_DATA_DIR, "configspecrc") + temp_config_file = os.path.join(temp_dir, config_file) + + config = _mocked_user_config( + temp_dir, APP_NAME, APP_AUTHOR, config_file, default=default_file, validate=True + ) + config.read_default_config() + config.write_default_config() + + user_config = _mocked_user_config( + temp_dir, APP_NAME, APP_AUTHOR, config_file, default=default_file, validate=True + ) + user_config.read() + assert temp_config_file in user_config.config_filenames + assert user_config == config + + with open(temp_config_file) as f: + contents = f.read() + assert "# Test file comment" in contents + assert "# Test section comment" in contents + assert "# Test field comment" in contents + assert "# Test field commented out" in contents + + +@with_temp_dir +def test_overwrite_default_config_from_configspec(temp_dir=None): + config_file = "test_config" + default_file = os.path.join(TEST_DATA_DIR, "configspecrc") + temp_config_file = os.path.join(temp_dir, config_file) + + config = _mocked_user_config( + temp_dir, APP_NAME, APP_AUTHOR, config_file, default=default_file, validate=True + ) + config.read_default_config() + config.write_default_config() + + with open(temp_config_file, "a") as f: + f.write("--APPEND--") + + config.write_default_config() + + with open(temp_config_file) as f: + assert "--APPEND--" in f.read() + + config.write_default_config(overwrite=True) + + with open(temp_config_file) as f: + assert "--APPEND--" not in f.read() + + +def test_read_invalid_config_file(): + config_file = "invalid_configrc" + + config = _mocked_user_config(TEST_DATA_DIR, APP_NAME, APP_AUTHOR, config_file) + config.read() + assert "section" in config + assert "test_string_file" in config["section"] + assert "test_boolean_default" not in config["section"] + assert "section2" in config + + +@with_temp_dir +def test_write_to_user_config(temp_dir=None): + config_file = "test_config" + default_file = os.path.join(TEST_DATA_DIR, "configrc") + temp_config_file = os.path.join(temp_dir, config_file) + + config = _mocked_user_config( + temp_dir, APP_NAME, APP_AUTHOR, config_file, default=default_file + ) + config.read_default_config() + config.write_default_config() + + with open(temp_config_file) as f: + assert "test_boolean_default = True" in f.read() + + config["section"]["test_boolean_default"] = False + config.write() + + with open(temp_config_file) as f: + assert "test_boolean_default = False" in f.read() + + +@with_temp_dir +def test_write_to_outfile(temp_dir=None): + config_file = "test_config" + outfile = os.path.join(temp_dir, "foo") + default_file = os.path.join(TEST_DATA_DIR, "configrc") + + config = _mocked_user_config( + temp_dir, APP_NAME, APP_AUTHOR, config_file, default=default_file + ) + config.read_default_config() + config.write_default_config() + + config["section"]["test_boolean_default"] = False + config.write(outfile=outfile) + + with open(outfile) as f: + assert "test_boolean_default = False" in f.read() |