120 lines
4.8 KiB
Go
120 lines
4.8 KiB
Go
// Copyright (c) 2026 Storm Dragon
|
|
// Authors: Storm Dragon, Angus Kola
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
package app
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"git.stormux.org/storm/cthulhu/internal/atspi"
|
|
"git.stormux.org/storm/cthulhu/internal/braille"
|
|
"git.stormux.org/storm/cthulhu/internal/config"
|
|
"git.stormux.org/storm/cthulhu/internal/input"
|
|
"git.stormux.org/storm/cthulhu/internal/presentation"
|
|
)
|
|
|
|
func TestLibreOfficeHeaderCommandsRespectOwnershipAndGates(t *testing.T) {
|
|
event := calcTestEvent(atspi.FocusEvent, "/cell", "10", "B3")
|
|
event.Source.TableRowIndex, event.Source.TableColumnIndex = 2, 1
|
|
event.Source.LibreOffice.Document = atspi.NewObjectID(event.Source.BusName, "/document")
|
|
event.Source.LibreOffice.SheetName = "Example"
|
|
state := eventLoopState{}
|
|
state.presentationOptions = presentation.DefaultOptions()
|
|
state.current = event.Source
|
|
state.owner.follow(event)
|
|
speech := &fakeSpeechQueue{spoken: make(chan string, 8)}
|
|
gate := &focusGate{}
|
|
frames := make(chan braille.Frame, 8)
|
|
handler := eventReviewHandler{state: &state, speech: speech, focusGate: gate,
|
|
calcHeaders: atspi.New(), syncForeground: func() {}, brailleOutput: calcFrameQueue{frames}}
|
|
for _, test := range []struct {
|
|
command input.Command
|
|
want string
|
|
}{
|
|
{input.SetColumnHeadersRow, "Row 3 set as column headers."},
|
|
{input.SetRowHeadersColumn, "Column B set as row headers."},
|
|
{input.ClearColumnHeadersRow, "Column headers cleared."},
|
|
{input.ClearRowHeadersColumn, "Row headers cleared."},
|
|
} {
|
|
handler.configureCalcHeader(test.command)
|
|
if got := <-speech.spoken; got != test.want {
|
|
t.Fatalf("header command = %q", got)
|
|
}
|
|
<-frames
|
|
}
|
|
// Clearing immediately refreshes the Braille base frame as well as the
|
|
// copied Where Am I snapshot, without waiting for another cell event.
|
|
state.current.TableColumnHeaders, state.current.TableRowHeaders = "Total", "Monday"
|
|
handler.configureCalcHeader(input.ClearColumnHeadersRow)
|
|
<-speech.spoken
|
|
if frame := <-frames; frame.Text != "Monday 10 B3" {
|
|
t.Fatalf("cleared frame = %+v", frame)
|
|
}
|
|
if state.current.TableColumnHeaders != "" || state.brailleSnapshot.TableColumnHeaders != "" {
|
|
t.Fatal("clear retained column heading")
|
|
}
|
|
gate.secure.Store(true)
|
|
handler.configureCalcHeader(input.SetColumnHeadersRow)
|
|
gate.secure.Store(false)
|
|
gate.suspended.Store(true)
|
|
handler.configureCalcHeader(input.SetColumnHeadersRow)
|
|
gate.suspended.Store(false)
|
|
if len(speech.spoken) != 0 || len(frames) != 0 {
|
|
t.Fatal("header command bypassed lock/suspension")
|
|
}
|
|
state.owner.focus = atspi.NewObjectID(event.Source.BusName, "/other")
|
|
handler.configureCalcHeader(input.SetColumnHeadersRow)
|
|
if got := <-speech.spoken; got != "Not in a Calc cell." {
|
|
t.Fatal(got)
|
|
}
|
|
handler.syncForeground = func() { state.current = atspi.Snapshot{} }
|
|
handler.configureCalcHeader(input.SetColumnHeadersRow)
|
|
if got := <-speech.spoken; got != "Not in a Calc cell." {
|
|
t.Fatal(got)
|
|
}
|
|
}
|
|
|
|
func TestLibreOfficeHeaderSpeechHistoryAndBraille(t *testing.T) {
|
|
event := calcTestEvent(atspi.FocusEvent, "/cell", "10", "B3")
|
|
event.Source.TableRowIndex, event.Source.TableColumnIndex = 2, 1
|
|
event.Source.TableRowHeaders, event.Source.TableColumnHeaders = "Monday", "Total"
|
|
state := eventLoopState{}
|
|
state.lastTable, state.lastTableCell = calcSheet(event.Source), event.Source.ID()
|
|
state.lastTableRow, state.lastTableColumn = 2, 0
|
|
filtered := state.calcHeaderSpeechEvent(event)
|
|
if filtered.Source.TableRowHeaders != "" || filtered.Source.TableColumnHeaders != "Total" {
|
|
t.Fatalf("horizontal: %+v", filtered.Source)
|
|
}
|
|
state.lastTableRow, state.lastTableColumn = 1, 1
|
|
filtered = state.calcHeaderSpeechEvent(event)
|
|
if filtered.Source.TableRowHeaders != "Monday" || filtered.Source.TableColumnHeaders != "" {
|
|
t.Fatalf("vertical: %+v", filtered.Source)
|
|
}
|
|
// The accepted snapshot retains both for Where Am I and Braille.
|
|
if got := presentation.FocusText(event.Source); got != "Monday row header, Total column header, 10, B3" {
|
|
t.Fatal(got)
|
|
}
|
|
if frame := brailleFocusFrame(event.Source); frame.Text != "Monday Total 10 B3" {
|
|
t.Fatalf("frame = %+v", frame)
|
|
}
|
|
reading := config.DefaultSettings().Reading
|
|
reading.OnlySpeakDisplayedText = true
|
|
options := presentation.DefaultOptions()
|
|
options.Reading = &reading
|
|
if got := presentation.FocusTextWithOptions(event.Source, options); got != "10" {
|
|
t.Fatal(got)
|
|
}
|
|
state.current = event.Source
|
|
state.clearObjectFocus(nil, nil, nil)
|
|
filtered = state.calcHeaderSpeechEvent(event)
|
|
if filtered.Source.TableRowHeaders == "" || filtered.Source.TableColumnHeaders == "" {
|
|
t.Fatal("focus return suppressed headers")
|
|
}
|
|
state.lastTable = atspi.NewObjectID(event.Source.BusName, "/other-sheet")
|
|
filtered = state.calcHeaderSpeechEvent(event)
|
|
if filtered.Source.TableRowHeaders == "" || filtered.Source.TableColumnHeaders == "" {
|
|
t.Fatal("sheet return suppressed headers")
|
|
}
|
|
}
|