7 "github.com/jhalter/mobius/hotline"
8 "github.com/stretchr/testify/assert"
9 "github.com/stretchr/testify/mock"
21 type mockReadWriteSeeker struct {
25 func (m *mockReadWriteSeeker) Read(p []byte) (int, error) {
28 return args.Int(0), args.Error(1)
31 func (m *mockReadWriteSeeker) Write(p []byte) (int, error) {
34 return args.Int(0), args.Error(1)
37 func (m *mockReadWriteSeeker) Seek(offset int64, whence int) (int64, error) {
38 args := m.Called(offset, whence)
40 return args.Get(0).(int64), args.Error(1)
43 func NewTestLogger() *slog.Logger {
44 return slog.New(slog.NewTextHandler(os.Stdout, nil))
47 var tranSortFunc = func(a, b hotline.Transaction) int {
49 binary.BigEndian.Uint16(a.ClientID[:]),
50 binary.BigEndian.Uint16(b.ClientID[:]),
54 // TranAssertEqual compares equality of transactions slices after stripping out the random transaction Type
55 func TranAssertEqual(t *testing.T, tran1, tran2 []hotline.Transaction) bool {
56 var newT1 []hotline.Transaction
57 var newT2 []hotline.Transaction
59 for _, trans := range tran1 {
60 trans.ID = [4]byte{0, 0, 0, 0}
61 var fs []hotline.Field
62 for _, field := range trans.Fields {
63 if field.Type == hotline.FieldRefNum { // FieldRefNum
66 if field.Type == hotline.FieldChatID { // FieldChatID
70 fs = append(fs, field)
73 newT1 = append(newT1, trans)
76 for _, trans := range tran2 {
77 trans.ID = [4]byte{0, 0, 0, 0}
78 var fs []hotline.Field
79 for _, field := range trans.Fields {
80 if field.Type == hotline.FieldRefNum { // FieldRefNum
83 if field.Type == hotline.FieldChatID { // FieldChatID
87 fs = append(fs, field)
90 newT2 = append(newT2, trans)
93 slices.SortFunc(newT1, tranSortFunc)
94 slices.SortFunc(newT2, tranSortFunc)
96 return assert.Equal(t, newT1, newT2)
99 func TestHandleSetChatSubject(t *testing.T) {
101 cc *hotline.ClientConn
102 t hotline.Transaction
107 want []hotline.Transaction
110 name: "sends chat subject to private chat members",
112 cc: &hotline.ClientConn{
113 UserName: []byte{0x00, 0x01},
114 Server: &hotline.Server{
115 ChatMgr: func() *hotline.MockChatManager {
116 m := hotline.MockChatManager{}
117 m.On("Members", hotline.ChatID{0x0, 0x0, 0x0, 0x1}).Return([]*hotline.ClientConn{
119 Account: &hotline.Account{
120 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
125 Account: &hotline.Account{
126 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
131 m.On("SetSubject", hotline.ChatID{0x0, 0x0, 0x0, 0x1}, "Test Subject")
134 //PrivateChats: map[[4]byte]*PrivateChat{
135 // [4]byte{0, 0, 0, 1}: {
137 // ClientConn: map[[2]byte]*ClientConn{
139 // Account: &hotline.Account{
140 // Access: AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
142 // ID: [2]byte{0, 1},
145 // Account: &hotline.Account{
146 // Access: AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
148 // ID: [2]byte{0, 2},
153 ClientMgr: func() *hotline.MockClientMgr {
154 m := hotline.MockClientMgr{}
155 m.On("List").Return([]*hotline.ClientConn{
157 Account: &hotline.Account{
158 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
163 Account: &hotline.Account{
164 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
174 t: hotline.Transaction{
175 Type: [2]byte{0, 0x6a},
176 ID: [4]byte{0, 0, 0, 1},
177 Fields: []hotline.Field{
178 hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1}),
179 hotline.NewField(hotline.FieldChatSubject, []byte("Test Subject")),
183 want: []hotline.Transaction{
185 ClientID: [2]byte{0, 1},
186 Type: [2]byte{0, 0x77},
187 Fields: []hotline.Field{
188 hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1}),
189 hotline.NewField(hotline.FieldChatSubject, []byte("Test Subject")),
193 ClientID: [2]byte{0, 2},
194 Type: [2]byte{0, 0x77},
195 Fields: []hotline.Field{
196 hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1}),
197 hotline.NewField(hotline.FieldChatSubject, []byte("Test Subject")),
203 for _, tt := range tests {
204 t.Run(tt.name, func(t *testing.T) {
205 got := HandleSetChatSubject(tt.args.cc, &tt.args.t)
206 if !TranAssertEqual(t, tt.want, got) {
207 t.Errorf("HandleSetChatSubject() got = %v, want %v", got, tt.want)
213 func TestHandleLeaveChat(t *testing.T) {
215 cc *hotline.ClientConn
216 t hotline.Transaction
221 want []hotline.Transaction
224 name: "when client 2 leaves chat",
226 cc: &hotline.ClientConn{
228 Server: &hotline.Server{
229 ChatMgr: func() *hotline.MockChatManager {
230 m := hotline.MockChatManager{}
231 m.On("Members", hotline.ChatID{0x0, 0x0, 0x0, 0x1}).Return([]*hotline.ClientConn{
233 Account: &hotline.Account{
234 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
239 m.On("Leave", hotline.ChatID{0x0, 0x0, 0x0, 0x1}, [2]uint8{0x0, 0x2})
240 m.On("GetSubject").Return("unset")
243 ClientMgr: func() *hotline.MockClientMgr {
244 m := hotline.MockClientMgr{}
245 m.On("Get").Return([]*hotline.ClientConn{
247 Account: &hotline.Account{
248 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
253 Account: &hotline.Account{
254 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
264 t: hotline.NewTransaction(hotline.TranDeleteUser, [2]byte{}, hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1})),
266 want: []hotline.Transaction{
268 ClientID: [2]byte{0, 1},
269 Type: [2]byte{0, 0x76},
270 Fields: []hotline.Field{
271 hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1}),
272 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
278 for _, tt := range tests {
279 t.Run(tt.name, func(t *testing.T) {
280 got := HandleLeaveChat(tt.args.cc, &tt.args.t)
281 if !TranAssertEqual(t, tt.want, got) {
282 t.Errorf("HandleLeaveChat() got = %v, want %v", got, tt.want)
288 func TestHandleGetUserNameList(t *testing.T) {
290 cc *hotline.ClientConn
291 t hotline.Transaction
296 want []hotline.Transaction
299 name: "replies with userlist transaction",
301 cc: &hotline.ClientConn{
303 Server: &hotline.Server{
304 ClientMgr: func() *hotline.MockClientMgr {
305 m := hotline.MockClientMgr{}
306 m.On("List").Return([]*hotline.ClientConn{
310 Flags: [2]byte{0, 3},
311 UserName: []byte{0, 4},
316 Flags: [2]byte{0, 3},
317 UserName: []byte{0, 4},
325 t: hotline.Transaction{},
327 want: []hotline.Transaction{
329 ClientID: [2]byte{0, 1},
331 Fields: []hotline.Field{
333 hotline.FieldUsernameWithInfo,
334 []byte{00, 01, 00, 02, 00, 03, 00, 02, 00, 04},
337 hotline.FieldUsernameWithInfo,
338 []byte{00, 02, 00, 02, 00, 03, 00, 02, 00, 04},
345 for _, tt := range tests {
346 t.Run(tt.name, func(t *testing.T) {
347 got := HandleGetUserNameList(tt.args.cc, &tt.args.t)
348 assert.Equal(t, tt.want, got)
353 func TestHandleChatSend(t *testing.T) {
355 cc *hotline.ClientConn
356 t hotline.Transaction
361 want []hotline.Transaction
364 name: "sends chat msg transaction to all clients",
366 cc: &hotline.ClientConn{
367 Account: &hotline.Account{
368 Access: func() hotline.AccessBitmap {
369 var bits hotline.AccessBitmap
370 bits.Set(hotline.AccessSendChat)
374 UserName: []byte{0x00, 0x01},
375 Server: &hotline.Server{
376 ClientMgr: func() *hotline.MockClientMgr {
377 m := hotline.MockClientMgr{}
378 m.On("List").Return([]*hotline.ClientConn{
380 Account: &hotline.Account{
381 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
386 Account: &hotline.Account{
387 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
397 t: hotline.Transaction{
398 Fields: []hotline.Field{
399 hotline.NewField(hotline.FieldData, []byte("hai")),
403 want: []hotline.Transaction{
405 ClientID: [2]byte{0, 1},
408 Type: [2]byte{0, 0x6a},
409 Fields: []hotline.Field{
410 hotline.NewField(hotline.FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
414 ClientID: [2]byte{0, 2},
417 Type: [2]byte{0, 0x6a},
418 Fields: []hotline.Field{
419 hotline.NewField(hotline.FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
425 name: "treats Chat Type 00 00 00 00 as a public chat message",
427 cc: &hotline.ClientConn{
428 Account: &hotline.Account{
429 Access: func() hotline.AccessBitmap {
430 var bits hotline.AccessBitmap
431 bits.Set(hotline.AccessSendChat)
435 UserName: []byte{0x00, 0x01},
436 Server: &hotline.Server{
437 ClientMgr: func() *hotline.MockClientMgr {
438 m := hotline.MockClientMgr{}
439 m.On("List").Return([]*hotline.ClientConn{
441 Account: &hotline.Account{
442 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
447 Account: &hotline.Account{
448 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
458 t: hotline.Transaction{
459 Fields: []hotline.Field{
460 hotline.NewField(hotline.FieldData, []byte("hai")),
461 hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 0}),
465 want: []hotline.Transaction{
467 ClientID: [2]byte{0, 1},
468 Type: [2]byte{0, 0x6a},
469 Fields: []hotline.Field{
470 hotline.NewField(hotline.FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
474 ClientID: [2]byte{0, 2},
475 Type: [2]byte{0, 0x6a},
476 Fields: []hotline.Field{
477 hotline.NewField(hotline.FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
483 name: "when user does not have required permission",
485 cc: &hotline.ClientConn{
486 Account: &hotline.Account{
487 Access: func() hotline.AccessBitmap {
488 var bits hotline.AccessBitmap
492 Server: &hotline.Server{
493 //Accounts: map[string]*Account{},
496 t: hotline.NewTransaction(
497 hotline.TranChatSend, [2]byte{0, 1},
498 hotline.NewField(hotline.FieldData, []byte("hai")),
501 want: []hotline.Transaction{
504 ErrorCode: [4]byte{0, 0, 0, 1},
505 Fields: []hotline.Field{
506 hotline.NewField(hotline.FieldError, []byte("You are not allowed to participate in chat.")),
512 name: "sends chat msg as emote if FieldChatOptions is set to 1",
514 cc: &hotline.ClientConn{
515 Account: &hotline.Account{
516 Access: func() hotline.AccessBitmap {
517 var bits hotline.AccessBitmap
518 bits.Set(hotline.AccessSendChat)
522 UserName: []byte("Testy McTest"),
523 Server: &hotline.Server{
524 ClientMgr: func() *hotline.MockClientMgr {
525 m := hotline.MockClientMgr{}
526 m.On("List").Return([]*hotline.ClientConn{
528 Account: &hotline.Account{
529 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
534 Account: &hotline.Account{
535 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
545 t: hotline.Transaction{
546 Fields: []hotline.Field{
547 hotline.NewField(hotline.FieldData, []byte("performed action")),
548 hotline.NewField(hotline.FieldChatOptions, []byte{0x00, 0x01}),
552 want: []hotline.Transaction{
554 ClientID: [2]byte{0, 1},
557 Type: [2]byte{0, 0x6a},
558 Fields: []hotline.Field{
559 hotline.NewField(hotline.FieldData, []byte("\r*** Testy McTest performed action")),
563 ClientID: [2]byte{0, 2},
566 Type: [2]byte{0, 0x6a},
567 Fields: []hotline.Field{
568 hotline.NewField(hotline.FieldData, []byte("\r*** Testy McTest performed action")),
574 name: "does not send chat msg as emote if FieldChatOptions is set to 0",
576 cc: &hotline.ClientConn{
577 Account: &hotline.Account{
578 Access: func() hotline.AccessBitmap {
579 var bits hotline.AccessBitmap
580 bits.Set(hotline.AccessSendChat)
584 UserName: []byte("Testy McTest"),
585 Server: &hotline.Server{
586 ClientMgr: func() *hotline.MockClientMgr {
587 m := hotline.MockClientMgr{}
588 m.On("List").Return([]*hotline.ClientConn{
590 Account: &hotline.Account{
591 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
596 Account: &hotline.Account{
597 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
607 t: hotline.Transaction{
608 Fields: []hotline.Field{
609 hotline.NewField(hotline.FieldData, []byte("hello")),
610 hotline.NewField(hotline.FieldChatOptions, []byte{0x00, 0x00}),
614 want: []hotline.Transaction{
616 ClientID: [2]byte{0, 1},
617 Type: [2]byte{0, 0x6a},
618 Fields: []hotline.Field{
619 hotline.NewField(hotline.FieldData, []byte("\r Testy McTest: hello")),
623 ClientID: [2]byte{0, 2},
624 Type: [2]byte{0, 0x6a},
625 Fields: []hotline.Field{
626 hotline.NewField(hotline.FieldData, []byte("\r Testy McTest: hello")),
632 name: "only sends chat msg to clients with AccessReadChat permission",
634 cc: &hotline.ClientConn{
635 Account: &hotline.Account{
636 Access: func() hotline.AccessBitmap {
637 var bits hotline.AccessBitmap
638 bits.Set(hotline.AccessSendChat)
642 UserName: []byte{0x00, 0x01},
643 Server: &hotline.Server{
644 ClientMgr: func() *hotline.MockClientMgr {
645 m := hotline.MockClientMgr{}
646 m.On("List").Return([]*hotline.ClientConn{
648 Account: &hotline.Account{
649 Access: func() hotline.AccessBitmap {
650 var bits hotline.AccessBitmap
651 bits.Set(hotline.AccessReadChat)
658 Account: &hotline.Account{},
667 t: hotline.Transaction{
668 Fields: []hotline.Field{
669 hotline.NewField(hotline.FieldData, []byte("hai")),
673 want: []hotline.Transaction{
675 ClientID: [2]byte{0, 1},
676 Type: [2]byte{0, 0x6a},
677 Fields: []hotline.Field{
678 hotline.NewField(hotline.FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
684 name: "only sends private chat msg to members of private chat",
686 cc: &hotline.ClientConn{
687 Account: &hotline.Account{
688 Access: func() hotline.AccessBitmap {
689 var bits hotline.AccessBitmap
690 bits.Set(hotline.AccessSendChat)
694 UserName: []byte{0x00, 0x01},
695 Server: &hotline.Server{
696 ChatMgr: func() *hotline.MockChatManager {
697 m := hotline.MockChatManager{}
698 m.On("Members", hotline.ChatID{0x0, 0x0, 0x0, 0x1}).Return([]*hotline.ClientConn{
706 m.On("GetSubject").Return("unset")
709 ClientMgr: func() *hotline.MockClientMgr {
710 m := hotline.MockClientMgr{}
711 m.On("List").Return([]*hotline.ClientConn{
713 Account: &hotline.Account{
714 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
719 Account: &hotline.Account{
720 Access: hotline.AccessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
725 Account: &hotline.Account{
726 Access: hotline.AccessBitmap{0, 0, 0, 0, 0, 0, 0, 0},
736 t: hotline.Transaction{
737 Fields: []hotline.Field{
738 hotline.NewField(hotline.FieldData, []byte("hai")),
739 hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1}),
743 want: []hotline.Transaction{
745 ClientID: [2]byte{0, 1},
746 Type: [2]byte{0, 0x6a},
747 Fields: []hotline.Field{
748 hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1}),
749 hotline.NewField(hotline.FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
753 ClientID: [2]byte{0, 2},
754 Type: [2]byte{0, 0x6a},
755 Fields: []hotline.Field{
756 hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1}),
757 hotline.NewField(hotline.FieldData, []byte{0x0d, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x3a, 0x20, 0x20, 0x68, 0x61, 0x69}),
763 for _, tt := range tests {
764 t.Run(tt.name, func(t *testing.T) {
765 got := HandleChatSend(tt.args.cc, &tt.args.t)
766 TranAssertEqual(t, tt.want, got)
771 func TestHandleGetFileInfo(t *testing.T) {
773 cc *hotline.ClientConn
774 t hotline.Transaction
779 wantRes []hotline.Transaction
782 name: "returns expected fields when a valid file is requested",
784 cc: &hotline.ClientConn{
786 Account: &hotline.Account{},
787 Server: &hotline.Server{
788 FS: &hotline.OSFileStore{},
789 Config: hotline.Config{
790 FileRoot: func() string {
791 path, _ := os.Getwd()
792 return filepath.Join(path, "/test/config/Files")
797 t: hotline.NewTransaction(
798 hotline.TranGetFileInfo, [2]byte{},
799 hotline.NewField(hotline.FieldFileName, []byte("testfile.txt")),
800 hotline.NewField(hotline.FieldFilePath, []byte{0x00, 0x00}),
803 wantRes: []hotline.Transaction{
805 ClientID: [2]byte{0, 1},
808 Fields: []hotline.Field{
809 hotline.NewField(hotline.FieldFileName, []byte("testfile.txt")),
810 hotline.NewField(hotline.FieldFileTypeString, []byte("Text File")),
811 hotline.NewField(hotline.FieldFileCreatorString, []byte("ttxt")),
812 hotline.NewField(hotline.FieldFileType, []byte("TEXT")),
813 hotline.NewField(hotline.FieldFileCreateDate, make([]byte, 8)),
814 hotline.NewField(hotline.FieldFileModifyDate, make([]byte, 8)),
815 hotline.NewField(hotline.FieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
821 for _, tt := range tests {
822 t.Run(tt.name, func(t *testing.T) {
823 gotRes := HandleGetFileInfo(tt.args.cc, &tt.args.t)
825 // Clear the file timestamp fields to work around problems running the tests in multiple timezones
826 // TODO: revisit how to test this by mocking the stat calls
827 gotRes[0].Fields[4].Data = make([]byte, 8)
828 gotRes[0].Fields[5].Data = make([]byte, 8)
830 if !TranAssertEqual(t, tt.wantRes, gotRes) {
831 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
837 func TestHandleNewFolder(t *testing.T) {
839 cc *hotline.ClientConn
840 t hotline.Transaction
845 wantRes []hotline.Transaction
848 name: "without required permission",
850 cc: &hotline.ClientConn{
851 Account: &hotline.Account{
852 Access: func() hotline.AccessBitmap {
853 var bits hotline.AccessBitmap
858 t: hotline.NewTransaction(
859 hotline.TranNewFolder,
863 wantRes: []hotline.Transaction{
866 ErrorCode: [4]byte{0, 0, 0, 1},
867 Fields: []hotline.Field{
868 hotline.NewField(hotline.FieldError, []byte("You are not allowed to create folders.")),
874 name: "when path is nested",
876 cc: &hotline.ClientConn{
877 Account: &hotline.Account{
878 Access: func() hotline.AccessBitmap {
879 var bits hotline.AccessBitmap
880 bits.Set(hotline.AccessCreateFolder)
885 Server: &hotline.Server{
886 Config: hotline.Config{
889 FS: func() *hotline.MockFileStore {
890 mfs := &hotline.MockFileStore{}
891 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
892 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
897 t: hotline.NewTransaction(
898 hotline.TranNewFolder, [2]byte{0, 1},
899 hotline.NewField(hotline.FieldFileName, []byte("testFolder")),
900 hotline.NewField(hotline.FieldFilePath, []byte{
908 wantRes: []hotline.Transaction{
910 ClientID: [2]byte{0, 1},
916 name: "when path is not nested",
918 cc: &hotline.ClientConn{
919 Account: &hotline.Account{
920 Access: func() hotline.AccessBitmap {
921 var bits hotline.AccessBitmap
922 bits.Set(hotline.AccessCreateFolder)
927 Server: &hotline.Server{
928 Config: hotline.Config{
931 FS: func() *hotline.MockFileStore {
932 mfs := &hotline.MockFileStore{}
933 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
934 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
939 t: hotline.NewTransaction(
940 hotline.TranNewFolder, [2]byte{0, 1},
941 hotline.NewField(hotline.FieldFileName, []byte("testFolder")),
944 wantRes: []hotline.Transaction{
946 ClientID: [2]byte{0, 1},
952 name: "when Write returns an err",
954 cc: &hotline.ClientConn{
955 Account: &hotline.Account{
956 Access: func() hotline.AccessBitmap {
957 var bits hotline.AccessBitmap
958 bits.Set(hotline.AccessCreateFolder)
963 Server: &hotline.Server{
964 Config: hotline.Config{
967 FS: func() *hotline.MockFileStore {
968 mfs := &hotline.MockFileStore{}
969 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
970 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
975 t: hotline.NewTransaction(
976 hotline.TranNewFolder, [2]byte{0, 1},
977 hotline.NewField(hotline.FieldFileName, []byte("testFolder")),
978 hotline.NewField(hotline.FieldFilePath, []byte{
983 wantRes: []hotline.Transaction{},
986 name: "FieldFileName does not allow directory traversal",
988 cc: &hotline.ClientConn{
989 Account: &hotline.Account{
990 Access: func() hotline.AccessBitmap {
991 var bits hotline.AccessBitmap
992 bits.Set(hotline.AccessCreateFolder)
997 Server: &hotline.Server{
998 Config: hotline.Config{
1001 FS: func() *hotline.MockFileStore {
1002 mfs := &hotline.MockFileStore{}
1003 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
1004 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
1009 t: hotline.NewTransaction(
1010 hotline.TranNewFolder, [2]byte{0, 1},
1011 hotline.NewField(hotline.FieldFileName, []byte("../../testFolder")),
1014 wantRes: []hotline.Transaction{
1016 ClientID: [2]byte{0, 1},
1022 name: "FieldFilePath does not allow directory traversal",
1024 cc: &hotline.ClientConn{
1025 Account: &hotline.Account{
1026 Access: func() hotline.AccessBitmap {
1027 var bits hotline.AccessBitmap
1028 bits.Set(hotline.AccessCreateFolder)
1033 Server: &hotline.Server{
1034 Config: hotline.Config{
1035 FileRoot: "/Files/",
1037 FS: func() *hotline.MockFileStore {
1038 mfs := &hotline.MockFileStore{}
1039 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
1040 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
1045 t: hotline.NewTransaction(
1046 hotline.TranNewFolder, [2]byte{0, 1},
1047 hotline.NewField(hotline.FieldFileName, []byte("testFolder")),
1048 hotline.NewField(hotline.FieldFilePath, []byte{
1059 wantRes: []hotline.Transaction{
1061 ClientID: [2]byte{0, 1},
1067 for _, tt := range tests {
1068 t.Run(tt.name, func(t *testing.T) {
1069 gotRes := HandleNewFolder(tt.args.cc, &tt.args.t)
1071 if !TranAssertEqual(t, tt.wantRes, gotRes) {
1072 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
1078 func TestHandleUploadFile(t *testing.T) {
1080 cc *hotline.ClientConn
1081 t hotline.Transaction
1086 wantRes []hotline.Transaction
1089 name: "when request is valid and user has Upload Anywhere permission",
1091 cc: &hotline.ClientConn{
1092 Server: &hotline.Server{
1093 FS: &hotline.OSFileStore{},
1094 FileTransferMgr: hotline.NewMemFileTransferMgr(),
1095 Config: hotline.Config{
1096 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1098 ClientFileTransferMgr: hotline.NewClientFileTransferMgr(),
1099 Account: &hotline.Account{
1100 Access: func() hotline.AccessBitmap {
1101 var bits hotline.AccessBitmap
1102 bits.Set(hotline.AccessUploadFile)
1103 bits.Set(hotline.AccessUploadAnywhere)
1108 t: hotline.NewTransaction(
1109 hotline.TranUploadFile, [2]byte{0, 1},
1110 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1111 hotline.NewField(hotline.FieldFilePath, []byte{
1119 wantRes: []hotline.Transaction{
1122 Fields: []hotline.Field{
1123 hotline.NewField(hotline.FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
1129 name: "when user does not have required access",
1131 cc: &hotline.ClientConn{
1132 Account: &hotline.Account{
1133 Access: func() hotline.AccessBitmap {
1134 var bits hotline.AccessBitmap
1139 t: hotline.NewTransaction(
1140 hotline.TranUploadFile, [2]byte{0, 1},
1141 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1142 hotline.NewField(hotline.FieldFilePath, []byte{
1150 wantRes: []hotline.Transaction{
1153 ErrorCode: [4]byte{0, 0, 0, 1},
1154 Fields: []hotline.Field{
1155 hotline.NewField(hotline.FieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
1161 for _, tt := range tests {
1162 t.Run(tt.name, func(t *testing.T) {
1163 gotRes := HandleUploadFile(tt.args.cc, &tt.args.t)
1164 TranAssertEqual(t, tt.wantRes, gotRes)
1169 func TestHandleMakeAlias(t *testing.T) {
1171 cc *hotline.ClientConn
1172 t hotline.Transaction
1177 wantRes []hotline.Transaction
1180 name: "with valid input and required permissions",
1182 cc: &hotline.ClientConn{
1183 Logger: NewTestLogger(),
1184 Account: &hotline.Account{
1185 Access: func() hotline.AccessBitmap {
1186 var bits hotline.AccessBitmap
1187 bits.Set(hotline.AccessMakeAlias)
1191 Server: &hotline.Server{
1192 Config: hotline.Config{
1193 FileRoot: func() string {
1194 path, _ := os.Getwd()
1195 return path + "/test/config/Files"
1198 Logger: NewTestLogger(),
1199 FS: func() *hotline.MockFileStore {
1200 mfs := &hotline.MockFileStore{}
1201 path, _ := os.Getwd()
1204 path+"/test/config/Files/foo/testFile",
1205 path+"/test/config/Files/bar/testFile",
1211 t: hotline.NewTransaction(
1212 hotline.TranMakeFileAlias, [2]byte{0, 1},
1213 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1214 hotline.NewField(hotline.FieldFilePath, hotline.EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1215 hotline.NewField(hotline.FieldFileNewPath, hotline.EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1218 wantRes: []hotline.Transaction{
1221 Fields: []hotline.Field(nil),
1226 name: "when symlink returns an error",
1228 cc: &hotline.ClientConn{
1229 Logger: NewTestLogger(),
1230 Account: &hotline.Account{
1231 Access: func() hotline.AccessBitmap {
1232 var bits hotline.AccessBitmap
1233 bits.Set(hotline.AccessMakeAlias)
1237 Server: &hotline.Server{
1238 Config: hotline.Config{
1239 FileRoot: func() string {
1240 path, _ := os.Getwd()
1241 return path + "/test/config/Files"
1244 Logger: NewTestLogger(),
1245 FS: func() *hotline.MockFileStore {
1246 mfs := &hotline.MockFileStore{}
1247 path, _ := os.Getwd()
1250 path+"/test/config/Files/foo/testFile",
1251 path+"/test/config/Files/bar/testFile",
1252 ).Return(errors.New("ohno"))
1257 t: hotline.NewTransaction(
1258 hotline.TranMakeFileAlias, [2]byte{0, 1},
1259 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1260 hotline.NewField(hotline.FieldFilePath, hotline.EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1261 hotline.NewField(hotline.FieldFileNewPath, hotline.EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1264 wantRes: []hotline.Transaction{
1267 ErrorCode: [4]byte{0, 0, 0, 1},
1268 Fields: []hotline.Field{
1269 hotline.NewField(hotline.FieldError, []byte("Error creating alias")),
1275 name: "when user does not have required permission",
1277 cc: &hotline.ClientConn{
1278 Logger: NewTestLogger(),
1279 Account: &hotline.Account{
1280 Access: hotline.AccessBitmap{},
1282 Server: &hotline.Server{
1283 Config: hotline.Config{
1284 FileRoot: func() string {
1285 path, _ := os.Getwd()
1286 return path + "/test/config/Files"
1291 t: hotline.NewTransaction(
1292 hotline.TranMakeFileAlias, [2]byte{0, 1},
1293 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1294 hotline.NewField(hotline.FieldFilePath, []byte{
1300 hotline.NewField(hotline.FieldFileNewPath, []byte{
1308 wantRes: []hotline.Transaction{
1311 ErrorCode: [4]byte{0, 0, 0, 1},
1312 Fields: []hotline.Field{
1313 hotline.NewField(hotline.FieldError, []byte("You are not allowed to make aliases.")),
1319 for _, tt := range tests {
1320 t.Run(tt.name, func(t *testing.T) {
1321 gotRes := HandleMakeAlias(tt.args.cc, &tt.args.t)
1322 TranAssertEqual(t, tt.wantRes, gotRes)
1327 func TestHandleGetUser(t *testing.T) {
1329 cc *hotline.ClientConn
1330 t hotline.Transaction
1335 wantRes []hotline.Transaction
1338 name: "when account is valid",
1340 cc: &hotline.ClientConn{
1341 Account: &hotline.Account{
1342 Access: func() hotline.AccessBitmap {
1343 var bits hotline.AccessBitmap
1344 bits.Set(hotline.AccessOpenUser)
1348 Server: &hotline.Server{
1349 AccountManager: func() *MockAccountManager {
1350 m := MockAccountManager{}
1351 m.On("Get", "guest").Return(&hotline.Account{
1354 Password: "password",
1355 Access: hotline.AccessBitmap{},
1361 t: hotline.NewTransaction(
1362 hotline.TranGetUser, [2]byte{0, 1},
1363 hotline.NewField(hotline.FieldUserLogin, []byte("guest")),
1366 wantRes: []hotline.Transaction{
1369 Fields: []hotline.Field{
1370 hotline.NewField(hotline.FieldUserName, []byte("Guest")),
1371 hotline.NewField(hotline.FieldUserLogin, hotline.EncodeString([]byte("guest"))),
1372 hotline.NewField(hotline.FieldUserPassword, []byte("password")),
1373 hotline.NewField(hotline.FieldUserAccess, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
1379 name: "when user does not have required permission",
1381 cc: &hotline.ClientConn{
1382 Account: &hotline.Account{
1383 Access: func() hotline.AccessBitmap {
1384 var bits hotline.AccessBitmap
1388 Server: &hotline.Server{
1389 //Accounts: map[string]*Account{},
1392 t: hotline.NewTransaction(
1393 hotline.TranGetUser, [2]byte{0, 1},
1394 hotline.NewField(hotline.FieldUserLogin, []byte("nonExistentUser")),
1397 wantRes: []hotline.Transaction{
1400 ErrorCode: [4]byte{0, 0, 0, 1},
1401 Fields: []hotline.Field{
1402 hotline.NewField(hotline.FieldError, []byte("You are not allowed to view accounts.")),
1408 name: "when account does not exist",
1410 cc: &hotline.ClientConn{
1411 Account: &hotline.Account{
1412 Access: func() hotline.AccessBitmap {
1413 var bits hotline.AccessBitmap
1414 bits.Set(hotline.AccessOpenUser)
1418 Server: &hotline.Server{
1419 AccountManager: func() *MockAccountManager {
1420 m := MockAccountManager{}
1421 m.On("Get", "nonExistentUser").Return((*hotline.Account)(nil))
1426 t: hotline.NewTransaction(
1427 hotline.TranGetUser, [2]byte{0, 1},
1428 hotline.NewField(hotline.FieldUserLogin, []byte("nonExistentUser")),
1431 wantRes: []hotline.Transaction{
1435 Type: [2]byte{0, 0},
1436 ErrorCode: [4]byte{0, 0, 0, 1},
1437 Fields: []hotline.Field{
1438 hotline.NewField(hotline.FieldError, []byte("Account does not exist.")),
1444 for _, tt := range tests {
1445 t.Run(tt.name, func(t *testing.T) {
1446 gotRes := HandleGetUser(tt.args.cc, &tt.args.t)
1447 TranAssertEqual(t, tt.wantRes, gotRes)
1452 func TestHandleDeleteUser(t *testing.T) {
1454 cc *hotline.ClientConn
1455 t hotline.Transaction
1460 wantRes []hotline.Transaction
1463 name: "when user exists",
1465 cc: &hotline.ClientConn{
1466 Account: &hotline.Account{
1467 Access: func() hotline.AccessBitmap {
1468 var bits hotline.AccessBitmap
1469 bits.Set(hotline.AccessDeleteUser)
1473 Server: &hotline.Server{
1474 AccountManager: func() *MockAccountManager {
1475 m := MockAccountManager{}
1476 m.On("Delete", "testuser").Return(nil)
1479 ClientMgr: func() *hotline.MockClientMgr {
1480 m := hotline.MockClientMgr{}
1481 m.On("List").Return([]*hotline.ClientConn{}) // TODO
1486 t: hotline.NewTransaction(
1487 hotline.TranDeleteUser, [2]byte{0, 1},
1488 hotline.NewField(hotline.FieldUserLogin, hotline.EncodeString([]byte("testuser"))),
1491 wantRes: []hotline.Transaction{
1495 Type: [2]byte{0, 0},
1496 Fields: []hotline.Field(nil),
1501 name: "when user does not have required permission",
1503 cc: &hotline.ClientConn{
1504 Account: &hotline.Account{
1505 Access: hotline.AccessBitmap{},
1507 Server: &hotline.Server{
1508 //Accounts: map[string]*Account{},
1511 t: hotline.NewTransaction(
1512 hotline.TranDeleteUser, [2]byte{0, 1},
1513 hotline.NewField(hotline.FieldUserLogin, hotline.EncodeString([]byte("testuser"))),
1516 wantRes: []hotline.Transaction{
1519 ErrorCode: [4]byte{0, 0, 0, 1},
1520 Fields: []hotline.Field{
1521 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete accounts.")),
1527 for _, tt := range tests {
1528 t.Run(tt.name, func(t *testing.T) {
1529 gotRes := HandleDeleteUser(tt.args.cc, &tt.args.t)
1530 TranAssertEqual(t, tt.wantRes, gotRes)
1535 func TestHandleGetMsgs(t *testing.T) {
1537 cc *hotline.ClientConn
1538 t hotline.Transaction
1543 wantRes []hotline.Transaction
1546 name: "returns news data",
1548 cc: &hotline.ClientConn{
1549 Account: &hotline.Account{
1550 Access: func() hotline.AccessBitmap {
1551 var bits hotline.AccessBitmap
1552 bits.Set(hotline.AccessNewsReadArt)
1556 Server: &hotline.Server{
1557 MessageBoard: func() *mockReadWriteSeeker {
1558 m := mockReadWriteSeeker{}
1559 m.On("Seek", int64(0), 0).Return(int64(0), nil)
1560 m.On("Read", mock.AnythingOfType("[]uint8")).Run(func(args mock.Arguments) {
1561 arg := args.Get(0).([]uint8)
1563 }).Return(4, io.EOF)
1568 t: hotline.NewTransaction(
1569 hotline.TranGetMsgs, [2]byte{0, 1},
1572 wantRes: []hotline.Transaction{
1575 Fields: []hotline.Field{
1576 hotline.NewField(hotline.FieldData, []byte("TEST")),
1582 name: "when user does not have required permission",
1584 cc: &hotline.ClientConn{
1585 Account: &hotline.Account{
1586 Access: hotline.AccessBitmap{},
1588 Server: &hotline.Server{
1589 //Accounts: map[string]*Account{},
1592 t: hotline.NewTransaction(
1593 hotline.TranGetMsgs, [2]byte{0, 1},
1596 wantRes: []hotline.Transaction{
1599 ErrorCode: [4]byte{0, 0, 0, 1},
1600 Fields: []hotline.Field{
1601 hotline.NewField(hotline.FieldError, []byte("You are not allowed to read news.")),
1607 for _, tt := range tests {
1608 t.Run(tt.name, func(t *testing.T) {
1609 gotRes := HandleGetMsgs(tt.args.cc, &tt.args.t)
1610 TranAssertEqual(t, tt.wantRes, gotRes)
1615 func TestHandleNewUser(t *testing.T) {
1617 cc *hotline.ClientConn
1618 t hotline.Transaction
1623 wantRes []hotline.Transaction
1626 name: "when user does not have required permission",
1628 cc: &hotline.ClientConn{
1629 Account: &hotline.Account{
1630 Access: func() hotline.AccessBitmap {
1631 var bits hotline.AccessBitmap
1635 Server: &hotline.Server{
1636 //Accounts: map[string]*Account{},
1639 t: hotline.NewTransaction(
1640 hotline.TranNewUser, [2]byte{0, 1},
1643 wantRes: []hotline.Transaction{
1646 ErrorCode: [4]byte{0, 0, 0, 1},
1647 Fields: []hotline.Field{
1648 hotline.NewField(hotline.FieldError, []byte("You are not allowed to create new accounts.")),
1654 name: "when user attempts to create account with greater access",
1656 cc: &hotline.ClientConn{
1657 Account: &hotline.Account{
1658 Access: func() hotline.AccessBitmap {
1659 var bits hotline.AccessBitmap
1660 bits.Set(hotline.AccessCreateUser)
1664 Server: &hotline.Server{
1665 AccountManager: func() *MockAccountManager {
1666 m := MockAccountManager{}
1667 m.On("Get", "userB").Return((*hotline.Account)(nil))
1672 t: hotline.NewTransaction(
1673 hotline.TranNewUser, [2]byte{0, 1},
1674 hotline.NewField(hotline.FieldUserLogin, hotline.EncodeString([]byte("userB"))),
1676 hotline.FieldUserAccess,
1678 var bits hotline.AccessBitmap
1679 bits.Set(hotline.AccessDisconUser)
1685 wantRes: []hotline.Transaction{
1688 ErrorCode: [4]byte{0, 0, 0, 1},
1689 Fields: []hotline.Field{
1690 hotline.NewField(hotline.FieldError, []byte("Cannot create account with more access than yourself.")),
1696 for _, tt := range tests {
1697 t.Run(tt.name, func(t *testing.T) {
1698 gotRes := HandleNewUser(tt.args.cc, &tt.args.t)
1699 TranAssertEqual(t, tt.wantRes, gotRes)
1704 func TestHandleListUsers(t *testing.T) {
1706 cc *hotline.ClientConn
1707 t hotline.Transaction
1712 wantRes []hotline.Transaction
1715 name: "when user does not have required permission",
1717 cc: &hotline.ClientConn{
1718 Account: &hotline.Account{
1719 Access: func() hotline.AccessBitmap {
1720 var bits hotline.AccessBitmap
1724 Server: &hotline.Server{
1725 //Accounts: map[string]*Account{},
1728 t: hotline.NewTransaction(
1729 hotline.TranNewUser, [2]byte{0, 1},
1732 wantRes: []hotline.Transaction{
1735 ErrorCode: [4]byte{0, 0, 0, 1},
1736 Fields: []hotline.Field{
1737 hotline.NewField(hotline.FieldError, []byte("You are not allowed to view accounts.")),
1743 name: "when user has required permission",
1745 cc: &hotline.ClientConn{
1746 Account: &hotline.Account{
1747 Access: func() hotline.AccessBitmap {
1748 var bits hotline.AccessBitmap
1749 bits.Set(hotline.AccessOpenUser)
1753 Server: &hotline.Server{
1754 AccountManager: func() *MockAccountManager {
1755 m := MockAccountManager{}
1756 m.On("List").Return([]hotline.Account{
1761 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
1768 t: hotline.NewTransaction(
1769 hotline.TranGetClientInfoText, [2]byte{0, 1},
1770 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
1773 wantRes: []hotline.Transaction{
1776 Fields: []hotline.Field{
1777 hotline.NewField(hotline.FieldData, []byte{
1778 0x00, 0x04, 0x00, 0x66, 0x00, 0x05, 0x67, 0x75, 0x65, 0x73, 0x74, 0x00, 0x69, 0x00, 0x05, 0x98,
1779 0x8a, 0x9a, 0x8c, 0x8b, 0x00, 0x6e, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1780 0x00, 0x6a, 0x00, 0x01, 0x78,
1787 for _, tt := range tests {
1788 t.Run(tt.name, func(t *testing.T) {
1789 gotRes := HandleListUsers(tt.args.cc, &tt.args.t)
1791 TranAssertEqual(t, tt.wantRes, gotRes)
1796 func TestHandleDownloadFile(t *testing.T) {
1798 cc *hotline.ClientConn
1799 t hotline.Transaction
1804 wantRes []hotline.Transaction
1807 name: "when user does not have required permission",
1809 cc: &hotline.ClientConn{
1810 Account: &hotline.Account{
1811 Access: func() hotline.AccessBitmap {
1812 var bits hotline.AccessBitmap
1816 Server: &hotline.Server{},
1818 t: hotline.NewTransaction(hotline.TranDownloadFile, [2]byte{0, 1}),
1820 wantRes: []hotline.Transaction{
1823 ErrorCode: [4]byte{0, 0, 0, 1},
1824 Fields: []hotline.Field{
1825 hotline.NewField(hotline.FieldError, []byte("You are not allowed to download files.")),
1831 name: "with a valid file",
1833 cc: &hotline.ClientConn{
1834 ClientFileTransferMgr: hotline.NewClientFileTransferMgr(),
1835 Account: &hotline.Account{
1836 Access: func() hotline.AccessBitmap {
1837 var bits hotline.AccessBitmap
1838 bits.Set(hotline.AccessDownloadFile)
1842 Server: &hotline.Server{
1843 FS: &hotline.OSFileStore{},
1844 FileTransferMgr: hotline.NewMemFileTransferMgr(),
1845 Config: hotline.Config{
1846 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1850 t: hotline.NewTransaction(
1851 hotline.TranDownloadFile,
1853 hotline.NewField(hotline.FieldFileName, []byte("testfile.txt")),
1854 hotline.NewField(hotline.FieldFilePath, []byte{0x0, 0x00}),
1857 wantRes: []hotline.Transaction{
1860 Fields: []hotline.Field{
1861 hotline.NewField(hotline.FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1862 hotline.NewField(hotline.FieldWaitingCount, []byte{0x00, 0x00}),
1863 hotline.NewField(hotline.FieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1864 hotline.NewField(hotline.FieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
1870 name: "when client requests to resume 1k test file at offset 256",
1872 cc: &hotline.ClientConn{
1873 ClientFileTransferMgr: hotline.NewClientFileTransferMgr(),
1874 Account: &hotline.Account{
1875 Access: func() hotline.AccessBitmap {
1876 var bits hotline.AccessBitmap
1877 bits.Set(hotline.AccessDownloadFile)
1881 Server: &hotline.Server{
1882 FS: &hotline.OSFileStore{},
1884 // FS: func() *hotline.MockFileStore {
1885 // path, _ := os.Getwd()
1886 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1891 // mfi := &hotline.MockFileInfo{}
1892 // mfi.On("Mode").Return(fs.FileMode(0))
1893 // mfs := &MockFileStore{}
1894 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1895 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1896 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
1897 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
1901 FileTransferMgr: hotline.NewMemFileTransferMgr(),
1902 Config: hotline.Config{
1903 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1905 //Accounts: map[string]*Account{},
1908 t: hotline.NewTransaction(
1909 hotline.TranDownloadFile,
1911 hotline.NewField(hotline.FieldFileName, []byte("testfile-1k")),
1912 hotline.NewField(hotline.FieldFilePath, []byte{0x00, 0x00}),
1914 hotline.FieldFileResumeData,
1916 frd := hotline.FileResumeData{
1917 ForkCount: [2]byte{0, 2},
1918 ForkInfoList: []hotline.ForkInfoList{
1920 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
1921 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
1924 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
1925 DataSize: [4]byte{0, 0, 0, 0},
1929 b, _ := frd.BinaryMarshal()
1935 wantRes: []hotline.Transaction{
1938 Fields: []hotline.Field{
1939 hotline.NewField(hotline.FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1940 hotline.NewField(hotline.FieldWaitingCount, []byte{0x00, 0x00}),
1941 hotline.NewField(hotline.FieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
1942 hotline.NewField(hotline.FieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
1948 for _, tt := range tests {
1949 t.Run(tt.name, func(t *testing.T) {
1950 gotRes := HandleDownloadFile(tt.args.cc, &tt.args.t)
1951 TranAssertEqual(t, tt.wantRes, gotRes)
1956 func TestHandleUpdateUser(t *testing.T) {
1958 cc *hotline.ClientConn
1959 t hotline.Transaction
1964 wantRes []hotline.Transaction
1967 name: "when action is create user without required permission",
1969 cc: &hotline.ClientConn{
1970 Logger: NewTestLogger(),
1971 Server: &hotline.Server{
1972 AccountManager: func() *MockAccountManager {
1973 m := MockAccountManager{}
1974 m.On("Get", "bbb").Return((*hotline.Account)(nil))
1977 Logger: NewTestLogger(),
1979 Account: &hotline.Account{
1980 Access: hotline.AccessBitmap{},
1983 t: hotline.NewTransaction(
1984 hotline.TranUpdateUser,
1986 hotline.NewField(hotline.FieldData, []byte{
1987 0x00, 0x04, // field count
1989 0x00, 0x69, // FieldUserLogin = 105
1993 0x00, 0x6a, // FieldUserPassword = 106
1997 0x00, 0x66, // FieldUserName = 102
2001 0x00, 0x6e, // FieldUserAccess = 110
2003 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2007 wantRes: []hotline.Transaction{
2010 ErrorCode: [4]byte{0, 0, 0, 1},
2011 Fields: []hotline.Field{
2012 hotline.NewField(hotline.FieldError, []byte("You are not allowed to create new accounts.")),
2018 name: "when action is modify user without required permission",
2020 cc: &hotline.ClientConn{
2021 Logger: NewTestLogger(),
2022 Server: &hotline.Server{
2023 Logger: NewTestLogger(),
2024 AccountManager: func() *MockAccountManager {
2025 m := MockAccountManager{}
2026 m.On("Get", "bbb").Return(&hotline.Account{})
2030 Account: &hotline.Account{
2031 Access: func() hotline.AccessBitmap {
2032 var bits hotline.AccessBitmap
2037 t: hotline.NewTransaction(
2038 hotline.TranUpdateUser,
2040 hotline.NewField(hotline.FieldData, []byte{
2041 0x00, 0x04, // field count
2043 0x00, 0x69, // FieldUserLogin = 105
2047 0x00, 0x6a, // FieldUserPassword = 106
2051 0x00, 0x66, // FieldUserName = 102
2055 0x00, 0x6e, // FieldUserAccess = 110
2057 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2061 wantRes: []hotline.Transaction{
2064 ErrorCode: [4]byte{0, 0, 0, 1},
2065 Fields: []hotline.Field{
2066 hotline.NewField(hotline.FieldError, []byte("You are not allowed to modify accounts.")),
2072 name: "when action is delete user without required permission",
2074 cc: &hotline.ClientConn{
2075 Logger: NewTestLogger(),
2076 Server: &hotline.Server{},
2077 Account: &hotline.Account{
2078 Access: hotline.AccessBitmap{},
2081 t: hotline.NewTransaction(
2082 hotline.TranUpdateUser,
2084 hotline.NewField(hotline.FieldData, []byte{
2092 wantRes: []hotline.Transaction{
2095 ErrorCode: [4]byte{0, 0, 0, 1},
2096 Fields: []hotline.Field{
2097 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete accounts.")),
2103 for _, tt := range tests {
2104 t.Run(tt.name, func(t *testing.T) {
2105 gotRes := HandleUpdateUser(tt.args.cc, &tt.args.t)
2106 TranAssertEqual(t, tt.wantRes, gotRes)
2111 func TestHandleDelNewsArt(t *testing.T) {
2113 cc *hotline.ClientConn
2114 t hotline.Transaction
2119 wantRes []hotline.Transaction
2122 name: "without required permission",
2124 cc: &hotline.ClientConn{
2125 Account: &hotline.Account{
2126 Access: func() hotline.AccessBitmap {
2127 var bits hotline.AccessBitmap
2132 t: hotline.NewTransaction(
2133 hotline.TranDelNewsArt,
2137 wantRes: []hotline.Transaction{
2140 ErrorCode: [4]byte{0, 0, 0, 1},
2141 Fields: []hotline.Field{
2142 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete news articles.")),
2148 for _, tt := range tests {
2149 t.Run(tt.name, func(t *testing.T) {
2150 gotRes := HandleDelNewsArt(tt.args.cc, &tt.args.t)
2151 TranAssertEqual(t, tt.wantRes, gotRes)
2156 func TestHandleDisconnectUser(t *testing.T) {
2158 cc *hotline.ClientConn
2159 t hotline.Transaction
2164 wantRes []hotline.Transaction
2167 name: "without required permission",
2169 cc: &hotline.ClientConn{
2170 Account: &hotline.Account{
2171 Access: func() hotline.AccessBitmap {
2172 var bits hotline.AccessBitmap
2177 t: hotline.NewTransaction(
2178 hotline.TranDelNewsArt,
2182 wantRes: []hotline.Transaction{
2185 ErrorCode: [4]byte{0, 0, 0, 1},
2186 Fields: []hotline.Field{
2187 hotline.NewField(hotline.FieldError, []byte("You are not allowed to disconnect users.")),
2193 name: "when target user has 'cannot be disconnected' priv",
2195 cc: &hotline.ClientConn{
2196 Server: &hotline.Server{
2197 ClientMgr: func() *hotline.MockClientMgr {
2198 m := hotline.MockClientMgr{}
2199 m.On("Get", hotline.ClientID{0x0, 0x1}).Return(&hotline.ClientConn{
2200 Account: &hotline.Account{
2202 Access: func() hotline.AccessBitmap {
2203 var bits hotline.AccessBitmap
2204 bits.Set(hotline.AccessCannotBeDiscon)
2213 Account: &hotline.Account{
2214 Access: func() hotline.AccessBitmap {
2215 var bits hotline.AccessBitmap
2216 bits.Set(hotline.AccessDisconUser)
2221 t: hotline.NewTransaction(
2222 hotline.TranDelNewsArt,
2224 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
2227 wantRes: []hotline.Transaction{
2230 ErrorCode: [4]byte{0, 0, 0, 1},
2231 Fields: []hotline.Field{
2232 hotline.NewField(hotline.FieldError, []byte("unnamed is not allowed to be disconnected.")),
2238 for _, tt := range tests {
2239 t.Run(tt.name, func(t *testing.T) {
2240 gotRes := HandleDisconnectUser(tt.args.cc, &tt.args.t)
2241 TranAssertEqual(t, tt.wantRes, gotRes)
2246 func TestHandleSendInstantMsg(t *testing.T) {
2248 cc *hotline.ClientConn
2249 t hotline.Transaction
2254 wantRes []hotline.Transaction
2257 name: "without required permission",
2259 cc: &hotline.ClientConn{
2260 Account: &hotline.Account{
2261 Access: func() hotline.AccessBitmap {
2262 var bits hotline.AccessBitmap
2267 t: hotline.NewTransaction(
2268 hotline.TranDelNewsArt,
2272 wantRes: []hotline.Transaction{
2275 ErrorCode: [4]byte{0, 0, 0, 1},
2276 Fields: []hotline.Field{
2277 hotline.NewField(hotline.FieldError, []byte("You are not allowed to send private messages.")),
2283 name: "when client 1 sends a message to client 2",
2285 cc: &hotline.ClientConn{
2286 Account: &hotline.Account{
2287 Access: func() hotline.AccessBitmap {
2288 var bits hotline.AccessBitmap
2289 bits.Set(hotline.AccessSendPrivMsg)
2294 UserName: []byte("User1"),
2295 Server: &hotline.Server{
2296 ClientMgr: func() *hotline.MockClientMgr {
2297 m := hotline.MockClientMgr{}
2298 m.On("Get", hotline.ClientID{0x0, 0x2}).Return(&hotline.ClientConn{
2299 AutoReply: []byte(nil),
2300 Flags: [2]byte{0, 0},
2307 t: hotline.NewTransaction(
2308 hotline.TranSendInstantMsg,
2310 hotline.NewField(hotline.FieldData, []byte("hai")),
2311 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2314 wantRes: []hotline.Transaction{
2315 hotline.NewTransaction(
2316 hotline.TranServerMsg,
2318 hotline.NewField(hotline.FieldData, []byte("hai")),
2319 hotline.NewField(hotline.FieldUserName, []byte("User1")),
2320 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
2321 hotline.NewField(hotline.FieldOptions, []byte{0, 1}),
2324 ClientID: [2]byte{0, 1},
2326 Fields: []hotline.Field(nil),
2331 name: "when client 2 has autoreply enabled",
2333 cc: &hotline.ClientConn{
2334 Account: &hotline.Account{
2335 Access: func() hotline.AccessBitmap {
2336 var bits hotline.AccessBitmap
2337 bits.Set(hotline.AccessSendPrivMsg)
2342 UserName: []byte("User1"),
2343 Server: &hotline.Server{
2344 ClientMgr: func() *hotline.MockClientMgr {
2345 m := hotline.MockClientMgr{}
2346 m.On("Get", hotline.ClientID{0x0, 0x2}).Return(&hotline.ClientConn{
2347 Flags: [2]byte{0, 0},
2349 UserName: []byte("User2"),
2350 AutoReply: []byte("autohai"),
2356 t: hotline.NewTransaction(
2357 hotline.TranSendInstantMsg,
2359 hotline.NewField(hotline.FieldData, []byte("hai")),
2360 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2363 wantRes: []hotline.Transaction{
2364 hotline.NewTransaction(
2365 hotline.TranServerMsg,
2367 hotline.NewField(hotline.FieldData, []byte("hai")),
2368 hotline.NewField(hotline.FieldUserName, []byte("User1")),
2369 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
2370 hotline.NewField(hotline.FieldOptions, []byte{0, 1}),
2372 hotline.NewTransaction(
2373 hotline.TranServerMsg,
2375 hotline.NewField(hotline.FieldData, []byte("autohai")),
2376 hotline.NewField(hotline.FieldUserName, []byte("User2")),
2377 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2378 hotline.NewField(hotline.FieldOptions, []byte{0, 1}),
2381 ClientID: [2]byte{0, 1},
2383 Fields: []hotline.Field(nil),
2388 name: "when client 2 has refuse private messages enabled",
2390 cc: &hotline.ClientConn{
2391 Account: &hotline.Account{
2392 Access: func() hotline.AccessBitmap {
2393 var bits hotline.AccessBitmap
2394 bits.Set(hotline.AccessSendPrivMsg)
2399 UserName: []byte("User1"),
2400 Server: &hotline.Server{
2401 ClientMgr: func() *hotline.MockClientMgr {
2402 m := hotline.MockClientMgr{}
2403 m.On("Get", hotline.ClientID{0x0, 0x2}).Return(&hotline.ClientConn{
2404 Flags: [2]byte{255, 255},
2406 UserName: []byte("User2"),
2413 t: hotline.NewTransaction(
2414 hotline.TranSendInstantMsg,
2416 hotline.NewField(hotline.FieldData, []byte("hai")),
2417 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2420 wantRes: []hotline.Transaction{
2421 hotline.NewTransaction(
2422 hotline.TranServerMsg,
2424 hotline.NewField(hotline.FieldData, []byte("User2 does not accept private messages.")),
2425 hotline.NewField(hotline.FieldUserName, []byte("User2")),
2426 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2427 hotline.NewField(hotline.FieldOptions, []byte{0, 2}),
2430 ClientID: [2]byte{0, 1},
2432 Fields: []hotline.Field(nil),
2437 for _, tt := range tests {
2438 t.Run(tt.name, func(t *testing.T) {
2439 gotRes := HandleSendInstantMsg(tt.args.cc, &tt.args.t)
2440 TranAssertEqual(t, tt.wantRes, gotRes)
2445 func TestHandleDeleteFile(t *testing.T) {
2447 cc *hotline.ClientConn
2448 t hotline.Transaction
2453 wantRes []hotline.Transaction
2456 name: "when user does not have required permission to delete a folder",
2458 cc: &hotline.ClientConn{
2459 Account: &hotline.Account{
2460 Access: func() hotline.AccessBitmap {
2461 var bits hotline.AccessBitmap
2465 Server: &hotline.Server{
2466 Config: hotline.Config{
2467 FileRoot: func() string {
2468 return "/fakeRoot/Files"
2471 FS: func() *hotline.MockFileStore {
2472 mfi := &hotline.MockFileInfo{}
2473 mfi.On("Mode").Return(fs.FileMode(0))
2474 mfi.On("Size").Return(int64(100))
2475 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2476 mfi.On("IsDir").Return(false)
2477 mfi.On("Name").Return("testfile")
2479 mfs := &hotline.MockFileStore{}
2480 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2481 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2482 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2486 //Accounts: map[string]*Account{},
2489 t: hotline.NewTransaction(
2490 hotline.TranDeleteFile, [2]byte{0, 1},
2491 hotline.NewField(hotline.FieldFileName, []byte("testfile")),
2492 hotline.NewField(hotline.FieldFilePath, []byte{
2500 wantRes: []hotline.Transaction{
2503 ErrorCode: [4]byte{0, 0, 0, 1},
2504 Fields: []hotline.Field{
2505 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete files.")),
2511 name: "deletes all associated metadata files",
2513 cc: &hotline.ClientConn{
2514 Account: &hotline.Account{
2515 Access: func() hotline.AccessBitmap {
2516 var bits hotline.AccessBitmap
2517 bits.Set(hotline.AccessDeleteFile)
2521 Server: &hotline.Server{
2522 Config: hotline.Config{
2523 FileRoot: func() string {
2524 return "/fakeRoot/Files"
2527 FS: func() *hotline.MockFileStore {
2528 mfi := &hotline.MockFileInfo{}
2529 mfi.On("Mode").Return(fs.FileMode(0))
2530 mfi.On("Size").Return(int64(100))
2531 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2532 mfi.On("IsDir").Return(false)
2533 mfi.On("Name").Return("testfile")
2535 mfs := &hotline.MockFileStore{}
2536 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2537 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2538 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2540 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2541 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2542 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2543 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2547 //Accounts: map[string]*Account{},
2550 t: hotline.NewTransaction(
2551 hotline.TranDeleteFile, [2]byte{0, 1},
2552 hotline.NewField(hotline.FieldFileName, []byte("testfile")),
2553 hotline.NewField(hotline.FieldFilePath, []byte{
2561 wantRes: []hotline.Transaction{
2564 Fields: []hotline.Field(nil),
2569 for _, tt := range tests {
2570 t.Run(tt.name, func(t *testing.T) {
2571 gotRes := HandleDeleteFile(tt.args.cc, &tt.args.t)
2572 TranAssertEqual(t, tt.wantRes, gotRes)
2574 tt.args.cc.Server.FS.(*hotline.MockFileStore).AssertExpectations(t)
2579 func TestHandleGetFileNameList(t *testing.T) {
2581 cc *hotline.ClientConn
2582 t hotline.Transaction
2587 wantRes []hotline.Transaction
2590 name: "when FieldFilePath is a drop box, but user does not have AccessViewDropBoxes ",
2592 cc: &hotline.ClientConn{
2593 Account: &hotline.Account{
2594 Access: func() hotline.AccessBitmap {
2595 var bits hotline.AccessBitmap
2599 Server: &hotline.Server{
2601 Config: hotline.Config{
2602 FileRoot: func() string {
2603 path, _ := os.Getwd()
2604 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2609 t: hotline.NewTransaction(
2610 hotline.TranGetFileNameList, [2]byte{0, 1},
2611 hotline.NewField(hotline.FieldFilePath, []byte{
2615 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2619 wantRes: []hotline.Transaction{
2622 ErrorCode: [4]byte{0, 0, 0, 1},
2623 Fields: []hotline.Field{
2624 hotline.NewField(hotline.FieldError, []byte("You are not allowed to view drop boxes.")),
2630 name: "with file root",
2632 cc: &hotline.ClientConn{
2633 Account: &hotline.Account{
2634 FileRoot: func() string {
2635 path, _ := os.Getwd()
2636 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2639 Server: &hotline.Server{},
2641 t: hotline.NewTransaction(
2642 hotline.TranGetFileNameList, [2]byte{0, 1},
2643 hotline.NewField(hotline.FieldFilePath, []byte{
2649 wantRes: []hotline.Transaction{
2652 Fields: []hotline.Field{
2654 hotline.FieldFileNameWithInfo,
2656 fnwi := hotline.FileNameWithInfo{
2657 FileNameWithInfoHeader: hotline.FileNameWithInfoHeader{
2658 Type: [4]byte{0x54, 0x45, 0x58, 0x54},
2659 Creator: [4]byte{0x54, 0x54, 0x58, 0x54},
2660 FileSize: [4]byte{0, 0, 0x04, 0},
2662 NameScript: [2]byte{},
2663 NameSize: [2]byte{0, 0x0b},
2665 Name: []byte("testfile-1k"),
2667 b, _ := io.ReadAll(&fnwi)
2676 for _, tt := range tests {
2677 t.Run(tt.name, func(t *testing.T) {
2678 gotRes := HandleGetFileNameList(tt.args.cc, &tt.args.t)
2679 TranAssertEqual(t, tt.wantRes, gotRes)
2684 func TestHandleGetClientInfoText(t *testing.T) {
2686 cc *hotline.ClientConn
2687 t hotline.Transaction
2692 wantRes []hotline.Transaction
2695 name: "when user does not have required permission",
2697 cc: &hotline.ClientConn{
2698 Account: &hotline.Account{
2699 Access: func() hotline.AccessBitmap {
2700 var bits hotline.AccessBitmap
2704 Server: &hotline.Server{
2705 //Accounts: map[string]*Account{},
2708 t: hotline.NewTransaction(
2709 hotline.TranGetClientInfoText, [2]byte{0, 1},
2710 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
2713 wantRes: []hotline.Transaction{
2716 ErrorCode: [4]byte{0, 0, 0, 1},
2717 Fields: []hotline.Field{
2718 hotline.NewField(hotline.FieldError, []byte("You are not allowed to get client info.")),
2724 name: "with a valid user",
2726 cc: &hotline.ClientConn{
2727 UserName: []byte("Testy McTest"),
2728 RemoteAddr: "1.2.3.4:12345",
2729 Account: &hotline.Account{
2730 Access: func() hotline.AccessBitmap {
2731 var bits hotline.AccessBitmap
2732 bits.Set(hotline.AccessGetClientInfo)
2738 Server: &hotline.Server{
2739 ClientMgr: func() *hotline.MockClientMgr {
2740 m := hotline.MockClientMgr{}
2741 m.On("Get", hotline.ClientID{0x0, 0x1}).Return(&hotline.ClientConn{
2742 UserName: []byte("Testy McTest"),
2743 RemoteAddr: "1.2.3.4:12345",
2744 Account: &hotline.Account{
2745 Access: func() hotline.AccessBitmap {
2746 var bits hotline.AccessBitmap
2747 bits.Set(hotline.AccessGetClientInfo)
2758 ClientFileTransferMgr: hotline.ClientFileTransferMgr{},
2760 t: hotline.NewTransaction(
2761 hotline.TranGetClientInfoText, [2]byte{0, 1},
2762 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
2765 wantRes: []hotline.Transaction{
2768 Fields: []hotline.Field{
2769 hotline.NewField(hotline.FieldData, []byte(
2770 strings.ReplaceAll(`Nickname: Testy McTest
2773 Address: 1.2.3.4:12345
2775 -------- File Downloads ---------
2779 ------- Folder Downloads --------
2783 --------- File Uploads ----------
2787 -------- Folder Uploads ---------
2791 ------- Waiting Downloads -------
2797 hotline.NewField(hotline.FieldUserName, []byte("Testy McTest")),
2803 for _, tt := range tests {
2804 t.Run(tt.name, func(t *testing.T) {
2805 gotRes := HandleGetClientInfoText(tt.args.cc, &tt.args.t)
2806 TranAssertEqual(t, tt.wantRes, gotRes)
2811 func TestHandleTranAgreed(t *testing.T) {
2813 cc *hotline.ClientConn
2814 t hotline.Transaction
2819 wantRes []hotline.Transaction
2822 name: "normal request flow",
2824 cc: &hotline.ClientConn{
2825 Account: &hotline.Account{
2826 Access: func() hotline.AccessBitmap {
2827 var bits hotline.AccessBitmap
2828 bits.Set(hotline.AccessDisconUser)
2829 bits.Set(hotline.AccessAnyName)
2833 Flags: [2]byte{0, 1},
2834 Version: []byte{0, 1},
2836 Logger: NewTestLogger(),
2837 Server: &hotline.Server{
2838 Config: hotline.Config{
2839 BannerFile: "Banner.jpg",
2841 ClientMgr: func() *hotline.MockClientMgr {
2842 m := hotline.MockClientMgr{}
2843 m.On("List").Return([]*hotline.ClientConn{
2845 // ID: [2]byte{0, 2},
2846 // UserName: []byte("UserB"),
2854 t: hotline.NewTransaction(
2855 hotline.TranAgreed, [2]byte{},
2856 hotline.NewField(hotline.FieldUserName, []byte("username")),
2857 hotline.NewField(hotline.FieldUserIconID, []byte{0, 1}),
2858 hotline.NewField(hotline.FieldOptions, []byte{0, 0}),
2861 wantRes: []hotline.Transaction{
2863 ClientID: [2]byte{0, 1},
2864 Type: [2]byte{0, 0x7a},
2865 Fields: []hotline.Field{
2866 hotline.NewField(hotline.FieldBannerType, []byte("JPEG")),
2870 ClientID: [2]byte{0, 1},
2872 Fields: []hotline.Field{},
2877 for _, tt := range tests {
2878 t.Run(tt.name, func(t *testing.T) {
2879 gotRes := HandleTranAgreed(tt.args.cc, &tt.args.t)
2880 TranAssertEqual(t, tt.wantRes, gotRes)
2885 func TestHandleSetClientUserInfo(t *testing.T) {
2887 cc *hotline.ClientConn
2888 t hotline.Transaction
2893 wantRes []hotline.Transaction
2896 name: "when client does not have AccessAnyName",
2898 cc: &hotline.ClientConn{
2899 Account: &hotline.Account{
2900 Access: func() hotline.AccessBitmap {
2901 var bits hotline.AccessBitmap
2906 UserName: []byte("Guest"),
2907 Flags: [2]byte{0, 1},
2908 Server: &hotline.Server{
2909 ClientMgr: func() *hotline.MockClientMgr {
2910 m := hotline.MockClientMgr{}
2911 m.On("List").Return([]*hotline.ClientConn{
2920 t: hotline.NewTransaction(
2921 hotline.TranSetClientUserInfo, [2]byte{},
2922 hotline.NewField(hotline.FieldUserIconID, []byte{0, 1}),
2923 hotline.NewField(hotline.FieldUserName, []byte("NOPE")),
2926 wantRes: []hotline.Transaction{
2928 ClientID: [2]byte{0, 1},
2929 Type: [2]byte{0x01, 0x2d},
2930 Fields: []hotline.Field{
2931 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
2932 hotline.NewField(hotline.FieldUserIconID, []byte{0, 1}),
2933 hotline.NewField(hotline.FieldUserFlags, []byte{0, 1}),
2934 hotline.NewField(hotline.FieldUserName, []byte("Guest"))},
2939 for _, tt := range tests {
2940 t.Run(tt.name, func(t *testing.T) {
2941 gotRes := HandleSetClientUserInfo(tt.args.cc, &tt.args.t)
2942 TranAssertEqual(t, tt.wantRes, gotRes)
2947 func TestHandleDelNewsItem(t *testing.T) {
2949 cc *hotline.ClientConn
2950 t hotline.Transaction
2955 wantRes []hotline.Transaction
2958 name: "when user does not have permission to delete a news category",
2960 cc: &hotline.ClientConn{
2961 Account: &hotline.Account{
2962 Access: hotline.AccessBitmap{},
2965 Server: &hotline.Server{
2966 ThreadedNewsMgr: func() *hotline.MockThreadNewsMgr {
2967 m := hotline.MockThreadNewsMgr{}
2968 m.On("NewsItem", []string{"test"}).Return(hotline.NewsCategoryListData15{
2969 Type: hotline.NewsCategory,
2975 t: hotline.NewTransaction(
2976 hotline.TranDelNewsItem, [2]byte{},
2977 hotline.NewField(hotline.FieldNewsPath,
2982 0x74, 0x65, 0x73, 0x74,
2987 wantRes: []hotline.Transaction{
2989 ClientID: [2]byte{0, 1},
2991 ErrorCode: [4]byte{0, 0, 0, 1},
2992 Fields: []hotline.Field{
2993 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete news categories.")),
2999 name: "when user does not have permission to delete a news folder",
3001 cc: &hotline.ClientConn{
3002 Account: &hotline.Account{
3003 Access: hotline.AccessBitmap{},
3006 Server: &hotline.Server{
3007 ThreadedNewsMgr: func() *hotline.MockThreadNewsMgr {
3008 m := hotline.MockThreadNewsMgr{}
3009 m.On("NewsItem", []string{"test"}).Return(hotline.NewsCategoryListData15{
3010 Type: hotline.NewsBundle,
3016 t: hotline.NewTransaction(
3017 hotline.TranDelNewsItem, [2]byte{},
3018 hotline.NewField(hotline.FieldNewsPath,
3023 0x74, 0x65, 0x73, 0x74,
3028 wantRes: []hotline.Transaction{
3030 ClientID: [2]byte{0, 1},
3032 ErrorCode: [4]byte{0, 0, 0, 1},
3033 Fields: []hotline.Field{
3034 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete news folders.")),
3040 name: "when user deletes a news folder",
3042 cc: &hotline.ClientConn{
3043 Account: &hotline.Account{
3044 Access: func() hotline.AccessBitmap {
3045 var bits hotline.AccessBitmap
3046 bits.Set(hotline.AccessNewsDeleteFldr)
3051 Server: &hotline.Server{
3052 ThreadedNewsMgr: func() *hotline.MockThreadNewsMgr {
3053 m := hotline.MockThreadNewsMgr{}
3054 m.On("NewsItem", []string{"test"}).Return(hotline.NewsCategoryListData15{Type: hotline.NewsBundle})
3055 m.On("DeleteNewsItem", []string{"test"}).Return(nil)
3060 t: hotline.NewTransaction(
3061 hotline.TranDelNewsItem, [2]byte{},
3062 hotline.NewField(hotline.FieldNewsPath,
3067 0x74, 0x65, 0x73, 0x74,
3072 wantRes: []hotline.Transaction{
3074 ClientID: [2]byte{0, 1},
3076 Fields: []hotline.Field{},
3081 for _, tt := range tests {
3082 t.Run(tt.name, func(t *testing.T) {
3083 gotRes := HandleDelNewsItem(tt.args.cc, &tt.args.t)
3085 TranAssertEqual(t, tt.wantRes, gotRes)
3090 func TestHandleTranOldPostNews(t *testing.T) {
3092 cc *hotline.ClientConn
3093 t hotline.Transaction
3098 wantRes []hotline.Transaction
3101 name: "when user does not have required permission",
3103 cc: &hotline.ClientConn{
3104 Account: &hotline.Account{
3105 Access: hotline.AccessBitmap{},
3108 t: hotline.NewTransaction(
3109 hotline.TranOldPostNews, [2]byte{0, 1},
3110 hotline.NewField(hotline.FieldData, []byte("hai")),
3113 wantRes: []hotline.Transaction{
3116 ErrorCode: [4]byte{0, 0, 0, 1},
3117 Fields: []hotline.Field{
3118 hotline.NewField(hotline.FieldError, []byte("You are not allowed to post news.")),
3124 name: "when user posts news update",
3126 cc: &hotline.ClientConn{
3127 Account: &hotline.Account{
3128 Access: func() hotline.AccessBitmap {
3129 var bits hotline.AccessBitmap
3130 bits.Set(hotline.AccessNewsPostArt)
3134 Server: &hotline.Server{
3135 Config: hotline.Config{
3138 ClientMgr: func() *hotline.MockClientMgr {
3139 m := hotline.MockClientMgr{}
3140 m.On("List").Return([]*hotline.ClientConn{})
3143 MessageBoard: func() *mockReadWriteSeeker {
3144 m := mockReadWriteSeeker{}
3145 m.On("Seek", int64(0), 0).Return(int64(0), nil)
3146 m.On("Read", mock.AnythingOfType("[]uint8")).Run(func(args mock.Arguments) {
3147 arg := args.Get(0).([]uint8)
3149 }).Return(4, io.EOF)
3150 m.On("Write", mock.AnythingOfType("[]uint8")).Return(3, nil)
3155 t: hotline.NewTransaction(
3156 hotline.TranOldPostNews, [2]byte{0, 1},
3157 hotline.NewField(hotline.FieldData, []byte("hai")),
3160 wantRes: []hotline.Transaction{
3167 for _, tt := range tests {
3168 t.Run(tt.name, func(t *testing.T) {
3169 gotRes := HandleTranOldPostNews(tt.args.cc, &tt.args.t)
3171 TranAssertEqual(t, tt.wantRes, gotRes)
3176 func TestHandleInviteNewChat(t *testing.T) {
3178 cc *hotline.ClientConn
3179 t hotline.Transaction
3184 wantRes []hotline.Transaction
3187 name: "when user does not have required permission",
3189 cc: &hotline.ClientConn{
3190 Account: &hotline.Account{
3191 Access: func() hotline.AccessBitmap {
3192 var bits hotline.AccessBitmap
3197 t: hotline.NewTransaction(hotline.TranInviteNewChat, [2]byte{0, 1}),
3199 wantRes: []hotline.Transaction{
3202 ErrorCode: [4]byte{0, 0, 0, 1},
3203 Fields: []hotline.Field{
3204 hotline.NewField(hotline.FieldError, []byte("You are not allowed to request private chat.")),
3210 name: "when userA invites userB to new private chat",
3212 cc: &hotline.ClientConn{
3214 Account: &hotline.Account{
3215 Access: func() hotline.AccessBitmap {
3216 var bits hotline.AccessBitmap
3217 bits.Set(hotline.AccessOpenChat)
3221 UserName: []byte("UserA"),
3223 Flags: [2]byte{0, 0},
3224 Server: &hotline.Server{
3225 ClientMgr: func() *hotline.MockClientMgr {
3226 m := hotline.MockClientMgr{}
3227 m.On("Get", hotline.ClientID{0x0, 0x2}).Return(&hotline.ClientConn{
3229 UserName: []byte("UserB"),
3233 ChatMgr: func() *hotline.MockChatManager {
3234 m := hotline.MockChatManager{}
3235 m.On("New", mock.AnythingOfType("*hotline.ClientConn")).Return(hotline.ChatID{0x52, 0xfd, 0xfc, 0x07})
3240 t: hotline.NewTransaction(
3241 hotline.TranInviteNewChat, [2]byte{0, 1},
3242 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
3245 wantRes: []hotline.Transaction{
3247 ClientID: [2]byte{0, 2},
3248 Type: [2]byte{0, 0x71},
3249 Fields: []hotline.Field{
3250 hotline.NewField(hotline.FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3251 hotline.NewField(hotline.FieldUserName, []byte("UserA")),
3252 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
3256 ClientID: [2]byte{0, 1},
3258 Fields: []hotline.Field{
3259 hotline.NewField(hotline.FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3260 hotline.NewField(hotline.FieldUserName, []byte("UserA")),
3261 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
3262 hotline.NewField(hotline.FieldUserIconID, []byte{0, 1}),
3263 hotline.NewField(hotline.FieldUserFlags, []byte{0, 0}),
3269 name: "when userA invites userB to new private chat, but UserB has refuse private chat enabled",
3271 cc: &hotline.ClientConn{
3273 Account: &hotline.Account{
3274 Access: func() hotline.AccessBitmap {
3275 var bits hotline.AccessBitmap
3276 bits.Set(hotline.AccessOpenChat)
3280 UserName: []byte("UserA"),
3282 Flags: [2]byte{0, 0},
3283 Server: &hotline.Server{
3284 ClientMgr: func() *hotline.MockClientMgr {
3285 m := hotline.MockClientMgr{}
3286 m.On("Get", hotline.ClientID{0, 2}).Return(&hotline.ClientConn{
3289 UserName: []byte("UserB"),
3290 Flags: [2]byte{255, 255},
3294 ChatMgr: func() *hotline.MockChatManager {
3295 m := hotline.MockChatManager{}
3296 m.On("New", mock.AnythingOfType("*hotline.ClientConn")).Return(hotline.ChatID{0x52, 0xfd, 0xfc, 0x07})
3301 t: hotline.NewTransaction(
3302 hotline.TranInviteNewChat, [2]byte{0, 1},
3303 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
3306 wantRes: []hotline.Transaction{
3308 ClientID: [2]byte{0, 1},
3309 Type: [2]byte{0, 0x68},
3310 Fields: []hotline.Field{
3311 hotline.NewField(hotline.FieldData, []byte("UserB does not accept private chats.")),
3312 hotline.NewField(hotline.FieldUserName, []byte("UserB")),
3313 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
3314 hotline.NewField(hotline.FieldOptions, []byte{0, 2}),
3318 ClientID: [2]byte{0, 1},
3320 Fields: []hotline.Field{
3321 hotline.NewField(hotline.FieldChatID, []byte{0x52, 0xfd, 0xfc, 0x07}),
3322 hotline.NewField(hotline.FieldUserName, []byte("UserA")),
3323 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
3324 hotline.NewField(hotline.FieldUserIconID, []byte{0, 1}),
3325 hotline.NewField(hotline.FieldUserFlags, []byte{0, 0}),
3331 for _, tt := range tests {
3332 t.Run(tt.name, func(t *testing.T) {
3334 gotRes := HandleInviteNewChat(tt.args.cc, &tt.args.t)
3336 TranAssertEqual(t, tt.wantRes, gotRes)
3341 func TestHandleGetNewsArtData(t *testing.T) {
3343 cc *hotline.ClientConn
3344 t hotline.Transaction
3349 wantRes []hotline.Transaction
3352 name: "when user does not have required permission",
3354 cc: &hotline.ClientConn{Account: &hotline.Account{}},
3355 t: hotline.NewTransaction(
3356 hotline.TranGetNewsArtData, [2]byte{0, 1},
3359 wantRes: []hotline.Transaction{
3362 ErrorCode: [4]byte{0, 0, 0, 1},
3363 Fields: []hotline.Field{
3364 hotline.NewField(hotline.FieldError, []byte("You are not allowed to read news.")),
3370 name: "when user has required permission",
3372 cc: &hotline.ClientConn{
3373 Account: &hotline.Account{
3374 Access: func() hotline.AccessBitmap {
3375 var bits hotline.AccessBitmap
3376 bits.Set(hotline.AccessNewsReadArt)
3380 Server: &hotline.Server{
3381 ThreadedNewsMgr: func() *hotline.MockThreadNewsMgr {
3382 m := hotline.MockThreadNewsMgr{}
3383 m.On("GetArticle", []string{"Example Category"}, uint32(1)).Return(&hotline.NewsArtData{
3387 PrevArt: [4]byte{0, 0, 0, 1},
3388 NextArt: [4]byte{0, 0, 0, 2},
3389 ParentArt: [4]byte{0, 0, 0, 3},
3390 FirstChildArt: [4]byte{0, 0, 0, 4},
3391 DataFlav: []byte("text/plain"),
3392 Data: "article data",
3398 t: hotline.NewTransaction(
3399 hotline.TranGetNewsArtData, [2]byte{0, 1},
3400 hotline.NewField(hotline.FieldNewsPath, []byte{
3402 0x00, 0x01, 0x00, 0x00, 0x10, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79,
3404 hotline.NewField(hotline.FieldNewsArtID, []byte{0, 1}),
3407 wantRes: []hotline.Transaction{
3410 Fields: []hotline.Field{
3411 hotline.NewField(hotline.FieldNewsArtTitle, []byte("title")),
3412 hotline.NewField(hotline.FieldNewsArtPoster, []byte("poster")),
3413 hotline.NewField(hotline.FieldNewsArtDate, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
3414 hotline.NewField(hotline.FieldNewsArtPrevArt, []byte{0, 0, 0, 1}),
3415 hotline.NewField(hotline.FieldNewsArtNextArt, []byte{0, 0, 0, 2}),
3416 hotline.NewField(hotline.FieldNewsArtParentArt, []byte{0, 0, 0, 3}),
3417 hotline.NewField(hotline.FieldNewsArt1stChildArt, []byte{0, 0, 0, 4}),
3418 hotline.NewField(hotline.FieldNewsArtDataFlav, []byte("text/plain")),
3419 hotline.NewField(hotline.FieldNewsArtData, []byte("article data")),
3425 for _, tt := range tests {
3426 t.Run(tt.name, func(t *testing.T) {
3427 gotRes := HandleGetNewsArtData(tt.args.cc, &tt.args.t)
3428 TranAssertEqual(t, tt.wantRes, gotRes)
3433 func TestHandleGetNewsArtNameList(t *testing.T) {
3435 cc *hotline.ClientConn
3436 t hotline.Transaction
3441 wantRes []hotline.Transaction
3444 name: "when user does not have required permission",
3446 cc: &hotline.ClientConn{
3447 Account: &hotline.Account{
3448 Access: func() hotline.AccessBitmap {
3449 var bits hotline.AccessBitmap
3453 Server: &hotline.Server{
3454 //Accounts: map[string]*Account{},
3457 t: hotline.NewTransaction(
3458 hotline.TranGetNewsArtNameList, [2]byte{0, 1},
3461 wantRes: []hotline.Transaction{
3465 Type: [2]byte{0, 0},
3466 ErrorCode: [4]byte{0, 0, 0, 1},
3467 Fields: []hotline.Field{
3468 hotline.NewField(hotline.FieldError, []byte("You are not allowed to read news.")),
3474 // name: "when user has required access",
3476 // cc: &hotline.ClientConn{
3477 // Account: &hotline.Account{
3478 // Access: func() hotline.AccessBitmap {
3479 // var bits hotline.AccessBitmap
3480 // bits.Set(hotline.AccessNewsReadArt)
3484 // Server: &hotline.Server{
3485 // ThreadedNewsMgr: func() *mockThreadNewsMgr {
3486 // m := mockThreadNewsMgr{}
3487 // m.On("ListArticles", []string{"Example Category"}).Return(NewsArtListData{
3488 // Name: []byte("testTitle"),
3489 // NewsArtList: []byte{},
3495 // t: NewTransaction(
3496 // TranGetNewsArtNameList,
3498 // // 00000000 00 01 00 00 10 45 78 61 6d 70 6c 65 20 43 61 74 |.....Example Cat|
3499 // // 00000010 65 67 6f 72 79 |egory|
3500 // NewField(hotline.FieldNewsPath, []byte{
3501 // 0x00, 0x01, 0x00, 0x00, 0x10, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79,
3505 // wantRes: []hotline.Transaction{
3508 // Fields: []hotline.Field{
3509 // NewField(hotline.FieldNewsArtListData, []byte{
3510 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
3511 // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
3512 // 0x09, 0x74, 0x65, 0x73, 0x74, 0x54, 0x69, 0x74, 0x6c, 0x65, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x50,
3513 // 0x6f, 0x73, 0x74, 0x65, 0x72, 0x0a, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x69, 0x6e,
3522 for _, tt := range tests {
3523 t.Run(tt.name, func(t *testing.T) {
3524 gotRes := HandleGetNewsArtNameList(tt.args.cc, &tt.args.t)
3526 TranAssertEqual(t, tt.wantRes, gotRes)
3531 func TestHandleNewNewsFldr(t *testing.T) {
3533 cc *hotline.ClientConn
3534 t hotline.Transaction
3539 wantRes []hotline.Transaction
3542 name: "when user does not have required permission",
3544 cc: &hotline.ClientConn{
3545 Account: &hotline.Account{
3546 Access: func() hotline.AccessBitmap {
3547 var bits hotline.AccessBitmap
3551 Server: &hotline.Server{
3552 //Accounts: map[string]*Account{},
3555 t: hotline.NewTransaction(
3556 hotline.TranGetNewsArtNameList, [2]byte{0, 1},
3559 wantRes: []hotline.Transaction{
3563 Type: [2]byte{0, 0},
3564 ErrorCode: [4]byte{0, 0, 0, 1},
3565 Fields: []hotline.Field{
3566 hotline.NewField(hotline.FieldError, []byte("You are not allowed to create news folders.")),
3572 name: "with a valid request",
3574 cc: &hotline.ClientConn{
3575 Account: &hotline.Account{
3576 Access: func() hotline.AccessBitmap {
3577 var bits hotline.AccessBitmap
3578 bits.Set(hotline.AccessNewsCreateFldr)
3582 Logger: NewTestLogger(),
3584 Server: &hotline.Server{
3585 ThreadedNewsMgr: func() *hotline.MockThreadNewsMgr {
3586 m := hotline.MockThreadNewsMgr{}
3587 m.On("CreateGrouping", []string{"test"}, "testFolder", hotline.NewsBundle).Return(nil)
3592 t: hotline.NewTransaction(
3593 hotline.TranGetNewsArtNameList, [2]byte{0, 1},
3594 hotline.NewField(hotline.FieldFileName, []byte("testFolder")),
3595 hotline.NewField(hotline.FieldNewsPath,
3600 0x74, 0x65, 0x73, 0x74,
3605 wantRes: []hotline.Transaction{
3607 ClientID: [2]byte{0, 1},
3609 Fields: []hotline.Field{},
3614 // Name: "when there is an error writing the threaded news file",
3616 // cc: &hotline.ClientConn{
3617 // Account: &hotline.Account{
3618 // Access: func() hotline.AccessBitmap {
3619 // var bits hotline.AccessBitmap
3620 // bits.Set(hotline.AccessNewsCreateFldr)
3624 // logger: NewTestLogger(),
3625 // Type: [2]byte{0, 1},
3626 // Server: &hotline.Server{
3627 // ConfigDir: "/fakeConfigRoot",
3628 // FS: func() *hotline.MockFileStore {
3629 // mfs := &MockFileStore{}
3630 // mfs.On("WriteFile", "/fakeConfigRoot/ThreadedNews.yaml", mock.Anything, mock.Anything).Return(os.ErrNotExist)
3633 // ThreadedNews: &ThreadedNews{Categories: map[string]NewsCategoryListData15{
3635 // Type: []byte{0, 2},
3639 // SubCats: make(map[string]NewsCategoryListData15),
3644 // t: NewTransaction(
3645 // TranGetNewsArtNameList, [2]byte{0, 1},
3646 // NewField(hotline.FieldFileName, []byte("testFolder")),
3647 // NewField(hotline.FieldNewsPath,
3652 // 0x74, 0x65, 0x73, 0x74,
3657 // wantRes: []hotline.Transaction{
3659 // ClientID: [2]byte{0, 1},
3662 // Type: [2]byte{0, 0},
3663 // ErrorCode: [4]byte{0, 0, 0, 1},
3664 // Fields: []hotline.Field{
3665 // NewField(hotline.FieldError, []byte("Error creating news folder.")),
3670 for _, tt := range tests {
3671 t.Run(tt.name, func(t *testing.T) {
3672 gotRes := HandleNewNewsFldr(tt.args.cc, &tt.args.t)
3674 TranAssertEqual(t, tt.wantRes, gotRes)
3679 func TestHandleDownloadBanner(t *testing.T) {
3681 cc *hotline.ClientConn
3682 t hotline.Transaction
3687 wantRes []hotline.Transaction
3689 // TODO: Add test cases.
3691 for _, tt := range tests {
3692 t.Run(tt.name, func(t *testing.T) {
3693 gotRes := HandleDownloadBanner(tt.args.cc, &tt.args.t)
3695 assert.Equalf(t, tt.wantRes, gotRes, "HandleDownloadBanner(%v, %v)", tt.args.cc, &tt.args.t)
3700 func TestHandlePostNewsArt(t *testing.T) {
3702 cc *hotline.ClientConn
3703 t hotline.Transaction
3708 wantRes []hotline.Transaction
3711 name: "without required permission",
3713 cc: &hotline.ClientConn{
3714 Account: &hotline.Account{
3715 Access: func() hotline.AccessBitmap {
3716 var bits hotline.AccessBitmap
3721 t: hotline.NewTransaction(
3722 hotline.TranPostNewsArt,
3726 wantRes: []hotline.Transaction{
3729 ErrorCode: [4]byte{0, 0, 0, 1},
3730 Fields: []hotline.Field{
3731 hotline.NewField(hotline.FieldError, []byte("You are not allowed to post news articles.")),
3737 name: "with required permission",
3739 cc: &hotline.ClientConn{
3740 Server: &hotline.Server{
3741 ThreadedNewsMgr: func() *hotline.MockThreadNewsMgr {
3742 m := hotline.MockThreadNewsMgr{}
3743 m.On("PostArticle", []string{"www"}, uint32(0), mock.AnythingOfType("hotline.NewsArtData")).Return(nil)
3747 Account: &hotline.Account{
3748 Access: func() hotline.AccessBitmap {
3749 var bits hotline.AccessBitmap
3750 bits.Set(hotline.AccessNewsPostArt)
3755 t: hotline.NewTransaction(
3756 hotline.TranPostNewsArt,
3758 hotline.NewField(hotline.FieldNewsPath, []byte{0x00, 0x01, 0x00, 0x00, 0x03, 0x77, 0x77, 0x77}),
3759 hotline.NewField(hotline.FieldNewsArtID, []byte{0x00, 0x00, 0x00, 0x00}),
3762 wantRes: []hotline.Transaction{
3765 ErrorCode: [4]byte{0, 0, 0, 0},
3766 Fields: []hotline.Field{},
3771 for _, tt := range tests {
3772 t.Run(tt.name, func(t *testing.T) {
3773 TranAssertEqual(t, tt.wantRes, HandlePostNewsArt(tt.args.cc, &tt.args.t))