Files
agentu/internal/tui/app_test.go
T
loveuer a431d1ec95 v0.0.1: agentu mvp
Add OpenAI-compatible providers, TUI, slash commands, and model switching.
Add local file tools plus optional yolo shell execution.
Document config, usage, and development workflow.
2026-06-22 22:40:38 +08:00

164 lines
4.3 KiB
Go

package tui
import (
"context"
"strings"
"testing"
tea "github.com/charmbracelet/bubbletea"
)
func TestModelRendersChatShell(t *testing.T) {
m := newModel(context.Background(), nil, Options{ModelName: "test-model", Yolo: true})
next, _ := m.Update(tea.WindowSizeMsg{Width: 100, Height: 30})
rendered := next.(model).View()
for _, want := range []string{"agentu", "test-model", "yolo tools", "light", "ctrl+j", "alt+enter"} {
if !strings.Contains(rendered, want) {
t.Fatalf("rendered view missing %q:\n%s", want, rendered)
}
}
}
func TestCtrlJInsertsInputNewline(t *testing.T) {
m := newModel(context.Background(), nil, Options{ModelName: "test-model"})
m.input.SetValue("hello")
next, _ := m.Update(tea.KeyMsg{Type: tea.KeyCtrlJ})
got := next.(model).input.Value()
if got != "hello\n" {
t.Fatalf("input value = %q", got)
}
}
func TestInputStartsAtOneLineAndGrows(t *testing.T) {
m := newModel(context.Background(), nil, Options{ModelName: "test-model"})
if got := m.input.Height(); got != 1 {
t.Fatalf("initial input height = %d", got)
}
m.input.SetValue("one\ntwo\nthree")
m.afterInputChanged()
if got := m.input.Height(); got != 3 {
t.Fatalf("multiline input height = %d", got)
}
m.input.SetValue(strings.Repeat("line\n", 20))
m.afterInputChanged()
if got := m.input.Height(); got != maxInputLines {
t.Fatalf("clamped input height = %d", got)
}
}
func TestSlashCommandSuggestions(t *testing.T) {
m := newModel(context.Background(), nil, Options{ModelName: "test-model", Yolo: true})
next, _ := m.Update(tea.WindowSizeMsg{Width: 100, Height: 30})
m = next.(model)
m.input.SetValue("/")
m.afterInputChanged()
rendered := m.View()
for _, want := range []string{"/clear reset context", "/exit quit", "/model model/provider/thinking"} {
if !strings.Contains(rendered, want) {
t.Fatalf("rendered suggestions missing %q:\n%s", want, rendered)
}
}
}
func TestModelCommand(t *testing.T) {
m := newModel(context.Background(), nil, Options{ModelName: "test-model", Yolo: true})
m.input.SetValue("/model")
next, _ := m.submit()
rendered := next.(model).renderMessages()
for _, want := range []string{"model: test-model", "mode: yolo tools", "theme: light"} {
if !strings.Contains(rendered, want) {
t.Fatalf("model command output missing %q:\n%s", want, rendered)
}
}
}
func TestModelThinkingCommand(t *testing.T) {
manager := &fakeModelManager{model: "test-model", thinking: "none"}
m := newModel(context.Background(), nil, Options{ModelName: "test-model", ModelManager: manager})
m.input.SetValue("/model thinking high")
next, _ := m.submit()
rendered := next.(model).renderMessages()
if manager.thinking != "high" {
t.Fatalf("thinking = %q", manager.thinking)
}
if !strings.Contains(rendered, "thinking: high") {
t.Fatalf("model command output missing thinking:\n%s", rendered)
}
}
type fakeModelManager struct {
provider string
model string
thinking string
}
func (f *fakeModelManager) CurrentProvider() string {
if f.provider == "" {
return "default"
}
return f.provider
}
func (f *fakeModelManager) CurrentModel() string {
return f.model
}
func (f *fakeModelManager) CurrentThinking() string {
return f.thinking
}
func (f *fakeModelManager) Info() string {
return "provider: " + f.CurrentProvider() + "\nmodel: " + f.model + "\nthinking: " + f.thinking
}
func (f *fakeModelManager) SetProvider(name string) (string, error) {
f.provider = name
return f.Info(), nil
}
func (f *fakeModelManager) SetModel(model string) (string, error) {
f.model = model
return f.Info(), nil
}
func (f *fakeModelManager) SetThinking(level string) (string, error) {
f.thinking = level
return f.Info(), nil
}
func TestParseThemeMode(t *testing.T) {
for input, want := range map[string]ThemeMode{
"": ThemeLight,
"light": ThemeLight,
"dark": ThemeDark,
"DARK": ThemeDark,
} {
got, err := ParseThemeMode(input)
if err != nil {
t.Fatalf("ParseThemeMode(%q): %v", input, err)
}
if got != want {
t.Fatalf("ParseThemeMode(%q) = %q, want %q", input, got, want)
}
}
if _, err := ParseThemeMode("sepia"); err == nil {
t.Fatal("expected invalid theme error")
}
}
func TestCleanToolLog(t *testing.T) {
got := cleanToolLog("\n[tool] shell_run {\"command\":\"pwd\"}\n")
want := `shell_run {"command":"pwd"}`
if got != want {
t.Fatalf("got %q want %q", got, want)
}
}