Files
Ajedrez_Purgatorio/Assets/Tests/EditMode/Meta/DeadKingPoolTests.cs
T
jimmyabv f7d56066c0 feat: Purgatory Final duel vs La Muerte + SFX wiring + runtime options menu
- Duel flow: mating piece vs boss while board collapses (PurgatoryDuelManager/Rules/UI/MuerteQuotes)
- GameState.PurgatoryDuel + CampaignManager rescue/restart hooks + SquareClick routing
- Dice-based rescue of most valuable dead identity; final defeat restarts Chapter 1
- 6 SFX clips wired in Ch1/2/3 via AudioClipAssigner
- OptionsMenuController runtime audio/graphics panel, wired to MainMenu
- Tests migrated to Assets/Tests/EditMode subfolders + PurgatoryDuelRulesTests (200 total)
- Editor tools: DiagAssign, SpeakerDatabaseSetup, PurgatoryCanvasMaintenance
2026-08-24 19:39:52 -03:00

358 lines
12 KiB
C#

using NUnit.Framework;
using UnityEngine;
using AjedrezPurgatorio.Meta;
using AjedrezPurgatorio.Data;
using System.IO;
using System.Collections.Generic;
namespace AjedrezPurgatorio.Tests.Unit.Meta
{
/// <summary>
/// Unit tests for the DeadKingPool system.
/// Tests: AddDeadKing, GetRandomDeadKing, ShouldSpawnDeadKing,
/// FIFO rotation, content filtering, persistence.
/// </summary>
[TestFixture]
public class DeadKingPoolTests
{
private DeadKingPool _pool;
private string _testFilePath;
[SetUp]
public void Setup()
{
// Create a test instance of DeadKingPool
_pool = ScriptableObject.CreateInstance<DeadKingPool>();
// Mock persistent file path for testing
_testFilePath = Path.Combine(Application.temporaryCachePath, "test_dead_kings.json");
// Clear any existing test file
if (File.Exists(_testFilePath))
File.Delete(_testFilePath);
// Redirigir la ruta persistente al archivo de prueba: sin esto el pool
// cargaría el dead_kings.json real del jugador y los tests no serían
// deterministas.
SetPersistentPath(_pool, _testFilePath);
// Initialize the pool (will load from empty state)
_pool.Reinitialize();
}
[TearDown]
public void Teardown()
{
// Clean up test file
if (File.Exists(_testFilePath))
File.Delete(_testFilePath);
// Destroy test pool instance
if (_pool != null)
Object.DestroyImmediate(_pool);
}
private static void SetPersistentPath(DeadKingPool pool, string path)
{
var field = typeof(DeadKingPool).GetField("_persistentFilePath",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
Assert.IsNotNull(field, "_persistentFilePath no encontrado en DeadKingPool.");
field.SetValue(pool, path);
}
#region AddDeadKing Tests
[Test]
public void AddDeadKing_AddsToPool()
{
// Arrange
var testDK = CreateTestDeadKing("TestPlayer", "Test message", 1, 3);
// Act
_pool.AddDeadKing(testDK);
// Assert
Assert.AreEqual(1, _pool.Count, "Pool should contain 1 Dead King after adding");
}
[Test]
public void AddDeadKing_WithNullData_LogsErrorAndDoesNotAdd()
{
// Assert (log esperado antes del Act)
UnityEngine.TestTools.LogAssert.Expect(LogType.Error, "[DeadKingPool] Cannot add null Dead King data.");
// Act
_pool.AddDeadKing(null);
// Assert
Assert.AreEqual(0, _pool.Count, "Pool should remain empty when adding null data");
}
[Test]
public void AddDeadKing_WithEmptyName_UsesAnonimo()
{
// Arrange
var testDK = CreateTestDeadKing("", "Test message", 1, 3);
// Act
_pool.AddDeadKing(testDK);
var retrieved = _pool.GetRandomDeadKing();
// Assert
Assert.AreEqual("Anónimo", retrieved.playerName, "Empty name should default to 'Anónimo'");
}
[Test]
public void AddDeadKing_FiltersProfanity_InName()
{
// Arrange
var testDK = CreateTestDeadKing("TestFuckPlayer", "Clean message", 1, 3);
// Act
_pool.AddDeadKing(testDK);
var retrieved = _pool.GetRandomDeadKing();
// Assert
Assert.IsTrue(retrieved.playerName.Contains("***"), "Profanity in name should be filtered");
Assert.IsFalse(retrieved.playerName.Contains("Fuck"), "Original profanity should not appear");
}
[Test]
public void AddDeadKing_FiltersProfanity_InMessage()
{
// Arrange
var testDK = CreateTestDeadKing("TestPlayer", "This shit is hard", 1, 3);
// Act
_pool.AddDeadKing(testDK);
var retrieved = _pool.GetRandomDeadKing();
// Assert
Assert.IsTrue(retrieved.message.Contains("***"), "Profanity in message should be filtered");
Assert.IsFalse(retrieved.message.Contains("shit"), "Original profanity should not appear");
}
#endregion
#region FIFO Rotation Tests
[Test]
public void AddDeadKing_WhenPoolFull_RemovesOldest()
{
// Arrange: Fill pool to max capacity (assuming max is 100)
// For testing, we'll use reflection to set a smaller max size or add many DKs
// Simplified: Add 101 DKs and verify the first one is removed
// Add 100 DKs
for (int i = 0; i < 100; i++)
{
var dk = CreateTestDeadKing($"Player{i}", $"Message {i}", 0, i);
_pool.AddDeadKing(dk);
}
Assert.AreEqual(100, _pool.Count, "Pool should be at max capacity (100)");
// Act: Add one more (should trigger FIFO removal)
var newDK = CreateTestDeadKing("NewPlayer", "New message", 2, 5);
_pool.AddDeadKing(newDK);
// Assert
Assert.AreEqual(100, _pool.Count, "Pool should still be at max capacity after FIFO");
// Verify the new DK is in the pool
var allDKs = _pool.GetAllDeadKings();
bool containsNew = allDKs.Exists(dk => dk.playerName == "NewPlayer");
Assert.IsTrue(containsNew, "Newly added DK should be in the pool");
}
#endregion
#region GetRandomDeadKing Tests
[Test]
public void GetRandomDeadKing_WhenPoolEmpty_ReturnsNull()
{
// Act
var result = _pool.GetRandomDeadKing();
// Assert
Assert.IsNull(result, "Should return null when pool is empty");
}
[Test]
public void GetRandomDeadKing_WhenPoolHasOne_ReturnsThatOne()
{
// Arrange
var testDK = CreateTestDeadKing("OnlyPlayer", "Only message", 1, 3);
_pool.AddDeadKing(testDK);
// Act
var result = _pool.GetRandomDeadKing();
// Assert
Assert.IsNotNull(result, "Should return a Dead King");
Assert.AreEqual("OnlyPlayer", result.playerName, "Should return the only Dead King in pool");
}
[Test]
public void GetRandomDeadKing_WhenPoolHasMultiple_ReturnsRandomly()
{
// Arrange: Add 10 different DKs
for (int i = 0; i < 10; i++)
{
var dk = CreateTestDeadKing($"Player{i}", $"Message {i}", 0, i);
_pool.AddDeadKing(dk);
}
// Act: Get multiple random DKs and verify we get different ones
var results = new HashSet<string>();
for (int i = 0; i < 20; i++)
{
var dk = _pool.GetRandomDeadKing();
results.Add(dk.playerName);
}
// Assert: We should have gotten more than 1 unique DK (randomness)
Assert.Greater(results.Count, 1, "Should return different Dead Kings over multiple calls");
}
#endregion
#region ShouldSpawnDeadKing Tests
[Test]
public void ShouldSpawnDeadKing_WhenPoolEmpty_ReturnsFalse()
{
// Act
bool shouldSpawn = _pool.ShouldSpawnDeadKing(0);
// Assert
Assert.IsFalse(shouldSpawn, "Should not spawn when pool is empty");
}
[Test]
public void ShouldSpawnDeadKing_Chapter0_HasBaseChance()
{
// Arrange: Add one DK
_pool.AddDeadKing(CreateTestDeadKing("Test", "Test", 0, 0));
// Act: Run spawn check many times to verify probability
int spawnCount = 0;
int iterations = 1000;
for (int i = 0; i < iterations; i++)
{
if (_pool.ShouldSpawnDeadKing(0))
spawnCount++;
}
// Assert: Should be around 20% (0.2 base chance)
float spawnRate = (float)spawnCount / iterations;
Assert.Greater(spawnRate, 0.10f, "Spawn rate should be greater than 10%");
Assert.Less(spawnRate, 0.30f, "Spawn rate should be less than 30%");
// Expected: ~20% with some variance
}
[Test]
public void ShouldSpawnDeadKing_Chapter1_HasHigherChance()
{
// Arrange
_pool.AddDeadKing(CreateTestDeadKing("Test", "Test", 0, 0));
// Act
int spawnCount = 0;
int iterations = 1000;
for (int i = 0; i < iterations; i++)
{
if (_pool.ShouldSpawnDeadKing(1))
spawnCount++;
}
// Assert: Should be around 40% (0.2 base + 0.2 * 1)
float spawnRate = (float)spawnCount / iterations;
Assert.Greater(spawnRate, 0.30f, "Ch1 spawn rate should be higher than base");
Assert.Less(spawnRate, 0.50f, "Ch1 spawn rate should be less than 50%");
}
[Test]
public void ShouldSpawnDeadKing_Chapter2_HasEvenHigherChance()
{
// Arrange
_pool.AddDeadKing(CreateTestDeadKing("Test", "Test", 0, 0));
// Act
int spawnCount = 0;
int iterations = 1000;
for (int i = 0; i < iterations; i++)
{
if (_pool.ShouldSpawnDeadKing(2))
spawnCount++;
}
// Assert: Should be around 60% (0.2 base + 0.2 * 2)
float spawnRate = (float)spawnCount / iterations;
Assert.Greater(spawnRate, 0.50f, "Ch2 spawn rate should be ~60%");
Assert.Less(spawnRate, 0.70f, "Ch2 spawn rate should be less than 70%");
}
#endregion
#region Persistence Tests
[Test]
public void SaveAndLoad_Roundtrip_PreservesData()
{
// Arrange: Add multiple DKs
_pool.AddDeadKing(CreateTestDeadKing("Player1", "Message1", 1, 3));
_pool.AddDeadKing(CreateTestDeadKing("Player2", "Message2", 2, 5));
// Act: Save
_pool.SavePool();
// Create new pool instance and load from the SAME redirected test file
var newPool = ScriptableObject.CreateInstance<DeadKingPool>();
SetPersistentPath(newPool, _testFilePath);
newPool.Reinitialize();
newPool.LoadPool();
// Assert: Data should match
Assert.AreEqual(_pool.Count, newPool.Count, "Loaded pool should have same count");
var originalDKs = _pool.GetAllDeadKings();
var loadedDKs = newPool.GetAllDeadKings();
for (int i = 0; i < originalDKs.Count; i++)
{
Assert.AreEqual(originalDKs[i].playerName, loadedDKs[i].playerName, $"DK {i} name should match");
Assert.AreEqual(originalDKs[i].message, loadedDKs[i].message, $"DK {i} message should match");
Assert.AreEqual(originalDKs[i].chapterReached, loadedDKs[i].chapterReached, $"DK {i} chapter should match");
}
// Cleanup
Object.DestroyImmediate(newPool);
}
#endregion
#region Helper Methods
/// <summary>
/// Creates a test Dead King with specified data.
/// </summary>
private DeadKingData CreateTestDeadKing(string name, string message, int chapter, int piecesLost)
{
return new DeadKingData(
name,
message,
chapter,
piecesLost,
new CampaignStats(50, 10, 2, 1)
);
}
#endregion
}
}