4 "github.com/stretchr/testify/assert"
11 func TestHandleSetChatSubject(t *testing.T) {
23 name: "sends chat subject to private chat members",
26 UserName: []byte{0x00, 0x01},
28 PrivateChats: map[uint32]*PrivateChat{
31 ClientConn: map[uint16]*ClientConn{
34 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
40 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
47 Clients: map[uint16]*ClientConn{
50 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
56 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
66 Type: []byte{0, 0x6a},
67 ID: []byte{0, 0, 0, 1},
68 ErrorCode: []byte{0, 0, 0, 0},
70 NewField(fieldChatID, []byte{0, 0, 0, 1}),
71 NewField(fieldChatSubject, []byte("Test Subject")),
77 clientID: &[]byte{0, 1},
80 Type: []byte{0, 0x77},
81 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
82 ErrorCode: []byte{0, 0, 0, 0},
84 NewField(fieldChatID, []byte{0, 0, 0, 1}),
85 NewField(fieldChatSubject, []byte("Test Subject")),
89 clientID: &[]byte{0, 2},
92 Type: []byte{0, 0x77},
93 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
94 ErrorCode: []byte{0, 0, 0, 0},
96 NewField(fieldChatID, []byte{0, 0, 0, 1}),
97 NewField(fieldChatSubject, []byte("Test Subject")),
104 for _, tt := range tests {
105 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
107 t.Run(tt.name, func(t *testing.T) {
108 got, err := HandleSetChatSubject(tt.args.cc, tt.args.t)
109 if (err != nil) != tt.wantErr {
110 t.Errorf("HandleSetChatSubject() error = %v, wantErr %v", err, tt.wantErr)
113 if !assert.Equal(t, tt.want, got) {
114 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
120 func TestHandleLeaveChat(t *testing.T) {
132 name: "returns expected transactions",
137 PrivateChats: map[uint32]*PrivateChat{
139 ClientConn: map[uint16]*ClientConn{
142 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
148 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
155 Clients: map[uint16]*ClientConn{
158 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
164 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
171 t: NewTransaction(tranDeleteUser, nil, NewField(fieldChatID, []byte{0, 0, 0, 1})),
175 clientID: &[]byte{0, 1},
178 Type: []byte{0, 0x76},
179 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
180 ErrorCode: []byte{0, 0, 0, 0},
182 NewField(fieldChatID, []byte{0, 0, 0, 1}),
183 NewField(fieldUserID, []byte{0, 2}),
190 for _, tt := range tests {
192 t.Run(tt.name, func(t *testing.T) {
193 got, err := HandleLeaveChat(tt.args.cc, tt.args.t)
194 if (err != nil) != tt.wantErr {
195 t.Errorf("HandleLeaveChat() error = %v, wantErr %v", err, tt.wantErr)
198 if !assert.Equal(t, tt.want, got) {
199 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
205 func TestHandleGetUserNameList(t *testing.T) {
217 name: "replies with userlist transaction",
223 Clients: map[uint16]*ClientConn{
227 Flags: &[]byte{0, 3},
228 UserName: []byte{0, 4},
234 Flags: &[]byte{0, 3},
235 UserName: []byte{0, 4},
241 Flags: &[]byte{0, 3},
242 UserName: []byte{0, 4},
249 ID: []byte{0, 0, 0, 1},
255 clientID: &[]byte{1, 1},
259 ID: []byte{0, 0, 0, 1},
260 ErrorCode: []byte{0, 0, 0, 0},
263 fieldUsernameWithInfo,
264 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
267 fieldUsernameWithInfo,
268 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
276 for _, tt := range tests {
277 t.Run(tt.name, func(t *testing.T) {
278 got, err := HandleGetUserNameList(tt.args.cc, tt.args.t)
279 if (err != nil) != tt.wantErr {
280 t.Errorf("HandleGetUserNameList() error = %v, wantErr %v", err, tt.wantErr)
283 assert.Equal(t, tt.want, got)
288 func TestHandleChatSend(t *testing.T) {
300 name: "sends chat msg transaction to all clients",
303 UserName: []byte{0x00, 0x01},
305 Clients: map[uint16]*ClientConn{
308 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
314 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
323 NewField(fieldData, []byte("hai")),
329 clientID: &[]byte{0, 1},
332 Type: []byte{0, 0x6a},
333 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
334 ErrorCode: []byte{0, 0, 0, 0},
336 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
340 clientID: &[]byte{0, 2},
343 Type: []byte{0, 0x6a},
344 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
345 ErrorCode: []byte{0, 0, 0, 0},
347 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
354 name: "sends chat msg as emote if fieldChatOptions is set",
357 UserName: []byte("Testy McTest"),
359 Clients: map[uint16]*ClientConn{
362 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
368 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
377 NewField(fieldData, []byte("performed action")),
378 NewField(fieldChatOptions, []byte{0x00, 0x01}),
384 clientID: &[]byte{0, 1},
387 Type: []byte{0, 0x6a},
388 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
389 ErrorCode: []byte{0, 0, 0, 0},
391 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
395 clientID: &[]byte{0, 2},
398 Type: []byte{0, 0x6a},
399 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
400 ErrorCode: []byte{0, 0, 0, 0},
402 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
409 name: "only sends chat msg to clients with accessReadChat permission",
412 UserName: []byte{0x00, 0x01},
414 Clients: map[uint16]*ClientConn{
417 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
423 Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
432 NewField(fieldData, []byte("hai")),
438 clientID: &[]byte{0, 1},
441 Type: []byte{0, 0x6a},
442 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
443 ErrorCode: []byte{0, 0, 0, 0},
445 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
452 for _, tt := range tests {
453 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
454 t.Run(tt.name, func(t *testing.T) {
455 got, err := HandleChatSend(tt.args.cc, tt.args.t)
457 if (err != nil) != tt.wantErr {
458 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
461 if !assert.Equal(t, tt.want, got) {
462 t.Errorf("HandleChatSend() got = %v, want %v", got, tt.want)
468 func TestHandleGetFileInfo(t *testing.T) {
469 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
478 wantRes []Transaction
482 name: "returns expected fields when a valid file is requested",
485 ID: &[]byte{0x00, 0x01},
488 FileRoot: func() string {
489 path, _ := os.Getwd()
490 return path + "/test/config/Files"
496 tranGetFileInfo, nil,
497 NewField(fieldFileName, []byte("testfile.txt")),
498 NewField(fieldFilePath, []byte{0x00, 0x00}),
501 wantRes: []Transaction{
503 clientID: &[]byte{0, 1},
506 Type: []byte{0, 0xce},
507 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
508 ErrorCode: []byte{0, 0, 0, 0},
510 NewField(fieldFileName, []byte("testfile.txt")),
511 NewField(fieldFileTypeString, []byte("TEXT")),
512 NewField(fieldFileCreatorString, []byte("ttxt")),
513 NewField(fieldFileComment, []byte{}),
514 NewField(fieldFileType, []byte("TEXT")),
515 NewField(fieldFileCreateDate, make([]byte, 8)),
516 NewField(fieldFileModifyDate, make([]byte, 8)),
517 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
524 for _, tt := range tests {
525 t.Run(tt.name, func(t *testing.T) {
526 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
528 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
529 if (err != nil) != tt.wantErr {
530 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
534 // Clear the file timestamp fields to work around problems running the tests in multiple timezones
535 // TODO: revisit how to test this by mocking the stat calls
536 gotRes[0].Fields[5].Data = make([]byte, 8)
537 gotRes[0].Fields[6].Data = make([]byte, 8)
538 if !assert.Equal(t, tt.wantRes, gotRes) {
539 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
545 func TestHandleNewFolder(t *testing.T) {
554 wantRes []Transaction
558 name: "when path is nested",
569 tranNewFolder, &[]byte{0, 1},
570 NewField(fieldFileName, []byte("testFolder")),
571 NewField(fieldFilePath, []byte{
580 mfs := MockFileStore{}
581 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
582 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
585 wantRes: []Transaction{
587 clientID: &[]byte{0, 1},
590 Type: []byte{0, 0xcd},
591 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
592 ErrorCode: []byte{0, 0, 0, 0},
598 name: "when path is not nested",
609 tranNewFolder, &[]byte{0, 1},
610 NewField(fieldFileName, []byte("testFolder")),
614 mfs := MockFileStore{}
615 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
616 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
619 wantRes: []Transaction{
621 clientID: &[]byte{0, 1},
624 Type: []byte{0, 0xcd},
625 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
626 ErrorCode: []byte{0, 0, 0, 0},
632 name: "when UnmarshalBinary returns an err",
643 tranNewFolder, &[]byte{0, 1},
644 NewField(fieldFileName, []byte("testFolder")),
645 NewField(fieldFilePath, []byte{
651 mfs := MockFileStore{}
652 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
653 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
656 wantRes: []Transaction{},
660 name: "fieldFileName does not allow directory traversal",
671 tranNewFolder, &[]byte{0, 1},
672 NewField(fieldFileName, []byte("../../testFolder")),
676 mfs := MockFileStore{}
677 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
678 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
681 wantRes: []Transaction{
683 clientID: &[]byte{0, 1},
686 Type: []byte{0, 0xcd},
687 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
688 ErrorCode: []byte{0, 0, 0, 0},
693 name: "fieldFilePath does not allow directory traversal",
704 tranNewFolder, &[]byte{0, 1},
705 NewField(fieldFileName, []byte("testFolder")),
706 NewField(fieldFilePath, []byte{
718 mfs := MockFileStore{}
719 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
720 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
723 wantRes: []Transaction{
725 clientID: &[]byte{0, 1},
728 Type: []byte{0, 0xcd},
729 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
730 ErrorCode: []byte{0, 0, 0, 0},
735 for _, tt := range tests {
736 t.Run(tt.name, func(t *testing.T) {
739 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
740 if (err != nil) != tt.wantErr {
741 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
744 if !tranAssertEqual(t, tt.wantRes, gotRes) {
745 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
751 func TestHandleUploadFile(t *testing.T) {
759 wantRes []Transaction
763 name: "when request is valid",
767 FileTransfers: map[uint32]*FileTransfer{},
770 Access: func() *[]byte {
771 var bits accessBitmap
772 bits.Set(accessUploadFile)
779 tranUploadFile, &[]byte{0, 1},
780 NewField(fieldFileName, []byte("testFile")),
781 NewField(fieldFilePath, []byte{
789 wantRes: []Transaction{
793 Type: []byte{0, 0xcb},
794 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
795 ErrorCode: []byte{0, 0, 0, 0},
797 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
804 name: "when user does not have required access",
808 Access: func() *[]byte {
809 var bits accessBitmap
815 FileTransfers: map[uint32]*FileTransfer{},
819 tranUploadFile, &[]byte{0, 1},
820 NewField(fieldFileName, []byte("testFile")),
821 NewField(fieldFilePath, []byte{
829 wantRes: []Transaction{
833 Type: []byte{0, 0x00},
834 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
835 ErrorCode: []byte{0, 0, 0, 1},
837 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
844 for _, tt := range tests {
845 t.Run(tt.name, func(t *testing.T) {
847 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
848 if (err != nil) != tt.wantErr {
849 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
852 if !tranAssertEqual(t, tt.wantRes, gotRes) {
853 t.Errorf("HandleUploadFile() gotRes = %v, want %v", gotRes, tt.wantRes)