109 lines
3.3 KiB
Go
109 lines
3.3 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||
|
||
package reader
|
||
|
||
import (
|
||
"reflect"
|
||
"testing"
|
||
"time"
|
||
|
||
"git.stormux.org/storm/fenrir/internal/applicationoverrides"
|
||
"git.stormux.org/storm/fenrir/internal/command"
|
||
"git.stormux.org/storm/fenrir/internal/presentation"
|
||
"git.stormux.org/storm/fenrir/internal/screen"
|
||
)
|
||
|
||
func TestApplicationComposerCursorFeedback(t *testing.T) {
|
||
for _, mode := range []string{"left", "right", "status redraw", "leave review", "passive", "cursor off", "automatic off", "outside input", "edited input", "other adapter"} {
|
||
t.Run(mode, func(t *testing.T) {
|
||
r := New()
|
||
r.Configure_review(true, true, true, true)
|
||
before := fixture("Working", "› hello")
|
||
before.X, before.Y = 7, 1
|
||
frame := applicationoverrides.Frame{Recognized: true, OwnsPresentation: true, InputCursor: true, Input: &screen.Region{Left: 2, Top: 1, Right: 19, Bottom: 1}}
|
||
r.Update_application(before, frame)
|
||
next := fixture("Working", "› hello")
|
||
next.X, next.Y = 6, 1
|
||
want := []presentation.Message{presentation.Character_message('o')}
|
||
if mode == "right" {
|
||
before.X = 5
|
||
r.Update_application(before, frame)
|
||
}
|
||
if mode == "status redraw" {
|
||
copy(next.Line(0), []rune("Reading file"))
|
||
}
|
||
if mode == "leave review" {
|
||
r.Command(command.CurrentLine)
|
||
}
|
||
if mode != "passive" {
|
||
r.Note_input(true, false, false)
|
||
}
|
||
switch mode {
|
||
case "passive":
|
||
want = nil
|
||
case "cursor off":
|
||
r.Configure(true, false)
|
||
want = nil
|
||
case "automatic off":
|
||
r.Configure(false, true)
|
||
want = nil
|
||
case "outside input":
|
||
next.Y = 0
|
||
want = nil
|
||
case "edited input":
|
||
next.Line(1)[2] = 'X'
|
||
want = nil
|
||
case "other adapter":
|
||
frame.InputCursor = false
|
||
want = nil
|
||
}
|
||
if got := r.Update_application(next, frame); !reflect.DeepEqual(got, want) {
|
||
t.Fatal(mode, got, want)
|
||
}
|
||
if mode == "leave review" && r.review.Active() {
|
||
t.Fatal("direct navigation remained in detached review")
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func TestApplicationActivityUsesSoundTimerWithoutScreenRedraws(t *testing.T) {
|
||
r := New()
|
||
r.Configure_progress(true)
|
||
r.Configure(false, false) // Working cues are independent of speech/automatic reading.
|
||
s := fixture("Working", "› ")
|
||
frame := applicationoverrides.Frame{Recognized: true, OwnsPresentation: true, Activity: true}
|
||
r.Update_application(s, frame)
|
||
now := time.Now()
|
||
for _, elapsed := range []time.Duration{0, 4 * time.Second, 8 * time.Second} {
|
||
if value, ok := r.Next_progress(now.Add(elapsed)); !ok || value != 50 {
|
||
t.Fatal(elapsed, value, ok)
|
||
}
|
||
if _, ok := r.Next_progress(now.Add(elapsed + 3999*time.Millisecond)); ok {
|
||
t.Fatal("activity flooded")
|
||
}
|
||
}
|
||
frame.Activity = false
|
||
r.Update_application(s, frame)
|
||
if r.Progress_active() {
|
||
t.Fatal("idle retained activity")
|
||
}
|
||
if _, ok := r.Next_progress(now.Add(12 * time.Second)); ok {
|
||
t.Fatal("idle beeped")
|
||
}
|
||
frame.Activity = true
|
||
r.Configure_progress(false)
|
||
r.Update_application(s, frame)
|
||
if _, ok := r.Next_progress(now.Add(16 * time.Second)); ok {
|
||
t.Fatal("progress toggle ignored")
|
||
}
|
||
r.Configure_progress(true)
|
||
r.Update_application(s, frame)
|
||
s.Active = false
|
||
r.Update_application(s, frame)
|
||
if _, ok := r.Next_progress(now.Add(20 * time.Second)); ok {
|
||
t.Fatal("inactive terminal beeped")
|
||
}
|
||
}
|