]> git.r.bdr.sh - rbdr/mobius/blame - hotline/transaction_handlers_test.go
Limit chat message size to 8192 bytes
[rbdr/mobius] / hotline / transaction_handlers_test.go
CommitLineData
6988a057
JH
1package hotline
2
3import (
decc2fbf 4 "errors"
6988a057 5 "github.com/stretchr/testify/assert"
8eb43f95 6 "github.com/stretchr/testify/mock"
b129b7cb 7 "io"
00d1ef67 8 "io/fs"
00d1ef67 9 "os"
f22acf38 10 "path/filepath"
decc2fbf 11 "strings"
a2ef262a 12 "sync"
6988a057 13 "testing"
7cd900d6 14 "time"
6988a057
JH
15)
16
17func TestHandleSetChatSubject(t *testing.T) {
18 type args struct {
19 cc *ClientConn
a2ef262a 20 t Transaction
6988a057
JH
21 }
22 tests := []struct {
a2ef262a
JH
23 name string
24 args args
25 want []Transaction
6988a057
JH
26 }{
27 {
28 name: "sends chat subject to private chat members",
29 args: args{
30 cc: &ClientConn{
72dd37f1 31 UserName: []byte{0x00, 0x01},
6988a057 32 Server: &Server{
a2ef262a
JH
33 PrivateChats: map[[4]byte]*PrivateChat{
34 [4]byte{0, 0, 0, 1}: {
6988a057 35 Subject: "unset",
a2ef262a
JH
36 ClientConn: map[[2]byte]*ClientConn{
37 [2]byte{0, 1}: {
6988a057 38 Account: &Account{
187d6dc5 39 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 40 },
a2ef262a 41 ID: [2]byte{0, 1},
6988a057 42 },
a2ef262a 43 [2]byte{0, 2}: {
6988a057 44 Account: &Account{
187d6dc5 45 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 46 },
a2ef262a 47 ID: [2]byte{0, 2},
6988a057
JH
48 },
49 },
50 },
51 },
a2ef262a
JH
52 Clients: map[[2]byte]*ClientConn{
53 [2]byte{0, 1}: {
6988a057 54 Account: &Account{
187d6dc5 55 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 56 },
a2ef262a 57 ID: [2]byte{0, 1},
6988a057 58 },
a2ef262a 59 [2]byte{0, 2}: {
6988a057 60 Account: &Account{
187d6dc5 61 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 62 },
a2ef262a 63 ID: [2]byte{0, 2},
6988a057
JH
64 },
65 },
66 },
67 },
a2ef262a 68 t: Transaction{
153e2eac
JH
69 Type: [2]byte{0, 0x6a},
70 ID: [4]byte{0, 0, 0, 1},
6988a057 71 Fields: []Field{
d005ef04
JH
72 NewField(FieldChatID, []byte{0, 0, 0, 1}),
73 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
74 },
75 },
76 },
77 want: []Transaction{
78 {
a2ef262a 79 clientID: [2]byte{0, 1},
153e2eac 80 Type: [2]byte{0, 0x77},
6988a057 81 Fields: []Field{
d005ef04
JH
82 NewField(FieldChatID, []byte{0, 0, 0, 1}),
83 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
84 },
85 },
86 {
a2ef262a 87 clientID: [2]byte{0, 2},
153e2eac 88 Type: [2]byte{0, 0x77},
6988a057 89 Fields: []Field{
d005ef04
JH
90 NewField(FieldChatID, []byte{0, 0, 0, 1}),
91 NewField(FieldChatSubject, []byte("Test Subject")),
6988a057
JH
92 },
93 },
94 },
6988a057
JH
95 },
96 }
97 for _, tt := range tests {
6988a057 98 t.Run(tt.name, func(t *testing.T) {
a2ef262a 99 got := HandleSetChatSubject(tt.args.cc, &tt.args.t)
f8e4cd54 100 if !tranAssertEqual(t, tt.want, got) {
6988a057
JH
101 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
102 }
103 })
104 }
105}
106
107func TestHandleLeaveChat(t *testing.T) {
108 type args struct {
109 cc *ClientConn
a2ef262a 110 t Transaction
6988a057
JH
111 }
112 tests := []struct {
a2ef262a
JH
113 name string
114 args args
115 want []Transaction
6988a057
JH
116 }{
117 {
118 name: "returns expected transactions",
119 args: args{
120 cc: &ClientConn{
a2ef262a 121 ID: [2]byte{0, 2},
6988a057 122 Server: &Server{
a2ef262a
JH
123 PrivateChats: map[[4]byte]*PrivateChat{
124 [4]byte{0, 0, 0, 1}: {
125 ClientConn: map[[2]byte]*ClientConn{
126 [2]byte{0, 1}: {
6988a057 127 Account: &Account{
187d6dc5 128 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 129 },
a2ef262a 130 ID: [2]byte{0, 1},
6988a057 131 },
a2ef262a 132 [2]byte{0, 2}: {
6988a057 133 Account: &Account{
187d6dc5 134 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 135 },
a2ef262a 136 ID: [2]byte{0, 2},
6988a057
JH
137 },
138 },
139 },
140 },
a2ef262a
JH
141 Clients: map[[2]byte]*ClientConn{
142 [2]byte{0, 1}: {
6988a057 143 Account: &Account{
187d6dc5 144 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 145 },
a2ef262a 146 ID: [2]byte{0, 1},
6988a057 147 },
a2ef262a 148 [2]byte{0, 2}: {
6988a057 149 Account: &Account{
187d6dc5 150 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 151 },
a2ef262a 152 ID: [2]byte{0, 2},
6988a057
JH
153 },
154 },
155 },
156 },
a2ef262a 157 t: NewTransaction(TranDeleteUser, [2]byte{}, NewField(FieldChatID, []byte{0, 0, 0, 1})),
6988a057
JH
158 },
159 want: []Transaction{
160 {
a2ef262a 161 clientID: [2]byte{0, 1},
153e2eac 162 Type: [2]byte{0, 0x76},
6988a057 163 Fields: []Field{
d005ef04
JH
164 NewField(FieldChatID, []byte{0, 0, 0, 1}),
165 NewField(FieldUserID, []byte{0, 2}),
6988a057
JH
166 },
167 },
168 },
6988a057
JH
169 },
170 }
171 for _, tt := range tests {
6988a057 172 t.Run(tt.name, func(t *testing.T) {
a2ef262a 173 got := HandleLeaveChat(tt.args.cc, &tt.args.t)
f8e4cd54 174 if !tranAssertEqual(t, tt.want, got) {
6988a057
JH
175 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
176 }
177 })
178 }
179}
180
6988a057
JH
181func TestHandleGetUserNameList(t *testing.T) {
182 type args struct {
183 cc *ClientConn
a2ef262a 184 t Transaction
6988a057
JH
185 }
186 tests := []struct {
a2ef262a
JH
187 name string
188 args args
189 want []Transaction
6988a057
JH
190 }{
191 {
192 name: "replies with userlist transaction",
193 args: args{
194 cc: &ClientConn{
a2ef262a 195 ID: [2]byte{0, 1},
6988a057 196 Server: &Server{
a2ef262a
JH
197 Clients: map[[2]byte]*ClientConn{
198 [2]byte{0, 1}: {
199 ID: [2]byte{0, 1},
a7216f67 200 Icon: []byte{0, 2},
a2ef262a 201 Flags: [2]byte{0, 3},
72dd37f1 202 UserName: []byte{0, 4},
6988a057 203 },
a2ef262a
JH
204 [2]byte{0, 2}: {
205 ID: [2]byte{0, 2},
a7216f67 206 Icon: []byte{0, 2},
a2ef262a 207 Flags: [2]byte{0, 3},
c7e932c0 208 UserName: []byte{0, 4},
bd1ce113 209 },
6988a057
JH
210 },
211 },
212 },
a2ef262a 213 t: Transaction{},
6988a057
JH
214 },
215 want: []Transaction{
216 {
a2ef262a 217 clientID: [2]byte{0, 1},
153e2eac 218 IsReply: 0x01,
6988a057
JH
219 Fields: []Field{
220 NewField(
d005ef04 221 FieldUsernameWithInfo,
6988a057
JH
222 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
223 ),
c7e932c0 224 NewField(
d005ef04 225 FieldUsernameWithInfo,
c7e932c0
JH
226 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
227 ),
6988a057
JH
228 },
229 },
230 },
6988a057
JH
231 },
232 }
233 for _, tt := range tests {
234 t.Run(tt.name, func(t *testing.T) {
a2ef262a 235 got := HandleGetUserNameList(tt.args.cc, &tt.args.t)
bd1ce113 236 assert.Equal(t, tt.want, got)
6988a057
JH
237 })
238 }
239}
240
241func TestHandleChatSend(t *testing.T) {
242 type args struct {
243 cc *ClientConn
a2ef262a 244 t Transaction
6988a057
JH
245 }
246 tests := []struct {
a2ef262a
JH
247 name string
248 args args
249 want []Transaction
6988a057
JH
250 }{
251 {
252 name: "sends chat msg transaction to all clients",
253 args: args{
254 cc: &ClientConn{
9ebf276d 255 Account: &Account{
187d6dc5 256 Access: func() accessBitmap {
9ebf276d
JH
257 var bits accessBitmap
258 bits.Set(accessSendChat)
187d6dc5 259 return bits
9ebf276d
JH
260 }(),
261 },
72dd37f1 262 UserName: []byte{0x00, 0x01},
6988a057 263 Server: &Server{
a2ef262a
JH
264 Clients: map[[2]byte]*ClientConn{
265 [2]byte{0, 1}: {
6988a057 266 Account: &Account{
187d6dc5 267 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 268 },
a2ef262a 269 ID: [2]byte{0, 1},
6988a057 270 },
a2ef262a 271 [2]byte{0, 2}: {
6988a057 272 Account: &Account{
187d6dc5 273 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
6988a057 274 },
a2ef262a 275 ID: [2]byte{0, 2},
6988a057
JH
276 },
277 },
278 },
279 },
a2ef262a 280 t: Transaction{
6988a057 281 Fields: []Field{
d005ef04 282 NewField(FieldData, []byte("hai")),
6988a057
JH
283 },
284 },
285 },
286 want: []Transaction{
287 {
a2ef262a 288 clientID: [2]byte{0, 1},
153e2eac
JH
289 Flags: 0x00,
290 IsReply: 0x00,
291 Type: [2]byte{0, 0x6a},
6988a057 292 Fields: []Field{
d005ef04 293 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
294 },
295 },
296 {
a2ef262a 297 clientID: [2]byte{0, 2},
153e2eac
JH
298 Flags: 0x00,
299 IsReply: 0x00,
300 Type: [2]byte{0, 0x6a},
6988a057 301 Fields: []Field{
d005ef04 302 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
303 },
304 },
305 },
6988a057 306 },
361928c9
JH
307 {
308 name: "treats Chat ID 00 00 00 00 as a public chat message",
309 args: args{
310 cc: &ClientConn{
311 Account: &Account{
312 Access: func() accessBitmap {
313 var bits accessBitmap
314 bits.Set(accessSendChat)
315 return bits
316 }(),
317 },
318 UserName: []byte{0x00, 0x01},
319 Server: &Server{
a2ef262a
JH
320 Clients: map[[2]byte]*ClientConn{
321 [2]byte{0, 1}: {
361928c9
JH
322 Account: &Account{
323 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
324 },
a2ef262a 325 ID: [2]byte{0, 1},
361928c9 326 },
a2ef262a 327 [2]byte{0, 2}: {
361928c9
JH
328 Account: &Account{
329 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
330 },
a2ef262a 331 ID: [2]byte{0, 2},
361928c9
JH
332 },
333 },
334 },
335 },
a2ef262a 336 t: Transaction{
361928c9 337 Fields: []Field{
d005ef04
JH
338 NewField(FieldData, []byte("hai")),
339 NewField(FieldChatID, []byte{0, 0, 0, 0}),
361928c9
JH
340 },
341 },
342 },
343 want: []Transaction{
344 {
a2ef262a 345 clientID: [2]byte{0, 1},
153e2eac 346 Type: [2]byte{0, 0x6a},
361928c9 347 Fields: []Field{
d005ef04 348 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
361928c9
JH
349 },
350 },
351 {
a2ef262a 352 clientID: [2]byte{0, 2},
153e2eac 353 Type: [2]byte{0, 0x6a},
361928c9 354 Fields: []Field{
d005ef04 355 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
361928c9
JH
356 },
357 },
358 },
361928c9 359 },
9ebf276d
JH
360 {
361 name: "when user does not have required permission",
362 args: args{
363 cc: &ClientConn{
364 Account: &Account{
187d6dc5 365 Access: func() accessBitmap {
9ebf276d 366 var bits accessBitmap
187d6dc5 367 return bits
9ebf276d
JH
368 }(),
369 },
370 Server: &Server{
371 Accounts: map[string]*Account{},
372 },
373 },
374 t: NewTransaction(
a2ef262a 375 TranChatSend, [2]byte{0, 1},
d005ef04 376 NewField(FieldData, []byte("hai")),
9ebf276d
JH
377 ),
378 },
379 want: []Transaction{
380 {
9ebf276d 381 IsReply: 0x01,
153e2eac 382 ErrorCode: [4]byte{0, 0, 0, 1},
9ebf276d 383 Fields: []Field{
d005ef04 384 NewField(FieldError, []byte("You are not allowed to participate in chat.")),
9ebf276d
JH
385 },
386 },
387 },
9ebf276d 388 },
72dd37f1 389 {
d005ef04 390 name: "sends chat msg as emote if FieldChatOptions is set to 1",
72dd37f1
JH
391 args: args{
392 cc: &ClientConn{
9ebf276d 393 Account: &Account{
187d6dc5 394 Access: func() accessBitmap {
9ebf276d
JH
395 var bits accessBitmap
396 bits.Set(accessSendChat)
187d6dc5 397 return bits
9ebf276d
JH
398 }(),
399 },
72dd37f1
JH
400 UserName: []byte("Testy McTest"),
401 Server: &Server{
a2ef262a
JH
402 Clients: map[[2]byte]*ClientConn{
403 [2]byte{0, 1}: {
72dd37f1 404 Account: &Account{
187d6dc5 405 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
72dd37f1 406 },
a2ef262a 407 ID: [2]byte{0, 1},
72dd37f1 408 },
a2ef262a 409 [2]byte{0, 2}: {
72dd37f1 410 Account: &Account{
187d6dc5 411 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
72dd37f1 412 },
a2ef262a 413 ID: [2]byte{0, 2},
72dd37f1
JH
414 },
415 },
416 },
417 },
a2ef262a 418 t: Transaction{
72dd37f1 419 Fields: []Field{
d005ef04
JH
420 NewField(FieldData, []byte("performed action")),
421 NewField(FieldChatOptions, []byte{0x00, 0x01}),
72dd37f1
JH
422 },
423 },
424 },
425 want: []Transaction{
426 {
a2ef262a 427 clientID: [2]byte{0, 1},
153e2eac
JH
428 Flags: 0x00,
429 IsReply: 0x00,
430 Type: [2]byte{0, 0x6a},
72dd37f1 431 Fields: []Field{
d005ef04 432 NewField(FieldData, []byte("\r*** Testy McTest performed action")),
72dd37f1
JH
433 },
434 },
435 {
a2ef262a 436 clientID: [2]byte{0, 2},
153e2eac
JH
437 Flags: 0x00,
438 IsReply: 0x00,
439 Type: [2]byte{0, 0x6a},
72dd37f1 440 Fields: []Field{
d005ef04 441 NewField(FieldData, []byte("\r*** Testy McTest performed action")),
72dd37f1
JH
442 },
443 },
444 },
72dd37f1 445 },
2e43fd4e 446 {
d005ef04 447 name: "does not send chat msg as emote if FieldChatOptions is set to 0",
2e43fd4e
JH
448 args: args{
449 cc: &ClientConn{
450 Account: &Account{
451 Access: func() accessBitmap {
452 var bits accessBitmap
453 bits.Set(accessSendChat)
454 return bits
455 }(),
456 },
457 UserName: []byte("Testy McTest"),
458 Server: &Server{
a2ef262a
JH
459 Clients: map[[2]byte]*ClientConn{
460 [2]byte{0, 1}: {
2e43fd4e
JH
461 Account: &Account{
462 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
463 },
a2ef262a 464 ID: [2]byte{0, 1},
2e43fd4e 465 },
a2ef262a 466 [2]byte{0, 2}: {
2e43fd4e
JH
467 Account: &Account{
468 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
469 },
a2ef262a 470 ID: [2]byte{0, 2},
2e43fd4e
JH
471 },
472 },
473 },
474 },
a2ef262a 475 t: Transaction{
2e43fd4e 476 Fields: []Field{
d005ef04
JH
477 NewField(FieldData, []byte("hello")),
478 NewField(FieldChatOptions, []byte{0x00, 0x00}),
2e43fd4e
JH
479 },
480 },
481 },
482 want: []Transaction{
483 {
a2ef262a 484 clientID: [2]byte{0, 1},
153e2eac 485 Type: [2]byte{0, 0x6a},
2e43fd4e 486 Fields: []Field{
d005ef04 487 NewField(FieldData, []byte("\r Testy McTest: hello")),
2e43fd4e
JH
488 },
489 },
490 {
a2ef262a 491 clientID: [2]byte{0, 2},
153e2eac 492 Type: [2]byte{0, 0x6a},
2e43fd4e 493 Fields: []Field{
d005ef04 494 NewField(FieldData, []byte("\r Testy McTest: hello")),
2e43fd4e
JH
495 },
496 },
497 },
2e43fd4e 498 },
6988a057
JH
499 {
500 name: "only sends chat msg to clients with accessReadChat permission",
501 args: args{
502 cc: &ClientConn{
9ebf276d 503 Account: &Account{
187d6dc5 504 Access: func() accessBitmap {
9ebf276d
JH
505 var bits accessBitmap
506 bits.Set(accessSendChat)
187d6dc5 507 return bits
9ebf276d
JH
508 }(),
509 },
72dd37f1 510 UserName: []byte{0x00, 0x01},
6988a057 511 Server: &Server{
a2ef262a
JH
512 Clients: map[[2]byte]*ClientConn{
513 [2]byte{0, 1}: {
6988a057 514 Account: &Account{
187d6dc5
JH
515 Access: func() accessBitmap {
516 var bits accessBitmap
517 bits.Set(accessReadChat)
518 return bits
519 }()},
a2ef262a 520 ID: [2]byte{0, 1},
6988a057 521 },
a2ef262a 522 [2]byte{0, 2}: {
6988a057 523 Account: &Account{
187d6dc5 524 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
6988a057 525 },
a2ef262a 526 ID: [2]byte{0, 2},
6988a057
JH
527 },
528 },
529 },
530 },
a2ef262a 531 t: Transaction{
6988a057 532 Fields: []Field{
d005ef04 533 NewField(FieldData, []byte("hai")),
6988a057
JH
534 },
535 },
536 },
537 want: []Transaction{
538 {
a2ef262a 539 clientID: [2]byte{0, 1},
153e2eac 540 Type: [2]byte{0, 0x6a},
6988a057 541 Fields: []Field{
d005ef04 542 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
6988a057
JH
543 },
544 },
545 },
6988a057 546 },
481631f6
JH
547 {
548 name: "only sends private chat msg to members of private chat",
549 args: args{
550 cc: &ClientConn{
551 Account: &Account{
187d6dc5 552 Access: func() accessBitmap {
481631f6
JH
553 var bits accessBitmap
554 bits.Set(accessSendChat)
187d6dc5 555 return bits
481631f6
JH
556 }(),
557 },
558 UserName: []byte{0x00, 0x01},
559 Server: &Server{
a2ef262a
JH
560 PrivateChats: map[[4]byte]*PrivateChat{
561 [4]byte{0, 0, 0, 1}: {
562 ClientConn: map[[2]byte]*ClientConn{
563 [2]byte{0, 1}: {
564 ID: [2]byte{0, 1},
481631f6 565 },
a2ef262a
JH
566 [2]byte{0, 2}: {
567 ID: [2]byte{0, 2},
481631f6
JH
568 },
569 },
570 },
571 },
a2ef262a
JH
572 Clients: map[[2]byte]*ClientConn{
573 [2]byte{0, 1}: {
481631f6 574 Account: &Account{
187d6dc5 575 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
481631f6 576 },
a2ef262a 577 ID: [2]byte{0, 1},
481631f6 578 },
a2ef262a 579 [2]byte{0, 2}: {
481631f6 580 Account: &Account{
187d6dc5 581 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
481631f6 582 },
a2ef262a 583 ID: [2]byte{0, 2},
481631f6 584 },
a2ef262a 585 [2]byte{0, 3}: {
481631f6 586 Account: &Account{
187d6dc5 587 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
481631f6 588 },
a2ef262a 589 ID: [2]byte{0, 3},
481631f6
JH
590 },
591 },
592 },
593 },
a2ef262a 594 t: Transaction{
481631f6 595 Fields: []Field{
d005ef04
JH
596 NewField(FieldData, []byte("hai")),
597 NewField(FieldChatID, []byte{0, 0, 0, 1}),
481631f6
JH
598 },
599 },
600 },
601 want: []Transaction{
602 {
a2ef262a 603 clientID: [2]byte{0, 1},
153e2eac 604 Type: [2]byte{0, 0x6a},
481631f6 605 Fields: []Field{
d005ef04
JH
606 NewField(FieldChatID, []byte{0, 0, 0, 1}),
607 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
481631f6
JH
608 },
609 },
610 {
a2ef262a 611 clientID: [2]byte{0, 2},
153e2eac 612 Type: [2]byte{0, 0x6a},
481631f6 613 Fields: []Field{
d005ef04
JH
614 NewField(FieldChatID, []byte{0, 0, 0, 1}),
615 NewField(FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
481631f6
JH
616 },
617 },
618 },
481631f6 619 },
6988a057
JH
620 }
621 for _, tt := range tests {
6988a057 622 t.Run(tt.name, func(t *testing.T) {
a2ef262a 623 got := HandleChatSend(tt.args.cc, &tt.args.t)
9ebf276d 624 tranAssertEqual(t, tt.want, got)
6988a057
JH
625 })
626 }
627}
72dd37f1
JH
628
629func TestHandleGetFileInfo(t *testing.T) {
72dd37f1
JH
630 type args struct {
631 cc *ClientConn
a2ef262a 632 t Transaction
72dd37f1
JH
633 }
634 tests := []struct {
635 name string
636 args args
637 wantRes []Transaction
72dd37f1
JH
638 }{
639 {
640 name: "returns expected fields when a valid file is requested",
641 args: args{
642 cc: &ClientConn{
a2ef262a 643 ID: [2]byte{0x00, 0x01},
72dd37f1 644 Server: &Server{
7cd900d6 645 FS: &OSFileStore{},
72dd37f1 646 Config: &Config{
29f329ae
JH
647 FileRoot: func() string {
648 path, _ := os.Getwd()
f22acf38 649 return filepath.Join(path, "/test/config/Files")
29f329ae 650 }(),
72dd37f1
JH
651 },
652 },
653 },
654 t: NewTransaction(
a2ef262a 655 TranGetFileInfo, [2]byte{},
d005ef04
JH
656 NewField(FieldFileName, []byte("testfile.txt")),
657 NewField(FieldFilePath, []byte{0x00, 0x00}),
72dd37f1
JH
658 ),
659 },
660 wantRes: []Transaction{
661 {
a2ef262a 662 clientID: [2]byte{0, 1},
153e2eac
JH
663 IsReply: 0x01,
664 Type: [2]byte{0, 0},
72dd37f1 665 Fields: []Field{
d005ef04
JH
666 NewField(FieldFileName, []byte("testfile.txt")),
667 NewField(FieldFileTypeString, []byte("Text File")),
668 NewField(FieldFileCreatorString, []byte("ttxt")),
d005ef04
JH
669 NewField(FieldFileType, []byte("TEXT")),
670 NewField(FieldFileCreateDate, make([]byte, 8)),
671 NewField(FieldFileModifyDate, make([]byte, 8)),
672 NewField(FieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
72dd37f1
JH
673 },
674 },
675 },
72dd37f1
JH
676 },
677 }
678 for _, tt := range tests {
679 t.Run(tt.name, func(t *testing.T) {
a2ef262a 680 gotRes := HandleGetFileInfo(tt.args.cc, &tt.args.t)
29f329ae 681
a2ef262a 682 // Clear the file timestamp fields to work around problems running the tests in multiple timezones
29f329ae 683 // TODO: revisit how to test this by mocking the stat calls
84f3e842 684 gotRes[0].Fields[4].Data = make([]byte, 8)
29f329ae 685 gotRes[0].Fields[5].Data = make([]byte, 8)
f8e4cd54
JH
686
687 if !tranAssertEqual(t, tt.wantRes, gotRes) {
72dd37f1
JH
688 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
689 }
690 })
691 }
692}
00d1ef67
JH
693
694func TestHandleNewFolder(t *testing.T) {
695 type args struct {
696 cc *ClientConn
a2ef262a 697 t Transaction
00d1ef67
JH
698 }
699 tests := []struct {
00d1ef67
JH
700 name string
701 args args
702 wantRes []Transaction
00d1ef67 703 }{
d4c152a4 704 {
b196a50a 705 name: "without required permission",
d4c152a4
JH
706 args: args{
707 cc: &ClientConn{
708 Account: &Account{
187d6dc5 709 Access: func() accessBitmap {
d4c152a4 710 var bits accessBitmap
187d6dc5 711 return bits
d4c152a4
JH
712 }(),
713 },
714 },
715 t: NewTransaction(
a2ef262a
JH
716 TranNewFolder,
717 [2]byte{0, 0},
d4c152a4
JH
718 ),
719 },
720 wantRes: []Transaction{
721 {
d4c152a4 722 IsReply: 0x01,
153e2eac 723 ErrorCode: [4]byte{0, 0, 0, 1},
d4c152a4 724 Fields: []Field{
d005ef04 725 NewField(FieldError, []byte("You are not allowed to create folders.")),
d4c152a4
JH
726 },
727 },
728 },
d4c152a4 729 },
00d1ef67
JH
730 {
731 name: "when path is nested",
732 args: args{
733 cc: &ClientConn{
d4c152a4 734 Account: &Account{
187d6dc5 735 Access: func() accessBitmap {
d4c152a4
JH
736 var bits accessBitmap
737 bits.Set(accessCreateFolder)
187d6dc5 738 return bits
d4c152a4
JH
739 }(),
740 },
a2ef262a 741 ID: [2]byte{0, 1},
00d1ef67
JH
742 Server: &Server{
743 Config: &Config{
744 FileRoot: "/Files/",
745 },
b196a50a
JH
746 FS: func() *MockFileStore {
747 mfs := &MockFileStore{}
748 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
749 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
750 return mfs
751 }(),
00d1ef67
JH
752 },
753 },
754 t: NewTransaction(
a2ef262a 755 TranNewFolder, [2]byte{0, 1},
d005ef04
JH
756 NewField(FieldFileName, []byte("testFolder")),
757 NewField(FieldFilePath, []byte{
00d1ef67
JH
758 0x00, 0x01,
759 0x00, 0x00,
760 0x03,
761 0x61, 0x61, 0x61,
762 }),
763 ),
764 },
00d1ef67
JH
765 wantRes: []Transaction{
766 {
a2ef262a 767 clientID: [2]byte{0, 1},
153e2eac 768 IsReply: 0x01,
00d1ef67
JH
769 },
770 },
00d1ef67
JH
771 },
772 {
773 name: "when path is not nested",
774 args: args{
775 cc: &ClientConn{
d4c152a4 776 Account: &Account{
187d6dc5 777 Access: func() accessBitmap {
d4c152a4
JH
778 var bits accessBitmap
779 bits.Set(accessCreateFolder)
187d6dc5 780 return bits
d4c152a4
JH
781 }(),
782 },
a2ef262a 783 ID: [2]byte{0, 1},
00d1ef67
JH
784 Server: &Server{
785 Config: &Config{
786 FileRoot: "/Files",
787 },
b196a50a
JH
788 FS: func() *MockFileStore {
789 mfs := &MockFileStore{}
790 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
791 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
792 return mfs
793 }(),
00d1ef67
JH
794 },
795 },
796 t: NewTransaction(
a2ef262a 797 TranNewFolder, [2]byte{0, 1},
d005ef04 798 NewField(FieldFileName, []byte("testFolder")),
00d1ef67
JH
799 ),
800 },
00d1ef67
JH
801 wantRes: []Transaction{
802 {
a2ef262a 803 clientID: [2]byte{0, 1},
153e2eac 804 IsReply: 0x01,
00d1ef67
JH
805 },
806 },
00d1ef67
JH
807 },
808 {
8fc43f8e 809 name: "when Write returns an err",
00d1ef67
JH
810 args: args{
811 cc: &ClientConn{
d4c152a4 812 Account: &Account{
187d6dc5 813 Access: func() accessBitmap {
d4c152a4
JH
814 var bits accessBitmap
815 bits.Set(accessCreateFolder)
187d6dc5 816 return bits
d4c152a4
JH
817 }(),
818 },
a2ef262a 819 ID: [2]byte{0, 1},
00d1ef67
JH
820 Server: &Server{
821 Config: &Config{
822 FileRoot: "/Files/",
823 },
b196a50a
JH
824 FS: func() *MockFileStore {
825 mfs := &MockFileStore{}
826 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
827 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
828 return mfs
829 }(),
00d1ef67
JH
830 },
831 },
832 t: NewTransaction(
a2ef262a 833 TranNewFolder, [2]byte{0, 1},
d005ef04
JH
834 NewField(FieldFileName, []byte("testFolder")),
835 NewField(FieldFilePath, []byte{
00d1ef67
JH
836 0x00,
837 }),
838 ),
839 },
00d1ef67 840 wantRes: []Transaction{},
00d1ef67
JH
841 },
842 {
d005ef04 843 name: "FieldFileName does not allow directory traversal",
00d1ef67
JH
844 args: args{
845 cc: &ClientConn{
d4c152a4 846 Account: &Account{
187d6dc5 847 Access: func() accessBitmap {
d4c152a4
JH
848 var bits accessBitmap
849 bits.Set(accessCreateFolder)
187d6dc5 850 return bits
d4c152a4
JH
851 }(),
852 },
a2ef262a 853 ID: [2]byte{0, 1},
00d1ef67
JH
854 Server: &Server{
855 Config: &Config{
856 FileRoot: "/Files/",
857 },
b196a50a
JH
858 FS: func() *MockFileStore {
859 mfs := &MockFileStore{}
860 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
861 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
862 return mfs
863 }(),
00d1ef67
JH
864 },
865 },
866 t: NewTransaction(
a2ef262a 867 TranNewFolder, [2]byte{0, 1},
d005ef04 868 NewField(FieldFileName, []byte("../../testFolder")),
00d1ef67
JH
869 ),
870 },
00d1ef67
JH
871 wantRes: []Transaction{
872 {
a2ef262a 873 clientID: [2]byte{0, 1},
153e2eac 874 IsReply: 0x01,
00d1ef67 875 },
a2ef262a 876 },
00d1ef67
JH
877 },
878 {
d005ef04 879 name: "FieldFilePath does not allow directory traversal",
00d1ef67
JH
880 args: args{
881 cc: &ClientConn{
d4c152a4 882 Account: &Account{
187d6dc5 883 Access: func() accessBitmap {
d4c152a4
JH
884 var bits accessBitmap
885 bits.Set(accessCreateFolder)
187d6dc5 886 return bits
d4c152a4
JH
887 }(),
888 },
a2ef262a 889 ID: [2]byte{0, 1},
00d1ef67
JH
890 Server: &Server{
891 Config: &Config{
892 FileRoot: "/Files/",
893 },
b196a50a
JH
894 FS: func() *MockFileStore {
895 mfs := &MockFileStore{}
896 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
897 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
898 return mfs
899 }(),
00d1ef67
JH
900 },
901 },
902 t: NewTransaction(
a2ef262a 903 TranNewFolder, [2]byte{0, 1},
d005ef04
JH
904 NewField(FieldFileName, []byte("testFolder")),
905 NewField(FieldFilePath, []byte{
00d1ef67
JH
906 0x00, 0x02,
907 0x00, 0x00,
908 0x03,
909 0x2e, 0x2e, 0x2f,
910 0x00, 0x00,
911 0x03,
912 0x66, 0x6f, 0x6f,
913 }),
914 ),
915 },
00d1ef67
JH
916 wantRes: []Transaction{
917 {
a2ef262a 918 clientID: [2]byte{0, 1},
153e2eac 919 IsReply: 0x01,
00d1ef67 920 },
a2ef262a 921 },
00d1ef67
JH
922 },
923 }
924 for _, tt := range tests {
925 t.Run(tt.name, func(t *testing.T) {
a2ef262a 926 gotRes := HandleNewFolder(tt.args.cc, &tt.args.t)
d4c152a4 927
00d1ef67
JH
928 if !tranAssertEqual(t, tt.wantRes, gotRes) {
929 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
930 }
931 })
932 }
933}
934
92a7e455
JH
935func TestHandleUploadFile(t *testing.T) {
936 type args struct {
937 cc *ClientConn
a2ef262a 938 t Transaction
92a7e455
JH
939 }
940 tests := []struct {
941 name string
942 args args
943 wantRes []Transaction
92a7e455
JH
944 }{
945 {
7e2e07da 946 name: "when request is valid and user has Upload Anywhere permission",
92a7e455
JH
947 args: args{
948 cc: &ClientConn{
949 Server: &Server{
df1ade54
JH
950 FS: &OSFileStore{},
951 fileTransfers: map[[4]byte]*FileTransfer{},
952 Config: &Config{
953 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
954 }},
955 transfers: map[int]map[[4]byte]*FileTransfer{
956 FileUpload: {},
92a7e455
JH
957 },
958 Account: &Account{
187d6dc5 959 Access: func() accessBitmap {
92a7e455
JH
960 var bits accessBitmap
961 bits.Set(accessUploadFile)
7e2e07da 962 bits.Set(accessUploadAnywhere)
187d6dc5 963 return bits
92a7e455
JH
964 }(),
965 },
966 },
967 t: NewTransaction(
a2ef262a 968 TranUploadFile, [2]byte{0, 1},
d005ef04
JH
969 NewField(FieldFileName, []byte("testFile")),
970 NewField(FieldFilePath, []byte{
92a7e455
JH
971 0x00, 0x01,
972 0x00, 0x00,
973 0x03,
974 0x2e, 0x2e, 0x2f,
975 }),
976 ),
977 },
978 wantRes: []Transaction{
979 {
153e2eac 980 IsReply: 0x01,
92a7e455 981 Fields: []Field{
d005ef04 982 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
92a7e455
JH
983 },
984 },
985 },
92a7e455
JH
986 },
987 {
988 name: "when user does not have required access",
989 args: args{
990 cc: &ClientConn{
991 Account: &Account{
187d6dc5 992 Access: func() accessBitmap {
92a7e455 993 var bits accessBitmap
187d6dc5 994 return bits
92a7e455
JH
995 }(),
996 },
92a7e455
JH
997 },
998 t: NewTransaction(
a2ef262a 999 TranUploadFile, [2]byte{0, 1},
d005ef04
JH
1000 NewField(FieldFileName, []byte("testFile")),
1001 NewField(FieldFilePath, []byte{
92a7e455
JH
1002 0x00, 0x01,
1003 0x00, 0x00,
1004 0x03,
1005 0x2e, 0x2e, 0x2f,
1006 }),
1007 ),
1008 },
1009 wantRes: []Transaction{
1010 {
92a7e455 1011 IsReply: 0x01,
153e2eac 1012 ErrorCode: [4]byte{0, 0, 0, 1},
92a7e455 1013 Fields: []Field{
d005ef04 1014 NewField(FieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
92a7e455
JH
1015 },
1016 },
1017 },
92a7e455
JH
1018 },
1019 }
1020 for _, tt := range tests {
1021 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1022 gotRes := HandleUploadFile(tt.args.cc, &tt.args.t)
aebc4d36 1023 tranAssertEqual(t, tt.wantRes, gotRes)
92a7e455
JH
1024 })
1025 }
1026}
decc2fbf
JH
1027
1028func TestHandleMakeAlias(t *testing.T) {
1029 type args struct {
1030 cc *ClientConn
a2ef262a 1031 t Transaction
decc2fbf
JH
1032 }
1033 tests := []struct {
1034 name string
decc2fbf
JH
1035 args args
1036 wantRes []Transaction
decc2fbf
JH
1037 }{
1038 {
1039 name: "with valid input and required permissions",
decc2fbf
JH
1040 args: args{
1041 cc: &ClientConn{
02b446d8 1042 logger: NewTestLogger(),
decc2fbf 1043 Account: &Account{
187d6dc5 1044 Access: func() accessBitmap {
decc2fbf
JH
1045 var bits accessBitmap
1046 bits.Set(accessMakeAlias)
187d6dc5 1047 return bits
decc2fbf
JH
1048 }(),
1049 },
1050 Server: &Server{
1051 Config: &Config{
1052 FileRoot: func() string {
1053 path, _ := os.Getwd()
1054 return path + "/test/config/Files"
1055 }(),
1056 },
1057 Logger: NewTestLogger(),
b196a50a
JH
1058 FS: func() *MockFileStore {
1059 mfs := &MockFileStore{}
1060 path, _ := os.Getwd()
1061 mfs.On(
1062 "Symlink",
1063 path+"/test/config/Files/foo/testFile",
1064 path+"/test/config/Files/bar/testFile",
1065 ).Return(nil)
1066 return mfs
1067 }(),
decc2fbf
JH
1068 },
1069 },
1070 t: NewTransaction(
a2ef262a 1071 TranMakeFileAlias, [2]byte{0, 1},
d005ef04
JH
1072 NewField(FieldFileName, []byte("testFile")),
1073 NewField(FieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1074 NewField(FieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
decc2fbf
JH
1075 ),
1076 },
1077 wantRes: []Transaction{
1078 {
153e2eac
JH
1079 IsReply: 0x01,
1080 Fields: []Field(nil),
decc2fbf
JH
1081 },
1082 },
decc2fbf
JH
1083 },
1084 {
1085 name: "when symlink returns an error",
decc2fbf
JH
1086 args: args{
1087 cc: &ClientConn{
02b446d8 1088 logger: NewTestLogger(),
decc2fbf 1089 Account: &Account{
187d6dc5 1090 Access: func() accessBitmap {
decc2fbf
JH
1091 var bits accessBitmap
1092 bits.Set(accessMakeAlias)
187d6dc5 1093 return bits
decc2fbf
JH
1094 }(),
1095 },
1096 Server: &Server{
1097 Config: &Config{
1098 FileRoot: func() string {
1099 path, _ := os.Getwd()
1100 return path + "/test/config/Files"
1101 }(),
1102 },
1103 Logger: NewTestLogger(),
b196a50a
JH
1104 FS: func() *MockFileStore {
1105 mfs := &MockFileStore{}
1106 path, _ := os.Getwd()
1107 mfs.On(
1108 "Symlink",
1109 path+"/test/config/Files/foo/testFile",
1110 path+"/test/config/Files/bar/testFile",
1111 ).Return(errors.New("ohno"))
1112 return mfs
1113 }(),
decc2fbf
JH
1114 },
1115 },
1116 t: NewTransaction(
a2ef262a 1117 TranMakeFileAlias, [2]byte{0, 1},
d005ef04
JH
1118 NewField(FieldFileName, []byte("testFile")),
1119 NewField(FieldFilePath, EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1120 NewField(FieldFileNewPath, EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
decc2fbf
JH
1121 ),
1122 },
1123 wantRes: []Transaction{
1124 {
decc2fbf 1125 IsReply: 0x01,
153e2eac 1126 ErrorCode: [4]byte{0, 0, 0, 1},
decc2fbf 1127 Fields: []Field{
d005ef04 1128 NewField(FieldError, []byte("Error creating alias")),
decc2fbf
JH
1129 },
1130 },
1131 },
decc2fbf
JH
1132 },
1133 {
b196a50a 1134 name: "when user does not have required permission",
decc2fbf
JH
1135 args: args{
1136 cc: &ClientConn{
02b446d8 1137 logger: NewTestLogger(),
decc2fbf 1138 Account: &Account{
187d6dc5 1139 Access: func() accessBitmap {
decc2fbf 1140 var bits accessBitmap
187d6dc5 1141 return bits
decc2fbf
JH
1142 }(),
1143 },
1144 Server: &Server{
1145 Config: &Config{
1146 FileRoot: func() string {
1147 path, _ := os.Getwd()
1148 return path + "/test/config/Files"
1149 }(),
1150 },
1151 },
1152 },
1153 t: NewTransaction(
a2ef262a 1154 TranMakeFileAlias, [2]byte{0, 1},
d005ef04
JH
1155 NewField(FieldFileName, []byte("testFile")),
1156 NewField(FieldFilePath, []byte{
decc2fbf
JH
1157 0x00, 0x01,
1158 0x00, 0x00,
1159 0x03,
1160 0x2e, 0x2e, 0x2e,
1161 }),
d005ef04 1162 NewField(FieldFileNewPath, []byte{
decc2fbf
JH
1163 0x00, 0x01,
1164 0x00, 0x00,
1165 0x03,
1166 0x2e, 0x2e, 0x2e,
1167 }),
1168 ),
1169 },
1170 wantRes: []Transaction{
1171 {
decc2fbf 1172 IsReply: 0x01,
153e2eac 1173 ErrorCode: [4]byte{0, 0, 0, 1},
decc2fbf 1174 Fields: []Field{
d005ef04 1175 NewField(FieldError, []byte("You are not allowed to make aliases.")),
decc2fbf
JH
1176 },
1177 },
1178 },
decc2fbf
JH
1179 },
1180 }
1181 for _, tt := range tests {
1182 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1183 gotRes := HandleMakeAlias(tt.args.cc, &tt.args.t)
decc2fbf
JH
1184 tranAssertEqual(t, tt.wantRes, gotRes)
1185 })
1186 }
1187}
9ebf276d
JH
1188
1189func TestHandleGetUser(t *testing.T) {
1190 type args struct {
1191 cc *ClientConn
a2ef262a 1192 t Transaction
9ebf276d
JH
1193 }
1194 tests := []struct {
1195 name string
1196 args args
1197 wantRes []Transaction
9ebf276d
JH
1198 }{
1199 {
1200 name: "when account is valid",
1201 args: args{
1202 cc: &ClientConn{
1203 Account: &Account{
187d6dc5 1204 Access: func() accessBitmap {
9ebf276d
JH
1205 var bits accessBitmap
1206 bits.Set(accessOpenUser)
187d6dc5 1207 return bits
9ebf276d
JH
1208 }(),
1209 },
1210 Server: &Server{
1211 Accounts: map[string]*Account{
1212 "guest": {
1213 Login: "guest",
1214 Name: "Guest",
1215 Password: "password",
187d6dc5 1216 Access: accessBitmap{},
9ebf276d
JH
1217 },
1218 },
1219 },
1220 },
1221 t: NewTransaction(
a2ef262a 1222 TranGetUser, [2]byte{0, 1},
d005ef04 1223 NewField(FieldUserLogin, []byte("guest")),
9ebf276d
JH
1224 ),
1225 },
1226 wantRes: []Transaction{
1227 {
153e2eac 1228 IsReply: 0x01,
9ebf276d 1229 Fields: []Field{
d005ef04 1230 NewField(FieldUserName, []byte("Guest")),
76d0c1f6 1231 NewField(FieldUserLogin, encodeString([]byte("guest"))),
d005ef04
JH
1232 NewField(FieldUserPassword, []byte("password")),
1233 NewField(FieldUserAccess, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
9ebf276d
JH
1234 },
1235 },
1236 },
9ebf276d
JH
1237 },
1238 {
1239 name: "when user does not have required permission",
1240 args: args{
1241 cc: &ClientConn{
1242 Account: &Account{
187d6dc5 1243 Access: func() accessBitmap {
9ebf276d 1244 var bits accessBitmap
187d6dc5 1245 return bits
9ebf276d
JH
1246 }(),
1247 },
1248 Server: &Server{
1249 Accounts: map[string]*Account{},
1250 },
1251 },
1252 t: NewTransaction(
a2ef262a 1253 TranGetUser, [2]byte{0, 1},
d005ef04 1254 NewField(FieldUserLogin, []byte("nonExistentUser")),
9ebf276d
JH
1255 ),
1256 },
1257 wantRes: []Transaction{
1258 {
9ebf276d 1259 IsReply: 0x01,
153e2eac 1260 ErrorCode: [4]byte{0, 0, 0, 1},
9ebf276d 1261 Fields: []Field{
d005ef04 1262 NewField(FieldError, []byte("You are not allowed to view accounts.")),
9ebf276d
JH
1263 },
1264 },
1265 },
9ebf276d
JH
1266 },
1267 {
1268 name: "when account does not exist",
1269 args: args{
1270 cc: &ClientConn{
1271 Account: &Account{
187d6dc5 1272 Access: func() accessBitmap {
9ebf276d
JH
1273 var bits accessBitmap
1274 bits.Set(accessOpenUser)
187d6dc5 1275 return bits
9ebf276d
JH
1276 }(),
1277 },
1278 Server: &Server{
1279 Accounts: map[string]*Account{},
1280 },
1281 },
1282 t: NewTransaction(
a2ef262a 1283 TranGetUser, [2]byte{0, 1},
d005ef04 1284 NewField(FieldUserLogin, []byte("nonExistentUser")),
9ebf276d
JH
1285 ),
1286 },
1287 wantRes: []Transaction{
1288 {
1289 Flags: 0x00,
1290 IsReply: 0x01,
153e2eac
JH
1291 Type: [2]byte{0, 0},
1292 ErrorCode: [4]byte{0, 0, 0, 1},
9ebf276d 1293 Fields: []Field{
d005ef04 1294 NewField(FieldError, []byte("Account does not exist.")),
9ebf276d
JH
1295 },
1296 },
1297 },
9ebf276d
JH
1298 },
1299 }
1300 for _, tt := range tests {
1301 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1302 gotRes := HandleGetUser(tt.args.cc, &tt.args.t)
9ebf276d
JH
1303 tranAssertEqual(t, tt.wantRes, gotRes)
1304 })
1305 }
1306}
1307
1308func TestHandleDeleteUser(t *testing.T) {
1309 type args struct {
1310 cc *ClientConn
a2ef262a 1311 t Transaction
9ebf276d
JH
1312 }
1313 tests := []struct {
1314 name string
9ebf276d
JH
1315 args args
1316 wantRes []Transaction
9ebf276d
JH
1317 }{
1318 {
7cd900d6 1319 name: "when user dataFile",
9ebf276d
JH
1320 args: args{
1321 cc: &ClientConn{
1322 Account: &Account{
187d6dc5 1323 Access: func() accessBitmap {
9ebf276d
JH
1324 var bits accessBitmap
1325 bits.Set(accessDeleteUser)
187d6dc5 1326 return bits
9ebf276d
JH
1327 }(),
1328 },
1329 Server: &Server{
1330 Accounts: map[string]*Account{
1331 "testuser": {
1332 Login: "testuser",
1333 Name: "Testy McTest",
1334 Password: "password",
187d6dc5 1335 Access: accessBitmap{},
9ebf276d
JH
1336 },
1337 },
b196a50a
JH
1338 FS: func() *MockFileStore {
1339 mfs := &MockFileStore{}
1340 mfs.On("Remove", "Users/testuser.yaml").Return(nil)
1341 return mfs
1342 }(),
9ebf276d
JH
1343 },
1344 },
1345 t: NewTransaction(
a2ef262a 1346 TranDeleteUser, [2]byte{0, 1},
76d0c1f6 1347 NewField(FieldUserLogin, encodeString([]byte("testuser"))),
9ebf276d
JH
1348 ),
1349 },
1350 wantRes: []Transaction{
1351 {
153e2eac
JH
1352 Flags: 0x00,
1353 IsReply: 0x01,
1354 Type: [2]byte{0, 0},
1355 Fields: []Field(nil),
9ebf276d
JH
1356 },
1357 },
9ebf276d
JH
1358 },
1359 {
b196a50a 1360 name: "when user does not have required permission",
9ebf276d
JH
1361 args: args{
1362 cc: &ClientConn{
1363 Account: &Account{
187d6dc5 1364 Access: func() accessBitmap {
9ebf276d 1365 var bits accessBitmap
187d6dc5 1366 return bits
9ebf276d
JH
1367 }(),
1368 },
1369 Server: &Server{
1370 Accounts: map[string]*Account{},
1371 },
1372 },
1373 t: NewTransaction(
a2ef262a 1374 TranDeleteUser, [2]byte{0, 1},
76d0c1f6 1375 NewField(FieldUserLogin, encodeString([]byte("testuser"))),
9ebf276d
JH
1376 ),
1377 },
1378 wantRes: []Transaction{
1379 {
9ebf276d 1380 IsReply: 0x01,
153e2eac 1381 ErrorCode: [4]byte{0, 0, 0, 1},
9ebf276d 1382 Fields: []Field{
d005ef04 1383 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
9ebf276d
JH
1384 },
1385 },
1386 },
9ebf276d
JH
1387 },
1388 }
1389 for _, tt := range tests {
1390 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1391 gotRes := HandleDeleteUser(tt.args.cc, &tt.args.t)
9ebf276d
JH
1392 tranAssertEqual(t, tt.wantRes, gotRes)
1393 })
1394 }
1395}
481631f6
JH
1396
1397func TestHandleGetMsgs(t *testing.T) {
1398 type args struct {
1399 cc *ClientConn
a2ef262a 1400 t Transaction
481631f6
JH
1401 }
1402 tests := []struct {
1403 name string
1404 args args
1405 wantRes []Transaction
481631f6
JH
1406 }{
1407 {
1408 name: "returns news data",
1409 args: args{
1410 cc: &ClientConn{
1411 Account: &Account{
187d6dc5 1412 Access: func() accessBitmap {
481631f6
JH
1413 var bits accessBitmap
1414 bits.Set(accessNewsReadArt)
187d6dc5 1415 return bits
481631f6
JH
1416 }(),
1417 },
1418 Server: &Server{
1419 FlatNews: []byte("TEST"),
1420 },
1421 },
1422 t: NewTransaction(
a2ef262a 1423 TranGetMsgs, [2]byte{0, 1},
481631f6
JH
1424 ),
1425 },
1426 wantRes: []Transaction{
1427 {
153e2eac 1428 IsReply: 0x01,
481631f6 1429 Fields: []Field{
d005ef04 1430 NewField(FieldData, []byte("TEST")),
481631f6
JH
1431 },
1432 },
1433 },
481631f6
JH
1434 },
1435 {
1436 name: "when user does not have required permission",
1437 args: args{
1438 cc: &ClientConn{
1439 Account: &Account{
187d6dc5 1440 Access: func() accessBitmap {
481631f6 1441 var bits accessBitmap
187d6dc5 1442 return bits
481631f6
JH
1443 }(),
1444 },
1445 Server: &Server{
1446 Accounts: map[string]*Account{},
1447 },
1448 },
1449 t: NewTransaction(
a2ef262a 1450 TranGetMsgs, [2]byte{0, 1},
481631f6
JH
1451 ),
1452 },
1453 wantRes: []Transaction{
1454 {
481631f6 1455 IsReply: 0x01,
153e2eac 1456 ErrorCode: [4]byte{0, 0, 0, 1},
481631f6 1457 Fields: []Field{
d005ef04 1458 NewField(FieldError, []byte("You are not allowed to read news.")),
481631f6
JH
1459 },
1460 },
1461 },
481631f6
JH
1462 },
1463 }
1464 for _, tt := range tests {
1465 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1466 gotRes := HandleGetMsgs(tt.args.cc, &tt.args.t)
481631f6
JH
1467 tranAssertEqual(t, tt.wantRes, gotRes)
1468 })
1469 }
1470}
1471
1472func TestHandleNewUser(t *testing.T) {
1473 type args struct {
1474 cc *ClientConn
a2ef262a 1475 t Transaction
481631f6
JH
1476 }
1477 tests := []struct {
1478 name string
1479 args args
1480 wantRes []Transaction
481631f6
JH
1481 }{
1482 {
1483 name: "when user does not have required permission",
1484 args: args{
1485 cc: &ClientConn{
1486 Account: &Account{
187d6dc5 1487 Access: func() accessBitmap {
481631f6 1488 var bits accessBitmap
187d6dc5 1489 return bits
481631f6
JH
1490 }(),
1491 },
1492 Server: &Server{
1493 Accounts: map[string]*Account{},
1494 },
1495 },
1496 t: NewTransaction(
a2ef262a 1497 TranNewUser, [2]byte{0, 1},
481631f6
JH
1498 ),
1499 },
1500 wantRes: []Transaction{
1501 {
481631f6 1502 IsReply: 0x01,
153e2eac 1503 ErrorCode: [4]byte{0, 0, 0, 1},
481631f6 1504 Fields: []Field{
d005ef04 1505 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
481631f6
JH
1506 },
1507 },
1508 },
481631f6 1509 },
ecb1fcd9
JH
1510 {
1511 name: "when user attempts to create account with greater access",
1512 args: args{
1513 cc: &ClientConn{
1514 Account: &Account{
1515 Access: func() accessBitmap {
1516 var bits accessBitmap
1517 bits.Set(accessCreateUser)
1518 return bits
1519 }(),
1520 },
1521 Server: &Server{
1522 Accounts: map[string]*Account{},
1523 },
1524 },
1525 t: NewTransaction(
a2ef262a 1526 TranNewUser, [2]byte{0, 1},
d005ef04 1527 NewField(FieldUserLogin, []byte("userB")),
ecb1fcd9 1528 NewField(
d005ef04 1529 FieldUserAccess,
ecb1fcd9
JH
1530 func() []byte {
1531 var bits accessBitmap
1532 bits.Set(accessDisconUser)
1533 return bits[:]
1534 }(),
1535 ),
1536 ),
1537 },
1538 wantRes: []Transaction{
1539 {
ecb1fcd9 1540 IsReply: 0x01,
153e2eac 1541 ErrorCode: [4]byte{0, 0, 0, 1},
ecb1fcd9 1542 Fields: []Field{
d005ef04 1543 NewField(FieldError, []byte("Cannot create account with more access than yourself.")),
ecb1fcd9
JH
1544 },
1545 },
1546 },
ecb1fcd9 1547 },
481631f6
JH
1548 }
1549 for _, tt := range tests {
1550 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1551 gotRes := HandleNewUser(tt.args.cc, &tt.args.t)
481631f6
JH
1552 tranAssertEqual(t, tt.wantRes, gotRes)
1553 })
1554 }
1555}
1556
1557func TestHandleListUsers(t *testing.T) {
1558 type args struct {
1559 cc *ClientConn
a2ef262a 1560 t Transaction
481631f6
JH
1561 }
1562 tests := []struct {
1563 name string
1564 args args
1565 wantRes []Transaction
481631f6
JH
1566 }{
1567 {
1568 name: "when user does not have required permission",
1569 args: args{
1570 cc: &ClientConn{
1571 Account: &Account{
187d6dc5 1572 Access: func() accessBitmap {
481631f6 1573 var bits accessBitmap
187d6dc5 1574 return bits
481631f6
JH
1575 }(),
1576 },
1577 Server: &Server{
1578 Accounts: map[string]*Account{},
1579 },
1580 },
1581 t: NewTransaction(
a2ef262a 1582 TranNewUser, [2]byte{0, 1},
481631f6
JH
1583 ),
1584 },
1585 wantRes: []Transaction{
1586 {
481631f6 1587 IsReply: 0x01,
153e2eac 1588 ErrorCode: [4]byte{0, 0, 0, 1},
481631f6 1589 Fields: []Field{
d005ef04 1590 NewField(FieldError, []byte("You are not allowed to view accounts.")),
481631f6
JH
1591 },
1592 },
1593 },
481631f6 1594 },
60ec6281
JH
1595 {
1596 name: "when user has required permission",
1597 args: args{
1598 cc: &ClientConn{
1599 Account: &Account{
187d6dc5 1600 Access: func() accessBitmap {
60ec6281
JH
1601 var bits accessBitmap
1602 bits.Set(accessOpenUser)
187d6dc5 1603 return bits
60ec6281
JH
1604 }(),
1605 },
1606 Server: &Server{
1607 Accounts: map[string]*Account{
1608 "guest": {
1609 Name: "guest",
1610 Login: "guest",
1611 Password: "zz",
187d6dc5 1612 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
60ec6281
JH
1613 },
1614 },
1615 },
1616 },
1617 t: NewTransaction(
a2ef262a 1618 TranGetClientInfoText, [2]byte{0, 1},
d005ef04 1619 NewField(FieldUserID, []byte{0, 1}),
60ec6281
JH
1620 ),
1621 },
1622 wantRes: []Transaction{
1623 {
153e2eac 1624 IsReply: 0x01,
60ec6281 1625 Fields: []Field{
d005ef04 1626 NewField(FieldData, []byte{
60ec6281
JH
1627 0x00, 0x04, 0x00, 0x66, 0x00, 0x05, 0x67, 0x75, 0x65, 0x73, 0x74, 0x00, 0x69, 0x00, 0x05, 0x98,
1628 0x8a, 0x9a, 0x8c, 0x8b, 0x00, 0x6e, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1629 0x00, 0x6a, 0x00, 0x01, 0x78,
1630 }),
1631 },
1632 },
1633 },
60ec6281 1634 },
481631f6
JH
1635 }
1636 for _, tt := range tests {
1637 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1638 gotRes := HandleListUsers(tt.args.cc, &tt.args.t)
481631f6
JH
1639
1640 tranAssertEqual(t, tt.wantRes, gotRes)
1641 })
1642 }
1643}
1644
1645func TestHandleDownloadFile(t *testing.T) {
1646 type args struct {
1647 cc *ClientConn
a2ef262a 1648 t Transaction
481631f6
JH
1649 }
1650 tests := []struct {
1651 name string
1652 args args
1653 wantRes []Transaction
481631f6
JH
1654 }{
1655 {
1656 name: "when user does not have required permission",
1657 args: args{
1658 cc: &ClientConn{
1659 Account: &Account{
187d6dc5 1660 Access: func() accessBitmap {
481631f6 1661 var bits accessBitmap
187d6dc5 1662 return bits
481631f6
JH
1663 }(),
1664 },
1665 Server: &Server{},
1666 },
a2ef262a 1667 t: NewTransaction(TranDownloadFile, [2]byte{0, 1}),
481631f6
JH
1668 },
1669 wantRes: []Transaction{
1670 {
481631f6 1671 IsReply: 0x01,
153e2eac 1672 ErrorCode: [4]byte{0, 0, 0, 1},
481631f6 1673 Fields: []Field{
d005ef04 1674 NewField(FieldError, []byte("You are not allowed to download files.")),
481631f6
JH
1675 },
1676 },
1677 },
481631f6
JH
1678 },
1679 {
1680 name: "with a valid file",
1681 args: args{
1682 cc: &ClientConn{
df1ade54
JH
1683 transfers: map[int]map[[4]byte]*FileTransfer{
1684 FileDownload: {},
1685 },
481631f6 1686 Account: &Account{
187d6dc5 1687 Access: func() accessBitmap {
481631f6
JH
1688 var bits accessBitmap
1689 bits.Set(accessDownloadFile)
187d6dc5 1690 return bits
481631f6
JH
1691 }(),
1692 },
1693 Server: &Server{
7cd900d6 1694 FS: &OSFileStore{},
df1ade54 1695 fileTransfers: map[[4]byte]*FileTransfer{},
481631f6
JH
1696 Config: &Config{
1697 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1698 },
1699 Accounts: map[string]*Account{},
1700 },
1701 },
1702 t: NewTransaction(
a2ef262a
JH
1703 TranDownloadFile,
1704 [2]byte{0, 1},
d005ef04
JH
1705 NewField(FieldFileName, []byte("testfile.txt")),
1706 NewField(FieldFilePath, []byte{0x0, 0x00}),
481631f6
JH
1707 ),
1708 },
1709 wantRes: []Transaction{
1710 {
153e2eac 1711 IsReply: 0x01,
481631f6 1712 Fields: []Field{
d005ef04
JH
1713 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1714 NewField(FieldWaitingCount, []byte{0x00, 0x00}),
1715 NewField(FieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1716 NewField(FieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
481631f6
JH
1717 },
1718 },
1719 },
481631f6 1720 },
7cd900d6
JH
1721 {
1722 name: "when client requests to resume 1k test file at offset 256",
1723 args: args{
1724 cc: &ClientConn{
df1ade54
JH
1725 transfers: map[int]map[[4]byte]*FileTransfer{
1726 FileDownload: {},
1727 }, Account: &Account{
187d6dc5 1728 Access: func() accessBitmap {
7cd900d6
JH
1729 var bits accessBitmap
1730 bits.Set(accessDownloadFile)
187d6dc5 1731 return bits
7cd900d6
JH
1732 }(),
1733 },
1734 Server: &Server{
1735 FS: &OSFileStore{},
df1ade54 1736
7cd900d6
JH
1737 // FS: func() *MockFileStore {
1738 // path, _ := os.Getwd()
1739 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1740 // if err != nil {
1741 // panic(err)
1742 // }
1743 //
1744 // mfi := &MockFileInfo{}
1745 // mfi.On("Mode").Return(fs.FileMode(0))
1746 // mfs := &MockFileStore{}
1747 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1748 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1749 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
1750 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
1751 //
1752 // return mfs
1753 // }(),
df1ade54 1754 fileTransfers: map[[4]byte]*FileTransfer{},
7cd900d6
JH
1755 Config: &Config{
1756 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1757 },
1758 Accounts: map[string]*Account{},
1759 },
1760 },
1761 t: NewTransaction(
a2ef262a
JH
1762 TranDownloadFile,
1763 [2]byte{0, 1},
d005ef04
JH
1764 NewField(FieldFileName, []byte("testfile-1k")),
1765 NewField(FieldFilePath, []byte{0x00, 0x00}),
7cd900d6 1766 NewField(
d005ef04 1767 FieldFileResumeData,
7cd900d6
JH
1768 func() []byte {
1769 frd := FileResumeData{
7cd900d6
JH
1770 ForkCount: [2]byte{0, 2},
1771 ForkInfoList: []ForkInfoList{
1772 {
1773 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
1774 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
7cd900d6
JH
1775 },
1776 {
1777 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
1778 DataSize: [4]byte{0, 0, 0, 0},
7cd900d6
JH
1779 },
1780 },
1781 }
1782 b, _ := frd.BinaryMarshal()
1783 return b
1784 }(),
1785 ),
1786 ),
1787 },
1788 wantRes: []Transaction{
1789 {
153e2eac 1790 IsReply: 0x01,
7cd900d6 1791 Fields: []Field{
d005ef04
JH
1792 NewField(FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1793 NewField(FieldWaitingCount, []byte{0x00, 0x00}),
1794 NewField(FieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
1795 NewField(FieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
7cd900d6
JH
1796 },
1797 },
1798 },
7cd900d6 1799 },
481631f6
JH
1800 }
1801 for _, tt := range tests {
1802 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1803 gotRes := HandleDownloadFile(tt.args.cc, &tt.args.t)
481631f6
JH
1804 tranAssertEqual(t, tt.wantRes, gotRes)
1805 })
1806 }
1807}
d2810ae9
JH
1808
1809func TestHandleUpdateUser(t *testing.T) {
1810 type args struct {
1811 cc *ClientConn
a2ef262a 1812 t Transaction
d2810ae9
JH
1813 }
1814 tests := []struct {
1815 name string
1816 args args
1817 wantRes []Transaction
d2810ae9
JH
1818 }{
1819 {
1820 name: "when action is create user without required permission",
1821 args: args{
1822 cc: &ClientConn{
02b446d8 1823 logger: NewTestLogger(),
d2810ae9
JH
1824 Server: &Server{
1825 Logger: NewTestLogger(),
1826 },
1827 Account: &Account{
187d6dc5 1828 Access: func() accessBitmap {
d2810ae9 1829 var bits accessBitmap
187d6dc5 1830 return bits
d2810ae9
JH
1831 }(),
1832 },
1833 },
1834 t: NewTransaction(
d005ef04 1835 TranUpdateUser,
a2ef262a 1836 [2]byte{0, 0},
d005ef04 1837 NewField(FieldData, []byte{
d2810ae9
JH
1838 0x00, 0x04, // field count
1839
d005ef04 1840 0x00, 0x69, // FieldUserLogin = 105
d2810ae9
JH
1841 0x00, 0x03,
1842 0x9d, 0x9d, 0x9d,
1843
d005ef04 1844 0x00, 0x6a, // FieldUserPassword = 106
d2810ae9
JH
1845 0x00, 0x03,
1846 0x9c, 0x9c, 0x9c,
1847
d005ef04 1848 0x00, 0x66, // FieldUserName = 102
d2810ae9
JH
1849 0x00, 0x03,
1850 0x61, 0x61, 0x61,
1851
d005ef04 1852 0x00, 0x6e, // FieldUserAccess = 110
d2810ae9
JH
1853 0x00, 0x08,
1854 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1855 }),
1856 ),
1857 },
1858 wantRes: []Transaction{
1859 {
d2810ae9 1860 IsReply: 0x01,
153e2eac 1861 ErrorCode: [4]byte{0, 0, 0, 1},
d2810ae9 1862 Fields: []Field{
d005ef04 1863 NewField(FieldError, []byte("You are not allowed to create new accounts.")),
d2810ae9
JH
1864 },
1865 },
1866 },
d2810ae9
JH
1867 },
1868 {
1869 name: "when action is modify user without required permission",
1870 args: args{
1871 cc: &ClientConn{
02b446d8 1872 logger: NewTestLogger(),
d2810ae9
JH
1873 Server: &Server{
1874 Logger: NewTestLogger(),
1875 Accounts: map[string]*Account{
1876 "bbb": {},
1877 },
1878 },
1879 Account: &Account{
187d6dc5 1880 Access: func() accessBitmap {
d2810ae9 1881 var bits accessBitmap
187d6dc5 1882 return bits
d2810ae9
JH
1883 }(),
1884 },
1885 },
1886 t: NewTransaction(
d005ef04 1887 TranUpdateUser,
a2ef262a 1888 [2]byte{0, 0},
d005ef04 1889 NewField(FieldData, []byte{
d2810ae9
JH
1890 0x00, 0x04, // field count
1891
d005ef04 1892 0x00, 0x69, // FieldUserLogin = 105
d2810ae9
JH
1893 0x00, 0x03,
1894 0x9d, 0x9d, 0x9d,
1895
d005ef04 1896 0x00, 0x6a, // FieldUserPassword = 106
d2810ae9
JH
1897 0x00, 0x03,
1898 0x9c, 0x9c, 0x9c,
1899
d005ef04 1900 0x00, 0x66, // FieldUserName = 102
d2810ae9
JH
1901 0x00, 0x03,
1902 0x61, 0x61, 0x61,
1903
d005ef04 1904 0x00, 0x6e, // FieldUserAccess = 110
d2810ae9
JH
1905 0x00, 0x08,
1906 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1907 }),
1908 ),
1909 },
1910 wantRes: []Transaction{
1911 {
d2810ae9 1912 IsReply: 0x01,
153e2eac 1913 ErrorCode: [4]byte{0, 0, 0, 1},
d2810ae9 1914 Fields: []Field{
d005ef04 1915 NewField(FieldError, []byte("You are not allowed to modify accounts.")),
d2810ae9
JH
1916 },
1917 },
1918 },
d2810ae9
JH
1919 },
1920 {
1921 name: "when action is delete user without required permission",
1922 args: args{
1923 cc: &ClientConn{
02b446d8 1924 logger: NewTestLogger(),
d2810ae9 1925 Server: &Server{
d2810ae9
JH
1926 Accounts: map[string]*Account{
1927 "bbb": {},
1928 },
1929 },
1930 Account: &Account{
187d6dc5 1931 Access: func() accessBitmap {
d2810ae9 1932 var bits accessBitmap
187d6dc5 1933 return bits
d2810ae9
JH
1934 }(),
1935 },
1936 },
1937 t: NewTransaction(
d005ef04 1938 TranUpdateUser,
a2ef262a 1939 [2]byte{0, 0},
d005ef04 1940 NewField(FieldData, []byte{
d2810ae9
JH
1941 0x00, 0x01,
1942 0x00, 0x65,
1943 0x00, 0x03,
1944 0x88, 0x9e, 0x8b,
1945 }),
1946 ),
1947 },
1948 wantRes: []Transaction{
1949 {
d2810ae9 1950 IsReply: 0x01,
153e2eac 1951 ErrorCode: [4]byte{0, 0, 0, 1},
d2810ae9 1952 Fields: []Field{
d005ef04 1953 NewField(FieldError, []byte("You are not allowed to delete accounts.")),
d2810ae9
JH
1954 },
1955 },
1956 },
d2810ae9
JH
1957 },
1958 }
1959 for _, tt := range tests {
1960 t.Run(tt.name, func(t *testing.T) {
a2ef262a 1961 gotRes := HandleUpdateUser(tt.args.cc, &tt.args.t)
d2810ae9
JH
1962 tranAssertEqual(t, tt.wantRes, gotRes)
1963 })
1964 }
1965}
d4c152a4
JH
1966
1967func TestHandleDelNewsArt(t *testing.T) {
1968 type args struct {
1969 cc *ClientConn
a2ef262a 1970 t Transaction
d4c152a4
JH
1971 }
1972 tests := []struct {
1973 name string
1974 args args
1975 wantRes []Transaction
d4c152a4
JH
1976 }{
1977 {
1978 name: "without required permission",
1979 args: args{
1980 cc: &ClientConn{
1981 Account: &Account{
187d6dc5 1982 Access: func() accessBitmap {
d4c152a4 1983 var bits accessBitmap
187d6dc5 1984 return bits
d4c152a4
JH
1985 }(),
1986 },
1987 },
1988 t: NewTransaction(
d005ef04 1989 TranDelNewsArt,
a2ef262a 1990 [2]byte{0, 0},
d4c152a4
JH
1991 ),
1992 },
1993 wantRes: []Transaction{
1994 {
d4c152a4 1995 IsReply: 0x01,
153e2eac 1996 ErrorCode: [4]byte{0, 0, 0, 1},
d4c152a4 1997 Fields: []Field{
d005ef04 1998 NewField(FieldError, []byte("You are not allowed to delete news articles.")),
d4c152a4
JH
1999 },
2000 },
2001 },
d4c152a4
JH
2002 },
2003 }
2004 for _, tt := range tests {
2005 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2006 gotRes := HandleDelNewsArt(tt.args.cc, &tt.args.t)
d4c152a4
JH
2007 tranAssertEqual(t, tt.wantRes, gotRes)
2008 })
2009 }
2010}
2011
2012func TestHandleDisconnectUser(t *testing.T) {
2013 type args struct {
2014 cc *ClientConn
a2ef262a 2015 t Transaction
d4c152a4
JH
2016 }
2017 tests := []struct {
2018 name string
2019 args args
2020 wantRes []Transaction
d4c152a4
JH
2021 }{
2022 {
2023 name: "without required permission",
2024 args: args{
2025 cc: &ClientConn{
2026 Account: &Account{
187d6dc5 2027 Access: func() accessBitmap {
d4c152a4 2028 var bits accessBitmap
187d6dc5 2029 return bits
d4c152a4
JH
2030 }(),
2031 },
2032 },
2033 t: NewTransaction(
d005ef04 2034 TranDelNewsArt,
a2ef262a 2035 [2]byte{0, 0},
d4c152a4
JH
2036 ),
2037 },
2038 wantRes: []Transaction{
2039 {
d4c152a4 2040 IsReply: 0x01,
153e2eac 2041 ErrorCode: [4]byte{0, 0, 0, 1},
d4c152a4 2042 Fields: []Field{
d005ef04 2043 NewField(FieldError, []byte("You are not allowed to disconnect users.")),
d4c152a4
JH
2044 },
2045 },
2046 },
d4c152a4
JH
2047 },
2048 {
2049 name: "when target user has 'cannot be disconnected' priv",
2050 args: args{
2051 cc: &ClientConn{
2052 Server: &Server{
a2ef262a
JH
2053 Clients: map[[2]byte]*ClientConn{
2054 [2]byte{0, 1}: {
d4c152a4
JH
2055 Account: &Account{
2056 Login: "unnamed",
187d6dc5 2057 Access: func() accessBitmap {
d4c152a4
JH
2058 var bits accessBitmap
2059 bits.Set(accessCannotBeDiscon)
187d6dc5 2060 return bits
d4c152a4
JH
2061 }(),
2062 },
2063 },
2064 },
2065 },
2066 Account: &Account{
187d6dc5 2067 Access: func() accessBitmap {
d4c152a4
JH
2068 var bits accessBitmap
2069 bits.Set(accessDisconUser)
187d6dc5 2070 return bits
d4c152a4
JH
2071 }(),
2072 },
2073 },
2074 t: NewTransaction(
d005ef04 2075 TranDelNewsArt,
a2ef262a 2076 [2]byte{0, 0},
d005ef04 2077 NewField(FieldUserID, []byte{0, 1}),
d4c152a4
JH
2078 ),
2079 },
2080 wantRes: []Transaction{
2081 {
d4c152a4 2082 IsReply: 0x01,
153e2eac 2083 ErrorCode: [4]byte{0, 0, 0, 1},
d4c152a4 2084 Fields: []Field{
d005ef04 2085 NewField(FieldError, []byte("unnamed is not allowed to be disconnected.")),
d4c152a4
JH
2086 },
2087 },
2088 },
d4c152a4
JH
2089 },
2090 }
2091 for _, tt := range tests {
2092 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2093 gotRes := HandleDisconnectUser(tt.args.cc, &tt.args.t)
d4c152a4
JH
2094 tranAssertEqual(t, tt.wantRes, gotRes)
2095 })
2096 }
2097}
aeec1015
JH
2098
2099func TestHandleSendInstantMsg(t *testing.T) {
2100 type args struct {
2101 cc *ClientConn
a2ef262a 2102 t Transaction
aeec1015
JH
2103 }
2104 tests := []struct {
2105 name string
2106 args args
2107 wantRes []Transaction
aeec1015 2108 }{
69c2fb50
JH
2109 {
2110 name: "without required permission",
2111 args: args{
2112 cc: &ClientConn{
2113 Account: &Account{
187d6dc5 2114 Access: func() accessBitmap {
69c2fb50 2115 var bits accessBitmap
187d6dc5 2116 return bits
69c2fb50
JH
2117 }(),
2118 },
2119 },
2120 t: NewTransaction(
d005ef04 2121 TranDelNewsArt,
a2ef262a 2122 [2]byte{0, 0},
69c2fb50
JH
2123 ),
2124 },
2125 wantRes: []Transaction{
2126 {
69c2fb50 2127 IsReply: 0x01,
153e2eac 2128 ErrorCode: [4]byte{0, 0, 0, 1},
69c2fb50 2129 Fields: []Field{
d005ef04 2130 NewField(FieldError, []byte("You are not allowed to send private messages.")),
69c2fb50
JH
2131 },
2132 },
2133 },
69c2fb50 2134 },
aeec1015
JH
2135 {
2136 name: "when client 1 sends a message to client 2",
2137 args: args{
2138 cc: &ClientConn{
69c2fb50 2139 Account: &Account{
187d6dc5 2140 Access: func() accessBitmap {
69c2fb50
JH
2141 var bits accessBitmap
2142 bits.Set(accessSendPrivMsg)
187d6dc5 2143 return bits
69c2fb50
JH
2144 }(),
2145 },
a2ef262a 2146 ID: [2]byte{0, 1},
aeec1015
JH
2147 UserName: []byte("User1"),
2148 Server: &Server{
a2ef262a
JH
2149 Clients: map[[2]byte]*ClientConn{
2150 [2]byte{0, 2}: {
aeec1015 2151 AutoReply: []byte(nil),
a2ef262a 2152 Flags: [2]byte{0, 0},
aeec1015
JH
2153 },
2154 },
2155 },
2156 },
2157 t: NewTransaction(
d005ef04 2158 TranSendInstantMsg,
a2ef262a 2159 [2]byte{0, 1},
d005ef04
JH
2160 NewField(FieldData, []byte("hai")),
2161 NewField(FieldUserID, []byte{0, 2}),
aeec1015
JH
2162 ),
2163 },
2164 wantRes: []Transaction{
a2ef262a 2165 NewTransaction(
d005ef04 2166 TranServerMsg,
a2ef262a 2167 [2]byte{0, 2},
d005ef04
JH
2168 NewField(FieldData, []byte("hai")),
2169 NewField(FieldUserName, []byte("User1")),
2170 NewField(FieldUserID, []byte{0, 1}),
2171 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2172 ),
2173 {
a2ef262a 2174 clientID: [2]byte{0, 1},
153e2eac
JH
2175 IsReply: 0x01,
2176 Fields: []Field(nil),
aeec1015
JH
2177 },
2178 },
aeec1015
JH
2179 },
2180 {
2181 name: "when client 2 has autoreply enabled",
2182 args: args{
2183 cc: &ClientConn{
69c2fb50 2184 Account: &Account{
187d6dc5 2185 Access: func() accessBitmap {
69c2fb50
JH
2186 var bits accessBitmap
2187 bits.Set(accessSendPrivMsg)
187d6dc5 2188 return bits
69c2fb50
JH
2189 }(),
2190 },
a2ef262a 2191 ID: [2]byte{0, 1},
aeec1015
JH
2192 UserName: []byte("User1"),
2193 Server: &Server{
a2ef262a
JH
2194 Clients: map[[2]byte]*ClientConn{
2195 [2]byte{0, 2}: {
2196 Flags: [2]byte{0, 0},
2197 ID: [2]byte{0, 2},
aeec1015
JH
2198 UserName: []byte("User2"),
2199 AutoReply: []byte("autohai"),
2200 },
2201 },
2202 },
2203 },
2204 t: NewTransaction(
d005ef04 2205 TranSendInstantMsg,
a2ef262a 2206 [2]byte{0, 1},
d005ef04
JH
2207 NewField(FieldData, []byte("hai")),
2208 NewField(FieldUserID, []byte{0, 2}),
aeec1015
JH
2209 ),
2210 },
2211 wantRes: []Transaction{
a2ef262a 2212 NewTransaction(
d005ef04 2213 TranServerMsg,
a2ef262a 2214 [2]byte{0, 2},
d005ef04
JH
2215 NewField(FieldData, []byte("hai")),
2216 NewField(FieldUserName, []byte("User1")),
2217 NewField(FieldUserID, []byte{0, 1}),
2218 NewField(FieldOptions, []byte{0, 1}),
aeec1015 2219 ),
a2ef262a 2220 NewTransaction(
d005ef04 2221 TranServerMsg,
a2ef262a 2222 [2]byte{0, 1},
d005ef04
JH
2223 NewField(FieldData, []byte("autohai")),
2224 NewField(FieldUserName, []byte("User2")),
2225 NewField(FieldUserID, []byte{0, 2}),
2226 NewField(FieldOptions, []byte{0, 1}),
aeec1015
JH
2227 ),
2228 {
a2ef262a 2229 clientID: [2]byte{0, 1},
153e2eac
JH
2230 IsReply: 0x01,
2231 Fields: []Field(nil),
aeec1015
JH
2232 },
2233 },
aeec1015 2234 },
38f710ec
JH
2235 {
2236 name: "when client 2 has refuse private messages enabled",
2237 args: args{
2238 cc: &ClientConn{
2239 Account: &Account{
2240 Access: func() accessBitmap {
2241 var bits accessBitmap
2242 bits.Set(accessSendPrivMsg)
2243 return bits
2244 }(),
2245 },
a2ef262a 2246 ID: [2]byte{0, 1},
38f710ec
JH
2247 UserName: []byte("User1"),
2248 Server: &Server{
a2ef262a
JH
2249 Clients: map[[2]byte]*ClientConn{
2250 [2]byte{0, 2}: {
2251 Flags: [2]byte{255, 255},
2252 ID: [2]byte{0, 2},
38f710ec
JH
2253 UserName: []byte("User2"),
2254 },
2255 },
2256 },
2257 },
2258 t: NewTransaction(
d005ef04 2259 TranSendInstantMsg,
a2ef262a 2260 [2]byte{0, 1},
d005ef04
JH
2261 NewField(FieldData, []byte("hai")),
2262 NewField(FieldUserID, []byte{0, 2}),
38f710ec
JH
2263 ),
2264 },
2265 wantRes: []Transaction{
a2ef262a 2266 NewTransaction(
d005ef04 2267 TranServerMsg,
a2ef262a 2268 [2]byte{0, 1},
d005ef04
JH
2269 NewField(FieldData, []byte("User2 does not accept private messages.")),
2270 NewField(FieldUserName, []byte("User2")),
2271 NewField(FieldUserID, []byte{0, 2}),
2272 NewField(FieldOptions, []byte{0, 2}),
38f710ec
JH
2273 ),
2274 {
a2ef262a 2275 clientID: [2]byte{0, 1},
153e2eac
JH
2276 IsReply: 0x01,
2277 Fields: []Field(nil),
38f710ec
JH
2278 },
2279 },
38f710ec 2280 },
aeec1015
JH
2281 }
2282 for _, tt := range tests {
2283 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2284 gotRes := HandleSendInstantMsg(tt.args.cc, &tt.args.t)
aeec1015
JH
2285 tranAssertEqual(t, tt.wantRes, gotRes)
2286 })
2287 }
2288}
7cd900d6
JH
2289
2290func TestHandleDeleteFile(t *testing.T) {
2291 type args struct {
2292 cc *ClientConn
a2ef262a 2293 t Transaction
7cd900d6
JH
2294 }
2295 tests := []struct {
2296 name string
2297 args args
2298 wantRes []Transaction
7cd900d6
JH
2299 }{
2300 {
2301 name: "when user does not have required permission to delete a folder",
2302 args: args{
2303 cc: &ClientConn{
2304 Account: &Account{
187d6dc5 2305 Access: func() accessBitmap {
7cd900d6 2306 var bits accessBitmap
187d6dc5 2307 return bits
7cd900d6
JH
2308 }(),
2309 },
2310 Server: &Server{
2311 Config: &Config{
2312 FileRoot: func() string {
2313 return "/fakeRoot/Files"
2314 }(),
2315 },
2316 FS: func() *MockFileStore {
2317 mfi := &MockFileInfo{}
2318 mfi.On("Mode").Return(fs.FileMode(0))
2319 mfi.On("Size").Return(int64(100))
2320 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2321 mfi.On("IsDir").Return(false)
2322 mfi.On("Name").Return("testfile")
2323
2324 mfs := &MockFileStore{}
2325 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2326 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2327 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2328
2329 return mfs
2330 }(),
2331 Accounts: map[string]*Account{},
2332 },
2333 },
2334 t: NewTransaction(
a2ef262a 2335 TranDeleteFile, [2]byte{0, 1},
d005ef04
JH
2336 NewField(FieldFileName, []byte("testfile")),
2337 NewField(FieldFilePath, []byte{
7cd900d6
JH
2338 0x00, 0x01,
2339 0x00, 0x00,
2340 0x03,
2341 0x61, 0x61, 0x61,
2342 }),
2343 ),
2344 },
2345 wantRes: []Transaction{
2346 {
7cd900d6 2347 IsReply: 0x01,
153e2eac 2348 ErrorCode: [4]byte{0, 0, 0, 1},
7cd900d6 2349 Fields: []Field{
d005ef04 2350 NewField(FieldError, []byte("You are not allowed to delete files.")),
7cd900d6
JH
2351 },
2352 },
2353 },
7cd900d6
JH
2354 },
2355 {
2356 name: "deletes all associated metadata files",
2357 args: args{
2358 cc: &ClientConn{
2359 Account: &Account{
187d6dc5 2360 Access: func() accessBitmap {
7cd900d6
JH
2361 var bits accessBitmap
2362 bits.Set(accessDeleteFile)
187d6dc5 2363 return bits
7cd900d6
JH
2364 }(),
2365 },
2366 Server: &Server{
2367 Config: &Config{
2368 FileRoot: func() string {
2369 return "/fakeRoot/Files"
2370 }(),
2371 },
2372 FS: func() *MockFileStore {
2373 mfi := &MockFileInfo{}
2374 mfi.On("Mode").Return(fs.FileMode(0))
2375 mfi.On("Size").Return(int64(100))
2376 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2377 mfi.On("IsDir").Return(false)
2378 mfi.On("Name").Return("testfile")
2379
2380 mfs := &MockFileStore{}
2381 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2382 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2383 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2384
2385 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2386 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2387 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2388 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2389
2390 return mfs
2391 }(),
2392 Accounts: map[string]*Account{},
2393 },
2394 },
2395 t: NewTransaction(
a2ef262a 2396 TranDeleteFile, [2]byte{0, 1},
d005ef04
JH
2397 NewField(FieldFileName, []byte("testfile")),
2398 NewField(FieldFilePath, []byte{
7cd900d6
JH
2399 0x00, 0x01,
2400 0x00, 0x00,
2401 0x03,
2402 0x61, 0x61, 0x61,
2403 }),
2404 ),
2405 },
2406 wantRes: []Transaction{
2407 {
153e2eac
JH
2408 IsReply: 0x01,
2409 Fields: []Field(nil),
7cd900d6
JH
2410 },
2411 },
7cd900d6
JH
2412 },
2413 }
2414 for _, tt := range tests {
2415 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2416 gotRes := HandleDeleteFile(tt.args.cc, &tt.args.t)
7cd900d6
JH
2417 tranAssertEqual(t, tt.wantRes, gotRes)
2418
2419 tt.args.cc.Server.FS.(*MockFileStore).AssertExpectations(t)
2420 })
2421 }
2422}
2e08be58
JH
2423
2424func TestHandleGetFileNameList(t *testing.T) {
2425 type args struct {
2426 cc *ClientConn
a2ef262a 2427 t Transaction
2e08be58
JH
2428 }
2429 tests := []struct {
2430 name string
2431 args args
2432 wantRes []Transaction
2e08be58
JH
2433 }{
2434 {
d005ef04 2435 name: "when FieldFilePath is a drop box, but user does not have accessViewDropBoxes ",
2e08be58
JH
2436 args: args{
2437 cc: &ClientConn{
2438 Account: &Account{
187d6dc5 2439 Access: func() accessBitmap {
2e08be58 2440 var bits accessBitmap
187d6dc5 2441 return bits
2e08be58
JH
2442 }(),
2443 },
2444 Server: &Server{
2445
2446 Config: &Config{
2447 FileRoot: func() string {
2448 path, _ := os.Getwd()
2449 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2450 }(),
2451 },
2452 },
2453 },
2454 t: NewTransaction(
a2ef262a 2455 TranGetFileNameList, [2]byte{0, 1},
d005ef04 2456 NewField(FieldFilePath, []byte{
2e08be58
JH
2457 0x00, 0x01,
2458 0x00, 0x00,
2459 0x08,
2460 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2461 }),
2462 ),
2463 },
2464 wantRes: []Transaction{
2465 {
2e08be58 2466 IsReply: 0x01,
153e2eac 2467 ErrorCode: [4]byte{0, 0, 0, 1},
2e08be58 2468 Fields: []Field{
d005ef04 2469 NewField(FieldError, []byte("You are not allowed to view drop boxes.")),
2e08be58
JH
2470 },
2471 },
2472 },
2e08be58
JH
2473 },
2474 {
2475 name: "with file root",
2476 args: args{
2477 cc: &ClientConn{
2478 Server: &Server{
2479 Config: &Config{
2480 FileRoot: func() string {
2481 path, _ := os.Getwd()
2482 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2483 }(),
2484 },
2485 },
2486 },
2487 t: NewTransaction(
a2ef262a 2488 TranGetFileNameList, [2]byte{0, 1},
d005ef04 2489 NewField(FieldFilePath, []byte{
2e08be58
JH
2490 0x00, 0x00,
2491 0x00, 0x00,
2492 }),
2493 ),
2494 },
2495 wantRes: []Transaction{
2496 {
153e2eac 2497 IsReply: 0x01,
2e08be58
JH
2498 Fields: []Field{
2499 NewField(
d005ef04 2500 FieldFileNameWithInfo,
2e08be58
JH
2501 func() []byte {
2502 fnwi := FileNameWithInfo{
2503 fileNameWithInfoHeader: fileNameWithInfoHeader{
2504 Type: [4]byte{0x54, 0x45, 0x58, 0x54},
2505 Creator: [4]byte{0x54, 0x54, 0x58, 0x54},
2506 FileSize: [4]byte{0, 0, 0x04, 0},
2507 RSVD: [4]byte{},
2508 NameScript: [2]byte{},
2509 NameSize: [2]byte{0, 0x0b},
2510 },
95159e55 2511 Name: []byte("testfile-1k"),
2e08be58 2512 }
b129b7cb 2513 b, _ := io.ReadAll(&fnwi)
2e08be58
JH
2514 return b
2515 }(),
2516 ),
2517 },
2518 },
2519 },
2e08be58
JH
2520 },
2521 }
2522 for _, tt := range tests {
2523 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2524 gotRes := HandleGetFileNameList(tt.args.cc, &tt.args.t)
2e08be58
JH
2525 tranAssertEqual(t, tt.wantRes, gotRes)
2526 })
2527 }
2528}
df1ade54
JH
2529
2530func TestHandleGetClientInfoText(t *testing.T) {
2531 type args struct {
2532 cc *ClientConn
a2ef262a 2533 t Transaction
df1ade54
JH
2534 }
2535 tests := []struct {
2536 name string
2537 args args
2538 wantRes []Transaction
df1ade54
JH
2539 }{
2540 {
2541 name: "when user does not have required permission",
2542 args: args{
2543 cc: &ClientConn{
2544 Account: &Account{
187d6dc5 2545 Access: func() accessBitmap {
df1ade54 2546 var bits accessBitmap
187d6dc5 2547 return bits
df1ade54
JH
2548 }(),
2549 },
2550 Server: &Server{
2551 Accounts: map[string]*Account{},
2552 },
2553 },
2554 t: NewTransaction(
a2ef262a 2555 TranGetClientInfoText, [2]byte{0, 1},
d005ef04 2556 NewField(FieldUserID, []byte{0, 1}),
df1ade54
JH
2557 ),
2558 },
2559 wantRes: []Transaction{
2560 {
df1ade54 2561 IsReply: 0x01,
153e2eac 2562 ErrorCode: [4]byte{0, 0, 0, 1},
df1ade54 2563 Fields: []Field{
d005ef04 2564 NewField(FieldError, []byte("You are not allowed to get client info.")),
df1ade54
JH
2565 },
2566 },
2567 },
df1ade54
JH
2568 },
2569 {
2570 name: "with a valid user",
2571 args: args{
2572 cc: &ClientConn{
2573 UserName: []byte("Testy McTest"),
2574 RemoteAddr: "1.2.3.4:12345",
2575 Account: &Account{
187d6dc5 2576 Access: func() accessBitmap {
df1ade54
JH
2577 var bits accessBitmap
2578 bits.Set(accessGetClientInfo)
187d6dc5 2579 return bits
df1ade54
JH
2580 }(),
2581 Name: "test",
2582 Login: "test",
2583 },
2584 Server: &Server{
2585 Accounts: map[string]*Account{},
a2ef262a
JH
2586 Clients: map[[2]byte]*ClientConn{
2587 [2]byte{0, 1}: {
df1ade54
JH
2588 UserName: []byte("Testy McTest"),
2589 RemoteAddr: "1.2.3.4:12345",
2590 Account: &Account{
187d6dc5 2591 Access: func() accessBitmap {
df1ade54
JH
2592 var bits accessBitmap
2593 bits.Set(accessGetClientInfo)
187d6dc5 2594 return bits
df1ade54
JH
2595 }(),
2596 Name: "test",
2597 Login: "test",
2598 },
2599 },
2600 },
2601 },
2602 transfers: map[int]map[[4]byte]*FileTransfer{
2603 FileDownload: {},
2604 FileUpload: {},
2605 FolderDownload: {},
2606 FolderUpload: {},
2607 },
2608 },
2609 t: NewTransaction(
a2ef262a 2610 TranGetClientInfoText, [2]byte{0, 1},
d005ef04 2611 NewField(FieldUserID, []byte{0, 1}),
df1ade54
JH
2612 ),
2613 },
2614 wantRes: []Transaction{
2615 {
153e2eac 2616 IsReply: 0x01,
df1ade54 2617 Fields: []Field{
d005ef04 2618 NewField(FieldData, []byte(
c8bfd606 2619 strings.ReplaceAll(`Nickname: Testy McTest
df1ade54
JH
2620Name: test
2621Account: test
2622Address: 1.2.3.4:12345
2623
2624-------- File Downloads ---------
2625
2626None.
2627
2628------- Folder Downloads --------
2629
2630None.
2631
2632--------- File Uploads ----------
2633
2634None.
2635
2636-------- Folder Uploads ---------
2637
2638None.
2639
2640------- Waiting Downloads -------
2641
2642None.
2643
c8bfd606 2644`, "\n", "\r")),
df1ade54 2645 ),
d005ef04 2646 NewField(FieldUserName, []byte("Testy McTest")),
df1ade54
JH
2647 },
2648 },
2649 },
df1ade54
JH
2650 },
2651 }
2652 for _, tt := range tests {
2653 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2654 gotRes := HandleGetClientInfoText(tt.args.cc, &tt.args.t)
df1ade54
JH
2655 tranAssertEqual(t, tt.wantRes, gotRes)
2656 })
2657 }
2658}
ea5d8c51
JH
2659
2660func TestHandleTranAgreed(t *testing.T) {
2661 type args struct {
2662 cc *ClientConn
a2ef262a 2663 t Transaction
ea5d8c51
JH
2664 }
2665 tests := []struct {
2666 name string
2667 args args
2668 wantRes []Transaction
ea5d8c51
JH
2669 }{
2670 {
2671 name: "normal request flow",
2672 args: args{
2673 cc: &ClientConn{
2674 Account: &Account{
187d6dc5 2675 Access: func() accessBitmap {
ea5d8c51
JH
2676 var bits accessBitmap
2677 bits.Set(accessDisconUser)
2678 bits.Set(accessAnyName)
187d6dc5 2679 return bits
ea5d8c51 2680 }()},
a7216f67 2681 Icon: []byte{0, 1},
a2ef262a 2682 Flags: [2]byte{0, 1},
a7216f67 2683 Version: []byte{0, 1},
a2ef262a 2684 ID: [2]byte{0, 1},
ea5d8c51
JH
2685 logger: NewTestLogger(),
2686 Server: &Server{
2687 Config: &Config{
2688 BannerFile: "banner.jpg",
2689 },
2690 },
2691 },
2692 t: NewTransaction(
a2ef262a 2693 TranAgreed, [2]byte{},
d005ef04
JH
2694 NewField(FieldUserName, []byte("username")),
2695 NewField(FieldUserIconID, []byte{0, 1}),
2696 NewField(FieldOptions, []byte{0, 0}),
ea5d8c51
JH
2697 ),
2698 },
2699 wantRes: []Transaction{
2700 {
a2ef262a 2701 clientID: [2]byte{0, 1},
153e2eac 2702 Type: [2]byte{0, 0x7a},
ea5d8c51 2703 Fields: []Field{
d005ef04 2704 NewField(FieldBannerType, []byte("JPEG")),
ea5d8c51
JH
2705 },
2706 },
2707 {
a2ef262a 2708 clientID: [2]byte{0, 1},
153e2eac
JH
2709 IsReply: 0x01,
2710 Fields: []Field{},
ea5d8c51
JH
2711 },
2712 },
ea5d8c51
JH
2713 },
2714 }
2715 for _, tt := range tests {
2716 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2717 gotRes := HandleTranAgreed(tt.args.cc, &tt.args.t)
ea5d8c51
JH
2718 tranAssertEqual(t, tt.wantRes, gotRes)
2719 })
2720 }
2721}
264b7c27
JH
2722
2723func TestHandleSetClientUserInfo(t *testing.T) {
2724 type args struct {
2725 cc *ClientConn
a2ef262a 2726 t Transaction
264b7c27
JH
2727 }
2728 tests := []struct {
2729 name string
2730 args args
2731 wantRes []Transaction
264b7c27
JH
2732 }{
2733 {
2734 name: "when client does not have accessAnyName",
2735 args: args{
2736 cc: &ClientConn{
2737 Account: &Account{
187d6dc5 2738 Access: func() accessBitmap {
264b7c27 2739 var bits accessBitmap
187d6dc5 2740 return bits
264b7c27
JH
2741 }(),
2742 },
a2ef262a 2743 ID: [2]byte{0, 1},
264b7c27 2744 UserName: []byte("Guest"),
a2ef262a 2745 Flags: [2]byte{0, 1},
264b7c27 2746 Server: &Server{
a2ef262a
JH
2747 Clients: map[[2]byte]*ClientConn{
2748 [2]byte{0, 1}: {
2749 ID: [2]byte{0, 1},
264b7c27
JH
2750 },
2751 },
2752 },
2753 },
2754 t: NewTransaction(
a2ef262a 2755 TranSetClientUserInfo, [2]byte{},
d005ef04
JH
2756 NewField(FieldUserIconID, []byte{0, 1}),
2757 NewField(FieldUserName, []byte("NOPE")),
264b7c27
JH
2758 ),
2759 },
2760 wantRes: []Transaction{
2761 {
a2ef262a 2762 clientID: [2]byte{0, 1},
153e2eac 2763 Type: [2]byte{0x01, 0x2d},
264b7c27 2764 Fields: []Field{
d005ef04
JH
2765 NewField(FieldUserID, []byte{0, 1}),
2766 NewField(FieldUserIconID, []byte{0, 1}),
2767 NewField(FieldUserFlags, []byte{0, 1}),
2768 NewField(FieldUserName, []byte("Guest"))},
264b7c27
JH
2769 },
2770 },
264b7c27
JH
2771 },
2772 }
2773 for _, tt := range tests {
2774 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2775 gotRes := HandleSetClientUserInfo(tt.args.cc, &tt.args.t)
264b7c27
JH
2776 tranAssertEqual(t, tt.wantRes, gotRes)
2777 })
2778 }
2779}
8eb43f95
JH
2780
2781func TestHandleDelNewsItem(t *testing.T) {
2782 type args struct {
2783 cc *ClientConn
a2ef262a 2784 t Transaction
8eb43f95
JH
2785 }
2786 tests := []struct {
2787 name string
2788 args args
2789 wantRes []Transaction
8eb43f95
JH
2790 }{
2791 {
2792 name: "when user does not have permission to delete a news category",
2793 args: args{
2794 cc: &ClientConn{
2795 Account: &Account{
2796 Access: accessBitmap{},
2797 },
a2ef262a 2798 ID: [2]byte{0, 1},
8eb43f95
JH
2799 Server: &Server{
2800 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
2801 "test": {
0ed51327
JH
2802 Type: [2]byte{0, 3},
2803 Name: "zz",
8eb43f95
JH
2804 },
2805 }},
2806 },
2807 },
2808 t: NewTransaction(
a2ef262a 2809 TranDelNewsItem, [2]byte{},
d005ef04 2810 NewField(FieldNewsPath,
8eb43f95
JH
2811 []byte{
2812 0, 1,
2813 0, 0,
2814 4,
2815 0x74, 0x65, 0x73, 0x74,
2816 },
2817 ),
2818 ),
2819 },
2820 wantRes: []Transaction{
2821 {
a2ef262a 2822 clientID: [2]byte{0, 1},
8eb43f95 2823 IsReply: 0x01,
153e2eac 2824 ErrorCode: [4]byte{0, 0, 0, 1},
8eb43f95 2825 Fields: []Field{
d005ef04 2826 NewField(FieldError, []byte("You are not allowed to delete news categories.")),
8eb43f95
JH
2827 },
2828 },
2829 },
8eb43f95
JH
2830 },
2831 {
2832 name: "when user does not have permission to delete a news folder",
2833 args: args{
2834 cc: &ClientConn{
2835 Account: &Account{
2836 Access: accessBitmap{},
2837 },
a2ef262a 2838 ID: [2]byte{0, 1},
8eb43f95
JH
2839 Server: &Server{
2840 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
2841 "testcat": {
0ed51327
JH
2842 Type: [2]byte{0, 2},
2843 Name: "test",
8eb43f95
JH
2844 },
2845 }},
2846 },
2847 },
2848 t: NewTransaction(
a2ef262a 2849 TranDelNewsItem, [2]byte{},
d005ef04 2850 NewField(FieldNewsPath,
8eb43f95
JH
2851 []byte{
2852 0, 1,
2853 0, 0,
2854 4,
2855 0x74, 0x65, 0x73, 0x74,
2856 },
2857 ),
2858 ),
2859 },
2860 wantRes: []Transaction{
2861 {
a2ef262a 2862 clientID: [2]byte{0, 1},
8eb43f95 2863 IsReply: 0x01,
153e2eac 2864 ErrorCode: [4]byte{0, 0, 0, 1},
8eb43f95 2865 Fields: []Field{
d005ef04 2866 NewField(FieldError, []byte("You are not allowed to delete news folders.")),
8eb43f95
JH
2867 },
2868 },
2869 },
8eb43f95
JH
2870 },
2871 {
2872 name: "when user deletes a news folder",
2873 args: args{
2874 cc: &ClientConn{
2875 Account: &Account{
2876 Access: func() accessBitmap {
2877 var bits accessBitmap
2878 bits.Set(accessNewsDeleteFldr)
2879 return bits
2880 }(),
2881 },
a2ef262a 2882 ID: [2]byte{0, 1},
8eb43f95
JH
2883 Server: &Server{
2884 ConfigDir: "/fakeConfigRoot",
2885 FS: func() *MockFileStore {
2886 mfs := &MockFileStore{}
2887 mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(nil, os.ErrNotExist)
2888 return mfs
2889 }(),
2890 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
2891 "testcat": {
0ed51327
JH
2892 Type: [2]byte{0, 2},
2893 Name: "test",
8eb43f95
JH
2894 },
2895 }},
2896 },
2897 },
2898 t: NewTransaction(
a2ef262a 2899 TranDelNewsItem, [2]byte{},
d005ef04 2900 NewField(FieldNewsPath,
8eb43f95
JH
2901 []byte{
2902 0, 1,
2903 0, 0,
2904 4,
2905 0x74, 0x65, 0x73, 0x74,
2906 },
2907 ),
2908 ),
2909 },
2910 wantRes: []Transaction{
2911 {
a2ef262a 2912 clientID: [2]byte{0, 1},
153e2eac
JH
2913 IsReply: 0x01,
2914 Fields: []Field{},
8eb43f95
JH
2915 },
2916 },
8eb43f95
JH
2917 },
2918 }
2919 for _, tt := range tests {
2920 t.Run(tt.name, func(t *testing.T) {
a2ef262a
JH
2921 gotRes := HandleDelNewsItem(tt.args.cc, &tt.args.t)
2922
8eb43f95 2923 tranAssertEqual(t, tt.wantRes, gotRes)
969e6481
JH
2924 })
2925 }
2926}
8a1512f9
JH
2927
2928func TestHandleTranOldPostNews(t *testing.T) {
2929 type args struct {
2930 cc *ClientConn
a2ef262a 2931 t Transaction
8a1512f9
JH
2932 }
2933 tests := []struct {
2934 name string
2935 args args
2936 wantRes []Transaction
8a1512f9
JH
2937 }{
2938 {
2939 name: "when user does not have required permission",
2940 args: args{
2941 cc: &ClientConn{
2942 Account: &Account{
2943 Access: func() accessBitmap {
2944 var bits accessBitmap
2945 return bits
2946 }(),
2947 },
2948 },
2949 t: NewTransaction(
a2ef262a 2950 TranOldPostNews, [2]byte{0, 1},
d005ef04 2951 NewField(FieldData, []byte("hai")),
8a1512f9
JH
2952 ),
2953 },
2954 wantRes: []Transaction{
2955 {
8a1512f9 2956 IsReply: 0x01,
153e2eac 2957 ErrorCode: [4]byte{0, 0, 0, 1},
8a1512f9 2958 Fields: []Field{
d005ef04 2959 NewField(FieldError, []byte("You are not allowed to post news.")),
8a1512f9
JH
2960 },
2961 },
2962 },
8a1512f9
JH
2963 },
2964 {
2965 name: "when user posts news update",
2966 args: args{
2967 cc: &ClientConn{
2968 Account: &Account{
2969 Access: func() accessBitmap {
2970 var bits accessBitmap
2971 bits.Set(accessNewsPostArt)
2972 return bits
2973 }(),
2974 },
2975 Server: &Server{
2976 FS: func() *MockFileStore {
2977 mfs := &MockFileStore{}
2978 mfs.On("WriteFile", "/fakeConfigRoot/MessageBoard.txt", mock.Anything, mock.Anything).Return(nil, os.ErrNotExist)
2979 return mfs
2980 }(),
2981 ConfigDir: "/fakeConfigRoot",
2982 Config: &Config{},
2983 },
2984 },
2985 t: NewTransaction(
a2ef262a 2986 TranOldPostNews, [2]byte{0, 1},
d005ef04 2987 NewField(FieldData, []byte("hai")),
8a1512f9
JH
2988 ),
2989 },
2990 wantRes: []Transaction{
2991 {
153e2eac 2992 IsReply: 0x01,
8a1512f9
JH
2993 },
2994 },
8a1512f9
JH
2995 },
2996 }
2997 for _, tt := range tests {
2998 t.Run(tt.name, func(t *testing.T) {
a2ef262a 2999 gotRes := HandleTranOldPostNews(tt.args.cc, &tt.args.t)
8a1512f9
JH
3000
3001 tranAssertEqual(t, tt.wantRes, gotRes)
3002 })
3003 }
3004}
c1c44744
JH
3005
3006func TestHandleInviteNewChat(t *testing.T) {
3007 type args struct {
3008 cc *ClientConn
a2ef262a 3009 t Transaction
c1c44744
JH
3010 }
3011 tests := []struct {
3012 name string
3013 args args
3014 wantRes []Transaction
c1c44744
JH
3015 }{
3016 {
3017 name: "when user does not have required permission",
3018 args: args{
3019 cc: &ClientConn{
3020 Account: &Account{
3021 Access: func() accessBitmap {
3022 var bits accessBitmap
3023 return bits
3024 }(),
3025 },
3026 },
a2ef262a 3027 t: NewTransaction(TranInviteNewChat, [2]byte{0, 1}),
c1c44744
JH
3028 },
3029 wantRes: []Transaction{
3030 {
c1c44744 3031 IsReply: 0x01,
153e2eac 3032 ErrorCode: [4]byte{0, 0, 0, 1},
c1c44744 3033 Fields: []Field{
d005ef04 3034 NewField(FieldError, []byte("You are not allowed to request private chat.")),
c1c44744
JH
3035 },
3036 },
3037 },
c1c44744
JH
3038 },
3039 {
3040 name: "when userA invites userB to new private chat",
3041 args: args{
3042 cc: &ClientConn{
a2ef262a 3043 ID: [2]byte{0, 1},
c1c44744
JH
3044 Account: &Account{
3045 Access: func() accessBitmap {
3046 var bits accessBitmap
3047 bits.Set(accessOpenChat)
3048 return bits
3049 }(),
3050 },
3051 UserName: []byte("UserA"),
3052 Icon: []byte{0, 1},
a2ef262a 3053 Flags: [2]byte{0, 0},
c1c44744 3054 Server: &Server{
a2ef262a
JH
3055 Clients: map[[2]byte]*ClientConn{
3056 [2]byte{0, 2}: {
3057 ID: [2]byte{0, 2},
c1c44744 3058 UserName: []byte("UserB"),
c1c44744
JH
3059 },
3060 },
a2ef262a 3061 PrivateChats: make(map[[4]byte]*PrivateChat),
c1c44744
JH
3062 },
3063 },
3064 t: NewTransaction(
a2ef262a 3065 TranInviteNewChat, [2]byte{0, 1},
d005ef04 3066 NewField(FieldUserID, []byte{0, 2}),
c1c44744
JH
3067 ),
3068 },
3069 wantRes: []Transaction{
3070 {
a2ef262a 3071 clientID: [2]byte{0, 2},
153e2eac 3072 Type: [2]byte{0, 0x71},
c1c44744 3073 Fields: []Field{
d005ef04
JH
3074 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3075 NewField(FieldUserName, []byte("UserA")),
3076 NewField(FieldUserID, []byte{0, 1}),
c1c44744
JH
3077 },
3078 },
3079
3080 {
a2ef262a 3081 clientID: [2]byte{0, 1},
153e2eac 3082 IsReply: 0x01,
c1c44744 3083 Fields: []Field{
d005ef04
JH
3084 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3085 NewField(FieldUserName, []byte("UserA")),
3086 NewField(FieldUserID, []byte{0, 1}),
3087 NewField(FieldUserIconID, []byte{0, 1}),
3088 NewField(FieldUserFlags, []byte{0, 0}),
c1c44744
JH
3089 },
3090 },
3091 },
c1c44744
JH
3092 },
3093 {
3094 name: "when userA invites userB to new private chat, but UserB has refuse private chat enabled",
3095 args: args{
3096 cc: &ClientConn{
a2ef262a 3097 ID: [2]byte{0, 1},
c1c44744
JH
3098 Account: &Account{
3099 Access: func() accessBitmap {
3100 var bits accessBitmap
3101 bits.Set(accessOpenChat)
3102 return bits
3103 }(),
3104 },
3105 UserName: []byte("UserA"),
3106 Icon: []byte{0, 1},
a2ef262a 3107 Flags: [2]byte{0, 0},
c1c44744 3108 Server: &Server{
a2ef262a
JH
3109 Clients: map[[2]byte]*ClientConn{
3110 [2]byte{0, 2}: {
3111 ID: [2]byte{0, 2},
c1c44744 3112 UserName: []byte("UserB"),
a2ef262a 3113 Flags: [2]byte{255, 255},
c1c44744
JH
3114 },
3115 },
a2ef262a 3116 PrivateChats: make(map[[4]byte]*PrivateChat),
c1c44744
JH
3117 },
3118 },
3119 t: NewTransaction(
a2ef262a 3120 TranInviteNewChat, [2]byte{0, 1},
d005ef04 3121 NewField(FieldUserID, []byte{0, 2}),
c1c44744
JH
3122 ),
3123 },
3124 wantRes: []Transaction{
3125 {
a2ef262a 3126 clientID: [2]byte{0, 1},
153e2eac 3127 Type: [2]byte{0, 0x68},
c1c44744 3128 Fields: []Field{
d005ef04
JH
3129 NewField(FieldData, []byte("UserB does not accept private chats.")),
3130 NewField(FieldUserName, []byte("UserB")),
3131 NewField(FieldUserID, []byte{0, 2}),
3132 NewField(FieldOptions, []byte{0, 2}),
c1c44744
JH
3133 },
3134 },
3135 {
a2ef262a 3136 clientID: [2]byte{0, 1},
153e2eac 3137 IsReply: 0x01,
c1c44744 3138 Fields: []Field{
d005ef04
JH
3139 NewField(FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3140 NewField(FieldUserName, []byte("UserA")),
3141 NewField(FieldUserID, []byte{0, 1}),
3142 NewField(FieldUserIconID, []byte{0, 1}),
3143 NewField(FieldUserFlags, []byte{0, 0}),
c1c44744
JH
3144 },
3145 },
3146 },
c1c44744
JH
3147 },
3148 }
3149 for _, tt := range tests {
3150 t.Run(tt.name, func(t *testing.T) {
a2ef262a
JH
3151 gotRes := HandleInviteNewChat(tt.args.cc, &tt.args.t)
3152
c1c44744
JH
3153 tranAssertEqual(t, tt.wantRes, gotRes)
3154 })
3155 }
3156}
33265393
JH
3157
3158func TestHandleGetNewsArtData(t *testing.T) {
3159 type args struct {
3160 cc *ClientConn
a2ef262a 3161 t Transaction
33265393
JH
3162 }
3163 tests := []struct {
3164 name string
3165 args args
3166 wantRes []Transaction
33265393
JH
3167 }{
3168 {
3169 name: "when user does not have required permission",
3170 args: args{
3171 cc: &ClientConn{
3172 Account: &Account{
3173 Access: func() accessBitmap {
3174 var bits accessBitmap
3175 return bits
3176 }(),
3177 },
3178 Server: &Server{
3179 Accounts: map[string]*Account{},
3180 },
3181 },
3182 t: NewTransaction(
a2ef262a 3183 TranGetNewsArtData, [2]byte{0, 1},
33265393
JH
3184 ),
3185 },
3186 wantRes: []Transaction{
3187 {
33265393 3188 IsReply: 0x01,
153e2eac 3189 ErrorCode: [4]byte{0, 0, 0, 1},
33265393 3190 Fields: []Field{
d005ef04 3191 NewField(FieldError, []byte("You are not allowed to read news.")),
33265393
JH
3192 },
3193 },
3194 },
33265393
JH
3195 },
3196 }
3197 for _, tt := range tests {
3198 t.Run(tt.name, func(t *testing.T) {
a2ef262a 3199 gotRes := HandleGetNewsArtData(tt.args.cc, &tt.args.t)
33265393
JH
3200 tranAssertEqual(t, tt.wantRes, gotRes)
3201 })
3202 }
3203}
860861f2
JH
3204
3205func TestHandleGetNewsArtNameList(t *testing.T) {
3206 type args struct {
3207 cc *ClientConn
a2ef262a 3208 t Transaction
860861f2
JH
3209 }
3210 tests := []struct {
3211 name string
3212 args args
3213 wantRes []Transaction
860861f2
JH
3214 }{
3215 {
3216 name: "when user does not have required permission",
3217 args: args{
3218 cc: &ClientConn{
3219 Account: &Account{
3220 Access: func() accessBitmap {
3221 var bits accessBitmap
3222 return bits
3223 }(),
3224 },
3225 Server: &Server{
3226 Accounts: map[string]*Account{},
3227 },
3228 },
3229 t: NewTransaction(
a2ef262a 3230 TranGetNewsArtNameList, [2]byte{0, 1},
860861f2
JH
3231 ),
3232 },
3233 wantRes: []Transaction{
3234 {
3235 Flags: 0x00,
3236 IsReply: 0x01,
153e2eac
JH
3237 Type: [2]byte{0, 0},
3238 ErrorCode: [4]byte{0, 0, 0, 1},
860861f2 3239 Fields: []Field{
d005ef04 3240 NewField(FieldError, []byte("You are not allowed to read news.")),
860861f2
JH
3241 },
3242 },
3243 },
860861f2 3244 },
f8e4cd54
JH
3245 {
3246 name: "when user has required access",
3247 args: args{
3248 cc: &ClientConn{
3249 Account: &Account{
3250 Access: func() accessBitmap {
3251 var bits accessBitmap
3252 bits.Set(accessNewsReadArt)
3253 return bits
3254 }(),
3255 },
3256 Server: &Server{
3257 ThreadedNews: &ThreadedNews{
3258 Categories: map[string]NewsCategoryListData15{
3259 "Example Category": {
3260 Type: [2]byte{0, 2},
3261 Name: "",
3262 Articles: map[uint32]*NewsArtData{
3263 uint32(1): {
3264 Title: "testTitle",
3265 Poster: "testPoster",
3266 Data: "testBody",
3267 },
3268 },
3269 SubCats: nil,
3270 GUID: [16]byte{},
3271 AddSN: [4]byte{},
3272 DeleteSN: [4]byte{},
3273 },
3274 },
3275 },
3276
3277 //Accounts: map[string]*Account{
3278 // "guest": {
3279 // Name: "guest",
3280 // Login: "guest",
3281 // Password: "zz",
3282 // Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
3283 // },
3284 //},
3285 },
3286 },
3287 t: NewTransaction(
3288 TranGetNewsArtNameList,
a2ef262a 3289 [2]byte{0, 1},
f8e4cd54
JH
3290 // 00000000 00 01 00 00 10 45 78 61 6d 70 6c 65 20 43 61 74 |.....Example Cat|
3291 // 00000010 65 67 6f 72 79 |egory|
3292 NewField(FieldNewsPath, []byte{
3293 0x00, 0x01, 0x00, 0x00, 0x10, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79,
3294 }),
3295 ),
3296 },
3297 wantRes: []Transaction{
3298 {
153e2eac 3299 IsReply: 0x01,
f8e4cd54
JH
3300 Fields: []Field{
3301 NewField(FieldNewsArtListData, []byte{
3302 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
3303 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
3304 0x09, 0x74, 0x65, 0x73, 0x74, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x50,
3305 0x6f, 0x73, 0x74, 0x65, 0x72, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e,
3306 0x00, 0x08,
3307 },
3308 ),
3309 },
3310 },
3311 },
f8e4cd54 3312 },
860861f2
JH
3313 }
3314 for _, tt := range tests {
3315 t.Run(tt.name, func(t *testing.T) {
a2ef262a
JH
3316 gotRes := HandleGetNewsArtNameList(tt.args.cc, &tt.args.t)
3317
860861f2 3318 tranAssertEqual(t, tt.wantRes, gotRes)
860861f2
JH
3319 })
3320 }
3321}
3322
3323func TestHandleNewNewsFldr(t *testing.T) {
3324 type args struct {
3325 cc *ClientConn
a2ef262a 3326 t Transaction
860861f2
JH
3327 }
3328 tests := []struct {
3329 name string
3330 args args
3331 wantRes []Transaction
860861f2
JH
3332 }{
3333 {
3334 name: "when user does not have required permission",
3335 args: args{
3336 cc: &ClientConn{
3337 Account: &Account{
3338 Access: func() accessBitmap {
3339 var bits accessBitmap
3340 return bits
3341 }(),
3342 },
3343 Server: &Server{
3344 Accounts: map[string]*Account{},
3345 },
3346 },
3347 t: NewTransaction(
a2ef262a 3348 TranGetNewsArtNameList, [2]byte{0, 1},
860861f2
JH
3349 ),
3350 },
3351 wantRes: []Transaction{
3352 {
3353 Flags: 0x00,
3354 IsReply: 0x01,
153e2eac
JH
3355 Type: [2]byte{0, 0},
3356 ErrorCode: [4]byte{0, 0, 0, 1},
860861f2 3357 Fields: []Field{
d005ef04 3358 NewField(FieldError, []byte("You are not allowed to create news folders.")),
860861f2
JH
3359 },
3360 },
3361 },
860861f2
JH
3362 },
3363 {
3364 name: "with a valid request",
3365 args: args{
3366 cc: &ClientConn{
3367 Account: &Account{
3368 Access: func() accessBitmap {
3369 var bits accessBitmap
3370 bits.Set(accessNewsCreateFldr)
3371 return bits
3372 }(),
3373 },
3374 logger: NewTestLogger(),
a2ef262a 3375 ID: [2]byte{0, 1},
860861f2
JH
3376 Server: &Server{
3377 ConfigDir: "/fakeConfigRoot",
3378 FS: func() *MockFileStore {
3379 mfs := &MockFileStore{}
3380 mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(nil)
3381 return mfs
3382 }(),
3383 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3384 "test": {
0ed51327
JH
3385 Type: [2]byte{0, 2},
3386 Name: "test",
3387 SubCats: make(map[string]NewsCategoryListData15),
860861f2
JH
3388 },
3389 }},
3390 },
3391 },
3392 t: NewTransaction(
a2ef262a 3393 TranGetNewsArtNameList, [2]byte{0, 1},
d005ef04
JH
3394 NewField(FieldFileName, []byte("testFolder")),
3395 NewField(FieldNewsPath,
860861f2
JH
3396 []byte{
3397 0, 1,
3398 0, 0,
3399 4,
3400 0x74, 0x65, 0x73, 0x74,
3401 },
3402 ),
3403 ),
3404 },
3405 wantRes: []Transaction{
3406 {
a2ef262a 3407 clientID: [2]byte{0, 1},
153e2eac
JH
3408 IsReply: 0x01,
3409 Fields: []Field{},
860861f2
JH
3410 },
3411 },
860861f2
JH
3412 },
3413 //{
95159e55 3414 // Name: "when there is an error writing the threaded news file",
860861f2
JH
3415 // args: args{
3416 // cc: &ClientConn{
3417 // Account: &Account{
3418 // Access: func() accessBitmap {
3419 // var bits accessBitmap
3420 // bits.Set(accessNewsCreateFldr)
3421 // return bits
3422 // }(),
3423 // },
3424 // logger: NewTestLogger(),
a2ef262a 3425 // ID: [2]byte{0, 1},
860861f2
JH
3426 // Server: &Server{
3427 // ConfigDir: "/fakeConfigRoot",
3428 // FS: func() *MockFileStore {
3429 // mfs := &MockFileStore{}
3430 // mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(os.ErrNotExist)
3431 // return mfs
3432 // }(),
3433 // ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3434 // "test": {
3435 // Type: []byte{0, 2},
3436 // Count: nil,
3437 // NameSize: 0,
3438 // Name: "test",
3439 // SubCats: make(map[string]NewsCategoryListData15),
3440 // },
3441 // }},
3442 // },
3443 // },
3444 // t: NewTransaction(
a2ef262a 3445 // TranGetNewsArtNameList, [2]byte{0, 1},
d005ef04
JH
3446 // NewField(FieldFileName, []byte("testFolder")),
3447 // NewField(FieldNewsPath,
860861f2
JH
3448 // []byte{
3449 // 0, 1,
3450 // 0, 0,
3451 // 4,
3452 // 0x74, 0x65, 0x73, 0x74,
3453 // },
3454 // ),
3455 // ),
3456 // },
3457 // wantRes: []Transaction{
3458 // {
a2ef262a 3459 // clientID: [2]byte{0, 1},
860861f2
JH
3460 // Flags: 0x00,
3461 // IsReply: 0x01,
153e2eac
JH
3462 // Type: [2]byte{0, 0},
3463 // ErrorCode: [4]byte{0, 0, 0, 1},
860861f2 3464 // Fields: []Field{
d005ef04 3465 // NewField(FieldError, []byte("Error creating news folder.")),
860861f2
JH
3466 // },
3467 // },
3468 // },
860861f2
JH
3469 }
3470 for _, tt := range tests {
3471 t.Run(tt.name, func(t *testing.T) {
a2ef262a
JH
3472 gotRes := HandleNewNewsFldr(tt.args.cc, &tt.args.t)
3473
860861f2
JH
3474 tranAssertEqual(t, tt.wantRes, gotRes)
3475 })
3476 }
3477}
0ed51327
JH
3478
3479func TestHandleDownloadBanner(t *testing.T) {
3480 type args struct {
3481 cc *ClientConn
a2ef262a 3482 t Transaction
0ed51327
JH
3483 }
3484 tests := []struct {
3485 name string
3486 args args
3487 wantRes []Transaction
0ed51327
JH
3488 }{
3489 // TODO: Add test cases.
3490 }
3491 for _, tt := range tests {
3492 t.Run(tt.name, func(t *testing.T) {
a2ef262a
JH
3493 gotRes := HandleDownloadBanner(tt.args.cc, &tt.args.t)
3494
3495 assert.Equalf(t, tt.wantRes, gotRes, "HandleDownloadBanner(%v, %v)", tt.args.cc, &tt.args.t)
3496 })
3497 }
3498}
3499
3500func TestHandlePostNewsArt(t *testing.T) {
3501 type args struct {
3502 cc *ClientConn
3503 t Transaction
3504 }
3505 tests := []struct {
3506 name string
3507 args args
3508 wantRes []Transaction
3509 }{
3510 {
3511 name: "without required permission",
3512 args: args{
3513 cc: &ClientConn{
3514 Account: &Account{
3515 Access: func() accessBitmap {
3516 var bits accessBitmap
3517 return bits
3518 }(),
3519 },
3520 },
3521 t: NewTransaction(
3522 TranPostNewsArt,
3523 [2]byte{0, 0},
3524 ),
3525 },
3526 wantRes: []Transaction{
3527 {
3528 IsReply: 0x01,
3529 ErrorCode: [4]byte{0, 0, 0, 1},
3530 Fields: []Field{
3531 NewField(FieldError, []byte("You are not allowed to post news articles.")),
3532 },
3533 },
3534 },
3535 },
3536 {
3537 name: "with required permission",
3538 args: args{
3539 cc: &ClientConn{
3540 Server: &Server{
3541 FS: func() *MockFileStore {
3542 mfs := &MockFileStore{}
3543 mfs.On("WriteFile", "ThreadedNews.yaml", mock.Anything, mock.Anything).Return(nil, os.ErrNotExist)
3544 return mfs
3545 }(),
3546 mux: sync.Mutex{},
3547 threadedNewsMux: sync.Mutex{},
3548 ThreadedNews: &ThreadedNews{
3549 Categories: map[string]NewsCategoryListData15{
3550 "www": {
3551 Type: [2]byte{},
3552 Name: "www",
3553 Articles: map[uint32]*NewsArtData{},
3554 SubCats: nil,
3555 GUID: [16]byte{},
3556 AddSN: [4]byte{},
3557 DeleteSN: [4]byte{},
3558 readOffset: 0,
3559 },
3560 },
3561 },
3562 },
3563 Account: &Account{
3564 Access: func() accessBitmap {
3565 var bits accessBitmap
3566 bits.Set(accessNewsPostArt)
3567 return bits
3568 }(),
3569 },
3570 },
3571 t: NewTransaction(
3572 TranPostNewsArt,
3573 [2]byte{0, 0},
3574 NewField(FieldNewsPath, []byte{0x00, 0x01, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77}),
3575 NewField(FieldNewsArtID, []byte{0x00, 0x00, 0x00, 0x00}),
3576 ),
3577 },
3578 wantRes: []Transaction{
3579 {
3580 IsReply: 0x01,
3581 ErrorCode: [4]byte{0, 0, 0, 0},
3582 Fields: []Field{},
3583 },
3584 },
3585 },
3586 }
3587 for _, tt := range tests {
3588 t.Run(tt.name, func(t *testing.T) {
3589 tranAssertEqual(t, tt.wantRes, HandlePostNewsArt(tt.args.cc, &tt.args.t))
0ed51327
JH
3590 })
3591 }
3592}