4 "github.com/stretchr/testify/assert"
12 func TestHandleSetChatSubject(t *testing.T) {
24 name: "sends chat subject to private chat members",
27 UserName: []byte{0x00, 0x01},
29 PrivateChats: map[uint32]*PrivateChat{
32 ClientConn: map[uint16]*ClientConn{
35 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
41 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
48 Clients: map[uint16]*ClientConn{
51 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
57 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
67 Type: []byte{0, 0x6a},
68 ID: []byte{0, 0, 0, 1},
69 ErrorCode: []byte{0, 0, 0, 0},
71 NewField(fieldChatID, []byte{0, 0, 0, 1}),
72 NewField(fieldChatSubject, []byte("Test Subject")),
78 clientID: &[]byte{0, 1},
81 Type: []byte{0, 0x77},
82 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
83 ErrorCode: []byte{0, 0, 0, 0},
85 NewField(fieldChatID, []byte{0, 0, 0, 1}),
86 NewField(fieldChatSubject, []byte("Test Subject")),
90 clientID: &[]byte{0, 2},
93 Type: []byte{0, 0x77},
94 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
95 ErrorCode: []byte{0, 0, 0, 0},
97 NewField(fieldChatID, []byte{0, 0, 0, 1}),
98 NewField(fieldChatSubject, []byte("Test Subject")),
105 for _, tt := range tests {
106 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
108 t.Run(tt.name, func(t *testing.T) {
109 got, err := HandleSetChatSubject(tt.args.cc, tt.args.t)
110 if (err != nil) != tt.wantErr {
111 t.Errorf("HandleSetChatSubject() error = %v, wantErr %v", err, tt.wantErr)
114 if !assert.Equal(t, tt.want, got) {
115 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
121 func TestHandleLeaveChat(t *testing.T) {
133 name: "returns expected transactions",
138 PrivateChats: map[uint32]*PrivateChat{
140 ClientConn: map[uint16]*ClientConn{
143 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
149 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
156 Clients: map[uint16]*ClientConn{
159 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
165 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
172 t: NewTransaction(tranDeleteUser, nil, NewField(fieldChatID, []byte{0, 0, 0, 1})),
176 clientID: &[]byte{0, 1},
179 Type: []byte{0, 0x76},
180 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
181 ErrorCode: []byte{0, 0, 0, 0},
183 NewField(fieldChatID, []byte{0, 0, 0, 1}),
184 NewField(fieldUserID, []byte{0, 2}),
191 for _, tt := range tests {
193 t.Run(tt.name, func(t *testing.T) {
194 got, err := HandleLeaveChat(tt.args.cc, tt.args.t)
195 if (err != nil) != tt.wantErr {
196 t.Errorf("HandleLeaveChat() error = %v, wantErr %v", err, tt.wantErr)
199 if !assert.Equal(t, tt.want, got) {
200 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
206 func TestHandleGetUserNameList(t *testing.T) {
218 name: "replies with userlist transaction",
224 Clients: map[uint16]*ClientConn{
228 Flags: &[]byte{0, 3},
229 UserName: []byte{0, 4},
234 Flags: &[]byte{0, 3},
235 UserName: []byte{0, 4},
241 ID: []byte{0, 0, 0, 1},
247 clientID: &[]byte{1, 1},
251 ID: []byte{0, 0, 0, 1},
252 ErrorCode: []byte{0, 0, 0, 0},
255 fieldUsernameWithInfo,
256 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
259 fieldUsernameWithInfo,
260 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
268 for _, tt := range tests {
269 t.Run(tt.name, func(t *testing.T) {
270 got, err := HandleGetUserNameList(tt.args.cc, tt.args.t)
271 if (err != nil) != tt.wantErr {
272 t.Errorf("HandleGetUserNameList() error = %v, wantErr %v", err, tt.wantErr)
275 if !reflect.DeepEqual(got, tt.want) {
276 t.Errorf("HandleGetUserNameList() got = %v, want %v", got, tt.want)
282 func TestHandleChatSend(t *testing.T) {
294 name: "sends chat msg transaction to all clients",
297 UserName: []byte{0x00, 0x01},
299 Clients: map[uint16]*ClientConn{
302 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
308 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
317 NewField(fieldData, []byte("hai")),
323 clientID: &[]byte{0, 1},
326 Type: []byte{0, 0x6a},
327 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
328 ErrorCode: []byte{0, 0, 0, 0},
330 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
334 clientID: &[]byte{0, 2},
337 Type: []byte{0, 0x6a},
338 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
339 ErrorCode: []byte{0, 0, 0, 0},
341 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
348 name: "sends chat msg as emote if fieldChatOptions is set",
351 UserName: []byte("Testy McTest"),
353 Clients: map[uint16]*ClientConn{
356 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
362 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
371 NewField(fieldData, []byte("performed action")),
372 NewField(fieldChatOptions, []byte{0x00, 0x01}),
378 clientID: &[]byte{0, 1},
381 Type: []byte{0, 0x6a},
382 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
383 ErrorCode: []byte{0, 0, 0, 0},
385 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
389 clientID: &[]byte{0, 2},
392 Type: []byte{0, 0x6a},
393 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
394 ErrorCode: []byte{0, 0, 0, 0},
396 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
403 name: "only sends chat msg to clients with accessReadChat permission",
406 UserName: []byte{0x00, 0x01},
408 Clients: map[uint16]*ClientConn{
411 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
417 Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
426 NewField(fieldData, []byte("hai")),
432 clientID: &[]byte{0, 1},
435 Type: []byte{0, 0x6a},
436 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
437 ErrorCode: []byte{0, 0, 0, 0},
439 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
446 for _, tt := range tests {
447 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
448 t.Run(tt.name, func(t *testing.T) {
449 got, err := HandleChatSend(tt.args.cc, tt.args.t)
451 if (err != nil) != tt.wantErr {
452 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
455 if !assert.Equal(t, tt.want, got) {
456 t.Errorf("HandleChatSend() got = %v, want %v", got, tt.want)
462 func TestHandleGetFileInfo(t *testing.T) {
463 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
472 wantRes []Transaction
476 name: "returns expected fields when a valid file is requested",
479 ID: &[]byte{0x00, 0x01},
482 FileRoot: func() string {
483 path, _ := os.Getwd()
484 return path + "/test/config/Files"
490 tranGetFileInfo, nil,
491 NewField(fieldFileName, []byte("testfile.txt")),
492 NewField(fieldFilePath, []byte{0x00, 0x00}),
495 wantRes: []Transaction{
497 clientID: &[]byte{0, 1},
500 Type: []byte{0, 0xce},
501 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
502 ErrorCode: []byte{0, 0, 0, 0},
504 NewField(fieldFileName, []byte("testfile.txt")),
505 NewField(fieldFileTypeString, []byte("TEXT")),
506 NewField(fieldFileCreatorString, []byte("ttxt")),
507 NewField(fieldFileComment, []byte{}),
508 NewField(fieldFileType, []byte("TEXT")),
509 NewField(fieldFileCreateDate, make([]byte, 8)),
510 NewField(fieldFileModifyDate, make([]byte, 8)),
511 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
518 for _, tt := range tests {
519 t.Run(tt.name, func(t *testing.T) {
520 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
522 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
523 if (err != nil) != tt.wantErr {
524 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
528 // Clear the file timestamp fields to work around problems running the tests in multiple timezones
529 // TODO: revisit how to test this by mocking the stat calls
530 gotRes[0].Fields[5].Data = make([]byte, 8)
531 gotRes[0].Fields[6].Data = make([]byte, 8)
532 if !assert.Equal(t, tt.wantRes, gotRes) {
533 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
539 func TestHandleNewFolder(t *testing.T) {
548 wantRes []Transaction
552 name: "when path is nested",
563 tranNewFolder, &[]byte{0, 1},
564 NewField(fieldFileName, []byte("testFolder")),
565 NewField(fieldFilePath, []byte{
574 mfs := MockFileStore{}
575 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
576 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
579 wantRes: []Transaction{
581 clientID: &[]byte{0, 1},
584 Type: []byte{0, 0xcd},
585 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
586 ErrorCode: []byte{0, 0, 0, 0},
592 name: "when path is not nested",
603 tranNewFolder, &[]byte{0, 1},
604 NewField(fieldFileName, []byte("testFolder")),
608 mfs := MockFileStore{}
609 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
610 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
613 wantRes: []Transaction{
615 clientID: &[]byte{0, 1},
618 Type: []byte{0, 0xcd},
619 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
620 ErrorCode: []byte{0, 0, 0, 0},
626 name: "when UnmarshalBinary returns an err",
637 tranNewFolder, &[]byte{0, 1},
638 NewField(fieldFileName, []byte("testFolder")),
639 NewField(fieldFilePath, []byte{
645 mfs := MockFileStore{}
646 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
647 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
650 wantRes: []Transaction{},
654 name: "fieldFileName does not allow directory traversal",
665 tranNewFolder, &[]byte{0, 1},
666 NewField(fieldFileName, []byte("../../testFolder")),
670 mfs := MockFileStore{}
671 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
672 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
675 wantRes: []Transaction{
677 clientID: &[]byte{0, 1},
680 Type: []byte{0, 0xcd},
681 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
682 ErrorCode: []byte{0, 0, 0, 0},
687 name: "fieldFilePath does not allow directory traversal",
698 tranNewFolder, &[]byte{0, 1},
699 NewField(fieldFileName, []byte("testFolder")),
700 NewField(fieldFilePath, []byte{
712 mfs := MockFileStore{}
713 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
714 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
717 wantRes: []Transaction{
719 clientID: &[]byte{0, 1},
722 Type: []byte{0, 0xcd},
723 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
724 ErrorCode: []byte{0, 0, 0, 0},
729 for _, tt := range tests {
730 t.Run(tt.name, func(t *testing.T) {
733 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
734 if (err != nil) != tt.wantErr {
735 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
738 if !tranAssertEqual(t, tt.wantRes, gotRes) {
739 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
745 func TestHandleUploadFile(t *testing.T) {
753 wantRes []Transaction
757 name: "when request is valid",
761 FileTransfers: map[uint32]*FileTransfer{},
764 Access: func() *[]byte {
765 var bits accessBitmap
766 bits.Set(accessUploadFile)
773 tranUploadFile, &[]byte{0, 1},
774 NewField(fieldFileName, []byte("testFile")),
775 NewField(fieldFilePath, []byte{
783 wantRes: []Transaction{
787 Type: []byte{0, 0xcb},
788 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
789 ErrorCode: []byte{0, 0, 0, 0},
791 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
798 name: "when user does not have required access",
802 Access: func() *[]byte {
803 var bits accessBitmap
809 FileTransfers: map[uint32]*FileTransfer{},
813 tranUploadFile, &[]byte{0, 1},
814 NewField(fieldFileName, []byte("testFile")),
815 NewField(fieldFilePath, []byte{
823 wantRes: []Transaction{
827 Type: []byte{0, 0x00},
828 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
829 ErrorCode: []byte{0, 0, 0, 1},
831 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
838 for _, tt := range tests {
839 t.Run(tt.name, func(t *testing.T) {
841 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
842 if (err != nil) != tt.wantErr {
843 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
846 if !tranAssertEqual(t, tt.wantRes, gotRes) {
847 t.Errorf("HandleUploadFile() gotRes = %v, want %v", gotRes, tt.wantRes)