- Add config.py with load_config(), find_default_config(), get_token(), and get_map_path() - Auto-discover timesheets.toml in cwd; override with --config flag - Priority: CLI flag > config file > env var / cwd default - Add timesheets.example.toml as a committed reference template - Add timesheets.toml to .gitignore to prevent accidental secret leakage - Document config file format in AGENTS.md
88 lines
2.8 KiB
Python
88 lines
2.8 KiB
Python
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from timesheets.config import (
|
|
DEFAULT_CONFIG_FILENAME,
|
|
find_default_config,
|
|
get_map_path,
|
|
get_token,
|
|
load_config,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# load_config
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestLoadConfig:
|
|
def test_none_returns_empty(self):
|
|
assert load_config(None) == {}
|
|
|
|
def test_loads_valid_toml(self, tmp_path):
|
|
f = tmp_path / "timesheets.toml"
|
|
f.write_text('[joplin]\ntoken = "abc123"\n')
|
|
result = load_config(f)
|
|
assert result == {"joplin": {"token": "abc123"}}
|
|
|
|
def test_missing_file_exits(self, tmp_path, capsys):
|
|
with pytest.raises(SystemExit):
|
|
load_config(tmp_path / "nonexistent.toml")
|
|
assert "not found" in capsys.readouterr().err
|
|
|
|
def test_invalid_toml_exits(self, tmp_path, capsys):
|
|
f = tmp_path / "bad.toml"
|
|
f.write_text("not = valid = toml\n")
|
|
with pytest.raises(SystemExit):
|
|
load_config(f)
|
|
assert "could not parse" in capsys.readouterr().err
|
|
|
|
def test_accepts_str_path(self, tmp_path):
|
|
f = tmp_path / "timesheets.toml"
|
|
f.write_text('[projects]\nmap = "/some/path.json"\n')
|
|
result = load_config(str(f))
|
|
assert result["projects"]["map"] == "/some/path.json"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# find_default_config
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestFindDefaultConfig:
|
|
def test_returns_none_when_absent(self, tmp_path, monkeypatch):
|
|
monkeypatch.chdir(tmp_path)
|
|
assert find_default_config() is None
|
|
|
|
def test_returns_path_when_present(self, tmp_path, monkeypatch):
|
|
monkeypatch.chdir(tmp_path)
|
|
cfg = tmp_path / DEFAULT_CONFIG_FILENAME
|
|
cfg.write_text("")
|
|
result = find_default_config()
|
|
assert result == cfg
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# get_token / get_map_path
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestGetters:
|
|
def test_get_token_present(self):
|
|
assert get_token({"joplin": {"token": "xyz"}}) == "xyz"
|
|
|
|
def test_get_token_missing_section(self):
|
|
assert get_token({}) is None
|
|
|
|
def test_get_token_missing_key(self):
|
|
assert get_token({"joplin": {}}) is None
|
|
|
|
def test_get_map_path_present(self):
|
|
assert get_map_path({"projects": {"map": "/a/b.json"}}) == "/a/b.json"
|
|
|
|
def test_get_map_path_missing_section(self):
|
|
assert get_map_path({}) is None
|
|
|
|
def test_get_map_path_missing_key(self):
|
|
assert get_map_path({"projects": {}}) is None
|