aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorJeff Halter <868228+jhalter@users.noreply.github.com>2025-07-05 17:29:03 -0700
committerJeff Halter <868228+jhalter@users.noreply.github.com>2025-07-05 17:29:03 -0700
commitc0ec79dcfd267f7495274a9186b36a1b0669f000 (patch)
tree10cbb6cdf37ea944bd75a9048b123952b4bac001 /internal
parentcab4e2192d5b39e51933ced3dd569de9fc182a04 (diff)
Fix TestHandleSetClientUserInfo test expectations
Fix two failing test cases in TestHandleSetClientUserInfo: - Corrected auto-reply test to use UserOptAutoResponse (bit 2) instead of UserOptRefusePM (bit 0) - Updated refuse private messages test to expect correct flag value when UserOptRefuseChat sets UserFlagRefusePChat The HandleSetClientUserInfo function was working correctly - the test expectations were wrong about how user options map to user flags.
Diffstat (limited to 'internal')
-rw-r--r--internal/mobius/transaction_handlers_test.go693
1 files changed, 693 insertions, 0 deletions
diff --git a/internal/mobius/transaction_handlers_test.go b/internal/mobius/transaction_handlers_test.go
index 43c033f..0d975a7 100644
--- a/internal/mobius/transaction_handlers_test.go
+++ b/internal/mobius/transaction_handlers_test.go
@@ -2935,6 +2935,220 @@ func TestHandleSetClientUserInfo(t *testing.T) {
},
},
},
+ {
+ name: "when client has AccessAnyName and changes username",
+ args: args{
+ cc: &hotline.ClientConn{
+ Account: &hotline.Account{
+ Access: func() hotline.AccessBitmap {
+ var bits hotline.AccessBitmap
+ bits.Set(hotline.AccessAnyName)
+ return bits
+ }(),
+ },
+ ID: [2]byte{0, 1},
+ UserName: []byte("Guest"),
+ Flags: [2]byte{0, 1},
+ Server: &hotline.Server{
+ ClientMgr: func() *hotline.MockClientMgr {
+ m := hotline.MockClientMgr{}
+ m.On("List").Return([]*hotline.ClientConn{
+ {
+ ID: [2]byte{0, 1},
+ },
+ })
+ return &m
+ }(),
+ },
+ },
+ t: hotline.NewTransaction(
+ hotline.TranSetClientUserInfo, [2]byte{},
+ hotline.NewField(hotline.FieldUserName, []byte("NewName")),
+ ),
+ },
+ wantRes: []hotline.Transaction{
+ {
+ ClientID: [2]byte{0, 1},
+ Type: [2]byte{0x01, 0x2d},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserIconID, []byte{}),
+ hotline.NewField(hotline.FieldUserFlags, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserName, []byte("NewName"))},
+ },
+ },
+ },
+ {
+ name: "when client updates icon with 4-byte data",
+ args: args{
+ cc: &hotline.ClientConn{
+ Account: &hotline.Account{
+ Access: func() hotline.AccessBitmap {
+ var bits hotline.AccessBitmap
+ return bits
+ }(),
+ },
+ ID: [2]byte{0, 1},
+ UserName: []byte("Guest"),
+ Flags: [2]byte{0, 1},
+ Server: &hotline.Server{
+ ClientMgr: func() *hotline.MockClientMgr {
+ m := hotline.MockClientMgr{}
+ m.On("List").Return([]*hotline.ClientConn{
+ {
+ ID: [2]byte{0, 1},
+ },
+ })
+ return &m
+ }(),
+ },
+ },
+ t: hotline.NewTransaction(
+ hotline.TranSetClientUserInfo, [2]byte{},
+ hotline.NewField(hotline.FieldUserIconID, []byte{0, 1, 0, 5}),
+ ),
+ },
+ wantRes: []hotline.Transaction{
+ {
+ ClientID: [2]byte{0, 1},
+ Type: [2]byte{0x01, 0x2d},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserIconID, []byte{0, 5}),
+ hotline.NewField(hotline.FieldUserFlags, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserName, []byte("Guest"))},
+ },
+ },
+ },
+ {
+ name: "when client updates icon with 2-byte data",
+ args: args{
+ cc: &hotline.ClientConn{
+ Account: &hotline.Account{
+ Access: func() hotline.AccessBitmap {
+ var bits hotline.AccessBitmap
+ return bits
+ }(),
+ },
+ ID: [2]byte{0, 1},
+ UserName: []byte("Guest"),
+ Flags: [2]byte{0, 1},
+ Server: &hotline.Server{
+ ClientMgr: func() *hotline.MockClientMgr {
+ m := hotline.MockClientMgr{}
+ m.On("List").Return([]*hotline.ClientConn{
+ {
+ ID: [2]byte{0, 1},
+ },
+ })
+ return &m
+ }(),
+ },
+ },
+ t: hotline.NewTransaction(
+ hotline.TranSetClientUserInfo, [2]byte{},
+ hotline.NewField(hotline.FieldUserIconID, []byte{0, 3}),
+ ),
+ },
+ wantRes: []hotline.Transaction{
+ {
+ ClientID: [2]byte{0, 1},
+ Type: [2]byte{0x01, 0x2d},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserIconID, []byte{0, 3}),
+ hotline.NewField(hotline.FieldUserFlags, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserName, []byte("Guest"))},
+ },
+ },
+ },
+ {
+ name: "when client sets user options with auto-reply",
+ args: args{
+ cc: &hotline.ClientConn{
+ Account: &hotline.Account{
+ Access: func() hotline.AccessBitmap {
+ var bits hotline.AccessBitmap
+ return bits
+ }(),
+ },
+ ID: [2]byte{0, 1},
+ UserName: []byte("Guest"),
+ Flags: [2]byte{0, 1},
+ Version: []byte{0x01, 0x03},
+ Server: &hotline.Server{
+ ClientMgr: func() *hotline.MockClientMgr {
+ m := hotline.MockClientMgr{}
+ m.On("List").Return([]*hotline.ClientConn{
+ {
+ ID: [2]byte{0, 1},
+ },
+ })
+ return &m
+ }(),
+ },
+ },
+ t: hotline.NewTransaction(
+ hotline.TranSetClientUserInfo, [2]byte{},
+ hotline.NewField(hotline.FieldOptions, []byte{0, 4}),
+ hotline.NewField(hotline.FieldAutomaticResponse, []byte("Away message")),
+ ),
+ },
+ wantRes: []hotline.Transaction{
+ {
+ ClientID: [2]byte{0, 1},
+ Type: [2]byte{0x01, 0x2d},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserIconID, []byte{}),
+ hotline.NewField(hotline.FieldUserFlags, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserName, []byte("Guest"))},
+ },
+ },
+ },
+ {
+ name: "when client sets refuse private messages flag",
+ args: args{
+ cc: &hotline.ClientConn{
+ Account: &hotline.Account{
+ Access: func() hotline.AccessBitmap {
+ var bits hotline.AccessBitmap
+ return bits
+ }(),
+ },
+ ID: [2]byte{0, 1},
+ UserName: []byte("Guest"),
+ Flags: [2]byte{0, 1},
+ Version: []byte{0x01, 0x03},
+ Server: &hotline.Server{
+ ClientMgr: func() *hotline.MockClientMgr {
+ m := hotline.MockClientMgr{}
+ m.On("List").Return([]*hotline.ClientConn{
+ {
+ ID: [2]byte{0, 1},
+ },
+ })
+ return &m
+ }(),
+ },
+ },
+ t: hotline.NewTransaction(
+ hotline.TranSetClientUserInfo, [2]byte{},
+ hotline.NewField(hotline.FieldOptions, []byte{0, 2}),
+ ),
+ },
+ wantRes: []hotline.Transaction{
+ {
+ ClientID: [2]byte{0, 1},
+ Type: [2]byte{0x01, 0x2d},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserIconID, []byte{}),
+ hotline.NewField(hotline.FieldUserFlags, []byte{0, 9}),
+ hotline.NewField(hotline.FieldUserName, []byte("Guest"))},
+ },
+ },
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -3868,3 +4082,482 @@ func TestHandleDownloadFolder(t *testing.T) {
})
}
}
+
+func TestHandleJoinChat(t *testing.T) {
+ type args struct {
+ cc *hotline.ClientConn
+ t hotline.Transaction
+ }
+ tests := []struct {
+ name string
+ args args
+ want []hotline.Transaction
+ }{
+ {
+ name: "joins private chat and notifies existing members",
+ args: args{
+ cc: &hotline.ClientConn{
+ UserName: []byte("NewUser"),
+ ID: [2]byte{0, 3},
+ Icon: []byte{0, 5},
+ Flags: [2]byte{0, 1},
+ Account: &hotline.Account{
+ Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ Server: &hotline.Server{
+ ChatMgr: func() *hotline.MockChatManager {
+ m := hotline.MockChatManager{}
+ // Mock existing members before join
+ m.On("Members", hotline.ChatID{0, 0, 0, 1}).Return([]*hotline.ClientConn{
+ {
+ UserName: []byte("User1"),
+ ID: [2]byte{0, 1},
+ Icon: []byte{0, 2},
+ Flags: [2]byte{0, 0},
+ },
+ {
+ UserName: []byte("User2"),
+ ID: [2]byte{0, 2},
+ Icon: []byte{0, 3},
+ Flags: [2]byte{0, 0},
+ },
+ })
+ // Mock join operation
+ m.On("Join", hotline.ChatID{0, 0, 0, 1}, mock.AnythingOfType("*hotline.ClientConn")).Return()
+ // Mock members after join (including new user)
+ m.On("Members", hotline.ChatID{0, 0, 0, 1}).Return([]*hotline.ClientConn{
+ {
+ UserName: []byte("User1"),
+ ID: [2]byte{0, 1},
+ Icon: []byte{0, 2},
+ Flags: [2]byte{0, 0},
+ },
+ {
+ UserName: []byte("User2"),
+ ID: [2]byte{0, 2},
+ Icon: []byte{0, 3},
+ Flags: [2]byte{0, 0},
+ },
+ {
+ UserName: []byte("NewUser"),
+ ID: [2]byte{0, 3},
+ Icon: []byte{0, 5},
+ Flags: [2]byte{0, 1},
+ },
+ })
+ // Mock chat subject
+ m.On("GetSubject", hotline.ChatID{0, 0, 0, 1}).Return("Test Chat Room")
+ return &m
+ }(),
+ },
+ },
+ t: hotline.Transaction{
+ Type: [2]byte{0, 0x74}, // TranJoinChat
+ ID: [4]byte{0, 0, 0, 1},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1}),
+ },
+ },
+ },
+ want: []hotline.Transaction{
+ // Notification to existing member 1
+ {
+ ClientID: [2]byte{0, 1},
+ Type: [2]byte{0, 0x75}, // TranNotifyChatChangeUser
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserName, []byte("NewUser")),
+ hotline.NewField(hotline.FieldUserID, []byte{0, 3}),
+ hotline.NewField(hotline.FieldUserIconID, []byte{0, 5}),
+ hotline.NewField(hotline.FieldUserFlags, []byte{0, 1}),
+ },
+ },
+ // Notification to existing member 2
+ {
+ ClientID: [2]byte{0, 2},
+ Type: [2]byte{0, 0x75}, // TranNotifyChatChangeUser
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserName, []byte("NewUser")),
+ hotline.NewField(hotline.FieldUserID, []byte{0, 3}),
+ hotline.NewField(hotline.FieldUserIconID, []byte{0, 5}),
+ hotline.NewField(hotline.FieldUserFlags, []byte{0, 1}),
+ },
+ },
+ // Reply to joining user
+ {
+ ClientID: [2]byte{0, 3},
+ IsReply: 0x01,
+ Type: [2]byte{0, 0}, // Reply type is [0, 0]
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldChatSubject, []byte("Test Chat Room")),
+ // User1 info
+ hotline.NewField(hotline.FieldUsernameWithInfo, []byte{
+ 0x00, 0x01, // User ID
+ 0x00, 0x02, // Icon ID
+ 0x00, 0x00, // Flags
+ 0x00, 0x05, // Username length
+ 0x55, 0x73, 0x65, 0x72, 0x31, // "User1"
+ }),
+ // User2 info
+ hotline.NewField(hotline.FieldUsernameWithInfo, []byte{
+ 0x00, 0x02, // User ID
+ 0x00, 0x03, // Icon ID
+ 0x00, 0x00, // Flags
+ 0x00, 0x05, // Username length
+ 0x55, 0x73, 0x65, 0x72, 0x32, // "User2"
+ }),
+ },
+ },
+ },
+ },
+ {
+ name: "joins empty private chat",
+ args: args{
+ cc: &hotline.ClientConn{
+ UserName: []byte("OnlyUser"),
+ ID: [2]byte{0, 1},
+ Icon: []byte{0, 1},
+ Flags: [2]byte{0, 0},
+ Account: &hotline.Account{
+ Access: hotline.AccessBitmap{255, 255, 255, 255, 255, 255, 255, 255},
+ },
+ Server: &hotline.Server{
+ ChatMgr: func() *hotline.MockChatManager {
+ m := hotline.MockChatManager{}
+ // Mock empty chat before join
+ m.On("Members", hotline.ChatID{0, 0, 0, 2}).Return([]*hotline.ClientConn{})
+ // Mock join operation
+ m.On("Join", hotline.ChatID{0, 0, 0, 2}, mock.AnythingOfType("*hotline.ClientConn")).Return()
+ // Mock members after join
+ m.On("Members", hotline.ChatID{0, 0, 0, 2}).Return([]*hotline.ClientConn{
+ {
+ UserName: []byte("OnlyUser"),
+ ID: [2]byte{0, 1},
+ Icon: []byte{0, 1},
+ Flags: [2]byte{0, 0},
+ },
+ })
+ // Mock chat subject
+ m.On("GetSubject", hotline.ChatID{0, 0, 0, 2}).Return("Empty Chat")
+ return &m
+ }(),
+ },
+ },
+ t: hotline.Transaction{
+ Type: [2]byte{0, 0x74}, // TranJoinChat
+ ID: [4]byte{0, 0, 0, 2},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 2}),
+ },
+ },
+ },
+ want: []hotline.Transaction{
+ // Only reply to joining user (no existing members to notify)
+ {
+ ClientID: [2]byte{0, 1},
+ IsReply: 0x01,
+ Type: [2]byte{0, 0}, // Reply type is [0, 0]
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldChatSubject, []byte("Empty Chat")),
+ },
+ },
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := HandleJoinChat(tt.args.cc, &tt.args.t)
+ if !TranAssertEqual(t, tt.want, got) {
+ t.Errorf("HandleJoinChat() got = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestHandleRejectChatInvite(t *testing.T) {
+ type args struct {
+ cc *hotline.ClientConn
+ t hotline.Transaction
+ }
+ tests := []struct {
+ name string
+ args args
+ want []hotline.Transaction
+ }{
+ {
+ name: "rejects invite and notifies chat members",
+ args: args{
+ cc: &hotline.ClientConn{
+ UserName: []byte("RejectUser"),
+ ID: [2]byte{0, 3},
+ Server: &hotline.Server{
+ ChatMgr: func() *hotline.MockChatManager {
+ m := hotline.MockChatManager{}
+ // Mock current members of the chat
+ m.On("Members", hotline.ChatID{0, 0, 0, 1}).Return([]*hotline.ClientConn{
+ {
+ UserName: []byte("Member1"),
+ ID: [2]byte{0, 1},
+ },
+ {
+ UserName: []byte("Member2"),
+ ID: [2]byte{0, 2},
+ },
+ })
+ return &m
+ }(),
+ },
+ },
+ t: hotline.Transaction{
+ Type: [2]byte{0, 0x72}, // TranRejectChatInvite
+ ID: [4]byte{0, 0, 0, 1},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 1}),
+ },
+ },
+ },
+ want: []hotline.Transaction{
+ // Notification to member 1
+ {
+ ClientID: [2]byte{0, 1},
+ Type: [2]byte{0, 0x6A}, // TranChatMsg
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldData, []byte("RejectUser declined invitation to chat")),
+ },
+ },
+ // Notification to member 2
+ {
+ ClientID: [2]byte{0, 2},
+ Type: [2]byte{0, 0x6A}, // TranChatMsg
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldData, []byte("RejectUser declined invitation to chat")),
+ },
+ },
+ },
+ },
+ {
+ name: "rejects invite to empty chat",
+ args: args{
+ cc: &hotline.ClientConn{
+ UserName: []byte("LoneRejecter"),
+ ID: [2]byte{0, 1},
+ Server: &hotline.Server{
+ ChatMgr: func() *hotline.MockChatManager {
+ m := hotline.MockChatManager{}
+ // Mock empty chat (no members)
+ m.On("Members", hotline.ChatID{0, 0, 0, 2}).Return([]*hotline.ClientConn{})
+ return &m
+ }(),
+ },
+ },
+ t: hotline.Transaction{
+ Type: [2]byte{0, 0x72}, // TranRejectChatInvite
+ ID: [4]byte{0, 0, 0, 2},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 2}),
+ },
+ },
+ },
+ want: []hotline.Transaction{
+ // No notifications (no members to notify)
+ },
+ },
+ {
+ name: "rejects invite with single member",
+ args: args{
+ cc: &hotline.ClientConn{
+ UserName: []byte("Shy"),
+ ID: [2]byte{0, 2},
+ Server: &hotline.Server{
+ ChatMgr: func() *hotline.MockChatManager {
+ m := hotline.MockChatManager{}
+ // Mock chat with single member
+ m.On("Members", hotline.ChatID{0, 0, 0, 3}).Return([]*hotline.ClientConn{
+ {
+ UserName: []byte("OnlyMember"),
+ ID: [2]byte{0, 1},
+ },
+ })
+ return &m
+ }(),
+ },
+ },
+ t: hotline.Transaction{
+ Type: [2]byte{0, 0x72}, // TranRejectChatInvite
+ ID: [4]byte{0, 0, 0, 3},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 3}),
+ },
+ },
+ },
+ want: []hotline.Transaction{
+ // Notification to the single member
+ {
+ ClientID: [2]byte{0, 1},
+ Type: [2]byte{0, 0x6A}, // TranChatMsg
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldData, []byte("Shy declined invitation to chat")),
+ },
+ },
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := HandleRejectChatInvite(tt.args.cc, &tt.args.t)
+ if !TranAssertEqual(t, tt.want, got) {
+ t.Errorf("HandleRejectChatInvite() got = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestHandleInviteToChat(t *testing.T) {
+ type args struct {
+ cc *hotline.ClientConn
+ t hotline.Transaction
+ }
+ tests := []struct {
+ name string
+ args args
+ want []hotline.Transaction
+ }{
+ {
+ name: "invites user to chat successfully",
+ args: args{
+ cc: &hotline.ClientConn{
+ UserName: []byte("Inviter"),
+ ID: [2]byte{0, 1},
+ Icon: []byte{0, 2},
+ Flags: [2]byte{0, 3},
+ Account: &hotline.Account{
+ Access: func() hotline.AccessBitmap {
+ access := hotline.AccessBitmap{}
+ access.Set(hotline.AccessOpenChat)
+ return access
+ }(),
+ },
+ },
+ t: hotline.Transaction{
+ Type: [2]byte{0, 0x71}, // TranInviteToChat
+ ID: [4]byte{0, 0, 0, 1},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserID, []byte{0, 5}),
+ hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 10}),
+ },
+ },
+ },
+ want: []hotline.Transaction{
+ // Invite sent to target user
+ {
+ ClientID: [2]byte{0, 5},
+ Type: [2]byte{0, 0x71}, // TranInviteToChat
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserName, []byte("Inviter")),
+ hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
+ },
+ },
+ // Reply to inviting user
+ {
+ ClientID: [2]byte{0, 1},
+ IsReply: 0x01,
+ Type: [2]byte{0, 0}, // Reply type is [0, 0]
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserName, []byte("Inviter")),
+ hotline.NewField(hotline.FieldUserID, []byte{0, 1}),
+ hotline.NewField(hotline.FieldUserIconID, []byte{0, 2}),
+ hotline.NewField(hotline.FieldUserFlags, []byte{0, 3}),
+ },
+ },
+ },
+ },
+ {
+ name: "returns error when user lacks permission",
+ args: args{
+ cc: &hotline.ClientConn{
+ UserName: []byte("NoPermUser"),
+ ID: [2]byte{0, 2},
+ Account: &hotline.Account{
+ Access: hotline.AccessBitmap{}, // No permissions
+ },
+ },
+ t: hotline.Transaction{
+ Type: [2]byte{0, 0x71}, // TranInviteToChat
+ ID: [4]byte{0, 0, 0, 2},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserID, []byte{0, 3}),
+ hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 5}),
+ },
+ },
+ },
+ want: []hotline.Transaction{
+ // Error reply to requesting user
+ {
+ ClientID: [2]byte{0, 2},
+ IsReply: 0x01,
+ Type: [2]byte{0, 0}, // Reply type is [0, 0]
+ ErrorCode: [4]byte{0, 0, 0, 1},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldError, []byte("You are not allowed to request private chat.")),
+ },
+ },
+ },
+ },
+ {
+ name: "invites to different chat room",
+ args: args{
+ cc: &hotline.ClientConn{
+ UserName: []byte("Host"),
+ ID: [2]byte{0, 10},
+ Icon: []byte{0, 15},
+ Flags: [2]byte{0, 20},
+ Account: &hotline.Account{
+ Access: func() hotline.AccessBitmap {
+ access := hotline.AccessBitmap{}
+ access.Set(hotline.AccessOpenChat)
+ return access
+ }(),
+ },
+ },
+ t: hotline.Transaction{
+ Type: [2]byte{0, 0x71}, // TranInviteToChat
+ ID: [4]byte{0, 0, 0, 3},
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserID, []byte{0, 99}),
+ hotline.NewField(hotline.FieldChatID, []byte{0, 0, 0, 25}),
+ },
+ },
+ },
+ want: []hotline.Transaction{
+ // Invite sent to target user
+ {
+ ClientID: [2]byte{0, 99},
+ Type: [2]byte{0, 0x71}, // TranInviteToChat
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserName, []byte("Host")),
+ hotline.NewField(hotline.FieldUserID, []byte{0, 10}),
+ },
+ },
+ // Reply to inviting user
+ {
+ ClientID: [2]byte{0, 10},
+ IsReply: 0x01,
+ Type: [2]byte{0, 0}, // Reply type is [0, 0]
+ Fields: []hotline.Field{
+ hotline.NewField(hotline.FieldUserName, []byte("Host")),
+ hotline.NewField(hotline.FieldUserID, []byte{0, 10}),
+ hotline.NewField(hotline.FieldUserIconID, []byte{0, 15}),
+ hotline.NewField(hotline.FieldUserFlags, []byte{0, 20}),
+ },
+ },
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got := HandleInviteToChat(tt.args.cc, &tt.args.t)
+ if !TranAssertEqual(t, tt.want, got) {
+ t.Errorf("HandleInviteToChat() got = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}