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