package mhfpacket import ( "bytes" "io" "testing" "erupe-ce/common/byteframe" cfg "erupe-ce/config" "erupe-ce/network/clientctx" ) // --- 5-stmt packets (medium complexity) --- // TestParseMediumVoteFesta verifies Parse for MsgMhfVoteFesta. // Fields: AckHandle(u32), FestaID(u32), GuildID(u32), TrialID(u32) func TestParseMediumVoteFesta(t *testing.T) { tests := []struct { name string ack uint32 festaID uint32 guildID uint32 trialID uint32 }{ {"typical", 0x11223344, 1, 500, 42}, {"zero", 0, 0, 0, 0}, {"max", 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ack) bf.WriteUint32(tt.festaID) bf.WriteUint32(tt.guildID) bf.WriteUint32(tt.trialID) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfVoteFesta{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack) } if pkt.FestaID != tt.festaID { t.Errorf("FestaID = %d, want %d", pkt.FestaID, tt.festaID) } if pkt.GuildID != tt.guildID { t.Errorf("GuildID = %d, want %d", pkt.GuildID, tt.guildID) } if pkt.TrialID != tt.trialID { t.Errorf("TrialID = %d, want %d", pkt.TrialID, tt.trialID) } }) } } // TestParseMediumAcquireSemaphore verifies Parse for MsgSysAcquireSemaphore. // Fields: AckHandle(u32), SemaphoreIDLength(u8), SemaphoreID(string via bfutil.UpToNull) func TestParseMediumAcquireSemaphore(t *testing.T) { tests := []struct { name string ack uint32 semaphoreID string }{ {"typical", 0xAABBCCDD, "quest_semaphore"}, {"short", 1, "s"}, {"empty", 0, ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ack) // SemaphoreIDLength includes the null terminator in the read idBytes := []byte(tt.semaphoreID) idBytes = append(idBytes, 0x00) // null terminator bf.WriteUint8(uint8(len(idBytes))) bf.WriteBytes(idBytes) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgSysAcquireSemaphore{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack) } if pkt.SemaphoreID != tt.semaphoreID { t.Errorf("SemaphoreID = %q, want %q", pkt.SemaphoreID, tt.semaphoreID) } }) } } // TestParseMediumCheckSemaphore verifies Parse for MsgSysCheckSemaphore. // Fields: AckHandle(u32), semaphoreIDLength(u8), SemaphoreID(string via bfutil.UpToNull) func TestParseMediumCheckSemaphore(t *testing.T) { tests := []struct { name string ack uint32 semaphoreID string }{ {"typical", 0x12345678, "global_semaphore"}, {"short id", 42, "x"}, {"empty id", 0, ""}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ack) idBytes := []byte(tt.semaphoreID) idBytes = append(idBytes, 0x00) bf.WriteUint8(uint8(len(idBytes))) bf.WriteBytes(idBytes) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgSysCheckSemaphore{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack) } if pkt.SemaphoreID != tt.semaphoreID { t.Errorf("SemaphoreID = %q, want %q", pkt.SemaphoreID, tt.semaphoreID) } }) } } // TestParseMediumGetUserBinary verifies Parse for MsgSysGetUserBinary. // Fields: AckHandle(u32), CharID(u32), BinaryType(u8) func TestParseMediumGetUserBinary(t *testing.T) { tests := []struct { name string ack uint32 charID uint32 binaryType uint8 }{ {"typical", 0xDEADBEEF, 12345, 1}, {"zero", 0, 0, 0}, {"max", 0xFFFFFFFF, 0xFFFFFFFF, 255}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ack) bf.WriteUint32(tt.charID) bf.WriteUint8(tt.binaryType) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgSysGetUserBinary{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack) } if pkt.CharID != tt.charID { t.Errorf("CharID = %d, want %d", pkt.CharID, tt.charID) } if pkt.BinaryType != tt.binaryType { t.Errorf("BinaryType = %d, want %d", pkt.BinaryType, tt.binaryType) } }) } } // TestParseMediumSetObjectBinary verifies Parse for MsgSysSetObjectBinary. // Fields: ObjID(u32), DataSize(u16), RawDataPayload([]byte of DataSize) func TestParseMediumSetObjectBinary(t *testing.T) { tests := []struct { name string objID uint32 payload []byte }{ {"typical", 42, []byte{0x01, 0x02, 0x03, 0x04}}, {"empty", 0, []byte{}}, {"large", 0xCAFEBABE, []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x11, 0x22, 0x33, 0x44}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.objID) bf.WriteUint16(uint16(len(tt.payload))) bf.WriteBytes(tt.payload) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgSysSetObjectBinary{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.ObjID != tt.objID { t.Errorf("ObjID = %d, want %d", pkt.ObjID, tt.objID) } if pkt.DataSize != uint16(len(tt.payload)) { t.Errorf("DataSize = %d, want %d", pkt.DataSize, len(tt.payload)) } if !bytes.Equal(pkt.RawDataPayload, tt.payload) { t.Errorf("RawDataPayload = %v, want %v", pkt.RawDataPayload, tt.payload) } }) } } // TestParseMediumSetUserBinary verifies Parse for MsgSysSetUserBinary. // Fields: BinaryType(u8), DataSize(u16), RawDataPayload([]byte of DataSize) func TestParseMediumSetUserBinary(t *testing.T) { tests := []struct { name string binaryType uint8 payload []byte }{ {"typical", 1, []byte{0xDE, 0xAD, 0xBE, 0xEF}}, {"empty", 0, []byte{}}, {"max type", 255, []byte{0x01}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint8(tt.binaryType) bf.WriteUint16(uint16(len(tt.payload))) bf.WriteBytes(tt.payload) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgSysSetUserBinary{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.BinaryType != tt.binaryType { t.Errorf("BinaryType = %d, want %d", pkt.BinaryType, tt.binaryType) } if pkt.DataSize != uint16(len(tt.payload)) { t.Errorf("DataSize = %d, want %d", pkt.DataSize, len(tt.payload)) } if !bytes.Equal(pkt.RawDataPayload, tt.payload) { t.Errorf("RawDataPayload = %v, want %v", pkt.RawDataPayload, tt.payload) } }) } } // --- 4-stmt packets --- // TestParseMediumGetUdRanking verifies Parse for MsgMhfGetUdRanking. // Fields: AckHandle(u32), Unk0(u8) func TestParseMediumGetUdRanking(t *testing.T) { tests := []struct { name string ack uint32 unk0 uint8 }{ {"typical", 0x11223344, 5}, {"zero", 0, 0}, {"max", 0xFFFFFFFF, 255}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ack) bf.WriteUint8(tt.unk0) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfGetUdRanking{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack) } if pkt.Unk0 != tt.unk0 { t.Errorf("Unk0 = %d, want %d", pkt.Unk0, tt.unk0) } }) } } // TestParseMediumGetUdTacticsRanking verifies Parse for MsgMhfGetUdTacticsRanking. // Fields: AckHandle(u32), GuildID(u32) func TestParseMediumGetUdTacticsRanking(t *testing.T) { tests := []struct { name string ack uint32 guildID uint32 }{ {"typical", 0xAABBCCDD, 500}, {"zero", 0, 0}, {"max", 0xFFFFFFFF, 0xFFFFFFFF}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ack) bf.WriteUint32(tt.guildID) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfGetUdTacticsRanking{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack) } if pkt.GuildID != tt.guildID { t.Errorf("GuildID = %d, want %d", pkt.GuildID, tt.guildID) } }) } } // TestParseMediumRegistGuildTresure verifies Parse for MsgMhfRegistGuildTresure. // Fields: AckHandle(u32), DataLen(u16), Data([]byte), trailing u32 (discarded) func TestParseMediumRegistGuildTresure(t *testing.T) { tests := []struct { name string ack uint32 data []byte }{ {"typical", 0x12345678, []byte{0x01, 0x02, 0x03}}, {"empty data", 1, []byte{}}, {"larger data", 0xDEADBEEF, []byte{0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(tt.ack) bf.WriteUint16(uint16(len(tt.data))) bf.WriteBytes(tt.data) bf.WriteUint32(0) // trailing uint32 that is read and discarded _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfRegistGuildTresure{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != tt.ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, tt.ack) } if !bytes.Equal(pkt.Data, tt.data) { t.Errorf("Data = %v, want %v", pkt.Data, tt.data) } }) } } // TestParseMediumUpdateMyhouseInfo verifies Parse for MsgMhfUpdateMyhouseInfo. // Fields: AckHandle(u32), Unk0([]byte of 0x16A bytes) func TestParseMediumUpdateMyhouseInfo(t *testing.T) { t.Run("typical", func(t *testing.T) { bf := byteframe.NewByteFrame() ack := uint32(0xCAFEBABE) bf.WriteUint32(ack) // 0x16A = 362 bytes payload := make([]byte, 0x16A) for i := range payload { payload[i] = byte(i % 256) } bf.WriteBytes(payload) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfUpdateMyhouseInfo{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } if len(pkt.Data) != 0x16A { t.Errorf("Unk0 length = %d, want %d", len(pkt.Data), 0x16A) } if !bytes.Equal(pkt.Data, payload) { t.Error("Unk0 content mismatch") } }) t.Run("zero values", func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(0) bf.WriteBytes(make([]byte, 0x16A)) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgMhfUpdateMyhouseInfo{} if err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}); err != nil { t.Fatalf("Parse() error = %v", err) } if pkt.AckHandle != 0 { t.Errorf("AckHandle = 0x%X, want 0", pkt.AckHandle) } if len(pkt.Data) != 0x16A { t.Errorf("Unk0 length = %d, want %d", len(pkt.Data), 0x16A) } }) } // --- 3-stmt packets (AckHandle-only Parse) --- // TestParseMediumAckHandleOnlyBatch tests Parse for all 3-stmt packets that only // read a single AckHandle uint32. These are verified to parse correctly and // return the expected AckHandle value. func TestParseMediumAckHandleOnlyBatch(t *testing.T) { packets := []struct { name string pkt MHFPacket // getAck extracts the AckHandle from the parsed packet getAck func() uint32 }{ { "MsgMhfGetUdBonusQuestInfo", &MsgMhfGetUdBonusQuestInfo{}, nil, }, { "MsgMhfGetUdDailyPresentList", &MsgMhfGetUdDailyPresentList{}, nil, }, { "MsgMhfGetUdGuildMapInfo", &MsgMhfGetUdGuildMapInfo{}, nil, }, { "MsgMhfGetUdMonsterPoint", &MsgMhfGetUdMonsterPoint{}, nil, }, { "MsgMhfGetUdMyRanking", &MsgMhfGetUdMyRanking{}, nil, }, { "MsgMhfGetUdNormaPresentList", &MsgMhfGetUdNormaPresentList{}, nil, }, { "MsgMhfGetUdRankingRewardList", &MsgMhfGetUdRankingRewardList{}, nil, }, { "MsgMhfGetUdSelectedColorInfo", &MsgMhfGetUdSelectedColorInfo{}, nil, }, { "MsgMhfGetUdShopCoin", &MsgMhfGetUdShopCoin{}, nil, }, { "MsgMhfGetUdTacticsBonusQuest", &MsgMhfGetUdTacticsBonusQuest{}, nil, }, { "MsgMhfGetUdTacticsFirstQuestBonus", &MsgMhfGetUdTacticsFirstQuestBonus{}, nil, }, { "MsgMhfGetUdTacticsFollower", &MsgMhfGetUdTacticsFollower{}, nil, }, { "MsgMhfGetUdTacticsLog", &MsgMhfGetUdTacticsLog{}, nil, }, { "MsgMhfGetUdTacticsPoint", &MsgMhfGetUdTacticsPoint{}, nil, }, { "MsgMhfGetUdTacticsRewardList", &MsgMhfGetUdTacticsRewardList{}, nil, }, { "MsgMhfReceiveCafeDurationBonus", &MsgMhfReceiveCafeDurationBonus{}, nil, }, { "MsgSysDeleteSemaphore", &MsgSysDeleteSemaphore{}, nil, }, { "MsgSysReleaseSemaphore", &MsgSysReleaseSemaphore{}, nil, }, } ctx := &clientctx.ClientContext{RealClientMode: cfg.ZZ} ackValues := []uint32{0x12345678, 0, 0xFFFFFFFF, 0xDEADBEEF} for _, tc := range packets { for _, ackVal := range ackValues { t.Run(tc.name+"/ack_"+ackHex(ackVal), func(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(ackVal) _, _ = bf.Seek(0, io.SeekStart) err := tc.pkt.Parse(bf, ctx) if err != nil { t.Fatalf("Parse() error = %v", err) } }) } } } // TestParseMediumAckHandleOnlyVerifyValues tests each 3-stmt AckHandle-only // packet individually, verifying that the AckHandle field is correctly populated. func TestParseMediumAckHandleOnlyVerifyValues(t *testing.T) { ctx := &clientctx.ClientContext{RealClientMode: cfg.ZZ} ack := uint32(0xCAFEBABE) makeFrame := func() *byteframe.ByteFrame { bf := byteframe.NewByteFrame() bf.WriteUint32(ack) _, _ = bf.Seek(0, io.SeekStart) return bf } t.Run("MsgMhfGetUdBonusQuestInfo", func(t *testing.T) { pkt := &MsgMhfGetUdBonusQuestInfo{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdDailyPresentList", func(t *testing.T) { pkt := &MsgMhfGetUdDailyPresentList{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdGuildMapInfo", func(t *testing.T) { pkt := &MsgMhfGetUdGuildMapInfo{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdMonsterPoint", func(t *testing.T) { pkt := &MsgMhfGetUdMonsterPoint{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdMyRanking", func(t *testing.T) { pkt := &MsgMhfGetUdMyRanking{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdNormaPresentList", func(t *testing.T) { pkt := &MsgMhfGetUdNormaPresentList{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdRankingRewardList", func(t *testing.T) { pkt := &MsgMhfGetUdRankingRewardList{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdSelectedColorInfo", func(t *testing.T) { pkt := &MsgMhfGetUdSelectedColorInfo{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdShopCoin", func(t *testing.T) { pkt := &MsgMhfGetUdShopCoin{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdTacticsBonusQuest", func(t *testing.T) { pkt := &MsgMhfGetUdTacticsBonusQuest{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdTacticsFirstQuestBonus", func(t *testing.T) { pkt := &MsgMhfGetUdTacticsFirstQuestBonus{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdTacticsFollower", func(t *testing.T) { pkt := &MsgMhfGetUdTacticsFollower{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdTacticsLog", func(t *testing.T) { pkt := &MsgMhfGetUdTacticsLog{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdTacticsPoint", func(t *testing.T) { pkt := &MsgMhfGetUdTacticsPoint{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfGetUdTacticsRewardList", func(t *testing.T) { pkt := &MsgMhfGetUdTacticsRewardList{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgMhfReceiveCafeDurationBonus", func(t *testing.T) { pkt := &MsgMhfReceiveCafeDurationBonus{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) t.Run("MsgSysDeleteSemaphore", func(t *testing.T) { pkt := &MsgSysDeleteSemaphore{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.SemaphoreID != ack { t.Errorf("SemaphoreID = 0x%X, want 0x%X", pkt.SemaphoreID, ack) } }) t.Run("MsgSysReleaseSemaphore", func(t *testing.T) { pkt := &MsgSysReleaseSemaphore{} if err := pkt.Parse(makeFrame(), ctx); err != nil { t.Fatal(err) } if pkt.AckHandle != ack { t.Errorf("AckHandle = 0x%X, want 0x%X", pkt.AckHandle, ack) } }) } // TestParseMediumDeleteUser verifies that MsgSysDeleteUser.Parse returns // NOT IMPLEMENTED error (Parse is not implemented, only Build is). func TestParseMediumDeleteUser(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(12345) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgSysDeleteUser{} err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}) if err == nil { t.Fatal("Parse() should return error for NOT IMPLEMENTED") } if err.Error() != "NOT IMPLEMENTED" { t.Errorf("Parse() error = %q, want %q", err.Error(), "NOT IMPLEMENTED") } } // TestParseMediumInsertUser verifies that MsgSysInsertUser.Parse returns // NOT IMPLEMENTED error (Parse is not implemented, only Build is). func TestParseMediumInsertUser(t *testing.T) { bf := byteframe.NewByteFrame() bf.WriteUint32(12345) _, _ = bf.Seek(0, io.SeekStart) pkt := &MsgSysInsertUser{} err := pkt.Parse(bf, &clientctx.ClientContext{RealClientMode: cfg.ZZ}) if err == nil { t.Fatal("Parse() should return error for NOT IMPLEMENTED") } if err.Error() != "NOT IMPLEMENTED" { t.Errorf("Parse() error = %q, want %q", err.Error(), "NOT IMPLEMENTED") } } // ackHex returns a hex string for a uint32 ack value, used for test naming. func ackHex(v uint32) string { const hex = "0123456789ABCDEF" buf := make([]byte, 8) for i := 7; i >= 0; i-- { buf[i] = hex[v&0xF] v >>= 4 } return string(buf) }