Files
cthulhu/internal/app/notification_test.go

139 lines
4.3 KiB
Go

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
package app
import (
"context"
"log/slog"
"testing"
"time"
"git.stormux.org/storm/cthulhu/internal/atspi"
"git.stormux.org/storm/cthulhu/internal/notification"
)
func TestNotificationProvidersAndHistoryMatchReferenceBehavior(t *testing.T) {
tests := []struct {
name string
event atspi.Event
expectedSpeech []string
expectedHistory string
}{
{
name: "xfce notification daemon labels",
event: notificationSnapshot("xfce4-notifyd", atspi.WindowCreateEvent, atspi.NewSnapshot(
"/notification", "", "frame", "", "Mail arrived New message",
)),
expectedSpeech: []string{"Notification Mail arrived New message"},
expectedHistory: "Notification Mail arrived New message",
},
{
name: "notify-osd name without value announces prefix and message",
event: notificationSnapshot("notify-osd", atspi.AccessibleNameEvent, atspi.NewSnapshot(
"/notification", "Volume", "notification", "at maximum", "",
)),
expectedSpeech: []string{"Notification", "Volume at maximum"},
expectedHistory: "Volume at maximum",
},
{
name: "notify-osd gauge value is not saved",
event: gaugeSnapshot(),
expectedSpeech: []string{"55"},
expectedHistory: "",
},
{
name: "generic accessible notification is saved",
event: showingNotification("Mail", "You have one unread message", true),
expectedSpeech: []string{"Mail, notification, You have one unread message"},
expectedHistory: "Mail You have one unread message",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
presenter := notification.NewPresenter()
speech, entries := processNotificationEvent(t, test.event, presenter)
if len(speech) != len(test.expectedSpeech) {
t.Fatalf("speech count = %d, want %d: %q", len(speech), len(test.expectedSpeech), speech)
}
for index, expected := range test.expectedSpeech {
if speech[index] != expected {
t.Fatalf("speech %d = %q, want %q", index, speech[index], expected)
}
}
if test.expectedHistory == "" {
if len(entries) != 0 {
t.Fatalf("history length = %d, want 0", len(entries))
}
return
}
if len(entries) != 1 {
t.Fatalf("history length = %d, want 1", len(entries))
}
if entries[0].Message != test.expectedHistory {
t.Fatalf("history = %q, want %q", entries[0].Message, test.expectedHistory)
}
})
}
}
func TestHiddenGenericNotificationIsNotSaved(t *testing.T) {
event := showingNotification("Mail", "You have one unread message", false)
presenter := notification.NewPresenter()
_, entries := processNotificationEvent(t, event, presenter)
if len(entries) != 0 {
t.Fatalf("history length = %d, want 0", len(entries))
}
}
func showingNotification(name, text string, showing bool) atspi.Event {
event := notificationSnapshot("Application", atspi.ShowingStateEvent,
atspi.NewSnapshot("/notification", name, "notification", "", text))
if showing {
event.Detail1 = 1
}
return event
}
func notificationSnapshot(application, eventType string, snapshot atspi.Snapshot) atspi.Event {
snapshot.ApplicationName = application
return atspi.NewEvent(eventType, snapshot)
}
func gaugeSnapshot() atspi.Event {
snapshot := atspi.NewSnapshot("/notification", "Volume", "notification", "", "")
snapshot.ValueKnown = true
snapshot.CurrentValue = 55
return notificationSnapshot("notify-osd", atspi.ValueChangedEvent, snapshot)
}
func processNotificationEvent(t *testing.T, event atspi.Event, presenter *notification.Presenter) ([]string, []notification.Entry) {
t.Helper()
speech := &fakeSpeechQueue{spoken: make(chan string, 8)}
adapter := &fakeAdapter{events: make(chan atspi.Event, 1)}
adapter.events <- event
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
completed := make(chan error, 1)
go func() {
completed <- processEventsWithInput(
ctx, slog.New(slog.DiscardHandler), speech, adapter,
nil, nil, 0, nil, nil, nil, presenter,
)
}()
var messages []string
for {
select {
case message := <-speech.spoken:
messages = append(messages, message)
case <-time.After(50 * time.Millisecond):
cancel()
if err := <-completed; err != nil {
t.Fatalf("process events: %v", err)
}
return messages, presenter.Entries()
}
}
}