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