acdream/tests/AcDream.App.Tests/Rendering/RenderFramePreparationControllerTests.cs
Erik 9d7df1bfc5 refactor(render): compose render frame orchestrator
Move the accepted draw transaction and failure recovery behind typed frame-phase owners so GameWindow only supplies immutable frame input. Preserve retail draw order, make ImGui/bootstrap shutdown ownership explicit, and restore exact text-render GL state on failures.\n\nCo-authored-by: Codex <codex@openai.com>
2026-07-22 08:03:49 +02:00

92 lines
2.7 KiB
C#

using AcDream.App.Rendering;
namespace AcDream.App.Tests.Rendering;
public sealed class RenderFramePreparationControllerTests
{
private static readonly RenderFrameInput Input = new(0.25d, 1280, 720);
[Fact]
public void Prepare_PreservesResourcesThenDevToolsThenWeatherOrder()
{
List<string> calls = [];
var resources = new Resources(calls);
var devTools = new DevTools(calls);
var weather = new Weather(calls);
var preparation = new RenderFramePreparationController(
resources,
devTools,
weather);
preparation.Prepare(Input);
Assert.Equal(["resources", "devtools-begin", "weather"], calls);
Assert.Equal(Input, resources.Input);
Assert.Equal((float)Input.DeltaSeconds, devTools.DeltaSeconds);
Assert.Equal(Input.DeltaSeconds, weather.DeltaSeconds);
}
[Fact]
public void Prepare_DevToolsAreOptionalWithoutChangingRequiredOrder()
{
List<string> calls = [];
var preparation = new RenderFramePreparationController(
new Resources(calls),
devTools: null,
new Weather(calls));
preparation.Prepare(Input);
Assert.Equal(["resources", "weather"], calls);
}
[Fact]
public void Constructor_RejectsMissingRequiredOwners()
{
var resources = new Resources([]);
var weather = new Weather([]);
Assert.Throws<ArgumentNullException>(() =>
new RenderFramePreparationController(null!, null, weather));
Assert.Throws<ArgumentNullException>(() =>
new RenderFramePreparationController(resources, null, null!));
}
private sealed class Resources(List<string> calls) : IRenderFrameResourcePhase
{
public RenderFrameInput Input { get; private set; }
public void Prepare(RenderFrameInput input)
{
Input = input;
calls.Add("resources");
}
}
private sealed class DevTools(List<string> calls) : IDevToolsFrameLifecycle
{
public float DeltaSeconds { get; private set; }
public void BeginFrame(float deltaSeconds)
{
DeltaSeconds = deltaSeconds;
calls.Add("devtools-begin");
}
public void AbortFrame() => calls.Add("devtools-abort");
public void Render(double deltaSeconds, int viewportWidth, int viewportHeight) =>
calls.Add("devtools-render");
}
private sealed class Weather(List<string> calls) : IRenderWeatherFramePhase
{
public double DeltaSeconds { get; private set; }
public void Tick(double deltaSeconds)
{
DeltaSeconds = deltaSeconds;
calls.Add("weather");
}
}
}