Files
talk/cmd/talk/cli_test.go
T
m3ta-chironandClaude Fable 5.1 07c89f4939
test / test (push) Canceled after 0s
feat(cli): talk version as a subcommand
A bare `talk version` was spoken as an announcement because only the
--version flag existed. The subcommand prints the same line.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-25 12:53:30 +01:00

137 lines
4.2 KiB
Go

package main
import (
"bytes"
"io"
"strings"
"testing"
)
// wantSubcommands is the CLI surface, deliberately tested as a hard-coded
// list (not derived from the command table) so the tests fire when table and
// documentation drift apart.
var wantSubcommands = []string{
"say", "wrap", "mute", "unmute", "status", "daemon", "cancel", "uri", "voices", "test", "doctor", "setup",
}
// runCLI is the test entry into run with empty stdin (no text via pipe), the
// usual call without input.
func runCLI(argv []string, stdout, stderr io.Writer) int {
return run(argv, strings.NewReader(""), stdout, stderr)
}
func TestHelpListsAllSubcommands(t *testing.T) {
var out, errBuf bytes.Buffer
code := runCLI([]string{"--help"}, &out, &errBuf)
if code != exitOK {
t.Fatalf("--help: exit code = %d, want %d (stderr: %q)", code, exitOK, errBuf.String())
}
lines := strings.Split(out.String(), "\n")
for _, name := range wantSubcommands {
found := false
for _, ln := range lines {
if strings.HasPrefix(strings.TrimLeft(ln, " "), name+" ") {
found = true
break
}
}
if !found {
t.Errorf("--help does not list command %q (output: %q)", name, out.String())
}
}
}
func TestVersionDefault(t *testing.T) {
var out, errBuf bytes.Buffer
code := runCLI([]string{"--version"}, &out, &errBuf)
if code != exitOK {
t.Fatalf("--version: exit code = %d, want %d", code, exitOK)
}
if got, want := out.String(), "talk version dev\n"; got != want {
t.Errorf("--version output = %q, want %q", got, want)
}
}
// TestVersionSubcommand: `talk version` prints the version instead of
// speaking the word.
func TestVersionSubcommand(t *testing.T) {
var out, errBuf bytes.Buffer
if code := runCLI([]string{"version"}, &out, &errBuf); code != exitOK {
t.Fatalf("version: exit code = %d, stderr %q", code, errBuf.String())
}
if got, want := out.String(), versionString()+"\n"; got != want {
t.Errorf("version output = %q, want %q", got, want)
}
}
func TestVersionStringWithCommit(t *testing.T) {
oldCommit := commit
commit = "c0ffee1"
defer func() { commit = oldCommit }()
if got, want := versionString(), "talk version dev (c0ffee1)"; got != want {
t.Errorf("versionString() = %q, want %q", got, want)
}
}
func TestSayHelpShowsFlags(t *testing.T) {
var out, errBuf bytes.Buffer
code := runCLI([]string{"say", "--help"}, &out, &errBuf)
if code != exitOK {
t.Fatalf("talk say --help: exit code = %d, want %d", code, exitOK)
}
for _, f := range []string{"-wait", "-now", "-priority", "-voice", "-lang", "-provider"} {
if !strings.Contains(out.String(), f) {
t.Errorf("talk say --help does not show flag %s (output: %q)", f, out.String())
}
}
}
// TestWrapHelpShowsSayFlags: wrap inherits the say flags (at least --wait).
func TestWrapHelpShowsSayFlags(t *testing.T) {
var out, errBuf bytes.Buffer
code := runCLI([]string{"wrap", "--help"}, &out, &errBuf)
if code != exitOK {
t.Fatalf("talk wrap --help: exit code = %d, want %d (stderr: %q)", code, exitOK, errBuf.String())
}
for _, f := range []string{"-wait", "-provider"} {
if !strings.Contains(out.String(), f) {
t.Errorf("talk wrap --help does not show flag %s (output: %q)", f, out.String())
}
}
}
func TestHelpSubcommand(t *testing.T) {
t.Run("without argument", func(t *testing.T) {
var out, errBuf bytes.Buffer
if code := runCLI([]string{"help"}, &out, &errBuf); code != exitOK {
t.Fatalf("talk help: exit code = %d, want %d", code, exitOK)
}
for _, name := range wantSubcommands {
if !strings.Contains(out.String(), name) {
t.Errorf("talk help does not list %q", name)
}
}
})
t.Run("with command", func(t *testing.T) {
var out, errBuf bytes.Buffer
if code := runCLI([]string{"help", "mute"}, &out, &errBuf); code != exitOK {
t.Fatalf("talk help mute: exit code = %d, want %d", code, exitOK)
}
if !strings.Contains(out.String(), "talk mute") {
t.Errorf("talk help mute does not show mute's usage: %q", out.String())
}
})
}
func TestUnknownFlag(t *testing.T) {
var out, errBuf bytes.Buffer
code := runCLI([]string{"--bogus"}, &out, &errBuf)
if code != exitUsage {
t.Fatalf("talk --bogus: exit code = %d, want %d", code, exitUsage)
}
if !strings.Contains(errBuf.String(), "bogus") {
t.Errorf("talk --bogus: error message missing on stderr: %q", errBuf.String())
}
}