Files
Zordon/tests/test_config.py
brett 24eb7b5616 Add Unit Tests (#132)
* Add tests and new github workflow

* Add new unit tests

* Add Github CI workflow

* Workflow fix

* Add pytest install to workflow file

* More CI / test updates

* More test cleanup

* Whitespace cleanup and link complexity override

* More whitespace cleanup

* Make lint less strict

* More lint tweaks
2026-06-06 00:02:01 -05:00

173 lines
5.2 KiB
Python

from pathlib import Path
from unittest.mock import patch
from src.utilities.config import Config, _CONFIG_ATTRS
class TestConfigDefaults:
"""Default attribute values."""
def test_default_upload_folder(self):
assert Config.upload_folder == '~/zordon-uploads/'
def test_default_port(self):
assert Config.port_number == 8080
def test_default_server_log_level(self):
assert Config.server_log_level == 'debug'
def test_default_enable_split_jobs(self):
assert Config.enable_split_jobs is True
def test_default_worker_timeout(self):
assert Config.worker_process_timeout == 120
class TestConfigInstance:
"""Instance creation and attribute initialisation."""
def test_init_copies_class_attrs(self):
cfg = Config()
assert cfg.upload_folder == '~/zordon-uploads/'
assert cfg.port_number == 8080
def test_init_has_all_attrs(self):
cfg = Config()
for attr in _CONFIG_ATTRS:
assert hasattr(cfg, attr), f'missing attr: {attr}'
class TestConfigLoad:
"""Loading configuration from YAML."""
def test_load_sets_attributes(self, tmp_path):
config_file = tmp_path / 'config.yaml'
config_file.write_text('port_number: 9090\nserver_log_level: info\n')
cfg = Config()
cfg.load(config_file)
assert cfg.port_number == 9090
assert cfg.server_log_level == 'info'
def test_load_expands_upload_folder(self, tmp_path):
config_file = tmp_path / 'config.yaml'
config_file.write_text('upload_folder: ~/custom-uploads/\n')
cfg = Config()
cfg.load(config_file)
# expanduser strips trailing slash
assert cfg.upload_folder.endswith('/custom-uploads')
def test_load_ignores_unknown_keys(self, tmp_path):
config_file = tmp_path / 'config.yaml'
config_file.write_text('nonexistent_key: value\nport_number: 7070\n')
cfg = Config()
cfg.load(config_file)
assert cfg.port_number == 7070
def test_load_raises_on_missing_file(self):
cfg = Config()
try:
cfg.load(Path('/nonexistent/path.yaml'))
assert False, 'expected FileNotFoundError'
except FileNotFoundError:
pass
class TestConfigSyncClass:
"""_sync_class propagates instance attrs to class level."""
def test_sync_class_propagates_attrs(self):
orig = Config._default_instance
try:
cfg = Config()
cfg.port_number = 7777
Config._default_instance = cfg
Config._sync_class()
assert Config.port_number == 7777
finally:
Config._default_instance = orig
Config._sync_class()
def test_sync_class_noop_when_no_instance(self):
orig = Config._default_instance
try:
Config._default_instance = None
Config._sync_class()
finally:
Config._default_instance = orig
Config._sync_class()
class TestConfigLoadConfig:
"""Classmethod load_config — full bootstrap."""
def test_load_config_sets_default_instance(self, tmp_path):
orig = Config._default_instance
try:
config_file = tmp_path / 'config.yaml'
config_file.write_text('port_number: 9999\n')
Config._default_instance = None
Config.load_config(config_file)
assert Config._default_instance is not None
assert Config.port_number == 9999
finally:
Config._default_instance = orig
Config._sync_class()
class TestConfigDir:
"""config_dir() returns OS-specific path."""
@patch('src.utilities.config.current_system_os')
def test_config_dir_macos(self, mock_os):
mock_os.return_value = 'macos'
result = Config.config_dir()
assert 'Library/Application Support/Zordon' in str(result)
@patch('src.utilities.config.current_system_os')
def test_config_dir_windows(self, mock_os):
mock_os.return_value = 'windows'
with patch.dict('os.environ', {'APPDATA': 'C:\\Users\\Test\\AppData\\Roaming'}):
result = Config.config_dir()
assert 'Zordon' in str(result)
@patch('src.utilities.config.current_system_os')
def test_config_dir_linux(self, mock_os):
mock_os.return_value = 'linux'
result = Config.config_dir()
assert '.config/Zordon' in str(result)
class TestSetupConfigDir:
"""setup_config_dir creates dir and copies template."""
@patch('src.utilities.config.copy_directory_contents')
@patch('src.utilities.config.os.makedirs')
@patch('src.utilities.config.os.path.exists')
def test_creates_dir_when_missing(self, mock_exists, mock_makedirs, mock_copy):
mock_exists.return_value = False
Config.setup_config_dir()
mock_makedirs.assert_called_once()
@patch('src.utilities.config.copy_directory_contents')
@patch('src.utilities.config.os.makedirs')
@patch('src.utilities.config.os.path.exists')
def test_skips_when_dir_exists(self, mock_exists, mock_makedirs, mock_copy):
mock_exists.return_value = True
Config.setup_config_dir()
mock_makedirs.assert_not_called()
mock_copy.assert_not_called()