Files
Ajedrez_Purgatorio/Assets/Tests/EditMode/Campaign/CampaignManagerConfigTests.cs
T

189 lines
7.1 KiB
C#

using System.Reflection;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
namespace AjedrezPurgatorio.Tests.Unit.Campaign
{
/// <summary>
/// Tests de integración de CampaignManager — Suite 3 del plan de automatización.
///
/// Alcance EditMode (sin cargas de escena): registro de campañas desde Resources,
/// selección de campaña activa, propiedades derivadas y guard clauses de
/// LoadChapter que retornan antes de tocar SceneManager.
///
/// Nota: AddComponent en EditMode NO invoca Awake, así que invocamos
/// BuildCampaignRegistry por reflexión sin pasar por el singleton ni
/// DontDestroyOnLoad.
/// </summary>
[TestFixture]
[Category("Unit")]
[Category("Campaign")]
[Category("CampaignManager")]
[Category("FastTests")]
public class CampaignManagerConfigTests
{
private GameObject _root;
private CampaignManager _manager;
private MethodInfo _buildRegistryMethod;
[SetUp]
public void SetUp()
{
_root = new GameObject("CampaignManagerTestRoot");
_manager = _root.AddComponent<CampaignManager>();
_buildRegistryMethod = typeof(CampaignManager).GetMethod(
"BuildCampaignRegistry", BindingFlags.NonPublic | BindingFlags.Instance);
Assert.IsNotNull(_buildRegistryMethod, "BuildCampaignRegistry no encontrado.");
// Carga el registry desde Resources/Campaigns igual que Awake,
// pero sin singleton ni DontDestroyOnLoad (incompatibles con EditMode).
// OnEnable es silencioso cuando no hay fuente JSON asignada.
_buildRegistryMethod.Invoke(_manager, null);
}
[TearDown]
public void TearDown()
{
Object.DestroyImmediate(_root);
}
// ------------------------------------------------------------------
// Registro de campañas
// ------------------------------------------------------------------
[Test]
public void Registry_LoadsAtLeastOneCampaignFromResources()
{
Assert.GreaterOrEqual(_manager.CampaignCount, 1,
"Resources/Campaigns debe contener al menos la campaña Gambito.");
}
[Test]
public void Registry_IgnoresDuplicateCampaignIds_OnRebuild()
{
int countAfterFirstBuild = _manager.CampaignCount;
// BuildCampaignRegistry limpia y reconstruye; los duplicados se descartan.
_buildRegistryMethod.Invoke(_manager, null);
Assert.AreEqual(countAfterFirstBuild, _manager.CampaignCount,
"Reconstruir el registry no debe duplicar campañas.");
}
// ------------------------------------------------------------------
// Selección de campaña activa
// ------------------------------------------------------------------
[Test]
public void SetDefaultCampaign_SelectsFirstRegistered()
{
Assert.GreaterOrEqual(_manager.CampaignCount, 1);
Assert.IsTrue(_manager.SetDefaultCampaign());
Assert.IsNotNull(_manager.ActiveCampaignId);
Assert.IsNotEmpty(_manager.ActiveCampaignId);
}
[Test]
public void SetDefaultCampaign_WithoutRegistry_Fails()
{
// Manager recién creado SIN invocar BuildCampaignRegistry:
// el registro interno está vacío.
var emptyRoot = new GameObject("EmptyCampaignManagerRoot");
var empty = emptyRoot.AddComponent<CampaignManager>();
try
{
Assert.AreEqual(0, empty.CampaignCount);
Assert.IsFalse(empty.SetDefaultCampaign(),
"Sin campañas registradas debe retornar false.");
}
finally
{
Object.DestroyImmediate(emptyRoot);
}
}
[Test]
public void SetCampaign_WithGambitoId_Succeeds()
{
Assert.IsTrue(_manager.SetCampaign("gambito"));
Assert.AreEqual("gambito", _manager.ActiveCampaignId);
}
[Test]
public void SetCampaign_WithInvalidId_Fails_AndKeepsPreviousActive()
{
Assert.IsTrue(_manager.SetDefaultCampaign());
string previousId = _manager.ActiveCampaignId;
LogAssert.Expect(LogType.Error,
"[CampaignManager] Campaña no encontrada: campana-inexistente-xyz. Disponibles: gambito");
Assert.IsFalse(_manager.SetCampaign("campana-inexistente-xyz"));
Assert.AreEqual(previousId, _manager.ActiveCampaignId,
"Un fallo de selección no debe alterar la campaña activa.");
}
[Test]
public void TotalChapters_IsPositive_AfterValidSelection()
{
Assert.IsTrue(_manager.SetCampaign("gambito"));
Assert.Greater(_manager.TotalChapters, 0,
"La campaña Gambito debe declarar al menos un capítulo.");
}
[Test]
public void ActiveCampaignId_DefaultsToFirstRegistered_BeforeExplicitSelection()
{
// ValidateConfiguration/BuildCampaignRegistry deja _activeConfig = campaigns[0].
Assert.IsNotNull(_manager.ActiveCampaignId,
"Tras construir el registry hay una campaña activa por defecto.");
Assert.IsNotEmpty(_manager.ActiveCampaignId);
}
// ------------------------------------------------------------------
// Guard clauses de LoadChapter (retornan antes de cargar escena)
// ------------------------------------------------------------------
[Test]
public void LoadChapter_NegativeIndex_Rejected_WithoutActivatingCampaign()
{
LogAssert.Expect(LogType.Error, "[CampaignManager] Índice fuera de rango: -1");
_manager.LoadChapter(-1);
Assert.IsFalse(_manager.IsCampaignActive,
"Índice inválido no debe activar la campaña.");
}
[Test]
public void LoadChapter_IndexOutOfRange_Rejected_WithoutActivatingCampaign()
{
Assert.IsTrue(_manager.SetCampaign("gambito"));
int outOfRange = _manager.TotalChapters; // índices válidos: 0..TotalChapters-1
LogAssert.Expect(LogType.Error, $"[CampaignManager] Índice fuera de rango: {outOfRange}");
_manager.LoadChapter(outOfRange);
Assert.IsFalse(_manager.IsCampaignActive);
}
[Test]
public void StartCampaign_WithValidConfig_ActivatesCampaignState()
{
Assert.IsTrue(_manager.SetCampaign("gambito"));
// StartCampaign llama a LoadChapterScene → SceneTransitionManager o
// SceneManager.LoadScene. En EditMode eso es inviable, así que solo
// verificamos las guardas previas mediante TotalChapters > 0.
Assert.Greater(_manager.TotalChapters, 0,
"Con config válida StartCampaign superaría sus guardas iniciales.");
Assert.IsFalse(_manager.IsCampaignActive,
"En EditMode nunca llegamos a ejecutar la carga de escena.");
}
}
}