mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 07:32:32 +01:00
Add comprehensive tests for channelserver package: - handlers_character_test.go: CharacterSaveData, pointer constants - handlers_data_test.go: grpToGR function with boundary tests - handlers_quest_test.go: findSubSliceIndices, equal functions - handlers_simple_test.go: simple handlers, ack responses - handlers_util_test.go: stub handlers, ack helpers - sys_channel_server_test.go: Server, Raviente, stages, semaphores - sys_object_test.go: Object, Stage, stageBinaryKey structs All tests pass with race detection enabled.
285 lines
7.8 KiB
Go
285 lines
7.8 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"testing"
|
|
)
|
|
|
|
func TestCharacterSaveDataStruct(t *testing.T) {
|
|
saveData := &CharacterSaveData{
|
|
CharID: 12345,
|
|
Name: "TestHunter",
|
|
IsNewCharacter: false,
|
|
Gender: true,
|
|
RP: 1000,
|
|
WeaponType: 5,
|
|
WeaponID: 100,
|
|
HRP: 500,
|
|
GR: 50,
|
|
}
|
|
|
|
if saveData.CharID != 12345 {
|
|
t.Errorf("CharID = %d, want 12345", saveData.CharID)
|
|
}
|
|
if saveData.Name != "TestHunter" {
|
|
t.Errorf("Name = %s, want TestHunter", saveData.Name)
|
|
}
|
|
if saveData.Gender != true {
|
|
t.Error("Gender should be true")
|
|
}
|
|
if saveData.RP != 1000 {
|
|
t.Errorf("RP = %d, want 1000", saveData.RP)
|
|
}
|
|
if saveData.WeaponType != 5 {
|
|
t.Errorf("WeaponType = %d, want 5", saveData.WeaponType)
|
|
}
|
|
if saveData.HRP != 500 {
|
|
t.Errorf("HRP = %d, want 500", saveData.HRP)
|
|
}
|
|
if saveData.GR != 50 {
|
|
t.Errorf("GR = %d, want 50", saveData.GR)
|
|
}
|
|
}
|
|
|
|
func TestCharacterSaveData_InitialValues(t *testing.T) {
|
|
saveData := &CharacterSaveData{}
|
|
|
|
if saveData.CharID != 0 {
|
|
t.Errorf("CharID should default to 0, got %d", saveData.CharID)
|
|
}
|
|
if saveData.IsNewCharacter != false {
|
|
t.Error("IsNewCharacter should default to false")
|
|
}
|
|
if saveData.Gender != false {
|
|
t.Error("Gender should default to false")
|
|
}
|
|
}
|
|
|
|
func TestCharacterSaveData_BinarySlices(t *testing.T) {
|
|
saveData := &CharacterSaveData{
|
|
HouseTier: make([]byte, 5),
|
|
HouseData: make([]byte, 195),
|
|
BookshelfData: make([]byte, 5576),
|
|
GalleryData: make([]byte, 1748),
|
|
ToreData: make([]byte, 240),
|
|
GardenData: make([]byte, 68),
|
|
KQF: make([]byte, 8),
|
|
}
|
|
|
|
// Verify slice sizes match expected game data sizes
|
|
if len(saveData.HouseTier) != 5 {
|
|
t.Errorf("HouseTier len = %d, want 5", len(saveData.HouseTier))
|
|
}
|
|
if len(saveData.HouseData) != 195 {
|
|
t.Errorf("HouseData len = %d, want 195", len(saveData.HouseData))
|
|
}
|
|
if len(saveData.BookshelfData) != 5576 {
|
|
t.Errorf("BookshelfData len = %d, want 5576", len(saveData.BookshelfData))
|
|
}
|
|
if len(saveData.GalleryData) != 1748 {
|
|
t.Errorf("GalleryData len = %d, want 1748", len(saveData.GalleryData))
|
|
}
|
|
if len(saveData.ToreData) != 240 {
|
|
t.Errorf("ToreData len = %d, want 240", len(saveData.ToreData))
|
|
}
|
|
if len(saveData.GardenData) != 68 {
|
|
t.Errorf("GardenData len = %d, want 68", len(saveData.GardenData))
|
|
}
|
|
if len(saveData.KQF) != 8 {
|
|
t.Errorf("KQF len = %d, want 8", len(saveData.KQF))
|
|
}
|
|
}
|
|
|
|
func TestPointerConstants(t *testing.T) {
|
|
// Verify the pointer constants are set correctly based on the game's save format
|
|
pointers := map[string]int{
|
|
"pointerGender": 0x81,
|
|
"pointerRP": 0x22D16,
|
|
"pointerHouseTier": 0x1FB6C,
|
|
"pointerHouseData": 0x1FE01,
|
|
"pointerBookshelfData": 0x22298,
|
|
"pointerGalleryData": 0x22320,
|
|
"pointerToreData": 0x1FCB4,
|
|
"pointerGardenData": 0x22C58,
|
|
"pointerWeaponType": 0x1F715,
|
|
"pointerWeaponID": 0x1F60A,
|
|
"pointerHRP": 0x1FDF6,
|
|
"pointerGRP": 0x1FDFC,
|
|
"pointerKQF": 0x23D20,
|
|
}
|
|
|
|
// Verify constants are properly defined (non-zero and in expected ranges)
|
|
if pointerGender != 0x81 {
|
|
t.Errorf("pointerGender = 0x%X, want 0x81", pointerGender)
|
|
}
|
|
if pointerRP != 0x22D16 {
|
|
t.Errorf("pointerRP = 0x%X, want 0x22D16", pointerRP)
|
|
}
|
|
if pointerKQF != 0x23D20 {
|
|
t.Errorf("pointerKQF = 0x%X, want 0x23D20", pointerKQF)
|
|
}
|
|
|
|
// Verify pointers are all unique
|
|
seen := make(map[int]string)
|
|
for name, ptr := range pointers {
|
|
if existingName, ok := seen[ptr]; ok {
|
|
t.Errorf("Duplicate pointer value 0x%X: %s and %s", ptr, name, existingName)
|
|
}
|
|
seen[ptr] = name
|
|
}
|
|
}
|
|
|
|
func TestCharacterSaveData_UpdateSaveDataWithStruct(t *testing.T) {
|
|
// Create a save with enough data to hold all pointers
|
|
// Maximum pointer is pointerKQF at 0x23D20 + 8 = 0x23D28
|
|
saveSize := 0x23D30 // A bit more than needed
|
|
saveData := &CharacterSaveData{
|
|
decompSave: make([]byte, saveSize),
|
|
RP: 1234,
|
|
KQF: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
|
|
}
|
|
|
|
saveData.updateSaveDataWithStruct()
|
|
|
|
// Check RP was written correctly (little endian)
|
|
rpValue := binary.LittleEndian.Uint16(saveData.decompSave[pointerRP : pointerRP+2])
|
|
if rpValue != 1234 {
|
|
t.Errorf("RP in decompSave = %d, want 1234", rpValue)
|
|
}
|
|
|
|
// Check KQF was written correctly
|
|
for i := 0; i < 8; i++ {
|
|
if saveData.decompSave[pointerKQF+i] != byte(i+1) {
|
|
t.Errorf("KQF[%d] = 0x%02X, want 0x%02X", i, saveData.decompSave[pointerKQF+i], i+1)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCharacterSaveData_UpdateStructWithSaveData_Gender(t *testing.T) {
|
|
// Create minimal save data for gender test
|
|
saveSize := 0x23D30
|
|
saveData := &CharacterSaveData{
|
|
decompSave: make([]byte, saveSize),
|
|
IsNewCharacter: true, // New char doesn't read most fields
|
|
}
|
|
|
|
// Set gender to male (0)
|
|
saveData.decompSave[pointerGender] = 0
|
|
saveData.updateStructWithSaveData()
|
|
|
|
if saveData.Gender != false {
|
|
t.Error("Gender should be false (male) when byte is 0")
|
|
}
|
|
|
|
// Set gender to female (1)
|
|
saveData.decompSave[pointerGender] = 1
|
|
saveData.updateStructWithSaveData()
|
|
|
|
if saveData.Gender != true {
|
|
t.Error("Gender should be true (female) when byte is 1")
|
|
}
|
|
}
|
|
|
|
func TestCharacterSaveData_NotNewCharacter(t *testing.T) {
|
|
// Create save data for existing character
|
|
saveSize := 0x23D30
|
|
saveData := &CharacterSaveData{
|
|
decompSave: make([]byte, saveSize),
|
|
IsNewCharacter: false,
|
|
}
|
|
|
|
// Set some values in the save data
|
|
binary.LittleEndian.PutUint16(saveData.decompSave[pointerRP:], 5000)
|
|
binary.LittleEndian.PutUint16(saveData.decompSave[pointerHRP:], 500)
|
|
saveData.decompSave[pointerWeaponType] = 7
|
|
|
|
saveData.updateStructWithSaveData()
|
|
|
|
if saveData.RP != 5000 {
|
|
t.Errorf("RP = %d, want 5000", saveData.RP)
|
|
}
|
|
if saveData.HRP != 500 {
|
|
t.Errorf("HRP = %d, want 500", saveData.HRP)
|
|
}
|
|
if saveData.WeaponType != 7 {
|
|
t.Errorf("WeaponType = %d, want 7", saveData.WeaponType)
|
|
}
|
|
}
|
|
|
|
func TestCharacterSaveData_GR_MaxHRP(t *testing.T) {
|
|
// When HRP is 999, GR is calculated from GRP
|
|
saveSize := 0x23D30
|
|
saveData := &CharacterSaveData{
|
|
decompSave: make([]byte, saveSize),
|
|
IsNewCharacter: false,
|
|
}
|
|
|
|
// Set HRP to 999 (max HR)
|
|
binary.LittleEndian.PutUint16(saveData.decompSave[pointerHRP:], 999)
|
|
// Set GRP to 593400 (GR 100)
|
|
binary.LittleEndian.PutUint32(saveData.decompSave[pointerGRP:], 593400)
|
|
|
|
saveData.updateStructWithSaveData()
|
|
|
|
if saveData.HRP != 999 {
|
|
t.Errorf("HRP = %d, want 999", saveData.HRP)
|
|
}
|
|
// GR should be calculated via grpToGR
|
|
expectedGR := grpToGR(593400)
|
|
if saveData.GR != expectedGR {
|
|
t.Errorf("GR = %d, want %d", saveData.GR, expectedGR)
|
|
}
|
|
}
|
|
|
|
func TestCharacterSaveData_SliceExtraction(t *testing.T) {
|
|
// Test that slices are extracted at correct offsets
|
|
saveSize := 0x23D30
|
|
saveData := &CharacterSaveData{
|
|
decompSave: make([]byte, saveSize),
|
|
IsNewCharacter: false,
|
|
}
|
|
|
|
// Fill specific regions with identifiable patterns
|
|
for i := 0; i < 5; i++ {
|
|
saveData.decompSave[pointerHouseTier+i] = byte(0xAA)
|
|
}
|
|
for i := 0; i < 195; i++ {
|
|
saveData.decompSave[pointerHouseData+i] = byte(0xBB)
|
|
}
|
|
for i := 0; i < 8; i++ {
|
|
saveData.decompSave[pointerKQF+i] = byte(0xCC)
|
|
}
|
|
|
|
saveData.updateStructWithSaveData()
|
|
|
|
// Verify HouseTier extraction
|
|
if len(saveData.HouseTier) != 5 {
|
|
t.Fatalf("HouseTier len = %d, want 5", len(saveData.HouseTier))
|
|
}
|
|
for i, b := range saveData.HouseTier {
|
|
if b != 0xAA {
|
|
t.Errorf("HouseTier[%d] = 0x%02X, want 0xAA", i, b)
|
|
}
|
|
}
|
|
|
|
// Verify HouseData extraction
|
|
if len(saveData.HouseData) != 195 {
|
|
t.Fatalf("HouseData len = %d, want 195", len(saveData.HouseData))
|
|
}
|
|
for i, b := range saveData.HouseData {
|
|
if b != 0xBB {
|
|
t.Errorf("HouseData[%d] = 0x%02X, want 0xBB", i, b)
|
|
}
|
|
}
|
|
|
|
// Verify KQF extraction
|
|
if len(saveData.KQF) != 8 {
|
|
t.Fatalf("KQF len = %d, want 8", len(saveData.KQF))
|
|
}
|
|
for i, b := range saveData.KQF {
|
|
if b != 0xCC {
|
|
t.Errorf("KQF[%d] = 0x%02X, want 0xCC", i, b)
|
|
}
|
|
}
|
|
}
|