eq2go/internal/items/item_db_test.go

259 lines
7.0 KiB
Go

package items
import (
"context"
"fmt"
"math/rand"
"testing"
"zombiezen.com/go/sqlite/sqlitex"
)
// setupTestDB creates a test database with minimal schema
func setupTestDB(t *testing.T) *sqlitex.Pool {
// Create unique database name to avoid test contamination
dbName := fmt.Sprintf("file:test_%s_%d.db?mode=memory&cache=shared", t.Name(), rand.Int63())
pool, err := sqlitex.NewPool(dbName, sqlitex.PoolOptions{
PoolSize: 10,
})
if err != nil {
t.Fatalf("Failed to create test database pool: %v", err)
}
// Create complete test schema matching the real database structure
schema := `
CREATE TABLE items (
id INTEGER PRIMARY KEY,
soe_id INTEGER DEFAULT 0,
name TEXT NOT NULL DEFAULT '',
description TEXT DEFAULT '',
icon INTEGER DEFAULT 0,
icon2 INTEGER DEFAULT 0,
icon_heroic_op INTEGER DEFAULT 0,
icon_heroic_op2 INTEGER DEFAULT 0,
icon_id INTEGER DEFAULT 0,
icon_backdrop INTEGER DEFAULT 0,
icon_border INTEGER DEFAULT 0,
icon_tint_red INTEGER DEFAULT 0,
icon_tint_green INTEGER DEFAULT 0,
icon_tint_blue INTEGER DEFAULT 0,
tier INTEGER DEFAULT 1,
level INTEGER DEFAULT 1,
success_sellback INTEGER DEFAULT 0,
stack_size INTEGER DEFAULT 1,
generic_info_show_name INTEGER DEFAULT 1,
generic_info_item_flags INTEGER DEFAULT 0,
generic_info_item_flags2 INTEGER DEFAULT 0,
generic_info_creator_flag INTEGER DEFAULT 0,
generic_info_condition INTEGER DEFAULT 100,
generic_info_weight INTEGER DEFAULT 10,
generic_info_skill_req1 INTEGER DEFAULT 0,
generic_info_skill_req2 INTEGER DEFAULT 0,
generic_info_skill_min_level INTEGER DEFAULT 0,
generic_info_item_type INTEGER DEFAULT 0,
generic_info_appearance_id INTEGER DEFAULT 0,
generic_info_appearance_red INTEGER DEFAULT 0,
generic_info_appearance_green INTEGER DEFAULT 0,
generic_info_appearance_blue INTEGER DEFAULT 0,
generic_info_appearance_highlight_red INTEGER DEFAULT 0,
generic_info_appearance_highlight_green INTEGER DEFAULT 0,
generic_info_appearance_highlight_blue INTEGER DEFAULT 0,
generic_info_collectable INTEGER DEFAULT 0,
generic_info_offers_quest_id INTEGER DEFAULT 0,
generic_info_part_of_quest_id INTEGER DEFAULT 0,
generic_info_max_charges INTEGER DEFAULT 0,
generic_info_adventure_classes INTEGER DEFAULT 0,
generic_info_tradeskill_classes INTEGER DEFAULT 0,
generic_info_adventure_default_level INTEGER DEFAULT 1,
generic_info_tradeskill_default_level INTEGER DEFAULT 1,
generic_info_usable INTEGER DEFAULT 0,
generic_info_harvest INTEGER DEFAULT 0,
generic_info_body_drop INTEGER DEFAULT 0,
generic_info_pvp_description INTEGER DEFAULT 0,
generic_info_merc_only INTEGER DEFAULT 0,
generic_info_mount_only INTEGER DEFAULT 0,
generic_info_set_id INTEGER DEFAULT 0,
generic_info_collectable_unk INTEGER DEFAULT 0,
generic_info_transmuted_material INTEGER DEFAULT 0,
broker_price INTEGER DEFAULT 0,
sell_price INTEGER DEFAULT 0,
max_sell_value INTEGER DEFAULT 0,
created TEXT DEFAULT CURRENT_TIMESTAMP,
script_name TEXT DEFAULT '',
lua_script TEXT DEFAULT ''
);
CREATE TABLE item_mod_stats (
item_id INTEGER,
stat_type INTEGER,
stat_subtype INTEGER DEFAULT 0,
value REAL,
stat_name TEXT DEFAULT '',
level INTEGER DEFAULT 0
);
CREATE TABLE item_effects (
item_id INTEGER,
effect TEXT,
percentage INTEGER DEFAULT 0,
subbulletflag INTEGER DEFAULT 0
);
CREATE TABLE item_appearances (
item_id INTEGER,
type INTEGER,
red INTEGER DEFAULT 0,
green INTEGER DEFAULT 0,
blue INTEGER DEFAULT 0,
highlight_red INTEGER DEFAULT 0,
highlight_green INTEGER DEFAULT 0,
highlight_blue INTEGER DEFAULT 0
);
CREATE TABLE item_levels_override (
item_id INTEGER,
adventure_class INTEGER,
tradeskill_class INTEGER,
level INTEGER
);
CREATE TABLE item_mod_strings (
item_id INTEGER,
stat_string TEXT
);
CREATE TABLE item_details_weapon (
item_id INTEGER PRIMARY KEY,
wield_type INTEGER DEFAULT 2,
damage_low1 INTEGER DEFAULT 1,
damage_high1 INTEGER DEFAULT 2,
damage_low2 INTEGER DEFAULT 0,
damage_high2 INTEGER DEFAULT 0,
damage_low3 INTEGER DEFAULT 0,
damage_high3 INTEGER DEFAULT 0,
delay_hundredths INTEGER DEFAULT 300,
rating REAL DEFAULT 1.0
);
CREATE TABLE item_details_armor (
item_id INTEGER PRIMARY KEY,
mitigation_low INTEGER DEFAULT 1,
mitigation_high INTEGER DEFAULT 2
);
CREATE TABLE item_details_bag (
item_id INTEGER PRIMARY KEY,
num_slots INTEGER DEFAULT 6,
weight_reduction INTEGER DEFAULT 0
);
`
// Execute schema on connection
ctx := context.Background()
conn, err := pool.Take(ctx)
if err != nil {
t.Fatalf("Failed to get connection: %v", err)
}
defer pool.Put(conn)
if err := sqlitex.ExecuteScript(conn, schema, nil); err != nil {
t.Fatalf("Failed to create test schema: %v", err)
}
return pool
}
func TestNewItemDatabase(t *testing.T) {
pool := setupTestDB(t)
defer pool.Close()
idb := NewItemDatabase(pool)
if idb == nil {
t.Fatal("Expected non-nil ItemDatabase")
}
if idb.pool == nil {
t.Fatal("Expected non-nil database pool")
}
}
func TestItemDatabaseBasicOperation(t *testing.T) {
pool := setupTestDB(t)
defer pool.Close()
idb := NewItemDatabase(pool)
masterList := NewMasterItemList()
// Test that LoadItems doesn't crash (even with empty database)
err := idb.LoadItems(masterList)
if err != nil {
t.Fatalf("LoadItems should not fail with empty database: %v", err)
}
if masterList.GetItemCount() != 0 {
t.Errorf("Expected empty master list, got %d items", masterList.GetItemCount())
}
}
func TestItemDatabaseWithData(t *testing.T) {
pool := setupTestDB(t)
defer pool.Close()
// Insert test data
ctx := context.Background()
conn, err := pool.Take(ctx)
if err != nil {
t.Fatalf("Failed to get connection: %v", err)
}
defer pool.Put(conn)
// Insert a test item
err = sqlitex.Execute(conn, `INSERT INTO items (id, name, generic_info_item_type) VALUES (?, ?, ?)`, &sqlitex.ExecOptions{
Args: []any{1, "Test Sword", ItemTypeWeapon},
})
if err != nil {
t.Fatalf("Failed to insert test item: %v", err)
}
// Insert weapon details
err = sqlitex.Execute(conn, `INSERT INTO item_details_weapon (item_id, damage_low1, damage_high1) VALUES (?, ?, ?)`, &sqlitex.ExecOptions{
Args: []any{1, 10, 15},
})
if err != nil {
t.Fatalf("Failed to insert weapon details: %v", err)
}
// Load items
idb := NewItemDatabase(pool)
masterList := NewMasterItemList()
err = idb.LoadItems(masterList)
if err != nil {
t.Fatalf("Failed to load items: %v", err)
}
if masterList.GetItemCount() != 1 {
t.Errorf("Expected 1 item, got %d items", masterList.GetItemCount())
}
// Verify the item was loaded correctly
item := masterList.GetItem(1)
if item == nil {
t.Fatal("Expected to find item with ID 1")
}
if item.Name != "Test Sword" {
t.Errorf("Expected item name 'Test Sword', got '%s'", item.Name)
}
if item.WeaponInfo == nil {
t.Error("Expected weapon info to be loaded")
} else {
if item.WeaponInfo.DamageLow1 != 10 {
t.Errorf("Expected damage low 10, got %d", item.WeaponInfo.DamageLow1)
}
if item.WeaponInfo.DamageHigh1 != 15 {
t.Errorf("Expected damage high 15, got %d", item.WeaponInfo.DamageHigh1)
}
}
}