test(channelserver): add handler tests for guild info, alliance, cooking, adventure, and treasure

Cover 5 more handler files with mock-based unit tests, bringing
package coverage from 43.7% to 47.7%. Extend mockGuildRepoOps with
alliance, cooking, adventure, treasure hunt, and hunt data methods.
This commit is contained in:
Houmgaor
2026-02-21 18:10:19 +01:00
parent 7852e8505f
commit 2a5cd50e3f
6 changed files with 1396 additions and 0 deletions

View File

@@ -0,0 +1,200 @@
package channelserver
import (
"testing"
"erupe-ce/network/mhfpacket"
)
// --- handleMsgMhfLoadGuildAdventure tests ---
func TestLoadGuildAdventure_NoAdventures(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
adventures: []*GuildAdventure{},
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfLoadGuildAdventure{AckHandle: 100}
handleMsgMhfLoadGuildAdventure(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestLoadGuildAdventure_WithAdventures(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
adventures: []*GuildAdventure{
{ID: 1, Destination: 5, Charge: 0, Depart: 1000, Return: 2000, CollectedBy: ""},
{ID: 2, Destination: 8, Charge: 100, Depart: 1000, Return: 2000, CollectedBy: "1"},
},
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfLoadGuildAdventure{AckHandle: 100}
handleMsgMhfLoadGuildAdventure(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 10 {
t.Errorf("Response too short for 2 adventures: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
func TestLoadGuildAdventure_DBError(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
listAdvErr: errNotFound,
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfLoadGuildAdventure{AckHandle: 100}
handleMsgMhfLoadGuildAdventure(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfRegistGuildAdventure tests ---
func TestRegistGuildAdventure_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfRegistGuildAdventure{
AckHandle: 100,
Destination: 5,
}
handleMsgMhfRegistGuildAdventure(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestRegistGuildAdventure_Error(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{createAdvErr: errNotFound}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfRegistGuildAdventure{
AckHandle: 100,
Destination: 5,
}
// Should not panic; error is logged
handleMsgMhfRegistGuildAdventure(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfAcquireGuildAdventure tests ---
func TestAcquireGuildAdventure_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfAcquireGuildAdventure{
AckHandle: 100,
ID: 42,
}
handleMsgMhfAcquireGuildAdventure(session, pkt)
if guildMock.collectAdvID != 42 {
t.Errorf("CollectAdventure ID = %d, want 42", guildMock.collectAdvID)
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfChargeGuildAdventure tests ---
func TestChargeGuildAdventure_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfChargeGuildAdventure{
AckHandle: 100,
ID: 42,
Amount: 500,
}
handleMsgMhfChargeGuildAdventure(session, pkt)
if guildMock.chargeAdvID != 42 {
t.Errorf("ChargeAdventure ID = %d, want 42", guildMock.chargeAdvID)
}
if guildMock.chargeAdvAmount != 500 {
t.Errorf("ChargeAdventure Amount = %d, want 500", guildMock.chargeAdvAmount)
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfRegistGuildAdventureDiva tests ---
func TestRegistGuildAdventureDiva_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfRegistGuildAdventureDiva{
AckHandle: 100,
Destination: 3,
Charge: 200,
}
handleMsgMhfRegistGuildAdventureDiva(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}

View File

@@ -0,0 +1,320 @@
package channelserver
import (
"testing"
"time"
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
)
// --- handleMsgMhfCreateJoint tests ---
func TestCreateJoint_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfCreateJoint{
AckHandle: 100,
GuildID: 10,
Name: "TestAlliance",
}
handleMsgMhfCreateJoint(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestCreateJoint_Error(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{createAllianceErr: errNotFound}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfCreateJoint{
AckHandle: 100,
GuildID: 10,
Name: "TestAlliance",
}
// Should not panic; error is logged
handleMsgMhfCreateJoint(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfOperateJoint tests ---
func TestOperateJoint_Disband_AsOwner(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
alliance: &GuildAlliance{
ID: 5,
ParentGuildID: 10,
},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1 // session charID
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateJoint{
AckHandle: 100,
AllianceID: 5,
GuildID: 10,
Action: mhfpacket.OPERATE_JOINT_DISBAND,
}
handleMsgMhfOperateJoint(session, pkt)
if guildMock.deletedAllianceID != 5 {
t.Errorf("DeleteAlliance called with %d, want 5", guildMock.deletedAllianceID)
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestOperateJoint_Disband_NotOwner(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
alliance: &GuildAlliance{
ID: 5,
ParentGuildID: 99, // different guild
},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateJoint{
AckHandle: 100,
AllianceID: 5,
GuildID: 10,
Action: mhfpacket.OPERATE_JOINT_DISBAND,
}
handleMsgMhfOperateJoint(session, pkt)
if guildMock.deletedAllianceID != 0 {
t.Error("Should not disband when not alliance owner")
}
}
func TestOperateJoint_Leave_AsLeader(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
alliance: &GuildAlliance{
ID: 5,
ParentGuildID: 99,
SubGuild1ID: 10,
},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateJoint{
AckHandle: 100,
AllianceID: 5,
GuildID: 10,
Action: mhfpacket.OPERATE_JOINT_LEAVE,
}
handleMsgMhfOperateJoint(session, pkt)
if guildMock.removedAllyArgs == nil {
t.Fatal("RemoveGuildFromAlliance should be called")
}
if guildMock.removedAllyArgs[1] != 10 {
t.Errorf("Removed guildID = %d, want 10", guildMock.removedAllyArgs[1])
}
}
func TestOperateJoint_Leave_NotLeader(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
alliance: &GuildAlliance{ID: 5, ParentGuildID: 99},
}
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 999 // not session char
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateJoint{
AckHandle: 100,
AllianceID: 5,
GuildID: 10,
Action: mhfpacket.OPERATE_JOINT_LEAVE,
}
handleMsgMhfOperateJoint(session, pkt)
if guildMock.removedAllyArgs != nil {
t.Error("Non-leader should not be able to leave alliance")
}
}
func TestOperateJoint_Kick_AsAllianceOwner(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
alliance: &GuildAlliance{
ID: 5,
ParentGuildID: 10,
ParentGuild: Guild{},
SubGuild1ID: 20,
},
}
guildMock.alliance.ParentGuild.LeaderCharID = 1 // session char owns alliance
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
data1 := byteframe.NewByteFrame()
data1.WriteUint32(20) // guildID to kick
_, _ = data1.Seek(0, 0)
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateJoint{
AckHandle: 100,
AllianceID: 5,
GuildID: 10,
Action: mhfpacket.OPERATE_JOINT_KICK,
Data1: data1,
}
handleMsgMhfOperateJoint(session, pkt)
if guildMock.removedAllyArgs == nil {
t.Fatal("RemoveGuildFromAlliance should be called for kick")
}
if guildMock.removedAllyArgs[1] != 20 {
t.Errorf("Kicked guildID = %d, want 20", guildMock.removedAllyArgs[1])
}
}
func TestOperateJoint_Kick_NotOwner(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
alliance: &GuildAlliance{
ID: 5,
ParentGuildID: 99,
ParentGuild: Guild{},
},
}
guildMock.alliance.ParentGuild.LeaderCharID = 999 // not session char
guildMock.guild = &Guild{ID: 10}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateJoint{
AckHandle: 100,
AllianceID: 5,
GuildID: 10,
Action: mhfpacket.OPERATE_JOINT_KICK,
}
handleMsgMhfOperateJoint(session, pkt)
if guildMock.removedAllyArgs != nil {
t.Error("Non-owner should not kick from alliance")
}
}
// --- handleMsgMhfInfoJoint tests ---
func TestInfoJoint_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
alliance: &GuildAlliance{
ID: 5,
Name: "TestAlliance",
CreatedAt: time.Now(),
TotalMembers: 15,
ParentGuildID: 10,
ParentGuild: Guild{Name: "ParentGuild", MemberCount: 5},
},
}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfInfoJoint{AckHandle: 100, AllianceID: 5}
handleMsgMhfInfoJoint(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 10 {
t.Errorf("Response too short: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
func TestInfoJoint_WithSubGuilds(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
alliance: &GuildAlliance{
ID: 5,
Name: "BigAlliance",
CreatedAt: time.Now(),
TotalMembers: 30,
ParentGuildID: 10,
ParentGuild: Guild{Name: "Parent", MemberCount: 10},
SubGuild1ID: 20,
SubGuild1: Guild{Name: "Sub1", MemberCount: 10},
SubGuild2ID: 30,
SubGuild2: Guild{Name: "Sub2", MemberCount: 10},
},
}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfInfoJoint{AckHandle: 100, AllianceID: 5}
handleMsgMhfInfoJoint(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 30 {
t.Errorf("Response too short for alliance with sub guilds: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
func TestInfoJoint_NotFound(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{getAllianceErr: errNotFound}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfInfoJoint{AckHandle: 100, AllianceID: 999}
handleMsgMhfInfoJoint(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}

View File

@@ -0,0 +1,306 @@
package channelserver
import (
"testing"
"time"
"erupe-ce/network/mhfpacket"
)
// --- handleMsgMhfLoadGuildCooking tests ---
func TestLoadGuildCooking_NoMeals(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
meals: []*GuildMeal{},
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfLoadGuildCooking{AckHandle: 100}
handleMsgMhfLoadGuildCooking(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestLoadGuildCooking_WithActiveMeals(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
meals: []*GuildMeal{
{ID: 1, MealID: 100, Level: 3, CreatedAt: TimeAdjusted()}, // active (within 60 min)
{ID: 2, MealID: 200, Level: 1, CreatedAt: TimeAdjusted().Add(-2 * time.Hour)}, // expired
},
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfLoadGuildCooking{AckHandle: 100}
handleMsgMhfLoadGuildCooking(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 TestLoadGuildCooking_DBError(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
listMealsErr: errNotFound,
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfLoadGuildCooking{AckHandle: 100}
handleMsgMhfLoadGuildCooking(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfRegistGuildCooking tests ---
func TestRegistGuildCooking_NewMeal(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
createdMealID: 42,
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfRegistGuildCooking{
AckHandle: 100,
OverwriteID: 0, // New meal
MealID: 5,
Success: 1,
}
handleMsgMhfRegistGuildCooking(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 8 {
t.Errorf("Response too short: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
func TestRegistGuildCooking_UpdateMeal(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfRegistGuildCooking{
AckHandle: 100,
OverwriteID: 42, // Update existing
MealID: 5,
Success: 2,
}
handleMsgMhfRegistGuildCooking(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestRegistGuildCooking_CreateError(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
createMealErr: errNotFound,
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfRegistGuildCooking{
AckHandle: 100,
OverwriteID: 0,
MealID: 5,
Success: 1,
}
handleMsgMhfRegistGuildCooking(session, pkt)
// Should return fail ack
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfGuildHuntdata tests ---
func TestGuildHuntdata_Acquire(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGuildHuntdata{
AckHandle: 100,
Operation: 0, // Acquire
GuildID: 10,
}
handleMsgMhfGuildHuntdata(session, pkt)
if !guildMock.claimBoxCalled {
t.Error("ClaimHuntBox should be called")
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestGuildHuntdata_Enumerate(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
guildKills: []*GuildKill{
{ID: 1, Monster: 100},
{ID: 2, Monster: 200},
},
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGuildHuntdata{
AckHandle: 100,
Operation: 1, // Enumerate
GuildID: 10,
}
handleMsgMhfGuildHuntdata(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 1 {
t.Fatal("Response too short")
}
default:
t.Error("No response packet queued")
}
}
func TestGuildHuntdata_Check_HasKills(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
countKills: 5,
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGuildHuntdata{
AckHandle: 100,
Operation: 2, // Check
GuildID: 10,
}
handleMsgMhfGuildHuntdata(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestGuildHuntdata_Check_NoKills(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
countKills: 0,
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGuildHuntdata{
AckHandle: 100,
Operation: 2,
GuildID: 10,
}
handleMsgMhfGuildHuntdata(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfAddGuildWeeklyBonusExceptionalUser tests ---
func TestAddGuildWeeklyBonusExceptionalUser_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfAddGuildWeeklyBonusExceptionalUser{
AckHandle: 100,
NumUsers: 3,
}
handleMsgMhfAddGuildWeeklyBonusExceptionalUser(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestAddGuildWeeklyBonusExceptionalUser_NoGuild(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.getErr = errNotFound
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfAddGuildWeeklyBonusExceptionalUser{
AckHandle: 100,
NumUsers: 3,
}
// Should not panic; just skips the bonus
handleMsgMhfAddGuildWeeklyBonusExceptionalUser(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}

View File

@@ -0,0 +1,227 @@
package channelserver
import (
"testing"
"time"
"erupe-ce/common/byteframe"
"erupe-ce/network/mhfpacket"
)
// guildInfoServer creates a mock server with ClanMemberLimits set,
// which handleMsgMhfInfoGuild requires.
func guildInfoServer() *Server {
s := createMockServer()
s.erupeConfig.GameplayOptions.ClanMemberLimits = [][]uint8{{0, 30}}
return s
}
// --- handleMsgMhfInfoGuild tests ---
func TestInfoGuild_ByGuildID(t *testing.T) {
server := guildInfoServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 1, IsLeader: true},
}
joined := time.Now()
guildMock.membership.JoinedAt = &joined
guildMock.guild = &Guild{
ID: 10,
Name: "Test",
Comment: "Hello",
MemberCount: 5,
CreatedAt: time.Now(),
RoomExpiry: time.Now().Add(time.Hour),
}
guildMock.guild.LeaderCharID = 1
guildMock.guild.LeaderName = "Leader"
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfInfoGuild{AckHandle: 100, GuildID: 10}
handleMsgMhfInfoGuild(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 20 {
t.Errorf("Response too short: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
if session.prevGuildID != 10 {
t.Errorf("prevGuildID = %d, want 10", session.prevGuildID)
}
}
func TestInfoGuild_ByCharID(t *testing.T) {
server := guildInfoServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 5},
}
guildMock.guild = &Guild{
ID: 10,
Name: "MyGuild",
CreatedAt: time.Now(),
RoomExpiry: time.Now(),
}
guildMock.guild.LeaderCharID = 99
guildMock.guild.LeaderName = "Boss"
server.guildRepo = guildMock
session := createMockSession(1, server)
// GuildID=0 means look up by charID
pkt := &mhfpacket.MsgMhfInfoGuild{AckHandle: 100, GuildID: 0}
handleMsgMhfInfoGuild(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 20 {
t.Errorf("Response too short: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
func TestInfoGuild_NotFound(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.getErr = errNotFound
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfInfoGuild{AckHandle: 100, GuildID: 999}
handleMsgMhfInfoGuild(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestInfoGuild_MembershipError(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
getMemberErr: errNotFound,
}
guildMock.guild = &Guild{
ID: 10,
Name: "Test",
CreatedAt: time.Now(),
RoomExpiry: time.Now(),
}
guildMock.guild.LeaderCharID = 1
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfInfoGuild{AckHandle: 100, GuildID: 10}
handleMsgMhfInfoGuild(session, pkt)
// Should return early with count=0 response
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestInfoGuild_WithAlliance(t *testing.T) {
server := guildInfoServer()
guildMock := &mockGuildRepoOps{
membership: &GuildMember{GuildID: 10, CharID: 1, OrderIndex: 1, IsLeader: true},
alliance: &GuildAlliance{
ID: 5,
Name: "TestAlliance",
CreatedAt: time.Now(),
TotalMembers: 15,
ParentGuildID: 10,
ParentGuild: Guild{Name: "Test", MemberCount: 5},
},
}
guildMock.guild = &Guild{
ID: 10,
Name: "Test",
CreatedAt: time.Now(),
RoomExpiry: time.Now(),
AllianceID: 5,
}
guildMock.guild.LeaderCharID = 1
guildMock.guild.LeaderName = "Leader"
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfInfoGuild{AckHandle: 100, GuildID: 10}
handleMsgMhfInfoGuild(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 50 {
t.Errorf("Alliance response too short: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfEnumerateGuild tests ---
func TestEnumerateGuild_ByName(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.guild = nil
server.guildRepo = guildMock
session := createMockSession(1, server)
// Simulate search term in Data2
data2 := byteframe.NewByteFrame()
data2.WriteBytes([]byte("Test\x00"))
_, _ = data2.Seek(0, 0)
pkt := &mhfpacket.MsgMhfEnumerateGuild{
AckHandle: 100,
Type: mhfpacket.ENUMERATE_GUILD_TYPE_GUILD_NAME,
Data2: data2,
}
handleMsgMhfEnumerateGuild(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestEnumerateGuild_NoResults(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.getErr = errNotFound
server.guildRepo = guildMock
session := createMockSession(1, server)
data2 := byteframe.NewByteFrame()
data2.WriteBytes([]byte("NonExistent\x00"))
_, _ = data2.Seek(0, 0)
pkt := &mhfpacket.MsgMhfEnumerateGuild{
AckHandle: 100,
Type: mhfpacket.ENUMERATE_GUILD_TYPE_GUILD_NAME,
Data2: data2,
}
handleMsgMhfEnumerateGuild(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}

View File

@@ -0,0 +1,204 @@
package channelserver
import (
"testing"
"time"
"erupe-ce/network/mhfpacket"
)
// --- handleMsgMhfEnumerateGuildTresure tests ---
func TestEnumerateGuildTresure_NoGuild(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
guildMock.getErr = errNotFound
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateGuildTresure{AckHandle: 100, MaxHunts: 30}
handleMsgMhfEnumerateGuildTresure(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
func TestEnumerateGuildTresure_PendingHunt(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
pendingHunt: &TreasureHunt{
HuntID: 1,
Destination: 5,
Level: 3,
Start: time.Now(),
HuntData: make([]byte, 10),
},
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateGuildTresure{AckHandle: 100, MaxHunts: 1}
handleMsgMhfEnumerateGuildTresure(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 8 {
t.Errorf("Response too short: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
func TestEnumerateGuildTresure_GuildHunts(t *testing.T) {
server := createMockServer()
// Set a large expiry so hunts are considered active
server.erupeConfig.GameplayOptions.TreasureHuntExpiry = 86400
guildMock := &mockGuildRepoOps{
guildHunts: []*TreasureHunt{
{HuntID: 1, Destination: 5, Level: 2, Start: TimeAdjusted(), HuntData: make([]byte, 10)},
{HuntID: 2, Destination: 8, Level: 3, Start: TimeAdjusted(), HuntData: make([]byte, 10)},
},
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateGuildTresure{AckHandle: 100, MaxHunts: 30}
handleMsgMhfEnumerateGuildTresure(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) < 8 {
t.Errorf("Response too short for 2 hunts: %d bytes", len(p.data))
}
default:
t.Error("No response packet queued")
}
}
func TestEnumerateGuildTresure_ListError(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{
listHuntsErr: errNotFound,
}
guildMock.guild = &Guild{ID: 10}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateGuildTresure{AckHandle: 100, MaxHunts: 30}
handleMsgMhfEnumerateGuildTresure(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfAcquireGuildTresure tests ---
func TestAcquireGuildTresure_Success(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfAcquireGuildTresure{AckHandle: 100, HuntID: 42}
handleMsgMhfAcquireGuildTresure(session, pkt)
if guildMock.acquireHuntID != 42 {
t.Errorf("AcquireHunt ID = %d, want 42", guildMock.acquireHuntID)
}
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}
// --- handleMsgMhfOperateGuildTresureReport tests ---
func TestOperateGuildTresureReport_Register(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuildTresureReport{
AckHandle: 100,
HuntID: 42,
State: 0, // Register
}
handleMsgMhfOperateGuildTresureReport(session, pkt)
if guildMock.reportHuntID != 42 {
t.Errorf("RegisterHuntReport ID = %d, want 42", guildMock.reportHuntID)
}
}
func TestOperateGuildTresureReport_Collect(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuildTresureReport{
AckHandle: 100,
HuntID: 42,
State: 1, // Collect
}
handleMsgMhfOperateGuildTresureReport(session, pkt)
if guildMock.collectHuntID != 42 {
t.Errorf("CollectHunt ID = %d, want 42", guildMock.collectHuntID)
}
}
func TestOperateGuildTresureReport_Claim(t *testing.T) {
server := createMockServer()
guildMock := &mockGuildRepoOps{}
server.guildRepo = guildMock
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfOperateGuildTresureReport{
AckHandle: 100,
HuntID: 42,
State: 2, // Claim
}
handleMsgMhfOperateGuildTresureReport(session, pkt)
if guildMock.claimHuntID != 42 {
t.Errorf("ClaimHuntReward ID = %d, want 42", guildMock.claimHuntID)
}
}
// --- handleMsgMhfGetGuildTresureSouvenir tests ---
func TestGetGuildTresureSouvenir_Empty(t *testing.T) {
server := createMockServer()
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetGuildTresureSouvenir{AckHandle: 100}
handleMsgMhfGetGuildTresureSouvenir(session, pkt)
select {
case <-session.sendPackets:
default:
t.Error("No response packet queued")
}
}

View File

@@ -363,6 +363,47 @@ type mockGuildRepoOps struct {
createdPost []interface{} createdPost []interface{}
deletedPostID uint32 deletedPostID uint32
// Alliance
alliance *GuildAlliance
getAllianceErr error
createAllianceErr error
deleteAllianceErr error
removeAllyErr error
deletedAllianceID uint32
removedAllyArgs []uint32
// Cooking
meals []*GuildMeal
listMealsErr error
createdMealID uint32
createMealErr error
updateMealErr error
// Adventure
adventures []*GuildAdventure
listAdvErr error
createAdvErr error
collectAdvID uint32
chargeAdvID uint32
chargeAdvAmount uint32
// Treasure hunt
pendingHunt *TreasureHunt
guildHunts []*TreasureHunt
listHuntsErr error
acquireHuntID uint32
reportHuntID uint32
collectHuntID uint32
claimHuntID uint32
createHuntErr error
// Hunt data
guildKills []*GuildKill
listKillsErr error
countKills int
countKillsErr error
claimBoxCalled bool
// Data // Data
membership *GuildMember membership *GuildMember
application *GuildApplication application *GuildApplication
@@ -460,6 +501,104 @@ func (m *mockGuildRepoOps) DeletePost(postID uint32) error {
return m.deletePostErr return m.deletePostErr
} }
func (m *mockGuildRepoOps) GetAllianceByID(_ uint32) (*GuildAlliance, error) {
return m.alliance, m.getAllianceErr
}
func (m *mockGuildRepoOps) CreateAlliance(_ string, _ uint32) error {
return m.createAllianceErr
}
func (m *mockGuildRepoOps) DeleteAlliance(id uint32) error {
m.deletedAllianceID = id
return m.deleteAllianceErr
}
func (m *mockGuildRepoOps) RemoveGuildFromAlliance(allyID, guildID, sub1, sub2 uint32) error {
m.removedAllyArgs = []uint32{allyID, guildID, sub1, sub2}
return m.removeAllyErr
}
func (m *mockGuildRepoOps) ListMeals(_ uint32) ([]*GuildMeal, error) {
return m.meals, m.listMealsErr
}
func (m *mockGuildRepoOps) CreateMeal(_, _, _ uint32, _ time.Time) (uint32, error) {
return m.createdMealID, m.createMealErr
}
func (m *mockGuildRepoOps) UpdateMeal(_, _, _ uint32, _ time.Time) error {
return m.updateMealErr
}
func (m *mockGuildRepoOps) ListAdventures(_ uint32) ([]*GuildAdventure, error) {
return m.adventures, m.listAdvErr
}
func (m *mockGuildRepoOps) CreateAdventure(_, _ uint32, _, _ int64) error {
return m.createAdvErr
}
func (m *mockGuildRepoOps) CreateAdventureWithCharge(_, _, _ uint32, _, _ int64) error {
return m.createAdvErr
}
func (m *mockGuildRepoOps) CollectAdventure(id uint32, _ uint32) error {
m.collectAdvID = id
return nil
}
func (m *mockGuildRepoOps) ChargeAdventure(id uint32, amount uint32) error {
m.chargeAdvID = id
m.chargeAdvAmount = amount
return nil
}
func (m *mockGuildRepoOps) GetPendingHunt(_ uint32) (*TreasureHunt, error) {
return m.pendingHunt, nil
}
func (m *mockGuildRepoOps) ListGuildHunts(_, _ uint32) ([]*TreasureHunt, error) {
return m.guildHunts, m.listHuntsErr
}
func (m *mockGuildRepoOps) CreateHunt(_, _, _, _ uint32, _ []byte, _ string) error {
return m.createHuntErr
}
func (m *mockGuildRepoOps) AcquireHunt(id uint32) error {
m.acquireHuntID = id
return nil
}
func (m *mockGuildRepoOps) RegisterHuntReport(id, _ uint32) error {
m.reportHuntID = id
return nil
}
func (m *mockGuildRepoOps) CollectHunt(id uint32) error {
m.collectHuntID = id
return nil
}
func (m *mockGuildRepoOps) ClaimHuntReward(id, _ uint32) error {
m.claimHuntID = id
return nil
}
func (m *mockGuildRepoOps) ClaimHuntBox(_ uint32, _ time.Time) error {
m.claimBoxCalled = true
return nil
}
func (m *mockGuildRepoOps) ListGuildKills(_, _ uint32) ([]*GuildKill, error) {
return m.guildKills, m.listKillsErr
}
func (m *mockGuildRepoOps) CountGuildKills(_, _ uint32) (int, error) {
return m.countKills, m.countKillsErr
}
// --- mockUserRepoForItems --- // --- mockUserRepoForItems ---
type mockUserRepoForItems struct { type mockUserRepoForItems struct {