Files
talk/test/doctor_test.go
T
m3ta-chironandClaude Fable 5.1 df9a9b30cf feat(cli): doctor, test, voices, setup — Einrichtung und Diagnose ohne TUI
Usability-Schicht für Nutzer, die kein Terminal-Handbuch lesen wollen:

- `talk doctor`: eine Zeile je Prüfpunkt mit klarem Satz, was Sache ist und
  was zu tun wäre — Config (kaputt → ✘, die übrigen Prüfungen laufen mit
  Defaults weiter), Daemon (läuft / startet beim nächsten Sprechbefehl /
  fremder Dienst auf dem Port → ✘ mit Port-Hinweis), Audio (oto-Kontext
  wirklich initialisieren; null → ⚠), jede Provider-Stufe (Key-Env-Name,
  Endpunkt, Default-Stimme; OS-Stimme nennt den gefundenen Mechanismus),
  Mute (an → ⚠ mit unmute-Hinweis), Gesetze inkl. gerade aktiver Ruhezeit.
  --probe macht echte Synthese-Proben, --json liefert die Liste. Exit 0
  ohne ✘. Windows-Konsolen bekommen [OK]/[WARN]/[FAIL].
- `talk test`: Testsatz direkt über den Sprech-Kern (nicht über den
  Daemon), nennt die Stufe, die wirklich gesprochen hat, Synthese- und
  Wiedergabezeit; Mute/Ruhezeit gelten bewusst nicht, Mute wird genannt.
- `talk voices`: kuratierter Katalog mit Namen (ElevenLabs-Premade, OpenAI,
  Edge-Neural de/en-Locales) als Tabelle, „*“ = effektive Default-Stimme
  (Config vor Repo-Default), Config-IDs außerhalb des Katalogs als eigene
  Zeile, Filter --provider/--lang, --json.
- `talk setup`: wenige Fragen statt Bubble Tea — Keys nur als Hinweis
  (ohne Key läuft die Edge-Stimme), Stimme je Sprache aus dem Katalog mit
  Probehören, Ruhezeit; schreibt die config.toml zusammengeführt mit
  bestehenden Werten (.bak), spricht einen Testsatz. q bricht ab, bevor
  etwas geschrieben wird; ohne Terminal keine Fragen, nur die wirksame
  Konfiguration.

Unterbau: provider.Catalog/VoiceName/DefaultVoice, Chain.SpeakOutcome
(Stufe, Bytes, Zeiten) durch speak.Engine bis in Daemon-Log und test,
audio.Check (oto-Initialisierung ohne Ton), config.Path,
OSBuiltin.Describe. README: Abschnitt „Erste Schritte“.

Tests: voices-Zeilen (Default-Markierung, Config-Override, Filter, JSON),
doctor (ohne Daemon, Mute/Key via JSON, fremder Dienst → Exit 1, kaputte
Config → ✘ aber vollständiger Bericht), test (fake espeak), setup
(stdin-Antworten → config.toml-Inhalt, Merge mit .bak, Abbruch schreibt
nichts, Pipe stellt keine Fragen), Prozessgrenze: doctor/--probe/voices/
test gegen echten Daemon.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-24 10:08:44 +02:00

41 lines
1.3 KiB
Go

package test
// Prozessgrenzen-Tests für die Diagnose-Befehle gegen einen echten Daemon.
import (
"strings"
"testing"
)
// TestDoctorMitDaemon: Läuft der Daemon, ist er ✔ mit Version und Log-
// Pfad; voices und test funktionieren als Prozess.
func TestDoctorMitDaemon(t *testing.T) {
root := t.TempDir()
fake := newFakeProvider(t, 0)
d := startDaemon(t, root, fake.srv.URL, nil)
env := daemonEnv(root, d.port, fake.srv.URL, nil)
res := runTalk(t, env, "doctor")
if res.code != 0 {
t.Fatalf("talk doctor: Exit %d\n%s\n%s", res.code, res.stdout, res.stderr)
}
for _, want := range []string{"✔ Daemon", "läuft unter " + d.baseURL, "daemon.log", "✔ elevenlabs", "Key gesetzt"} {
if !strings.Contains(res.stdout, want) {
t.Errorf("doctor ohne %q:\n%s", want, res.stdout)
}
}
res = runTalk(t, env, "doctor", "--probe")
if res.code != 0 || !strings.Contains(res.stdout, "Probe ok") {
t.Errorf("doctor --probe: Exit %d\n%s", res.code, res.stdout)
}
fake.waitArrived(t, 1)
if res := runTalk(t, env, "voices"); res.code != 0 || !strings.HasPrefix(res.stdout, "PROVIDER") {
t.Errorf("talk voices: Exit %d, stdout %q", res.code, res.stdout)
}
if res := runTalk(t, env, "test"); res.code != 0 || !strings.Contains(res.stdout, "provider: elevenlabs") {
t.Errorf("talk test: Exit %d, stdout %q, stderr %q", res.code, res.stdout, res.stderr)
}
}