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},
235 ID: []byte{0, 0, 0, 1},
241 clientID: &[]byte{1, 1},
245 ID: []byte{0, 0, 0, 1},
246 ErrorCode: []byte{0, 0, 0, 0},
249 fieldUsernameWithInfo,
250 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
258 for _, tt := range tests {
259 t.Run(tt.name, func(t *testing.T) {
260 got, err := HandleGetUserNameList(tt.args.cc, tt.args.t)
261 if (err != nil) != tt.wantErr {
262 t.Errorf("HandleGetUserNameList() error = %v, wantErr %v", err, tt.wantErr)
265 if !reflect.DeepEqual(got, tt.want) {
266 t.Errorf("HandleGetUserNameList() got = %v, want %v", got, tt.want)
272 func TestHandleChatSend(t *testing.T) {
284 name: "sends chat msg transaction to all clients",
287 UserName: []byte{0x00, 0x01},
289 Clients: map[uint16]*ClientConn{
292 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
298 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
307 NewField(fieldData, []byte("hai")),
313 clientID: &[]byte{0, 1},
316 Type: []byte{0, 0x6a},
317 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
318 ErrorCode: []byte{0, 0, 0, 0},
320 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
324 clientID: &[]byte{0, 2},
327 Type: []byte{0, 0x6a},
328 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
329 ErrorCode: []byte{0, 0, 0, 0},
331 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
338 name: "sends chat msg as emote if fieldChatOptions is set",
341 UserName: []byte("Testy McTest"),
343 Clients: map[uint16]*ClientConn{
346 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
352 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
361 NewField(fieldData, []byte("performed action")),
362 NewField(fieldChatOptions, []byte{0x00, 0x01}),
368 clientID: &[]byte{0, 1},
371 Type: []byte{0, 0x6a},
372 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
373 ErrorCode: []byte{0, 0, 0, 0},
375 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
379 clientID: &[]byte{0, 2},
382 Type: []byte{0, 0x6a},
383 ID: []byte{0xf0, 0xc5, 0x34, 0x1e}, // Random ID from rand.Seed(1)
384 ErrorCode: []byte{0, 0, 0, 0},
386 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
393 name: "only sends chat msg to clients with accessReadChat permission",
396 UserName: []byte{0x00, 0x01},
398 Clients: map[uint16]*ClientConn{
401 Access: &[]byte{255, 255, 255, 255, 255, 255, 255, 255},
407 Access: &[]byte{0, 0, 0, 0, 0, 0, 0, 0},
416 NewField(fieldData, []byte("hai")),
422 clientID: &[]byte{0, 1},
425 Type: []byte{0, 0x6a},
426 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
427 ErrorCode: []byte{0, 0, 0, 0},
429 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
436 for _, tt := range tests {
437 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
438 t.Run(tt.name, func(t *testing.T) {
439 got, err := HandleChatSend(tt.args.cc, tt.args.t)
441 if (err != nil) != tt.wantErr {
442 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
445 if !assert.Equal(t, tt.want, got) {
446 t.Errorf("HandleChatSend() got = %v, want %v", got, tt.want)
452 func TestHandleGetFileInfo(t *testing.T) {
453 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
462 wantRes []Transaction
466 name: "returns expected fields when a valid file is requested",
469 ID: &[]byte{0x00, 0x01},
472 FileRoot: func() string {
473 path, _ := os.Getwd()
474 return path + "/test/config/Files"
480 tranGetFileInfo, nil,
481 NewField(fieldFileName, []byte("testfile.txt")),
482 NewField(fieldFilePath, []byte{0x00, 0x00}),
485 wantRes: []Transaction{
487 clientID: &[]byte{0, 1},
490 Type: []byte{0, 0xce},
491 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
492 ErrorCode: []byte{0, 0, 0, 0},
494 NewField(fieldFileName, []byte("testfile.txt")),
495 NewField(fieldFileTypeString, []byte("TEXT")),
496 NewField(fieldFileCreatorString, []byte("ttxt")),
497 NewField(fieldFileComment, []byte{}),
498 NewField(fieldFileType, []byte("TEXT")),
499 NewField(fieldFileCreateDate, make([]byte, 8)),
500 NewField(fieldFileModifyDate, make([]byte, 8)),
501 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
508 for _, tt := range tests {
509 t.Run(tt.name, func(t *testing.T) {
510 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
512 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
513 if (err != nil) != tt.wantErr {
514 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
518 // Clear the file timestamp fields to work around problems running the tests in multiple timezones
519 // TODO: revisit how to test this by mocking the stat calls
520 gotRes[0].Fields[5].Data = make([]byte, 8)
521 gotRes[0].Fields[6].Data = make([]byte, 8)
522 if !assert.Equal(t, tt.wantRes, gotRes) {
523 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
529 func TestHandleNewFolder(t *testing.T) {
538 wantRes []Transaction
542 name: "when path is nested",
553 tranNewFolder, &[]byte{0, 1},
554 NewField(fieldFileName, []byte("testFolder")),
555 NewField(fieldFilePath, []byte{
564 mfs := MockFileStore{}
565 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
566 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
569 wantRes: []Transaction{
571 clientID: &[]byte{0, 1},
574 Type: []byte{0, 0xcd},
575 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
576 ErrorCode: []byte{0, 0, 0, 0},
582 name: "when path is not nested",
593 tranNewFolder, &[]byte{0, 1},
594 NewField(fieldFileName, []byte("testFolder")),
598 mfs := MockFileStore{}
599 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
600 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
603 wantRes: []Transaction{
605 clientID: &[]byte{0, 1},
608 Type: []byte{0, 0xcd},
609 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
610 ErrorCode: []byte{0, 0, 0, 0},
616 name: "when UnmarshalBinary returns an err",
627 tranNewFolder, &[]byte{0, 1},
628 NewField(fieldFileName, []byte("testFolder")),
629 NewField(fieldFilePath, []byte{
635 mfs := MockFileStore{}
636 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
637 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
640 wantRes: []Transaction{},
644 name: "fieldFileName does not allow directory traversal",
655 tranNewFolder, &[]byte{0, 1},
656 NewField(fieldFileName, []byte("../../testFolder")),
660 mfs := MockFileStore{}
661 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
662 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
665 wantRes: []Transaction{
667 clientID: &[]byte{0, 1},
670 Type: []byte{0, 0xcd},
671 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
672 ErrorCode: []byte{0, 0, 0, 0},
677 name: "fieldFilePath does not allow directory traversal",
688 tranNewFolder, &[]byte{0, 1},
689 NewField(fieldFileName, []byte("testFolder")),
690 NewField(fieldFilePath, []byte{
702 mfs := MockFileStore{}
703 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
704 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
707 wantRes: []Transaction{
709 clientID: &[]byte{0, 1},
712 Type: []byte{0, 0xcd},
713 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
714 ErrorCode: []byte{0, 0, 0, 0},
719 for _, tt := range tests {
720 t.Run(tt.name, func(t *testing.T) {
723 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
724 if (err != nil) != tt.wantErr {
725 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
728 if !tranAssertEqual(t, tt.wantRes, gotRes) {
729 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
735 func TestHandleUploadFile(t *testing.T) {
743 wantRes []Transaction
747 name: "when request is valid",
751 FileTransfers: map[uint32]*FileTransfer{},
754 Access: func() *[]byte {
755 var bits accessBitmap
756 bits.Set(accessUploadFile)
763 tranUploadFile, &[]byte{0, 1},
764 NewField(fieldFileName, []byte("testFile")),
765 NewField(fieldFilePath, []byte{
773 wantRes: []Transaction{
777 Type: []byte{0, 0xcb},
778 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
779 ErrorCode: []byte{0, 0, 0, 0},
781 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
788 name: "when user does not have required access",
792 Access: func() *[]byte {
793 var bits accessBitmap
799 FileTransfers: map[uint32]*FileTransfer{},
803 tranUploadFile, &[]byte{0, 1},
804 NewField(fieldFileName, []byte("testFile")),
805 NewField(fieldFilePath, []byte{
813 wantRes: []Transaction{
817 Type: []byte{0, 0x00},
818 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
819 ErrorCode: []byte{0, 0, 0, 1},
821 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
828 for _, tt := range tests {
829 t.Run(tt.name, func(t *testing.T) {
831 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
832 if (err != nil) != tt.wantErr {
833 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
836 if !tranAssertEqual(t, tt.wantRes, gotRes) {
837 t.Errorf("HandleUploadFile() gotRes = %v, want %v", gotRes, tt.wantRes)