Files
fenrir/internal/app/codex_events_test.go

153 lines
5.0 KiB
Go

// Copyright (c) 2026 Storm Dragon
// SPDX-License-Identifier: GPL-3.0-or-later
package app
import (
"encoding/json"
"os"
"slices"
"strings"
"testing"
"time"
"git.stormux.org/storm/fenrir/internal/applicationoverrides/codex"
"git.stormux.org/storm/fenrir/internal/command"
"git.stormux.org/storm/fenrir/internal/control"
)
func TestCodexEventRoutingWholeMessagesMuteReviewAndExit(t *testing.T) {
t.Setenv("WINDOWID", "42")
a, voice := persistence_application(t, true)
a.options.TerminalMode = true
snapshot := override_screen(1, "OpenAI Codex")
override_read(t, a, snapshot)
a.select_override("codex")
override_read(t, a, snapshot)
base := codex.Event{Version: 1, Epoch: 1, Window: "42", Terminal: 1, Session: "fixture-session", Kind: "status", Status: "working"}
send := func(event codex.Event, uid int) string {
t.Helper()
encoded, err := json.Marshal(event)
if err != nil {
t.Fatal(err)
}
reply := make(chan string, 1)
a.remote_request(control.Request{UID: uid, Text: "APPLICATION CODEX " + string(encoded), Reply: reply})
return <-reply
}
other := base
other.Window = "43"
if reply := send(other, os.Geteuid()); !strings.Contains(reply, "another terminal") {
t.Fatal(reply)
}
if reply := send(base, os.Geteuid()+1); !strings.Contains(reply, "not permitted") {
t.Fatal(reply)
}
a.settings.live.Remote.EnableCommandRemote = false
if reply := send(base, os.Geteuid()); !strings.Contains(reply, "disabled") {
t.Fatal(reply)
}
a.settings.live.Remote.EnableCommandRemote = true
if reply := send(base, os.Geteuid()); reply != "" {
t.Fatal(reply)
}
a.handle_command(command.ReadLiveRegion10)
if got := voice.messages[len(voice.messages)-1]; got != "Codex working" {
t.Fatal(got)
}
message := base
message.Kind, message.ID, message.Parts, message.Text = "message", "first", 2, "Complete "
start := len(voice.messages)
if reply := send(message, os.Geteuid()); reply != "" {
t.Fatal(reply)
}
override_read(t, a, snapshot)
if len(voice.messages) != start {
t.Fatal("partial text spoken", voice.messages[start:])
}
message.Part, message.Text = 1, "message"
if reply := send(message, os.Geteuid()); reply != "" {
t.Fatal(reply)
}
override_read(t, a, snapshot)
if got := voice.messages[len(voice.messages)-1]; got != "Complete message" {
t.Fatal(got)
}
message.Part, message.Parts, message.Text = 0, 1, "Complete message"
start = len(voice.messages)
if reply := send(message, os.Geteuid()); reply != "" {
t.Fatal(reply)
}
override_read(t, a, override_screen(1, "file output and repeated streaming text"))
if len(voice.messages) != start {
t.Fatal("duplicate or tool output spoken", voice.messages[start:])
}
a.handle_command(command.Mute)
message.ID, message.Text = "muted", "Message while muted"
if reply := send(message, os.Geteuid()); reply != "" {
t.Fatal(reply)
}
override_read(t, a, snapshot)
if len(voice.messages) != start {
t.Fatal("mute bypassed")
}
a.handle_command(command.Mute)
a.handle_command(command.ReadLiveRegion1)
if got := voice.messages[len(voice.messages)-1]; got != "Message while muted" {
t.Fatal(got)
}
// Stored replies must not replace raw screen review.
a.handle_command(command.CurrentLine)
if slices.Contains(voice.messages[len(voice.messages)-1:], "Message while muted") {
t.Fatal("history replaced raw review")
}
base.Status = "closed"
if reply := send(base, os.Geteuid()); reply != "" {
t.Fatal(reply)
}
override_read(t, a, override_screen(1, "[Username@host directory] $"))
if a.overrideCurrent != nil || a.overrides[1] != nil {
t.Fatal("shell did not restore defaults")
}
}
func TestCodexWorkingToneUsesExistingSoundGates(t *testing.T) {
for _, mode := range []string{"enabled", "sound off", "progress off", "muted", "automatic off", "menu"} {
t.Run(mode, func(t *testing.T) {
a, _ := persistence_application(t, true)
snapshot := override_screen(1, "OpenAI Codex")
override_read(t, a, snapshot)
a.select_override("codex")
override_read(t, a, snapshot)
sounds := &fakeSounds{}
a.cues = sounds
a.settings.live.Presentation.Sound.Enabled = mode != "sound off"
a.settings.live.Presentation.Progress.Enabled = mode != "progress off"
a.settings.live.Reading.Automatic = mode != "automatic off"
a.configure_reader()
if mode == "muted" {
a.handle_command(command.Mute)
}
if mode == "menu" {
a.open_applications()
}
adapter := a.overrideCurrent.adapter.(*codex.Adapter)
if err := adapter.Accept(codex.Event{Version: 1, Epoch: 1, Session: "fixture-session", Kind: "status", Status: "working"}); err != nil {
t.Fatal(err)
}
override_read(t, a, snapshot)
want := mode == "enabled" || mode == "muted" || mode == "automatic off"
if (len(sounds.progress) > 0) != want {
t.Fatal(mode, sounds.progress)
}
if err := adapter.Accept(codex.Event{Version: 1, Epoch: 1, Session: "fixture-session", Kind: "status", Status: "permission"}); err != nil {
t.Fatal(err)
}
override_read(t, a, snapshot)
if _, ok := a.engine.Next_progress(time.Now().Add(2 * time.Second)); ok {
t.Fatal("approval wait retained working beep")
}
})
}
}