package monsters import ( "os" "testing" "dk/internal/database" ) func setupTestDB(t *testing.T) *database.DB { testDB := "test_monsters.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 monsters table createTable := `CREATE TABLE monsters ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, max_hp INTEGER NOT NULL DEFAULT 0, max_dmg INTEGER NOT NULL DEFAULT 0, armor INTEGER NOT NULL DEFAULT 0, level INTEGER NOT NULL DEFAULT 0, max_exp INTEGER NOT NULL DEFAULT 0, max_gold INTEGER NOT NULL DEFAULT 0, immune INTEGER NOT NULL DEFAULT 0 )` if err := db.Exec(createTable); err != nil { t.Fatalf("Failed to create monsters table: %v", err) } // Insert test data testMonsters := `INSERT INTO monsters (name, max_hp, max_dmg, armor, level, max_exp, max_gold, immune) VALUES ('Blue Slime', 4, 3, 1, 1, 1, 1, 0), ('Red Slime', 6, 5, 1, 1, 2, 1, 0), ('Shadow', 10, 9, 3, 2, 6, 2, 1), ('Silver Slime', 15, 100, 200, 30, 15, 1000, 2), ('Raven', 16, 13, 5, 4, 18, 6, 0)` if err := db.Exec(testMonsters); err != nil { t.Fatalf("Failed to insert test monsters: %v", err) } return db } func TestFind(t *testing.T) { db := setupTestDB(t) defer db.Close() // Test finding existing monster monster, err := Find(db, 1) if err != nil { t.Fatalf("Failed to find monster: %v", err) } if monster.ID != 1 { t.Errorf("Expected ID 1, got %d", monster.ID) } if monster.Name != "Blue Slime" { t.Errorf("Expected name 'Blue Slime', got '%s'", monster.Name) } if monster.MaxHP != 4 { t.Errorf("Expected max_hp 4, got %d", monster.MaxHP) } if monster.MaxDmg != 3 { t.Errorf("Expected max_dmg 3, got %d", monster.MaxDmg) } if monster.Armor != 1 { t.Errorf("Expected armor 1, got %d", monster.Armor) } if monster.Level != 1 { t.Errorf("Expected level 1, got %d", monster.Level) } if monster.MaxExp != 1 { t.Errorf("Expected max_exp 1, got %d", monster.MaxExp) } if monster.MaxGold != 1 { t.Errorf("Expected max_gold 1, got %d", monster.MaxGold) } if monster.Immune != ImmuneNone { t.Errorf("Expected immune %d, got %d", ImmuneNone, monster.Immune) } // Test finding non-existent monster _, err = Find(db, 999) if err == nil { t.Error("Expected error when finding non-existent monster") } } func TestAll(t *testing.T) { db := setupTestDB(t) defer db.Close() monsters, err := All(db) if err != nil { t.Fatalf("Failed to get all monsters: %v", err) } if len(monsters) != 5 { t.Errorf("Expected 5 monsters, got %d", len(monsters)) } // Check first monster (should be ordered by level, then id) if monsters[0].Name != "Blue Slime" { t.Errorf("Expected first monster to be 'Blue Slime', got '%s'", monsters[0].Name) } } func TestByLevel(t *testing.T) { db := setupTestDB(t) defer db.Close() // Test level 1 monsters level1Monsters, err := ByLevel(db, 1) if err != nil { t.Fatalf("Failed to get level 1 monsters: %v", err) } if len(level1Monsters) != 2 { t.Errorf("Expected 2 level 1 monsters, got %d", len(level1Monsters)) } for _, monster := range level1Monsters { if monster.Level != 1 { t.Errorf("Expected level 1, got %d for monster %s", monster.Level, monster.Name) } } // Test level that doesn't exist noMonsters, err := ByLevel(db, 999) if err != nil { t.Fatalf("Failed to query non-existent level: %v", err) } if len(noMonsters) != 0 { t.Errorf("Expected 0 monsters at level 999, got %d", len(noMonsters)) } } func TestByLevelRange(t *testing.T) { db := setupTestDB(t) defer db.Close() // Test level range 1-2 monsters, err := ByLevelRange(db, 1, 2) if err != nil { t.Fatalf("Failed to get monsters by level range: %v", err) } if len(monsters) != 3 { t.Errorf("Expected 3 monsters in level range 1-2, got %d", len(monsters)) } // Verify all monsters are within range for _, monster := range monsters { if monster.Level < 1 || monster.Level > 2 { t.Errorf("Monster %s level %d is outside range 1-2", monster.Name, monster.Level) } } // Verify ordering (by level, then id) if monsters[0].Level > monsters[len(monsters)-1].Level { t.Error("Expected monsters to be ordered by level") } } func TestByImmunity(t *testing.T) { db := setupTestDB(t) defer db.Close() // Test Hurt immune monsters hurtImmune, err := ByImmunity(db, ImmuneHurt) if err != nil { t.Fatalf("Failed to get Hurt immune monsters: %v", err) } if len(hurtImmune) != 1 { t.Errorf("Expected 1 Hurt immune monster, got %d", len(hurtImmune)) } if len(hurtImmune) > 0 && hurtImmune[0].Name != "Shadow" { t.Errorf("Expected Hurt immune monster to be 'Shadow', got '%s'", hurtImmune[0].Name) } // Test Sleep immune monsters sleepImmune, err := ByImmunity(db, ImmuneSleep) if err != nil { t.Fatalf("Failed to get Sleep immune monsters: %v", err) } if len(sleepImmune) != 1 { t.Errorf("Expected 1 Sleep immune monster, got %d", len(sleepImmune)) } // Test no immunity monsters noImmunity, err := ByImmunity(db, ImmuneNone) if err != nil { t.Fatalf("Failed to get non-immune monsters: %v", err) } if len(noImmunity) != 3 { t.Errorf("Expected 3 non-immune monsters, got %d", len(noImmunity)) } } func TestBuilder(t *testing.T) { db := setupTestDB(t) defer db.Close() // Create new monster using builder monster, err := NewBuilder(db). WithName("Test Dragon"). WithMaxHP(100). WithMaxDmg(25). WithArmor(10). WithLevel(15). WithMaxExp(500). WithMaxGold(100). WithImmunity(ImmuneHurt). Create() if err != nil { t.Fatalf("Failed to create monster with builder: %v", err) } if monster.ID == 0 { t.Error("Expected non-zero ID after creation") } if monster.Name != "Test Dragon" { t.Errorf("Expected name 'Test Dragon', got '%s'", monster.Name) } if monster.MaxHP != 100 { t.Errorf("Expected max_hp 100, got %d", monster.MaxHP) } if monster.MaxDmg != 25 { t.Errorf("Expected max_dmg 25, got %d", monster.MaxDmg) } if monster.Armor != 10 { t.Errorf("Expected armor 10, got %d", monster.Armor) } if monster.Level != 15 { t.Errorf("Expected level 15, got %d", monster.Level) } if monster.MaxExp != 500 { t.Errorf("Expected max_exp 500, got %d", monster.MaxExp) } if monster.MaxGold != 100 { t.Errorf("Expected max_gold 100, got %d", monster.MaxGold) } if monster.Immune != ImmuneHurt { t.Errorf("Expected immune %d, got %d", ImmuneHurt, monster.Immune) } // Verify it was saved to database foundMonster, err := Find(db, monster.ID) if err != nil { t.Fatalf("Failed to find created monster: %v", err) } if foundMonster.Name != "Test Dragon" { t.Errorf("Created monster not found in database") } } func TestSave(t *testing.T) { db := setupTestDB(t) defer db.Close() monster, err := Find(db, 1) if err != nil { t.Fatalf("Failed to find monster: %v", err) } // Modify monster monster.Name = "Updated Blue Slime" monster.MaxHP = 8 monster.Level = 2 // Save changes err = monster.Save() if err != nil { t.Fatalf("Failed to save monster: %v", err) } // Verify changes were saved updatedMonster, err := Find(db, 1) if err != nil { t.Fatalf("Failed to find updated monster: %v", err) } if updatedMonster.Name != "Updated Blue Slime" { t.Errorf("Expected updated name 'Updated Blue Slime', got '%s'", updatedMonster.Name) } if updatedMonster.MaxHP != 8 { t.Errorf("Expected updated max_hp 8, got %d", updatedMonster.MaxHP) } if updatedMonster.Level != 2 { t.Errorf("Expected updated level 2, got %d", updatedMonster.Level) } } func TestDelete(t *testing.T) { db := setupTestDB(t) defer db.Close() monster, err := Find(db, 1) if err != nil { t.Fatalf("Failed to find monster: %v", err) } // Delete monster err = monster.Delete() if err != nil { t.Fatalf("Failed to delete monster: %v", err) } // Verify monster was deleted _, err = Find(db, 1) if err == nil { t.Error("Expected error when finding deleted monster") } } func TestImmunityMethods(t *testing.T) { db := setupTestDB(t) defer db.Close() blueSlime, _ := Find(db, 1) // No immunity shadow, _ := Find(db, 3) // Hurt immune silverSlime, _ := Find(db, 4) // Sleep immune // Test IsHurtImmune if blueSlime.IsHurtImmune() { t.Error("Expected blue slime not to be Hurt immune") } if !shadow.IsHurtImmune() { t.Error("Expected shadow to be Hurt immune") } if silverSlime.IsHurtImmune() { t.Error("Expected silver slime not to be Hurt immune") } // Test IsSleepImmune if blueSlime.IsSleepImmune() { t.Error("Expected blue slime not to be Sleep immune") } if shadow.IsSleepImmune() { t.Error("Expected shadow not to be Sleep immune") } if !silverSlime.IsSleepImmune() { t.Error("Expected silver slime to be Sleep immune") } // Test HasImmunity if blueSlime.HasImmunity() { t.Error("Expected blue slime to have no immunity") } if !shadow.HasImmunity() { t.Error("Expected shadow to have immunity") } if !silverSlime.HasImmunity() { t.Error("Expected silver slime to have immunity") } // Test ImmunityName if blueSlime.ImmunityName() != "None" { t.Errorf("Expected blue slime immunity name 'None', got '%s'", blueSlime.ImmunityName()) } if shadow.ImmunityName() != "Hurt Spells" { t.Errorf("Expected shadow immunity name 'Hurt Spells', got '%s'", shadow.ImmunityName()) } if silverSlime.ImmunityName() != "Sleep Spells" { t.Errorf("Expected silver slime immunity name 'Sleep Spells', got '%s'", silverSlime.ImmunityName()) } } func TestUtilityMethods(t *testing.T) { db := setupTestDB(t) defer db.Close() blueSlime, _ := Find(db, 1) // Test DifficultyRating expectedDifficulty := float64(4+3+1) / float64(1) // (HP + Damage + Armor) / Level if blueSlime.DifficultyRating() != expectedDifficulty { t.Errorf("Expected difficulty rating %.2f, got %.2f", expectedDifficulty, blueSlime.DifficultyRating()) } // Test ExpPerHP expectedExpPerHP := float64(1) / float64(4) // Exp / HP if blueSlime.ExpPerHP() != expectedExpPerHP { t.Errorf("Expected exp per HP %.2f, got %.2f", expectedExpPerHP, blueSlime.ExpPerHP()) } // Test GoldPerHP expectedGoldPerHP := float64(1) / float64(4) // Gold / HP if blueSlime.GoldPerHP() != expectedGoldPerHP { t.Errorf("Expected gold per HP %.2f, got %.2f", expectedGoldPerHP, blueSlime.GoldPerHP()) } }