116 lines
3.9 KiB
Go
116 lines
3.9 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/command"
|
|
"git.stormux.org/storm/fenrir/internal/presentation"
|
|
"git.stormux.org/storm/fenrir/internal/screen"
|
|
)
|
|
|
|
func TestDeletionEchoWithAutomaticReadingDisabled(t *testing.T) {
|
|
for _, trial := range []struct {
|
|
name, before, after string
|
|
beforeX, afterX int
|
|
want []presentation.Message
|
|
}{
|
|
{"backspace", "$ abc", "$ ab", 5, 4, []presentation.Message{presentation.Character_message('c')}},
|
|
{"delete", "$ abc", "$ ac", 3, 3, []presentation.Message{presentation.Character_message('b')}},
|
|
{"midline backspace", "$ abc", "$ ac", 4, 3, []presentation.Message{presentation.Character_message('b')}},
|
|
{"unicode", "$ café", "$ caf", 6, 5, []presentation.Message{presentation.Character_message('é')}},
|
|
{"punctuation", "$ .", "$ ", 3, 2, []presentation.Message{presentation.Character_message('.')}},
|
|
{"space", "$ ab ", "$ ab", 5, 4, []presentation.Message{presentation.Character_message(' ')}},
|
|
{"word", "$ one two", "$ one ", 9, 6, []presentation.Message{{Text: "two"}}},
|
|
{"forward word", "$ one two", "$ two", 2, 2, []presentation.Message{{Text: "one "}}},
|
|
} {
|
|
t.Run(trial.name, func(t *testing.T) {
|
|
r := New()
|
|
r.Configure(false, false)
|
|
r.Configure_echo(false, false, false)
|
|
before := fixture(trial.before, "background")
|
|
before.X = trial.beforeX
|
|
r.Update(before)
|
|
r.Command(command.CurrentLine)
|
|
r.Note_input(true, false, false)
|
|
r.Note_deletion()
|
|
// An unchanged capture and background output can precede the edit.
|
|
r.Update(before)
|
|
background := fixture(trial.before, "changed background")
|
|
background.X = trial.beforeX
|
|
if got := r.Update(background); len(got) != 0 {
|
|
t.Fatal("background output escaped autoread", got)
|
|
}
|
|
after := fixture(trial.after, "more background")
|
|
after.X = trial.afterX
|
|
if got := r.Update(after); !reflect.DeepEqual(got, trial.want) {
|
|
t.Fatal("deletion echo", got, trial.want)
|
|
}
|
|
if got := r.Update(before); len(got) != 0 {
|
|
t.Fatal("redraw spoke after deletion", got)
|
|
}
|
|
if got := r.Update(after); len(got) != 0 {
|
|
t.Fatal("deletion authorization was reused", got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeletionEchoRejectsUnconfirmedChanges(t *testing.T) {
|
|
for _, mode := range []string{"no key", "expired", "other key", "reader command", "redraw", "cursor only", "no echo", "new terminal", "new buffer", "resize", "inactive", "live region"} {
|
|
t.Run(mode, func(t *testing.T) {
|
|
r := New()
|
|
r.Configure(false, true)
|
|
before, after := fixture("$ abc", "background"), fixture("$ ab", "changed background")
|
|
before.X, after.X = 5, 4
|
|
r.Update(before)
|
|
if mode != "no key" {
|
|
r.Note_input(true, false, false)
|
|
r.Note_deletion()
|
|
}
|
|
switch mode {
|
|
case "expired":
|
|
r.progressDeletionAt = time.Now().Add(-time.Second)
|
|
case "other key":
|
|
r.Note_input(true, false, false)
|
|
case "reader command":
|
|
r.Command(command.CurrentLine)
|
|
case "redraw":
|
|
after = fixture("$ xx", "changed background")
|
|
after.X = 4
|
|
case "cursor only":
|
|
after = before
|
|
after.X = 4
|
|
case "no echo":
|
|
after = before
|
|
case "new terminal":
|
|
after.Terminal++
|
|
case "new buffer":
|
|
after.Generation++
|
|
case "resize":
|
|
after = fixture("$ ab")
|
|
after.X = 4
|
|
case "inactive":
|
|
after.Active = false
|
|
case "live region":
|
|
r.ensure_regions().live[0] = &screen.Region{Right: before.Cols - 1}
|
|
}
|
|
if got := r.Update(after); len(got) != 0 {
|
|
t.Fatal("unconfirmed or excluded deletion spoke", got)
|
|
}
|
|
if mode == "new terminal" || mode == "new buffer" || mode == "resize" || mode == "inactive" {
|
|
if got := r.Update(before); len(got) != 0 {
|
|
t.Fatal("old session spoke", got)
|
|
}
|
|
if got := r.Update(fixture("$ ab", "background")); len(got) != 0 {
|
|
t.Fatal("pending deletion survived session change", got)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|