registry_test.go raw
1 package specialkinds
2
3 import (
4 "context"
5 "errors"
6 "testing"
7
8 "next.orly.dev/pkg/nostr/encoders/event"
9 )
10
11 func TestNewRegistry(t *testing.T) {
12 r := NewRegistry()
13 if r == nil {
14 t.Fatal("NewRegistry returned nil")
15 }
16 if r.HandlerCount() != 0 {
17 t.Errorf("expected 0 handlers, got %d", r.HandlerCount())
18 }
19 }
20
21 func TestRegistryRegister(t *testing.T) {
22 r := NewRegistry()
23
24 h := NewHandlerFunc(
25 "test-handler",
26 func(ev *event.E) bool { return true },
27 func(ctx context.Context, ev *event.E, hctx *HandlerContext) Result {
28 return Handled("test")
29 },
30 )
31
32 r.Register(h)
33
34 if r.HandlerCount() != 1 {
35 t.Errorf("expected 1 handler, got %d", r.HandlerCount())
36 }
37
38 names := r.ListHandlers()
39 if len(names) != 1 || names[0] != "test-handler" {
40 t.Errorf("unexpected handler names: %v", names)
41 }
42 }
43
44 func TestRegistryTryHandle_NoMatch(t *testing.T) {
45 r := NewRegistry()
46
47 // Register a handler that never matches
48 h := NewHandlerFunc(
49 "never-matches",
50 func(ev *event.E) bool { return false },
51 func(ctx context.Context, ev *event.E, hctx *HandlerContext) Result {
52 return Handled("should not be called")
53 },
54 )
55 r.Register(h)
56
57 ev := &event.E{Kind: 1}
58 result, matched := r.TryHandle(context.Background(), ev, nil)
59
60 if matched {
61 t.Error("expected no match, got matched")
62 }
63 if result != nil {
64 t.Error("expected nil result when no match")
65 }
66 }
67
68 func TestRegistryTryHandle_Match(t *testing.T) {
69 r := NewRegistry()
70
71 // Register a handler that matches kind 1
72 h := NewHandlerFunc(
73 "kind-1-handler",
74 func(ev *event.E) bool { return ev.Kind == 1 },
75 func(ctx context.Context, ev *event.E, hctx *HandlerContext) Result {
76 return Handled("processed kind 1")
77 },
78 )
79 r.Register(h)
80
81 ev := &event.E{Kind: 1}
82 result, matched := r.TryHandle(context.Background(), ev, nil)
83
84 if !matched {
85 t.Error("expected match, got no match")
86 }
87 if result == nil {
88 t.Fatal("expected result, got nil")
89 }
90 if !result.Handled {
91 t.Error("expected Handled=true")
92 }
93 if result.Message != "processed kind 1" {
94 t.Errorf("unexpected message: %s", result.Message)
95 }
96 }
97
98 func TestRegistryTryHandle_FirstMatchWins(t *testing.T) {
99 r := NewRegistry()
100
101 // Register two handlers that both match kind 1
102 h1 := NewHandlerFunc(
103 "first-handler",
104 func(ev *event.E) bool { return ev.Kind == 1 },
105 func(ctx context.Context, ev *event.E, hctx *HandlerContext) Result {
106 return Handled("first")
107 },
108 )
109 h2 := NewHandlerFunc(
110 "second-handler",
111 func(ev *event.E) bool { return ev.Kind == 1 },
112 func(ctx context.Context, ev *event.E, hctx *HandlerContext) Result {
113 return Handled("second")
114 },
115 )
116 r.Register(h1)
117 r.Register(h2)
118
119 ev := &event.E{Kind: 1}
120 result, _ := r.TryHandle(context.Background(), ev, nil)
121
122 if result.Message != "first" {
123 t.Errorf("expected first handler to win, got message: %s", result.Message)
124 }
125 }
126
127 func TestHandlerContext(t *testing.T) {
128 r := NewRegistry()
129
130 var capturedCtx *HandlerContext
131
132 h := NewHandlerFunc(
133 "context-capture",
134 func(ev *event.E) bool { return true },
135 func(ctx context.Context, ev *event.E, hctx *HandlerContext) Result {
136 capturedCtx = hctx
137 return Handled("captured")
138 },
139 )
140 r.Register(h)
141
142 hctx := &HandlerContext{
143 AuthedPubkey: []byte{1, 2, 3},
144 Remote: "127.0.0.1:12345",
145 ConnectionID: "conn-abc",
146 }
147
148 r.TryHandle(context.Background(), &event.E{Kind: 1}, hctx)
149
150 if capturedCtx == nil {
151 t.Fatal("handler context not captured")
152 }
153 if string(capturedCtx.AuthedPubkey) != string(hctx.AuthedPubkey) {
154 t.Error("AuthedPubkey mismatch")
155 }
156 if capturedCtx.Remote != hctx.Remote {
157 t.Error("Remote mismatch")
158 }
159 if capturedCtx.ConnectionID != hctx.ConnectionID {
160 t.Error("ConnectionID mismatch")
161 }
162 }
163
164 func TestResultConstructors(t *testing.T) {
165 t.Run("Handled", func(t *testing.T) {
166 r := Handled("msg")
167 if !r.Handled || r.Continue || r.SaveEvent || r.Error != nil {
168 t.Error("unexpected Handled result")
169 }
170 if r.Message != "msg" {
171 t.Errorf("unexpected message: %s", r.Message)
172 }
173 })
174
175 t.Run("HandledWithSave", func(t *testing.T) {
176 r := HandledWithSave("msg")
177 if !r.Handled || r.Continue || !r.SaveEvent || r.Error != nil {
178 t.Error("unexpected HandledWithSave result")
179 }
180 })
181
182 t.Run("ContinueProcessing", func(t *testing.T) {
183 r := ContinueProcessing()
184 if r.Handled || !r.Continue || r.SaveEvent || r.Error != nil {
185 t.Error("unexpected ContinueProcessing result")
186 }
187 })
188
189 t.Run("ErrorResult", func(t *testing.T) {
190 err := errors.New("test error")
191 r := ErrorResult(err)
192 if r.Handled || r.Continue || r.SaveEvent || r.Error != err {
193 t.Error("unexpected ErrorResult result")
194 }
195 })
196 }
197
198 func TestHandlerFuncInterface(t *testing.T) {
199 h := NewHandlerFunc(
200 "test",
201 func(ev *event.E) bool { return ev.Kind == 42 },
202 func(ctx context.Context, ev *event.E, hctx *HandlerContext) Result {
203 return Handled("42")
204 },
205 )
206
207 // Check interface compliance
208 var _ Handler = h
209
210 if h.Name() != "test" {
211 t.Errorf("unexpected name: %s", h.Name())
212 }
213
214 if !h.CanHandle(&event.E{Kind: 42}) {
215 t.Error("expected CanHandle to return true for kind 42")
216 }
217 if h.CanHandle(&event.E{Kind: 1}) {
218 t.Error("expected CanHandle to return false for kind 1")
219 }
220
221 result := h.Handle(context.Background(), &event.E{Kind: 42}, nil)
222 if result.Message != "42" {
223 t.Errorf("unexpected result message: %s", result.Message)
224 }
225 }
226