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 { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
477 tranGetFileInfo, nil,
478 NewField(fieldFileName, []byte("testfile.txt")),
479 NewField(fieldFilePath, []byte{0x00, 0x00}),
482 wantRes: []Transaction{
484 clientID: &[]byte{0, 1},
487 Type: []byte{0, 0xce},
488 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
489 ErrorCode: []byte{0, 0, 0, 0},
491 NewField(fieldFileName, []byte("testfile.txt")),
492 NewField(fieldFileTypeString, []byte("TEXT")),
493 NewField(fieldFileCreatorString, []byte("ttxt")),
494 NewField(fieldFileComment, []byte("TODO")),
495 NewField(fieldFileType, []byte("TEXT")),
496 NewField(fieldFileCreateDate, []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}),
497 NewField(fieldFileModifyDate, []byte{0x07, 0x70, 0x00, 0x00, 0xba, 0x74, 0x24, 0x73}),
498 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
505 for _, tt := range tests {
506 t.Run(tt.name, func(t *testing.T) {
507 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
509 gotRes, err := HandleGetFileInfo(tt.args.cc, tt.args.t)
510 if (err != nil) != tt.wantErr {
511 t.Errorf("HandleGetFileInfo() error = %v, wantErr %v", err, tt.wantErr)
514 if !assert.Equal(t, tt.wantRes, gotRes) {
515 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
521 func TestHandleNewFolder(t *testing.T) {
530 wantRes []Transaction
534 name: "when path is nested",
545 tranNewFolder, &[]byte{0, 1},
546 NewField(fieldFileName, []byte("testFolder")),
547 NewField(fieldFilePath, []byte{
556 mfs := MockFileStore{}
557 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
558 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
561 wantRes: []Transaction{
563 clientID: &[]byte{0, 1},
566 Type: []byte{0, 0xcd},
567 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
568 ErrorCode: []byte{0, 0, 0, 0},
574 name: "when path is not nested",
585 tranNewFolder, &[]byte{0, 1},
586 NewField(fieldFileName, []byte("testFolder")),
590 mfs := MockFileStore{}
591 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
592 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
595 wantRes: []Transaction{
597 clientID: &[]byte{0, 1},
600 Type: []byte{0, 0xcd},
601 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
602 ErrorCode: []byte{0, 0, 0, 0},
608 name: "when UnmarshalBinary returns an err",
619 tranNewFolder, &[]byte{0, 1},
620 NewField(fieldFileName, []byte("testFolder")),
621 NewField(fieldFilePath, []byte{
627 mfs := MockFileStore{}
628 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
629 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
632 wantRes: []Transaction{},
636 name: "fieldFileName does not allow directory traversal",
647 tranNewFolder, &[]byte{0, 1},
648 NewField(fieldFileName, []byte("../../testFolder")),
652 mfs := MockFileStore{}
653 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
654 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
657 wantRes: []Transaction{
659 clientID: &[]byte{0, 1},
662 Type: []byte{0, 0xcd},
663 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
664 ErrorCode: []byte{0, 0, 0, 0},
669 name: "fieldFilePath does not allow directory traversal",
680 tranNewFolder, &[]byte{0, 1},
681 NewField(fieldFileName, []byte("testFolder")),
682 NewField(fieldFilePath, []byte{
694 mfs := MockFileStore{}
695 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
696 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
699 wantRes: []Transaction{
701 clientID: &[]byte{0, 1},
704 Type: []byte{0, 0xcd},
705 ID: []byte{0x9a, 0xcb, 0x04, 0x42}, // Random ID from rand.Seed(1)
706 ErrorCode: []byte{0, 0, 0, 0},
711 for _, tt := range tests {
712 t.Run(tt.name, func(t *testing.T) {
715 gotRes, err := HandleNewFolder(tt.args.cc, tt.args.t)
716 if (err != nil) != tt.wantErr {
717 t.Errorf("HandleNewFolder() error = %v, wantErr %v", err, tt.wantErr)
720 if !tranAssertEqual(t, tt.wantRes, gotRes) {
721 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
727 func TestHandleUploadFile(t *testing.T) {
735 wantRes []Transaction
739 name: "when request is valid",
743 FileTransfers: map[uint32]*FileTransfer{},
746 Access: func() *[]byte {
747 var bits accessBitmap
748 bits.Set(accessUploadFile)
755 tranUploadFile, &[]byte{0, 1},
756 NewField(fieldFileName, []byte("testFile")),
757 NewField(fieldFilePath, []byte{
765 wantRes: []Transaction{
769 Type: []byte{0, 0xcb},
770 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
771 ErrorCode: []byte{0, 0, 0, 0},
773 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
780 name: "when user does not have required access",
784 Access: func() *[]byte {
785 var bits accessBitmap
791 FileTransfers: map[uint32]*FileTransfer{},
795 tranUploadFile, &[]byte{0, 1},
796 NewField(fieldFileName, []byte("testFile")),
797 NewField(fieldFilePath, []byte{
805 wantRes: []Transaction{
809 Type: []byte{0, 0x00},
810 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
811 ErrorCode: []byte{0, 0, 0, 1},
813 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
820 for _, tt := range tests {
821 t.Run(tt.name, func(t *testing.T) {
823 gotRes, err := HandleUploadFile(tt.args.cc, tt.args.t)
824 if (err != nil) != tt.wantErr {
825 t.Errorf("HandleUploadFile() error = %v, wantErr %v", err, tt.wantErr)
828 if !tranAssertEqual(t, tt.wantRes, gotRes) {
829 t.Errorf("HandleUploadFile() gotRes = %v, want %v", gotRes, tt.wantRes)