mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 15:43:49 +01:00
Add zero-dependency SQLite mode so users can run Erupe without
PostgreSQL. A transparent db.DB wrapper auto-translates PostgreSQL
SQL ($N placeholders, now(), ::casts, ILIKE, public. prefix,
TRUNCATE) for SQLite at runtime — all 28 repo files use the wrapper
with no per-query changes needed.
Setup wizard gains two new steps: quest file detection with download
link, and gameplay presets (solo/small/community/rebalanced). The API
server gets a /dashboard endpoint with auto-refreshing stats.
CI release workflow now builds and pushes Docker images to GHCR
alongside binary artifacts on tag push.
Key changes:
- common/db: DB/Tx wrapper with 6 SQL translation rules
- server/migrations/sqlite: full SQLite schema (0001-0005)
- config: Database.Driver field ("postgres" or "sqlite")
- main.go: SQLite connection with WAL mode, single writer
- server/setup: quest check + preset selection steps
- server/api: /dashboard with live stats
- .github/workflows: Docker in release, deduplicate docker.yml
661 lines
18 KiB
Go
661 lines
18 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"testing"
|
|
|
|
"erupe-ce/common/byteframe"
|
|
cfg "erupe-ce/config"
|
|
"erupe-ce/network/mhfpacket"
|
|
)
|
|
|
|
func TestHandleMsgMhfLoadLegendDispatch(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfLoadLegendDispatch{
|
|
AckHandle: 12345,
|
|
}
|
|
|
|
handleMsgMhfLoadLegendDispatch(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Error("Response packet should have data")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
// --- NEW TESTS ---
|
|
|
|
// buildCatBytes constructs a binary cat data payload suitable for GetAirouDetails.
|
|
func buildCatBytes(cats []Airou) []byte {
|
|
buf := new(bytes.Buffer)
|
|
// catCount
|
|
buf.WriteByte(byte(len(cats)))
|
|
for _, cat := range cats {
|
|
catBuf := new(bytes.Buffer)
|
|
// ID (uint32)
|
|
_ = binary.Write(catBuf, binary.BigEndian, cat.ID)
|
|
// 1 byte skip (unknown bool)
|
|
catBuf.WriteByte(0)
|
|
// Name (18 bytes)
|
|
name := make([]byte, 18)
|
|
copy(name, cat.Name)
|
|
catBuf.Write(name)
|
|
// Task (uint8)
|
|
catBuf.WriteByte(cat.Task)
|
|
// 16 bytes skip (appearance data)
|
|
catBuf.Write(make([]byte, 16))
|
|
// Personality (uint8)
|
|
catBuf.WriteByte(cat.Personality)
|
|
// Class (uint8)
|
|
catBuf.WriteByte(cat.Class)
|
|
// 5 bytes skip (affection and colour sliders)
|
|
catBuf.Write(make([]byte, 5))
|
|
// Experience (uint32)
|
|
_ = binary.Write(catBuf, binary.BigEndian, cat.Experience)
|
|
// 1 byte skip (bool for weapon equipped)
|
|
catBuf.WriteByte(0)
|
|
// WeaponType (uint8)
|
|
catBuf.WriteByte(cat.WeaponType)
|
|
// WeaponID (uint16)
|
|
_ = binary.Write(catBuf, binary.BigEndian, cat.WeaponID)
|
|
|
|
catData := catBuf.Bytes()
|
|
// catDefLen (uint32) - total length of the cat data after this field
|
|
_ = binary.Write(buf, binary.BigEndian, uint32(len(catData)))
|
|
buf.Write(catData)
|
|
}
|
|
return buf.Bytes()
|
|
}
|
|
|
|
func TestGetAirouDetails_Empty(t *testing.T) {
|
|
// Zero cats
|
|
data := []byte{0x00}
|
|
bf := byteframe.NewByteFrameFromBytes(data)
|
|
cats := GetAirouDetails(bf)
|
|
|
|
if len(cats) != 0 {
|
|
t.Errorf("Expected 0 cats, got %d", len(cats))
|
|
}
|
|
}
|
|
|
|
func TestGetAirouDetails_SingleCat(t *testing.T) {
|
|
input := Airou{
|
|
ID: 42,
|
|
Name: []byte("TestCat"),
|
|
Task: 4,
|
|
Personality: 3,
|
|
Class: 2,
|
|
Experience: 1500,
|
|
WeaponType: 6,
|
|
WeaponID: 100,
|
|
}
|
|
|
|
data := buildCatBytes([]Airou{input})
|
|
bf := byteframe.NewByteFrameFromBytes(data)
|
|
cats := GetAirouDetails(bf)
|
|
|
|
if len(cats) != 1 {
|
|
t.Fatalf("Expected 1 cat, got %d", len(cats))
|
|
}
|
|
|
|
cat := cats[0]
|
|
if cat.ID != 42 {
|
|
t.Errorf("ID = %d, want 42", cat.ID)
|
|
}
|
|
if cat.Task != 4 {
|
|
t.Errorf("Task = %d, want 4", cat.Task)
|
|
}
|
|
if cat.Personality != 3 {
|
|
t.Errorf("Personality = %d, want 3", cat.Personality)
|
|
}
|
|
if cat.Class != 2 {
|
|
t.Errorf("Class = %d, want 2", cat.Class)
|
|
}
|
|
if cat.Experience != 1500 {
|
|
t.Errorf("Experience = %d, want 1500", cat.Experience)
|
|
}
|
|
if cat.WeaponType != 6 {
|
|
t.Errorf("WeaponType = %d, want 6", cat.WeaponType)
|
|
}
|
|
if cat.WeaponID != 100 {
|
|
t.Errorf("WeaponID = %d, want 100", cat.WeaponID)
|
|
}
|
|
// Name should be 18 bytes (padded with nulls)
|
|
if len(cat.Name) != 18 {
|
|
t.Errorf("Name length = %d, want 18", len(cat.Name))
|
|
}
|
|
// First bytes should match "TestCat"
|
|
if !bytes.HasPrefix(cat.Name, []byte("TestCat")) {
|
|
t.Errorf("Name does not start with 'TestCat', got %v", cat.Name)
|
|
}
|
|
}
|
|
|
|
func TestGetAirouDetails_MultipleCats(t *testing.T) {
|
|
inputs := []Airou{
|
|
{ID: 1, Name: []byte("Alpha"), Task: 1, Personality: 0, Class: 0, Experience: 100, WeaponType: 6, WeaponID: 10},
|
|
{ID: 2, Name: []byte("Beta"), Task: 2, Personality: 1, Class: 1, Experience: 200, WeaponType: 6, WeaponID: 20},
|
|
{ID: 3, Name: []byte("Gamma"), Task: 4, Personality: 2, Class: 2, Experience: 300, WeaponType: 6, WeaponID: 30},
|
|
}
|
|
|
|
data := buildCatBytes(inputs)
|
|
bf := byteframe.NewByteFrameFromBytes(data)
|
|
cats := GetAirouDetails(bf)
|
|
|
|
if len(cats) != 3 {
|
|
t.Fatalf("Expected 3 cats, got %d", len(cats))
|
|
}
|
|
|
|
for i, cat := range cats {
|
|
if cat.ID != inputs[i].ID {
|
|
t.Errorf("Cat %d: CatID = %d, want %d", i, cat.ID, inputs[i].ID)
|
|
}
|
|
if cat.Task != inputs[i].Task {
|
|
t.Errorf("Cat %d: CurrentTask = %d, want %d", i, cat.Task, inputs[i].Task)
|
|
}
|
|
if cat.Experience != inputs[i].Experience {
|
|
t.Errorf("Cat %d: Experience = %d, want %d", i, cat.Experience, inputs[i].Experience)
|
|
}
|
|
if cat.WeaponID != inputs[i].WeaponID {
|
|
t.Errorf("Cat %d: WeaponID = %d, want %d", i, cat.WeaponID, inputs[i].WeaponID)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetAirouDetails_ExtraTrailingBytes(t *testing.T) {
|
|
// The GetAirouDetails function handles extra bytes by seeking to catStart+catDefLen.
|
|
// Simulate a cat definition with extra trailing bytes by increasing catDefLen.
|
|
buf := new(bytes.Buffer)
|
|
buf.WriteByte(1) // catCount = 1
|
|
|
|
catBuf := new(bytes.Buffer)
|
|
_ = binary.Write(catBuf, binary.BigEndian, uint32(99)) // catID
|
|
catBuf.WriteByte(0) // skip
|
|
catBuf.Write(make([]byte, 18)) // name
|
|
catBuf.WriteByte(3) // currentTask
|
|
catBuf.Write(make([]byte, 16)) // appearance skip
|
|
catBuf.WriteByte(1) // personality
|
|
catBuf.WriteByte(2) // class
|
|
catBuf.Write(make([]byte, 5)) // affection skip
|
|
_ = binary.Write(catBuf, binary.BigEndian, uint32(500)) // experience
|
|
catBuf.WriteByte(0) // weapon equipped bool
|
|
catBuf.WriteByte(6) // weaponType
|
|
_ = binary.Write(catBuf, binary.BigEndian, uint16(50)) // weaponID
|
|
|
|
catData := catBuf.Bytes()
|
|
// Add 10 extra trailing bytes
|
|
extra := make([]byte, 10)
|
|
catDataWithExtra := append(catData, extra...)
|
|
|
|
_ = binary.Write(buf, binary.BigEndian, uint32(len(catDataWithExtra)))
|
|
buf.Write(catDataWithExtra)
|
|
|
|
bf := byteframe.NewByteFrameFromBytes(buf.Bytes())
|
|
cats := GetAirouDetails(bf)
|
|
|
|
if len(cats) != 1 {
|
|
t.Fatalf("Expected 1 cat, got %d", len(cats))
|
|
}
|
|
if cats[0].ID != 99 {
|
|
t.Errorf("ID = %d, want 99", cats[0].ID)
|
|
}
|
|
if cats[0].Experience != 500 {
|
|
t.Errorf("Experience = %d, want 500", cats[0].Experience)
|
|
}
|
|
}
|
|
|
|
func TestGetAirouDetails_CatNamePadding(t *testing.T) {
|
|
// Verify that names shorter than 18 bytes are correctly padded with null bytes.
|
|
input := Airou{
|
|
ID: 1,
|
|
Name: []byte("Hi"),
|
|
}
|
|
|
|
data := buildCatBytes([]Airou{input})
|
|
bf := byteframe.NewByteFrameFromBytes(data)
|
|
cats := GetAirouDetails(bf)
|
|
|
|
if len(cats) != 1 {
|
|
t.Fatalf("Expected 1 cat, got %d", len(cats))
|
|
}
|
|
if len(cats[0].Name) != 18 {
|
|
t.Errorf("Name length = %d, want 18", len(cats[0].Name))
|
|
}
|
|
// "Hi" followed by null bytes
|
|
if cats[0].Name[0] != 'H' || cats[0].Name[1] != 'i' {
|
|
t.Errorf("Name first bytes = %v, want 'Hi...'", cats[0].Name[:2])
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgMhfMercenaryHuntdata_RequestTypeIs1(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfMercenaryHuntdata{
|
|
AckHandle: 12345,
|
|
RequestType: 1,
|
|
}
|
|
|
|
handleMsgMhfMercenaryHuntdata(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Error("Response packet should have data")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgMhfMercenaryHuntdata_RequestTypeIs0(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfMercenaryHuntdata{
|
|
AckHandle: 12345,
|
|
RequestType: 0,
|
|
}
|
|
|
|
handleMsgMhfMercenaryHuntdata(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Error("Response packet should have data")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgMhfMercenaryHuntdata_RequestTypeIs2(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfMercenaryHuntdata{
|
|
AckHandle: 12345,
|
|
RequestType: 2,
|
|
}
|
|
|
|
handleMsgMhfMercenaryHuntdata(session, pkt)
|
|
|
|
// RequestType=2 takes the else branch (same as 0)
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Error("Response packet should have data")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgMhfLoadLegendDispatch_Response(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfLoadLegendDispatch{
|
|
AckHandle: 22222,
|
|
}
|
|
|
|
handleMsgMhfLoadLegendDispatch(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Error("Response packet should have data")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestAirouStruct(t *testing.T) {
|
|
cat := Airou{
|
|
ID: 42,
|
|
Name: []byte("TestCat"),
|
|
Task: 4,
|
|
Personality: 2,
|
|
Class: 1,
|
|
Experience: 1500,
|
|
WeaponType: 6,
|
|
WeaponID: 100,
|
|
}
|
|
|
|
if cat.ID != 42 {
|
|
t.Errorf("ID = %d, want 42", cat.ID)
|
|
}
|
|
if cat.Task != 4 {
|
|
t.Errorf("Task = %d, want 4", cat.Task)
|
|
}
|
|
if cat.Experience != 1500 {
|
|
t.Errorf("Experience = %d, want 1500", cat.Experience)
|
|
}
|
|
if cat.WeaponType != 6 {
|
|
t.Errorf("WeaponType = %d, want 6", cat.WeaponType)
|
|
}
|
|
if cat.WeaponID != 100 {
|
|
t.Errorf("WeaponID = %d, want 100", cat.WeaponID)
|
|
}
|
|
}
|
|
|
|
// TestHandleMsgMhfMercenaryHuntdata_Unk0_1 tests with Unk0=1 (returns 1 byte)
|
|
func TestHandleMsgMhfMercenaryHuntdata_Unk0_1(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfMercenaryHuntdata{
|
|
AckHandle: 12345,
|
|
RequestType: 1,
|
|
}
|
|
|
|
handleMsgMhfMercenaryHuntdata(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Error("Response packet should have data")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
// TestHandleMsgMhfMercenaryHuntdata_Unk0_0 tests with Unk0=0 (returns 0 bytes payload)
|
|
func TestHandleMsgMhfMercenaryHuntdata_Unk0_0(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfMercenaryHuntdata{
|
|
AckHandle: 12345,
|
|
RequestType: 0,
|
|
}
|
|
|
|
handleMsgMhfMercenaryHuntdata(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Error("Response packet should have data")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
// TestHandleMsgMhfEnumerateMercenaryLog tests the mercenary log enumeration handler
|
|
func TestHandleMsgMhfEnumerateMercenaryLog(t *testing.T) {
|
|
server := createMockServer()
|
|
session := createMockSession(1, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfEnumerateMercenaryLog{
|
|
AckHandle: 12345,
|
|
}
|
|
|
|
handleMsgMhfEnumerateMercenaryLog(session, pkt)
|
|
|
|
select {
|
|
case p := <-session.sendPackets:
|
|
if len(p.data) == 0 {
|
|
t.Error("Response packet should have data")
|
|
}
|
|
default:
|
|
t.Error("No response packet queued")
|
|
}
|
|
}
|
|
|
|
func TestHandleMsgMhfLoadPartner(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfLoadPartner{AckHandle: 1}
|
|
handleMsgMhfLoadPartner(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfSavePartner(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfSavePartner{AckHandle: 1, RawDataPayload: []byte{1, 2, 3, 4}}
|
|
handleMsgMhfSavePartner(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfLoadHunterNavi_G8(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
server.erupeConfig.RealClientMode = cfg.G10
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfLoadHunterNavi{AckHandle: 1}
|
|
handleMsgMhfLoadHunterNavi(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfLoadHunterNavi_G7(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
server.erupeConfig.RealClientMode = cfg.G7
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfLoadHunterNavi{AckHandle: 1}
|
|
handleMsgMhfLoadHunterNavi(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfSaveHunterNavi_NoDiff(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
data := make([]byte, 100)
|
|
pkt := &mhfpacket.MsgMhfSaveHunterNavi{
|
|
AckHandle: 1,
|
|
IsDataDiff: false,
|
|
RawDataPayload: data,
|
|
}
|
|
handleMsgMhfSaveHunterNavi(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfSaveHunterNavi_Diff(t *testing.T) {
|
|
server := createMockServer()
|
|
charRepo := newMockCharacterRepo()
|
|
charRepo.columns["hunternavi"] = make([]byte, 552)
|
|
server.charRepo = charRepo
|
|
server.erupeConfig.RealClientMode = cfg.G10
|
|
session := createMockSession(100, server)
|
|
|
|
// Create a valid diff payload (deltacomp format: pairs of offset+data)
|
|
// A simple diff: zero length means no changes
|
|
diffData := make([]byte, 4) // minimal diff
|
|
pkt := &mhfpacket.MsgMhfSaveHunterNavi{
|
|
AckHandle: 1,
|
|
IsDataDiff: true,
|
|
RawDataPayload: diffData,
|
|
}
|
|
handleMsgMhfSaveHunterNavi(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfSaveHunterNavi_OversizedPayload(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
data := make([]byte, 5000) // > 4096
|
|
pkt := &mhfpacket.MsgMhfSaveHunterNavi{
|
|
AckHandle: 1,
|
|
IsDataDiff: false,
|
|
RawDataPayload: data,
|
|
}
|
|
handleMsgMhfSaveHunterNavi(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfCreateMercenary_Success(t *testing.T) {
|
|
server := createMockServer()
|
|
server.mercenaryRepo = &mockMercenaryRepo{nextRastaID: 42}
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfCreateMercenary{AckHandle: 1}
|
|
handleMsgMhfCreateMercenary(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfCreateMercenary_Error(t *testing.T) {
|
|
server := createMockServer()
|
|
server.mercenaryRepo = &mockMercenaryRepo{rastaIDErr: errNotFound}
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfCreateMercenary{AckHandle: 1}
|
|
handleMsgMhfCreateMercenary(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfSaveMercenary_Normal(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
mercData := make([]byte, 100)
|
|
// Write a uint32 index at the start
|
|
mercData[0] = 0
|
|
mercData[1] = 0
|
|
mercData[2] = 0
|
|
mercData[3] = 1
|
|
pkt := &mhfpacket.MsgMhfSaveMercenary{
|
|
AckHandle: 1,
|
|
GCP: 500,
|
|
PactMercID: 10,
|
|
MercData: mercData,
|
|
}
|
|
handleMsgMhfSaveMercenary(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfSaveMercenary_Oversized(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfSaveMercenary{
|
|
AckHandle: 1,
|
|
MercData: make([]byte, 70000),
|
|
}
|
|
handleMsgMhfSaveMercenary(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfReadMercenaryM_EmptyData(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfReadMercenaryM{AckHandle: 1, CharID: 200}
|
|
handleMsgMhfReadMercenaryM(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfReadMercenaryM_WithData(t *testing.T) {
|
|
server := createMockServer()
|
|
charRepo := newMockCharacterRepo()
|
|
charRepo.columns["savemercenary"] = []byte{0x01, 0x02, 0x03, 0x04}
|
|
server.charRepo = charRepo
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfReadMercenaryM{AckHandle: 1, CharID: 100}
|
|
handleMsgMhfReadMercenaryM(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfContractMercenary_Op0(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfContractMercenary{AckHandle: 1, Op: 0, CID: 200, PactMercID: 42}
|
|
handleMsgMhfContractMercenary(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfContractMercenary_Op1(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfContractMercenary{AckHandle: 1, Op: 1}
|
|
handleMsgMhfContractMercenary(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfContractMercenary_Op2(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfContractMercenary{AckHandle: 1, Op: 2, CID: 200}
|
|
handleMsgMhfContractMercenary(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfReadMercenaryW_NoPact(t *testing.T) {
|
|
server := createMockServer()
|
|
charRepo := newMockCharacterRepo()
|
|
server.charRepo = charRepo
|
|
server.mercenaryRepo = &mockMercenaryRepo{}
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfReadMercenaryW{AckHandle: 1, Op: 0}
|
|
handleMsgMhfReadMercenaryW(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfReadMercenaryW_WithPact(t *testing.T) {
|
|
server := createMockServer()
|
|
charRepo := newMockCharacterRepo()
|
|
charRepo.ints["pact_id"] = 42
|
|
server.charRepo = charRepo
|
|
server.mercenaryRepo = &mockMercenaryRepo{}
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfReadMercenaryW{AckHandle: 1, Op: 0}
|
|
handleMsgMhfReadMercenaryW(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfReadMercenaryW_Op2(t *testing.T) {
|
|
server := createMockServer()
|
|
charRepo := newMockCharacterRepo()
|
|
server.charRepo = charRepo
|
|
server.mercenaryRepo = &mockMercenaryRepo{}
|
|
session := createMockSession(100, server)
|
|
|
|
// Op 2 skips loan enumeration
|
|
pkt := &mhfpacket.MsgMhfReadMercenaryW{AckHandle: 1, Op: 2}
|
|
handleMsgMhfReadMercenaryW(session, pkt)
|
|
<-session.sendPackets
|
|
}
|
|
|
|
func TestHandleMsgMhfLoadOtomoAirou(t *testing.T) {
|
|
server := createMockServer()
|
|
server.charRepo = newMockCharacterRepo()
|
|
session := createMockSession(100, server)
|
|
|
|
pkt := &mhfpacket.MsgMhfLoadOtomoAirou{AckHandle: 1}
|
|
handleMsgMhfLoadOtomoAirou(session, pkt)
|
|
<-session.sendPackets
|
|
}
|