mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-03-22 07:32:32 +01:00
fix(channelserver): resolve all golangci-lint issues and add handler tests
Fix errcheck violations across 11 repo files by wrapping deferred rows.Close() and tx.Rollback() calls to discard the error return. Fix unchecked Scan/Exec calls in guild store tests. Fix staticcheck SA9003 empty branch in test helpers. Add 6 mock-based unit tests for GetCharacterSaveData covering nil savedata, sql.ErrNoRows, DB errors, compressed round-trip, new-character skip, and config mode/pointer propagation.
This commit is contained in:
@@ -2,7 +2,9 @@ package channelserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
cfg "erupe-ce/config"
|
||||
@@ -571,3 +573,175 @@ func BenchmarkDecompress(b *testing.B) {
|
||||
_ = save.Decompress()
|
||||
}
|
||||
}
|
||||
|
||||
// --- Mock-based GetCharacterSaveData tests ---
|
||||
|
||||
func TestGetCharacterSaveData_NilSavedata(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := newMockCharacterRepo()
|
||||
mock.loadSaveDataID = 42
|
||||
mock.loadSaveDataName = "Hunter"
|
||||
mock.loadSaveDataNew = true
|
||||
server.charRepo = mock
|
||||
session := createMockSession(42, server)
|
||||
|
||||
result, err := GetCharacterSaveData(session, 42)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatal("expected non-nil result")
|
||||
}
|
||||
if result.CharID != 42 {
|
||||
t.Errorf("CharID = %d, want 42", result.CharID)
|
||||
}
|
||||
if result.Name != "Hunter" {
|
||||
t.Errorf("Name = %q, want %q", result.Name, "Hunter")
|
||||
}
|
||||
if !result.IsNewCharacter {
|
||||
t.Error("IsNewCharacter should be true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCharacterSaveData_NotFound(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := newMockCharacterRepo()
|
||||
mock.loadSaveDataErr = sql.ErrNoRows
|
||||
server.charRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
|
||||
result, err := GetCharacterSaveData(session, 999)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for missing character")
|
||||
}
|
||||
if result != nil {
|
||||
t.Error("expected nil result for missing character")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCharacterSaveData_DBError(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := newMockCharacterRepo()
|
||||
mock.loadSaveDataErr = errors.New("connection refused")
|
||||
server.charRepo = mock
|
||||
session := createMockSession(1, server)
|
||||
|
||||
result, err := GetCharacterSaveData(session, 1)
|
||||
if err == nil {
|
||||
t.Fatal("expected error on DB failure")
|
||||
}
|
||||
if result != nil {
|
||||
t.Error("expected nil result on DB failure")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCharacterSaveData_WithCompressedData(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := newMockCharacterRepo()
|
||||
|
||||
// Create minimal valid savedata and compress it
|
||||
saveData := make([]byte, 150000)
|
||||
copy(saveData[88:], append([]byte("TestHunter"), 0x00))
|
||||
compressed, err := nullcomp.Compress(saveData)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to compress test savedata: %v", err)
|
||||
}
|
||||
|
||||
mock.loadSaveDataID = 10
|
||||
mock.loadSaveDataData = compressed
|
||||
mock.loadSaveDataName = "TestHunter"
|
||||
mock.loadSaveDataNew = false
|
||||
server.charRepo = mock
|
||||
session := createMockSession(10, server)
|
||||
|
||||
result, err := GetCharacterSaveData(session, 10)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatal("expected non-nil result")
|
||||
}
|
||||
if result.CharID != 10 {
|
||||
t.Errorf("CharID = %d, want 10", result.CharID)
|
||||
}
|
||||
if result.IsNewCharacter {
|
||||
t.Error("IsNewCharacter should be false")
|
||||
}
|
||||
if result.Name != "TestHunter" {
|
||||
t.Errorf("Name = %q, want %q", result.Name, "TestHunter")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCharacterSaveData_NewCharacterSkipsDecompress(t *testing.T) {
|
||||
// When savedata is nil AND IsNewCharacter=true, GetCharacterSaveData
|
||||
// returns a valid result without decompressing.
|
||||
server := createMockServer()
|
||||
mock := newMockCharacterRepo()
|
||||
mock.loadSaveDataID = 5
|
||||
mock.loadSaveDataName = "NewPlayer"
|
||||
mock.loadSaveDataNew = true
|
||||
// loadSaveDataData is nil
|
||||
server.charRepo = mock
|
||||
session := createMockSession(5, server)
|
||||
|
||||
result, err := GetCharacterSaveData(session, 5)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatal("expected non-nil result")
|
||||
}
|
||||
if !result.IsNewCharacter {
|
||||
t.Error("IsNewCharacter should be true")
|
||||
}
|
||||
if result.CharID != 5 {
|
||||
t.Errorf("CharID = %d, want 5", result.CharID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCharacterSaveData_ConfigMode(t *testing.T) {
|
||||
server := createMockServer()
|
||||
mock := newMockCharacterRepo()
|
||||
|
||||
saveData := make([]byte, 150000)
|
||||
copy(saveData[88:], append([]byte("ModeTest"), 0x00))
|
||||
compressed, err := nullcomp.Compress(saveData)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to compress: %v", err)
|
||||
}
|
||||
|
||||
mock.loadSaveDataID = 1
|
||||
mock.loadSaveDataData = compressed
|
||||
mock.loadSaveDataName = "ModeTest"
|
||||
server.charRepo = mock
|
||||
|
||||
modes := []struct {
|
||||
mode cfg.Mode
|
||||
name string
|
||||
}{
|
||||
{cfg.S6, "S6"},
|
||||
{cfg.F5, "F5"},
|
||||
{cfg.G10, "G10"},
|
||||
{cfg.Z2, "Z2"},
|
||||
{cfg.ZZ, "ZZ"},
|
||||
}
|
||||
for _, tc := range modes {
|
||||
mode := tc.mode
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
server.erupeConfig.RealClientMode = mode
|
||||
session := createMockSession(1, server)
|
||||
|
||||
result, err := GetCharacterSaveData(session, 1)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error for mode %v: %v", mode, err)
|
||||
}
|
||||
if result.Mode != mode {
|
||||
t.Errorf("Mode = %v, want %v", result.Mode, mode)
|
||||
}
|
||||
expectedPointers := getPointers(mode)
|
||||
if len(result.Pointers) != len(expectedPointers) {
|
||||
t.Errorf("Pointers count = %d, want %d", len(result.Pointers), len(expectedPointers))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (r *DistributionRepository) List(charID uint32, distType uint8) ([]Distribu
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
var dists []Distribution
|
||||
for rows.Next() {
|
||||
@@ -52,7 +52,7 @@ func (r *DistributionRepository) GetItems(distributionID uint32) ([]Distribution
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
var items []DistributionItem
|
||||
for rows.Next() {
|
||||
|
||||
@@ -63,7 +63,7 @@ func (r *FestaRepository) GetFestaEvents() ([]FestaEvent, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var e FestaEvent
|
||||
if err := rows.StructScan(&e); err != nil {
|
||||
@@ -103,7 +103,7 @@ func (r *FestaRepository) GetTrialsWithMonopoly() ([]FestaTrial, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var trial FestaTrial
|
||||
if err := rows.StructScan(&trial); err != nil {
|
||||
@@ -213,7 +213,7 @@ func (r *FestaRepository) ListPrizes(charID uint32, prizeType string) ([]Prize,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var prize Prize
|
||||
if err := rows.StructScan(&prize); err != nil {
|
||||
|
||||
@@ -38,7 +38,7 @@ func (r *GachaRepository) GetRewardPool(gachaID uint32) ([]GachaEntry, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var entry GachaEntry
|
||||
if err := rows.StructScan(&entry); err == nil {
|
||||
@@ -58,7 +58,7 @@ func (r *GachaRepository) GetItemsForEntry(entryID uint32) ([]GachaItem, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var item GachaItem
|
||||
if err := rows.StructScan(&item); err == nil {
|
||||
@@ -78,7 +78,7 @@ func (r *GachaRepository) GetGuaranteedItems(rollType uint8, gachaID uint32) ([]
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var item GachaItem
|
||||
if err := rows.StructScan(&item); err == nil {
|
||||
@@ -155,7 +155,7 @@ func (r *GachaRepository) GetBoxEntryIDs(gachaID uint32, charID uint32) ([]uint3
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var id uint32
|
||||
if err := rows.Scan(&id); err == nil {
|
||||
@@ -194,7 +194,7 @@ func (r *GachaRepository) ListShop() ([]Gacha, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var g Gacha
|
||||
if err := rows.StructScan(&g); err == nil {
|
||||
@@ -224,7 +224,7 @@ func (r *GachaRepository) GetAllEntries(gachaID uint32) ([]GachaEntry, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var entry GachaEntry
|
||||
if err := rows.StructScan(&entry); err == nil {
|
||||
|
||||
@@ -115,7 +115,7 @@ func (r *GuildRepository) GetByID(guildID uint32) (*Guild, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
if !rows.Next() {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -144,7 +144,7 @@ func (r *GuildRepository) GetByCharID(charID uint32) (*Guild, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
if !rows.Next() {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -157,7 +157,7 @@ func (r *GuildRepository) ListAll() ([]*Guild, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
var guilds []*Guild
|
||||
for rows.Next() {
|
||||
@@ -370,7 +370,7 @@ func (r *GuildRepository) GetMembers(guildID uint32, applicants bool) ([]*GuildM
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
members := make([]*GuildMember, 0)
|
||||
for rows.Next() {
|
||||
@@ -390,7 +390,7 @@ func (r *GuildRepository) GetCharacterMembership(charID uint32) (*GuildMember, e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
if !rows.Next() {
|
||||
return nil, nil
|
||||
@@ -486,7 +486,7 @@ func (r *GuildRepository) ListPosts(guildID uint32, postType int) ([]*MessageBoa
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var posts []*MessageBoardPost
|
||||
for rows.Next() {
|
||||
post := &MessageBoardPost{}
|
||||
@@ -504,7 +504,7 @@ func (r *GuildRepository) CreatePost(guildID, authorID, stampID uint32, postType
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
if _, err := tx.Exec(
|
||||
`INSERT INTO guild_posts (guild_id, author_id, stamp_id, post_type, title, body) VALUES ($1, $2, $3, $4, $5, $6)`,
|
||||
@@ -585,7 +585,7 @@ func (r *GuildRepository) GetAllianceByID(allianceID uint32) (*GuildAlliance, er
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
if !rows.Next() {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -598,7 +598,7 @@ func (r *GuildRepository) ListAlliances() ([]*GuildAlliance, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var alliances []*GuildAlliance
|
||||
for rows.Next() {
|
||||
alliance, err := r.scanAllianceWithGuilds(rows)
|
||||
@@ -679,7 +679,7 @@ func (r *GuildRepository) ListAdventures(guildID uint32) ([]*GuildAdventure, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var adventures []*GuildAdventure
|
||||
for rows.Next() {
|
||||
adv := &GuildAdventure{}
|
||||
@@ -714,7 +714,7 @@ func (r *GuildRepository) CollectAdventure(adventureID uint32, charID uint32) er
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
var collectedBy string
|
||||
err = tx.QueryRow("SELECT collected_by FROM guild_adventures WHERE id = $1 FOR UPDATE", adventureID).Scan(&collectedBy)
|
||||
@@ -766,7 +766,7 @@ func (r *GuildRepository) ListGuildHunts(guildID, charID uint32) ([]*TreasureHun
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var hunts []*TreasureHunt
|
||||
for rows.Next() {
|
||||
hunt := &TreasureHunt{}
|
||||
@@ -821,7 +821,7 @@ func (r *GuildRepository) ListMeals(guildID uint32) ([]*GuildMeal, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var meals []*GuildMeal
|
||||
for rows.Next() {
|
||||
meal := &GuildMeal{}
|
||||
@@ -871,7 +871,7 @@ func (r *GuildRepository) ListGuildKills(guildID, charID uint32) ([]*GuildKill,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var kills []*GuildKill
|
||||
for rows.Next() {
|
||||
kill := &GuildKill{}
|
||||
@@ -928,7 +928,7 @@ func (r *GuildRepository) ListInvitedCharacters(guildID uint32) ([]*ScoutedChara
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var chars []*ScoutedCharacter
|
||||
for rows.Next() {
|
||||
sc := &ScoutedCharacter{}
|
||||
|
||||
@@ -935,10 +935,14 @@ func TestRemoveGuildFromAllianceSub1(t *testing.T) {
|
||||
t.Fatalf("CreateAlliance failed: %v", err)
|
||||
}
|
||||
var allianceID uint32
|
||||
db.QueryRow("SELECT id FROM guild_alliances WHERE parent_id=$1", guildID).Scan(&allianceID)
|
||||
if err := db.QueryRow("SELECT id FROM guild_alliances WHERE parent_id=$1", guildID).Scan(&allianceID); err != nil {
|
||||
t.Fatalf("Failed to get alliance ID: %v", err)
|
||||
}
|
||||
|
||||
// Add sub1
|
||||
db.Exec("UPDATE guild_alliances SET sub1_id=$1 WHERE id=$2", guild2, allianceID)
|
||||
if _, err := db.Exec("UPDATE guild_alliances SET sub1_id=$1 WHERE id=$2", guild2, allianceID); err != nil {
|
||||
t.Fatalf("Failed to set sub1: %v", err)
|
||||
}
|
||||
|
||||
// Remove sub1
|
||||
if err := repo.RemoveGuildFromAlliance(allianceID, guild2, guild2, 0); err != nil {
|
||||
@@ -972,8 +976,12 @@ func TestRemoveGuildFromAllianceSub1ShiftsSub2(t *testing.T) {
|
||||
t.Fatalf("CreateAlliance failed: %v", err)
|
||||
}
|
||||
var allianceID uint32
|
||||
db.QueryRow("SELECT id FROM guild_alliances WHERE parent_id=$1", guildID).Scan(&allianceID)
|
||||
db.Exec("UPDATE guild_alliances SET sub1_id=$1, sub2_id=$2 WHERE id=$3", guild2, guild3, allianceID)
|
||||
if err := db.QueryRow("SELECT id FROM guild_alliances WHERE parent_id=$1", guildID).Scan(&allianceID); err != nil {
|
||||
t.Fatalf("Failed to get alliance ID: %v", err)
|
||||
}
|
||||
if _, err := db.Exec("UPDATE guild_alliances SET sub1_id=$1, sub2_id=$2 WHERE id=$3", guild2, guild3, allianceID); err != nil {
|
||||
t.Fatalf("Failed to set sub guilds: %v", err)
|
||||
}
|
||||
|
||||
// Remove sub1 — sub2 should shift into sub1's slot
|
||||
if err := repo.RemoveGuildFromAlliance(allianceID, guild2, guild2, guild3); err != nil {
|
||||
@@ -1010,8 +1018,12 @@ func TestRemoveGuildFromAllianceSub2(t *testing.T) {
|
||||
t.Fatalf("CreateAlliance failed: %v", err)
|
||||
}
|
||||
var allianceID uint32
|
||||
db.QueryRow("SELECT id FROM guild_alliances WHERE parent_id=$1", guildID).Scan(&allianceID)
|
||||
db.Exec("UPDATE guild_alliances SET sub1_id=$1, sub2_id=$2 WHERE id=$3", guild2, guild3, allianceID)
|
||||
if err := db.QueryRow("SELECT id FROM guild_alliances WHERE parent_id=$1", guildID).Scan(&allianceID); err != nil {
|
||||
t.Fatalf("Failed to get alliance ID: %v", err)
|
||||
}
|
||||
if _, err := db.Exec("UPDATE guild_alliances SET sub1_id=$1, sub2_id=$2 WHERE id=$3", guild2, guild3, allianceID); err != nil {
|
||||
t.Fatalf("Failed to set sub guilds: %v", err)
|
||||
}
|
||||
|
||||
// Remove sub2 directly
|
||||
if err := repo.RemoveGuildFromAlliance(allianceID, guild3, guild2, guild3); err != nil {
|
||||
@@ -1093,7 +1105,9 @@ func TestChargeAdventure(t *testing.T) {
|
||||
}
|
||||
|
||||
var charge uint32
|
||||
db.QueryRow("SELECT charge FROM guild_adventures WHERE id=$1", advID).Scan(&charge)
|
||||
if err := db.QueryRow("SELECT charge FROM guild_adventures WHERE id=$1", advID).Scan(&charge); err != nil {
|
||||
t.Fatalf("Failed to get charge: %v", err)
|
||||
}
|
||||
if charge != 25 {
|
||||
t.Errorf("Expected charge=25, got %d", charge)
|
||||
}
|
||||
@@ -1194,7 +1208,9 @@ func TestAcquireHunt(t *testing.T) {
|
||||
|
||||
// Verify in DB
|
||||
var acquired bool
|
||||
db.QueryRow("SELECT acquired FROM guild_hunts WHERE id=$1", hunt.HuntID).Scan(&acquired)
|
||||
if err := db.QueryRow("SELECT acquired FROM guild_hunts WHERE id=$1", hunt.HuntID).Scan(&acquired); err != nil {
|
||||
t.Fatalf("Failed to get acquired: %v", err)
|
||||
}
|
||||
if !acquired {
|
||||
t.Error("Expected acquired=true in DB")
|
||||
}
|
||||
@@ -1208,7 +1224,9 @@ func TestListGuildHunts(t *testing.T) {
|
||||
t.Fatalf("CreateHunt failed: %v", err)
|
||||
}
|
||||
hunt, _ := repo.GetPendingHunt(charID)
|
||||
repo.AcquireHunt(hunt.HuntID)
|
||||
if err := repo.AcquireHunt(hunt.HuntID); err != nil {
|
||||
t.Fatalf("AcquireHunt failed: %v", err)
|
||||
}
|
||||
|
||||
// Create a level-1 hunt (should not appear)
|
||||
if err := repo.CreateHunt(guildID, charID, 20, 1, nil, ""); err != nil {
|
||||
@@ -1240,7 +1258,9 @@ func TestRegisterHuntReport(t *testing.T) {
|
||||
}
|
||||
|
||||
var treasureHunt *uint32
|
||||
db.QueryRow("SELECT treasure_hunt FROM guild_characters WHERE character_id=$1", charID).Scan(&treasureHunt)
|
||||
if err := db.QueryRow("SELECT treasure_hunt FROM guild_characters WHERE character_id=$1", charID).Scan(&treasureHunt); err != nil {
|
||||
t.Fatalf("Failed to get treasure_hunt: %v", err)
|
||||
}
|
||||
if treasureHunt == nil || *treasureHunt != hunt.HuntID {
|
||||
t.Errorf("Expected treasure_hunt=%d, got %v", hunt.HuntID, treasureHunt)
|
||||
}
|
||||
@@ -1253,7 +1273,9 @@ func TestCollectHunt(t *testing.T) {
|
||||
t.Fatalf("CreateHunt failed: %v", err)
|
||||
}
|
||||
hunt, _ := repo.GetPendingHunt(charID)
|
||||
repo.RegisterHuntReport(hunt.HuntID, charID)
|
||||
if err := repo.RegisterHuntReport(hunt.HuntID, charID); err != nil {
|
||||
t.Fatalf("RegisterHuntReport failed: %v", err)
|
||||
}
|
||||
|
||||
if err := repo.CollectHunt(hunt.HuntID); err != nil {
|
||||
t.Fatalf("CollectHunt failed: %v", err)
|
||||
@@ -1261,14 +1283,18 @@ func TestCollectHunt(t *testing.T) {
|
||||
|
||||
// Hunt should be marked collected
|
||||
var collected bool
|
||||
db.QueryRow("SELECT collected FROM guild_hunts WHERE id=$1", hunt.HuntID).Scan(&collected)
|
||||
if err := db.QueryRow("SELECT collected FROM guild_hunts WHERE id=$1", hunt.HuntID).Scan(&collected); err != nil {
|
||||
t.Fatalf("Failed to scan collected: %v", err)
|
||||
}
|
||||
if !collected {
|
||||
t.Error("Expected collected=true")
|
||||
}
|
||||
|
||||
// Character's treasure_hunt should be cleared
|
||||
var treasureHunt *uint32
|
||||
db.QueryRow("SELECT treasure_hunt FROM guild_characters WHERE character_id=$1", charID).Scan(&treasureHunt)
|
||||
if err := db.QueryRow("SELECT treasure_hunt FROM guild_characters WHERE character_id=$1", charID).Scan(&treasureHunt); err != nil {
|
||||
t.Fatalf("Failed to get treasure_hunt: %v", err)
|
||||
}
|
||||
if treasureHunt != nil {
|
||||
t.Errorf("Expected treasure_hunt=NULL, got %v", *treasureHunt)
|
||||
}
|
||||
@@ -1287,7 +1313,9 @@ func TestClaimHuntReward(t *testing.T) {
|
||||
}
|
||||
|
||||
var count int
|
||||
db.QueryRow("SELECT COUNT(*) FROM guild_hunts_claimed WHERE hunt_id=$1 AND character_id=$2", hunt.HuntID, charID).Scan(&count)
|
||||
if err := db.QueryRow("SELECT COUNT(*) FROM guild_hunts_claimed WHERE hunt_id=$1 AND character_id=$2", hunt.HuntID, charID).Scan(&count); err != nil {
|
||||
t.Fatalf("Failed to scan claimed count: %v", err)
|
||||
}
|
||||
if count != 1 {
|
||||
t.Errorf("Expected 1 claimed entry, got %d", count)
|
||||
}
|
||||
@@ -1365,7 +1393,9 @@ func TestClaimHuntBox(t *testing.T) {
|
||||
}
|
||||
|
||||
var got time.Time
|
||||
db.QueryRow("SELECT box_claimed FROM guild_characters WHERE character_id=$1", charID).Scan(&got)
|
||||
if err := db.QueryRow("SELECT box_claimed FROM guild_characters WHERE character_id=$1", charID).Scan(&got); err != nil {
|
||||
t.Fatalf("Failed to scan box_claimed: %v", err)
|
||||
}
|
||||
if !got.Equal(claimedAt) {
|
||||
t.Errorf("Expected box_claimed=%v, got %v", claimedAt, got)
|
||||
}
|
||||
@@ -1376,11 +1406,17 @@ func TestListAndCountGuildKills(t *testing.T) {
|
||||
|
||||
// Set box_claimed to the past so kills after it are visible
|
||||
past := time.Now().Add(-1 * time.Hour).UTC().Truncate(time.Second)
|
||||
repo.ClaimHuntBox(charID, past)
|
||||
if err := repo.ClaimHuntBox(charID, past); err != nil {
|
||||
t.Fatalf("ClaimHuntBox failed: %v", err)
|
||||
}
|
||||
|
||||
// Insert kill logs for this character
|
||||
db.Exec("INSERT INTO kill_logs (character_id, monster, quantity, timestamp) VALUES ($1, 100, 1, NOW())", charID)
|
||||
db.Exec("INSERT INTO kill_logs (character_id, monster, quantity, timestamp) VALUES ($1, 200, 1, NOW())", charID)
|
||||
if _, err := db.Exec("INSERT INTO kill_logs (character_id, monster, quantity, timestamp) VALUES ($1, 100, 1, NOW())", charID); err != nil {
|
||||
t.Fatalf("Failed to insert kill log: %v", err)
|
||||
}
|
||||
if _, err := db.Exec("INSERT INTO kill_logs (character_id, monster, quantity, timestamp) VALUES ($1, 200, 1, NOW())", charID); err != nil {
|
||||
t.Fatalf("Failed to insert kill log: %v", err)
|
||||
}
|
||||
|
||||
kills, err := repo.ListGuildKills(guildID, charID)
|
||||
if err != nil {
|
||||
@@ -1403,7 +1439,9 @@ func TestListGuildKillsEmpty(t *testing.T) {
|
||||
repo, _, guildID, charID := setupGuildRepo(t)
|
||||
|
||||
// Set box_claimed to now — no kills after it
|
||||
repo.ClaimHuntBox(charID, time.Now().UTC())
|
||||
if err := repo.ClaimHuntBox(charID, time.Now().UTC()); err != nil {
|
||||
t.Fatalf("ClaimHuntBox failed: %v", err)
|
||||
}
|
||||
|
||||
kills, err := repo.ListGuildKills(guildID, charID)
|
||||
if err != nil {
|
||||
@@ -1433,7 +1471,9 @@ func TestDisbandCleansUpAlliance(t *testing.T) {
|
||||
}
|
||||
|
||||
var allianceID uint32
|
||||
db.QueryRow("SELECT id FROM guild_alliances WHERE parent_id=$1", guildID).Scan(&allianceID)
|
||||
if err := db.QueryRow("SELECT id FROM guild_alliances WHERE parent_id=$1", guildID).Scan(&allianceID); err != nil {
|
||||
t.Fatalf("Failed to scan alliance ID: %v", err)
|
||||
}
|
||||
|
||||
if err := repo.Disband(guildID); err != nil {
|
||||
t.Fatalf("Disband failed: %v", err)
|
||||
|
||||
@@ -46,7 +46,7 @@ func (r *HouseRepository) SearchHousesByName(name string) ([]HouseData, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var house HouseData
|
||||
if err := rows.StructScan(&house); err == nil {
|
||||
@@ -194,7 +194,7 @@ func (r *HouseRepository) GetTitles(charID uint32) ([]Title, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
for rows.Next() {
|
||||
var title Title
|
||||
if err := rows.StructScan(&title); err == nil {
|
||||
|
||||
@@ -44,7 +44,7 @@ func (r *MercenaryRepository) GetMercenaryLoans(charID uint32) ([]MercenaryLoan,
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query mercenary loans: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var result []MercenaryLoan
|
||||
for rows.Next() {
|
||||
var l MercenaryLoan
|
||||
@@ -69,7 +69,7 @@ func (r *MercenaryRepository) GetGuildHuntCatsUsed(charID uint32) ([]GuildHuntCa
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query guild hunt cats: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var result []GuildHuntCatUsage
|
||||
for rows.Next() {
|
||||
var u GuildHuntCatUsage
|
||||
@@ -90,7 +90,7 @@ func (r *MercenaryRepository) GetGuildAirou(guildID uint32) ([][]byte, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query guild airou: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var result [][]byte
|
||||
for rows.Next() {
|
||||
var data []byte
|
||||
|
||||
@@ -22,7 +22,7 @@ func (r *MiscRepository) GetTrendWeapons(weaponType uint8) ([]uint16, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query trend_weapons: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var result []uint16
|
||||
for rows.Next() {
|
||||
var id uint16
|
||||
|
||||
@@ -118,6 +118,13 @@ type mockCharacterRepo struct {
|
||||
adjustErr error
|
||||
readErr error
|
||||
saveErr error
|
||||
|
||||
// LoadSaveData mock fields
|
||||
loadSaveDataID uint32
|
||||
loadSaveDataData []byte
|
||||
loadSaveDataNew bool
|
||||
loadSaveDataName string
|
||||
loadSaveDataErr error
|
||||
}
|
||||
|
||||
func newMockCharacterRepo() *mockCharacterRepo {
|
||||
@@ -194,7 +201,9 @@ func (m *mockCharacterRepo) UpdateGCPAndPact(_ uint32, _ uint32, _ uint32) error
|
||||
func (m *mockCharacterRepo) FindByRastaID(_ int) (uint32, string, error) { return 0, "", nil }
|
||||
func (m *mockCharacterRepo) SaveCharacterData(_ uint32, _ []byte, _, _ uint16, _ bool, _ uint8, _ uint16) error { return nil }
|
||||
func (m *mockCharacterRepo) SaveHouseData(_ uint32, _ []byte, _, _, _, _, _ []byte) error { return nil }
|
||||
func (m *mockCharacterRepo) LoadSaveData(_ uint32) (uint32, []byte, bool, string, error) { return 0, nil, false, "", nil }
|
||||
func (m *mockCharacterRepo) LoadSaveData(_ uint32) (uint32, []byte, bool, string, error) {
|
||||
return m.loadSaveDataID, m.loadSaveDataData, m.loadSaveDataNew, m.loadSaveDataName, m.loadSaveDataErr
|
||||
}
|
||||
|
||||
// --- mockGoocooRepo ---
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ func (r *ScenarioRepository) GetCounters() ([]Scenario, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query scenario_counter: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var result []Scenario
|
||||
for rows.Next() {
|
||||
var s Scenario
|
||||
|
||||
@@ -124,7 +124,7 @@ func (r *TowerRepository) GetTenrouiraiMissionScores(guildID uint32, missionInde
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
var scores []TenrouiraiCharScore
|
||||
for rows.Next() {
|
||||
var cs TenrouiraiCharScore
|
||||
|
||||
@@ -173,9 +173,7 @@ func applyUpdateSchema(t *testing.T, db *sqlx.DB, projectRoot string) {
|
||||
if stmt == "" {
|
||||
continue
|
||||
}
|
||||
if _, err := db.Exec(stmt); err != nil {
|
||||
// Silently ignore — these are expected for role mismatches, already-applied changes, etc.
|
||||
}
|
||||
_, _ = db.Exec(stmt) // Errors expected for role mismatches, already-applied changes, etc.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,7 +258,7 @@ func truncateAllTables(t *testing.T, db *sqlx.DB) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to list tables for truncation: %v", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
var tables []string
|
||||
for rows.Next() {
|
||||
|
||||
Reference in New Issue
Block a user