mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-21 23:22:34 +01:00
An MMO server without multiplayer defeats the purpose. PostgreSQL is the right choice and Docker Compose already solves the setup pain. This reverts the common/db wrapper, SQLite schema, config Driver field, modernc.org/sqlite dependency, and all repo type changes while keeping the dashboard, wizard, and CI improvements from the previous commit.
378 lines
11 KiB
Go
378 lines
11 KiB
Go
package channelserver
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
)
|
|
|
|
func setupHouseRepo(t *testing.T) (*HouseRepository, *sqlx.DB, uint32) {
|
|
t.Helper()
|
|
db := SetupTestDB(t)
|
|
userID := CreateTestUser(t, db, "house_test_user")
|
|
charID := CreateTestCharacter(t, db, userID, "HouseChar")
|
|
CreateTestUserBinary(t, db, charID)
|
|
repo := NewHouseRepository(db)
|
|
t.Cleanup(func() { TeardownTestDB(t, db) })
|
|
return repo, db, charID
|
|
}
|
|
|
|
func TestRepoHouseGetHouseByCharID(t *testing.T) {
|
|
repo, _, charID := setupHouseRepo(t)
|
|
|
|
house, err := repo.GetHouseByCharID(charID)
|
|
if err != nil {
|
|
t.Fatalf("GetHouseByCharID failed: %v", err)
|
|
}
|
|
if house.CharID != charID {
|
|
t.Errorf("Expected charID=%d, got: %d", charID, house.CharID)
|
|
}
|
|
if house.Name != "HouseChar" {
|
|
t.Errorf("Expected name='HouseChar', got: %q", house.Name)
|
|
}
|
|
// Default house_state is 2 (password-protected) via COALESCE
|
|
if house.HouseState != 2 {
|
|
t.Errorf("Expected default house_state=2, got: %d", house.HouseState)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseSearchHousesByName(t *testing.T) {
|
|
repo, db, _ := setupHouseRepo(t)
|
|
|
|
user2 := CreateTestUser(t, db, "house_user2")
|
|
charID2 := CreateTestCharacter(t, db, user2, "HouseAlpha")
|
|
CreateTestUserBinary(t, db, charID2)
|
|
user3 := CreateTestUser(t, db, "house_user3")
|
|
charID3 := CreateTestCharacter(t, db, user3, "BetaHouse")
|
|
CreateTestUserBinary(t, db, charID3)
|
|
|
|
houses, err := repo.SearchHousesByName("House")
|
|
if err != nil {
|
|
t.Fatalf("SearchHousesByName failed: %v", err)
|
|
}
|
|
if len(houses) < 2 {
|
|
t.Errorf("Expected at least 2 matches for 'House', got: %d", len(houses))
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseSearchHousesByNameNoMatch(t *testing.T) {
|
|
repo, _, _ := setupHouseRepo(t)
|
|
|
|
houses, err := repo.SearchHousesByName("ZZZnonexistent")
|
|
if err != nil {
|
|
t.Fatalf("SearchHousesByName failed: %v", err)
|
|
}
|
|
if len(houses) != 0 {
|
|
t.Errorf("Expected 0 matches, got: %d", len(houses))
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseUpdateHouseState(t *testing.T) {
|
|
repo, _, charID := setupHouseRepo(t)
|
|
|
|
if err := repo.UpdateHouseState(charID, 1, "secret"); err != nil {
|
|
t.Fatalf("UpdateHouseState failed: %v", err)
|
|
}
|
|
|
|
state, password, err := repo.GetHouseAccess(charID)
|
|
if err != nil {
|
|
t.Fatalf("GetHouseAccess failed: %v", err)
|
|
}
|
|
if state != 1 {
|
|
t.Errorf("Expected state=1, got: %d", state)
|
|
}
|
|
if password != "secret" {
|
|
t.Errorf("Expected password='secret', got: %q", password)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseGetHouseAccessDefault(t *testing.T) {
|
|
repo, _, charID := setupHouseRepo(t)
|
|
|
|
state, password, err := repo.GetHouseAccess(charID)
|
|
if err != nil {
|
|
t.Fatalf("GetHouseAccess failed: %v", err)
|
|
}
|
|
if state != 2 {
|
|
t.Errorf("Expected default state=2, got: %d", state)
|
|
}
|
|
if password != "" {
|
|
t.Errorf("Expected empty password, got: %q", password)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseUpdateInterior(t *testing.T) {
|
|
repo, db, charID := setupHouseRepo(t)
|
|
|
|
furniture := []byte{0x01, 0x02, 0x03}
|
|
if err := repo.UpdateInterior(charID, furniture); err != nil {
|
|
t.Fatalf("UpdateInterior failed: %v", err)
|
|
}
|
|
|
|
var got []byte
|
|
if err := db.QueryRow("SELECT house_furniture FROM user_binary WHERE id=$1", charID).Scan(&got); err != nil {
|
|
t.Fatalf("Verification query failed: %v", err)
|
|
}
|
|
if len(got) != 3 || got[0] != 0x01 {
|
|
t.Errorf("Expected furniture data, got: %x", got)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseGetHouseContents(t *testing.T) {
|
|
repo, db, charID := setupHouseRepo(t)
|
|
|
|
tier := []byte{0x01}
|
|
data := []byte{0x02}
|
|
furniture := []byte{0x03}
|
|
bookshelf := []byte{0x04}
|
|
gallery := []byte{0x05}
|
|
tore := []byte{0x06}
|
|
garden := []byte{0x07}
|
|
if _, err := db.Exec(
|
|
"UPDATE user_binary SET house_tier=$1, house_data=$2, house_furniture=$3, bookshelf=$4, gallery=$5, tore=$6, garden=$7 WHERE id=$8",
|
|
tier, data, furniture, bookshelf, gallery, tore, garden, charID,
|
|
); err != nil {
|
|
t.Fatalf("Setup failed: %v", err)
|
|
}
|
|
|
|
gotTier, gotData, gotFurniture, gotBookshelf, gotGallery, gotTore, gotGarden, err := repo.GetHouseContents(charID)
|
|
if err != nil {
|
|
t.Fatalf("GetHouseContents failed: %v", err)
|
|
}
|
|
if len(gotTier) != 1 || gotTier[0] != 0x01 {
|
|
t.Errorf("Unexpected tier: %x", gotTier)
|
|
}
|
|
if len(gotData) != 1 || gotData[0] != 0x02 {
|
|
t.Errorf("Unexpected data: %x", gotData)
|
|
}
|
|
if len(gotFurniture) != 1 || gotFurniture[0] != 0x03 {
|
|
t.Errorf("Unexpected furniture: %x", gotFurniture)
|
|
}
|
|
if len(gotBookshelf) != 1 || gotBookshelf[0] != 0x04 {
|
|
t.Errorf("Unexpected bookshelf: %x", gotBookshelf)
|
|
}
|
|
if len(gotGallery) != 1 || gotGallery[0] != 0x05 {
|
|
t.Errorf("Unexpected gallery: %x", gotGallery)
|
|
}
|
|
if len(gotTore) != 1 || gotTore[0] != 0x06 {
|
|
t.Errorf("Unexpected tore: %x", gotTore)
|
|
}
|
|
if len(gotGarden) != 1 || gotGarden[0] != 0x07 {
|
|
t.Errorf("Unexpected garden: %x", gotGarden)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseGetMission(t *testing.T) {
|
|
repo, db, charID := setupHouseRepo(t)
|
|
|
|
mission := []byte{0xAA, 0xBB}
|
|
if _, err := db.Exec("UPDATE user_binary SET mission=$1 WHERE id=$2", mission, charID); err != nil {
|
|
t.Fatalf("Setup failed: %v", err)
|
|
}
|
|
|
|
got, err := repo.GetMission(charID)
|
|
if err != nil {
|
|
t.Fatalf("GetMission failed: %v", err)
|
|
}
|
|
if len(got) != 2 || got[0] != 0xAA {
|
|
t.Errorf("Expected mission data, got: %x", got)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseUpdateMission(t *testing.T) {
|
|
repo, db, charID := setupHouseRepo(t)
|
|
|
|
mission := []byte{0xCC, 0xDD, 0xEE}
|
|
if err := repo.UpdateMission(charID, mission); err != nil {
|
|
t.Fatalf("UpdateMission failed: %v", err)
|
|
}
|
|
|
|
var got []byte
|
|
if err := db.QueryRow("SELECT mission FROM user_binary WHERE id=$1", charID).Scan(&got); err != nil {
|
|
t.Fatalf("Verification query failed: %v", err)
|
|
}
|
|
if len(got) != 3 || got[0] != 0xCC {
|
|
t.Errorf("Expected mission data, got: %x", got)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseInitializeWarehouse(t *testing.T) {
|
|
repo, db, charID := setupHouseRepo(t)
|
|
|
|
if err := repo.InitializeWarehouse(charID); err != nil {
|
|
t.Fatalf("InitializeWarehouse failed: %v", err)
|
|
}
|
|
|
|
var count int
|
|
if err := db.QueryRow("SELECT COUNT(*) FROM warehouse WHERE character_id=$1", charID).Scan(&count); err != nil {
|
|
t.Fatalf("Verification query failed: %v", err)
|
|
}
|
|
if count != 1 {
|
|
t.Errorf("Expected 1 warehouse row, got: %d", count)
|
|
}
|
|
|
|
// Calling again should be idempotent
|
|
if err := repo.InitializeWarehouse(charID); err != nil {
|
|
t.Fatalf("Second InitializeWarehouse failed: %v", err)
|
|
}
|
|
if err := db.QueryRow("SELECT COUNT(*) FROM warehouse WHERE character_id=$1", charID).Scan(&count); err != nil {
|
|
t.Fatalf("Verification query failed: %v", err)
|
|
}
|
|
if count != 1 {
|
|
t.Errorf("Expected still 1 warehouse row after idempotent call, got: %d", count)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseGetWarehouseNames(t *testing.T) {
|
|
repo, db, charID := setupHouseRepo(t)
|
|
|
|
if err := repo.InitializeWarehouse(charID); err != nil {
|
|
t.Fatalf("InitializeWarehouse failed: %v", err)
|
|
}
|
|
if _, err := db.Exec("UPDATE warehouse SET item0name='Items Box 0', equip3name='Equip Box 3' WHERE character_id=$1", charID); err != nil {
|
|
t.Fatalf("Setup failed: %v", err)
|
|
}
|
|
|
|
itemNames, equipNames, err := repo.GetWarehouseNames(charID)
|
|
if err != nil {
|
|
t.Fatalf("GetWarehouseNames failed: %v", err)
|
|
}
|
|
if itemNames[0] != "Items Box 0" {
|
|
t.Errorf("Expected item0name='Items Box 0', got: %q", itemNames[0])
|
|
}
|
|
if equipNames[3] != "Equip Box 3" {
|
|
t.Errorf("Expected equip3name='Equip Box 3', got: %q", equipNames[3])
|
|
}
|
|
// Other names should be empty (COALESCE)
|
|
if itemNames[1] != "" {
|
|
t.Errorf("Expected empty item1name, got: %q", itemNames[1])
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseRenameWarehouseBox(t *testing.T) {
|
|
repo, db, charID := setupHouseRepo(t)
|
|
|
|
if err := repo.InitializeWarehouse(charID); err != nil {
|
|
t.Fatalf("InitializeWarehouse failed: %v", err)
|
|
}
|
|
|
|
if err := repo.RenameWarehouseBox(charID, 0, 5, "My Items"); err != nil {
|
|
t.Fatalf("RenameWarehouseBox(item) failed: %v", err)
|
|
}
|
|
if err := repo.RenameWarehouseBox(charID, 1, 2, "My Equips"); err != nil {
|
|
t.Fatalf("RenameWarehouseBox(equip) failed: %v", err)
|
|
}
|
|
|
|
var item5name, equip2name string
|
|
if err := db.QueryRow("SELECT COALESCE(item5name,''), COALESCE(equip2name,'') FROM warehouse WHERE character_id=$1", charID).Scan(&item5name, &equip2name); err != nil {
|
|
t.Fatalf("Verification query failed: %v", err)
|
|
}
|
|
if item5name != "My Items" {
|
|
t.Errorf("Expected item5name='My Items', got: %q", item5name)
|
|
}
|
|
if equip2name != "My Equips" {
|
|
t.Errorf("Expected equip2name='My Equips', got: %q", equip2name)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseRenameWarehouseBoxInvalidType(t *testing.T) {
|
|
repo, _, charID := setupHouseRepo(t)
|
|
|
|
err := repo.RenameWarehouseBox(charID, 5, 0, "Bad")
|
|
if err == nil {
|
|
t.Fatal("Expected error for invalid box type, got nil")
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseWarehouseItemData(t *testing.T) {
|
|
repo, _, charID := setupHouseRepo(t)
|
|
|
|
if err := repo.InitializeWarehouse(charID); err != nil {
|
|
t.Fatalf("InitializeWarehouse failed: %v", err)
|
|
}
|
|
|
|
data := []byte{0x01, 0x02, 0x03}
|
|
if err := repo.SetWarehouseItemData(charID, 3, data); err != nil {
|
|
t.Fatalf("SetWarehouseItemData failed: %v", err)
|
|
}
|
|
|
|
got, err := repo.GetWarehouseItemData(charID, 3)
|
|
if err != nil {
|
|
t.Fatalf("GetWarehouseItemData failed: %v", err)
|
|
}
|
|
if len(got) != 3 || got[0] != 0x01 {
|
|
t.Errorf("Expected item data, got: %x", got)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseWarehouseEquipData(t *testing.T) {
|
|
repo, _, charID := setupHouseRepo(t)
|
|
|
|
if err := repo.InitializeWarehouse(charID); err != nil {
|
|
t.Fatalf("InitializeWarehouse failed: %v", err)
|
|
}
|
|
|
|
data := []byte{0xAA, 0xBB}
|
|
if err := repo.SetWarehouseEquipData(charID, 7, data); err != nil {
|
|
t.Fatalf("SetWarehouseEquipData failed: %v", err)
|
|
}
|
|
|
|
got, err := repo.GetWarehouseEquipData(charID, 7)
|
|
if err != nil {
|
|
t.Fatalf("GetWarehouseEquipData failed: %v", err)
|
|
}
|
|
if len(got) != 2 || got[0] != 0xAA {
|
|
t.Errorf("Expected equip data, got: %x", got)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseAcquireTitle(t *testing.T) {
|
|
repo, _, charID := setupHouseRepo(t)
|
|
|
|
if err := repo.AcquireTitle(100, charID); err != nil {
|
|
t.Fatalf("AcquireTitle failed: %v", err)
|
|
}
|
|
|
|
titles, err := repo.GetTitles(charID)
|
|
if err != nil {
|
|
t.Fatalf("GetTitles failed: %v", err)
|
|
}
|
|
if len(titles) != 1 {
|
|
t.Fatalf("Expected 1 title, got: %d", len(titles))
|
|
}
|
|
if titles[0].ID != 100 {
|
|
t.Errorf("Expected title ID=100, got: %d", titles[0].ID)
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseAcquireTitleIdempotent(t *testing.T) {
|
|
repo, _, charID := setupHouseRepo(t)
|
|
|
|
if err := repo.AcquireTitle(100, charID); err != nil {
|
|
t.Fatalf("First AcquireTitle failed: %v", err)
|
|
}
|
|
if err := repo.AcquireTitle(100, charID); err != nil {
|
|
t.Fatalf("Second AcquireTitle failed: %v", err)
|
|
}
|
|
|
|
titles, err := repo.GetTitles(charID)
|
|
if err != nil {
|
|
t.Fatalf("GetTitles failed: %v", err)
|
|
}
|
|
if len(titles) != 1 {
|
|
t.Errorf("Expected 1 title after idempotent acquire, got: %d", len(titles))
|
|
}
|
|
}
|
|
|
|
func TestRepoHouseGetTitlesEmpty(t *testing.T) {
|
|
repo, _, charID := setupHouseRepo(t)
|
|
|
|
titles, err := repo.GetTitles(charID)
|
|
if err != nil {
|
|
t.Fatalf("GetTitles failed: %v", err)
|
|
}
|
|
if len(titles) != 0 {
|
|
t.Errorf("Expected 0 titles, got: %d", len(titles))
|
|
}
|
|
}
|