namespace GFramework.Godot.Tests.Text; /// /// 的纯托管行为测试。 /// [TestFixture] public sealed class RichTextEffectsControllerTests { /// /// 验证启用框架效果时会开启宿主 BBCode,并在 Profile 为空时回退到内置默认配置。 /// [Test] public void RefreshEffects_Should_Enable_Bbcode_And_Use_BuiltIn_Default_Profile() { var host = new FakeRichTextEffectHost(); var controller = new RichTextEffectsController( host, () => null, () => true, () => false); controller.RefreshEffects(); Assert.That(host.BbcodeEnabled, Is.True); Assert.That(host.CapturedAnimatedEffectsEnabled, Has.Count.EqualTo(1)); Assert.That(host.CapturedAnimatedEffectsEnabled[0], Is.False); Assert.That(host.CapturedProfiles, Has.Count.EqualTo(1)); Assert.That(host.CapturedProfiles[0].Effects.Select(static entry => entry.Key), Is.EqualTo(new[] { "green", "red", "gold", "blue", "fade_in", "sine", "jitter", "fly_in" })); } /// /// 验证关闭框架效果时不会触发新的效果安装,并会清空宿主的自定义效果集合。 /// [Test] public void RefreshEffects_Should_Clear_CustomEffects_When_Framework_Effects_Are_Disabled() { var host = new FakeRichTextEffectHost { BbcodeEnabled = true }; host.SimulateInstalledEffects(); var controller = new RichTextEffectsController( host, () => RichTextEffectPlan.CreateBuiltInDefault(), () => false, () => true); controller.RefreshEffects(); Assert.That(host.BbcodeEnabled, Is.True); Assert.That(host.CustomEffectsInstalled, Is.False); Assert.That(host.ClearCustomEffectsCallCount, Is.EqualTo(1)); Assert.That(host.CapturedProfiles, Is.Empty); } /// /// 验证控制器会在每次刷新时读取最新的配置访问器结果,避免缓存旧配置。 /// [Test] public void RefreshEffects_Should_Use_The_Current_Profile_From_Accessor() { var host = new FakeRichTextEffectHost(); var firstProfile = new RichTextEffectPlan( [ new RichTextEffectPlanEntry("green") ]); var secondProfile = new RichTextEffectPlan( [ new RichTextEffectPlanEntry("gold") ]); RichTextEffectPlan? currentProfile = firstProfile; var controller = new RichTextEffectsController( host, () => currentProfile, () => true, () => true); controller.RefreshEffects(); currentProfile = secondProfile; controller.RefreshEffects(); Assert.That(host.CapturedProfiles, Has.Count.EqualTo(2)); Assert.That(host.CapturedProfiles[0], Is.SameAs(firstProfile)); Assert.That(host.CapturedProfiles[1], Is.SameAs(secondProfile)); } private sealed class FakeRichTextEffectHost : IRichTextEffectHost { public List CapturedProfiles { get; } = []; public List CapturedAnimatedEffectsEnabled { get; } = []; public bool CustomEffectsInstalled { get; private set; } public int ClearCustomEffectsCallCount { get; private set; } public bool BbcodeEnabled { get; set; } public void ApplyEffects(RichTextEffectPlan profile, bool animatedEffectsEnabled) { ArgumentNullException.ThrowIfNull(profile); CapturedProfiles.Add(profile); CapturedAnimatedEffectsEnabled.Add(animatedEffectsEnabled); CustomEffectsInstalled = true; } public void ClearCustomEffects() { ClearCustomEffectsCallCount++; CustomEffectsInstalled = false; } public void SimulateInstalledEffects() { CustomEffectsInstalled = true; } } }