162 lines
5.7 KiB
Go
162 lines
5.7 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package atspi
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
func headerTestSnapshot() (Snapshot, ObjectID) {
|
|
return Snapshot{BusName: ":1.42", Path: "/cell", TablePath: "/sheet", Role: "table cell",
|
|
ApplicationProcess: "soffice.bin", TablePositionKnown: true, TableRowIndex: 2, TableColumnIndex: 3,
|
|
LibreOffice: &LibreOfficeContext{Cell: true, InSpreadsheet: true, Document: NewObjectID(":1.42", "/document"), SheetName: "Example"}}, NewObjectID(":1.42", "/window")
|
|
}
|
|
|
|
func TestLibreOfficeHeadersScopeLifetimeAndIndependentAxes(t *testing.T) {
|
|
adapter := New()
|
|
snapshot, window := headerTestSnapshot()
|
|
key, _ := libreOfficeHeaderIdentity(snapshot, window)
|
|
if err := adapter.ConfigureLibreOfficeHeader(snapshot, window, true, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := adapter.ConfigureLibreOfficeHeader(snapshot, window, false, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
choice := adapter.libreOfficeHeaders.get(key)
|
|
if !choice.rowSet || choice.row != 2 || !choice.columnSet || choice.column != 3 {
|
|
t.Fatalf("choice = %+v", choice)
|
|
}
|
|
snapshot.TablePath = "/recreated-sheet-table"
|
|
recreated, _ := libreOfficeHeaderIdentity(snapshot, window)
|
|
if adapter.libreOfficeHeaders.get(recreated) != choice {
|
|
t.Fatal("sheet switch lost the document choice")
|
|
}
|
|
for _, other := range []libreOfficeHeaderKey{
|
|
{NewObjectID(":1.42", "/other-window"), key.document, key.sheet},
|
|
{key.window, NewObjectID(":1.42", "/other-document"), key.sheet},
|
|
{key.window, key.document, "Other"},
|
|
{NewObjectID(":1.43", "/window"), NewObjectID(":1.43", "/document"), "Example"},
|
|
} {
|
|
if got := adapter.libreOfficeHeaders.get(other); got.rowSet || got.columnSet {
|
|
t.Fatalf("headers crossed identity: %+v", other)
|
|
}
|
|
}
|
|
if err := adapter.ConfigureLibreOfficeHeader(snapshot, window, true, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := adapter.libreOfficeHeaders.get(key); got.rowSet || !got.columnSet {
|
|
t.Fatalf("clearing one axis changed the other: %+v", got)
|
|
}
|
|
// Locking retires output/native focus, but document choices survive.
|
|
adapter.SetSecureInputActive(true)
|
|
if err := adapter.ConfigureLibreOfficeHeader(snapshot, window, true, false); err == nil {
|
|
t.Fatal("configuration accepted while locked")
|
|
}
|
|
adapter.SetSecureInputActive(false)
|
|
if !adapter.libreOfficeHeaders.get(key).columnSet {
|
|
t.Fatal("lock discarded the document choice")
|
|
}
|
|
adapter.libreOfficeHeaders.forget(NewObjectID(":1.42", "/other-window"))
|
|
if !adapter.libreOfficeHeaders.get(key).columnSet {
|
|
t.Fatal("unrelated destruction discarded choice")
|
|
}
|
|
for _, id := range []ObjectID{key.document, key.window} {
|
|
if err := adapter.ConfigureLibreOfficeHeader(snapshot, window, false, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
adapter.libreOfficeHeaders.forget(id)
|
|
if got := adapter.libreOfficeHeaders.get(key); got.rowSet || got.columnSet {
|
|
t.Fatalf("destruction retained choice: %+v", id)
|
|
}
|
|
}
|
|
_ = adapter.ConfigureLibreOfficeHeader(snapshot, window, false, false)
|
|
adapter.libreOfficeHeaders.reset()
|
|
if len(adapter.libreOfficeHeaders.choices) != 0 {
|
|
t.Fatal("shutdown retained choices")
|
|
}
|
|
_ = adapter.ConfigureLibreOfficeHeader(snapshot, window, true, false)
|
|
adapter.libreOfficeHeaders.forget(NewObjectID(":1.42", "/other-window"))
|
|
if !adapter.libreOfficeHeaders.get(key).rowSet {
|
|
t.Fatal("unrelated tab changes retired choice")
|
|
}
|
|
adapter.libreOfficeHeaders.forget(window)
|
|
if adapter.libreOfficeHeaders.get(key).rowSet {
|
|
t.Fatal("sheet topology change retained choice")
|
|
}
|
|
}
|
|
|
|
func TestLibreOfficeHeadersRejectInvalidContextAndBoundChoices(t *testing.T) {
|
|
for _, invalid := range []string{"process", "editor", "defunct", "position", "negative", "document", "sheet", "bus", "window"} {
|
|
snapshot, window := headerTestSnapshot()
|
|
switch invalid {
|
|
case "process":
|
|
snapshot.ApplicationProcess = "chromium"
|
|
case "editor":
|
|
snapshot.Role = "paragraph"
|
|
case "defunct":
|
|
snapshot.Defunct = true
|
|
case "position":
|
|
snapshot.TablePositionKnown = false
|
|
case "negative":
|
|
snapshot.TableColumnIndex = -1
|
|
case "document":
|
|
snapshot.LibreOffice.Document = ObjectID{}
|
|
case "sheet":
|
|
snapshot.LibreOffice.SheetName = ""
|
|
case "bus":
|
|
window.BusName = ":1.43"
|
|
case "window":
|
|
window = ObjectID{}
|
|
}
|
|
adapter := New()
|
|
if err := adapter.ConfigureLibreOfficeHeader(snapshot, window, true, false); err == nil {
|
|
t.Fatalf("accepted invalid %s context", invalid)
|
|
}
|
|
}
|
|
adapter := New()
|
|
snapshot, window := headerTestSnapshot()
|
|
for index := 0; index < 65; index++ {
|
|
snapshot.LibreOffice.SheetName = fmt.Sprintf("Sheet%d", index)
|
|
err := adapter.ConfigureLibreOfficeHeader(snapshot, window, true, false)
|
|
if (err != nil) != (index == 64) {
|
|
t.Fatalf("bounded choice %d: %v", index, err)
|
|
}
|
|
}
|
|
snapshot.LibreOffice.SheetName = "Sheet0"
|
|
if err := adapter.ConfigureLibreOfficeHeader(snapshot, window, true, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
snapshot.LibreOffice.SheetName = "Sheet64"
|
|
if err := adapter.ConfigureLibreOfficeHeader(snapshot, window, true, false); err != nil {
|
|
t.Fatal("clear did not free capacity:", err)
|
|
}
|
|
}
|
|
|
|
func TestLibreOfficeHeadersConcurrentCaptureAndCommands(t *testing.T) {
|
|
adapter := New()
|
|
snapshot, window := headerTestSnapshot()
|
|
key, _ := libreOfficeHeaderIdentity(snapshot, window)
|
|
var workers sync.WaitGroup
|
|
for index := 0; index < 3; index++ {
|
|
workers.Add(1)
|
|
go func(index int) {
|
|
defer workers.Done()
|
|
for count := 0; count < 100; count++ {
|
|
switch index {
|
|
case 0:
|
|
_ = adapter.ConfigureLibreOfficeHeader(snapshot, window, true, count%2 == 0)
|
|
case 1:
|
|
_ = adapter.libreOfficeHeaders.get(key)
|
|
case 2:
|
|
adapter.libreOfficeHeaders.forget(window)
|
|
}
|
|
}
|
|
}(index)
|
|
}
|
|
workers.Wait()
|
|
}
|