package factions import ( "testing" ) func TestNewFaction(t *testing.T) { faction := NewFaction(1, "Test Faction", "TestType", "A test faction") if faction == nil { t.Fatal("NewFaction returned nil") } if faction.ID != 1 { t.Errorf("Expected ID 1, got %d", faction.ID) } if faction.Name != "Test Faction" { t.Errorf("Expected name 'Test Faction', got '%s'", faction.Name) } if faction.Type != "TestType" { t.Errorf("Expected type 'TestType', got '%s'", faction.Type) } if faction.Description != "A test faction" { t.Errorf("Expected description 'A test faction', got '%s'", faction.Description) } } func TestMasterFactionList(t *testing.T) { mfl := NewMasterList() if mfl == nil { t.Fatal("NewMasterFactionList returned nil") } // Test adding faction faction := NewFaction(100, "Test Faction", "Test", "Test faction") err := mfl.AddFaction(faction) if err != nil { t.Fatalf("Failed to add faction: %v", err) } // Test getting faction retrieved := mfl.GetFaction(100) if retrieved == nil { t.Error("Failed to retrieve added faction") } else if retrieved.Name != "Test Faction" { t.Errorf("Expected name 'Test Faction', got '%s'", retrieved.Name) } // Test getting all factions factions := mfl.GetAllFactions() if len(factions) == 0 { t.Error("Expected at least one faction") } } func TestPlayerFaction(t *testing.T) { mfl := NewMasterList() pf := NewPlayerFaction(mfl) if pf == nil { t.Fatal("NewPlayerFaction returned nil") } // Use faction ID > 10 since IDs <= 10 are special factions that always return 0 testFactionID := int32(100) // Test setting faction value pf.SetFactionValue(testFactionID, 1000) value := pf.GetFactionValue(testFactionID) if value != 1000 { t.Errorf("Expected faction value 1000, got %d", value) } // Test faction modification pf.IncreaseFaction(testFactionID, 500) value = pf.GetFactionValue(testFactionID) if value != 1500 { t.Errorf("Expected faction value 1500 after increase, got %d", value) } pf.DecreaseFaction(testFactionID, 200) value = pf.GetFactionValue(testFactionID) if value != 1300 { t.Errorf("Expected faction value 1300 after decrease, got %d", value) } // Test consideration calculation consideration := pf.GetCon(testFactionID) if consideration < -4 || consideration > 4 { t.Errorf("Consideration %d is out of valid range [-4, 4]", consideration) } } func TestFactionRelations(t *testing.T) { mfl := NewMasterList() // Add test factions faction1 := NewFaction(1, "Faction 1", "Test", "Test faction 1") faction2 := NewFaction(2, "Faction 2", "Test", "Test faction 2") faction3 := NewFaction(3, "Faction 3", "Test", "Test faction 3") mfl.AddFaction(faction1) mfl.AddFaction(faction2) mfl.AddFaction(faction3) // Test hostile relations mfl.AddHostileFaction(1, 2) // Check if faction 2 is in the hostile list for faction 1 hostiles := mfl.GetHostileFactions(1) isHostile := false for _, hostileID := range hostiles { if hostileID == 2 { isHostile = true break } } if !isHostile { t.Error("Expected faction 2 to be hostile to faction 1") } // Test friendly relations mfl.AddFriendlyFaction(1, 3) // Check if faction 3 is in the friendly list for faction 1 friendlies := mfl.GetFriendlyFactions(1) isFriendly := false for _, friendlyID := range friendlies { if friendlyID == 3 { isFriendly = true break } } if !isFriendly { t.Error("Expected faction 3 to be friendly to faction 1") } // Test removing relations - need to implement RemoveHostileFaction first // For now, just verify current state hostiles = mfl.GetHostileFactions(1) isHostile = false for _, hostileID := range hostiles { if hostileID == 2 { isHostile = true break } } if !isHostile { t.Error("Expected faction 2 to still be hostile to faction 1 (removal not implemented)") } } func TestFactionValidation(t *testing.T) { mfl := NewMasterList() // Test nil faction err := mfl.AddFaction(nil) if err == nil { t.Error("Expected error when adding nil faction") } // Test invalid faction ID faction := NewFaction(0, "Invalid", "Test", "Invalid faction") err = mfl.AddFaction(faction) if err == nil { t.Error("Expected error when adding faction with ID 0") } // Test empty name faction = NewFaction(1, "", "Test", "Empty name faction") err = mfl.AddFaction(faction) if err == nil { t.Error("Expected error when adding faction with empty name") } } func TestMasterListBespokeFeatures(t *testing.T) { mfl := NewMasterList() // Create test factions with different properties faction1 := NewFaction(1, "Special Faction", "Special", "A special faction") faction2 := NewFaction(20, "City Faction", "City", "A city faction") faction3 := NewFaction(21, "Guild Faction", "Guild", "A guild faction") faction4 := NewFaction(30, "Another City", "City", "Another city faction") // Add factions mfl.AddFaction(faction1) mfl.AddFaction(faction2) mfl.AddFaction(faction3) mfl.AddFaction(faction4) // Test GetFactionSafe retrieved, exists := mfl.GetFactionSafe(20) if !exists || retrieved == nil { t.Error("GetFactionSafe should return existing faction and true") } _, exists = mfl.GetFactionSafe(9999) if exists { t.Error("GetFactionSafe should return false for non-existent ID") } // Test GetFactionByName (case-insensitive) found := mfl.GetFactionByName("city faction") if found == nil || found.ID != 20 { t.Error("GetFactionByName should find 'City Faction' (case insensitive)") } found = mfl.GetFactionByName("GUILD FACTION") if found == nil || found.ID != 21 { t.Error("GetFactionByName should find 'Guild Faction' (uppercase)") } found = mfl.GetFactionByName("NonExistent") if found != nil { t.Error("GetFactionByName should return nil for non-existent faction") } // Test GetFactionsByType cityFactions := mfl.GetFactionsByType("City") if len(cityFactions) != 2 { t.Errorf("GetFactionsByType('City') returned %v results, want 2", len(cityFactions)) } guildFactions := mfl.GetFactionsByType("Guild") if len(guildFactions) != 1 { t.Errorf("GetFactionsByType('Guild') returned %v results, want 1", len(guildFactions)) } // Test GetSpecialFactions and GetRegularFactions specialFactions := mfl.GetSpecialFactions() if len(specialFactions) != 1 { t.Errorf("GetSpecialFactions() returned %v results, want 1", len(specialFactions)) } regularFactions := mfl.GetRegularFactions() if len(regularFactions) != 3 { t.Errorf("GetRegularFactions() returned %v results, want 3", len(regularFactions)) } // Test GetTypes types := mfl.GetTypes() if len(types) < 3 { t.Errorf("GetTypes() returned %v types, want at least 3", len(types)) } // Verify types contains expected values typeMap := make(map[string]bool) for _, factionType := range types { typeMap[factionType] = true } if !typeMap["Special"] || !typeMap["City"] || !typeMap["Guild"] { t.Error("GetTypes() should contain 'Special', 'City', and 'Guild'") } // Test UpdateFaction updatedFaction := &Faction{ ID: 20, Name: "Updated City Faction", Type: "UpdatedCity", Description: "An updated city faction", } err := mfl.UpdateFaction(updatedFaction) if err != nil { t.Errorf("UpdateFaction failed: %v", err) } // Verify the update worked retrieved = mfl.GetFaction(20) if retrieved.Name != "Updated City Faction" { t.Errorf("Expected updated name 'Updated City Faction', got '%s'", retrieved.Name) } if retrieved.Type != "UpdatedCity" { t.Errorf("Expected updated type 'UpdatedCity', got '%s'", retrieved.Type) } // Test updating non-existent faction nonExistentFaction := &Faction{ID: 9999, Name: "Non-existent"} err = mfl.UpdateFaction(nonExistentFaction) if err == nil { t.Error("UpdateFaction should fail for non-existent faction") } // Test GetAllFactionsList allList := mfl.GetAllFactionsList() if len(allList) != 4 { t.Errorf("GetAllFactionsList() returned %v factions, want 4", len(allList)) } // Test GetFactionIDs ids := mfl.GetFactionIDs() if len(ids) != 4 { t.Errorf("GetFactionIDs() returned %v IDs, want 4", len(ids)) } } func TestMasterListConcurrency(t *testing.T) { mfl := NewMasterList() // Add initial factions for i := 1; i <= 50; i++ { faction := NewFaction(int32(i+100), "Faction", "Test", "Test faction") mfl.AddFaction(faction) } // Test concurrent access done := make(chan bool, 10) // Concurrent readers for i := 0; i < 5; i++ { go func() { defer func() { done <- true }() for j := 0; j < 100; j++ { mfl.GetFaction(int32(j%50 + 101)) mfl.GetFactionsByType("Test") mfl.GetFactionByName("faction") mfl.HasFaction(int32(j%50 + 101)) } }() } // Concurrent writers for i := 0; i < 5; i++ { go func(workerID int) { defer func() { done <- true }() for j := 0; j < 10; j++ { factionID := int32(workerID*1000 + j + 1000) faction := NewFaction(factionID, "Worker Faction", "Worker", "Worker test faction") mfl.AddFaction(faction) // Some may fail due to concurrent additions } }(i) } // Wait for all goroutines for i := 0; i < 10; i++ { <-done } // Verify final state - should have at least 50 initial factions finalCount := mfl.GetFactionCount() if finalCount < 50 { t.Errorf("Expected at least 50 factions after concurrent operations, got %d", finalCount) } if finalCount > 100 { t.Errorf("Expected at most 100 factions after concurrent operations, got %d", finalCount) } }