Files
Erupe/server/channelserver/handlers_shop_test.go
Houmgaor 4a1e019457 fix(shop): update early return test to use pre-G1 client version
PR #150 moved the early return threshold from G10 to G1, so the test
using G7 no longer hit the early return path and panicked on nil
gachaRepo.
2026-02-26 21:57:40 +01:00

477 lines
11 KiB
Go

package channelserver
import (
"errors"
"testing"
"erupe-ce/common/byteframe"
cfg "erupe-ce/config"
"erupe-ce/network/mhfpacket"
)
func TestHandleMsgMhfEnumerateShop_Case1_PreG1EarlyReturn(t *testing.T) {
server := createMockServer()
server.erupeConfig.RealClientMode = cfg.F5
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateShop{
AckHandle: 100,
ShopType: 1,
ShopID: 0,
}
handleMsgMhfEnumerateShop(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("Empty response")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateShop_Case1_GachaList(t *testing.T) {
server := createMockServer()
server.erupeConfig.RealClientMode = cfg.ZZ
gachaRepo := &mockGachaRepo{
gachas: []Gacha{
{ID: 1, Name: "TestGacha", MinGR: 0, MinHR: 0, GachaType: 1},
},
}
server.gachaRepo = gachaRepo
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateShop{
AckHandle: 100,
ShopType: 1,
ShopID: 0,
}
handleMsgMhfEnumerateShop(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("Empty response")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateShop_Case1_ListShopError(t *testing.T) {
server := createMockServer()
server.erupeConfig.RealClientMode = cfg.ZZ
gachaRepo := &mockGachaRepo{
listShopErr: errors.New("db error"),
}
server.gachaRepo = gachaRepo
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateShop{
AckHandle: 100,
ShopType: 1,
ShopID: 0,
}
handleMsgMhfEnumerateShop(session, pkt)
select {
case <-session.sendPackets:
// returns empty on error
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateShop_Case2_GachaDetail(t *testing.T) {
server := createMockServer()
server.erupeConfig.RealClientMode = cfg.ZZ
gachaRepo := &mockGachaRepo{
shopType: 1, // non-box
allEntries: []GachaEntry{
{ID: 10, EntryType: 1, ItemType: 1, ItemNumber: 100, ItemQuantity: 5,
Weight: 50, Rarity: 2, Rolls: 1, FrontierPoints: 10, DailyLimit: 3, Name: "Item1"},
},
entryItems: map[uint32][]GachaItem{
10: {{ItemType: 1, ItemID: 500, Quantity: 1}},
},
weightDivisor: 1.0,
}
server.gachaRepo = gachaRepo
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateShop{
AckHandle: 100,
ShopType: 2,
ShopID: 1,
}
handleMsgMhfEnumerateShop(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("Empty response")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateShop_Case2_AllEntriesError(t *testing.T) {
server := createMockServer()
server.erupeConfig.RealClientMode = cfg.ZZ
gachaRepo := &mockGachaRepo{
allEntriesErr: errors.New("db error"),
}
server.gachaRepo = gachaRepo
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateShop{
AckHandle: 100,
ShopType: 2,
ShopID: 1,
}
handleMsgMhfEnumerateShop(session, pkt)
select {
case <-session.sendPackets:
// returns empty on error
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateShop_Case10_ShopItems(t *testing.T) {
server := createMockServer()
server.erupeConfig.RealClientMode = cfg.ZZ
shopRepo := &mockShopRepo{
shopItems: []ShopItem{
{ID: 1, ItemID: 100, Cost: 500, Quantity: 10, MinHR: 1},
{ID: 2, ItemID: 200, Cost: 1000, Quantity: 5, MinHR: 3},
{ID: 3, ItemID: 300, Cost: 2000, Quantity: 1, MinHR: 5},
},
}
server.shopRepo = shopRepo
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateShop{
AckHandle: 100,
ShopType: 10,
ShopID: 0,
Limit: 2, // Limit to 2 items
}
handleMsgMhfEnumerateShop(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("Empty response")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfEnumerateShop_Cases3to9(t *testing.T) {
for _, shopType := range []uint8{3, 4, 5, 6, 7, 8, 9} {
server := createMockServer()
server.erupeConfig.RealClientMode = cfg.ZZ
shopRepo := &mockShopRepo{
shopItems: []ShopItem{
{ID: 1, ItemID: 100, Cost: 500, Quantity: 10},
},
}
server.shopRepo = shopRepo
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfEnumerateShop{
AckHandle: 100,
ShopType: shopType,
ShopID: 0,
Limit: 100,
}
handleMsgMhfEnumerateShop(session, pkt)
select {
case <-session.sendPackets:
// success
default:
t.Errorf("No response for shop type %d", shopType)
}
}
}
func TestHandleMsgMhfAcquireExchangeShop_RecordsPurchases(t *testing.T) {
server := createMockServer()
shopRepo := &mockShopRepo{}
server.shopRepo = shopRepo
session := createMockSession(1, server)
// Build payload: 2 exchanges, one with non-zero hash, one with zero hash
payload := byteframe.NewByteFrame()
payload.WriteUint16(2) // count
payload.WriteUint32(12345) // itemHash 1
payload.WriteUint32(3) // buyCount 1
payload.WriteUint32(0) // itemHash 2 (zero, should be skipped)
payload.WriteUint32(1) // buyCount 2
pkt := &mhfpacket.MsgMhfAcquireExchangeShop{
AckHandle: 100,
RawDataPayload: payload.Data(),
}
handleMsgMhfAcquireExchangeShop(session, pkt)
if len(shopRepo.purchases) != 1 {
t.Errorf("Expected 1 purchase recorded (skipping zero hash), got %d", len(shopRepo.purchases))
}
if len(shopRepo.purchases) > 0 && shopRepo.purchases[0].itemHash != 12345 {
t.Errorf("Expected itemHash=12345, got %d", shopRepo.purchases[0].itemHash)
}
select {
case <-session.sendPackets:
// success
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfExchangeFpoint2Item_Success(t *testing.T) {
server := createMockServer()
shopRepo := &mockShopRepo{
fpointQuantity: 1,
fpointValue: 100,
}
server.shopRepo = shopRepo
userRepo := &mockUserRepoGacha{fpDeductBalance: 900}
server.userRepo = userRepo
session := createMockSession(1, server)
session.userID = 1
pkt := &mhfpacket.MsgMhfExchangeFpoint2Item{
AckHandle: 100,
TradeID: 1,
Quantity: 1,
}
handleMsgMhfExchangeFpoint2Item(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("Empty response")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfExchangeFpoint2Item_GetFpointItemError(t *testing.T) {
server := createMockServer()
shopRepo := &mockShopRepo{
fpointItemErr: errors.New("not found"),
}
server.shopRepo = shopRepo
server.userRepo = &mockUserRepoGacha{}
session := createMockSession(1, server)
session.userID = 1
pkt := &mhfpacket.MsgMhfExchangeFpoint2Item{
AckHandle: 100,
TradeID: 999,
Quantity: 1,
}
handleMsgMhfExchangeFpoint2Item(session, pkt)
select {
case <-session.sendPackets:
// returns fail
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfExchangeFpoint2Item_DeductError(t *testing.T) {
server := createMockServer()
shopRepo := &mockShopRepo{
fpointQuantity: 1,
fpointValue: 100,
}
server.shopRepo = shopRepo
userRepo := &mockUserRepoGacha{fpDeductErr: errors.New("insufficient")}
server.userRepo = userRepo
session := createMockSession(1, server)
session.userID = 1
pkt := &mhfpacket.MsgMhfExchangeFpoint2Item{
AckHandle: 100,
TradeID: 1,
Quantity: 1,
}
handleMsgMhfExchangeFpoint2Item(session, pkt)
select {
case <-session.sendPackets:
// returns fail
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfExchangeItem2Fpoint_Success(t *testing.T) {
server := createMockServer()
shopRepo := &mockShopRepo{
fpointQuantity: 1,
fpointValue: 50,
}
server.shopRepo = shopRepo
userRepo := &mockUserRepoGacha{fpCreditBalance: 1050}
server.userRepo = userRepo
session := createMockSession(1, server)
session.userID = 1
pkt := &mhfpacket.MsgMhfExchangeItem2Fpoint{
AckHandle: 100,
TradeID: 1,
Quantity: 1,
}
handleMsgMhfExchangeItem2Fpoint(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("Empty response")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfExchangeItem2Fpoint_GetFpointItemError(t *testing.T) {
server := createMockServer()
shopRepo := &mockShopRepo{
fpointItemErr: errors.New("not found"),
}
server.shopRepo = shopRepo
server.userRepo = &mockUserRepoGacha{}
session := createMockSession(1, server)
session.userID = 1
pkt := &mhfpacket.MsgMhfExchangeItem2Fpoint{
AckHandle: 100,
TradeID: 999,
Quantity: 1,
}
handleMsgMhfExchangeItem2Fpoint(session, pkt)
select {
case <-session.sendPackets:
// returns fail
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfExchangeItem2Fpoint_CreditError(t *testing.T) {
server := createMockServer()
shopRepo := &mockShopRepo{
fpointQuantity: 1,
fpointValue: 50,
}
server.shopRepo = shopRepo
userRepo := &mockUserRepoGacha{fpCreditErr: errors.New("credit error")}
server.userRepo = userRepo
session := createMockSession(1, server)
session.userID = 1
pkt := &mhfpacket.MsgMhfExchangeItem2Fpoint{
AckHandle: 100,
TradeID: 1,
Quantity: 1,
}
handleMsgMhfExchangeItem2Fpoint(session, pkt)
select {
case <-session.sendPackets:
// returns fail
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfGetFpointExchangeList_Z2Mode(t *testing.T) {
server := createMockServer()
server.erupeConfig.RealClientMode = cfg.Z2
shopRepo := &mockShopRepo{
fpointExchanges: []FPointExchange{
{ID: 1, ItemType: 1, ItemID: 100, Quantity: 5, FPoints: 10, Buyable: true},
{ID: 2, ItemType: 2, ItemID: 200, Quantity: 1, FPoints: 50, Buyable: false},
},
}
server.shopRepo = shopRepo
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetFpointExchangeList{AckHandle: 100}
handleMsgMhfGetFpointExchangeList(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("Empty response")
}
default:
t.Error("No response packet queued")
}
}
func TestHandleMsgMhfGetFpointExchangeList_ZZMode(t *testing.T) {
server := createMockServer()
server.erupeConfig.RealClientMode = cfg.ZZ
shopRepo := &mockShopRepo{
fpointExchanges: []FPointExchange{
{ID: 1, ItemType: 1, ItemID: 100, Quantity: 5, FPoints: 10, Buyable: true},
},
}
server.shopRepo = shopRepo
session := createMockSession(1, server)
pkt := &mhfpacket.MsgMhfGetFpointExchangeList{AckHandle: 100}
handleMsgMhfGetFpointExchangeList(session, pkt)
select {
case p := <-session.sendPackets:
if len(p.data) == 0 {
t.Fatal("Empty response")
}
default:
t.Error("No response packet queued")
}
}