mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-21 23:22:34 +01:00
feat(go): upgrade from go 1.21 to 1.23
BREAKING CHANGE: will not work properly with Go 1.21.
This commit is contained in:
6
.github/workflows/go-improved.yml
vendored
6
.github/workflows/go-improved.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.23'
|
||||
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.23'
|
||||
|
||||
- name: Download dependencies
|
||||
run: go mod download
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.23'
|
||||
|
||||
- name: Run golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
|
||||
2
.github/workflows/go.yml
vendored
2
.github/workflows/go.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.23'
|
||||
|
||||
- name: Build Linux-amd64
|
||||
run: env GOOS=linux GOARCH=amd64 go build -v
|
||||
|
||||
@@ -25,6 +25,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Bumped golang.org/x/net from 0.33.0 to 0.38.0
|
||||
- Bumped golang.org/x/crypto from 0.31.0 to 0.35.0
|
||||
|
||||
## Removed
|
||||
|
||||
- Compatibility with Go 1.21 removed.
|
||||
|
||||
## [9.2.0] - 2023-04-01
|
||||
|
||||
### Added in 9.2.0
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/server/channelserver/compression/nullcomp"
|
||||
@@ -68,7 +68,7 @@ var tests = []struct {
|
||||
}
|
||||
|
||||
func readTestDataFile(filename string) []byte {
|
||||
data, err := ioutil.ReadFile(fmt.Sprintf("./test_data/%s", filename))
|
||||
data, err := os.ReadFile(fmt.Sprintf("./test_data/%s", filename))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"erupe-ce/network/binpacket"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
"fmt"
|
||||
"golang.org/x/exp/slices"
|
||||
"math"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
713
server/channelserver/handlers_cast_binary_test.go
Normal file
713
server/channelserver/handlers_cast_binary_test.go
Normal file
@@ -0,0 +1,713 @@
|
||||
package channelserver
|
||||
|
||||
import (
|
||||
"net"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/common/mhfcourse"
|
||||
_config "erupe-ce/config"
|
||||
"erupe-ce/network/binpacket"
|
||||
"erupe-ce/network/mhfpacket"
|
||||
)
|
||||
|
||||
// TestSendServerChatMessage verifies that server chat messages are correctly formatted and queued
|
||||
func TestSendServerChatMessage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
message string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "simple_message",
|
||||
message: "Hello, World!",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty_message",
|
||||
message: "",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "special_characters",
|
||||
message: "Test @#$%^&*()",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "unicode_message",
|
||||
message: "テスト メッセージ",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "long_message",
|
||||
message: strings.Repeat("A", 1000),
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
|
||||
// Send the chat message
|
||||
sendServerChatMessage(s, tt.message)
|
||||
|
||||
// Verify the message was queued
|
||||
if len(s.sendPackets) == 0 {
|
||||
t.Error("no packets were queued")
|
||||
return
|
||||
}
|
||||
|
||||
// Read from the channel with timeout to avoid hanging
|
||||
select {
|
||||
case pkt := <-s.sendPackets:
|
||||
if pkt.data == nil {
|
||||
t.Error("packet data is nil")
|
||||
}
|
||||
// Verify it's an MHFPacket (contains opcode)
|
||||
if len(pkt.data) < 2 {
|
||||
t.Error("packet too short to contain opcode")
|
||||
}
|
||||
default:
|
||||
t.Error("no packet available in channel")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleMsgSysCastBinary_SimpleData verifies basic data message handling
|
||||
func TestHandleMsgSysCastBinary_SimpleData(t *testing.T) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
s.charID = 54321
|
||||
s.stage = NewStage("test_stage")
|
||||
s.stage.clients[s] = s.charID
|
||||
s.server.sessions = make(map[net.Conn]*Session)
|
||||
|
||||
// Create a data message payload
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0xDEADBEEF)
|
||||
|
||||
pkt := &mhfpacket.MsgSysCastBinary{
|
||||
Unk: 0,
|
||||
BroadcastType: BroadcastTypeStage,
|
||||
MessageType: BinaryMessageTypeData,
|
||||
RawDataPayload: bf.Data(),
|
||||
}
|
||||
|
||||
// Should not panic
|
||||
handleMsgSysCastBinary(s, pkt)
|
||||
}
|
||||
|
||||
// TestHandleMsgSysCastBinary_DiceCommand verifies the @dice command
|
||||
func TestHandleMsgSysCastBinary_DiceCommand(t *testing.T) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
s.charID = 99999
|
||||
s.stage = NewStage("test_stage")
|
||||
s.stage.clients[s] = s.charID
|
||||
s.server.sessions = make(map[net.Conn]*Session)
|
||||
|
||||
// Build a chat message with @dice command
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
msg := &binpacket.MsgBinChat{
|
||||
Unk0: 0,
|
||||
Type: 5,
|
||||
Flags: 0x80,
|
||||
Message: "@dice",
|
||||
SenderName: "TestPlayer",
|
||||
}
|
||||
msg.Build(bf)
|
||||
|
||||
pkt := &mhfpacket.MsgSysCastBinary{
|
||||
Unk: 0,
|
||||
BroadcastType: BroadcastTypeStage,
|
||||
MessageType: BinaryMessageTypeChat,
|
||||
RawDataPayload: bf.Data(),
|
||||
}
|
||||
|
||||
// Should execute dice command and return
|
||||
handleMsgSysCastBinary(s, pkt)
|
||||
|
||||
// Verify a response was queued (dice result)
|
||||
if len(s.sendPackets) == 0 {
|
||||
t.Error("dice command did not queue a response")
|
||||
}
|
||||
}
|
||||
|
||||
// TestBroadcastTypes verifies different broadcast types are handled
|
||||
func TestBroadcastTypes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
broadcastType uint8
|
||||
buildPayload func() []byte
|
||||
}{
|
||||
{
|
||||
name: "broadcast_targeted",
|
||||
broadcastType: BroadcastTypeTargeted,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetBE() // Targeted uses BE
|
||||
msg := &binpacket.MsgBinTargeted{
|
||||
TargetCharIDs: []uint32{1, 2, 3},
|
||||
RawDataPayload: []byte{0xDE, 0xAD, 0xBE, 0xEF},
|
||||
}
|
||||
msg.Build(bf)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "broadcast_stage",
|
||||
broadcastType: BroadcastTypeStage,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0x12345678)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "broadcast_server",
|
||||
broadcastType: BroadcastTypeServer,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0x12345678)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "broadcast_world",
|
||||
broadcastType: BroadcastTypeWorld,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0x12345678)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
s.charID = 22222
|
||||
s.stage = NewStage("test_stage")
|
||||
s.stage.clients[s] = s.charID
|
||||
s.server.sessions = make(map[net.Conn]*Session)
|
||||
|
||||
pkt := &mhfpacket.MsgSysCastBinary{
|
||||
Unk: 0,
|
||||
BroadcastType: tt.broadcastType,
|
||||
MessageType: BinaryMessageTypeState,
|
||||
RawDataPayload: tt.buildPayload(),
|
||||
}
|
||||
|
||||
// Should handle without panic
|
||||
handleMsgSysCastBinary(s, pkt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestBinaryMessageTypes verifies different message types are handled
|
||||
func TestBinaryMessageTypes(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
messageType uint8
|
||||
buildPayload func() []byte
|
||||
}{
|
||||
{
|
||||
name: "msg_type_state",
|
||||
messageType: BinaryMessageTypeState,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0xDEADBEEF)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "msg_type_chat",
|
||||
messageType: BinaryMessageTypeChat,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
msg := &binpacket.MsgBinChat{
|
||||
Unk0: 0,
|
||||
Type: 5,
|
||||
Flags: 0x80,
|
||||
Message: "test",
|
||||
SenderName: "Player",
|
||||
}
|
||||
msg.Build(bf)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "msg_type_quest",
|
||||
messageType: BinaryMessageTypeQuest,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0xDEADBEEF)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "msg_type_data",
|
||||
messageType: BinaryMessageTypeData,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0xDEADBEEF)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "msg_type_mail_notify",
|
||||
messageType: BinaryMessageTypeMailNotify,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0xDEADBEEF)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "msg_type_emote",
|
||||
messageType: BinaryMessageTypeEmote,
|
||||
buildPayload: func() []byte {
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0xDEADBEEF)
|
||||
return bf.Data()
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
s.charID = 33333
|
||||
s.stage = NewStage("test_stage")
|
||||
s.stage.clients[s] = s.charID
|
||||
s.server.sessions = make(map[net.Conn]*Session)
|
||||
|
||||
pkt := &mhfpacket.MsgSysCastBinary{
|
||||
Unk: 0,
|
||||
BroadcastType: BroadcastTypeStage,
|
||||
MessageType: tt.messageType,
|
||||
RawDataPayload: tt.buildPayload(),
|
||||
}
|
||||
|
||||
// Should handle without panic
|
||||
handleMsgSysCastBinary(s, pkt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestSlicesContainsUsage verifies the slices.Contains function works correctly
|
||||
func TestSlicesContainsUsage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
items []_config.Course
|
||||
target _config.Course
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "item_exists",
|
||||
items: []_config.Course{
|
||||
{Name: "Course1", Enabled: true},
|
||||
{Name: "Course2", Enabled: false},
|
||||
},
|
||||
target: _config.Course{Name: "Course1", Enabled: true},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "item_not_found",
|
||||
items: []_config.Course{
|
||||
{Name: "Course1", Enabled: true},
|
||||
{Name: "Course2", Enabled: false},
|
||||
},
|
||||
target: _config.Course{Name: "Course3", Enabled: true},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "empty_slice",
|
||||
items: []_config.Course{},
|
||||
target: _config.Course{Name: "Course1", Enabled: true},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "enabled_mismatch",
|
||||
items: []_config.Course{
|
||||
{Name: "Course1", Enabled: true},
|
||||
},
|
||||
target: _config.Course{Name: "Course1", Enabled: false},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := slices.Contains(tt.items, tt.target)
|
||||
if result != tt.expected {
|
||||
t.Errorf("slices.Contains() = %v, want %v", result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestSlicesIndexFuncUsage verifies the slices.IndexFunc function works correctly
|
||||
func TestSlicesIndexFuncUsage(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
courses []mhfcourse.Course
|
||||
predicate func(mhfcourse.Course) bool
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
name: "empty_slice",
|
||||
courses: []mhfcourse.Course{},
|
||||
predicate: func(c mhfcourse.Course) bool {
|
||||
return true
|
||||
},
|
||||
expected: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := slices.IndexFunc(tt.courses, tt.predicate)
|
||||
if result != tt.expected {
|
||||
t.Errorf("slices.IndexFunc() = %d, want %d", result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestChatMessageParsing verifies chat message extraction from binary payload
|
||||
func TestChatMessageParsing(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
messageContent string
|
||||
authorName string
|
||||
}{
|
||||
{
|
||||
name: "standard_message",
|
||||
messageContent: "Hello World",
|
||||
authorName: "Player123",
|
||||
},
|
||||
{
|
||||
name: "special_chars_message",
|
||||
messageContent: "Test@#$%^&*()",
|
||||
authorName: "SpecialUser",
|
||||
},
|
||||
{
|
||||
name: "empty_message",
|
||||
messageContent: "",
|
||||
authorName: "Silent",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Build a binary chat message
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
msg := &binpacket.MsgBinChat{
|
||||
Unk0: 0,
|
||||
Type: 5,
|
||||
Flags: 0x80,
|
||||
Message: tt.messageContent,
|
||||
SenderName: tt.authorName,
|
||||
}
|
||||
msg.Build(bf)
|
||||
|
||||
// Parse it back
|
||||
parseBf := byteframe.NewByteFrameFromBytes(bf.Data())
|
||||
parseBf.SetLE()
|
||||
parseBf.Seek(8, 0) // Skip initial bytes
|
||||
|
||||
message := string(parseBf.ReadNullTerminatedBytes())
|
||||
author := string(parseBf.ReadNullTerminatedBytes())
|
||||
|
||||
if message != tt.messageContent {
|
||||
t.Errorf("message mismatch: got %q, want %q", message, tt.messageContent)
|
||||
}
|
||||
if author != tt.authorName {
|
||||
t.Errorf("author mismatch: got %q, want %q", author, tt.authorName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestBinaryMessageTypeEnums verifies message type constants
|
||||
func TestBinaryMessageTypeEnums(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
typeVal uint8
|
||||
typeID uint8
|
||||
}{
|
||||
{
|
||||
name: "state_type",
|
||||
typeVal: BinaryMessageTypeState,
|
||||
typeID: 0,
|
||||
},
|
||||
{
|
||||
name: "chat_type",
|
||||
typeVal: BinaryMessageTypeChat,
|
||||
typeID: 1,
|
||||
},
|
||||
{
|
||||
name: "quest_type",
|
||||
typeVal: BinaryMessageTypeQuest,
|
||||
typeID: 2,
|
||||
},
|
||||
{
|
||||
name: "data_type",
|
||||
typeVal: BinaryMessageTypeData,
|
||||
typeID: 3,
|
||||
},
|
||||
{
|
||||
name: "mail_notify_type",
|
||||
typeVal: BinaryMessageTypeMailNotify,
|
||||
typeID: 4,
|
||||
},
|
||||
{
|
||||
name: "emote_type",
|
||||
typeVal: BinaryMessageTypeEmote,
|
||||
typeID: 6,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.typeVal != tt.typeID {
|
||||
t.Errorf("type mismatch: got %d, want %d", tt.typeVal, tt.typeID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestBroadcastTypeEnums verifies broadcast type constants
|
||||
func TestBroadcastTypeEnums(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
typeVal uint8
|
||||
typeID uint8
|
||||
}{
|
||||
{
|
||||
name: "targeted_type",
|
||||
typeVal: BroadcastTypeTargeted,
|
||||
typeID: 0x01,
|
||||
},
|
||||
{
|
||||
name: "stage_type",
|
||||
typeVal: BroadcastTypeStage,
|
||||
typeID: 0x03,
|
||||
},
|
||||
{
|
||||
name: "server_type",
|
||||
typeVal: BroadcastTypeServer,
|
||||
typeID: 0x06,
|
||||
},
|
||||
{
|
||||
name: "world_type",
|
||||
typeVal: BroadcastTypeWorld,
|
||||
typeID: 0x0a,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.typeVal != tt.typeID {
|
||||
t.Errorf("type mismatch: got %d, want %d", tt.typeVal, tt.typeID)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestPayloadHandling verifies raw payload handling in different scenarios
|
||||
func TestPayloadHandling(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
payloadSize int
|
||||
broadcastType uint8
|
||||
messageType uint8
|
||||
}{
|
||||
{
|
||||
name: "empty_payload",
|
||||
payloadSize: 0,
|
||||
broadcastType: BroadcastTypeStage,
|
||||
messageType: BinaryMessageTypeData,
|
||||
},
|
||||
{
|
||||
name: "small_payload",
|
||||
payloadSize: 4,
|
||||
broadcastType: BroadcastTypeStage,
|
||||
messageType: BinaryMessageTypeData,
|
||||
},
|
||||
{
|
||||
name: "large_payload",
|
||||
payloadSize: 10000,
|
||||
broadcastType: BroadcastTypeStage,
|
||||
messageType: BinaryMessageTypeData,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
s.charID = 44444
|
||||
s.stage = NewStage("test_stage")
|
||||
s.stage.clients[s] = s.charID
|
||||
s.server.sessions = make(map[net.Conn]*Session)
|
||||
|
||||
// Create payload of specified size
|
||||
payload := make([]byte, tt.payloadSize)
|
||||
for i := 0; i < len(payload); i++ {
|
||||
payload[i] = byte(i % 256)
|
||||
}
|
||||
|
||||
pkt := &mhfpacket.MsgSysCastBinary{
|
||||
Unk: 0,
|
||||
BroadcastType: tt.broadcastType,
|
||||
MessageType: tt.messageType,
|
||||
RawDataPayload: payload,
|
||||
}
|
||||
|
||||
// Should handle without panic
|
||||
handleMsgSysCastBinary(s, pkt)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestCastedBinaryPacketConstruction verifies correct packet construction
|
||||
func TestCastedBinaryPacketConstruction(t *testing.T) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
s.charID = 77777
|
||||
|
||||
message := "Test message"
|
||||
|
||||
sendServerChatMessage(s, message)
|
||||
|
||||
// Verify a packet was queued
|
||||
if len(s.sendPackets) == 0 {
|
||||
t.Fatal("no packets queued")
|
||||
}
|
||||
|
||||
// Extract packet from channel
|
||||
pkt := <-s.sendPackets
|
||||
|
||||
if pkt.data == nil {
|
||||
t.Error("packet data is nil")
|
||||
}
|
||||
|
||||
// The packet should be at least a valid MHF packet with opcode
|
||||
if len(pkt.data) < 2 {
|
||||
t.Error("packet too short")
|
||||
}
|
||||
}
|
||||
|
||||
// TestNilPayloadHandling verifies safe handling of nil payloads
|
||||
func TestNilPayloadHandling(t *testing.T) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
s.charID = 55555
|
||||
s.stage = NewStage("test_stage")
|
||||
s.stage.clients[s] = s.charID
|
||||
s.server.sessions = make(map[net.Conn]*Session)
|
||||
|
||||
pkt := &mhfpacket.MsgSysCastBinary{
|
||||
Unk: 0,
|
||||
BroadcastType: BroadcastTypeStage,
|
||||
MessageType: BinaryMessageTypeData,
|
||||
RawDataPayload: nil,
|
||||
}
|
||||
|
||||
// Should handle nil payload without panic
|
||||
handleMsgSysCastBinary(s, pkt)
|
||||
}
|
||||
|
||||
// BenchmarkSendServerChatMessage benchmarks the chat message sending
|
||||
func BenchmarkSendServerChatMessage(b *testing.B) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
|
||||
message := "This is a benchmark message"
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
sendServerChatMessage(s, message)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkHandleMsgSysCastBinary benchmarks the packet handling
|
||||
func BenchmarkHandleMsgSysCastBinary(b *testing.B) {
|
||||
mock := &MockCryptConn{sentPackets: make([][]byte, 0)}
|
||||
s := createTestSession(mock)
|
||||
s.charID = 99999
|
||||
s.stage = NewStage("test_stage")
|
||||
s.stage.clients[s] = s.charID
|
||||
s.server.sessions = make(map[net.Conn]*Session)
|
||||
|
||||
// Prepare packet
|
||||
bf := byteframe.NewByteFrame()
|
||||
bf.SetLE()
|
||||
bf.WriteUint32(0x12345678)
|
||||
|
||||
pkt := &mhfpacket.MsgSysCastBinary{
|
||||
Unk: 0,
|
||||
BroadcastType: BroadcastTypeStage,
|
||||
MessageType: BinaryMessageTypeData,
|
||||
RawDataPayload: bf.Data(),
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
handleMsgSysCastBinary(s, pkt)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSlicesContains benchmarks the slices.Contains function
|
||||
func BenchmarkSlicesContains(b *testing.B) {
|
||||
courses := []_config.Course{
|
||||
{Name: "Course1", Enabled: true},
|
||||
{Name: "Course2", Enabled: false},
|
||||
{Name: "Course3", Enabled: true},
|
||||
{Name: "Course4", Enabled: false},
|
||||
{Name: "Course5", Enabled: true},
|
||||
}
|
||||
|
||||
target := _config.Course{Name: "Course3", Enabled: true}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
slices.Contains(courses, target)
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkSlicesIndexFunc benchmarks the slices.IndexFunc function
|
||||
func BenchmarkSlicesIndexFunc(b *testing.B) {
|
||||
// Create mock courses (empty as real data not needed for benchmark)
|
||||
courses := make([]mhfcourse.Course, 100)
|
||||
|
||||
predicate := func(c mhfcourse.Course) bool {
|
||||
return false // Worst case - always iterate to end
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
slices.IndexFunc(courses, predicate)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user