mirror of
https://github.com/blw1138/Zordon.git
synced 2026-06-09 13:39:24 -05:00
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
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user