1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
package notify
import "testing"
type event struct {
id uint32
reason uint32
}
func newTestStore() (*Store, *[]event) {
emitted := &[]event{}
s := NewStore(
func(id, reason uint32) { *emitted = append(*emitted, event{id, reason}) },
func(live, history []Popup) {},
)
return s, emitted
}
func popup(app string) *Popup {
return &Popup{App: app, Urgency: Normal, Created: 1}
}
func TestAddAssignsIdsFromOne(t *testing.T) {
s, _ := newTestStore()
a, replaced := s.Add(popup("a"), "", 0)
b, _ := s.Add(popup("b"), "", 0)
if replaced {
t.Fatal("first add reported replaced")
}
if a != 1 || b != 2 {
t.Errorf("ids = %d, %d, want 1, 2", a, b)
}
}
func TestReplaceByIDReusesTheIDAndEmitsNothing(t *testing.T) {
s, emitted := newTestStore()
id, _ := s.Add(popup("a"), "", 0)
*emitted = nil
again, replaced := s.Add(popup("a2"), "", id)
if !replaced {
t.Fatal("replace by id not reported")
}
if again != id {
t.Errorf("replace id = %d, want %d", again, id)
}
if len(*emitted) != 0 {
t.Errorf("replace emitted %v, want none", *emitted)
}
}
func TestReplaceByStackTag(t *testing.T) {
s, _ := newTestStore()
first, _ := s.Add(popup("mail"), "mail-account", 0)
second, replaced := s.Add(popup("mail"), "mail-account", 0)
if !replaced || second != first {
t.Errorf("stack replace = id %d replaced %v, want id %d replaced true", second, replaced, first)
}
}
func TestExpireClosesOnceAndKeepsTheEntry(t *testing.T) {
s, emitted := newTestStore()
id, _ := s.Add(popup("a"), "", 0)
s.Expire(id)
s.Expire(id)
if len(*emitted) != 1 || (*emitted)[0].reason != 1 {
t.Fatalf("emitted = %v, want one reason 1", *emitted)
}
if s.Actionable(id) {
t.Error("expired entry still actionable")
}
}
func TestDismissFilesHistoryAndEmitsDismissed(t *testing.T) {
s, emitted := newTestStore()
id, _ := s.Add(popup("a"), "", 0)
s.Dismiss(id, 2)
if len(*emitted) != 1 || (*emitted)[0].reason != 2 {
t.Fatalf("emitted = %v, want one reason 2", *emitted)
}
if s.Actionable(id) {
t.Error("dismissed entry still live")
}
}
func TestDismissAfterExpireEmitsNothingMore(t *testing.T) {
s, emitted := newTestStore()
id, _ := s.Add(popup("a"), "", 0)
s.Expire(id)
*emitted = nil
s.Dismiss(id, 2)
if len(*emitted) != 0 {
t.Errorf("dismiss after expire emitted %v, want none", *emitted)
}
}
func TestQueueCapEvictsToHistory(t *testing.T) {
s, emitted := newTestStore()
for i := 0; i < 21; i++ {
s.Add(popup("a"), "", 0)
}
if len(*emitted) == 0 {
t.Fatal("eviction emitted nothing")
}
}
func TestHistoryRingCapsAtTwenty(t *testing.T) {
s, _ := newTestStore()
for i := 0; i < 30; i++ {
id, _ := s.Add(popup("a"), "", 0)
s.Dismiss(id, 2)
}
if got := len(s.historySnapshot()); got != 20 {
t.Errorf("history length = %d, want 20", got)
}
}
|