mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-27 10:03:06 +01:00
test(channelserver): add mock-based handler unit tests
Leverage the new repository interfaces to test handler logic without a database. Adds shared mock implementations (achievement, mail, character, goocoo, guild) and 32 new handler tests covering achievement, mail, cafe/boost, and goocoo handlers.
This commit is contained in:
@@ -3,6 +3,8 @@ package channelserver
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"erupe-ce/network/mhfpacket"
|
||||
)
|
||||
|
||||
func TestMailStruct(t *testing.T) {
|
||||
@@ -81,3 +83,411 @@ func TestMailStruct_DefaultValues(t *testing.T) {
|
||||
t.Error("Default Read should be false")
|
||||
}
|
||||
}
|
||||
|
||||
// --- Mock-based handler tests ---
|
||||
|
||||
func TestHandleMsgMhfListMail_Empty(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{mails: []Mail{}}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
|
||||
pkt := &mhfpacket.MsgMhfListMail{AckHandle: 100}
|
||||
|
||||
handleMsgMhfListMail(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 TestHandleMsgMhfListMail_WithMails(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{
|
||||
mails: []Mail{
|
||||
{ID: 10, SenderID: 100, Subject: "Hello", SenderName: "Sender1", CreatedAt: time.Now()},
|
||||
{ID: 20, SenderID: 200, Subject: "World", SenderName: "Sender2", CreatedAt: time.Now(), Locked: true},
|
||||
},
|
||||
}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
|
||||
pkt := &mhfpacket.MsgMhfListMail{AckHandle: 100}
|
||||
|
||||
handleMsgMhfListMail(session, pkt)
|
||||
|
||||
// Verify mailList was populated
|
||||
if session.mailList == nil {
|
||||
t.Fatal("mailList should be initialized")
|
||||
}
|
||||
if session.mailList[0] != 10 {
|
||||
t.Errorf("mailList[0] = %d, want 10", session.mailList[0])
|
||||
}
|
||||
if session.mailList[1] != 20 {
|
||||
t.Errorf("mailList[1] = %d, want 20", session.mailList[1])
|
||||
}
|
||||
if session.mailAccIndex != 2 {
|
||||
t.Errorf("mailAccIndex = %d, want 2", session.mailAccIndex)
|
||||
}
|
||||
|
||||
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 TestHandleMsgMhfListMail_DBError(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{listErr: errNotFound}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
|
||||
pkt := &mhfpacket.MsgMhfListMail{AckHandle: 100}
|
||||
|
||||
handleMsgMhfListMail(session, pkt)
|
||||
|
||||
select {
|
||||
case p := <-session.sendPackets:
|
||||
// Should return a fallback response with single zero byte
|
||||
if len(p.data) == 0 {
|
||||
t.Error("Should have fallback response data")
|
||||
}
|
||||
default:
|
||||
t.Error("No response packet queued")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfReadMail_Success(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{
|
||||
mailByID: map[int]*Mail{
|
||||
42: {ID: 42, Body: "Test body content"},
|
||||
},
|
||||
}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
session.mailList = make([]int, 256)
|
||||
session.mailList[0] = 42
|
||||
|
||||
pkt := &mhfpacket.MsgMhfReadMail{
|
||||
AckHandle: 100,
|
||||
AccIndex: 0,
|
||||
}
|
||||
|
||||
handleMsgMhfReadMail(session, pkt)
|
||||
|
||||
if mock.markReadCalled != 42 {
|
||||
t.Errorf("MarkRead called with %d, want 42", mock.markReadCalled)
|
||||
}
|
||||
|
||||
select {
|
||||
case p := <-session.sendPackets:
|
||||
if len(p.data) == 0 {
|
||||
t.Error("Response should have body data")
|
||||
}
|
||||
default:
|
||||
t.Error("No response packet queued")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfReadMail_OutOfBounds(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
// mailList is nil, so any AccIndex is out of bounds
|
||||
|
||||
pkt := &mhfpacket.MsgMhfReadMail{
|
||||
AckHandle: 100,
|
||||
AccIndex: 5,
|
||||
}
|
||||
|
||||
handleMsgMhfReadMail(session, pkt)
|
||||
|
||||
select {
|
||||
case p := <-session.sendPackets:
|
||||
// Should get fallback single-byte response
|
||||
if len(p.data) == 0 {
|
||||
t.Error("Should have fallback response")
|
||||
}
|
||||
default:
|
||||
t.Error("No response packet queued")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfReadMail_ZeroMailID(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
session.mailList = make([]int, 256)
|
||||
// mailList[0] is 0 (default)
|
||||
|
||||
pkt := &mhfpacket.MsgMhfReadMail{
|
||||
AckHandle: 100,
|
||||
AccIndex: 0,
|
||||
}
|
||||
|
||||
handleMsgMhfReadMail(session, pkt)
|
||||
|
||||
select {
|
||||
case p := <-session.sendPackets:
|
||||
if len(p.data) == 0 {
|
||||
t.Error("Should have fallback response")
|
||||
}
|
||||
default:
|
||||
t.Error("No response packet queued")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfOprtMail_Delete(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{
|
||||
mailByID: map[int]*Mail{
|
||||
42: {ID: 42},
|
||||
},
|
||||
}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
session.mailList = make([]int, 256)
|
||||
session.mailList[0] = 42
|
||||
|
||||
pkt := &mhfpacket.MsgMhfOprtMail{
|
||||
AckHandle: 100,
|
||||
AccIndex: 0,
|
||||
Operation: mhfpacket.OperateMailDelete,
|
||||
}
|
||||
|
||||
handleMsgMhfOprtMail(session, pkt)
|
||||
|
||||
if mock.markDeletedID != 42 {
|
||||
t.Errorf("MarkDeleted called with %d, want 42", mock.markDeletedID)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-session.sendPackets:
|
||||
default:
|
||||
t.Error("No response packet queued")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfOprtMail_Lock(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{
|
||||
mailByID: map[int]*Mail{
|
||||
42: {ID: 42},
|
||||
},
|
||||
}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
session.mailList = make([]int, 256)
|
||||
session.mailList[0] = 42
|
||||
|
||||
pkt := &mhfpacket.MsgMhfOprtMail{
|
||||
AckHandle: 100,
|
||||
AccIndex: 0,
|
||||
Operation: mhfpacket.OperateMailLock,
|
||||
}
|
||||
|
||||
handleMsgMhfOprtMail(session, pkt)
|
||||
|
||||
if mock.lockID != 42 || !mock.lockValue {
|
||||
t.Errorf("SetLocked called with ID=%d locked=%v, want ID=42 locked=true", mock.lockID, mock.lockValue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfOprtMail_Unlock(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{
|
||||
mailByID: map[int]*Mail{
|
||||
42: {ID: 42},
|
||||
},
|
||||
}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
session.mailList = make([]int, 256)
|
||||
session.mailList[0] = 42
|
||||
|
||||
pkt := &mhfpacket.MsgMhfOprtMail{
|
||||
AckHandle: 100,
|
||||
AccIndex: 0,
|
||||
Operation: mhfpacket.OperateMailUnlock,
|
||||
}
|
||||
|
||||
handleMsgMhfOprtMail(session, pkt)
|
||||
|
||||
if mock.lockID != 42 || mock.lockValue {
|
||||
t.Errorf("SetLocked called with ID=%d locked=%v, want ID=42 locked=false", mock.lockID, mock.lockValue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfOprtMail_AcquireItem(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{
|
||||
mailByID: map[int]*Mail{
|
||||
42: {ID: 42, AttachedItemID: 100, AttachedItemAmount: 5},
|
||||
},
|
||||
}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
session.mailList = make([]int, 256)
|
||||
session.mailList[0] = 42
|
||||
|
||||
pkt := &mhfpacket.MsgMhfOprtMail{
|
||||
AckHandle: 100,
|
||||
AccIndex: 0,
|
||||
Operation: mhfpacket.OperateMailAcquireItem,
|
||||
}
|
||||
|
||||
handleMsgMhfOprtMail(session, pkt)
|
||||
|
||||
if mock.itemReceivedID != 42 {
|
||||
t.Errorf("MarkItemReceived called with %d, want 42", mock.itemReceivedID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfOprtMail_OutOfBounds(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
// No mailList set
|
||||
|
||||
pkt := &mhfpacket.MsgMhfOprtMail{
|
||||
AckHandle: 100,
|
||||
AccIndex: 5,
|
||||
Operation: mhfpacket.OperateMailDelete,
|
||||
}
|
||||
|
||||
handleMsgMhfOprtMail(session, pkt)
|
||||
|
||||
// Should not have called any repo methods
|
||||
if mock.markDeletedID != 0 {
|
||||
t.Error("Should not have called MarkDeleted for out-of-bounds access")
|
||||
}
|
||||
|
||||
select {
|
||||
case <-session.sendPackets:
|
||||
default:
|
||||
t.Error("No response packet queued")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfSendMail_Direct(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := &mockMailRepo{}
|
||||
server.mailRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
|
||||
pkt := &mhfpacket.MsgMhfSendMail{
|
||||
AckHandle: 100,
|
||||
RecipientID: 42,
|
||||
Subject: "Hello",
|
||||
Body: "World",
|
||||
ItemID: 500,
|
||||
Quantity: 3,
|
||||
}
|
||||
|
||||
handleMsgMhfSendMail(session, pkt)
|
||||
|
||||
if len(mock.sentMails) != 1 {
|
||||
t.Fatalf("Expected 1 sent mail, got %d", len(mock.sentMails))
|
||||
}
|
||||
sent := mock.sentMails[0]
|
||||
if sent.senderID != 1 {
|
||||
t.Errorf("SenderID = %d, want 1", sent.senderID)
|
||||
}
|
||||
if sent.recipientID != 42 {
|
||||
t.Errorf("RecipientID = %d, want 42", sent.recipientID)
|
||||
}
|
||||
if sent.subject != "Hello" {
|
||||
t.Errorf("Subject = %s, want Hello", sent.subject)
|
||||
}
|
||||
if sent.itemID != 500 {
|
||||
t.Errorf("ItemID = %d, want 500", sent.itemID)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-session.sendPackets:
|
||||
default:
|
||||
t.Error("No response packet queued")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfSendMail_Guild(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mailMock := &mockMailRepo{}
|
||||
guildMock := &mockGuildRepoForMail{
|
||||
guild: &Guild{ID: 10},
|
||||
members: []*GuildMember{
|
||||
{CharID: 100},
|
||||
{CharID: 200},
|
||||
{CharID: 300},
|
||||
},
|
||||
}
|
||||
server.mailRepo = mailMock
|
||||
server.guildRepo = guildMock
|
||||
session := createMockSession(1, server)
|
||||
|
||||
pkt := &mhfpacket.MsgMhfSendMail{
|
||||
AckHandle: 100,
|
||||
RecipientID: 0, // 0 = guild mail
|
||||
Subject: "Guild News",
|
||||
Body: "Important update",
|
||||
}
|
||||
|
||||
handleMsgMhfSendMail(session, pkt)
|
||||
|
||||
if len(mailMock.sentMails) != 3 {
|
||||
t.Fatalf("Expected 3 sent mails (one per guild member), got %d", len(mailMock.sentMails))
|
||||
}
|
||||
for i, sent := range mailMock.sentMails {
|
||||
if sent.senderID != 1 {
|
||||
t.Errorf("Mail %d: SenderID = %d, want 1", i, sent.senderID)
|
||||
}
|
||||
}
|
||||
recipients := map[uint32]bool{}
|
||||
for _, sent := range mailMock.sentMails {
|
||||
recipients[sent.recipientID] = true
|
||||
}
|
||||
if !recipients[100] || !recipients[200] || !recipients[300] {
|
||||
t.Errorf("Expected recipients 100, 200, 300, got %v", recipients)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleMsgMhfSendMail_GuildNotFound(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mailMock := &mockMailRepo{}
|
||||
guildMock := &mockGuildRepoForMail{getErr: errNotFound}
|
||||
server.mailRepo = mailMock
|
||||
server.guildRepo = guildMock
|
||||
session := createMockSession(1, server)
|
||||
|
||||
pkt := &mhfpacket.MsgMhfSendMail{
|
||||
AckHandle: 100,
|
||||
RecipientID: 0, // Guild mail
|
||||
Subject: "Guild News",
|
||||
Body: "Update",
|
||||
}
|
||||
|
||||
handleMsgMhfSendMail(session, pkt)
|
||||
|
||||
if len(mailMock.sentMails) != 0 {
|
||||
t.Errorf("No mails should be sent when guild not found, got %d", len(mailMock.sentMails))
|
||||
}
|
||||
|
||||
select {
|
||||
case <-session.sendPackets:
|
||||
default:
|
||||
t.Error("No response packet queued")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user