Files

103 lines
3.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
package codex
import (
"strings"
"testing"
"git.stormux.org/storm/fenrir/internal/command"
"git.stormux.org/storm/fenrir/internal/screen"
)
func accept_event(t *testing.T, a *Adapter, event Event) {
t.Helper()
event.Version, event.Session, event.Epoch = 1, "fixture-session", 1
if err := a.Accept(event); err != nil {
t.Fatal(err)
}
}
func TestCompleteChunksDeduplicationHistoryAndStatus(t *testing.T) {
a := &Adapter{}
accept_event(t, a, Event{Kind: "status", Status: "working"})
accept_event(t, a, Event{Kind: "message", ID: "first", Text: "Whole ", Parts: 2})
if frame := a.Observe(screen.Snapshot{}); len(frame.Updates) != 0 {
t.Fatal("partial message spoken")
}
accept_event(t, a, Event{Kind: "message", ID: "first", Text: "reply", Part: 1, Parts: 2})
frame := a.Observe(screen.Snapshot{})
if !frame.OwnsPresentation || len(frame.Updates) != 1 || frame.Updates[0].Text != "Whole reply" {
t.Fatal(frame)
}
accept_event(t, a, Event{Kind: "message", ID: "first", Text: "Whole reply", Parts: 1})
if len(a.Observe(screen.Snapshot{}).Updates) != 0 {
t.Fatal("duplicate spoken")
}
accept_event(t, a, Event{Kind: "message", ID: "second", Text: "Old reply", Parts: 1, Baseline: true})
if len(a.Observe(screen.Snapshot{}).Updates) != 0 {
t.Fatal("baseline spoken")
}
if got, _ := a.Command(command.ReadLiveRegion1); got.Text != "Old reply" {
t.Fatal(got)
}
if got, _ := a.Command(command.ReadLiveRegion2); got.Text != "Whole reply" {
t.Fatal(got)
}
if got, _ := a.Command(command.ReadLiveRegion10); got.Text != "Codex working" {
t.Fatal(got)
}
a.Reset()
if got, _ := a.Command(command.ReadLiveRegion2); got.Text != "Whole reply" {
t.Fatal("suspension lost history")
}
accept_event(t, a, Event{Kind: "status", Status: "closed"})
if a.Observe(screen.Snapshot{}).Recognized {
t.Fatal("exit retained presentation ownership")
}
}
func TestRejectInterleavedSessionOutOfOrderAndOversize(t *testing.T) {
a := &Adapter{}
accept_event(t, a, Event{Kind: "status", Status: "idle"})
if err := a.Accept(Event{Version: 1, Epoch: 1, Session: "another-session", Kind: "status", Status: "working"}); err == nil {
t.Fatal("another session attached")
}
if err := a.Accept(Event{Version: 1, Epoch: 1, Session: "fixture-session", Kind: "message", ID: "test", Part: 1, Parts: 2, Text: "tail"}); err == nil {
t.Fatal("out of order accepted")
}
if err := a.Accept(Event{Version: 1, Epoch: 1, Session: "fixture-session", Kind: "message", ID: "test", Parts: 1, Text: strings.Repeat("x", 6001)}); err == nil {
t.Fatal("oversize chunk accepted")
}
}
func TestConversationSwitchRejectsPreviousFollower(t *testing.T) {
a := &Adapter{}
accept_event(t, a, Event{Kind: "status", Status: "working"})
accept_event(t, a, Event{Kind: "message", ID: "old", Text: "Previous conversation", Parts: 1})
if err := a.Accept(Event{Version: 1, Epoch: 2, Session: "new-session", Kind: "status", Status: "idle"}); err != nil {
t.Fatal(err)
}
if len(a.history) != 0 || len(a.pending) != 0 {
t.Fatal("conversation history leaked")
}
if err := a.Accept(Event{Version: 1, Epoch: 1, Session: "fixture-session", Kind: "status", Status: "working"}); err == nil {
t.Fatal("old follower replaced new conversation")
}
}
func TestInputLimitedToComposer(t *testing.T) {
a := &Adapter{}
s := screen.Snapshot{Active: true, Rows: 8, Cols: 40, X: 5, Y: 6, Cells: []rune(strings.Repeat(" ", 320))}
copy(s.Line(6), []rune("› hello"))
frame := a.Observe(s)
if frame.Input == nil || frame.Input.Top != 6 || frame.Input.Left != 2 {
t.Fatal(frame.Input)
}
s.Y = 2
if a.Observe(s).Input != nil {
t.Fatal("transcript treated as composer")
}
}