test(channelserver): add handler tests for guild ops, scout, board, and items

Cover the 4 handler files that had no tests: handlers_guild_ops.go,
handlers_guild_scout.go, handlers_guild_board.go, and handlers_items.go.
44 new tests exercise the error-logging paths added in 8fe6f60 and the
core handler logic (disband, resign, apply, leave, accept/reject/kick,
scout answer, message board CRUD, weekly stamps, item box parsing).

New mock types: mockGuildRepoOps (enhanced guild repo with configurable
errors and state tracking), mockUserRepoForItems, mockStampRepoForItems,
mockHouseRepoForItems. Coverage rises from 41.1% to 43.7%.
This commit is contained in:
Houmgaor
2026-02-21 17:58:08 +01:00
parent 8fe6f60813
commit 7852e8505f
5 changed files with 1740 additions and 0 deletions

View File

@@ -0,0 +1,241 @@
package channelserver
import (
"testing"
"time"
"erupe-ce/network/mhfpacket"
)
// --- handleMsgMhfUpdateGuildMessageBoard tests ---
func TestUpdateGuildMessageBoard_CreatePost(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfUpdateGuildMessageBoard{
AckHandle: 100,
MessageOp: 0, // Create
PostType: 0,
StampID: 5,
Title: "Test Title",
Body: "Test Body",
}
handleMsgMhfUpdateGuildMessageBoard(session, pkt)
if guildMock.createdPost == nil {
t.Fatal("CreatePost should be called")
}
if guildMock.createdPost[0].(uint32) != 10 {
t.Errorf("CreatePost guildID = %d, want 10", guildMock.createdPost[0])
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestUpdateGuildMessageBoard_DeletePost(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfUpdateGuildMessageBoard{
AckHandle: 100,
MessageOp: 1, // Delete
PostID: 42,
}
handleMsgMhfUpdateGuildMessageBoard(session, pkt)
if guildMock.deletedPostID != 42 {
t.Errorf("DeletePost postID = %d, want 42", guildMock.deletedPostID)
}
}
func TestUpdateGuildMessageBoard_NoGuild(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
guildMock := &mockGuildRepoOps{}
guildMock.getErr = errNotFound
server.guildRepo = guildMock
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfUpdateGuildMessageBoard{
AckHandle: 100,
MessageOp: 0,
}
handleMsgMhfUpdateGuildMessageBoard(session, pkt)
// Returns early with empty success
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestUpdateGuildMessageBoard_Applicant(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
guildMock := &mockGuildRepoOps{
hasAppResult: true, // is an applicant
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 999
server.guildRepo = guildMock
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfUpdateGuildMessageBoard{
AckHandle: 100,
MessageOp: 0,
}
handleMsgMhfUpdateGuildMessageBoard(session, pkt)
if guildMock.createdPost != nil {
t.Error("Applicant should not be able to create posts")
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestUpdateGuildMessageBoard_HasAppError(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
guildMock := &mockGuildRepoOps{
hasAppErr: errNotFound, // error checking app status
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfUpdateGuildMessageBoard{
AckHandle: 100,
MessageOp: 0,
Title: "Test",
Body: "Body",
}
// Should log warning and treat as non-applicant (applicant=false on error)
handleMsgMhfUpdateGuildMessageBoard(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfEnumerateGuildMessageBoard tests ---
func TestEnumerateGuildMessageBoard_NoPosts(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
guildMock := &mockGuildRepoOps{
posts: []*MessageBoardPost{},
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateGuildMessageBoard{
AckHandle: 100,
BoardType: 0,
MaxPosts: 100,
}
handleMsgMhfEnumerateGuildMessageBoard(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestEnumerateGuildMessageBoard_WithPosts(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
guildMock := &mockGuildRepoOps{
posts: []*MessageBoardPost{
{ID: 1, AuthorID: 100, StampID: 5, Title: "Hello", Body: "World", Timestamp: time.Now()},
{ID: 2, AuthorID: 200, StampID: 0, Title: "Test", Body: "Post", Timestamp: time.Now()},
},
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateGuildMessageBoard{
AckHandle: 100,
BoardType: 0,
MaxPosts: 100,
}
handleMsgMhfEnumerateGuildMessageBoard(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 8 {
t.Errorf("Response too short for 2 posts: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
func TestEnumerateGuildMessageBoard_DBError(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
guildMock := &mockGuildRepoOps{
listPostsErr: errNotFound,
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateGuildMessageBoard{
AckHandle: 100,
BoardType: 0,
MaxPosts: 100,
}
handleMsgMhfEnumerateGuildMessageBoard(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}

View File

@@ -0,0 +1,607 @@
package channelserver
import (
"testing"
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
)
// --- handleMsgMhfOperateGuild tests ---
func TestOperateGuild_Disband_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildDisband,
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.disbandedID != 10 {
t.Errorf("Disband called with guild %d, want 10", guildMock.disbandedID)
}
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("No response data")
}
default:
t.Error("No response packet queued")
}
}
func TestOperateGuild_Disband_NotLeader(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 5},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 999 // different from session charID
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildDisband,
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.disbandedID != 0 {
t.Error("Disband should not be called for non-leader")
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestOperateGuild_Disband_RepoError(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
disbandErr: errNotFound,
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildDisband,
}
handleMsgMhfOperateGuild(session, pkt)
// response=0 when disband fails
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestOperateGuild_Resign_TransferLeadership(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
guildMock.members = []*GuildMember{
{CharID: 1, OrderIndex: 1, IsLeader: true},
{CharID: 2, OrderIndex: 2, AvoidLeadership: false},
}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildResign,
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.guild.LeaderCharID != 2 {
t.Errorf("Leader should transfer to charID 2, got %d", guildMock.guild.LeaderCharID)
}
if len(guildMock.savedMembers) < 2 {
t.Fatalf("Expected 2 saved members, got %d", len(guildMock.savedMembers))
}
if guildMock.savedGuild == nil {
t.Error("Guild should be saved after resign")
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestOperateGuild_Resign_SkipsAvoidLeadership(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
guildMock.members = []*GuildMember{
{CharID: 1, OrderIndex: 1, IsLeader: true},
{CharID: 2, OrderIndex: 2, AvoidLeadership: true},
{CharID: 3, OrderIndex: 3, AvoidLeadership: false},
}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildResign,
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.guild.LeaderCharID != 3 {
t.Errorf("Leader should transfer to charID 3 (skipping 2), got %d", guildMock.guild.LeaderCharID)
}
}
func TestOperateGuild_Apply_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 5},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 999
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildApply,
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.createdAppArgs == nil {
t.Fatal("CreateApplication should be called")
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestOperateGuild_Apply_RepoError(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 5},
createAppErr: errNotFound,
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 999
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildApply,
}
handleMsgMhfOperateGuild(session, pkt)
// Should still succeed with 0 leader ID
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestOperateGuild_Leave_AsApplicant(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{}
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsApplicant: true, OrderIndex: 5},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 999
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildLeave,
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.rejectedCharID != 1 {
t.Errorf("RejectApplication should be called for applicant, got rejectedCharID=%d", guildMock.rejectedCharID)
}
if guildMock.removedCharID != 0 {
t.Error("RemoveCharacter should not be called for applicant")
}
}
func TestOperateGuild_Leave_AsMember(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{}
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsApplicant: false, OrderIndex: 5},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 999
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildLeave,
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.removedCharID != 1 {
t.Errorf("RemoveCharacter should be called with charID 1, got %d", guildMock.removedCharID)
}
if len(mailMock.sentMails) != 1 {
t.Fatalf("Expected 1 withdrawal mail, got %d", len(mailMock.sentMails))
}
if mailMock.sentMails[0].recipientID != 1 {
t.Errorf("Mail recipientID = %d, want 1", mailMock.sentMails[0].recipientID)
}
}
func TestOperateGuild_Leave_MailError(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{sendErr: errNotFound}
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsApplicant: false, OrderIndex: 5},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 999
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildLeave,
}
// Should not panic; mail error is logged as warning
handleMsgMhfOperateGuild(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestOperateGuild_UpdateComment_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildUpdateComment,
Data2: newNullTermBF([]byte("Test\x00")),
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.savedGuild == nil {
t.Error("Guild should be saved after comment update")
}
}
func TestOperateGuild_UpdateComment_NotLeader(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 10}, // not leader, not sub-leader
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 999
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildUpdateComment,
}
handleMsgMhfOperateGuild(session, pkt)
// Should return fail ack
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected fail response")
}
default:
t.Error("No response packet queued")
}
}
func TestOperateGuild_UpdateMotto_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildUpdateMotto,
Data1: newMottoBF(5, 3),
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.savedGuild == nil {
t.Error("Guild should be saved after motto update")
}
if guildMock.savedGuild.MainMotto != 3 {
t.Errorf("MainMotto = %d, want 3", guildMock.savedGuild.MainMotto)
}
if guildMock.savedGuild.SubMotto != 5 {
t.Errorf("SubMotto = %d, want 5", guildMock.savedGuild.SubMotto)
}
}
func TestOperateGuild_UpdateMotto_NotLeader(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 10},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 999
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildUpdateMotto,
}
handleMsgMhfOperateGuild(session, pkt)
if guildMock.savedGuild != nil {
t.Error("Guild should not be saved when not leader")
}
}
func TestOperateGuild_GuildNotFound(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.getErr = errNotFound
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuild{
AckHandle: 100,
GuildID: 10,
Action: mhfpacket.OperateGuildDisband,
}
handleMsgMhfOperateGuild(session, pkt)
// Should return fail ack
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfOperateGuildMember tests ---
func TestOperateGuildMember_Accept(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{}
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuildMember{
AckHandle: 100,
GuildID: 10,
CharID: 42,
Action: mhfpacket.OPERATE_GUILD_MEMBER_ACTION_ACCEPT,
}
handleMsgMhfOperateGuildMember(session, pkt)
if guildMock.acceptedCharID != 42 {
t.Errorf("AcceptApplication charID = %d, want 42", guildMock.acceptedCharID)
}
if len(mailMock.sentMails) != 1 {
t.Fatalf("Expected 1 mail, got %d", len(mailMock.sentMails))
}
if mailMock.sentMails[0].recipientID != 42 {
t.Errorf("Mail recipientID = %d, want 42", mailMock.sentMails[0].recipientID)
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestOperateGuildMember_Reject(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{}
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuildMember{
AckHandle: 100,
GuildID: 10,
CharID: 42,
Action: mhfpacket.OPERATE_GUILD_MEMBER_ACTION_REJECT,
}
handleMsgMhfOperateGuildMember(session, pkt)
if guildMock.rejectedCharID != 42 {
t.Errorf("RejectApplication charID = %d, want 42", guildMock.rejectedCharID)
}
if len(mailMock.sentMails) != 1 {
t.Fatalf("Expected 1 mail, got %d", len(mailMock.sentMails))
}
}
func TestOperateGuildMember_Kick(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{}
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuildMember{
AckHandle: 100,
GuildID: 10,
CharID: 42,
Action: mhfpacket.OPERATE_GUILD_MEMBER_ACTION_KICK,
}
handleMsgMhfOperateGuildMember(session, pkt)
if guildMock.removedCharID != 42 {
t.Errorf("RemoveCharacter charID = %d, want 42", guildMock.removedCharID)
}
if len(mailMock.sentMails) != 1 {
t.Fatalf("Expected 1 mail, got %d", len(mailMock.sentMails))
}
}
func TestOperateGuildMember_MailError(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{sendErr: errNotFound}
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, IsLeader: true, OrderIndex: 1},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuildMember{
AckHandle: 100,
GuildID: 10,
CharID: 42,
Action: mhfpacket.OPERATE_GUILD_MEMBER_ACTION_ACCEPT,
}
// Should not panic; mail error logged as warning
handleMsgMhfOperateGuildMember(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestOperateGuildMember_NotLeaderOrSub(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 10}, // not sub-leader
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 999 // not the session char
server.guildRepo = guildMock
server.mailRepo = &mockMailRepo{}
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuildMember{
AckHandle: 100,
GuildID: 10,
CharID: 42,
Action: mhfpacket.OPERATE_GUILD_MEMBER_ACTION_ACCEPT,
}
handleMsgMhfOperateGuildMember(session, pkt)
if guildMock.acceptedCharID != 0 {
t.Error("Should not accept when actor lacks permission")
}
}
// --- byteframe helpers for packet Data fields ---
func newNullTermBF(data []byte) *byteframe.ByteFrame {
bf := byteframe.NewByteFrame()
bf.WriteBytes(data)
_, _ = bf.Seek(0, 0)
return bf
}
func newMottoBF(sub, main uint8) *byteframe.ByteFrame {
bf := byteframe.NewByteFrame()
bf.WriteUint16(0) // skipped
bf.WriteUint8(sub) // SubMotto
bf.WriteUint8(main) // MainMotto
_, _ = bf.Seek(0, 0)
return bf
}

View File

@@ -0,0 +1,262 @@
package channelserver
import (
"testing"
"erupe-ce/network/mhfpacket"
)
// --- handleMsgMhfAnswerGuildScout tests ---
func TestAnswerGuildScout_Accept(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{}
guildMock := &mockGuildRepoOps{
application: &GuildApplication{GuildID: 10, CharID: 1},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 50
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
AckHandle: 100,
LeaderID: 50,
Answer: true,
}
handleMsgMhfAnswerGuildScout(session, pkt)
if guildMock.acceptedCharID != 1 {
t.Errorf("AcceptApplication charID = %d, want 1", guildMock.acceptedCharID)
}
if len(mailMock.sentMails) != 2 {
t.Fatalf("Expected 2 mails (self + leader), got %d", len(mailMock.sentMails))
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestAnswerGuildScout_Decline(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{}
guildMock := &mockGuildRepoOps{
application: &GuildApplication{GuildID: 10, CharID: 1},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 50
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
AckHandle: 100,
LeaderID: 50,
Answer: false,
}
handleMsgMhfAnswerGuildScout(session, pkt)
if guildMock.rejectedCharID != 1 {
t.Errorf("RejectApplication charID = %d, want 1", guildMock.rejectedCharID)
}
if len(mailMock.sentMails) != 2 {
t.Fatalf("Expected 2 mails (self + leader), got %d", len(mailMock.sentMails))
}
}
func TestAnswerGuildScout_GuildNotFound(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.getErr = errNotFound
server.guildRepo = guildMock
server.mailRepo = &mockMailRepo{}
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
AckHandle: 100,
LeaderID: 50,
Answer: true,
}
handleMsgMhfAnswerGuildScout(session, pkt)
// Should return fail ack
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestAnswerGuildScout_ApplicationMissing(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{}
guildMock := &mockGuildRepoOps{
application: nil, // no application found
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 50
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
AckHandle: 100,
LeaderID: 50,
Answer: true,
}
handleMsgMhfAnswerGuildScout(session, pkt)
// No mails should be sent when application is missing
if len(mailMock.sentMails) != 0 {
t.Errorf("Expected 0 mails for missing application, got %d", len(mailMock.sentMails))
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestAnswerGuildScout_MailError(t *testing.T) {
server := createMockServer()
mailMock := &mockMailRepo{sendErr: errNotFound}
guildMock := &mockGuildRepoOps{
application: &GuildApplication{GuildID: 10, CharID: 1},
}
guildMock.guild = &Guild{ID: 10, Name: "TestGuild"}
guildMock.guild.LeaderCharID = 50
server.guildRepo = guildMock
server.mailRepo = mailMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfAnswerGuildScout{
AckHandle: 100,
LeaderID: 50,
Answer: true,
}
// Should not panic; mail errors logged as warnings
handleMsgMhfAnswerGuildScout(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfGetRejectGuildScout tests ---
func TestGetRejectGuildScout_Restricted(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
charMock.bools["restrict_guild_scout"] = true
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetRejectGuildScout{AckHandle: 100}
handleMsgMhfGetRejectGuildScout(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 4 {
t.Fatal("Response too short")
}
default:
t.Error("No response packet queued")
}
}
func TestGetRejectGuildScout_Open(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
charMock.bools["restrict_guild_scout"] = false
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetRejectGuildScout{AckHandle: 100}
handleMsgMhfGetRejectGuildScout(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestGetRejectGuildScout_DBError(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
charMock.readErr = errNotFound
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetRejectGuildScout{AckHandle: 100}
handleMsgMhfGetRejectGuildScout(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfSetRejectGuildScout tests ---
func TestSetRejectGuildScout_Success(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfSetRejectGuildScout{
AckHandle: 100,
Reject: true,
}
handleMsgMhfSetRejectGuildScout(session, pkt)
if !charMock.bools["restrict_guild_scout"] {
t.Error("restrict_guild_scout should be true")
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestSetRejectGuildScout_DBError(t *testing.T) {
server := createMockServer()
charMock := newMockCharacterRepo()
charMock.saveErr = errNotFound
server.charRepo = charMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfSetRejectGuildScout{
AckHandle: 100,
Reject: true,
}
handleMsgMhfSetRejectGuildScout(session, pkt)
// Should return fail ack
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}

View File

@@ -0,0 +1,364 @@
package channelserver
import (
"testing"
"time"
"erupe-ce/common/byteframe"
"erupe-ce/common/mhfitem"
"erupe-ce/network/mhfpacket"
)
// --- userGetItems tests ---
func TestUserGetItems_NilData(t *testing.T) {
server := createMockServer()
userMock := &mockUserRepoForItems{itemBoxData: nil}
server.userRepo = userMock
session := createMockSession(1, server)
session.userID = 1
items := userGetItems(session)
if len(items) != 0 {
t.Errorf("Expected empty items, got %d", len(items))
}
}
func TestUserGetItems_DBError(t *testing.T) {
server := createMockServer()
userMock := &mockUserRepoForItems{itemBoxErr: errNotFound}
server.userRepo = userMock
session := createMockSession(1, server)
session.userID = 1
items := userGetItems(session)
if len(items) != 0 {
t.Errorf("Expected empty items on error, got %d", len(items))
}
}
func TestUserGetItems_ParsesData(t *testing.T) {
// Build serialized item box with 1 item
bf := byteframe.NewByteFrame()
bf.WriteUint16(1) // numStacks
bf.WriteUint16(0) // unused
// Item stack: warehouseID(4) + itemID(2) + quantity(2) + unk0(4) = 12 bytes
bf.WriteUint32(100) // warehouseID
bf.WriteUint16(500) // itemID
bf.WriteUint16(3) // quantity
bf.WriteUint32(0) // unk0
server := createMockServer()
userMock := &mockUserRepoForItems{itemBoxData: bf.Data()}
server.userRepo = userMock
session := createMockSession(1, server)
session.userID = 1
items := userGetItems(session)
if len(items) != 1 {
t.Fatalf("Expected 1 item, got %d", len(items))
}
if items[0].Item.ItemID != 500 {
t.Errorf("ItemID = %d, want 500", items[0].Item.ItemID)
}
if items[0].Quantity != 3 {
t.Errorf("Quantity = %d, want 3", items[0].Quantity)
}
}
// --- handleMsgMhfCheckWeeklyStamp tests ---
func TestCheckWeeklyStamp_InvalidType(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfCheckWeeklyStamp{
AckHandle: 100,
StampType: "invalid",
}
handleMsgMhfCheckWeeklyStamp(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestCheckWeeklyStamp_FirstCheck(t *testing.T) {
server := createMockServer()
stampMock := &mockStampRepoForItems{
checkedErr: errNotFound, // no existing record
totals: [2]uint16{0, 0},
}
server.stampRepo = stampMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfCheckWeeklyStamp{
AckHandle: 100,
StampType: "hl",
}
handleMsgMhfCheckWeeklyStamp(session, pkt)
if !stampMock.initCalled {
t.Error("Init should be called on first check")
}
select {
case p := <-session.sendPackets:
if len(p.data) < 14 {
t.Errorf("Response too short: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
func TestCheckWeeklyStamp_WithinWeek(t *testing.T) {
server := createMockServer()
stampMock := &mockStampRepoForItems{
checkedTime: TimeAdjusted(), // checked right now (within this week)
totals: [2]uint16{3, 1},
}
server.stampRepo = stampMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfCheckWeeklyStamp{
AckHandle: 100,
StampType: "hl",
}
handleMsgMhfCheckWeeklyStamp(session, pkt)
if stampMock.incrementCalled {
t.Error("IncrementTotal should not be called within same week")
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestCheckWeeklyStamp_WeekRollover(t *testing.T) {
server := createMockServer()
stampMock := &mockStampRepoForItems{
checkedTime: TimeWeekStart().Add(-24 * time.Hour), // before this week
totals: [2]uint16{5, 2},
}
server.stampRepo = stampMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfCheckWeeklyStamp{
AckHandle: 100,
StampType: "ex",
}
handleMsgMhfCheckWeeklyStamp(session, pkt)
if !stampMock.incrementCalled {
t.Error("IncrementTotal should be called after week rollover")
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestCheckWeeklyStamp_GetTotalsError(t *testing.T) {
server := createMockServer()
stampMock := &mockStampRepoForItems{
checkedTime: TimeAdjusted(),
totalsErr: errNotFound,
}
server.stampRepo = stampMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfCheckWeeklyStamp{
AckHandle: 100,
StampType: "hl",
}
// Should not panic; logs warning, returns zeros
handleMsgMhfCheckWeeklyStamp(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfExchangeWeeklyStamp tests ---
func TestExchangeWeeklyStamp_InvalidType(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfExchangeWeeklyStamp{
AckHandle: 100,
StampType: "invalid",
}
handleMsgMhfExchangeWeeklyStamp(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestExchangeWeeklyStamp_HL(t *testing.T) {
server := createMockServer()
stampMock := &mockStampRepoForItems{
exchangeResult: [2]uint16{10, 5},
}
houseMock := newMockHouseRepoForItems()
server.stampRepo = stampMock
server.houseRepo = houseMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfExchangeWeeklyStamp{
AckHandle: 100,
StampType: "hl",
}
handleMsgMhfExchangeWeeklyStamp(session, pkt)
// Verify warehouse gift box was updated (index 10)
if houseMock.setData[10] == nil {
t.Error("Gift box should be updated with ticket item")
}
// Parse the gift box to verify the item
if len(houseMock.setData[10]) > 0 {
bf := byteframe.NewByteFrameFromBytes(houseMock.setData[10])
count := bf.ReadUint16()
if count != 1 {
t.Errorf("Expected 1 item in gift box, got %d", count)
}
bf.ReadUint16() // unused
item := mhfitem.ReadWarehouseItem(bf)
if item.Item.ItemID != 1630 {
t.Errorf("ItemID = %d, want 1630 (HL ticket)", item.Item.ItemID)
}
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestExchangeWeeklyStamp_EX(t *testing.T) {
server := createMockServer()
stampMock := &mockStampRepoForItems{
exchangeResult: [2]uint16{10, 5},
}
houseMock := newMockHouseRepoForItems()
server.stampRepo = stampMock
server.houseRepo = houseMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfExchangeWeeklyStamp{
AckHandle: 100,
StampType: "ex",
}
handleMsgMhfExchangeWeeklyStamp(session, pkt)
if houseMock.setData[10] == nil {
t.Error("Gift box should be updated with ticket item")
}
if len(houseMock.setData[10]) > 0 {
bf := byteframe.NewByteFrameFromBytes(houseMock.setData[10])
count := bf.ReadUint16()
if count != 1 {
t.Errorf("Expected 1 item in gift box, got %d", count)
}
bf.ReadUint16() // unused
item := mhfitem.ReadWarehouseItem(bf)
if item.Item.ItemID != 1631 {
t.Errorf("ItemID = %d, want 1631 (EX ticket)", item.Item.ItemID)
}
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestExchangeWeeklyStamp_ExchangeError(t *testing.T) {
server := createMockServer()
stampMock := &mockStampRepoForItems{
exchangeErr: errNotFound,
}
server.stampRepo = stampMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfExchangeWeeklyStamp{
AckHandle: 100,
StampType: "hl",
}
handleMsgMhfExchangeWeeklyStamp(session, pkt)
// Should return fail ack
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestExchangeWeeklyStamp_Yearly(t *testing.T) {
server := createMockServer()
stampMock := &mockStampRepoForItems{
yearlyResult: [2]uint16{20, 10},
}
houseMock := newMockHouseRepoForItems()
server.stampRepo = stampMock
server.houseRepo = houseMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfExchangeWeeklyStamp{
AckHandle: 100,
StampType: "ex",
ExchangeType: 10, // Yearly
}
handleMsgMhfExchangeWeeklyStamp(session, pkt)
if houseMock.setData[10] == nil {
t.Error("Gift box should be updated with yearly ticket")
}
if len(houseMock.setData[10]) > 0 {
bf := byteframe.NewByteFrameFromBytes(houseMock.setData[10])
count := bf.ReadUint16()
if count != 1 {
t.Errorf("Expected 1 item in gift box, got %d", count)
}
bf.ReadUint16() // unused
item := mhfitem.ReadWarehouseItem(bf)
if item.Item.ItemID != 2210 {
t.Errorf("ItemID = %d, want 2210 (yearly ticket)", item.Item.ItemID)
}
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}

View File

@@ -330,3 +330,269 @@ func (m *mockGuildRepoForMail) InsertKillLog(_ uint32, _ int, _ uint8, _ time.Ti
func (m *mockGuildRepoForMail) ListInvitedCharacters(_ uint32) ([]*ScoutedCharacter, error) { return nil, nil }
func (m *mockGuildRepoForMail) RolloverDailyRP(_ uint32, _ time.Time) error { return nil }
func (m *mockGuildRepoForMail) AddWeeklyBonusUsers(_ uint32, _ uint8) error { return nil }
// --- mockGuildRepoOps (enhanced guild repo for ops/scout/board tests) ---
type mockGuildRepoOps struct {
mockGuildRepoForMail
// Configurable errors
saveErr error
saveMemberErr error
disbandErr error
getMembersErr error
acceptErr error
rejectErr error
removeErr error
createAppErr error
getMemberErr error
hasAppResult bool
hasAppErr error
listPostsErr error
createPostErr error
deletePostErr error
// State tracking
disbandedID uint32
removedCharID uint32
acceptedCharID uint32
rejectedCharID uint32
savedGuild *Guild
savedMembers []*GuildMember
createdAppArgs []interface{}
createdPost []interface{}
deletedPostID uint32
// Data
membership *GuildMember
application *GuildApplication
posts []*MessageBoardPost
}
func (m *mockGuildRepoOps) GetByID(guildID uint32) (*Guild, error) {
if m.getErr != nil {
return nil, m.getErr
}
if m.guild != nil && m.guild.ID == guildID {
return m.guild, nil
}
return nil, errNotFound
}
func (m *mockGuildRepoOps) GetByCharID(charID uint32) (*Guild, error) {
if m.getErr != nil {
return nil, m.getErr
}
return m.guild, nil
}
func (m *mockGuildRepoOps) GetMembers(guildID uint32, applicants bool) ([]*GuildMember, error) {
if m.getMembersErr != nil {
return nil, m.getMembersErr
}
return m.members, nil
}
func (m *mockGuildRepoOps) GetCharacterMembership(_ uint32) (*GuildMember, error) {
if m.getMemberErr != nil {
return nil, m.getMemberErr
}
return m.membership, nil
}
func (m *mockGuildRepoOps) Save(guild *Guild) error {
m.savedGuild = guild
return m.saveErr
}
func (m *mockGuildRepoOps) SaveMember(member *GuildMember) error {
m.savedMembers = append(m.savedMembers, member)
return m.saveMemberErr
}
func (m *mockGuildRepoOps) Disband(guildID uint32) error {
m.disbandedID = guildID
return m.disbandErr
}
func (m *mockGuildRepoOps) RemoveCharacter(charID uint32) error {
m.removedCharID = charID
return m.removeErr
}
func (m *mockGuildRepoOps) AcceptApplication(guildID, charID uint32) error {
m.acceptedCharID = charID
return m.acceptErr
}
func (m *mockGuildRepoOps) RejectApplication(guildID, charID uint32) error {
m.rejectedCharID = charID
return m.rejectErr
}
func (m *mockGuildRepoOps) CreateApplication(guildID, charID, actorID uint32, appType GuildApplicationType) error {
m.createdAppArgs = []interface{}{guildID, charID, actorID, appType}
return m.createAppErr
}
func (m *mockGuildRepoOps) HasApplication(guildID, charID uint32) (bool, error) {
return m.hasAppResult, m.hasAppErr
}
func (m *mockGuildRepoOps) GetApplication(guildID, charID uint32, appType GuildApplicationType) (*GuildApplication, error) {
return m.application, nil
}
func (m *mockGuildRepoOps) ListPosts(guildID uint32, postType int) ([]*MessageBoardPost, error) {
if m.listPostsErr != nil {
return nil, m.listPostsErr
}
return m.posts, nil
}
func (m *mockGuildRepoOps) CreatePost(guildID, authorID, stampID uint32, postType int, title, body string, maxPosts int) error {
m.createdPost = []interface{}{guildID, authorID, stampID, postType, title, body, maxPosts}
return m.createPostErr
}
func (m *mockGuildRepoOps) DeletePost(postID uint32) error {
m.deletedPostID = postID
return m.deletePostErr
}
// --- mockUserRepoForItems ---
type mockUserRepoForItems struct {
itemBoxData []byte
itemBoxErr error
setData []byte
}
func (m *mockUserRepoForItems) GetItemBox(_ uint32) ([]byte, error) {
return m.itemBoxData, m.itemBoxErr
}
func (m *mockUserRepoForItems) SetItemBox(_ uint32, data []byte) error {
m.setData = data
return nil
}
// Stub all other UserRepo methods.
func (m *mockUserRepoForItems) GetGachaPoints(_ uint32) (uint32, uint32, uint32, error) { return 0, 0, 0, nil }
func (m *mockUserRepoForItems) GetTrialCoins(_ uint32) (uint16, error) { return 0, nil }
func (m *mockUserRepoForItems) DeductTrialCoins(_ uint32, _ uint32) error { return nil }
func (m *mockUserRepoForItems) DeductPremiumCoins(_ uint32, _ uint32) error { return nil }
func (m *mockUserRepoForItems) AddPremiumCoins(_ uint32, _ uint32) error { return nil }
func (m *mockUserRepoForItems) AddTrialCoins(_ uint32, _ uint32) error { return nil }
func (m *mockUserRepoForItems) DeductFrontierPoints(_ uint32, _ uint32) error { return nil }
func (m *mockUserRepoForItems) AddFrontierPoints(_ uint32, _ uint32) error { return nil }
func (m *mockUserRepoForItems) AdjustFrontierPointsDeduct(_ uint32, _ int) (uint32, error) { return 0, nil }
func (m *mockUserRepoForItems) AdjustFrontierPointsCredit(_ uint32, _ int) (uint32, error) { return 0, nil }
func (m *mockUserRepoForItems) AddFrontierPointsFromGacha(_ uint32, _ uint32, _ uint8) error { return nil }
func (m *mockUserRepoForItems) GetRights(_ uint32) (uint32, error) { return 0, nil }
func (m *mockUserRepoForItems) SetRights(_ uint32, _ uint32) error { return nil }
func (m *mockUserRepoForItems) IsOp(_ uint32) (bool, error) { return false, nil }
func (m *mockUserRepoForItems) SetLastCharacter(_ uint32, _ uint32) error { return nil }
func (m *mockUserRepoForItems) GetTimer(_ uint32) (bool, error) { return false, nil }
func (m *mockUserRepoForItems) SetTimer(_ uint32, _ bool) error { return nil }
func (m *mockUserRepoForItems) CountByPSNID(_ string) (int, error) { return 0, nil }
func (m *mockUserRepoForItems) SetPSNID(_ uint32, _ string) error { return nil }
func (m *mockUserRepoForItems) GetDiscordToken(_ uint32) (string, error) { return "", nil }
func (m *mockUserRepoForItems) SetDiscordToken(_ uint32, _ string) error { return nil }
func (m *mockUserRepoForItems) LinkDiscord(_ string, _ string) (string, error) { return "", nil }
func (m *mockUserRepoForItems) SetPasswordByDiscordID(_ string, _ []byte) error { return nil }
func (m *mockUserRepoForItems) GetByIDAndUsername(_ uint32) (uint32, string, error) { return 0, "", nil }
func (m *mockUserRepoForItems) BanUser(_ uint32, _ *time.Time) error { return nil }
// --- mockStampRepoForItems ---
type mockStampRepoForItems struct {
checkedTime time.Time
checkedErr error
totals [2]uint16 // total, redeemed
totalsErr error
initCalled bool
incrementCalled bool
setCalled bool
exchangeResult [2]uint16
exchangeErr error
yearlyResult [2]uint16
yearlyErr error
}
func (m *mockStampRepoForItems) GetChecked(_ uint32, _ string) (time.Time, error) {
return m.checkedTime, m.checkedErr
}
func (m *mockStampRepoForItems) Init(_ uint32, _ time.Time) error {
m.initCalled = true
return nil
}
func (m *mockStampRepoForItems) SetChecked(_ uint32, _ string, _ time.Time) error {
m.setCalled = true
return nil
}
func (m *mockStampRepoForItems) IncrementTotal(_ uint32, _ string) error {
m.incrementCalled = true
return nil
}
func (m *mockStampRepoForItems) GetTotals(_ uint32, _ string) (uint16, uint16, error) {
return m.totals[0], m.totals[1], m.totalsErr
}
func (m *mockStampRepoForItems) ExchangeYearly(_ uint32) (uint16, uint16, error) {
return m.yearlyResult[0], m.yearlyResult[1], m.yearlyErr
}
func (m *mockStampRepoForItems) Exchange(_ uint32, _ string) (uint16, uint16, error) {
return m.exchangeResult[0], m.exchangeResult[1], m.exchangeErr
}
// --- mockHouseRepoForItems ---
type mockHouseRepoForItems struct {
warehouseItems map[uint8][]byte
setData map[uint8][]byte
setErr error
}
func newMockHouseRepoForItems() *mockHouseRepoForItems {
return &mockHouseRepoForItems{
warehouseItems: make(map[uint8][]byte),
setData: make(map[uint8][]byte),
}
}
func (m *mockHouseRepoForItems) GetWarehouseItemData(_ uint32, index uint8) ([]byte, error) {
return m.warehouseItems[index], nil
}
func (m *mockHouseRepoForItems) SetWarehouseItemData(_ uint32, index uint8, data []byte) error {
m.setData[index] = data
return m.setErr
}
func (m *mockHouseRepoForItems) InitializeWarehouse(_ uint32) error { return nil }
// Stub all other HouseRepo methods.
func (m *mockHouseRepoForItems) UpdateInterior(_ uint32, _ []byte) error { return nil }
func (m *mockHouseRepoForItems) GetHouseByCharID(_ uint32) (HouseData, error) { return HouseData{}, nil }
func (m *mockHouseRepoForItems) SearchHousesByName(_ string) ([]HouseData, error) { return nil, nil }
func (m *mockHouseRepoForItems) UpdateHouseState(_ uint32, _ uint8, _ string) error { return nil }
func (m *mockHouseRepoForItems) GetHouseAccess(_ uint32) (uint8, string, error) { return 0, "", nil }
func (m *mockHouseRepoForItems) GetHouseContents(_ uint32) ([]byte, []byte, []byte, []byte, []byte, []byte, []byte, error) {
return nil, nil, nil, nil, nil, nil, nil, nil
}
func (m *mockHouseRepoForItems) GetMission(_ uint32) ([]byte, error) { return nil, nil }
func (m *mockHouseRepoForItems) UpdateMission(_ uint32, _ []byte) error { return nil }
func (m *mockHouseRepoForItems) GetWarehouseNames(_ uint32) ([10]string, [10]string, error) {
return [10]string{}, [10]string{}, nil
}
func (m *mockHouseRepoForItems) RenameWarehouseBox(_ uint32, _ uint8, _ uint8, _ string) error { return nil }
func (m *mockHouseRepoForItems) GetWarehouseEquipData(_ uint32, _ uint8) ([]byte, error) { return nil, nil }
func (m *mockHouseRepoForItems) SetWarehouseEquipData(_ uint32, _ uint8, _ []byte) error { return nil }
func (m *mockHouseRepoForItems) GetTitles(_ uint32) ([]Title, error) { return nil, nil }
func (m *mockHouseRepoForItems) AcquireTitle(_ uint16, _ uint32) error { return nil }