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

194 lines
6.5 KiB
C#

using System.Collections.Generic;
using System.IO;
using System.Reflection;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using UnityEditor;
/// <summary>
/// Cobertura de ramas restantes de CampaignManager: registro de campañas
/// (config del Inspector, JSON inválido y duplicado en Resources), guards de
/// LoadChapter, EnsureChildSystem y cierre forzado del diálogo mid-turn.
/// </summary>
[TestFixture]
[Category("Unit")]
[Category("Campaign")]
[Category("FastTests")]
public class CampaignManagerCoverageTests
{
private static readonly BindingFlags Flags =
BindingFlags.NonPublic | BindingFlags.Instance;
private const string ResourcesFolder = "Assets/Game/Data/Resources/Campaigns";
private GameObject _root;
private CampaignManager _manager;
private readonly List<string> _tempFiles = new List<string>();
[SetUp]
public void Setup()
{
_root = new GameObject("CampaignManagerCoverageRoot");
_manager = _root.AddComponent<CampaignManager>();
}
[TearDown]
public void Teardown()
{
bool removedAny = false;
foreach (string file in _tempFiles)
{
if (File.Exists(file))
{
File.Delete(file);
removedAny = true;
}
}
_tempFiles.Clear();
if (removedAny)
{
AssetDatabase.Refresh();
}
Object.DestroyImmediate(_root);
LogAssert.ignoreFailingMessages = false;
}
private object GetPrivate(string name)
{
return typeof(CampaignManager).GetField(name, Flags).GetValue(_manager);
}
private void InvokePrivate(string name, params object[] args)
{
var method = typeof(CampaignManager).GetMethod(name, Flags);
Assert.IsNotNull(method, $"{name} no encontrado.");
method.Invoke(_manager, args);
}
private CampaignConfig MakeConfigFromJson(string json)
{
// CreateInstance dispara OnEnable → LoadFromJson sin fuente.
// OnEnable es silencioso cuando no hay fuente JSON asignada.
var config = ScriptableObject.CreateInstance<CampaignConfig>();
config.SetJsonSource(new TextAsset(json));
config.LoadFromJson();
return config;
}
private string WriteTempResource(string fileName, string contents)
{
string path = Path.Combine(ResourcesFolder, fileName);
File.WriteAllText(path, contents);
_tempFiles.Add(path);
AssetDatabase.Refresh();
return path;
}
[Test]
public void BuildCampaignRegistry_InspectorConfig_IsFirstAndActive()
{
var inspectorConfig = MakeConfigFromJson(
"{\"campaignId\":\"_inspector\",\"chapters\":[{\"id\":\"c1\"}]}");
typeof(CampaignManager).GetField("_campaignConfig", Flags)
.SetValue(_manager, inspectorConfig);
// La config del Inspector se añade SIN log; los recursos de
// Resources se registran al BuildCampaignRegistry (OnEnable silencioso).
LogAssert.ignoreFailingMessages = true;
InvokePrivate("BuildCampaignRegistry");
LogAssert.ignoreFailingMessages = false;
var registry = GetPrivate("_campaigns") as List<CampaignConfig>;
Assert.IsNotNull(registry);
Assert.IsTrue(RegistryHasId(registry, "_inspector"),
"La config del Inspector debe estar registrada.");
Assert.AreSame(inspectorConfig, GetPrivate("_activeConfig"),
"La config del Inspector debe ser la activa por defecto.");
Object.DestroyImmediate(inspectorConfig);
}
[Test]
public void BuildCampaignRegistry_InvalidResourceJson_IsSkipped()
{
WriteTempResource("_zz_invalid_test.json", "{esto no es json válido::");
LogAssert.ignoreFailingMessages = true;
InvokePrivate("BuildCampaignRegistry");
LogAssert.ignoreFailingMessages = false;
var registry = GetPrivate("_campaigns") as List<CampaignConfig>;
Assert.IsNotNull(registry);
Assert.IsFalse(RegistryHasId(registry, "_zz_invalid_test"),
"El JSON inválido no debe registrarse.");
}
[Test]
public void BuildCampaignRegistry_DuplicateCampaignId_SecondIsIgnored()
{
WriteTempResource("_zz_dup_a.json", "{\"campaignId\":\"_zzdup\",\"chapters\":[{\"id\":\"z1\"}]}");
WriteTempResource("_zz_dup_b.json", "{\"campaignId\":\"_zzdup\",\"chapters\":[{\"id\":\"z2\"}]}");
LogAssert.ignoreFailingMessages = true;
InvokePrivate("BuildCampaignRegistry");
LogAssert.ignoreFailingMessages = false;
var registry = GetPrivate("_campaigns") as List<CampaignConfig>;
Assert.IsNotNull(registry);
int dupCount = 0;
foreach (var campaign in registry)
{
if (campaign.CampaignId == "_zzdup") dupCount++;
}
Assert.AreEqual(1, dupCount, "Solo la primera campaña con el id debe registrarse.");
}
private static bool RegistryHasId(List<CampaignConfig> registry, string id)
{
foreach (var campaign in registry)
{
if (campaign.CampaignId == id) return true;
}
return false;
}
[Test]
public void LoadChapter_WithoutActiveConfig_LogsError()
{
LogAssert.Expect(LogType.Error, "[CampaignManager] CampaignConfig no asignado.");
_manager.LoadChapter(0);
}
[Test]
public void LoadChapter_IndexOutOfRange_LogsError()
{
var config = MakeConfigFromJson("{\"campaignId\":\"_one\",\"chapters\":[{\"id\":\"c1\"}]}");
typeof(CampaignManager).GetField("_activeConfig", Flags).SetValue(_manager, config);
LogAssert.ignoreFailingMessages = false;
LogAssert.Expect(LogType.Error, "[CampaignManager] Índice fuera de rango: 7");
_manager.LoadChapter(7);
Object.DestroyImmediate(config);
}
[Test]
public void EnsureChildSystem_CreatesOnceAndReusesAfterwards()
{
var ensureMethod = typeof(CampaignManager).GetMethod("EnsureChildSystem", Flags);
Assert.IsNotNull(ensureMethod, "EnsureChildSystem no encontrado.");
var generic = ensureMethod.MakeGenericMethod(typeof(DialogueTriggerSystem));
DialogueTriggerSystem first = (DialogueTriggerSystem)generic.Invoke(_manager, null);
DialogueTriggerSystem second = (DialogueTriggerSystem)generic.Invoke(_manager, null);
Assert.IsNotNull(first);
Assert.AreSame(first, second, "La segunda llamada debe reutilizar el sistema existente.");
Assert.IsTrue(first.transform.IsChildOf(_root.transform));
}
}