Enable isolated Remote speech and protect reading exports
Attach incoming software speech to reader sessions with lease checks, local output priority and isolated cancellation. Preserve every document fragment source for privacy checks and export reviewed browse current-line reading, spelling and phonetic output. Verified focused reading and Remote race tests, complete review and external Remote race suites, private relay integration, speech regressions, affected-package vet, reader build and Tentacles make check. Audible speech, physical input/Braille and live interoperability remain unverified.
This commit is contained in:
1 parent
ac67236eca
commit
49be8309fe
27 files changed
+986
-54
No files matched your search
@@ -56,6 +56,10 @@ func TestCurrentLineReadsWholeBrowseLineWithoutMoving(t *testing.T) {
|
||||
if result.Err != nil || strings.TrimSpace(result.DocumentCaretText) != "Second café 猫" {
|
||||
t.Fatalf("whole browse line from middle: %+v", result)
|
||||
}
|
||||
owner, err := cursor.tree.DocumentContext(result.DocumentPosition.Object)
|
||||
if err != nil || len(result.DocumentCaretContext) == 0 || !reflect.DeepEqual(result.DocumentCaretContext, owner.Ancestors) {
|
||||
t.Fatal("current-line report lost its captured source ancestry", err)
|
||||
}
|
||||
if !reflect.DeepEqual(cursor.places, before) || capturer.nativePlacements != 0 {
|
||||
t.Fatal("report changed browse or native caret")
|
||||
}
|
||||
@@ -76,6 +80,9 @@ func TestCurrentLineJoinsBrowseFragmentsWithoutMoving(t *testing.T) {
|
||||
if result.Err != nil || result.DocumentCaretText != "One two." || !reflect.DeepEqual(cursor.places, before) {
|
||||
t.Fatalf("fragmented current line: %+v", result)
|
||||
}
|
||||
if result.DocumentCaretLine == nil || len(result.DocumentCaretLine.SourceContexts) != 2 || len(result.DocumentCaretContext) == 0 {
|
||||
t.Fatal("fragmented report lost source ancestry")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrentLineReadsBrowseControlLabel(t *testing.T) {
|
||||
@@ -99,6 +106,46 @@ func TestCurrentLineReadsBrowseControlLabel(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCurrentLineUsesRecapturedSourceContext(t *testing.T) {
|
||||
text := caretTextReader{webID("/text"): "First\nSecond", webID("/next"): "Last"}
|
||||
cursor := newCaretTextCursor(t, text)
|
||||
fresh := newCaretTextCursor(t, text).tree
|
||||
capturer := &sequenceReadAllCapturer{caretTextReader: text, trees: []*atspi.AccessibleTree{fresh},
|
||||
invalidateTree: cursor.tree, staleAt: 2}
|
||||
worker, _ := NewWorker(capturer, time.Second)
|
||||
worker.SyncFocus(webID("/text"))
|
||||
result := worker.read_current_line(t.Context(), cursor, true)
|
||||
if result.Err != nil || strings.TrimSpace(result.DocumentCaretText) != "First" || capturer.index != 1 {
|
||||
t.Fatalf("current line did not recover capture: %+v", result)
|
||||
}
|
||||
owner, err := fresh.DocumentContext(result.DocumentPosition.Object)
|
||||
if err != nil || len(result.DocumentCaretContext) == 0 || !reflect.DeepEqual(result.DocumentCaretContext, owner.Ancestors) {
|
||||
t.Fatal("report did not retain the replacement tree's source context", err)
|
||||
}
|
||||
}
|
||||
|
||||
type currentLineStaleContextCapturer struct{ *readAllCapturer }
|
||||
|
||||
func (capturer *currentLineStaleContextCapturer) ReadDocumentCaret(ctx context.Context, reference atspi.ObjectReference, offset int, unit atspi.DocumentCaretUnit) (atspi.DocumentCaretText, error) {
|
||||
text, err := capturer.caretTextReader.ReadDocumentCaret(ctx, reference, offset, unit)
|
||||
if unit == atspi.DocumentCaretLineRemainder {
|
||||
capturer.tree.InvalidateSnapshot(webID("/doc"))
|
||||
}
|
||||
return text, err
|
||||
}
|
||||
|
||||
func TestCurrentLinePreservesLocalTextWithStaleContext(t *testing.T) {
|
||||
text := caretTextReader{webID("/text"): "Local line", webID("/next"): "Last"}
|
||||
cursor := newCaretTextCursor(t, text)
|
||||
capturer := ¤tLineStaleContextCapturer{&readAllCapturer{caretTextReader: text, tree: cursor.tree}}
|
||||
worker, _ := NewWorker(capturer, time.Second)
|
||||
worker.SyncFocus(webID("/text"))
|
||||
result := worker.read_current_line(t.Context(), cursor, true)
|
||||
if result.Err != nil || result.DocumentCaretText != "Local line" || len(result.DocumentCaretContext) != 0 {
|
||||
t.Fatalf("stale ancestry must leave local reading available without export metadata: %+v", result)
|
||||
}
|
||||
}
|
||||
|
||||
type currentLineFragmentCapturer struct {
|
||||
*readAllCapturer
|
||||
fragmentTextReader
|
||||
|
||||
Reference in new issue
Block a user