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") } }