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{
785 ID: [2]byte{0x00, 0x01},
786 Server: &hotline.Server{
787 FS: &hotline.OSFileStore{},
788 Config: hotline.Config{
789 FileRoot: func() string {
790 path, _ := os.Getwd()
791 return filepath.Join(path, "/test/config/Files")
796 t: hotline.NewTransaction(
797 hotline.TranGetFileInfo, [2]byte{},
798 hotline.NewField(hotline.FieldFileName, []byte("testfile.txt")),
799 hotline.NewField(hotline.FieldFilePath, []byte{0x00, 0x00}),
802 wantRes: []hotline.Transaction{
804 ClientID: [2]byte{0, 1},
807 Fields: []hotline.Field{
808 hotline.NewField(hotline.FieldFileName, []byte("testfile.txt")),
809 hotline.NewField(hotline.FieldFileTypeString, []byte("Text File")),
810 hotline.NewField(hotline.FieldFileCreatorString, []byte("ttxt")),
811 hotline.NewField(hotline.FieldFileType, []byte("TEXT")),
812 hotline.NewField(hotline.FieldFileCreateDate, make([]byte, 8)),
813 hotline.NewField(hotline.FieldFileModifyDate, make([]byte, 8)),
814 hotline.NewField(hotline.FieldFileSize, []byte{0x0, 0x0, 0x0, 0x17}),
820 for _, tt := range tests {
821 t.Run(tt.name, func(t *testing.T) {
822 gotRes := HandleGetFileInfo(tt.args.cc, &tt.args.t)
824 // Clear the file timestamp fields to work around problems running the tests in multiple timezones
825 // TODO: revisit how to test this by mocking the stat calls
826 gotRes[0].Fields[4].Data = make([]byte, 8)
827 gotRes[0].Fields[5].Data = make([]byte, 8)
829 if !TranAssertEqual(t, tt.wantRes, gotRes) {
830 t.Errorf("HandleGetFileInfo() gotRes = %v, want %v", gotRes, tt.wantRes)
836 func TestHandleNewFolder(t *testing.T) {
838 cc *hotline.ClientConn
839 t hotline.Transaction
844 wantRes []hotline.Transaction
847 name: "without required permission",
849 cc: &hotline.ClientConn{
850 Account: &hotline.Account{
851 Access: func() hotline.AccessBitmap {
852 var bits hotline.AccessBitmap
857 t: hotline.NewTransaction(
858 hotline.TranNewFolder,
862 wantRes: []hotline.Transaction{
865 ErrorCode: [4]byte{0, 0, 0, 1},
866 Fields: []hotline.Field{
867 hotline.NewField(hotline.FieldError, []byte("You are not allowed to create folders.")),
873 name: "when path is nested",
875 cc: &hotline.ClientConn{
876 Account: &hotline.Account{
877 Access: func() hotline.AccessBitmap {
878 var bits hotline.AccessBitmap
879 bits.Set(hotline.AccessCreateFolder)
884 Server: &hotline.Server{
885 Config: hotline.Config{
888 FS: func() *hotline.MockFileStore {
889 mfs := &hotline.MockFileStore{}
890 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
891 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
896 t: hotline.NewTransaction(
897 hotline.TranNewFolder, [2]byte{0, 1},
898 hotline.NewField(hotline.FieldFileName, []byte("testFolder")),
899 hotline.NewField(hotline.FieldFilePath, []byte{
907 wantRes: []hotline.Transaction{
909 ClientID: [2]byte{0, 1},
915 name: "when path is not nested",
917 cc: &hotline.ClientConn{
918 Account: &hotline.Account{
919 Access: func() hotline.AccessBitmap {
920 var bits hotline.AccessBitmap
921 bits.Set(hotline.AccessCreateFolder)
926 Server: &hotline.Server{
927 Config: hotline.Config{
930 FS: func() *hotline.MockFileStore {
931 mfs := &hotline.MockFileStore{}
932 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
933 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
938 t: hotline.NewTransaction(
939 hotline.TranNewFolder, [2]byte{0, 1},
940 hotline.NewField(hotline.FieldFileName, []byte("testFolder")),
943 wantRes: []hotline.Transaction{
945 ClientID: [2]byte{0, 1},
951 name: "when Write returns an err",
953 cc: &hotline.ClientConn{
954 Account: &hotline.Account{
955 Access: func() hotline.AccessBitmap {
956 var bits hotline.AccessBitmap
957 bits.Set(hotline.AccessCreateFolder)
962 Server: &hotline.Server{
963 Config: hotline.Config{
966 FS: func() *hotline.MockFileStore {
967 mfs := &hotline.MockFileStore{}
968 mfs.On("Mkdir", "/Files/aaa/testFolder", fs.FileMode(0777)).Return(nil)
969 mfs.On("Stat", "/Files/aaa/testFolder").Return(nil, os.ErrNotExist)
974 t: hotline.NewTransaction(
975 hotline.TranNewFolder, [2]byte{0, 1},
976 hotline.NewField(hotline.FieldFileName, []byte("testFolder")),
977 hotline.NewField(hotline.FieldFilePath, []byte{
982 wantRes: []hotline.Transaction{},
985 name: "FieldFileName does not allow directory traversal",
987 cc: &hotline.ClientConn{
988 Account: &hotline.Account{
989 Access: func() hotline.AccessBitmap {
990 var bits hotline.AccessBitmap
991 bits.Set(hotline.AccessCreateFolder)
996 Server: &hotline.Server{
997 Config: hotline.Config{
1000 FS: func() *hotline.MockFileStore {
1001 mfs := &hotline.MockFileStore{}
1002 mfs.On("Mkdir", "/Files/testFolder", fs.FileMode(0777)).Return(nil)
1003 mfs.On("Stat", "/Files/testFolder").Return(nil, os.ErrNotExist)
1008 t: hotline.NewTransaction(
1009 hotline.TranNewFolder, [2]byte{0, 1},
1010 hotline.NewField(hotline.FieldFileName, []byte("../../testFolder")),
1013 wantRes: []hotline.Transaction{
1015 ClientID: [2]byte{0, 1},
1021 name: "FieldFilePath does not allow directory traversal",
1023 cc: &hotline.ClientConn{
1024 Account: &hotline.Account{
1025 Access: func() hotline.AccessBitmap {
1026 var bits hotline.AccessBitmap
1027 bits.Set(hotline.AccessCreateFolder)
1032 Server: &hotline.Server{
1033 Config: hotline.Config{
1034 FileRoot: "/Files/",
1036 FS: func() *hotline.MockFileStore {
1037 mfs := &hotline.MockFileStore{}
1038 mfs.On("Mkdir", "/Files/foo/testFolder", fs.FileMode(0777)).Return(nil)
1039 mfs.On("Stat", "/Files/foo/testFolder").Return(nil, os.ErrNotExist)
1044 t: hotline.NewTransaction(
1045 hotline.TranNewFolder, [2]byte{0, 1},
1046 hotline.NewField(hotline.FieldFileName, []byte("testFolder")),
1047 hotline.NewField(hotline.FieldFilePath, []byte{
1058 wantRes: []hotline.Transaction{
1060 ClientID: [2]byte{0, 1},
1066 for _, tt := range tests {
1067 t.Run(tt.name, func(t *testing.T) {
1068 gotRes := HandleNewFolder(tt.args.cc, &tt.args.t)
1070 if !TranAssertEqual(t, tt.wantRes, gotRes) {
1071 t.Errorf("HandleNewFolder() gotRes = %v, want %v", gotRes, tt.wantRes)
1077 func TestHandleUploadFile(t *testing.T) {
1079 cc *hotline.ClientConn
1080 t hotline.Transaction
1085 wantRes []hotline.Transaction
1088 name: "when request is valid and user has Upload Anywhere permission",
1090 cc: &hotline.ClientConn{
1091 Server: &hotline.Server{
1092 FS: &hotline.OSFileStore{},
1093 FileTransferMgr: hotline.NewMemFileTransferMgr(),
1094 Config: hotline.Config{
1095 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1097 ClientFileTransferMgr: hotline.NewClientFileTransferMgr(),
1098 Account: &hotline.Account{
1099 Access: func() hotline.AccessBitmap {
1100 var bits hotline.AccessBitmap
1101 bits.Set(hotline.AccessUploadFile)
1102 bits.Set(hotline.AccessUploadAnywhere)
1107 t: hotline.NewTransaction(
1108 hotline.TranUploadFile, [2]byte{0, 1},
1109 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1110 hotline.NewField(hotline.FieldFilePath, []byte{
1118 wantRes: []hotline.Transaction{
1121 Fields: []hotline.Field{
1122 hotline.NewField(hotline.FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}), // rand.Seed(1)
1128 name: "when user does not have required access",
1130 cc: &hotline.ClientConn{
1131 Account: &hotline.Account{
1132 Access: func() hotline.AccessBitmap {
1133 var bits hotline.AccessBitmap
1138 t: hotline.NewTransaction(
1139 hotline.TranUploadFile, [2]byte{0, 1},
1140 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1141 hotline.NewField(hotline.FieldFilePath, []byte{
1149 wantRes: []hotline.Transaction{
1152 ErrorCode: [4]byte{0, 0, 0, 1},
1153 Fields: []hotline.Field{
1154 hotline.NewField(hotline.FieldError, []byte("You are not allowed to upload files.")), // rand.Seed(1)
1160 for _, tt := range tests {
1161 t.Run(tt.name, func(t *testing.T) {
1162 gotRes := HandleUploadFile(tt.args.cc, &tt.args.t)
1163 TranAssertEqual(t, tt.wantRes, gotRes)
1168 func TestHandleMakeAlias(t *testing.T) {
1170 cc *hotline.ClientConn
1171 t hotline.Transaction
1176 wantRes []hotline.Transaction
1179 name: "with valid input and required permissions",
1181 cc: &hotline.ClientConn{
1182 Logger: NewTestLogger(),
1183 Account: &hotline.Account{
1184 Access: func() hotline.AccessBitmap {
1185 var bits hotline.AccessBitmap
1186 bits.Set(hotline.AccessMakeAlias)
1190 Server: &hotline.Server{
1191 Config: hotline.Config{
1192 FileRoot: func() string {
1193 path, _ := os.Getwd()
1194 return path + "/test/config/Files"
1197 Logger: NewTestLogger(),
1198 FS: func() *hotline.MockFileStore {
1199 mfs := &hotline.MockFileStore{}
1200 path, _ := os.Getwd()
1203 path+"/test/config/Files/foo/testFile",
1204 path+"/test/config/Files/bar/testFile",
1210 t: hotline.NewTransaction(
1211 hotline.TranMakeFileAlias, [2]byte{0, 1},
1212 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1213 hotline.NewField(hotline.FieldFilePath, hotline.EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1214 hotline.NewField(hotline.FieldFileNewPath, hotline.EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1217 wantRes: []hotline.Transaction{
1220 Fields: []hotline.Field(nil),
1225 name: "when symlink returns an error",
1227 cc: &hotline.ClientConn{
1228 Logger: NewTestLogger(),
1229 Account: &hotline.Account{
1230 Access: func() hotline.AccessBitmap {
1231 var bits hotline.AccessBitmap
1232 bits.Set(hotline.AccessMakeAlias)
1236 Server: &hotline.Server{
1237 Config: hotline.Config{
1238 FileRoot: func() string {
1239 path, _ := os.Getwd()
1240 return path + "/test/config/Files"
1243 Logger: NewTestLogger(),
1244 FS: func() *hotline.MockFileStore {
1245 mfs := &hotline.MockFileStore{}
1246 path, _ := os.Getwd()
1249 path+"/test/config/Files/foo/testFile",
1250 path+"/test/config/Files/bar/testFile",
1251 ).Return(errors.New("ohno"))
1256 t: hotline.NewTransaction(
1257 hotline.TranMakeFileAlias, [2]byte{0, 1},
1258 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1259 hotline.NewField(hotline.FieldFilePath, hotline.EncodeFilePath(strings.Join([]string{"foo"}, "/"))),
1260 hotline.NewField(hotline.FieldFileNewPath, hotline.EncodeFilePath(strings.Join([]string{"bar"}, "/"))),
1263 wantRes: []hotline.Transaction{
1266 ErrorCode: [4]byte{0, 0, 0, 1},
1267 Fields: []hotline.Field{
1268 hotline.NewField(hotline.FieldError, []byte("Error creating alias")),
1274 name: "when user does not have required permission",
1276 cc: &hotline.ClientConn{
1277 Logger: NewTestLogger(),
1278 Account: &hotline.Account{
1279 Access: hotline.AccessBitmap{},
1281 Server: &hotline.Server{
1282 Config: hotline.Config{
1283 FileRoot: func() string {
1284 path, _ := os.Getwd()
1285 return path + "/test/config/Files"
1290 t: hotline.NewTransaction(
1291 hotline.TranMakeFileAlias, [2]byte{0, 1},
1292 hotline.NewField(hotline.FieldFileName, []byte("testFile")),
1293 hotline.NewField(hotline.FieldFilePath, []byte{
1299 hotline.NewField(hotline.FieldFileNewPath, []byte{
1307 wantRes: []hotline.Transaction{
1310 ErrorCode: [4]byte{0, 0, 0, 1},
1311 Fields: []hotline.Field{
1312 hotline.NewField(hotline.FieldError, []byte("You are not allowed to make aliases.")),
1318 for _, tt := range tests {
1319 t.Run(tt.name, func(t *testing.T) {
1320 gotRes := HandleMakeAlias(tt.args.cc, &tt.args.t)
1321 TranAssertEqual(t, tt.wantRes, gotRes)
1326 func TestHandleGetUser(t *testing.T) {
1328 cc *hotline.ClientConn
1329 t hotline.Transaction
1334 wantRes []hotline.Transaction
1337 name: "when account is valid",
1339 cc: &hotline.ClientConn{
1340 Account: &hotline.Account{
1341 Access: func() hotline.AccessBitmap {
1342 var bits hotline.AccessBitmap
1343 bits.Set(hotline.AccessOpenUser)
1347 Server: &hotline.Server{
1348 AccountManager: func() *MockAccountManager {
1349 m := MockAccountManager{}
1350 m.On("Get", "guest").Return(&hotline.Account{
1353 Password: "password",
1354 Access: hotline.AccessBitmap{},
1360 t: hotline.NewTransaction(
1361 hotline.TranGetUser, [2]byte{0, 1},
1362 hotline.NewField(hotline.FieldUserLogin, []byte("guest")),
1365 wantRes: []hotline.Transaction{
1368 Fields: []hotline.Field{
1369 hotline.NewField(hotline.FieldUserName, []byte("Guest")),
1370 hotline.NewField(hotline.FieldUserLogin, hotline.EncodeString([]byte("guest"))),
1371 hotline.NewField(hotline.FieldUserPassword, []byte("password")),
1372 hotline.NewField(hotline.FieldUserAccess, []byte{0, 0, 0, 0, 0, 0, 0, 0}),
1378 name: "when user does not have required permission",
1380 cc: &hotline.ClientConn{
1381 Account: &hotline.Account{
1382 Access: func() hotline.AccessBitmap {
1383 var bits hotline.AccessBitmap
1387 Server: &hotline.Server{
1388 //Accounts: map[string]*Account{},
1391 t: hotline.NewTransaction(
1392 hotline.TranGetUser, [2]byte{0, 1},
1393 hotline.NewField(hotline.FieldUserLogin, []byte("nonExistentUser")),
1396 wantRes: []hotline.Transaction{
1399 ErrorCode: [4]byte{0, 0, 0, 1},
1400 Fields: []hotline.Field{
1401 hotline.NewField(hotline.FieldError, []byte("You are not allowed to view accounts.")),
1407 name: "when account does not exist",
1409 cc: &hotline.ClientConn{
1410 Account: &hotline.Account{
1411 Access: func() hotline.AccessBitmap {
1412 var bits hotline.AccessBitmap
1413 bits.Set(hotline.AccessOpenUser)
1417 Server: &hotline.Server{
1418 AccountManager: func() *MockAccountManager {
1419 m := MockAccountManager{}
1420 m.On("Get", "nonExistentUser").Return((*hotline.Account)(nil))
1425 t: hotline.NewTransaction(
1426 hotline.TranGetUser, [2]byte{0, 1},
1427 hotline.NewField(hotline.FieldUserLogin, []byte("nonExistentUser")),
1430 wantRes: []hotline.Transaction{
1434 Type: [2]byte{0, 0},
1435 ErrorCode: [4]byte{0, 0, 0, 1},
1436 Fields: []hotline.Field{
1437 hotline.NewField(hotline.FieldError, []byte("Account does not exist.")),
1443 for _, tt := range tests {
1444 t.Run(tt.name, func(t *testing.T) {
1445 gotRes := HandleGetUser(tt.args.cc, &tt.args.t)
1446 TranAssertEqual(t, tt.wantRes, gotRes)
1451 func TestHandleDeleteUser(t *testing.T) {
1453 cc *hotline.ClientConn
1454 t hotline.Transaction
1459 wantRes []hotline.Transaction
1462 name: "when user exists",
1464 cc: &hotline.ClientConn{
1465 Account: &hotline.Account{
1466 Access: func() hotline.AccessBitmap {
1467 var bits hotline.AccessBitmap
1468 bits.Set(hotline.AccessDeleteUser)
1472 Server: &hotline.Server{
1473 AccountManager: func() *MockAccountManager {
1474 m := MockAccountManager{}
1475 m.On("Delete", "testuser").Return(nil)
1478 ClientMgr: func() *hotline.MockClientMgr {
1479 m := hotline.MockClientMgr{}
1480 m.On("List").Return([]*hotline.ClientConn{}) // TODO
1485 t: hotline.NewTransaction(
1486 hotline.TranDeleteUser, [2]byte{0, 1},
1487 hotline.NewField(hotline.FieldUserLogin, hotline.EncodeString([]byte("testuser"))),
1490 wantRes: []hotline.Transaction{
1494 Type: [2]byte{0, 0},
1495 Fields: []hotline.Field(nil),
1500 name: "when user does not have required permission",
1502 cc: &hotline.ClientConn{
1503 Account: &hotline.Account{
1504 Access: hotline.AccessBitmap{},
1506 Server: &hotline.Server{
1507 //Accounts: map[string]*Account{},
1510 t: hotline.NewTransaction(
1511 hotline.TranDeleteUser, [2]byte{0, 1},
1512 hotline.NewField(hotline.FieldUserLogin, hotline.EncodeString([]byte("testuser"))),
1515 wantRes: []hotline.Transaction{
1518 ErrorCode: [4]byte{0, 0, 0, 1},
1519 Fields: []hotline.Field{
1520 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete accounts.")),
1526 for _, tt := range tests {
1527 t.Run(tt.name, func(t *testing.T) {
1528 gotRes := HandleDeleteUser(tt.args.cc, &tt.args.t)
1529 TranAssertEqual(t, tt.wantRes, gotRes)
1534 func TestHandleGetMsgs(t *testing.T) {
1536 cc *hotline.ClientConn
1537 t hotline.Transaction
1542 wantRes []hotline.Transaction
1545 name: "returns news data",
1547 cc: &hotline.ClientConn{
1548 Account: &hotline.Account{
1549 Access: func() hotline.AccessBitmap {
1550 var bits hotline.AccessBitmap
1551 bits.Set(hotline.AccessNewsReadArt)
1555 Server: &hotline.Server{
1556 MessageBoard: func() *mockReadWriteSeeker {
1557 m := mockReadWriteSeeker{}
1558 m.On("Seek", int64(0), 0).Return(int64(0), nil)
1559 m.On("Read", mock.AnythingOfType("[]uint8")).Run(func(args mock.Arguments) {
1560 arg := args.Get(0).([]uint8)
1562 }).Return(4, io.EOF)
1567 t: hotline.NewTransaction(
1568 hotline.TranGetMsgs, [2]byte{0, 1},
1571 wantRes: []hotline.Transaction{
1574 Fields: []hotline.Field{
1575 hotline.NewField(hotline.FieldData, []byte("TEST")),
1581 name: "when user does not have required permission",
1583 cc: &hotline.ClientConn{
1584 Account: &hotline.Account{
1585 Access: hotline.AccessBitmap{},
1587 Server: &hotline.Server{
1588 //Accounts: map[string]*Account{},
1591 t: hotline.NewTransaction(
1592 hotline.TranGetMsgs, [2]byte{0, 1},
1595 wantRes: []hotline.Transaction{
1598 ErrorCode: [4]byte{0, 0, 0, 1},
1599 Fields: []hotline.Field{
1600 hotline.NewField(hotline.FieldError, []byte("You are not allowed to read news.")),
1606 for _, tt := range tests {
1607 t.Run(tt.name, func(t *testing.T) {
1608 gotRes := HandleGetMsgs(tt.args.cc, &tt.args.t)
1609 TranAssertEqual(t, tt.wantRes, gotRes)
1614 func TestHandleNewUser(t *testing.T) {
1616 cc *hotline.ClientConn
1617 t hotline.Transaction
1622 wantRes []hotline.Transaction
1625 name: "when user does not have required permission",
1627 cc: &hotline.ClientConn{
1628 Account: &hotline.Account{
1629 Access: func() hotline.AccessBitmap {
1630 var bits hotline.AccessBitmap
1634 Server: &hotline.Server{
1635 //Accounts: map[string]*Account{},
1638 t: hotline.NewTransaction(
1639 hotline.TranNewUser, [2]byte{0, 1},
1642 wantRes: []hotline.Transaction{
1645 ErrorCode: [4]byte{0, 0, 0, 1},
1646 Fields: []hotline.Field{
1647 hotline.NewField(hotline.FieldError, []byte("You are not allowed to create new accounts.")),
1653 name: "when user attempts to create account with greater access",
1655 cc: &hotline.ClientConn{
1656 Account: &hotline.Account{
1657 Access: func() hotline.AccessBitmap {
1658 var bits hotline.AccessBitmap
1659 bits.Set(hotline.AccessCreateUser)
1663 Server: &hotline.Server{
1664 AccountManager: func() *MockAccountManager {
1665 m := MockAccountManager{}
1666 m.On("Get", "userB").Return((*hotline.Account)(nil))
1671 t: hotline.NewTransaction(
1672 hotline.TranNewUser, [2]byte{0, 1},
1673 hotline.NewField(hotline.FieldUserLogin, hotline.EncodeString([]byte("userB"))),
1675 hotline.FieldUserAccess,
1677 var bits hotline.AccessBitmap
1678 bits.Set(hotline.AccessDisconUser)
1684 wantRes: []hotline.Transaction{
1687 ErrorCode: [4]byte{0, 0, 0, 1},
1688 Fields: []hotline.Field{
1689 hotline.NewField(hotline.FieldError, []byte("Cannot create account with more access than yourself.")),
1695 for _, tt := range tests {
1696 t.Run(tt.name, func(t *testing.T) {
1697 gotRes := HandleNewUser(tt.args.cc, &tt.args.t)
1698 TranAssertEqual(t, tt.wantRes, gotRes)
1703 func TestHandleListUsers(t *testing.T) {
1705 cc *hotline.ClientConn
1706 t hotline.Transaction
1711 wantRes []hotline.Transaction
1714 name: "when user does not have required permission",
1716 cc: &hotline.ClientConn{
1717 Account: &hotline.Account{
1718 Access: func() hotline.AccessBitmap {
1719 var bits hotline.AccessBitmap
1723 Server: &hotline.Server{
1724 //Accounts: map[string]*Account{},
1727 t: hotline.NewTransaction(
1728 hotline.TranNewUser, [2]byte{0, 1},
1731 wantRes: []hotline.Transaction{
1734 ErrorCode: [4]byte{0, 0, 0, 1},
1735 Fields: []hotline.Field{
1736 hotline.NewField(hotline.FieldError, []byte("You are not allowed to view accounts.")),
1742 name: "when user has required permission",
1744 cc: &hotline.ClientConn{
1745 Account: &hotline.Account{
1746 Access: func() hotline.AccessBitmap {
1747 var bits hotline.AccessBitmap
1748 bits.Set(hotline.AccessOpenUser)
1752 Server: &hotline.Server{
1753 AccountManager: func() *MockAccountManager {
1754 m := MockAccountManager{}
1755 m.On("List").Return([]hotline.Account{
1760 Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
1767 t: hotline.NewTransaction(
1768 hotline.TranGetClientInfoText, [2]byte{0, 1},
1769 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
1772 wantRes: []hotline.Transaction{
1775 Fields: []hotline.Field{
1776 hotline.NewField(hotline.FieldData, []byte{
1777 0x00, 0x04, 0x00, 0x66, 0x00, 0x05, 0x67, 0x75, 0x65, 0x73, 0x74, 0x00, 0x69, 0x00, 0x05, 0x98,
1778 0x8a, 0x9a, 0x8c, 0x8b, 0x00, 0x6e, 0x00, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1779 0x00, 0x6a, 0x00, 0x01, 0x78,
1786 for _, tt := range tests {
1787 t.Run(tt.name, func(t *testing.T) {
1788 gotRes := HandleListUsers(tt.args.cc, &tt.args.t)
1790 TranAssertEqual(t, tt.wantRes, gotRes)
1795 func TestHandleDownloadFile(t *testing.T) {
1797 cc *hotline.ClientConn
1798 t hotline.Transaction
1803 wantRes []hotline.Transaction
1806 name: "when user does not have required permission",
1808 cc: &hotline.ClientConn{
1809 Account: &hotline.Account{
1810 Access: func() hotline.AccessBitmap {
1811 var bits hotline.AccessBitmap
1815 Server: &hotline.Server{},
1817 t: hotline.NewTransaction(hotline.TranDownloadFile, [2]byte{0, 1}),
1819 wantRes: []hotline.Transaction{
1822 ErrorCode: [4]byte{0, 0, 0, 1},
1823 Fields: []hotline.Field{
1824 hotline.NewField(hotline.FieldError, []byte("You are not allowed to download files.")),
1830 name: "with a valid file",
1832 cc: &hotline.ClientConn{
1833 ClientFileTransferMgr: hotline.NewClientFileTransferMgr(),
1834 Account: &hotline.Account{
1835 Access: func() hotline.AccessBitmap {
1836 var bits hotline.AccessBitmap
1837 bits.Set(hotline.AccessDownloadFile)
1841 Server: &hotline.Server{
1842 FS: &hotline.OSFileStore{},
1843 FileTransferMgr: hotline.NewMemFileTransferMgr(),
1844 Config: hotline.Config{
1845 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1849 t: hotline.NewTransaction(
1850 hotline.TranDownloadFile,
1852 hotline.NewField(hotline.FieldFileName, []byte("testfile.txt")),
1853 hotline.NewField(hotline.FieldFilePath, []byte{0x0, 0x00}),
1856 wantRes: []hotline.Transaction{
1859 Fields: []hotline.Field{
1860 hotline.NewField(hotline.FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1861 hotline.NewField(hotline.FieldWaitingCount, []byte{0x00, 0x00}),
1862 hotline.NewField(hotline.FieldTransferSize, []byte{0x00, 0x00, 0x00, 0xa5}),
1863 hotline.NewField(hotline.FieldFileSize, []byte{0x00, 0x00, 0x00, 0x17}),
1869 name: "when client requests to resume 1k test file at offset 256",
1871 cc: &hotline.ClientConn{
1872 ClientFileTransferMgr: hotline.NewClientFileTransferMgr(),
1873 Account: &hotline.Account{
1874 Access: func() hotline.AccessBitmap {
1875 var bits hotline.AccessBitmap
1876 bits.Set(hotline.AccessDownloadFile)
1880 Server: &hotline.Server{
1881 FS: &hotline.OSFileStore{},
1883 // FS: func() *hotline.MockFileStore {
1884 // path, _ := os.Getwd()
1885 // testFile, err := os.Open(path + "/test/config/Files/testfile-1k")
1890 // mfi := &hotline.MockFileInfo{}
1891 // mfi.On("Mode").Return(fs.FileMode(0))
1892 // mfs := &MockFileStore{}
1893 // mfs.On("Stat", "/fakeRoot/Files/testfile.txt").Return(mfi, nil)
1894 // mfs.On("Open", "/fakeRoot/Files/testfile.txt").Return(testFile, nil)
1895 // mfs.On("Stat", "/fakeRoot/Files/.info_testfile.txt").Return(nil, errors.New("no"))
1896 // mfs.On("Stat", "/fakeRoot/Files/.rsrc_testfile.txt").Return(nil, errors.New("no"))
1900 FileTransferMgr: hotline.NewMemFileTransferMgr(),
1901 Config: hotline.Config{
1902 FileRoot: func() string { path, _ := os.Getwd(); return path + "/test/config/Files" }(),
1904 //Accounts: map[string]*Account{},
1907 t: hotline.NewTransaction(
1908 hotline.TranDownloadFile,
1910 hotline.NewField(hotline.FieldFileName, []byte("testfile-1k")),
1911 hotline.NewField(hotline.FieldFilePath, []byte{0x00, 0x00}),
1913 hotline.FieldFileResumeData,
1915 frd := hotline.FileResumeData{
1916 ForkCount: [2]byte{0, 2},
1917 ForkInfoList: []hotline.ForkInfoList{
1919 Fork: [4]byte{0x44, 0x41, 0x54, 0x41}, // "DATA"
1920 DataSize: [4]byte{0, 0, 0x01, 0x00}, // request offset 256
1923 Fork: [4]byte{0x4d, 0x41, 0x43, 0x52}, // "MACR"
1924 DataSize: [4]byte{0, 0, 0, 0},
1928 b, _ := frd.BinaryMarshal()
1934 wantRes: []hotline.Transaction{
1937 Fields: []hotline.Field{
1938 hotline.NewField(hotline.FieldRefNum, []byte{0x52, 0xfd, 0xfc, 0x07}),
1939 hotline.NewField(hotline.FieldWaitingCount, []byte{0x00, 0x00}),
1940 hotline.NewField(hotline.FieldTransferSize, []byte{0x00, 0x00, 0x03, 0x8d}),
1941 hotline.NewField(hotline.FieldFileSize, []byte{0x00, 0x00, 0x03, 0x00}),
1947 for _, tt := range tests {
1948 t.Run(tt.name, func(t *testing.T) {
1949 gotRes := HandleDownloadFile(tt.args.cc, &tt.args.t)
1950 TranAssertEqual(t, tt.wantRes, gotRes)
1955 func TestHandleUpdateUser(t *testing.T) {
1957 cc *hotline.ClientConn
1958 t hotline.Transaction
1963 wantRes []hotline.Transaction
1966 name: "when action is create user without required permission",
1968 cc: &hotline.ClientConn{
1969 Logger: NewTestLogger(),
1970 Server: &hotline.Server{
1971 AccountManager: func() *MockAccountManager {
1972 m := MockAccountManager{}
1973 m.On("Get", "bbb").Return((*hotline.Account)(nil))
1976 Logger: NewTestLogger(),
1978 Account: &hotline.Account{
1979 Access: hotline.AccessBitmap{},
1982 t: hotline.NewTransaction(
1983 hotline.TranUpdateUser,
1985 hotline.NewField(hotline.FieldData, []byte{
1986 0x00, 0x04, // field count
1988 0x00, 0x69, // FieldUserLogin = 105
1992 0x00, 0x6a, // FieldUserPassword = 106
1996 0x00, 0x66, // FieldUserName = 102
2000 0x00, 0x6e, // FieldUserAccess = 110
2002 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2006 wantRes: []hotline.Transaction{
2009 ErrorCode: [4]byte{0, 0, 0, 1},
2010 Fields: []hotline.Field{
2011 hotline.NewField(hotline.FieldError, []byte("You are not allowed to create new accounts.")),
2017 name: "when action is modify user without required permission",
2019 cc: &hotline.ClientConn{
2020 Logger: NewTestLogger(),
2021 Server: &hotline.Server{
2022 Logger: NewTestLogger(),
2023 AccountManager: func() *MockAccountManager {
2024 m := MockAccountManager{}
2025 m.On("Get", "bbb").Return(&hotline.Account{})
2029 Account: &hotline.Account{
2030 Access: func() hotline.AccessBitmap {
2031 var bits hotline.AccessBitmap
2036 t: hotline.NewTransaction(
2037 hotline.TranUpdateUser,
2039 hotline.NewField(hotline.FieldData, []byte{
2040 0x00, 0x04, // field count
2042 0x00, 0x69, // FieldUserLogin = 105
2046 0x00, 0x6a, // FieldUserPassword = 106
2050 0x00, 0x66, // FieldUserName = 102
2054 0x00, 0x6e, // FieldUserAccess = 110
2056 0x60, 0x70, 0x0c, 0x20, 0x03, 0x80, 0x00, 0x00,
2060 wantRes: []hotline.Transaction{
2063 ErrorCode: [4]byte{0, 0, 0, 1},
2064 Fields: []hotline.Field{
2065 hotline.NewField(hotline.FieldError, []byte("You are not allowed to modify accounts.")),
2071 name: "when action is delete user without required permission",
2073 cc: &hotline.ClientConn{
2074 Logger: NewTestLogger(),
2075 Server: &hotline.Server{},
2076 Account: &hotline.Account{
2077 Access: hotline.AccessBitmap{},
2080 t: hotline.NewTransaction(
2081 hotline.TranUpdateUser,
2083 hotline.NewField(hotline.FieldData, []byte{
2091 wantRes: []hotline.Transaction{
2094 ErrorCode: [4]byte{0, 0, 0, 1},
2095 Fields: []hotline.Field{
2096 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete accounts.")),
2102 for _, tt := range tests {
2103 t.Run(tt.name, func(t *testing.T) {
2104 gotRes := HandleUpdateUser(tt.args.cc, &tt.args.t)
2105 TranAssertEqual(t, tt.wantRes, gotRes)
2110 func TestHandleDelNewsArt(t *testing.T) {
2112 cc *hotline.ClientConn
2113 t hotline.Transaction
2118 wantRes []hotline.Transaction
2121 name: "without required permission",
2123 cc: &hotline.ClientConn{
2124 Account: &hotline.Account{
2125 Access: func() hotline.AccessBitmap {
2126 var bits hotline.AccessBitmap
2131 t: hotline.NewTransaction(
2132 hotline.TranDelNewsArt,
2136 wantRes: []hotline.Transaction{
2139 ErrorCode: [4]byte{0, 0, 0, 1},
2140 Fields: []hotline.Field{
2141 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete news articles.")),
2147 for _, tt := range tests {
2148 t.Run(tt.name, func(t *testing.T) {
2149 gotRes := HandleDelNewsArt(tt.args.cc, &tt.args.t)
2150 TranAssertEqual(t, tt.wantRes, gotRes)
2155 func TestHandleDisconnectUser(t *testing.T) {
2157 cc *hotline.ClientConn
2158 t hotline.Transaction
2163 wantRes []hotline.Transaction
2166 name: "without required permission",
2168 cc: &hotline.ClientConn{
2169 Account: &hotline.Account{
2170 Access: func() hotline.AccessBitmap {
2171 var bits hotline.AccessBitmap
2176 t: hotline.NewTransaction(
2177 hotline.TranDelNewsArt,
2181 wantRes: []hotline.Transaction{
2184 ErrorCode: [4]byte{0, 0, 0, 1},
2185 Fields: []hotline.Field{
2186 hotline.NewField(hotline.FieldError, []byte("You are not allowed to disconnect users.")),
2192 name: "when target user has 'cannot be disconnected' priv",
2194 cc: &hotline.ClientConn{
2195 Server: &hotline.Server{
2196 ClientMgr: func() *hotline.MockClientMgr {
2197 m := hotline.MockClientMgr{}
2198 m.On("Get", hotline.ClientID{0x0, 0x1}).Return(&hotline.ClientConn{
2199 Account: &hotline.Account{
2201 Access: func() hotline.AccessBitmap {
2202 var bits hotline.AccessBitmap
2203 bits.Set(hotline.AccessCannotBeDiscon)
2212 Account: &hotline.Account{
2213 Access: func() hotline.AccessBitmap {
2214 var bits hotline.AccessBitmap
2215 bits.Set(hotline.AccessDisconUser)
2220 t: hotline.NewTransaction(
2221 hotline.TranDelNewsArt,
2223 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
2226 wantRes: []hotline.Transaction{
2229 ErrorCode: [4]byte{0, 0, 0, 1},
2230 Fields: []hotline.Field{
2231 hotline.NewField(hotline.FieldError, []byte("unnamed is not allowed to be disconnected.")),
2237 for _, tt := range tests {
2238 t.Run(tt.name, func(t *testing.T) {
2239 gotRes := HandleDisconnectUser(tt.args.cc, &tt.args.t)
2240 TranAssertEqual(t, tt.wantRes, gotRes)
2245 func TestHandleSendInstantMsg(t *testing.T) {
2247 cc *hotline.ClientConn
2248 t hotline.Transaction
2253 wantRes []hotline.Transaction
2256 name: "without required permission",
2258 cc: &hotline.ClientConn{
2259 Account: &hotline.Account{
2260 Access: func() hotline.AccessBitmap {
2261 var bits hotline.AccessBitmap
2266 t: hotline.NewTransaction(
2267 hotline.TranDelNewsArt,
2271 wantRes: []hotline.Transaction{
2274 ErrorCode: [4]byte{0, 0, 0, 1},
2275 Fields: []hotline.Field{
2276 hotline.NewField(hotline.FieldError, []byte("You are not allowed to send private messages.")),
2282 name: "when client 1 sends a message to client 2",
2284 cc: &hotline.ClientConn{
2285 Account: &hotline.Account{
2286 Access: func() hotline.AccessBitmap {
2287 var bits hotline.AccessBitmap
2288 bits.Set(hotline.AccessSendPrivMsg)
2293 UserName: []byte("User1"),
2294 Server: &hotline.Server{
2295 ClientMgr: func() *hotline.MockClientMgr {
2296 m := hotline.MockClientMgr{}
2297 m.On("Get", hotline.ClientID{0x0, 0x2}).Return(&hotline.ClientConn{
2298 AutoReply: []byte(nil),
2299 Flags: [2]byte{0, 0},
2306 t: hotline.NewTransaction(
2307 hotline.TranSendInstantMsg,
2309 hotline.NewField(hotline.FieldData, []byte("hai")),
2310 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2313 wantRes: []hotline.Transaction{
2314 hotline.NewTransaction(
2315 hotline.TranServerMsg,
2317 hotline.NewField(hotline.FieldData, []byte("hai")),
2318 hotline.NewField(hotline.FieldUserName, []byte("User1")),
2319 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
2320 hotline.NewField(hotline.FieldOptions, []byte{0, 1}),
2323 ClientID: [2]byte{0, 1},
2325 Fields: []hotline.Field(nil),
2330 name: "when client 2 has autoreply enabled",
2332 cc: &hotline.ClientConn{
2333 Account: &hotline.Account{
2334 Access: func() hotline.AccessBitmap {
2335 var bits hotline.AccessBitmap
2336 bits.Set(hotline.AccessSendPrivMsg)
2341 UserName: []byte("User1"),
2342 Server: &hotline.Server{
2343 ClientMgr: func() *hotline.MockClientMgr {
2344 m := hotline.MockClientMgr{}
2345 m.On("Get", hotline.ClientID{0x0, 0x2}).Return(&hotline.ClientConn{
2346 Flags: [2]byte{0, 0},
2348 UserName: []byte("User2"),
2349 AutoReply: []byte("autohai"),
2355 t: hotline.NewTransaction(
2356 hotline.TranSendInstantMsg,
2358 hotline.NewField(hotline.FieldData, []byte("hai")),
2359 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2362 wantRes: []hotline.Transaction{
2363 hotline.NewTransaction(
2364 hotline.TranServerMsg,
2366 hotline.NewField(hotline.FieldData, []byte("hai")),
2367 hotline.NewField(hotline.FieldUserName, []byte("User1")),
2368 hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
2369 hotline.NewField(hotline.FieldOptions, []byte{0, 1}),
2371 hotline.NewTransaction(
2372 hotline.TranServerMsg,
2374 hotline.NewField(hotline.FieldData, []byte("autohai")),
2375 hotline.NewField(hotline.FieldUserName, []byte("User2")),
2376 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2377 hotline.NewField(hotline.FieldOptions, []byte{0, 1}),
2380 ClientID: [2]byte{0, 1},
2382 Fields: []hotline.Field(nil),
2387 name: "when client 2 has refuse private messages enabled",
2389 cc: &hotline.ClientConn{
2390 Account: &hotline.Account{
2391 Access: func() hotline.AccessBitmap {
2392 var bits hotline.AccessBitmap
2393 bits.Set(hotline.AccessSendPrivMsg)
2398 UserName: []byte("User1"),
2399 Server: &hotline.Server{
2400 ClientMgr: func() *hotline.MockClientMgr {
2401 m := hotline.MockClientMgr{}
2402 m.On("Get", hotline.ClientID{0x0, 0x2}).Return(&hotline.ClientConn{
2403 Flags: [2]byte{255, 255},
2405 UserName: []byte("User2"),
2412 t: hotline.NewTransaction(
2413 hotline.TranSendInstantMsg,
2415 hotline.NewField(hotline.FieldData, []byte("hai")),
2416 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2419 wantRes: []hotline.Transaction{
2420 hotline.NewTransaction(
2421 hotline.TranServerMsg,
2423 hotline.NewField(hotline.FieldData, []byte("User2 does not accept private messages.")),
2424 hotline.NewField(hotline.FieldUserName, []byte("User2")),
2425 hotline.NewField(hotline.FieldUserID, []byte{0, 2}),
2426 hotline.NewField(hotline.FieldOptions, []byte{0, 2}),
2429 ClientID: [2]byte{0, 1},
2431 Fields: []hotline.Field(nil),
2436 for _, tt := range tests {
2437 t.Run(tt.name, func(t *testing.T) {
2438 gotRes := HandleSendInstantMsg(tt.args.cc, &tt.args.t)
2439 TranAssertEqual(t, tt.wantRes, gotRes)
2444 func TestHandleDeleteFile(t *testing.T) {
2446 cc *hotline.ClientConn
2447 t hotline.Transaction
2452 wantRes []hotline.Transaction
2455 name: "when user does not have required permission to delete a folder",
2457 cc: &hotline.ClientConn{
2458 Account: &hotline.Account{
2459 Access: func() hotline.AccessBitmap {
2460 var bits hotline.AccessBitmap
2464 Server: &hotline.Server{
2465 Config: hotline.Config{
2466 FileRoot: func() string {
2467 return "/fakeRoot/Files"
2470 FS: func() *hotline.MockFileStore {
2471 mfi := &hotline.MockFileInfo{}
2472 mfi.On("Mode").Return(fs.FileMode(0))
2473 mfi.On("Size").Return(int64(100))
2474 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2475 mfi.On("IsDir").Return(false)
2476 mfi.On("Name").Return("testfile")
2478 mfs := &hotline.MockFileStore{}
2479 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2480 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2481 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2485 //Accounts: map[string]*Account{},
2488 t: hotline.NewTransaction(
2489 hotline.TranDeleteFile, [2]byte{0, 1},
2490 hotline.NewField(hotline.FieldFileName, []byte("testfile")),
2491 hotline.NewField(hotline.FieldFilePath, []byte{
2499 wantRes: []hotline.Transaction{
2502 ErrorCode: [4]byte{0, 0, 0, 1},
2503 Fields: []hotline.Field{
2504 hotline.NewField(hotline.FieldError, []byte("You are not allowed to delete files.")),
2510 name: "deletes all associated metadata files",
2512 cc: &hotline.ClientConn{
2513 Account: &hotline.Account{
2514 Access: func() hotline.AccessBitmap {
2515 var bits hotline.AccessBitmap
2516 bits.Set(hotline.AccessDeleteFile)
2520 Server: &hotline.Server{
2521 Config: hotline.Config{
2522 FileRoot: func() string {
2523 return "/fakeRoot/Files"
2526 FS: func() *hotline.MockFileStore {
2527 mfi := &hotline.MockFileInfo{}
2528 mfi.On("Mode").Return(fs.FileMode(0))
2529 mfi.On("Size").Return(int64(100))
2530 mfi.On("ModTime").Return(time.Parse(time.Layout, time.Layout))
2531 mfi.On("IsDir").Return(false)
2532 mfi.On("Name").Return("testfile")
2534 mfs := &hotline.MockFileStore{}
2535 mfs.On("Stat", "/fakeRoot/Files/aaa/testfile").Return(mfi, nil)
2536 mfs.On("Stat", "/fakeRoot/Files/aaa/.info_testfile").Return(nil, errors.New("err"))
2537 mfs.On("Stat", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil, errors.New("err"))
2539 mfs.On("RemoveAll", "/fakeRoot/Files/aaa/testfile").Return(nil)
2540 mfs.On("Remove", "/fakeRoot/Files/aaa/testfile.incomplete").Return(nil)
2541 mfs.On("Remove", "/fakeRoot/Files/aaa/.rsrc_testfile").Return(nil)
2542 mfs.On("Remove", "/fakeRoot/Files/aaa/.info_testfile").Return(nil)
2546 //Accounts: map[string]*Account{},
2549 t: hotline.NewTransaction(
2550 hotline.TranDeleteFile, [2]byte{0, 1},
2551 hotline.NewField(hotline.FieldFileName, []byte("testfile")),
2552 hotline.NewField(hotline.FieldFilePath, []byte{
2560 wantRes: []hotline.Transaction{
2563 Fields: []hotline.Field(nil),
2568 for _, tt := range tests {
2569 t.Run(tt.name, func(t *testing.T) {
2570 gotRes := HandleDeleteFile(tt.args.cc, &tt.args.t)
2571 TranAssertEqual(t, tt.wantRes, gotRes)
2573 tt.args.cc.Server.FS.(*hotline.MockFileStore).AssertExpectations(t)
2578 func TestHandleGetFileNameList(t *testing.T) {
2580 cc *hotline.ClientConn
2581 t hotline.Transaction
2586 wantRes []hotline.Transaction
2589 name: "when FieldFilePath is a drop box, but user does not have AccessViewDropBoxes ",
2591 cc: &hotline.ClientConn{
2592 Account: &hotline.Account{
2593 Access: func() hotline.AccessBitmap {
2594 var bits hotline.AccessBitmap
2598 Server: &hotline.Server{
2600 Config: hotline.Config{
2601 FileRoot: func() string {
2602 path, _ := os.Getwd()
2603 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
2608 t: hotline.NewTransaction(
2609 hotline.TranGetFileNameList, [2]byte{0, 1},
2610 hotline.NewField(hotline.FieldFilePath, []byte{
2614 0x64, 0x72, 0x6f, 0x70, 0x20, 0x62, 0x6f, 0x78, // "drop box"
2618 wantRes: []hotline.Transaction{
2621 ErrorCode: [4]byte{0, 0, 0, 1},
2622 Fields: []hotline.Field{
2623 hotline.NewField(hotline.FieldError, []byte("You are not allowed to view drop boxes.")),
2629 name: "with file root",
2631 cc: &hotline.ClientConn{
2632 Server: &hotline.Server{
2633 Config: hotline.Config{
2634 FileRoot: func() string {
2635 path, _ := os.Getwd()
2636 return filepath.Join(path, "/test/config/Files/getFileNameListTestDir")
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))