440 lines
11 KiB
Go
440 lines
11 KiB
Go
package towns
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
|
|
"dk/internal/database"
|
|
)
|
|
|
|
func setupTestDB(t *testing.T) *database.DB {
|
|
testDB := "test_towns.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 towns table
|
|
createTable := `CREATE TABLE towns (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL,
|
|
x INTEGER NOT NULL DEFAULT 0,
|
|
y INTEGER NOT NULL DEFAULT 0,
|
|
inn_cost INTEGER NOT NULL DEFAULT 0,
|
|
map_cost INTEGER NOT NULL DEFAULT 0,
|
|
tp_cost INTEGER NOT NULL DEFAULT 0,
|
|
shop_list TEXT NOT NULL DEFAULT ''
|
|
)`
|
|
|
|
if err := db.Exec(createTable); err != nil {
|
|
t.Fatalf("Failed to create towns table: %v", err)
|
|
}
|
|
|
|
// Insert test data
|
|
testTowns := `INSERT INTO towns (name, x, y, inn_cost, map_cost, tp_cost, shop_list) VALUES
|
|
('Midworld', 0, 0, 5, 0, 0, '1,2,3,17,18,19'),
|
|
('Roma', 30, 30, 10, 25, 5, '2,3,4,18,19,29'),
|
|
('Bris', 70, -70, 25, 50, 15, '2,3,4,5,18,19,20'),
|
|
('Kalle', -100, 100, 40, 100, 30, '5,6,8,10,12,21,22,23'),
|
|
('Endworld', -250, -250, 125, 9000, 160, '16,27,33')`
|
|
|
|
if err := db.Exec(testTowns); err != nil {
|
|
t.Fatalf("Failed to insert test towns: %v", err)
|
|
}
|
|
|
|
return db
|
|
}
|
|
|
|
func TestFind(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test finding existing town
|
|
town, err := Find(db, 1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find town: %v", err)
|
|
}
|
|
|
|
if town.ID != 1 {
|
|
t.Errorf("Expected ID 1, got %d", town.ID)
|
|
}
|
|
if town.Name != "Midworld" {
|
|
t.Errorf("Expected name 'Midworld', got '%s'", town.Name)
|
|
}
|
|
if town.X != 0 {
|
|
t.Errorf("Expected X 0, got %d", town.X)
|
|
}
|
|
if town.Y != 0 {
|
|
t.Errorf("Expected Y 0, got %d", town.Y)
|
|
}
|
|
if town.InnCost != 5 {
|
|
t.Errorf("Expected inn_cost 5, got %d", town.InnCost)
|
|
}
|
|
if town.MapCost != 0 {
|
|
t.Errorf("Expected map_cost 0, got %d", town.MapCost)
|
|
}
|
|
if town.TPCost != 0 {
|
|
t.Errorf("Expected tp_cost 0, got %d", town.TPCost)
|
|
}
|
|
if town.ShopList != "1,2,3,17,18,19" {
|
|
t.Errorf("Expected shop_list '1,2,3,17,18,19', got '%s'", town.ShopList)
|
|
}
|
|
|
|
// Test finding non-existent town
|
|
_, err = Find(db, 999)
|
|
if err == nil {
|
|
t.Error("Expected error when finding non-existent town")
|
|
}
|
|
}
|
|
|
|
func TestAll(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
towns, err := All(db)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get all towns: %v", err)
|
|
}
|
|
|
|
if len(towns) != 5 {
|
|
t.Errorf("Expected 5 towns, got %d", len(towns))
|
|
}
|
|
|
|
// Check ordering (by ID)
|
|
if towns[0].Name != "Midworld" {
|
|
t.Errorf("Expected first town to be 'Midworld', got '%s'", towns[0].Name)
|
|
}
|
|
}
|
|
|
|
func TestByName(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test finding existing town by name
|
|
town, err := ByName(db, "Midworld")
|
|
if err != nil {
|
|
t.Fatalf("Failed to find town by name: %v", err)
|
|
}
|
|
|
|
if town.Name != "Midworld" {
|
|
t.Errorf("Expected name 'Midworld', got '%s'", town.Name)
|
|
}
|
|
if town.X != 0 || town.Y != 0 {
|
|
t.Errorf("Expected coordinates (0,0), got (%d,%d)", town.X, town.Y)
|
|
}
|
|
|
|
// Test case insensitivity
|
|
townLower, err := ByName(db, "midworld")
|
|
if err != nil {
|
|
t.Fatalf("Failed to find town by lowercase name: %v", err)
|
|
}
|
|
|
|
if townLower.ID != town.ID {
|
|
t.Error("Case insensitive search should return same town")
|
|
}
|
|
|
|
// Test non-existent town
|
|
_, err = ByName(db, "Atlantis")
|
|
if err == nil {
|
|
t.Error("Expected error when finding non-existent town by name")
|
|
}
|
|
}
|
|
|
|
func TestByMaxInnCost(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test towns with inn cost <= 10
|
|
cheapInns, err := ByMaxInnCost(db, 10)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get towns by max inn cost: %v", err)
|
|
}
|
|
|
|
expectedCount := 2 // Midworld(5) and Roma(10)
|
|
if len(cheapInns) != expectedCount {
|
|
t.Errorf("Expected %d towns with inn cost <= 10, got %d", expectedCount, len(cheapInns))
|
|
}
|
|
|
|
// Verify all towns have inn cost <= 10
|
|
for _, town := range cheapInns {
|
|
if town.InnCost > 10 {
|
|
t.Errorf("Town %s has inn cost %d, expected <= 10", town.Name, town.InnCost)
|
|
}
|
|
}
|
|
|
|
// Verify ordering (by inn cost, then ID)
|
|
if cheapInns[0].InnCost > cheapInns[1].InnCost {
|
|
t.Error("Expected towns to be ordered by inn cost")
|
|
}
|
|
}
|
|
|
|
func TestByMaxTPCost(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test towns with TP cost <= 15
|
|
cheapTP, err := ByMaxTPCost(db, 15)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get towns by max TP cost: %v", err)
|
|
}
|
|
|
|
expectedCount := 3 // Midworld(0), Roma(5), Bris(15)
|
|
if len(cheapTP) != expectedCount {
|
|
t.Errorf("Expected %d towns with TP cost <= 15, got %d", expectedCount, len(cheapTP))
|
|
}
|
|
|
|
// Verify all towns have TP cost <= 15
|
|
for _, town := range cheapTP {
|
|
if town.TPCost > 15 {
|
|
t.Errorf("Town %s has TP cost %d, expected <= 15", town.Name, town.TPCost)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestByDistance(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Test towns within distance 50 from origin (0,0)
|
|
nearbyTowns, err := ByDistance(db, 0, 0, 50)
|
|
if err != nil {
|
|
t.Fatalf("Failed to get towns by distance: %v", err)
|
|
}
|
|
|
|
// Midworld (0,0) distance=0, Roma (30,30) distance=sqrt(1800)≈42.4
|
|
expectedCount := 2
|
|
if len(nearbyTowns) != expectedCount {
|
|
t.Errorf("Expected %d towns within distance 50, got %d", expectedCount, len(nearbyTowns))
|
|
}
|
|
|
|
// Verify distances are within limit
|
|
for _, town := range nearbyTowns {
|
|
distance := town.DistanceFrom(0, 0)
|
|
if distance > 50*50 { // Using squared distance
|
|
t.Errorf("Town %s distance %.2f is beyond limit", town.Name, distance)
|
|
}
|
|
}
|
|
|
|
// Verify ordering (by distance)
|
|
if len(nearbyTowns) >= 2 {
|
|
dist1 := nearbyTowns[0].DistanceFrom(0, 0)
|
|
dist2 := nearbyTowns[1].DistanceFrom(0, 0)
|
|
if dist1 > dist2 {
|
|
t.Error("Expected towns to be ordered by distance")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestBuilder(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
// Create new town using builder
|
|
town, err := NewBuilder(db).
|
|
WithName("Test City").
|
|
WithCoordinates(100, -50).
|
|
WithInnCost(20).
|
|
WithMapCost(75).
|
|
WithTPCost(25).
|
|
WithShopItems([]string{"1", "2", "10", "15"}).
|
|
Create()
|
|
|
|
if err != nil {
|
|
t.Fatalf("Failed to create town with builder: %v", err)
|
|
}
|
|
|
|
if town.ID == 0 {
|
|
t.Error("Expected non-zero ID after creation")
|
|
}
|
|
if town.Name != "Test City" {
|
|
t.Errorf("Expected name 'Test City', got '%s'", town.Name)
|
|
}
|
|
if town.X != 100 {
|
|
t.Errorf("Expected X 100, got %d", town.X)
|
|
}
|
|
if town.Y != -50 {
|
|
t.Errorf("Expected Y -50, got %d", town.Y)
|
|
}
|
|
if town.InnCost != 20 {
|
|
t.Errorf("Expected inn cost 20, got %d", town.InnCost)
|
|
}
|
|
if town.MapCost != 75 {
|
|
t.Errorf("Expected map cost 75, got %d", town.MapCost)
|
|
}
|
|
if town.TPCost != 25 {
|
|
t.Errorf("Expected TP cost 25, got %d", town.TPCost)
|
|
}
|
|
if town.ShopList != "1,2,10,15" {
|
|
t.Errorf("Expected shop list '1,2,10,15', got '%s'", town.ShopList)
|
|
}
|
|
|
|
// Verify it was saved to database
|
|
foundTown, err := Find(db, town.ID)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find created town: %v", err)
|
|
}
|
|
|
|
if foundTown.Name != "Test City" {
|
|
t.Errorf("Created town not found in database")
|
|
}
|
|
}
|
|
|
|
func TestSave(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
town, err := Find(db, 1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find town: %v", err)
|
|
}
|
|
|
|
// Modify town
|
|
town.Name = "Updated Midworld"
|
|
town.X = 5
|
|
town.Y = -5
|
|
town.InnCost = 8
|
|
|
|
// Save changes
|
|
err = town.Save()
|
|
if err != nil {
|
|
t.Fatalf("Failed to save town: %v", err)
|
|
}
|
|
|
|
// Verify changes were saved
|
|
updatedTown, err := Find(db, 1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find updated town: %v", err)
|
|
}
|
|
|
|
if updatedTown.Name != "Updated Midworld" {
|
|
t.Errorf("Expected updated name 'Updated Midworld', got '%s'", updatedTown.Name)
|
|
}
|
|
if updatedTown.X != 5 {
|
|
t.Errorf("Expected updated X 5, got %d", updatedTown.X)
|
|
}
|
|
if updatedTown.Y != -5 {
|
|
t.Errorf("Expected updated Y -5, got %d", updatedTown.Y)
|
|
}
|
|
if updatedTown.InnCost != 8 {
|
|
t.Errorf("Expected updated inn cost 8, got %d", updatedTown.InnCost)
|
|
}
|
|
}
|
|
|
|
func TestDelete(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
town, err := Find(db, 1)
|
|
if err != nil {
|
|
t.Fatalf("Failed to find town: %v", err)
|
|
}
|
|
|
|
// Delete town
|
|
err = town.Delete()
|
|
if err != nil {
|
|
t.Fatalf("Failed to delete town: %v", err)
|
|
}
|
|
|
|
// Verify town was deleted
|
|
_, err = Find(db, 1)
|
|
if err == nil {
|
|
t.Error("Expected error when finding deleted town")
|
|
}
|
|
}
|
|
|
|
func TestShopItemMethods(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
town, _ := Find(db, 1) // Midworld with shop_list "1,2,3,17,18,19"
|
|
|
|
// Test GetShopItems
|
|
items := town.GetShopItems()
|
|
expectedItems := []string{"1", "2", "3", "17", "18", "19"}
|
|
if len(items) != len(expectedItems) {
|
|
t.Errorf("Expected %d shop items, got %d", len(expectedItems), len(items))
|
|
}
|
|
|
|
for i, expected := range expectedItems {
|
|
if i < len(items) && items[i] != expected {
|
|
t.Errorf("Expected item %s at position %d, got %s", expected, i, items[i])
|
|
}
|
|
}
|
|
|
|
// Test HasShopItem
|
|
if !town.HasShopItem("1") {
|
|
t.Error("Expected town to have shop item '1'")
|
|
}
|
|
if !town.HasShopItem("19") {
|
|
t.Error("Expected town to have shop item '19'")
|
|
}
|
|
if town.HasShopItem("99") {
|
|
t.Error("Expected town not to have shop item '99'")
|
|
}
|
|
|
|
// Test SetShopItems
|
|
newItems := []string{"5", "10", "15"}
|
|
town.SetShopItems(newItems)
|
|
if town.ShopList != "5,10,15" {
|
|
t.Errorf("Expected shop list '5,10,15', got '%s'", town.ShopList)
|
|
}
|
|
|
|
// Test with empty shop list
|
|
emptyTown, _ := Find(db, 5) // Create a town with empty shop list
|
|
emptyTown.ShopList = ""
|
|
emptyItems := emptyTown.GetShopItems()
|
|
if len(emptyItems) != 0 {
|
|
t.Errorf("Expected 0 items for empty shop list, got %d", len(emptyItems))
|
|
}
|
|
}
|
|
|
|
func TestUtilityMethods(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
defer db.Close()
|
|
|
|
midworld, _ := Find(db, 1)
|
|
roma, _ := Find(db, 2)
|
|
|
|
// Test DistanceFrom
|
|
distance := roma.DistanceFrom(0, 0) // Roma is at (30,30)
|
|
expectedDistance := float64(30*30 + 30*30) // 1800
|
|
if distance != expectedDistance {
|
|
t.Errorf("Expected distance %.2f, got %.2f", expectedDistance, distance)
|
|
}
|
|
|
|
// Test IsStartingTown
|
|
if !midworld.IsStartingTown() {
|
|
t.Error("Expected Midworld to be starting town")
|
|
}
|
|
if roma.IsStartingTown() {
|
|
t.Error("Expected Roma not to be starting town")
|
|
}
|
|
|
|
// Test CanAffordInn
|
|
if !midworld.CanAffordInn(10) {
|
|
t.Error("Expected to afford Midworld inn with 10 gold (cost 5)")
|
|
}
|
|
if midworld.CanAffordInn(3) {
|
|
t.Error("Expected not to afford Midworld inn with 3 gold (cost 5)")
|
|
}
|
|
|
|
// Test CanAffordMap
|
|
if !roma.CanAffordMap(30) {
|
|
t.Error("Expected to afford Roma map with 30 gold (cost 25)")
|
|
}
|
|
if roma.CanAffordMap(20) {
|
|
t.Error("Expected not to afford Roma map with 20 gold (cost 25)")
|
|
}
|
|
|
|
// Test CanAffordTeleport
|
|
if !roma.CanAffordTeleport(10) {
|
|
t.Error("Expected to afford Roma teleport with 10 gold (cost 5)")
|
|
}
|
|
if roma.CanAffordTeleport(3) {
|
|
t.Error("Expected not to afford Roma teleport with 3 gold (cost 5)")
|
|
}
|
|
} |