445 lines
10 KiB
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")
|
|
}
|
|
} |