Added tests for configoptions.py
This commit is contained in:
@@ -2247,6 +2247,7 @@ For additional details about how osxphotos is implemented or if you would like t
|
|||||||
- [bpylist2](https://pypi.org/project/bpylist2/)
|
- [bpylist2](https://pypi.org/project/bpylist2/)
|
||||||
- [pathvalidate](https://pypi.org/project/pathvalidate/)
|
- [pathvalidate](https://pypi.org/project/pathvalidate/)
|
||||||
- [wurlitzer](https://pypi.org/project/wurlitzer/)
|
- [wurlitzer](https://pypi.org/project/wurlitzer/)
|
||||||
|
- [toml](https://github.com/uiri/toml)
|
||||||
|
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ class ConfigOptions:
|
|||||||
Args:
|
Args:
|
||||||
name: name for these options, will be used for section heading in TOML file when saving/loading from file
|
name: name for these options, will be used for section heading in TOML file when saving/loading from file
|
||||||
attrs: dict with name and default value for all allowed attributes
|
attrs: dict with name and default value for all allowed attributes
|
||||||
|
ignore: optional list of strings of keys to ignore from attrs dict
|
||||||
"""
|
"""
|
||||||
self._name = name
|
self._name = name
|
||||||
self._attrs = attrs.copy()
|
self._attrs = attrs.copy()
|
||||||
@@ -113,7 +114,7 @@ class ConfigOptions:
|
|||||||
strb = ", ".join(prefix + x.replace("_", "-") for x in b)
|
strb = ", ".join(prefix + x.replace("_", "-") for x in b)
|
||||||
else:
|
else:
|
||||||
stra = a
|
stra = a
|
||||||
strb = ", ".join(x for x in b)
|
strb = ", ".join(b)
|
||||||
raise ConfigOptionsInvalidError(
|
raise ConfigOptionsInvalidError(
|
||||||
f"{stra} must be used with at least one of: {strb}."
|
f"{stra} must be used with at least one of: {strb}."
|
||||||
)
|
)
|
||||||
@@ -166,7 +167,7 @@ class ConfigOptions:
|
|||||||
if type(self._attrs[attr]) == tuple:
|
if type(self._attrs[attr]) == tuple:
|
||||||
val = tuple(val)
|
val = tuple(val)
|
||||||
setattr(self, attr, val)
|
setattr(self, attr, val)
|
||||||
return self, None
|
return self
|
||||||
|
|
||||||
def asdict(self):
|
def asdict(self):
|
||||||
return {attr: getattr(self, attr) for attr in sorted(self._attrs.keys())}
|
return {attr: getattr(self, attr) for attr in sorted(self._attrs.keys())}
|
||||||
|
|||||||
1
setup.py
1
setup.py
@@ -80,6 +80,7 @@ setup(
|
|||||||
"dataclasses==0.7;python_version<'3.7'",
|
"dataclasses==0.7;python_version<'3.7'",
|
||||||
"wurlitzer>=2.0.1",
|
"wurlitzer>=2.0.1",
|
||||||
"photoscript>=0.1.0",
|
"photoscript>=0.1.0",
|
||||||
|
"toml>=0.10.0",
|
||||||
],
|
],
|
||||||
entry_points={"console_scripts": ["osxphotos=osxphotos.__main__:cli"]},
|
entry_points={"console_scripts": ["osxphotos=osxphotos.__main__:cli"]},
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
|
|||||||
@@ -3974,6 +3974,7 @@ def test_save_load_config():
|
|||||||
cwd = os.getcwd()
|
cwd = os.getcwd()
|
||||||
# pylint: disable=not-context-manager
|
# pylint: disable=not-context-manager
|
||||||
with runner.isolated_filesystem():
|
with runner.isolated_filesystem():
|
||||||
|
# test save config file
|
||||||
result = runner.invoke(
|
result = runner.invoke(
|
||||||
export,
|
export,
|
||||||
[
|
[
|
||||||
@@ -3993,6 +3994,7 @@ def test_save_load_config():
|
|||||||
files = glob.glob("*")
|
files = glob.glob("*")
|
||||||
assert "config.toml" in files
|
assert "config.toml" in files
|
||||||
|
|
||||||
|
# test load config file
|
||||||
result = runner.invoke(
|
result = runner.invoke(
|
||||||
export,
|
export,
|
||||||
[
|
[
|
||||||
@@ -4007,3 +4009,55 @@ def test_save_load_config():
|
|||||||
assert "Loaded options from file" in result.output
|
assert "Loaded options from file" in result.output
|
||||||
assert "Skipped up to date XMP sidecar" in result.output
|
assert "Skipped up to date XMP sidecar" in result.output
|
||||||
|
|
||||||
|
# test overwrite existing config file
|
||||||
|
result = runner.invoke(
|
||||||
|
export,
|
||||||
|
[
|
||||||
|
os.path.join(cwd, CLI_PHOTOS_DB),
|
||||||
|
".",
|
||||||
|
"-V",
|
||||||
|
"--sidecar",
|
||||||
|
"XMP",
|
||||||
|
"--touch-file",
|
||||||
|
"--not-live",
|
||||||
|
"--update",
|
||||||
|
"--save-config",
|
||||||
|
"config.toml",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert "Saving options to file" in result.output
|
||||||
|
files = glob.glob("*")
|
||||||
|
assert "config.toml" in files
|
||||||
|
|
||||||
|
# test load config file with incompat command line option
|
||||||
|
result = runner.invoke(
|
||||||
|
export,
|
||||||
|
[
|
||||||
|
os.path.join(cwd, CLI_PHOTOS_DB),
|
||||||
|
".",
|
||||||
|
"-V",
|
||||||
|
"--load-config",
|
||||||
|
"config.toml",
|
||||||
|
"--live",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert result.exit_code != 0
|
||||||
|
assert "Incompatible export options" in result.output
|
||||||
|
|
||||||
|
# test load config file with command line override
|
||||||
|
result = runner.invoke(
|
||||||
|
export,
|
||||||
|
[
|
||||||
|
os.path.join(cwd, CLI_PHOTOS_DB),
|
||||||
|
".",
|
||||||
|
"-V",
|
||||||
|
"--load-config",
|
||||||
|
"config.toml",
|
||||||
|
"--sidecar",
|
||||||
|
"json",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
assert result.exit_code == 0
|
||||||
|
assert "Writing exiftool JSON sidecar" in result.output
|
||||||
|
assert "Writing XMP sidecar" not in result.output
|
||||||
|
|||||||
86
tests/test_configoptions.py
Normal file
86
tests/test_configoptions.py
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
""" test ConfigOptions class """
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
import pytest
|
||||||
|
import toml
|
||||||
|
|
||||||
|
from osxphotos.configoptions import (
|
||||||
|
ConfigOptions,
|
||||||
|
ConfigOptionsInvalidError,
|
||||||
|
ConfigOptionsLoadError,
|
||||||
|
)
|
||||||
|
|
||||||
|
VARS = {"foo": "bar", "bar": False, "test1": (), "test2": None, "test2_setting": False}
|
||||||
|
|
||||||
|
|
||||||
|
def test_init():
|
||||||
|
cfg = ConfigOptions("test", VARS)
|
||||||
|
assert isinstance(cfg, ConfigOptions)
|
||||||
|
assert cfg.foo is "bar"
|
||||||
|
assert cfg.bar == False
|
||||||
|
assert type(cfg.test1) == tuple
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_with_ignore():
|
||||||
|
cfg = ConfigOptions("test", VARS, ignore=["test2"])
|
||||||
|
assert isinstance(cfg, ConfigOptions)
|
||||||
|
assert hasattr(cfg, "test1")
|
||||||
|
assert not hasattr(cfg, "test2")
|
||||||
|
|
||||||
|
|
||||||
|
def test_write_to_file_load_from_file(tmpdir):
|
||||||
|
cfg = ConfigOptions("test", VARS)
|
||||||
|
cfg.bar = True
|
||||||
|
cfg_file = pathlib.Path(str(tmpdir)) / "test.toml"
|
||||||
|
cfg.write_to_file(str(cfg_file))
|
||||||
|
assert cfg_file.is_file()
|
||||||
|
|
||||||
|
cfg_dict = toml.load(str(cfg_file))
|
||||||
|
assert cfg_dict["test"]["foo"] == "bar"
|
||||||
|
|
||||||
|
cfg2 = ConfigOptions("test", VARS).load_from_file(str(cfg_file))
|
||||||
|
assert cfg2.foo == "bar"
|
||||||
|
assert cfg2.bar
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_from_file_error(tmpdir):
|
||||||
|
cfg_file = pathlib.Path(str(tmpdir)) / "test.toml"
|
||||||
|
cfg = ConfigOptions("test", VARS)
|
||||||
|
cfg.write_to_file(str(cfg_file))
|
||||||
|
# try to load with a section that doesn't exist in the TOML file
|
||||||
|
with pytest.raises(ConfigOptionsLoadError):
|
||||||
|
cfg2 = ConfigOptions("FOO", VARS).load_from_file(str(cfg_file))
|
||||||
|
|
||||||
|
|
||||||
|
def test_asdict():
|
||||||
|
cfg = ConfigOptions("test", VARS)
|
||||||
|
cfg_dict = cfg.asdict()
|
||||||
|
assert cfg_dict["foo"] == "bar"
|
||||||
|
assert cfg_dict["bar"] == False
|
||||||
|
assert cfg_dict["test1"] == ()
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate():
|
||||||
|
cfg = ConfigOptions("test", VARS)
|
||||||
|
|
||||||
|
# test exclusive
|
||||||
|
assert cfg.validate(exclusive=[("foo", "bar")])
|
||||||
|
cfg.bar = True
|
||||||
|
with pytest.raises(ConfigOptionsInvalidError):
|
||||||
|
assert cfg.validate(exclusive=[("foo", "bar")])
|
||||||
|
|
||||||
|
# test dependent
|
||||||
|
cfg.test2 = True
|
||||||
|
cfg.test2_setting = 1.0
|
||||||
|
assert cfg.validate(dependent=[("test2_setting", ("test2"))])
|
||||||
|
cfg.test2 = False
|
||||||
|
with pytest.raises(ConfigOptionsInvalidError):
|
||||||
|
assert cfg.validate(dependent=[("test2_setting", ("test2"))])
|
||||||
|
|
||||||
|
# test inclusive
|
||||||
|
cfg.foo = "foo"
|
||||||
|
cfg.bar = True
|
||||||
|
assert cfg.validate(inclusive=[("foo", "bar")])
|
||||||
|
cfg.foo = None
|
||||||
|
with pytest.raises(ConfigOptionsInvalidError):
|
||||||
|
assert cfg.validate(inclusive=[("foo", "bar")])
|
||||||
Reference in New Issue
Block a user