TestChannelFilter: allowed/denied/PM/no-config/core-exempt/ampersand. TestChannelConfig: TOML loading, defaults. TestJsonFormatter: fields, exception, unicode, single-line, timestamp format.
113 lines
3.7 KiB
Python
113 lines
3.7 KiB
Python
"""Tests for configuration loading and merging."""
|
|
|
|
import copy
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from derp.config import DEFAULTS, _merge, load, resolve_config
|
|
|
|
|
|
class TestMerge:
|
|
"""Test deep merge logic."""
|
|
|
|
def test_flat_override(self):
|
|
base = {"a": 1, "b": 2}
|
|
result = _merge(base, {"b": 99})
|
|
assert result == {"a": 1, "b": 99}
|
|
|
|
def test_nested_merge(self):
|
|
base = {"server": {"host": "a", "port": 1}}
|
|
result = _merge(base, {"server": {"port": 2}})
|
|
assert result == {"server": {"host": "a", "port": 2}}
|
|
|
|
def test_list_replacement(self):
|
|
base = {"channels": ["#old"]}
|
|
result = _merge(base, {"channels": ["#new"]})
|
|
assert result == {"channels": ["#new"]}
|
|
|
|
def test_empty_override(self):
|
|
base = {"a": 1, "b": 2}
|
|
result = _merge(base, {})
|
|
assert result == {"a": 1, "b": 2}
|
|
|
|
def test_new_keys(self):
|
|
base = {"a": 1}
|
|
result = _merge(base, {"b": 2})
|
|
assert result == {"a": 1, "b": 2}
|
|
|
|
def test_base_not_mutated(self):
|
|
base = {"server": {"host": "original"}}
|
|
original = copy.deepcopy(base)
|
|
_merge(base, {"server": {"host": "changed"}})
|
|
assert base == original
|
|
|
|
|
|
class TestLoad:
|
|
"""Test TOML file loading."""
|
|
|
|
def test_minimal_toml(self, tmp_path: Path):
|
|
config_file = tmp_path / "test.toml"
|
|
config_file.write_text('[server]\nnick = "testbot"\n')
|
|
result = load(config_file)
|
|
# Overridden value
|
|
assert result["server"]["nick"] == "testbot"
|
|
# Default preserved
|
|
assert result["server"]["host"] == "irc.libera.chat"
|
|
assert result["server"]["port"] == 6697
|
|
|
|
def test_full_override(self, tmp_path: Path):
|
|
config_file = tmp_path / "test.toml"
|
|
config_file.write_text(
|
|
'[server]\nhost = "custom.irc"\nport = 6667\n'
|
|
'[bot]\nprefix = "."\n'
|
|
)
|
|
result = load(config_file)
|
|
assert result["server"]["host"] == "custom.irc"
|
|
assert result["server"]["port"] == 6667
|
|
assert result["bot"]["prefix"] == "."
|
|
# Unset defaults still present
|
|
assert result["bot"]["channels"] == ["#test"]
|
|
|
|
|
|
class TestChannelConfig:
|
|
"""Test channel-level configuration merging."""
|
|
|
|
def test_channel_config_loaded(self, tmp_path: Path):
|
|
config_file = tmp_path / "test.toml"
|
|
config_file.write_text(
|
|
'[channels."#ops"]\nplugins = ["core", "dns"]\n'
|
|
)
|
|
result = load(config_file)
|
|
assert "#ops" in result["channels"]
|
|
assert result["channels"]["#ops"]["plugins"] == ["core", "dns"]
|
|
|
|
def test_default_channels_empty(self):
|
|
assert DEFAULTS["channels"] == {}
|
|
|
|
def test_default_logging_format(self):
|
|
assert DEFAULTS["logging"]["format"] == "text"
|
|
|
|
|
|
class TestResolveConfig:
|
|
"""Test config path resolution and fallback."""
|
|
|
|
def test_explicit_path(self, tmp_path: Path):
|
|
config_file = tmp_path / "explicit.toml"
|
|
config_file.write_text('[server]\nnick = "explicit"\n')
|
|
result = resolve_config(str(config_file))
|
|
assert result["server"]["nick"] == "explicit"
|
|
|
|
def test_no_file_fallback(self, tmp_path: Path, monkeypatch: "pytest.MonkeyPatch"):
|
|
# Run from tmp_path so config/derp.toml isn't found
|
|
monkeypatch.chdir(tmp_path)
|
|
result = resolve_config(str(tmp_path / "nonexistent.toml"))
|
|
# Should fall back to DEFAULTS
|
|
assert result["server"]["host"] == DEFAULTS["server"]["host"]
|
|
assert result["bot"]["prefix"] == DEFAULTS["bot"]["prefix"]
|
|
|
|
def test_defaults_not_mutated(self):
|
|
original = copy.deepcopy(DEFAULTS)
|
|
resolve_config(None)
|
|
assert DEFAULTS == original
|