Some checks failed
Release / Bump version and tag (push) Successful in 4s
Sidecar Release / Bump sidecar version and tag (push) Failing after 3s
Tests / Python Backend Tests (push) Failing after 3s
Tests / Frontend Tests (push) Successful in 8s
Tests / Rust Sidecar Tests (push) Successful in 3m10s
Test suite covering all three layers: Python backend (25 tests): - AppController: state machine, start/stop, callbacks, settings reload - API server: REST endpoints, config CRUD, status, devices - Config: dot-notation get/set, persistence, nested paths - Main headless: ready event port format validation Svelte frontend (14 tests via Vitest): - Backend store: exported properties/methods, port derivation, URLs - Config store: method names (fetchConfig not loadConfig), defaults - Transcriptions store: add/clear/plaintext - File extension regression: ensures $state runes only in .svelte.ts Rust sidecar (24 tests via cargo test): - Platform/arch detection, asset name construction - Ready event deserialization (with extra fields tolerance) - Path construction, version read/write, old version cleanup - Zip extraction, SidecarManager lifecycle CI workflow (.gitea/workflows/test.yml): - Runs on push to main and PRs - Three parallel jobs: Python, Frontend, Rust Also fixes three bugs found during test planning: - Settings: /api/check-updates -> GET /api/check-update - Settings: /api/remote/login -> /api/login - Settings: /api/remote/register -> /api/register Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
79 lines
2.7 KiB
Python
79 lines
2.7 KiB
Python
"""Tests for client.config.Config."""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
# Ensure project root is on path
|
|
project_root = Path(__file__).resolve().parent.parent.parent
|
|
sys.path.insert(0, str(project_root))
|
|
|
|
from client.config import Config
|
|
|
|
|
|
@pytest.fixture
|
|
def cfg(tmp_path):
|
|
"""A Config backed by a temp file so we never touch the real user config."""
|
|
return Config(config_path=str(tmp_path / "test_config.yaml"))
|
|
|
|
|
|
# ── dot-notation get ────────────────────────────────────────────────
|
|
|
|
|
|
def test_dot_notation_get(cfg):
|
|
"""Config.get should traverse nested dicts using dot-separated keys."""
|
|
cfg.config = {"audio": {"sample_rate": 16000}}
|
|
assert cfg.get("audio.sample_rate") == 16000
|
|
|
|
|
|
# ── dot-notation set ────────────────────────────────────────────────
|
|
|
|
|
|
def test_dot_notation_set(cfg):
|
|
"""Config.set should create/update nested values via dot-separated keys."""
|
|
cfg.set("audio.sample_rate", 44100)
|
|
assert cfg.config["audio"]["sample_rate"] == 44100
|
|
|
|
# Also readable via .get
|
|
assert cfg.get("audio.sample_rate") == 44100
|
|
|
|
|
|
# ── missing key returns default ─────────────────────────────────────
|
|
|
|
|
|
def test_missing_key_returns_default(cfg):
|
|
"""Accessing a nonexistent key should return the supplied default."""
|
|
assert cfg.get("nonexistent.path", "fallback") == "fallback"
|
|
assert cfg.get("also.missing") is None # default default is None
|
|
|
|
|
|
# ── nested set creates intermediate dicts ───────────────────────────
|
|
|
|
|
|
def test_nested_set_creates_path(cfg):
|
|
"""Setting a deeply nested key should create all intermediate dicts."""
|
|
cfg.config = {}
|
|
cfg.set("a.b.c.d", 42)
|
|
|
|
assert cfg.config["a"]["b"]["c"]["d"] == 42
|
|
assert cfg.get("a.b.c.d") == 42
|
|
|
|
|
|
# ── save and reload round-trip ──────────────────────────────────────
|
|
|
|
|
|
def test_save_and_reload(tmp_path):
|
|
"""Values persisted via save() should survive a fresh Config load."""
|
|
config_file = str(tmp_path / "roundtrip.yaml")
|
|
|
|
# Create and populate
|
|
cfg1 = Config(config_path=config_file)
|
|
cfg1.set("user.name", "TestUser")
|
|
cfg1.set("transcription.model", "tiny.en")
|
|
|
|
# Load a fresh instance from the same file
|
|
cfg2 = Config(config_path=config_file)
|
|
assert cfg2.get("user.name") == "TestUser"
|
|
assert cfg2.get("transcription.model") == "tiny.en"
|