using OpenTheBox.Core;
using OpenTheBox.Core.Characters;
using OpenTheBox.Core.Enums;
using OpenTheBox.Core.Items;
using OpenTheBox.Localization;
using OpenTheBox.Rendering;
using OpenTheBox.Rendering.Panels;
using Spectre.Console;
using Spectre.Console.Rendering;
namespace OpenTheBox.Tests;
// ── Helpers ──────────────────────────────────────────────────────────────
///
/// Renders an IRenderable to string using a local AnsiConsole. No shared state.
///
static class RenderHelper
{
public static string RenderToString(IRenderable renderable)
{
var writer = new StringWriter();
var console = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(writer),
Ansi = AnsiSupport.Yes,
ColorSystem = ColorSystemSupport.TrueColor
});
console.Write(renderable);
return writer.ToString();
}
}
///
/// Captures AnsiConsole.Console and Console.Out output for renderer tests.
/// MUST NOT be used in parallel — use [Collection("ConsoleTests")].
///
sealed class ConsoleCapture : IDisposable
{
private readonly IAnsiConsole _origAnsi;
private readonly TextWriter _origOut;
private readonly StringWriter _ansiWriter = new();
private readonly StringWriter _consoleWriter = new();
public ConsoleCapture()
{
_origAnsi = AnsiConsole.Console;
_origOut = Console.Out;
AnsiConsole.Console = AnsiConsole.Create(new AnsiConsoleSettings
{
Out = new AnsiConsoleOutput(_ansiWriter),
Interactive = InteractionSupport.No,
Ansi = AnsiSupport.Yes,
ColorSystem = ColorSystemSupport.TrueColor
});
Console.SetOut(_consoleWriter);
}
public string Output => _ansiWriter.ToString() + _consoleWriter.ToString();
public void Dispose()
{
AnsiConsole.Console = _origAnsi;
Console.SetOut(_origOut);
}
}
// ── Panel Tests ──────────────────────────────────────────────────────────
public class PortraitPanelTests
{
[Fact]
public void Render_DefaultAppearance_DoesNotThrow()
{
var result = RenderHelper.RenderToString(PortraitPanel.Render(new PlayerAppearance()));
Assert.NotEmpty(result);
}
[Fact]
public void Render_FullyEquipped_DoesNotThrow()
{
var appearance = new PlayerAppearance
{
HairStyle = HairStyle.Cyberpunk,
HairTint = TintColor.Neon,
EyeStyle = EyeStyle.CyberneticEyes,
BodyStyle = BodyStyle.Armored,
BodyTint = TintColor.Gold,
LegStyle = LegStyle.RocketBoots,
ArmStyle = ArmStyle.Wings
};
var result = RenderHelper.RenderToString(PortraitPanel.Render(appearance));
Assert.NotEmpty(result);
}
[Theory]
[MemberData(nameof(AllHairStyles))]
public void Render_EachHairStyle_DoesNotThrow(HairStyle style)
{
var result = RenderHelper.RenderToString(
PortraitPanel.Render(new PlayerAppearance { HairStyle = style }));
Assert.NotEmpty(result);
}
[Theory]
[MemberData(nameof(AllEyeStyles))]
public void Render_EachEyeStyle_DoesNotThrow(EyeStyle style)
{
var result = RenderHelper.RenderToString(
PortraitPanel.Render(new PlayerAppearance { EyeStyle = style }));
Assert.NotEmpty(result);
}
[Theory]
[MemberData(nameof(AllBodyStyles))]
public void Render_EachBodyStyle_DoesNotThrow(BodyStyle style)
{
var result = RenderHelper.RenderToString(
PortraitPanel.Render(new PlayerAppearance { BodyStyle = style }));
Assert.NotEmpty(result);
}
[Theory]
[MemberData(nameof(AllLegStyles))]
public void Render_EachLegStyle_DoesNotThrow(LegStyle style)
{
var result = RenderHelper.RenderToString(
PortraitPanel.Render(new PlayerAppearance { LegStyle = style }));
Assert.NotEmpty(result);
}
[Theory]
[MemberData(nameof(AllArmStyles))]
public void Render_EachArmStyle_DoesNotThrow(ArmStyle style)
{
var result = RenderHelper.RenderToString(
PortraitPanel.Render(new PlayerAppearance { ArmStyle = style }));
Assert.NotEmpty(result);
}
[Theory]
[MemberData(nameof(AllTintColors))]
public void Render_EachHairTint_DoesNotThrow(TintColor tint)
{
var result = RenderHelper.RenderToString(
PortraitPanel.Render(new PlayerAppearance { HairTint = tint }));
Assert.NotEmpty(result);
}
[Theory]
[MemberData(nameof(AllTintColors))]
public void Render_EachBodyTint_DoesNotThrow(TintColor tint)
{
var result = RenderHelper.RenderToString(
PortraitPanel.Render(new PlayerAppearance { BodyTint = tint }));
Assert.NotEmpty(result);
}
public static IEnumerable