package mhfpacket import ( "io" "testing" "erupe-ce/common/byteframe" cfg "erupe-ce/config" "erupe-ce/network" "erupe-ce/network/clientctx" ) func TestAcquirePacketOpcodes(t *testing.T) { tests := []struct { name string pkt MHFPacket expect network.PacketID }{ {"MsgMhfAcquireGuildTresure", &MsgMhfAcquireGuildTresure{}, network.MSG_MHF_ACQUIRE_GUILD_TRESURE}, {"MsgMhfAcquireTitle", &MsgMhfAcquireTitle{}, network.MSG_MHF_ACQUIRE_TITLE}, {"MsgMhfAcquireDistItem", &MsgMhfAcquireDistItem{}, network.MSG_MHF_ACQUIRE_DIST_ITEM}, {"MsgMhfAcquireMonthlyItem", &MsgMhfAcquireMonthlyItem{}, network.MSG_MHF_ACQUIRE_MONTHLY_ITEM}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.pkt.Opcode(); got != tt.expect { t.Errorf("Opcode() = %v, want %v", got, tt.expect) } }) } } func TestMsgMhfAcquireGuildTresureParse(t *testing.T) { tests := []struct { name string ackHandle uint32 huntID uint32 unk bool }{ {"basic acquisition", 1, 12345, false}, {"large hunt ID", 0xABCDEF12, 0xFFFFFFFF, true}, {"zero values", 0, 0, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ackHandle) bf.WriteUint32(tt.huntID) bf.WriteBool(tt.unk) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfAcquireGuildTresure{} err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}) if err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ackHandle { t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle) } if pkt.HuntID != tt.huntID { t.Errorf("HuntID = %d, want %d", pkt.HuntID, tt.huntID) } if pkt.Unk != tt.unk { t.Errorf("Unk = %v, want %v", pkt.Unk, tt.unk) } }) } } func TestMsgMhfAcquireTitleParse(t *testing.T) { tests := []struct { name string ackHandle uint32 titleIDs []uint16 }{ {"acquire title 1", 1, []uint16{1}}, {"acquire titles 100 200", 0x12345678, []uint16{100, 200}}, {"no titles", 0xFFFFFFFF, []uint16{}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ackHandle) bf.WriteUint16(uint16(len(tt.titleIDs))) // count bf.WriteUint16(0) // zeroed for _, id := range tt.titleIDs { bf.WriteUint16(id) } _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfAcquireTitle{} err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}) if err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ackHandle { t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle) } if len(pkt.TitleIDs) != len(tt.titleIDs) { t.Errorf("TitleIDs len = %d, want %d", len(pkt.TitleIDs), len(tt.titleIDs)) } for i, id := range tt.titleIDs { if i < len(pkt.TitleIDs) && pkt.TitleIDs[i] != id { t.Errorf("TitleIDs[%d] = %d, want %d", i, pkt.TitleIDs[i], id) } } }) } } func TestMsgMhfAcquireDistItemParse(t *testing.T) { tests := []struct { name string ackHandle uint32 distributionType uint8 distributionID uint32 }{ {"type 0", 1, 0, 12345}, {"type 1", 0xABCD, 1, 67890}, {"max values", 0xFFFFFFFF, 0xFF, 0xFFFFFFFF}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ackHandle) bf.WriteUint8(tt.distributionType) bf.WriteUint32(tt.distributionID) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfAcquireDistItem{} err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}) if err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ackHandle { t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle) } if pkt.DistributionType != tt.distributionType { t.Errorf("DistributionType = %d, want %d", pkt.DistributionType, tt.distributionType) } if pkt.DistributionID != tt.distributionID { t.Errorf("DistributionID = %d, want %d", pkt.DistributionID, tt.distributionID) } }) } } func TestMsgMhfAcquireMonthlyItemParse(t *testing.T) { tests := []struct { name string ackHandle uint32 unk0 uint8 unk1 uint8 unk2 uint16 unk3 uint32 }{ {"basic", 1, 0, 0, 0, 0}, {"with values", 100, 10, 20, 30, 40}, {"max values", 0xFFFFFFFF, 0xFF, 0xFF, 0xFFFF, 0xFFFFFFFF}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ackHandle) bf.WriteUint8(tt.unk0) bf.WriteUint8(tt.unk1) bf.WriteUint16(tt.unk2) bf.WriteUint32(tt.unk3) bf.WriteUint32(0) // Zeroed (consumed by Parse) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfAcquireMonthlyItem{} err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}) if err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ackHandle { t.Errorf("AckHandle = %d, want %d", pkt.AckHandle, tt.ackHandle) } if pkt.Unk0 != tt.unk0 { t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.unk0) } if pkt.Unk1 != tt.unk1 { t.Errorf("Unk1 = %d, want %d", pkt.Unk1, tt.unk1) } if pkt.Unk2 != tt.unk2 { t.Errorf("Unk2 = %d, want %d", pkt.Unk2, tt.unk2) } if pkt.Unk3 != tt.unk3 { t.Errorf("Unk3 = %d, want %d", pkt.Unk3, tt.unk3) } }) } } func TestAcquirePacketsFromOpcode(t *testing.T) { acquireOpcodes := []network.PacketID{ network.MSG_MHF_ACQUIRE_GUILD_TRESURE, network.MSG_MHF_ACQUIRE_TITLE, network.MSG_MHF_ACQUIRE_DIST_ITEM, network.MSG_MHF_ACQUIRE_MONTHLY_ITEM, } for _, opcode := range acquireOpcodes { t.Run(opcode.String(), func(t *testing.T) { pkt := FromOpcode(opcode) if pkt == nil { t.Fatalf("FromOpcode(%s) returned nil", opcode) } if pkt.Opcode() != opcode { t.Errorf("Opcode() = %s, want %s", pkt.Opcode(), opcode) } }) } } func TestAcquirePacketEdgeCases(t *testing.T) { t.Run("guild tresure with max hunt ID", func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(1) bf.WriteUint32(0xFFFFFFFF) bf.WriteBool(true) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfAcquireGuildTresure{} err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}) if err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.HuntID != 0xFFFFFFFF { t.Errorf("HuntID = %d, want %d", pkt.HuntID, 0xFFFFFFFF) } }) t.Run("dist item with all types", func(t *testing.T) { for i := uint8(0); i < 5; i++ { bf := byteframe.NewByteFrame() bf.WriteUint32(1) bf.WriteUint8(i) bf.WriteUint32(12345) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfAcquireDistItem{} err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}) if err != nil { t.Fatalf("Parse() error = %v for type %d", err, i) } if pkt.DistributionType != i { t.Errorf("DistributionType = %d, want %d", pkt.DistributionType, i) } } }) }