Eric Bower
·
2025-12-26
topic_test.go
1package pipe
2
3import (
4 "testing"
5)
6
7func TestToTopic(t *testing.T) {
8 tests := []struct {
9 name string
10 userName string
11 topic string
12 want string
13 }{
14 {
15 name: "basic topic",
16 userName: "alice",
17 topic: "mytopic",
18 want: "alice/mytopic",
19 },
20 {
21 name: "already prefixed with username",
22 userName: "alice",
23 topic: "alice/mytopic",
24 want: "alice/mytopic",
25 },
26 {
27 name: "different user prefix not stripped",
28 userName: "alice",
29 topic: "bob/mytopic",
30 want: "alice/bob/mytopic",
31 },
32 {
33 name: "empty topic",
34 userName: "alice",
35 topic: "",
36 want: "alice/",
37 },
38 }
39
40 for _, tt := range tests {
41 t.Run(tt.name, func(t *testing.T) {
42 got := toTopic(tt.userName, tt.topic)
43 if got != tt.want {
44 t.Errorf("toTopic(%q, %q) = %q, want %q", tt.userName, tt.topic, got, tt.want)
45 }
46 })
47 }
48}
49
50func TestToPublicTopic(t *testing.T) {
51 tests := []struct {
52 name string
53 topic string
54 want string
55 }{
56 {
57 name: "basic topic",
58 topic: "mytopic",
59 want: "public/mytopic",
60 },
61 {
62 name: "already public prefixed",
63 topic: "public/mytopic",
64 want: "public/mytopic",
65 },
66 {
67 name: "empty topic",
68 topic: "",
69 want: "public/",
70 },
71 }
72
73 for _, tt := range tests {
74 t.Run(tt.name, func(t *testing.T) {
75 got := toPublicTopic(tt.topic)
76 if got != tt.want {
77 t.Errorf("toPublicTopic(%q) = %q, want %q", tt.topic, got, tt.want)
78 }
79 })
80 }
81}
82
83func TestParseArgList(t *testing.T) {
84 tests := []struct {
85 name string
86 arg string
87 want []string
88 }{
89 {
90 name: "single item",
91 arg: "alice",
92 want: []string{"alice"},
93 },
94 {
95 name: "multiple items",
96 arg: "alice,bob,charlie",
97 want: []string{"alice", "bob", "charlie"},
98 },
99 {
100 name: "items with spaces",
101 arg: "alice, bob , charlie",
102 want: []string{"alice", "bob", "charlie"},
103 },
104 {
105 name: "empty string",
106 arg: "",
107 want: []string{""},
108 },
109 }
110
111 for _, tt := range tests {
112 t.Run(tt.name, func(t *testing.T) {
113 got := parseArgList(tt.arg)
114 if len(got) != len(tt.want) {
115 t.Errorf("parseArgList(%q) returned %d items, want %d", tt.arg, len(got), len(tt.want))
116 return
117 }
118 for i := range got {
119 if got[i] != tt.want[i] {
120 t.Errorf("parseArgList(%q)[%d] = %q, want %q", tt.arg, i, got[i], tt.want[i])
121 }
122 }
123 })
124 }
125}
126
127func TestResolveTopic(t *testing.T) {
128 tests := []struct {
129 name string
130 input TopicResolveInput
131 expect TopicResolveOutput
132 }{
133 {
134 name: "basic private topic",
135 input: TopicResolveInput{
136 UserName: "alice",
137 Topic: "mytopic",
138 IsAdmin: false,
139 IsPublic: false,
140 },
141 expect: TopicResolveOutput{
142 Name: "alice/mytopic",
143 WithoutUser: "mytopic",
144 },
145 },
146 {
147 name: "public topic",
148 input: TopicResolveInput{
149 UserName: "alice",
150 Topic: "mytopic",
151 IsAdmin: false,
152 IsPublic: true,
153 },
154 expect: TopicResolveOutput{
155 Name: "public/mytopic",
156 WithoutUser: "public/mytopic",
157 },
158 },
159 {
160 name: "admin with absolute path",
161 input: TopicResolveInput{
162 UserName: "admin",
163 Topic: "/rawtopic",
164 IsAdmin: true,
165 IsPublic: false,
166 },
167 expect: TopicResolveOutput{
168 Name: "rawtopic",
169 WithoutUser: "",
170 },
171 },
172 {
173 name: "admin without absolute path treated as regular user",
174 input: TopicResolveInput{
175 UserName: "admin",
176 Topic: "mytopic",
177 IsAdmin: true,
178 IsPublic: false,
179 },
180 expect: TopicResolveOutput{
181 Name: "admin/mytopic",
182 WithoutUser: "mytopic",
183 },
184 },
185 {
186 name: "topic already prefixed with username",
187 input: TopicResolveInput{
188 UserName: "alice",
189 Topic: "alice/mytopic",
190 IsAdmin: false,
191 IsPublic: false,
192 },
193 expect: TopicResolveOutput{
194 Name: "alice/mytopic",
195 WithoutUser: "alice/mytopic",
196 },
197 },
198 {
199 name: "public topic already prefixed",
200 input: TopicResolveInput{
201 UserName: "alice",
202 Topic: "public/mytopic",
203 IsAdmin: false,
204 IsPublic: true,
205 },
206 expect: TopicResolveOutput{
207 Name: "public/mytopic",
208 WithoutUser: "public/mytopic",
209 },
210 },
211 {
212 name: "access list exists - user has access",
213 input: TopicResolveInput{
214 UserName: "bob",
215 Topic: "sharedtopic",
216 IsAdmin: false,
217 IsPublic: false,
218 ExistingAccessList: []string{"bob", "charlie"},
219 HasExistingAccess: true,
220 HasUserAccess: true,
221 },
222 expect: TopicResolveOutput{
223 Name: "sharedtopic",
224 WithoutUser: "sharedtopic",
225 },
226 },
227 {
228 name: "access list exists - user denied (private)",
229 input: TopicResolveInput{
230 UserName: "eve",
231 Topic: "sharedtopic",
232 IsAdmin: false,
233 IsPublic: false,
234 ExistingAccessList: []string{"bob", "charlie"},
235 HasExistingAccess: true,
236 HasUserAccess: false,
237 },
238 expect: TopicResolveOutput{
239 Name: "eve/sharedtopic",
240 WithoutUser: "sharedtopic",
241 },
242 },
243 {
244 name: "access list exists - user denied (public) - generates new topic",
245 input: TopicResolveInput{
246 UserName: "eve",
247 Topic: "sharedtopic",
248 IsAdmin: false,
249 IsPublic: true,
250 ExistingAccessList: []string{"bob", "charlie"},
251 HasExistingAccess: true,
252 HasUserAccess: false,
253 },
254 expect: TopicResolveOutput{
255 Name: "public/sharedtopic",
256 WithoutUser: "public/sharedtopic",
257 AccessDenied: true,
258 GenerateNewTopic: true,
259 },
260 },
261 {
262 name: "access list creator gets access",
263 input: TopicResolveInput{
264 UserName: "alice",
265 Topic: "newtopic",
266 IsAdmin: false,
267 IsPublic: false,
268 AccessList: []string{"bob"},
269 ExistingAccessList: []string{"bob"},
270 HasExistingAccess: true,
271 IsAccessCreator: true,
272 HasUserAccess: false,
273 },
274 expect: TopicResolveOutput{
275 Name: "newtopic",
276 WithoutUser: "newtopic",
277 },
278 },
279 {
280 name: "admin bypasses access control",
281 input: TopicResolveInput{
282 UserName: "admin",
283 Topic: "restricted",
284 IsAdmin: true,
285 IsPublic: false,
286 ExistingAccessList: []string{"bob"},
287 HasExistingAccess: true,
288 HasUserAccess: false,
289 },
290 expect: TopicResolveOutput{
291 Name: "admin/restricted",
292 WithoutUser: "restricted",
293 },
294 },
295 }
296
297 for _, tt := range tests {
298 t.Run(tt.name, func(t *testing.T) {
299 got := resolveTopic(tt.input)
300 if got.Name != tt.expect.Name {
301 t.Errorf("resolveTopic().Name = %q, want %q", got.Name, tt.expect.Name)
302 }
303 if got.WithoutUser != tt.expect.WithoutUser {
304 t.Errorf("resolveTopic().WithoutUser = %q, want %q", got.WithoutUser, tt.expect.WithoutUser)
305 }
306 if got.AccessDenied != tt.expect.AccessDenied {
307 t.Errorf("resolveTopic().AccessDenied = %v, want %v", got.AccessDenied, tt.expect.AccessDenied)
308 }
309 if got.GenerateNewTopic != tt.expect.GenerateNewTopic {
310 t.Errorf("resolveTopic().GenerateNewTopic = %v, want %v", got.GenerateNewTopic, tt.expect.GenerateNewTopic)
311 }
312 })
313 }
314}