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:
Houmgaor
2026-02-21 14:47:25 +01:00
parent bd8e30d570
commit 35d8471d59
13 changed files with 280 additions and 59 deletions

View File

@@ -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))
}
})
}
}

View File

@@ -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() {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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{}

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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 ---

View File

@@ -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

View File

@@ -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

View File

@@ -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() {