6 "github.com/stretchr/testify/assert"
7 "github.com/stretchr/testify/mock"
17 func TestHandleSetChatSubject(t *testing.T) {
29 name: "sends chat subject to private chat members",
32 UserName: []byte{0x00, 0x01},
34 PrivateChats: map[uint32]*PrivateChat{
37 ClientConn: map[uint16]*ClientConn{
40 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
46 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
53 Clients: map[uint16]*ClientConn{
56 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
62 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
72 Type: []byte{0, 0x6a},
73 ID: []byte{0, 0, 0, 1},
74 ErrorCode: []byte{0, 0, 0, 0},
76 NewField(fieldChatID, []byte{0, 0, 0, 1}),
77 NewField(fieldChatSubject, []byte("Test Subject")),
83 clientID: &[]byte{0, 1},
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},
90 NewField(fieldChatID, []byte{0, 0, 0, 1}),
91 NewField(fieldChatSubject, []byte("Test Subject")),
95 clientID: &[]byte{0, 2},
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},
102 NewField(fieldChatID, []byte{0, 0, 0, 1}),
103 NewField(fieldChatSubject, []byte("Test Subject")),
110 for _, tt := range tests {
111 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
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)
119 if !assert.Equal(t, tt.want, got) {
120 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
126 func TestHandleLeaveChat(t *testing.T) {
138 name: "returns expected transactions",
143 PrivateChats: map[uint32]*PrivateChat{
145 ClientConn: map[uint16]*ClientConn{
148 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
154 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
161 Clients: map[uint16]*ClientConn{
164 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
170 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
177 t: NewTransaction(tranDeleteUser, nil, NewField(fieldChatID, []byte{0, 0, 0, 1})),
181 clientID: &[]byte{0, 1},
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},
188 NewField(fieldChatID, []byte{0, 0, 0, 1}),
189 NewField(fieldUserID, []byte{0, 2}),
196 for _, tt := range tests {
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)
204 if !assert.Equal(t, tt.want, got) {
205 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
211 func TestHandleGetUserNameList(t *testing.T) {
223 name: "replies with userlist transaction",
229 Clients: map[uint16]*ClientConn{
234 UserName: []byte{0, 4},
241 UserName: []byte{0, 4},
248 UserName: []byte{0, 4},
255 ID: []byte{0, 0, 0, 1},
261 clientID: &[]byte{1, 1},
265 ID: []byte{0, 0, 0, 1},
266 ErrorCode: []byte{0, 0, 0, 0},
269 fieldUsernameWithInfo,
270 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
273 fieldUsernameWithInfo,
274 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
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)
289 assert.Equal(t, tt.want, got)
294 func TestHandleChatSend(t *testing.T) {
306 name: "sends chat msg transaction to all clients",
310 Access: func() accessBitmap {
311 var bits accessBitmap
312 bits.Set(accessSendChat)
316 UserName: []byte{0x00, 0x01},
318 Clients: map[uint16]*ClientConn{
321 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
327 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
336 NewField(fieldData, []byte("hai")),
342 clientID: &[]byte{0, 1},
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},
349 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
353 clientID: &[]byte{0, 2},
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},
360 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
367 name: "when user does not have required permission",
371 Access: func() accessBitmap {
372 var bits accessBitmap
377 Accounts: map[string]*Account{},
381 tranChatSend, &[]byte{0, 1},
382 NewField(fieldData, []byte("hai")),
389 Type: []byte{0, 0x00},
390 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
391 ErrorCode: []byte{0, 0, 0, 1},
393 NewField(fieldError, []byte("You are not allowed to participate in chat.")),
400 name: "sends chat msg as emote if fieldChatOptions is set",
404 Access: func() accessBitmap {
405 var bits accessBitmap
406 bits.Set(accessSendChat)
410 UserName: []byte("Testy McTest"),
412 Clients: map[uint16]*ClientConn{
415 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
421 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
430 NewField(fieldData, []byte("performed action")),
431 NewField(fieldChatOptions, []byte{0x00, 0x01}),
437 clientID: &[]byte{0, 1},
440 Type: []byte{0, 0x6a},
441 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
442 ErrorCode: []byte{0, 0, 0, 0},
444 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
448 clientID: &[]byte{0, 2},
451 Type: []byte{0, 0x6a},
452 ID: []byte{0xf0, 0xc5, 0x34, 0x1e},
453 ErrorCode: []byte{0, 0, 0, 0},
455 NewField(fieldData, []byte("\r*** Testy McTest performed action")),
462 name: "only sends chat msg to clients with accessReadChat permission",
466 Access: func() accessBitmap {
467 var bits accessBitmap
468 bits.Set(accessSendChat)
472 UserName: []byte{0x00, 0x01},
474 Clients: map[uint16]*ClientConn{
477 Access: func() accessBitmap {
478 var bits accessBitmap
479 bits.Set(accessReadChat)
486 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
495 NewField(fieldData, []byte("hai")),
501 clientID: &[]byte{0, 1},
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},
508 NewField(fieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
515 name: "only sends private chat msg to members of private chat",
519 Access: func() accessBitmap {
520 var bits accessBitmap
521 bits.Set(accessSendChat)
525 UserName: []byte{0x00, 0x01},
527 PrivateChats: map[uint32]*PrivateChat{
529 ClientConn: map[uint16]*ClientConn{
539 Clients: map[uint16]*ClientConn{
542 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
548 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
554 Access: accessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
563 NewField(fieldData, []byte("hai")),
564 NewField(fieldChatID, []byte{0, 0, 0, 1}),
570 clientID: &[]byte{0, 1},
573 Type: []byte{0, 0x6a},
574 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
575 ErrorCode: []byte{0, 0, 0, 0},
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}),
582 clientID: &[]byte{0, 2},
585 Type: []byte{0, 0x6a},
586 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
587 ErrorCode: []byte{0, 0, 0, 0},
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}),
597 for _, tt := range tests {
598 t.Run(tt.name, func(t *testing.T) {
599 got, err := HandleChatSend(tt.args.cc, tt.args.t)
601 if (err != nil) != tt.wantErr {
602 t.Errorf("HandleChatSend() error = %v, wantErr %v", err, tt.wantErr)
605 tranAssertEqual(t, tt.want, got)
610 func TestHandleGetFileInfo(t *testing.T) {
611 rand.Seed(1) // reset seed between tests to make transaction IDs predictable
620 wantRes []Transaction
624 name: "returns expected fields when a valid file is requested",
627 ID: &[]byte{0x00, 0x01},
631 FileRoot: func() string {
632 path, _ := os.Getwd()
633 return filepath.Join(path, "/test/config/Files")
639 tranGetFileInfo, nil,
640 NewField(fieldFileName, []byte("testfile.txt")),
641 NewField(fieldFilePath, []byte{0x00, 0x00}),
644 wantRes: []Transaction{
646 clientID: &[]byte{0, 1},
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},
653 NewField(fieldFileName, []byte("testfile.txt")),
654 NewField(fieldFileTypeString, []byte("Text File")),
655 NewField(fieldFileCreatorString, []byte("ttxt")),
656 NewField(fieldFileComment, []byte{}),
657 NewField(fieldFileType, []byte("TEXT")),
658 NewField(fieldFileCreateDate, make([]byte, 8)),
659 NewField(fieldFileModifyDate, make([]byte, 8)),
660 NewField(fieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
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
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)
677 // Clear the fileWrapper timestamp fields to work around problems running the tests in multiple timezones
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)
681 if !assert.Equal(t, tt.wantRes, gotRes) {
682 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
688 func TestHandleNewFolder(t *testing.T) {
696 wantRes []Transaction
700 name: "without required permission",
704 Access: func() accessBitmap {
705 var bits accessBitmap
715 wantRes: []Transaction{
719 Type: []byte{0, 0x00},
720 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
721 ErrorCode: []byte{0, 0, 0, 1},
723 NewField(fieldError, []byte("You are not allowed to create folders.")),
730 name: "when path is nested",
734 Access: func() accessBitmap {
735 var bits accessBitmap
736 bits.Set(accessCreateFolder)
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)
754 tranNewFolder, &[]byte{0, 1},
755 NewField(fieldFileName, []byte("testFolder")),
756 NewField(fieldFilePath, []byte{
764 wantRes: []Transaction{
766 clientID: &[]byte{0, 1},
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},
777 name: "when path is not nested",
781 Access: func() accessBitmap {
782 var bits accessBitmap
783 bits.Set(accessCreateFolder)
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)
801 tranNewFolder, &[]byte{0, 1},
802 NewField(fieldFileName, []byte("testFolder")),
805 wantRes: []Transaction{
807 clientID: &[]byte{0, 1},
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},
818 name: "when Write returns an err",
822 Access: func() accessBitmap {
823 var bits accessBitmap
824 bits.Set(accessCreateFolder)
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)
842 tranNewFolder, &[]byte{0, 1},
843 NewField(fieldFileName, []byte("testFolder")),
844 NewField(fieldFilePath, []byte{
849 wantRes: []Transaction{},
853 name: "fieldFileName does not allow directory traversal",
857 Access: func() accessBitmap {
858 var bits accessBitmap
859 bits.Set(accessCreateFolder)
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)
877 tranNewFolder, &[]byte{0, 1},
878 NewField(fieldFileName, []byte("../../testFolder")),
881 wantRes: []Transaction{
883 clientID: &[]byte{0, 1},
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},
893 name: "fieldFilePath does not allow directory traversal",
897 Access: func() accessBitmap {
898 var bits accessBitmap
899 bits.Set(accessCreateFolder)
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)
917 tranNewFolder, &[]byte{0, 1},
918 NewField(fieldFileName, []byte("testFolder")),
919 NewField(fieldFilePath, []byte{
930 wantRes: []Transaction{
932 clientID: &[]byte{0, 1},
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},
942 for _, tt := range tests {
943 t.Run(tt.name, func(t *testing.T) {
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)
951 if !tranAssertEqual(t, tt.wantRes, gotRes) {
952 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
958 func TestHandleUploadFile(t *testing.T) {
966 wantRes []Transaction
970 name: "when request is valid and user has Upload Anywhere permission",
975 fileTransfers: map[[4]byte]*FileTransfer{},
977 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
979 transfers: map[int]map[[4]byte]*FileTransfer{
983 Access: func() accessBitmap {
984 var bits accessBitmap
985 bits.Set(accessUploadFile)
986 bits.Set(accessUploadAnywhere)
992 tranUploadFile, &[]byte{0, 1},
993 NewField(fieldFileName, []byte("testFile")),
994 NewField(fieldFilePath, []byte{
1002 wantRes: []Transaction{
1006 Type: []byte{0, 0xcb},
1007 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1008 ErrorCode: []byte{0, 0, 0, 0},
1010 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
1017 name: "when user does not have required access",
1021 Access: func() accessBitmap {
1022 var bits accessBitmap
1028 tranUploadFile, &[]byte{0, 1},
1029 NewField(fieldFileName, []byte("testFile")),
1030 NewField(fieldFilePath, []byte{
1038 wantRes: []Transaction{
1042 Type: []byte{0, 0x00},
1043 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1044 ErrorCode: []byte{0, 0, 0, 1},
1046 NewField(fieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
1053 for _, tt := range tests {
1054 t.Run(tt.name, func(t *testing.T) {
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)
1062 tranAssertEqual(t, tt.wantRes, gotRes)
1068 func TestHandleMakeAlias(t *testing.T) {
1076 wantRes []Transaction
1080 name: "with valid input and required permissions",
1083 logger: NewTestLogger(),
1085 Access: func() accessBitmap {
1086 var bits accessBitmap
1087 bits.Set(accessMakeAlias)
1093 FileRoot: func() string {
1094 path, _ := os.Getwd()
1095 return path + "/test/config/Files"
1098 Logger: NewTestLogger(),
1099 FS: func() *MockFileStore {
1100 mfs := &MockFileStore{}
1101 path, _ := os.Getwd()
1104 path+"/test/config/Files/foo/testFile",
1105 path+"/test/config/Files/bar/testFile",
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"}, "/"))),
1118 wantRes: []Transaction{
1122 Type: []byte{0, 0xd1},
1123 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1124 ErrorCode: []byte{0, 0, 0, 0},
1125 Fields: []Field(nil),
1131 name: "when symlink returns an error",
1134 logger: NewTestLogger(),
1136 Access: func() accessBitmap {
1137 var bits accessBitmap
1138 bits.Set(accessMakeAlias)
1144 FileRoot: func() string {
1145 path, _ := os.Getwd()
1146 return path + "/test/config/Files"
1149 Logger: NewTestLogger(),
1150 FS: func() *MockFileStore {
1151 mfs := &MockFileStore{}
1152 path, _ := os.Getwd()
1155 path+"/test/config/Files/foo/testFile",
1156 path+"/test/config/Files/bar/testFile",
1157 ).Return(errors.New("ohno"))
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"}, "/"))),
1169 wantRes: []Transaction{
1173 Type: []byte{0, 0x00},
1174 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1175 ErrorCode: []byte{0, 0, 0, 1},
1177 NewField(fieldError, []byte("Error creating alias")),
1184 name: "when user does not have required permission",
1187 logger: NewTestLogger(),
1189 Access: func() accessBitmap {
1190 var bits accessBitmap
1196 FileRoot: func() string {
1197 path, _ := os.Getwd()
1198 return path + "/test/config/Files"
1204 tranMakeFileAlias, &[]byte{0, 1},
1205 NewField(fieldFileName, []byte("testFile")),
1206 NewField(fieldFilePath, []byte{
1212 NewField(fieldFileNewPath, []byte{
1220 wantRes: []Transaction{
1224 Type: []byte{0, 0x00},
1225 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1226 ErrorCode: []byte{0, 0, 0, 1},
1228 NewField(fieldError, []byte("You are not allowed to make aliases.")),
1235 for _, tt := range tests {
1236 t.Run(tt.name, func(t *testing.T) {
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)
1243 tranAssertEqual(t, tt.wantRes, gotRes)
1248 func TestHandleGetUser(t *testing.T) {
1256 wantRes []Transaction
1257 wantErr assert.ErrorAssertionFunc
1260 name: "when account is valid",
1264 Access: func() accessBitmap {
1265 var bits accessBitmap
1266 bits.Set(accessOpenUser)
1271 Accounts: map[string]*Account{
1275 Password: "password",
1276 Access: accessBitmap{},
1282 tranGetUser, &[]byte{0, 1},
1283 NewField(fieldUserLogin, []byte("guest")),
1286 wantRes: []Transaction{
1290 Type: []byte{0x01, 0x60},
1291 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1292 ErrorCode: []byte{0, 0, 0, 0},
1294 NewField(fieldUserName, []byte("Guest")),
1295 NewField(fieldUserLogin, negateString([]byte("guest"))),
1296 NewField(fieldUserPassword, []byte("password")),
1297 NewField(fieldUserAccess, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
1301 wantErr: assert.NoError,
1304 name: "when user does not have required permission",
1308 Access: func() accessBitmap {
1309 var bits accessBitmap
1314 Accounts: map[string]*Account{},
1318 tranGetUser, &[]byte{0, 1},
1319 NewField(fieldUserLogin, []byte("nonExistentUser")),
1322 wantRes: []Transaction{
1326 Type: []byte{0, 0x00},
1327 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1328 ErrorCode: []byte{0, 0, 0, 1},
1330 NewField(fieldError, []byte("You are not allowed to view accounts.")),
1334 wantErr: assert.NoError,
1337 name: "when account does not exist",
1341 Access: func() accessBitmap {
1342 var bits accessBitmap
1343 bits.Set(accessOpenUser)
1348 Accounts: map[string]*Account{},
1352 tranGetUser, &[]byte{0, 1},
1353 NewField(fieldUserLogin, []byte("nonExistentUser")),
1356 wantRes: []Transaction{
1360 Type: []byte{0, 0x00},
1361 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1362 ErrorCode: []byte{0, 0, 0, 1},
1364 NewField(fieldError, []byte("Account does not exist.")),
1368 wantErr: assert.NoError,
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)) {
1378 tranAssertEqual(t, tt.wantRes, gotRes)
1383 func TestHandleDeleteUser(t *testing.T) {
1391 wantRes []Transaction
1392 wantErr assert.ErrorAssertionFunc
1395 name: "when user dataFile",
1399 Access: func() accessBitmap {
1400 var bits accessBitmap
1401 bits.Set(accessDeleteUser)
1406 Accounts: map[string]*Account{
1409 Name: "Testy McTest",
1410 Password: "password",
1411 Access: accessBitmap{},
1414 FS: func() *MockFileStore {
1415 mfs := &MockFileStore{}
1416 mfs.On("Remove", "Users/testuser.yaml").Return(nil)
1422 tranDeleteUser, &[]byte{0, 1},
1423 NewField(fieldUserLogin, negateString([]byte("testuser"))),
1426 wantRes: []Transaction{
1430 Type: []byte{0x1, 0x5f},
1431 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1432 ErrorCode: []byte{0, 0, 0, 0},
1433 Fields: []Field(nil),
1436 wantErr: assert.NoError,
1439 name: "when user does not have required permission",
1443 Access: func() accessBitmap {
1444 var bits accessBitmap
1449 Accounts: map[string]*Account{},
1453 tranDeleteUser, &[]byte{0, 1},
1454 NewField(fieldUserLogin, negateString([]byte("testuser"))),
1457 wantRes: []Transaction{
1461 Type: []byte{0, 0x00},
1462 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1463 ErrorCode: []byte{0, 0, 0, 1},
1465 NewField(fieldError, []byte("You are not allowed to delete accounts.")),
1469 wantErr: assert.NoError,
1472 for _, tt := range tests {
1473 t.Run(tt.name, func(t *testing.T) {
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)) {
1479 tranAssertEqual(t, tt.wantRes, gotRes)
1484 func TestHandleGetMsgs(t *testing.T) {
1492 wantRes []Transaction
1493 wantErr assert.ErrorAssertionFunc
1496 name: "returns news data",
1500 Access: func() accessBitmap {
1501 var bits accessBitmap
1502 bits.Set(accessNewsReadArt)
1507 FlatNews: []byte("TEST"),
1511 tranGetMsgs, &[]byte{0, 1},
1514 wantRes: []Transaction{
1518 Type: []byte{0, 0x65},
1519 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1520 ErrorCode: []byte{0, 0, 0, 0},
1522 NewField(fieldData, []byte("TEST")),
1526 wantErr: assert.NoError,
1529 name: "when user does not have required permission",
1533 Access: func() accessBitmap {
1534 var bits accessBitmap
1539 Accounts: map[string]*Account{},
1543 tranGetMsgs, &[]byte{0, 1},
1546 wantRes: []Transaction{
1550 Type: []byte{0, 0x00},
1551 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1552 ErrorCode: []byte{0, 0, 0, 1},
1554 NewField(fieldError, []byte("You are not allowed to read news.")),
1558 wantErr: assert.NoError,
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)) {
1568 tranAssertEqual(t, tt.wantRes, gotRes)
1573 func TestHandleNewUser(t *testing.T) {
1581 wantRes []Transaction
1582 wantErr assert.ErrorAssertionFunc
1585 name: "when user does not have required permission",
1589 Access: func() accessBitmap {
1590 var bits accessBitmap
1595 Accounts: map[string]*Account{},
1599 tranNewUser, &[]byte{0, 1},
1602 wantRes: []Transaction{
1606 Type: []byte{0, 0x00},
1607 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1608 ErrorCode: []byte{0, 0, 0, 1},
1610 NewField(fieldError, []byte("You are not allowed to create new accounts.")),
1614 wantErr: assert.NoError,
1617 for _, tt := range tests {
1618 t.Run(tt.name, func(t *testing.T) {
1619 gotRes, err := HandleNewUser(tt.args.cc, tt.args.t)
1620 if !tt.wantErr(t, err, fmt.Sprintf("HandleNewUser(%v, %v)", tt.args.cc, tt.args.t)) {
1624 tranAssertEqual(t, tt.wantRes, gotRes)
1629 func TestHandleListUsers(t *testing.T) {
1637 wantRes []Transaction
1638 wantErr assert.ErrorAssertionFunc
1641 name: "when user does not have required permission",
1645 Access: func() accessBitmap {
1646 var bits accessBitmap
1651 Accounts: map[string]*Account{},
1655 tranNewUser, &[]byte{0, 1},
1658 wantRes: []Transaction{
1662 Type: []byte{0, 0x00},
1663 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1664 ErrorCode: []byte{0, 0, 0, 1},
1666 NewField(fieldError, []byte("You are not allowed to view accounts.")),
1670 wantErr: assert.NoError,
1673 name: "when user has required permission",
1677 Access: func() accessBitmap {
1678 var bits accessBitmap
1679 bits.Set(accessOpenUser)
1684 Accounts: map[string]*Account{
1689 Access: accessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
1695 tranGetClientInfoText, &[]byte{0, 1},
1696 NewField(fieldUserID, []byte{0, 1}),
1699 wantRes: []Transaction{
1703 Type: []byte{0x01, 0x2f},
1704 ID: []byte{0, 0, 0, 0},
1705 ErrorCode: []byte{0, 0, 0, 0},
1707 NewField(fieldData, []byte{
1708 0x00, 0x04, 0x00, 0x66, 0x00, 0x05, 0x67, 0x75, 0x65, 0x73, 0x74, 0x00, 0x69, 0x00, 0x05, 0x98,
1709 0x8a, 0x9a, 0x8c, 0x8b, 0x00, 0x6e, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1710 0x00, 0x6a, 0x00, 0x01, 0x78,
1715 wantErr: assert.NoError,
1718 for _, tt := range tests {
1719 t.Run(tt.name, func(t *testing.T) {
1720 gotRes, err := HandleListUsers(tt.args.cc, tt.args.t)
1721 if !tt.wantErr(t, err, fmt.Sprintf("HandleListUsers(%v, %v)", tt.args.cc, tt.args.t)) {
1725 tranAssertEqual(t, tt.wantRes, gotRes)
1730 func TestHandleDownloadFile(t *testing.T) {
1738 wantRes []Transaction
1739 wantErr assert.ErrorAssertionFunc
1742 name: "when user does not have required permission",
1746 Access: func() accessBitmap {
1747 var bits accessBitmap
1753 t: NewTransaction(tranDownloadFile, &[]byte{0, 1}),
1755 wantRes: []Transaction{
1759 Type: []byte{0, 0x00},
1760 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1761 ErrorCode: []byte{0, 0, 0, 1},
1763 NewField(fieldError, []byte("You are not allowed to download files.")),
1767 wantErr: assert.NoError,
1770 name: "with a valid file",
1773 transfers: map[int]map[[4]byte]*FileTransfer{
1777 Access: func() accessBitmap {
1778 var bits accessBitmap
1779 bits.Set(accessDownloadFile)
1785 fileTransfers: map[[4]byte]*FileTransfer{},
1787 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1789 Accounts: map[string]*Account{},
1795 NewField(fieldFileName, []byte("testfile.txt")),
1796 NewField(fieldFilePath, []byte{0x0, 0x00}),
1799 wantRes: []Transaction{
1803 Type: []byte{0, 0x2},
1804 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1805 ErrorCode: []byte{0, 0, 0, 0},
1807 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1808 NewField(fieldWaitingCount, []byte{0x00, 0x00}),
1809 NewField(fieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1810 NewField(fieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
1814 wantErr: assert.NoError,
1817 name: "when client requests to resume 1k test file at offset 256",
1820 transfers: map[int]map[[4]byte]*FileTransfer{
1822 }, Account: &Account{
1823 Access: func() accessBitmap {
1824 var bits accessBitmap
1825 bits.Set(accessDownloadFile)
1832 // FS: func() *MockFileStore {
1833 // path, _ := os.Getwd()
1834 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1839 // mfi := &MockFileInfo{}
1840 // mfi.On("Mode").Return(fs.FileMode(0))
1841 // mfs := &MockFileStore{}
1842 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1843 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1844 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
1845 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
1849 fileTransfers: map[[4]byte]*FileTransfer{},
1851 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1853 Accounts: map[string]*Account{},
1859 NewField(fieldFileName, []byte("testfile-1k")),
1860 NewField(fieldFilePath, []byte{0x00, 0x00}),
1862 fieldFileResumeData,
1864 frd := FileResumeData{
1868 ForkCount: [2]byte{0, 2},
1869 ForkInfoList: []ForkInfoList{
1871 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
1872 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
1877 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
1878 DataSize: [4]byte{0, 0, 0, 0},
1884 b, _ := frd.BinaryMarshal()
1890 wantRes: []Transaction{
1894 Type: []byte{0, 0x2},
1895 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1896 ErrorCode: []byte{0, 0, 0, 0},
1898 NewField(fieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1899 NewField(fieldWaitingCount, []byte{0x00, 0x00}),
1900 NewField(fieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
1901 NewField(fieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
1905 wantErr: assert.NoError,
1908 for _, tt := range tests {
1909 t.Run(tt.name, func(t *testing.T) {
1910 gotRes, err := HandleDownloadFile(tt.args.cc, tt.args.t)
1911 if !tt.wantErr(t, err, fmt.Sprintf("HandleDownloadFile(%v, %v)", tt.args.cc, tt.args.t)) {
1915 tranAssertEqual(t, tt.wantRes, gotRes)
1920 func TestHandleUpdateUser(t *testing.T) {
1928 wantRes []Transaction
1929 wantErr assert.ErrorAssertionFunc
1932 name: "when action is create user without required permission",
1935 logger: NewTestLogger(),
1937 Logger: NewTestLogger(),
1940 Access: func() accessBitmap {
1941 var bits accessBitmap
1949 NewField(fieldData, []byte{
1950 0x00, 0x04, // field count
1952 0x00, 0x69, // fieldUserLogin = 105
1956 0x00, 0x6a, // fieldUserPassword = 106
1960 0x00, 0x66, // fieldUserName = 102
1964 0x00, 0x6e, // fieldUserAccess = 110
1966 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
1970 wantRes: []Transaction{
1974 Type: []byte{0, 0x00},
1975 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
1976 ErrorCode: []byte{0, 0, 0, 1},
1978 NewField(fieldError, []byte("You are not allowed to create new accounts.")),
1982 wantErr: assert.NoError,
1985 name: "when action is modify user without required permission",
1988 logger: NewTestLogger(),
1990 Logger: NewTestLogger(),
1991 Accounts: map[string]*Account{
1996 Access: func() accessBitmap {
1997 var bits accessBitmap
2005 NewField(fieldData, []byte{
2006 0x00, 0x04, // field count
2008 0x00, 0x69, // fieldUserLogin = 105
2012 0x00, 0x6a, // fieldUserPassword = 106
2016 0x00, 0x66, // fieldUserName = 102
2020 0x00, 0x6e, // fieldUserAccess = 110
2022 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2026 wantRes: []Transaction{
2030 Type: []byte{0, 0x00},
2031 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2032 ErrorCode: []byte{0, 0, 0, 1},
2034 NewField(fieldError, []byte("You are not allowed to modify accounts.")),
2038 wantErr: assert.NoError,
2041 name: "when action is delete user without required permission",
2044 logger: NewTestLogger(),
2046 Accounts: map[string]*Account{
2051 Access: func() accessBitmap {
2052 var bits accessBitmap
2060 NewField(fieldData, []byte{
2068 wantRes: []Transaction{
2072 Type: []byte{0, 0x00},
2073 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2074 ErrorCode: []byte{0, 0, 0, 1},
2076 NewField(fieldError, []byte("You are not allowed to delete accounts.")),
2080 wantErr: assert.NoError,
2083 for _, tt := range tests {
2084 t.Run(tt.name, func(t *testing.T) {
2085 gotRes, err := HandleUpdateUser(tt.args.cc, tt.args.t)
2086 if !tt.wantErr(t, err, fmt.Sprintf("HandleUpdateUser(%v, %v)", tt.args.cc, tt.args.t)) {
2090 tranAssertEqual(t, tt.wantRes, gotRes)
2095 func TestHandleDelNewsArt(t *testing.T) {
2103 wantRes []Transaction
2104 wantErr assert.ErrorAssertionFunc
2107 name: "without required permission",
2111 Access: func() accessBitmap {
2112 var bits accessBitmap
2122 wantRes: []Transaction{
2126 Type: []byte{0, 0x00},
2127 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2128 ErrorCode: []byte{0, 0, 0, 1},
2130 NewField(fieldError, []byte("You are not allowed to delete news articles.")),
2134 wantErr: assert.NoError,
2137 for _, tt := range tests {
2138 t.Run(tt.name, func(t *testing.T) {
2139 gotRes, err := HandleDelNewsArt(tt.args.cc, tt.args.t)
2140 if !tt.wantErr(t, err, fmt.Sprintf("HandleDelNewsArt(%v, %v)", tt.args.cc, tt.args.t)) {
2143 tranAssertEqual(t, tt.wantRes, gotRes)
2148 func TestHandleDisconnectUser(t *testing.T) {
2156 wantRes []Transaction
2157 wantErr assert.ErrorAssertionFunc
2160 name: "without required permission",
2164 Access: func() accessBitmap {
2165 var bits accessBitmap
2175 wantRes: []Transaction{
2179 Type: []byte{0, 0x00},
2180 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2181 ErrorCode: []byte{0, 0, 0, 1},
2183 NewField(fieldError, []byte("You are not allowed to disconnect users.")),
2187 wantErr: assert.NoError,
2190 name: "when target user has 'cannot be disconnected' priv",
2194 Clients: map[uint16]*ClientConn{
2198 Access: func() accessBitmap {
2199 var bits accessBitmap
2200 bits.Set(accessCannotBeDiscon)
2208 Access: func() accessBitmap {
2209 var bits accessBitmap
2210 bits.Set(accessDisconUser)
2218 NewField(fieldUserID, []byte{0, 1}),
2221 wantRes: []Transaction{
2225 Type: []byte{0, 0x00},
2226 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2227 ErrorCode: []byte{0, 0, 0, 1},
2229 NewField(fieldError, []byte("unnamed is not allowed to be disconnected.")),
2233 wantErr: assert.NoError,
2236 for _, tt := range tests {
2237 t.Run(tt.name, func(t *testing.T) {
2238 gotRes, err := HandleDisconnectUser(tt.args.cc, tt.args.t)
2239 if !tt.wantErr(t, err, fmt.Sprintf("HandleDisconnectUser(%v, %v)", tt.args.cc, tt.args.t)) {
2242 tranAssertEqual(t, tt.wantRes, gotRes)
2247 func TestHandleSendInstantMsg(t *testing.T) {
2255 wantRes []Transaction
2256 wantErr assert.ErrorAssertionFunc
2259 name: "without required permission",
2263 Access: func() accessBitmap {
2264 var bits accessBitmap
2274 wantRes: []Transaction{
2278 Type: []byte{0, 0x00},
2279 ID: []byte{0, 0, 0, 0},
2280 ErrorCode: []byte{0, 0, 0, 1},
2282 NewField(fieldError, []byte("You are not allowed to send private messages.")),
2286 wantErr: assert.NoError,
2289 name: "when client 1 sends a message to client 2",
2293 Access: func() accessBitmap {
2294 var bits accessBitmap
2295 bits.Set(accessSendPrivMsg)
2300 UserName: []byte("User1"),
2302 Clients: map[uint16]*ClientConn{
2304 AutoReply: []byte(nil),
2305 Flags: []byte{0, 0},
2313 NewField(fieldData, []byte("hai")),
2314 NewField(fieldUserID, []byte{0, 2}),
2317 wantRes: []Transaction{
2321 NewField(fieldData, []byte("hai")),
2322 NewField(fieldUserName, []byte("User1")),
2323 NewField(fieldUserID, []byte{0, 1}),
2324 NewField(fieldOptions, []byte{0, 1}),
2327 clientID: &[]byte{0, 1},
2330 Type: []byte{0x0, 0x6c},
2331 ID: []byte{0, 0, 0, 0},
2332 ErrorCode: []byte{0, 0, 0, 0},
2333 Fields: []Field(nil),
2336 wantErr: assert.NoError,
2339 name: "when client 2 has autoreply enabled",
2343 Access: func() accessBitmap {
2344 var bits accessBitmap
2345 bits.Set(accessSendPrivMsg)
2350 UserName: []byte("User1"),
2352 Clients: map[uint16]*ClientConn{
2354 Flags: []byte{0, 0},
2356 UserName: []byte("User2"),
2357 AutoReply: []byte("autohai"),
2365 NewField(fieldData, []byte("hai")),
2366 NewField(fieldUserID, []byte{0, 2}),
2369 wantRes: []Transaction{
2373 NewField(fieldData, []byte("hai")),
2374 NewField(fieldUserName, []byte("User1")),
2375 NewField(fieldUserID, []byte{0, 1}),
2376 NewField(fieldOptions, []byte{0, 1}),
2381 NewField(fieldData, []byte("autohai")),
2382 NewField(fieldUserName, []byte("User2")),
2383 NewField(fieldUserID, []byte{0, 2}),
2384 NewField(fieldOptions, []byte{0, 1}),
2387 clientID: &[]byte{0, 1},
2390 Type: []byte{0x0, 0x6c},
2391 ID: []byte{0, 0, 0, 0},
2392 ErrorCode: []byte{0, 0, 0, 0},
2393 Fields: []Field(nil),
2396 wantErr: assert.NoError,
2399 name: "when client 2 has refuse private messages enabled",
2403 Access: func() accessBitmap {
2404 var bits accessBitmap
2405 bits.Set(accessSendPrivMsg)
2410 UserName: []byte("User1"),
2412 Clients: map[uint16]*ClientConn{
2414 Flags: []byte{255, 255},
2416 UserName: []byte("User2"),
2424 NewField(fieldData, []byte("hai")),
2425 NewField(fieldUserID, []byte{0, 2}),
2428 wantRes: []Transaction{
2432 NewField(fieldData, []byte("User2 does not accept private messages.")),
2433 NewField(fieldUserName, []byte("User2")),
2434 NewField(fieldUserID, []byte{0, 2}),
2435 NewField(fieldOptions, []byte{0, 2}),
2438 clientID: &[]byte{0, 1},
2441 Type: []byte{0x0, 0x6c},
2442 ID: []byte{0, 0, 0, 0},
2443 ErrorCode: []byte{0, 0, 0, 0},
2444 Fields: []Field(nil),
2447 wantErr: assert.NoError,
2450 for _, tt := range tests {
2451 t.Run(tt.name, func(t *testing.T) {
2452 gotRes, err := HandleSendInstantMsg(tt.args.cc, tt.args.t)
2453 if !tt.wantErr(t, err, fmt.Sprintf("HandleSendInstantMsg(%v, %v)", tt.args.cc, tt.args.t)) {
2457 tranAssertEqual(t, tt.wantRes, gotRes)
2462 func TestHandleDeleteFile(t *testing.T) {
2470 wantRes []Transaction
2471 wantErr assert.ErrorAssertionFunc
2474 name: "when user does not have required permission to delete a folder",
2478 Access: func() accessBitmap {
2479 var bits accessBitmap
2485 FileRoot: func() string {
2486 return "/fakeRoot/Files"
2489 FS: func() *MockFileStore {
2490 mfi := &MockFileInfo{}
2491 mfi.On("Mode").Return(fs.FileMode(0))
2492 mfi.On("Size").Return(int64(100))
2493 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2494 mfi.On("IsDir").Return(false)
2495 mfi.On("Name").Return("testfile")
2497 mfs := &MockFileStore{}
2498 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2499 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2500 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2504 Accounts: map[string]*Account{},
2508 tranDeleteFile, &[]byte{0, 1},
2509 NewField(fieldFileName, []byte("testfile")),
2510 NewField(fieldFilePath, []byte{
2518 wantRes: []Transaction{
2522 Type: []byte{0, 0x00},
2523 ID: []byte{0x9a, 0xcb, 0x04, 0x42},
2524 ErrorCode: []byte{0, 0, 0, 1},
2526 NewField(fieldError, []byte("You are not allowed to delete files.")),
2530 wantErr: assert.NoError,
2533 name: "deletes all associated metadata files",
2537 Access: func() accessBitmap {
2538 var bits accessBitmap
2539 bits.Set(accessDeleteFile)
2545 FileRoot: func() string {
2546 return "/fakeRoot/Files"
2549 FS: func() *MockFileStore {
2550 mfi := &MockFileInfo{}
2551 mfi.On("Mode").Return(fs.FileMode(0))
2552 mfi.On("Size").Return(int64(100))
2553 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2554 mfi.On("IsDir").Return(false)
2555 mfi.On("Name").Return("testfile")
2557 mfs := &MockFileStore{}
2558 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2559 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2560 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2562 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2563 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2564 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2565 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2569 Accounts: map[string]*Account{},
2573 tranDeleteFile, &[]byte{0, 1},
2574 NewField(fieldFileName, []byte("testfile")),
2575 NewField(fieldFilePath, []byte{
2583 wantRes: []Transaction{
2587 Type: []byte{0x0, 0xcc},
2588 ID: []byte{0x0, 0x0, 0x0, 0x0},
2589 ErrorCode: []byte{0, 0, 0, 0},
2590 Fields: []Field(nil),
2593 wantErr: assert.NoError,
2596 for _, tt := range tests {
2597 t.Run(tt.name, func(t *testing.T) {
2598 gotRes, err := HandleDeleteFile(tt.args.cc, tt.args.t)
2599 if !tt.wantErr(t, err, fmt.Sprintf("HandleDeleteFile(%v, %v)", tt.args.cc, tt.args.t)) {
2603 tranAssertEqual(t, tt.wantRes, gotRes)
2605 tt.args.cc.Server.FS.(*MockFileStore).AssertExpectations(t)
2610 func TestHandleGetFileNameList(t *testing.T) {
2618 wantRes []Transaction
2619 wantErr assert.ErrorAssertionFunc
2622 name: "when fieldFilePath is a drop box, but user does not have accessViewDropBoxes ",
2626 Access: func() accessBitmap {
2627 var bits accessBitmap
2634 FileRoot: func() string {
2635 path, _ := os.Getwd()
2636 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2642 tranGetFileNameList, &[]byte{0, 1},
2643 NewField(fieldFilePath, []byte{
2647 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2651 wantRes: []Transaction{
2655 Type: []byte{0, 0x00},
2656 ID: []byte{0, 0, 0, 0},
2657 ErrorCode: []byte{0, 0, 0, 1},
2659 NewField(fieldError, []byte("You are not allowed to view drop boxes.")),
2663 wantErr: assert.NoError,
2666 name: "with file root",
2671 FileRoot: func() string {
2672 path, _ := os.Getwd()
2673 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2679 tranGetFileNameList, &[]byte{0, 1},
2680 NewField(fieldFilePath, []byte{
2686 wantRes: []Transaction{
2690 Type: []byte{0, 0xc8},
2691 ID: []byte{0, 0, 0, 0},
2692 ErrorCode: []byte{0, 0, 0, 0},
2695 fieldFileNameWithInfo,
2697 fnwi := FileNameWithInfo{
2698 fileNameWithInfoHeader: fileNameWithInfoHeader{
2699 Type: [4]byte{0x54, 0x45, 0x58, 0x54},
2700 Creator: [4]byte{0x54, 0x54, 0x58, 0x54},
2701 FileSize: [4]byte{0, 0, 0x04, 0},
2703 NameScript: [2]byte{},
2704 NameSize: [2]byte{0, 0x0b},
2706 name: []byte("testfile-1k"),
2708 b, _ := fnwi.MarshalBinary()
2715 wantErr: assert.NoError,
2718 for _, tt := range tests {
2719 t.Run(tt.name, func(t *testing.T) {
2720 gotRes, err := HandleGetFileNameList(tt.args.cc, tt.args.t)
2721 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetFileNameList(%v, %v)", tt.args.cc, tt.args.t)) {
2725 tranAssertEqual(t, tt.wantRes, gotRes)
2730 func TestHandleGetClientInfoText(t *testing.T) {
2738 wantRes []Transaction
2739 wantErr assert.ErrorAssertionFunc
2742 name: "when user does not have required permission",
2746 Access: func() accessBitmap {
2747 var bits accessBitmap
2752 Accounts: map[string]*Account{},
2756 tranGetClientInfoText, &[]byte{0, 1},
2757 NewField(fieldUserID, []byte{0, 1}),
2760 wantRes: []Transaction{
2764 Type: []byte{0, 0x00},
2765 ID: []byte{0, 0, 0, 0},
2766 ErrorCode: []byte{0, 0, 0, 1},
2768 NewField(fieldError, []byte("You are not allowed to get client info.")),
2772 wantErr: assert.NoError,
2775 name: "with a valid user",
2778 UserName: []byte("Testy McTest"),
2779 RemoteAddr: "1.2.3.4:12345",
2781 Access: func() accessBitmap {
2782 var bits accessBitmap
2783 bits.Set(accessGetClientInfo)
2790 Accounts: map[string]*Account{},
2791 Clients: map[uint16]*ClientConn{
2793 UserName: []byte("Testy McTest"),
2794 RemoteAddr: "1.2.3.4:12345",
2796 Access: func() accessBitmap {
2797 var bits accessBitmap
2798 bits.Set(accessGetClientInfo)
2807 transfers: map[int]map[[4]byte]*FileTransfer{
2815 tranGetClientInfoText, &[]byte{0, 1},
2816 NewField(fieldUserID, []byte{0, 1}),
2819 wantRes: []Transaction{
2823 Type: []byte{0x1, 0x2f},
2824 ID: []byte{0, 0, 0, 0},
2825 ErrorCode: []byte{0, 0, 0, 0},
2827 NewField(fieldData, []byte(
2828 strings.Replace(`Nickname: Testy McTest
2831 Address: 1.2.3.4:12345
2833 -------- File Downloads ---------
2837 ------- Folder Downloads --------
2841 --------- File Uploads ----------
2845 -------- Folder Uploads ---------
2849 ------- Waiting Downloads -------
2853 `, "\n", "\r", -1)),
2855 NewField(fieldUserName, []byte("Testy McTest")),
2859 wantErr: assert.NoError,
2862 for _, tt := range tests {
2863 t.Run(tt.name, func(t *testing.T) {
2864 gotRes, err := HandleGetClientInfoText(tt.args.cc, tt.args.t)
2865 if !tt.wantErr(t, err, fmt.Sprintf("HandleGetClientInfoText(%v, %v)", tt.args.cc, tt.args.t)) {
2868 tranAssertEqual(t, tt.wantRes, gotRes)
2873 func TestHandleTranAgreed(t *testing.T) {
2881 wantRes []Transaction
2882 wantErr assert.ErrorAssertionFunc
2885 name: "normal request flow",
2889 Access: func() accessBitmap {
2890 var bits accessBitmap
2891 bits.Set(accessDisconUser)
2892 bits.Set(accessAnyName)
2896 Flags: []byte{0, 1},
2897 Version: []byte{0, 1},
2899 logger: NewTestLogger(),
2902 BannerFile: "banner.jpg",
2908 NewField(fieldUserName, []byte("username")),
2909 NewField(fieldUserIconID, []byte{0, 1}),
2910 NewField(fieldOptions, []byte{0, 0}),
2913 wantRes: []Transaction{
2915 clientID: &[]byte{0, 1},
2918 Type: []byte{0, 0x7a},
2919 ID: []byte{0, 0, 0, 0},
2920 ErrorCode: []byte{0, 0, 0, 0},
2922 NewField(fieldBannerType, []byte("JPEG")),
2926 clientID: &[]byte{0, 1},
2929 Type: []byte{0, 0x79},
2930 ID: []byte{0, 0, 0, 0},
2931 ErrorCode: []byte{0, 0, 0, 0},
2935 wantErr: assert.NoError,
2938 for _, tt := range tests {
2939 t.Run(tt.name, func(t *testing.T) {
2940 gotRes, err := HandleTranAgreed(tt.args.cc, tt.args.t)
2941 if !tt.wantErr(t, err, fmt.Sprintf("HandleTranAgreed(%v, %v)", tt.args.cc, tt.args.t)) {
2944 tranAssertEqual(t, tt.wantRes, gotRes)
2949 func TestHandleSetClientUserInfo(t *testing.T) {
2957 wantRes []Transaction
2958 wantErr assert.ErrorAssertionFunc
2961 name: "when client does not have accessAnyName",
2965 Access: func() accessBitmap {
2966 var bits accessBitmap
2971 UserName: []byte("Guest"),
2972 Flags: []byte{0, 1},
2974 Clients: map[uint16]*ClientConn{
2982 tranSetClientUserInfo, nil,
2983 NewField(fieldUserIconID, []byte{0, 1}),
2984 NewField(fieldUserName, []byte("NOPE")),
2987 wantRes: []Transaction{
2989 clientID: &[]byte{0, 1},
2992 Type: []byte{0x01, 0x2d},
2993 ID: []byte{0, 0, 0, 0},
2994 ErrorCode: []byte{0, 0, 0, 0},
2996 NewField(fieldUserID, []byte{0, 1}),
2997 NewField(fieldUserIconID, []byte{0, 1}),
2998 NewField(fieldUserFlags, []byte{0, 1}),
2999 NewField(fieldUserName, []byte("Guest"))},
3002 wantErr: assert.NoError,
3005 for _, tt := range tests {
3006 t.Run(tt.name, func(t *testing.T) {
3007 gotRes, err := HandleSetClientUserInfo(tt.args.cc, tt.args.t)
3008 if !tt.wantErr(t, err, fmt.Sprintf("HandleSetClientUserInfo(%v, %v)", tt.args.cc, tt.args.t)) {
3012 tranAssertEqual(t, tt.wantRes, gotRes)
3017 func TestHandleDelNewsItem(t *testing.T) {
3025 wantRes []Transaction
3026 wantErr assert.ErrorAssertionFunc
3029 name: "when user does not have permission to delete a news category",
3033 Access: accessBitmap{},
3037 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3048 tranDelNewsItem, nil,
3049 NewField(fieldNewsPath,
3054 0x74, 0x65, 0x73, 0x74,
3059 wantRes: []Transaction{
3061 clientID: &[]byte{0, 1},
3064 Type: []byte{0, 0x00},
3065 ID: []byte{0, 0, 0, 0},
3066 ErrorCode: []byte{0, 0, 0, 1},
3068 NewField(fieldError, []byte("You are not allowed to delete news categories.")),
3072 wantErr: assert.NoError,
3075 name: "when user does not have permission to delete a news folder",
3079 Access: accessBitmap{},
3083 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3094 tranDelNewsItem, nil,
3095 NewField(fieldNewsPath,
3100 0x74, 0x65, 0x73, 0x74,
3105 wantRes: []Transaction{
3107 clientID: &[]byte{0, 1},
3110 Type: []byte{0, 0x00},
3111 ID: []byte{0, 0, 0, 0},
3112 ErrorCode: []byte{0, 0, 0, 1},
3114 NewField(fieldError, []byte("You are not allowed to delete news folders.")),
3118 wantErr: assert.NoError,
3121 name: "when user deletes a news folder",
3125 Access: func() accessBitmap {
3126 var bits accessBitmap
3127 bits.Set(accessNewsDeleteFldr)
3133 ConfigDir: "/fakeConfigRoot",
3134 FS: func() *MockFileStore {
3135 mfs := &MockFileStore{}
3136 mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(nil, os.ErrNotExist)
3139 ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3150 tranDelNewsItem, nil,
3151 NewField(fieldNewsPath,
3156 0x74, 0x65, 0x73, 0x74,
3161 wantRes: []Transaction{
3163 clientID: &[]byte{0, 1},
3166 Type: []byte{0x01, 0x7c},
3167 ID: []byte{0, 0, 0, 0},
3168 ErrorCode: []byte{0, 0, 0, 0},
3172 wantErr: assert.NoError,
3175 for _, tt := range tests {
3176 t.Run(tt.name, func(t *testing.T) {
3177 gotRes, err := HandleDelNewsItem(tt.args.cc, tt.args.t)
3178 if !tt.wantErr(t, err, fmt.Sprintf("HandleDelNewsItem(%v, %v)", tt.args.cc, tt.args.t)) {
3181 tranAssertEqual(t, tt.wantRes, gotRes)
3186 func TestHandleDownloadBanner(t *testing.T) {
3194 wantRes []Transaction
3195 wantErr assert.ErrorAssertionFunc
3198 name: "returns expected response",
3202 transfers: map[int]map[[4]byte]*FileTransfer{
3206 ConfigDir: "/config",
3208 BannerFile: "banner.jpg",
3210 fileTransfers: map[[4]byte]*FileTransfer{},
3211 FS: func() *MockFileStore {
3212 mfi := &MockFileInfo{}
3213 mfi.On("Size").Return(int64(100))
3215 mfs := &MockFileStore{}
3216 mfs.On("Stat", "/config/banner.jpg").Return(mfi, nil)
3221 t: NewTransaction(tranDownloadBanner, nil),
3223 wantRes: []Transaction{
3225 clientID: &[]byte{0, 1},
3228 Type: []byte{0x00, 0xd4},
3229 ID: []byte{0, 0, 0, 0},
3230 ErrorCode: []byte{0, 0, 0, 0},
3232 NewField(fieldRefNum, []byte{1, 2, 3, 4}),
3233 NewField(fieldTransferSize, []byte{0, 0, 0, 0x64}),
3237 wantErr: assert.NoError,
3240 for _, tt := range tests {
3241 t.Run(tt.name, func(t *testing.T) {
3242 gotRes, err := HandleDownloadBanner(tt.args.cc, tt.args.t)
3243 if !tt.wantErr(t, err, fmt.Sprintf("HandleDownloadBanner(%v, %v)", tt.args.cc, tt.args.t)) {
3247 tranAssertEqual(t, tt.wantRes, gotRes)
3252 func TestHandleTranOldPostNews(t *testing.T) {
3260 wantRes []Transaction
3261 wantErr assert.ErrorAssertionFunc
3264 name: "when user does not have required permission",
3268 Access: func() accessBitmap {
3269 var bits accessBitmap
3275 tranOldPostNews, &[]byte{0, 1},
3276 NewField(fieldData, []byte("hai")),
3279 wantRes: []Transaction{
3283 Type: []byte{0, 0x00},
3284 ID: []byte{0, 0, 0, 0},
3285 ErrorCode: []byte{0, 0, 0, 1},
3287 NewField(fieldError, []byte("You are not allowed to post news.")),
3291 wantErr: assert.NoError,
3294 name: "when user posts news update",
3298 Access: func() accessBitmap {
3299 var bits accessBitmap
3300 bits.Set(accessNewsPostArt)
3305 FS: func() *MockFileStore {
3306 mfs := &MockFileStore{}
3307 mfs.On("WriteFile", "/fakeConfigRoot/MessageBoard.txt", mock.Anything, mock.Anything).Return(nil, os.ErrNotExist)
3310 ConfigDir: "/fakeConfigRoot",
3315 tranOldPostNews, &[]byte{0, 1},
3316 NewField(fieldData, []byte("hai")),
3319 wantRes: []Transaction{
3323 Type: []byte{0, 0x67},
3324 ID: []byte{0, 0, 0, 0},
3325 ErrorCode: []byte{0, 0, 0, 0},
3328 wantErr: assert.NoError,
3331 for _, tt := range tests {
3332 t.Run(tt.name, func(t *testing.T) {
3333 gotRes, err := HandleTranOldPostNews(tt.args.cc, tt.args.t)
3334 if !tt.wantErr(t, err, fmt.Sprintf("HandleTranOldPostNews(%v, %v)", tt.args.cc, tt.args.t)) {
3338 tranAssertEqual(t, tt.wantRes, gotRes)
3343 func TestHandleInviteNewChat(t *testing.T) {
3351 wantRes []Transaction
3352 wantErr assert.ErrorAssertionFunc
3355 name: "when user does not have required permission",
3359 Access: func() accessBitmap {
3360 var bits accessBitmap
3365 t: NewTransaction(tranInviteNewChat, &[]byte{0, 1}),
3367 wantRes: []Transaction{
3371 Type: []byte{0, 0x00},
3372 ID: []byte{0, 0, 0, 0},
3373 ErrorCode: []byte{0, 0, 0, 1},
3375 NewField(fieldError, []byte("You are not allowed to request private chat.")),
3379 wantErr: assert.NoError,
3382 name: "when userA invites userB to new private chat",
3387 Access: func() accessBitmap {
3388 var bits accessBitmap
3389 bits.Set(accessOpenChat)
3393 UserName: []byte("UserA"),
3395 Flags: []byte{0, 0},
3397 Clients: map[uint16]*ClientConn{
3400 UserName: []byte("UserB"),
3401 Flags: []byte{0, 0},
3404 PrivateChats: make(map[uint32]*PrivateChat),
3408 tranInviteNewChat, &[]byte{0, 1},
3409 NewField(fieldUserID, []byte{0, 2}),
3412 wantRes: []Transaction{
3414 clientID: &[]byte{0, 2},
3417 Type: []byte{0, 0x71},
3418 ID: []byte{0, 0, 0, 0},
3419 ErrorCode: []byte{0, 0, 0, 0},
3421 NewField(fieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3422 NewField(fieldUserName, []byte("UserA")),
3423 NewField(fieldUserID, []byte{0, 1}),
3428 clientID: &[]byte{0, 1},
3431 Type: []byte{0, 0x70},
3432 ID: []byte{0, 0, 0, 0},
3433 ErrorCode: []byte{0, 0, 0, 0},
3435 NewField(fieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3436 NewField(fieldUserName, []byte("UserA")),
3437 NewField(fieldUserID, []byte{0, 1}),
3438 NewField(fieldUserIconID, []byte{0, 1}),
3439 NewField(fieldUserFlags, []byte{0, 0}),
3443 wantErr: assert.NoError,
3446 name: "when userA invites userB to new private chat, but UserB has refuse private chat enabled",
3451 Access: func() accessBitmap {
3452 var bits accessBitmap
3453 bits.Set(accessOpenChat)
3457 UserName: []byte("UserA"),
3459 Flags: []byte{0, 0},
3461 Clients: map[uint16]*ClientConn{
3464 UserName: []byte("UserB"),
3465 Flags: []byte{255, 255},
3468 PrivateChats: make(map[uint32]*PrivateChat),
3472 tranInviteNewChat, &[]byte{0, 1},
3473 NewField(fieldUserID, []byte{0, 2}),
3476 wantRes: []Transaction{
3478 clientID: &[]byte{0, 1},
3481 Type: []byte{0, 0x68},
3482 ID: []byte{0, 0, 0, 0},
3483 ErrorCode: []byte{0, 0, 0, 0},
3485 NewField(fieldData, []byte("UserB does not accept private chats.")),
3486 NewField(fieldUserName, []byte("UserB")),
3487 NewField(fieldUserID, []byte{0, 2}),
3488 NewField(fieldOptions, []byte{0, 2}),
3492 clientID: &[]byte{0, 1},
3495 Type: []byte{0, 0x70},
3496 ID: []byte{0, 0, 0, 0},
3497 ErrorCode: []byte{0, 0, 0, 0},
3499 NewField(fieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3500 NewField(fieldUserName, []byte("UserA")),
3501 NewField(fieldUserID, []byte{0, 1}),
3502 NewField(fieldUserIconID, []byte{0, 1}),
3503 NewField(fieldUserFlags, []byte{0, 0}),
3507 wantErr: assert.NoError,
3510 for _, tt := range tests {
3511 t.Run(tt.name, func(t *testing.T) {
3513 gotRes, err := HandleInviteNewChat(tt.args.cc, tt.args.t)
3514 if !tt.wantErr(t, err, fmt.Sprintf("HandleInviteNewChat(%v, %v)", tt.args.cc, tt.args.t)) {
3517 tranAssertEqual(t, tt.wantRes, gotRes)