153 lines
5.0 KiB
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")
|
|
}
|
|
})
|
|
}
|
|
}
|