test(channelserver): add handler coverage tests for misc, cafe, festa, event

Add four new test files covering previously-untested handler functions
to raise total coverage from 57.7% to 60.0%:

- handlers_misc_coverage_test.go: minidata, trend weapons, etc points,
  equip skin history
- handlers_cafe_coverage_test.go: cafe duration bonuses, daily cafe,
  cafe duration
- handlers_festa_coverage_test.go: mezfes data, festa voting, entry,
  charge, prizes, state queries, member enumeration
- handlers_event_coverage_test.go: weekly schedule, login boost,
  scenario data, friends/blacklist operations

Also make mockCharacterRepo.ReadEtcPoints configurable to support
etc points handler tests.
This commit is contained in:
Houmgaor
2026-02-26 22:28:32 +01:00
parent 4a1e019457
commit cdc4cd9ba3
5 changed files with 1060 additions and 1 deletions

View File

@@ -0,0 +1,213 @@
package channelserver
import (
"erupe-ce/common/mhfcourse"
"erupe-ce/network/mhfpacket"
"errors"
"testing"
"time"
)
// --- Cafe Duration Bonus Info tests ---
func TestHandleMsgMhfGetCafeDurationBonusInfo_Error(t *testing.T) {
srv := createMockServer()
srv.cafeRepo = &mockCafeRepo{bonusesErr: errors.New("db error")}
srv.charRepo = newMockCharacterRepo()
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetCafeDurationBonusInfo{AckHandle: 1}
handleMsgMhfGetCafeDurationBonusInfo(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfGetCafeDurationBonusInfo_WithBonuses(t *testing.T) {
srv := createMockServer()
srv.cafeRepo = &mockCafeRepo{
bonuses: []CafeBonus{
{ID: 1, TimeReq: 100, ItemType: 5, ItemID: 10, Quantity: 2, Claimed: false},
{ID: 2, TimeReq: 200, ItemType: 6, ItemID: 20, Quantity: 1, Claimed: true},
},
}
srv.charRepo = newMockCharacterRepo()
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetCafeDurationBonusInfo{AckHandle: 1}
handleMsgMhfGetCafeDurationBonusInfo(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
// --- Receive Cafe Duration Bonus tests ---
func TestHandleMsgMhfReceiveCafeDurationBonus_Error(t *testing.T) {
srv := createMockServer()
srv.cafeRepo = &mockCafeRepo{claimableErr: errors.New("db error")}
srv.charRepo = newMockCharacterRepo()
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfReceiveCafeDurationBonus{AckHandle: 1}
handleMsgMhfReceiveCafeDurationBonus(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfReceiveCafeDurationBonus_WithClaimable(t *testing.T) {
srv := createMockServer()
srv.cafeRepo = &mockCafeRepo{
claimable: []CafeBonus{
{ID: 1, ItemType: 5, ItemID: 10, Quantity: 2},
},
}
srv.charRepo = newMockCharacterRepo()
s := createMockSession(100, srv)
// Course 30 is required for claimable items
s.courses = []mhfcourse.Course{{ID: 30}}
pkt := &mhfpacket.MsgMhfReceiveCafeDurationBonus{AckHandle: 1}
handleMsgMhfReceiveCafeDurationBonus(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
// --- Post Cafe Duration Bonus Received tests ---
func TestHandleMsgMhfPostCafeDurationBonusReceived_Empty(t *testing.T) {
srv := createMockServer()
srv.cafeRepo = &mockCafeRepo{}
srv.charRepo = newMockCharacterRepo()
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfPostCafeDurationBonusReceived{AckHandle: 1, CafeBonusID: []uint32{}}
handleMsgMhfPostCafeDurationBonusReceived(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfPostCafeDurationBonusReceived_WithBonusIDs(t *testing.T) {
srv := createMockServer()
srv.cafeRepo = &mockCafeRepo{
bonusItemType: 17, // netcafe point type
bonusItemQty: 100,
}
charRepo := newMockCharacterRepo()
charRepo.ints["netcafe_points"] = 50
srv.charRepo = charRepo
s := createMockSession(100, srv)
srv.erupeConfig.GameplayOptions.MaximumNP = 99999
pkt := &mhfpacket.MsgMhfPostCafeDurationBonusReceived{AckHandle: 1, CafeBonusID: []uint32{1, 2}}
handleMsgMhfPostCafeDurationBonusReceived(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
// --- Daily Cafe Point tests ---
func TestHandleMsgMhfCheckDailyCafepoint_Eligible(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
// Set daily_time far in the past so midday.After(dailyTime) is true
charRepo.times["daily_time"] = time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
charRepo.ints["netcafe_points"] = 10
srv.charRepo = charRepo
srv.erupeConfig.GameplayOptions.MaximumNP = 99999
srv.erupeConfig.GameplayOptions.BonusQuestAllowance = 10
srv.erupeConfig.GameplayOptions.DailyQuestAllowance = 5
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfCheckDailyCafepoint{AckHandle: 1}
handleMsgMhfCheckDailyCafepoint(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfCheckDailyCafepoint_NotEligible(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
// Set daily_time far in the future so midday.After(dailyTime) is false
charRepo.times["daily_time"] = time.Date(2099, 12, 31, 23, 59, 59, 0, time.UTC)
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfCheckDailyCafepoint{AckHandle: 1}
handleMsgMhfCheckDailyCafepoint(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
// --- Cafe Duration tests ---
func TestHandleMsgMhfGetCafeDuration(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
// cafe_reset in the future so we don't trigger reset logic
charRepo.times["cafe_reset"] = time.Date(2099, 12, 31, 0, 0, 0, 0, time.UTC)
charRepo.ints["cafe_time"] = 3600
srv.charRepo = charRepo
srv.cafeRepo = &mockCafeRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetCafeDuration{AckHandle: 1}
handleMsgMhfGetCafeDuration(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}

View File

@@ -0,0 +1,226 @@
package channelserver
import (
"erupe-ce/network/mhfpacket"
"testing"
"time"
)
func TestHandleMsgMhfGetWeeklySchedule(t *testing.T) {
srv := createMockServer()
srv.eventRepo = &mockEventRepo{}
srv.erupeConfig.GameplayOptions.MinFeatureWeapons = 1
srv.erupeConfig.GameplayOptions.MaxFeatureWeapons = 3
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetWeeklySchedule{AckHandle: 1}
handleMsgMhfGetWeeklySchedule(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfGetKeepLoginBoostStatus_Disabled(t *testing.T) {
srv := createMockServer()
srv.eventRepo = &mockEventRepo{}
srv.erupeConfig.GameplayOptions.DisableLoginBoost = true
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetKeepLoginBoostStatus{AckHandle: 1}
handleMsgMhfGetKeepLoginBoostStatus(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfGetKeepLoginBoostStatus_EmptyBoosts(t *testing.T) {
srv := createMockServer()
srv.eventRepo = &mockEventRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetKeepLoginBoostStatus{AckHandle: 1}
handleMsgMhfGetKeepLoginBoostStatus(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfGetKeepLoginBoostStatus_WithBoosts(t *testing.T) {
srv := createMockServer()
srv.eventRepo = &mockEventRepo{
loginBoosts: []loginBoost{
{WeekReq: 1, Expiration: time.Now().Add(-7 * 24 * time.Hour)},
{WeekReq: 2, Expiration: time.Now().Add(-14 * 24 * time.Hour)},
{WeekReq: 3, Expiration: time.Now().Add(-21 * 24 * time.Hour)},
{WeekReq: 4, Expiration: time.Now().Add(-28 * 24 * time.Hour)},
{WeekReq: 5, Expiration: time.Now().Add(-35 * 24 * time.Hour)},
},
}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetKeepLoginBoostStatus{AckHandle: 1}
handleMsgMhfGetKeepLoginBoostStatus(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfUseKeepLoginBoost(t *testing.T) {
tests := []struct {
name string
boostWeekUsed uint8
}{
{"week1", 1},
{"week2", 2},
{"week3", 3},
{"week4", 4},
{"week5", 5},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
srv := createMockServer()
srv.eventRepo = &mockEventRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfUseKeepLoginBoost{AckHandle: 1, BoostWeekUsed: tt.boostWeekUsed}
handleMsgMhfUseKeepLoginBoost(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
})
}
}
func TestHandleMsgMhfLoadScenarioData(t *testing.T) {
srv := createMockServer()
srv.charRepo = newMockCharacterRepo()
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfLoadScenarioData{AckHandle: 1}
handleMsgMhfLoadScenarioData(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfSaveScenarioData(t *testing.T) {
srv := createMockServer()
srv.charRepo = newMockCharacterRepo()
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfSaveScenarioData{AckHandle: 1, RawDataPayload: []byte{0x01, 0x02, 0x03}}
handleMsgMhfSaveScenarioData(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfListMember(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
charRepo.strings["blocked"] = ""
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfListMember{AckHandle: 1}
handleMsgMhfListMember(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfOprMember_AddBlacklist(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
charRepo.strings["blocked"] = ""
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfOprMember{AckHandle: 1, Blacklist: true, Operation: false, CharIDs: []uint32{42}}
handleMsgMhfOprMember(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfOprMember_AddFriend(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
charRepo.strings["friends"] = ""
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfOprMember{AckHandle: 1, Blacklist: false, Operation: false, CharIDs: []uint32{42}}
handleMsgMhfOprMember(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfOprMember_RemoveBlacklist(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
charRepo.strings["blocked"] = "42"
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfOprMember{AckHandle: 1, Blacklist: true, Operation: true, CharIDs: []uint32{42}}
handleMsgMhfOprMember(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}

View File

@@ -0,0 +1,301 @@
package channelserver
import (
"erupe-ce/network/mhfpacket"
"testing"
)
func TestHandleMsgMhfSaveMezfesData(t *testing.T) {
srv := createMockServer()
srv.charRepo = newMockCharacterRepo()
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfSaveMezfesData{AckHandle: 1, RawDataPayload: []byte{0x01, 0x02}}
handleMsgMhfSaveMezfesData(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfLoadMezfesData(t *testing.T) {
srv := createMockServer()
srv.charRepo = newMockCharacterRepo()
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfLoadMezfesData{AckHandle: 1}
handleMsgMhfLoadMezfesData(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfVoteFesta(t *testing.T) {
srv := createMockServer()
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfVoteFesta{AckHandle: 1, TrialID: 42}
handleMsgMhfVoteFesta(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfEntryFesta_NoGuild(t *testing.T) {
srv := createMockServer()
srv.guildRepo = &mockGuildRepo{getErr: errNotFound}
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfEntryFesta{AckHandle: 1}
handleMsgMhfEntryFesta(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfEntryFesta_WithGuild(t *testing.T) {
srv := createMockServer()
srv.guildRepo = &mockGuildRepo{guild: &Guild{ID: 1}}
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfEntryFesta{AckHandle: 1}
handleMsgMhfEntryFesta(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfChargeFesta(t *testing.T) {
srv := createMockServer()
srv.festaRepo = &mockFestaRepo{}
srv.guildRepo = &mockGuildRepo{guild: &Guild{ID: 1}}
ensureFestaService(srv)
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfChargeFesta{AckHandle: 1, GuildID: 1, Souls: []uint16{10, 20}}
handleMsgMhfChargeFesta(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfAcquireFesta(t *testing.T) {
srv := createMockServer()
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfAcquireFesta{AckHandle: 1}
handleMsgMhfAcquireFesta(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfAcquireFestaPersonalPrize(t *testing.T) {
srv := createMockServer()
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfAcquireFestaPersonalPrize{AckHandle: 1, PrizeID: 5}
handleMsgMhfAcquireFestaPersonalPrize(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfAcquireFestaIntermediatePrize(t *testing.T) {
srv := createMockServer()
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfAcquireFestaIntermediatePrize{AckHandle: 1, PrizeID: 3}
handleMsgMhfAcquireFestaIntermediatePrize(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateFestaPersonalPrize(t *testing.T) {
srv := createMockServer()
srv.festaRepo = &mockFestaRepo{
prizes: []Prize{
{ID: 1, Tier: 1, SoulsReq: 100, ItemID: 5, NumItem: 1, Claimed: 0},
},
}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfEnumerateFestaPersonalPrize{AckHandle: 1}
handleMsgMhfEnumerateFestaPersonalPrize(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateFestaIntermediatePrize(t *testing.T) {
srv := createMockServer()
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfEnumerateFestaIntermediatePrize{AckHandle: 1}
handleMsgMhfEnumerateFestaIntermediatePrize(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfStateFestaU_NoGuild(t *testing.T) {
srv := createMockServer()
srv.guildRepo = &mockGuildRepo{getErr: errNotFound}
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfStateFestaU{AckHandle: 1}
handleMsgMhfStateFestaU(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfStateFestaU_WithGuild(t *testing.T) {
srv := createMockServer()
srv.guildRepo = &mockGuildRepo{guild: &Guild{ID: 1}}
srv.festaRepo = &mockFestaRepo{charSouls: 50}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfStateFestaU{AckHandle: 1}
handleMsgMhfStateFestaU(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfStateFestaG_NoGuild(t *testing.T) {
srv := createMockServer()
srv.guildRepo = &mockGuildRepo{getErr: errNotFound}
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfStateFestaG{AckHandle: 1}
handleMsgMhfStateFestaG(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfStateFestaG_WithGuild(t *testing.T) {
srv := createMockServer()
srv.guildRepo = &mockGuildRepo{guild: &Guild{ID: 1, Souls: 500}}
srv.festaRepo = &mockFestaRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfStateFestaG{AckHandle: 1}
handleMsgMhfStateFestaG(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateFestaMember_NoGuild(t *testing.T) {
srv := createMockServer()
srv.guildRepo = &mockGuildRepo{getErr: errNotFound}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfEnumerateFestaMember{AckHandle: 1}
handleMsgMhfEnumerateFestaMember(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateFestaMember_WithMembers(t *testing.T) {
srv := createMockServer()
srv.guildRepo = &mockGuildRepo{
guild: &Guild{ID: 1},
members: []*GuildMember{
{CharID: 1, Souls: 100},
{CharID: 2, Souls: 50},
{CharID: 3, Souls: 0},
},
}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfEnumerateFestaMember{AckHandle: 1}
handleMsgMhfEnumerateFestaMember(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}

View File

@@ -0,0 +1,313 @@
package channelserver
import (
"erupe-ce/network/mhfpacket"
"testing"
)
// --- Enhanced Minidata tests (in-memory store, no DB) ---
func TestHandleMsgMhfGetEnhancedMinidata_NotFound(t *testing.T) {
srv := createMockServer()
srv.minidata = NewMinidataStore()
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetEnhancedMinidata{AckHandle: 1, CharID: 999}
handleMsgMhfGetEnhancedMinidata(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfGetEnhancedMinidata_Found(t *testing.T) {
srv := createMockServer()
srv.minidata = NewMinidataStore()
srv.minidata.Set(42, []byte{0xDE, 0xAD, 0xBE, 0xEF})
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetEnhancedMinidata{AckHandle: 1, CharID: 42}
handleMsgMhfGetEnhancedMinidata(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfSetEnhancedMinidata(t *testing.T) {
srv := createMockServer()
srv.minidata = NewMinidataStore()
s := createMockSession(100, srv)
payload := []byte{0x01, 0x02, 0x03}
pkt := &mhfpacket.MsgMhfSetEnhancedMinidata{AckHandle: 1, RawDataPayload: payload}
handleMsgMhfSetEnhancedMinidata(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
data, ok := srv.minidata.Get(100)
if !ok {
t.Fatal("Minidata not stored")
}
if len(data) != 3 || data[0] != 0x01 {
t.Errorf("Unexpected stored data: %v", data)
}
}
// --- Trend Weapon tests ---
func TestHandleMsgMhfGetTrendWeapon_Empty(t *testing.T) {
srv := createMockServer()
srv.miscRepo = &mockMiscRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetTrendWeapon{AckHandle: 1}
handleMsgMhfGetTrendWeapon(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfGetTrendWeapon_WithWeapons(t *testing.T) {
srv := createMockServer()
srv.miscRepo = &mockMiscRepo{
trendWeapons: []uint16{100, 200, 300},
}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetTrendWeapon{AckHandle: 1}
handleMsgMhfGetTrendWeapon(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfUpdateUseTrendWeaponLog(t *testing.T) {
srv := createMockServer()
srv.miscRepo = &mockMiscRepo{}
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfUpdateUseTrendWeaponLog{AckHandle: 1, WeaponType: 3, WeaponID: 500}
handleMsgMhfUpdateUseTrendWeaponLog(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
}
// --- Etc Points tests ---
func TestHandleMsgMhfGetEtcPoints(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
charRepo.etcBonusQuests = 100
charRepo.etcDailyQuests = 50
charRepo.etcPromoPoints = 25
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetEtcPoints{AckHandle: 1}
handleMsgMhfGetEtcPoints(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfUpdateEtcPoint(t *testing.T) {
tests := []struct {
name string
pointType uint8
delta int16
column string
}{
{"bonus_quests", 0, 5, "bonus_quests"},
{"daily_quests", 1, 3, "daily_quests"},
{"promo_points", 2, 1, "promo_points"},
{"invalid_type", 99, 1, ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfUpdateEtcPoint{
AckHandle: 1,
PointType: tt.pointType,
Delta: tt.delta,
}
handleMsgMhfUpdateEtcPoint(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
if tt.column != "" {
val := charRepo.ints[tt.column]
if val != int(tt.delta) {
t.Errorf("Expected %s=%d, got %d", tt.column, tt.delta, val)
}
}
})
}
}
func TestHandleMsgMhfUpdateEtcPoint_NegativeDelta(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
charRepo.ints["bonus_quests"] = 10
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfUpdateEtcPoint{AckHandle: 1, PointType: 0, Delta: -5}
handleMsgMhfUpdateEtcPoint(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
if charRepo.ints["bonus_quests"] != 5 {
t.Errorf("Expected bonus_quests=5, got %d", charRepo.ints["bonus_quests"])
}
}
func TestHandleMsgMhfUpdateEtcPoint_ClampToZero(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
charRepo.ints["bonus_quests"] = 3
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfUpdateEtcPoint{AckHandle: 1, PointType: 0, Delta: -10}
handleMsgMhfUpdateEtcPoint(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
if charRepo.ints["bonus_quests"] != 0 {
t.Errorf("Expected bonus_quests=0, got %d", charRepo.ints["bonus_quests"])
}
}
// --- Equip Skin History tests ---
func TestHandleMsgMhfGetEquipSkinHist(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfGetEquipSkinHist{AckHandle: 1}
handleMsgMhfGetEquipSkinHist(s, pkt)
select {
case p := <-s.sendPackets:
if len(p.data) == 0 {
t.Fatal("Expected non-empty response")
}
default:
t.Fatal("No response packet queued")
}
}
func TestHandleMsgMhfUpdateEquipSkinHist_Valid(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfUpdateEquipSkinHist{AckHandle: 1, ArmourID: 10001, MogType: 0}
handleMsgMhfUpdateEquipSkinHist(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
if _, ok := charRepo.columns["skin_hist"]; !ok {
t.Error("Expected skin_hist to be saved")
}
}
func TestHandleMsgMhfUpdateEquipSkinHist_LowArmourID(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfUpdateEquipSkinHist{AckHandle: 1, ArmourID: 5000, MogType: 0}
handleMsgMhfUpdateEquipSkinHist(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
if _, ok := charRepo.columns["skin_hist"]; ok {
t.Error("Expected skin_hist NOT to be saved for low ArmourID")
}
}
func TestHandleMsgMhfUpdateEquipSkinHist_HighMogType(t *testing.T) {
srv := createMockServer()
charRepo := newMockCharacterRepo()
srv.charRepo = charRepo
s := createMockSession(100, srv)
pkt := &mhfpacket.MsgMhfUpdateEquipSkinHist{AckHandle: 1, ArmourID: 10001, MogType: 5}
handleMsgMhfUpdateEquipSkinHist(s, pkt)
select {
case <-s.sendPackets:
default:
t.Fatal("No response packet queued")
}
if _, ok := charRepo.columns["skin_hist"]; ok {
t.Error("Expected skin_hist NOT to be saved for high MogType")
}
}

View File

@@ -121,6 +121,12 @@ type mockCharacterRepo struct {
loadSaveDataNew bool loadSaveDataNew bool
loadSaveDataName string loadSaveDataName string
loadSaveDataErr error loadSaveDataErr error
// ReadEtcPoints mock fields
etcBonusQuests uint32
etcDailyQuests uint32
etcPromoPoints uint32
etcPointsErr error
} }
func newMockCharacterRepo() *mockCharacterRepo { func newMockCharacterRepo() *mockCharacterRepo {
@@ -205,7 +211,7 @@ func (m *mockCharacterRepo) SetDeleted(_ uint32) error
func (m *mockCharacterRepo) UpdateDailyCafe(_ uint32, _ time.Time, _, _ uint32) error { return nil } func (m *mockCharacterRepo) UpdateDailyCafe(_ uint32, _ time.Time, _, _ uint32) error { return nil }
func (m *mockCharacterRepo) ResetDailyQuests(_ uint32) error { return nil } func (m *mockCharacterRepo) ResetDailyQuests(_ uint32) error { return nil }
func (m *mockCharacterRepo) ReadEtcPoints(_ uint32) (uint32, uint32, uint32, error) { func (m *mockCharacterRepo) ReadEtcPoints(_ uint32) (uint32, uint32, uint32, error) {
return 0, 0, 0, nil return m.etcBonusQuests, m.etcDailyQuests, m.etcPromoPoints, m.etcPointsErr
} }
func (m *mockCharacterRepo) ResetCafeTime(_ uint32, _ time.Time) error { return nil } func (m *mockCharacterRepo) ResetCafeTime(_ uint32, _ time.Time) error { return nil }
func (m *mockCharacterRepo) UpdateGuildPostChecked(_ uint32) error { return nil } func (m *mockCharacterRepo) UpdateGuildPostChecked(_ uint32) error { return nil }