okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

dawntui: replace the generic /quota page with a screen of latest limits, bars and per-limit trails8e3e173

main
4.2 KiB157 linesraw
1package tui
2
3import (
4	"albedo/cli/internal/daemon"
5	"strings"
6	"testing"
7
8	tea "charm.land/bubbletea/v2"
9	"github.com/charmbracelet/x/ansi"
10)
11
12func dispatchCmd(app *AppModel, cmd tea.Cmd) *AppModel {
13	if cmd == nil {
14		return app
15	}
16	msg := cmd()
17	if batch, ok := msg.(tea.BatchMsg); ok {
18		for _, sub := range batch {
19			if sub != nil {
20				app = dispatchCmd(app, sub)
21			}
22		}
23		return app
24	}
25	if msg != nil {
26		updated, next := app.Update(msg)
27		app = updated.(*AppModel)
28		if next != nil {
29			app = dispatchCmd(app, next)
30		}
31	}
32	return app
33}
34
35func newTestApp(t *testing.T) *AppModel {
36	t.Helper()
37	conn := daemon.NewConnection(daemon.ConnectionSnapshot{Port: 1}, nil)
38	session := &daemon.Session{ID: "test-session", Model: "test-model"}
39	app := NewAppModel(conn, Bootstrap{}, session, "", false, nil)
40	t.Cleanup(app.Chat.Close)
41	app.Update(tea.WindowSizeMsg{Width: 100, Height: 30})
42	return app
43}
44
45func TestQuotaRouteFromChat(t *testing.T) {
46	app := newTestApp(t)
47	if app.State != AppStateChat {
48		t.Fatalf("expected initial state AppStateChat, got %v", app.State)
49	}
50
51	app.Chat.TextArea.SetValue("/quota")
52	updated, cmd := app.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
53	app = updated.(*AppModel)
54	app = dispatchCmd(app, cmd)
55
56	if app.State != AppStateQuota {
57		t.Fatalf("submitting /quota should reach AppStateQuota, got %v", app.State)
58	}
59
60	view := ansi.Strip(app.View().Content)
61	if !strings.Contains(view, "/quota") {
62		t.Fatalf("view should contain /quota title, got:\n%s", view)
63	}
64}
65
66func TestQuotaRouteEscapeReturnsToChat(t *testing.T) {
67	app := newTestApp(t)
68	app.Chat.TextArea.SetValue("/quota")
69	updated, cmd := app.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
70	app = updated.(*AppModel)
71	app = dispatchCmd(app, cmd)
72
73	if app.State != AppStateQuota {
74		t.Fatalf("failed to enter AppStateQuota: %v", app.State)
75	}
76
77	updated, cmd = app.Update(tea.KeyPressMsg{Code: tea.KeyEscape})
78	app = updated.(*AppModel)
79	app = dispatchCmd(app, cmd)
80
81	if app.State != AppStateChat {
82		t.Fatalf("esc from quota screen should return to AppStateChat, got %v", app.State)
83	}
84}
85
86func TestQuotaRouteWindowResize(t *testing.T) {
87	app := newTestApp(t)
88	app.Chat.TextArea.SetValue("/quota")
89	updated, cmd := app.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
90	app = updated.(*AppModel)
91	app = dispatchCmd(app, cmd)
92
93	if app.State != AppStateQuota {
94		t.Fatalf("failed to enter AppStateQuota: %v", app.State)
95	}
96
97	updated, _ = app.Update(tea.WindowSizeMsg{Width: 120, Height: 45})
98	app = updated.(*AppModel)
99
100	if app.Quota.Width != 120 || app.Quota.Height != 45 {
101		t.Fatalf("window resize did not resize QuotaModel: got (%d, %d), want (120, 45)", app.Quota.Width, app.Quota.Height)
102	}
103}
104
105func TestQuotaRouteStaleGenerationIgnored(t *testing.T) {
106	app := newTestApp(t)
107	app.Chat.TextArea.SetValue("/quota")
108	updated, cmd := app.Update(tea.KeyPressMsg{Code: tea.KeyEnter})
109	app = updated.(*AppModel)
110	app = dispatchCmd(app, cmd)
111
112	if app.State != AppStateQuota {
113		t.Fatalf("failed to enter AppStateQuota: %v", app.State)
114	}
115
116	currentGen := app.Quota.Generation
117	staleGen := currentGen - 1
118	reading := daemon.QuotaObservation{
119		Provider:  "test-provider",
120		AccountID: "test-account",
121		LimitID:   "test-limit",
122		Label:     "Test Limit",
123	}
124
125	// Send stale generation reply
126	updated, _ = app.Update(quotaLoadedMsg{
127		Gen:      staleGen,
128		Readings: []daemon.QuotaObservation{reading},
129	})
130	app = updated.(*AppModel)
131
132	if len(app.Quota.readings) != 0 {
133		t.Fatalf("stale generation reply modified Quota.readings: got %d readings, want 0", len(app.Quota.readings))
134	}
135
136	// Send matching generation reply
137	updated, _ = app.Update(quotaLoadedMsg{
138		Gen:      currentGen,
139		Readings: []daemon.QuotaObservation{reading},
140	})
141	app = updated.(*AppModel)
142
143	if len(app.Quota.readings) != 1 {
144		t.Fatalf("valid generation reply did not populate Quota.readings: got %d readings, want 1", len(app.Quota.readings))
145	}
146
147	// Send another stale reply with empty readings; it must not overwrite the existing reading
148	updated, _ = app.Update(quotaLoadedMsg{
149		Gen:      staleGen,
150		Readings: []daemon.QuotaObservation{},
151	})
152	app = updated.(*AppModel)
153
154	if len(app.Quota.readings) != 1 {
155		t.Fatalf("stale generation reply cleared existing Quota.readings: got %d readings, want 1", len(app.Quota.readings))
156	}
157}