// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later package atspi_test import ( "context" "os" "strings" "testing" "time" "git.stormux.org/storm/cthulhu/internal/atspi" "git.stormux.org/storm/cthulhu/internal/presentation" ) // Missing LABELLED_BY capture must fail even when the toolkit leaves Name empty. func TestNativeEditFieldLabels(t *testing.T) { if os.Getenv("CTHULHU_NATIVE_EDIT_LABELS") != "1" { t.Skip("requires isolated edit label fixture") } ctx, cancel := context.WithTimeout(context.Background(), 12*time.Second) defer cancel() adapter := atspi.New() if err := adapter.Start(ctx); err != nil { t.Fatal(err) } defer func() { stopCtx, stopCancel := context.WithTimeout(context.Background(), 3*time.Second) defer stopCancel() if err := adapter.Stop(stopCtx); err != nil { t.Error(err) } }() tree, err := adapter.CaptureDesktop(ctx) if err != nil { t.Fatal(err) } root, err := tree.Root() if err != nil { t.Fatal(err) } fields := map[string]atspi.Snapshot{} var walk func(atspi.ObjectReference) walk = func(ref atspi.ObjectReference) { snapshot, err := tree.Resolve(ref) if err != nil { t.Fatal(err) } if snapshot.Description != "" { fields[snapshot.Description] = snapshot } child, ok, err := tree.FirstChild(ref) if err != nil { t.Fatal(err) } for ok { walk(child) child, ok, err = tree.NextSibling(child) if err != nil { t.Fatal(err) } } } walk(root) for _, test := range []struct{ id, name string }{ {"related", "Nickname"}, {"multiple", "Account identifier"}, {"named", "Explicit name"}, {"unlabelled", ""}, {"protected", "Password"}, {"invalid-label", "Fallback label"}, {"password-target", ""}, } { t.Run(test.id, func(t *testing.T) { snapshot, ok := fields[test.id] if !ok { t.Fatal("missing edit field") } if snapshot.Name != test.name { t.Errorf("field label = %q, want %q", snapshot.Name, test.name) } spoken := presentation.FocusText(snapshot) if test.name != "" && !strings.Contains(spoken, test.name) { t.Errorf("speech %q omits label %q", spoken, test.name) } if test.id == "protected" && (snapshot.Text != "" || strings.Contains(spoken, "secret value")) { t.Fatal("password contents exposed") } }) } }