Dragon-Knight/internal/spells/spells_test.go

445 lines
10 KiB
Go

package spells
import (
"os"
"testing"
"dk/internal/database"
)
func setupTestDB(t *testing.T) *database.DB {
testDB := "test_spells.db"
t.Cleanup(func() {
os.Remove(testDB)
})
db, err := database.Open(testDB)
if err != nil {
t.Fatalf("Failed to open test database: %v", err)
}
// Create spells table
createTable := `CREATE TABLE spells (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
mp INTEGER NOT NULL DEFAULT 0,
attribute INTEGER NOT NULL DEFAULT 0,
type INTEGER NOT NULL DEFAULT 0
)`
if err := db.Exec(createTable); err != nil {
t.Fatalf("Failed to create spells table: %v", err)
}
// Insert test data
testSpells := `INSERT INTO spells (name, mp, attribute, type) VALUES
('Heal', 5, 10, 1),
('Revive', 10, 25, 1),
('Hurt', 5, 15, 2),
('Pain', 12, 35, 2),
('Sleep', 10, 5, 3),
('Dream', 30, 9, 3),
('Craze', 10, 10, 4),
('Ward', 10, 10, 5)`
if err := db.Exec(testSpells); err != nil {
t.Fatalf("Failed to insert test spells: %v", err)
}
return db
}
func TestFind(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
// Test finding existing spell
spell, err := Find(db, 1)
if err != nil {
t.Fatalf("Failed to find spell: %v", err)
}
if spell.ID != 1 {
t.Errorf("Expected ID 1, got %d", spell.ID)
}
if spell.Name != "Heal" {
t.Errorf("Expected name 'Heal', got '%s'", spell.Name)
}
if spell.MP != 5 {
t.Errorf("Expected MP 5, got %d", spell.MP)
}
if spell.Attribute != 10 {
t.Errorf("Expected attribute 10, got %d", spell.Attribute)
}
if spell.Type != TypeHealing {
t.Errorf("Expected type %d, got %d", TypeHealing, spell.Type)
}
// Test finding non-existent spell
_, err = Find(db, 999)
if err == nil {
t.Error("Expected error when finding non-existent spell")
}
}
func TestAll(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
spells, err := All(db)
if err != nil {
t.Fatalf("Failed to get all spells: %v", err)
}
if len(spells) != 8 {
t.Errorf("Expected 8 spells, got %d", len(spells))
}
// Check ordering (by type, then MP, then ID)
if spells[0].Type > spells[1].Type {
t.Error("Expected spells to be ordered by type first")
}
}
func TestByType(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
// Test healing spells
healingSpells, err := ByType(db, TypeHealing)
if err != nil {
t.Fatalf("Failed to get healing spells: %v", err)
}
if len(healingSpells) != 2 {
t.Errorf("Expected 2 healing spells, got %d", len(healingSpells))
}
for _, spell := range healingSpells {
if spell.Type != TypeHealing {
t.Errorf("Expected healing spell, got type %d", spell.Type)
}
}
// Test hurt spells
hurtSpells, err := ByType(db, TypeHurt)
if err != nil {
t.Fatalf("Failed to get hurt spells: %v", err)
}
if len(hurtSpells) != 2 {
t.Errorf("Expected 2 hurt spells, got %d", len(hurtSpells))
}
// Verify ordering within type (by MP)
if hurtSpells[0].MP > hurtSpells[1].MP {
t.Error("Expected spells within type to be ordered by MP")
}
}
func TestByMaxMP(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
// Test spells with MP <= 10
lowMPSpells, err := ByMaxMP(db, 10)
if err != nil {
t.Fatalf("Failed to get low MP spells: %v", err)
}
expectedCount := 6 // Heal(5), Hurt(5), Sleep(10), Craze(10), Revive(10), Ward(10)
if len(lowMPSpells) != expectedCount {
t.Errorf("Expected %d spells with MP <= 10, got %d", expectedCount, len(lowMPSpells))
}
// Verify all spells have MP <= 10
for _, spell := range lowMPSpells {
if spell.MP > 10 {
t.Errorf("Spell %s has MP %d, expected <= 10", spell.Name, spell.MP)
}
}
// Test very low MP threshold
veryLowMPSpells, err := ByMaxMP(db, 5)
if err != nil {
t.Fatalf("Failed to get very low MP spells: %v", err)
}
if len(veryLowMPSpells) != 2 { // Only Heal and Hurt
t.Errorf("Expected 2 spells with MP <= 5, got %d", len(veryLowMPSpells))
}
}
func TestByTypeAndMaxMP(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
// Test healing spells with MP <= 10
healingSpells, err := ByTypeAndMaxMP(db, TypeHealing, 10)
if err != nil {
t.Fatalf("Failed to get healing spells with MP <= 10: %v", err)
}
expectedCount := 2 // Heal(5) and Revive(10)
if len(healingSpells) != expectedCount {
t.Errorf("Expected %d healing spells with MP <= 10, got %d", expectedCount, len(healingSpells))
}
// Verify all are healing spells and within MP limit
for _, spell := range healingSpells {
if spell.Type != TypeHealing {
t.Errorf("Expected healing spell, got type %d", spell.Type)
}
if spell.MP > 10 {
t.Errorf("Spell %s has MP %d, expected <= 10", spell.Name, spell.MP)
}
}
// Test hurt spells with very low MP
lowHurtSpells, err := ByTypeAndMaxMP(db, TypeHurt, 5)
if err != nil {
t.Fatalf("Failed to get hurt spells with MP <= 5: %v", err)
}
if len(lowHurtSpells) != 1 { // Only Hurt(5)
t.Errorf("Expected 1 hurt spell with MP <= 5, got %d", len(lowHurtSpells))
}
}
func TestByName(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
// Test finding existing spell by name
spell, err := ByName(db, "Heal")
if err != nil {
t.Fatalf("Failed to find spell by name: %v", err)
}
if spell.Name != "Heal" {
t.Errorf("Expected name 'Heal', got '%s'", spell.Name)
}
if spell.Type != TypeHealing {
t.Errorf("Expected healing spell, got type %d", spell.Type)
}
// Test case insensitivity
spellLower, err := ByName(db, "heal")
if err != nil {
t.Fatalf("Failed to find spell by lowercase name: %v", err)
}
if spellLower.ID != spell.ID {
t.Error("Case insensitive search should return same spell")
}
// Test non-existent spell
_, err = ByName(db, "Fireball")
if err == nil {
t.Error("Expected error when finding non-existent spell by name")
}
}
func TestBuilder(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
// Create new spell using builder
spell, err := NewBuilder(db).
WithName("Lightning").
WithMP(25).
WithAttribute(60).
WithType(TypeHurt).
Create()
if err != nil {
t.Fatalf("Failed to create spell with builder: %v", err)
}
if spell.ID == 0 {
t.Error("Expected non-zero ID after creation")
}
if spell.Name != "Lightning" {
t.Errorf("Expected name 'Lightning', got '%s'", spell.Name)
}
if spell.MP != 25 {
t.Errorf("Expected MP 25, got %d", spell.MP)
}
if spell.Attribute != 60 {
t.Errorf("Expected attribute 60, got %d", spell.Attribute)
}
if spell.Type != TypeHurt {
t.Errorf("Expected type %d, got %d", TypeHurt, spell.Type)
}
// Verify it was saved to database
foundSpell, err := Find(db, spell.ID)
if err != nil {
t.Fatalf("Failed to find created spell: %v", err)
}
if foundSpell.Name != "Lightning" {
t.Errorf("Created spell not found in database")
}
}
func TestSave(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
spell, err := Find(db, 1)
if err != nil {
t.Fatalf("Failed to find spell: %v", err)
}
// Modify spell
spell.Name = "Enhanced Heal"
spell.MP = 7
spell.Attribute = 15
// Save changes
err = spell.Save()
if err != nil {
t.Fatalf("Failed to save spell: %v", err)
}
// Verify changes were saved
updatedSpell, err := Find(db, 1)
if err != nil {
t.Fatalf("Failed to find updated spell: %v", err)
}
if updatedSpell.Name != "Enhanced Heal" {
t.Errorf("Expected updated name 'Enhanced Heal', got '%s'", updatedSpell.Name)
}
if updatedSpell.MP != 7 {
t.Errorf("Expected updated MP 7, got %d", updatedSpell.MP)
}
if updatedSpell.Attribute != 15 {
t.Errorf("Expected updated attribute 15, got %d", updatedSpell.Attribute)
}
}
func TestDelete(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
spell, err := Find(db, 1)
if err != nil {
t.Fatalf("Failed to find spell: %v", err)
}
// Delete spell
err = spell.Delete()
if err != nil {
t.Fatalf("Failed to delete spell: %v", err)
}
// Verify spell was deleted
_, err = Find(db, 1)
if err == nil {
t.Error("Expected error when finding deleted spell")
}
}
func TestSpellTypeMethods(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
heal, _ := Find(db, 1) // Healing
hurt, _ := Find(db, 3) // Hurt
sleep, _ := Find(db, 5) // Sleep
craze, _ := Find(db, 7) // Attack boost
ward, _ := Find(db, 8) // Defense boost
// Test type checking methods
if !heal.IsHealing() {
t.Error("Expected Heal to be healing spell")
}
if heal.IsHurt() {
t.Error("Expected Heal not to be hurt spell")
}
if !hurt.IsHurt() {
t.Error("Expected Hurt to be hurt spell")
}
if hurt.IsHealing() {
t.Error("Expected Hurt not to be healing spell")
}
if !sleep.IsSleep() {
t.Error("Expected Sleep to be sleep spell")
}
if !craze.IsAttackBoost() {
t.Error("Expected Craze to be attack boost spell")
}
if !ward.IsDefenseBoost() {
t.Error("Expected Ward to be defense boost spell")
}
// Test TypeName
if heal.TypeName() != "Healing" {
t.Errorf("Expected Heal type name 'Healing', got '%s'", heal.TypeName())
}
if hurt.TypeName() != "Hurt" {
t.Errorf("Expected Hurt type name 'Hurt', got '%s'", hurt.TypeName())
}
if sleep.TypeName() != "Sleep" {
t.Errorf("Expected Sleep type name 'Sleep', got '%s'", sleep.TypeName())
}
if craze.TypeName() != "Attack Boost" {
t.Errorf("Expected Craze type name 'Attack Boost', got '%s'", craze.TypeName())
}
if ward.TypeName() != "Defense Boost" {
t.Errorf("Expected Ward type name 'Defense Boost', got '%s'", ward.TypeName())
}
}
func TestUtilityMethods(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
heal, _ := Find(db, 1) // MP: 5, Attribute: 10
hurt, _ := Find(db, 3) // MP: 5, Attribute: 15
sleep, _ := Find(db, 5) // MP: 10, Attribute: 5
// Test CanCast
if !heal.CanCast(10) {
t.Error("Expected to be able to cast Heal with 10 MP")
}
if heal.CanCast(3) {
t.Error("Expected not to be able to cast Heal with 3 MP")
}
// Test Efficiency
expectedHealEff := float64(10) / float64(5) // 2.0
if heal.Efficiency() != expectedHealEff {
t.Errorf("Expected Heal efficiency %.2f, got %.2f", expectedHealEff, heal.Efficiency())
}
expectedHurtEff := float64(15) / float64(5) // 3.0
if hurt.Efficiency() != expectedHurtEff {
t.Errorf("Expected Hurt efficiency %.2f, got %.2f", expectedHurtEff, hurt.Efficiency())
}
// Test IsOffensive
if heal.IsOffensive() {
t.Error("Expected Heal not to be offensive")
}
if !hurt.IsOffensive() {
t.Error("Expected Hurt to be offensive")
}
if !sleep.IsOffensive() {
t.Error("Expected Sleep to be offensive")
}
// Test IsSupport
if !heal.IsSupport() {
t.Error("Expected Heal to be support spell")
}
if hurt.IsSupport() {
t.Error("Expected Hurt not to be support spell")
}
}