Files
cthulhu/internal/review/document_caret_editable_test.go

110 lines
3.7 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package review
import (
"context"
"strings"
"testing"
"time"
"unicode/utf8"
"git.stormux.org/storm/cthulhu/internal/atspi"
)
func editable_caret_cursor(t *testing.T) (*DocumentCursor, caretTextReader) {
t.Helper()
reader := caretTextReader{
webID("/before"): "Suggested wording",
webID("/editor"): "\ufffc\ufffc",
webID("/first"): "Review the code.\nReport actionable issues.",
webID("/second"): "Explain the evidence.",
webID("/secret"): "Private fixture text",
webID("/after"): "Following paragraph",
}
node := func(path, role string, editable bool, children ...string) atspi.TreeNode {
snapshot := atspi.NewSnapshot(path, "", role, "", "")
snapshot.BusName = webID(path).BusName
snapshot.Editable = editable
snapshot.CharacterCount = utf8.RuneCountInString(reader[webID(path)])
result := atspi.TreeNode{Snapshot: snapshot}
for _, child := range children {
result.Children = append(result.Children, webID(child))
}
return result
}
tree, err := atspi.NewAccessibleTree(webID("/doc"), []atspi.TreeNode{
node("/doc", "document web", false, "/before", "/editor", "/password", "/after"),
node("/before", "static", false),
node("/editor", "entry", true, "/paragraph", "/second"),
node("/paragraph", "paragraph", true, "/first"),
node("/first", "static", true),
node("/second", "static", true),
node("/password", "password text", true, "/secret"),
// Even a provider which omits editable state on a password child
// must not expose that child's text through browse navigation.
node("/secret", "static", false),
node("/after", "static", false),
})
if err != nil {
t.Fatal(err)
}
cursor, err := NewDocumentCursor(tree)
if err != nil {
t.Fatal(err)
}
if _, err := cursor.SyncFocus(context.Background(), webID("/before")); err != nil {
t.Fatal(err)
}
return cursor, reader
}
func TestDocumentCaretReadsEditableDescendants(t *testing.T) {
ctx := context.Background()
cursor, reader := editable_caret_cursor(t)
for _, step := range []struct {
command DocumentCaretCommand
want string
}{
{CaretNextLine, "Review the code."},
{CaretNextLine, "Report actionable issues."},
{CaretNextLine, "Explain the evidence."},
{CaretNextLine, "Following paragraph"},
{CaretPreviousLine, "Explain the evidence."},
{CaretPreviousLine, "Report actionable issues."},
{CaretLineStart, "R"},
{CaretNextCharacter, "e"},
{CaretNextWord, "Report"},
{CaretPreviousLine, "Review the code."},
{CaretPreviousLine, "Suggested wording"},
} {
move, err := cursor.MoveCaret(ctx, reader, step.command)
if err != nil || !move.Moved || strings.TrimSpace(move.Text) != step.want {
t.Fatalf("%s: %q at %s, moved %t, %v; want %q", step.command, move.Text,
move.Position.Snapshot.Path, move.Moved, err, step.want)
}
}
}
func TestReadAllIncludesEditableDescendants(t *testing.T) {
cursor, reader := editable_caret_cursor(t)
capturer := &readAllCapturer{tree: cursor.tree, caretTextReader: reader}
worker, err := NewWorker(capturer, time.Second)
if err != nil {
t.Fatal(err)
}
worker.SyncFocus(webID("/before"))
result := worker.readAll(context.Background(), cursor)
want := []string{"Suggested wording", "Review the code.", "Report actionable issues.", "Explain the evidence.", "Following paragraph"}
if result.Err != nil || len(result.ReadAllLines) != len(want) {
t.Fatalf("Read All: %d lines, %v; want %d", len(result.ReadAllLines), result.Err, len(want))
}
for index, line := range result.ReadAllLines {
if got := strings.TrimSpace(line.Contents[0].Text); got != want[index] {
t.Fatalf("Read All line %d: %q; want %q", index, got, want[index])
}
}
}