129 lines
4.7 KiB
Go
129 lines
4.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"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/atspi"
|
|
)
|
|
|
|
func TestTableNavigationSpansHeadersAndBoundaries(t *testing.T) {
|
|
node := func(path, role, name string, children ...string) atspi.TreeNode {
|
|
s := atspi.NewSnapshot(path, name, role, "", "")
|
|
s.BusName = webID(path).BusName
|
|
n := atspi.TreeNode{Snapshot: s}
|
|
for _, child := range children {
|
|
n.Children = append(n.Children, webID(child))
|
|
}
|
|
return n
|
|
}
|
|
nodes := []atspi.TreeNode{node("/doc", "document web", "", "/table", "/outside"), node("/table", "table", "", "/a", "/b", "/c", "/d", "/e"), node("/outside", "paragraph", "Outside")}
|
|
nodes[1].Snapshot.TableRowCount, nodes[1].Snapshot.TableColumnCount = 3, 2
|
|
for _, c := range []struct {
|
|
path, name string
|
|
row, col, rs, cs int
|
|
}{{"/a", "A", 0, 0, 1, 1}, {"/b", "B", 0, 1, 1, 1}, {"/c", "Merged", 1, 0, 1, 2}, {"/d", "D", 2, 0, 1, 1}, {"/e", "", 2, 1, 1, 1}} {
|
|
n := node(c.path, "table cell", c.name)
|
|
n.Snapshot.TablePositionKnown = true
|
|
n.Snapshot.TableRowIndex, n.Snapshot.TableColumnIndex = c.row, c.col
|
|
n.Snapshot.TableRowSpan, n.Snapshot.TableColumnSpan = c.rs, c.cs
|
|
if c.col == 1 {
|
|
n.Snapshot.TableColumnHeaders = "Second"
|
|
}
|
|
nodes = append(nodes, n)
|
|
}
|
|
tree, err := atspi.NewAccessibleTree(webID("/doc"), nodes)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cursor, _ := NewDocumentCursor(tree)
|
|
cursor.SyncFocus(context.Background(), webID("/table"))
|
|
for _, step := range []struct {
|
|
command DocumentCaretCommand
|
|
path, text string
|
|
moved bool
|
|
}{
|
|
{TableFirst, "/a", "Row 1, column 1.", true},
|
|
{TableRight, "/b", "Second B", true},
|
|
{TableDown, "/c", "Spans 2 columns.", true},
|
|
{TableDown, "/e", "blank Row 3, column 2.", true},
|
|
{TableUp, "/c", "Merged", true},
|
|
{TableUp, "/b", "B", true},
|
|
{TableUp, "/b", "Top of column.", false},
|
|
{TableRight, "/b", "End of row.", false},
|
|
{TableLast, "/e", "blank", true},
|
|
{TableDown, "/e", "Bottom of column.", false},
|
|
{TableFirst, "/a", "A", true},
|
|
{TableLeft, "/a", "Beginning of row.", false},
|
|
} {
|
|
got, err := cursor.MoveCaret(context.Background(), caretTextReader{}, step.command)
|
|
if err != nil || got.Moved != step.moved || got.Position.Object.ID() != webID(step.path) || !strings.Contains(got.Text, step.text) {
|
|
t.Fatalf("command %v: %+v, %v", step.command, got, err)
|
|
}
|
|
}
|
|
cursor.SyncFocus(context.Background(), webID("/outside"))
|
|
got, err := cursor.MoveCaret(context.Background(), caretTextReader{}, TableRight)
|
|
if err != nil || got.Moved || got.Text != "Not in a table." {
|
|
t.Fatalf("outside: %+v %v", got, err)
|
|
}
|
|
}
|
|
|
|
func TestTableNavigationRowSpanAndNestedTable(t *testing.T) {
|
|
makeNode := func(path, role string, children ...string) atspi.TreeNode {
|
|
s := atspi.NewSnapshot(path, path, role, "", "")
|
|
s.BusName = webID(path).BusName
|
|
n := atspi.TreeNode{Snapshot: s}
|
|
for _, child := range children {
|
|
n.Children = append(n.Children, webID(child))
|
|
}
|
|
return n
|
|
}
|
|
doc := makeNode("/doc", "document web", "/table")
|
|
table := makeNode("/table", "table", "/a", "/b", "/c")
|
|
table.Snapshot.TableRowCount, table.Snapshot.TableColumnCount = 2, 2
|
|
a := makeNode("/a", "table cell", "/nested")
|
|
b := makeNode("/b", "table cell")
|
|
c := makeNode("/c", "table cell")
|
|
for _, n := range []*atspi.TreeNode{&a, &b, &c} {
|
|
n.Snapshot.TablePositionKnown = true
|
|
n.Snapshot.TableRowSpan = 1
|
|
n.Snapshot.TableColumnSpan = 1
|
|
}
|
|
a.Snapshot.TableRowSpan = 2
|
|
b.Snapshot.TableColumnIndex = 1
|
|
c.Snapshot.TableRowIndex = 1
|
|
c.Snapshot.TableColumnIndex = 1
|
|
nested := makeNode("/nested", "table", "/inner")
|
|
nested.Snapshot.TableRowCount = 1
|
|
nested.Snapshot.TableColumnCount = 1
|
|
inner := makeNode("/inner", "table cell")
|
|
inner.Snapshot.TablePositionKnown = true
|
|
inner.Snapshot.TableRowSpan = 1
|
|
inner.Snapshot.TableColumnSpan = 1
|
|
tree, err := atspi.NewAccessibleTree(webID("/doc"), []atspi.TreeNode{doc, table, a, b, c, nested, inner})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cursor, _ := NewDocumentCursor(tree)
|
|
cursor.SyncFocus(context.Background(), webID("/c"))
|
|
for _, step := range []struct {
|
|
cmd DocumentCaretCommand
|
|
path string
|
|
}{{TableLeft, "/a"}, {TableRight, "/c"}, {TableUp, "/b"}, {TableLeft, "/a"}, {TableRight, "/b"}} {
|
|
got, err := cursor.MoveCaret(context.Background(), caretTextReader{}, step.cmd)
|
|
if err != nil || got.Position.Object.ID() != webID(step.path) {
|
|
t.Fatalf("%v: %+v %v", step.cmd, got, err)
|
|
}
|
|
}
|
|
cursor.SyncFocus(context.Background(), webID("/inner"))
|
|
got, err := cursor.MoveCaret(context.Background(), caretTextReader{}, TableRight)
|
|
if err != nil || got.Moved || got.Text != "End of row." {
|
|
t.Fatalf("nested table escaped: %+v %v", got, err)
|
|
}
|
|
}
|