refactor(app): close ordered startup composition

This commit is contained in:
Erik 2026-07-22 19:20:20 +02:00
parent 54244d31f1
commit 530b4bd8f5
16 changed files with 537 additions and 215 deletions

View file

@ -42,6 +42,65 @@ public sealed class GameWindowCompositionPipelineTests
Assert.Equal("phase-9", phases.Calls[^1]);
}
[Fact]
public void ProductionDelegateEntryUsesTheSamePipelineAndExactResults()
{
var calls = new List<int>();
var values = Enumerable.Range(0, 9).Select(value => new Token(value)).ToArray();
GameWindowCompositionPipeline.Run<
Token,
Token,
Token,
Token,
Token,
Token,
Token,
Token,
Token>(
values[0],
platform => Pass(1, values[1], platform),
(platform, host) => Pass(2, values[2], platform, host),
(platform, host, content) => Pass(3, values[3], platform, host, content),
(platform, content, settings) => Pass(4, values[4], platform, content, settings),
(platform, host, content, settings, world) =>
Pass(5, values[5], platform, host, content, settings, world),
(platform, host, content, settings, world, interaction) =>
Pass(6, values[6], platform, host, content, settings, world, interaction),
(host, content, settings, world, interaction, live) =>
Pass(7, values[7], host, content, settings, world, interaction, live),
(platform, host, content, settings, world, interaction, live, session) =>
Pass(8, values[8], platform, host, content, settings, world, interaction, live, session),
frame =>
{
Assert.Same(values[8], frame);
calls.Add(9);
});
Assert.Equal(Enumerable.Range(1, 9), calls);
Token Pass(int phase, Token result, params Token[] actual)
{
Token[] expected = phase switch
{
1 => [values[0]],
2 => [values[0], values[1]],
3 => [values[0], values[1], values[2]],
4 => [values[0], values[2], values[3]],
5 => [values[0], values[1], values[2], values[3], values[4]],
6 => [values[0], values[1], values[2], values[3], values[4], values[5]],
7 => [values[1], values[2], values[3], values[4], values[5], values[6]],
8 => [values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7]],
_ => throw new ArgumentOutOfRangeException(nameof(phase)),
};
Assert.Equal(expected.Length, actual.Length);
for (int index = 0; index < expected.Length; index++)
Assert.Same(expected[index], actual[index]);
calls.Add(phase);
return result;
}
}
private sealed record Token(int Phase);
private sealed class RecordingPhases(int failingPhase) :
@ -49,10 +108,10 @@ public sealed class GameWindowCompositionPipelineTests
IContentEffectsAudioCompositionPhase<Token, Token, Token>,
ISettingsDevToolsCompositionPhase<Token, Token, Token, Token>,
IWorldRenderCompositionPhase<Token, Token, Token, Token>,
IInteractionUiCompositionPhase<Token, Token, Token, Token, Token>,
ILivePresentationCompositionPhase<Token, Token, Token, Token, Token>,
ISessionPlayerCompositionPhase<Token, Token, Token, Token, Token, Token>,
IFrameRootCompositionPhase<Token, Token, Token, Token, Token, Token, Token, Token>,
IInteractionUiCompositionPhase<Token, Token, Token, Token, Token, Token>,
ILivePresentationCompositionPhase<Token, Token, Token, Token, Token, Token, Token>,
ISessionPlayerCompositionPhase<Token, Token, Token, Token, Token, Token, Token>,
IFrameRootCompositionPhase<Token, Token, Token, Token, Token, Token, Token, Token, Token>,
ISessionStartCompositionPhase<Token>
{
public Token Platform { get; } = new(0);
@ -111,12 +170,14 @@ public sealed class GameWindowCompositionPipelineTests
return _world;
}
Token IInteractionUiCompositionPhase<Token, Token, Token, Token, Token>.Compose(
Token IInteractionUiCompositionPhase<Token, Token, Token, Token, Token, Token>.Compose(
Token platform,
Token host,
Token content,
Token settings,
Token world)
{
Assert.Same(Platform, platform);
Assert.Same(_host, host);
Assert.Same(_content, content);
Assert.Same(_settings, settings);
@ -125,29 +186,35 @@ public sealed class GameWindowCompositionPipelineTests
return _interaction;
}
Token ILivePresentationCompositionPhase<Token, Token, Token, Token, Token>.Compose(
Token ILivePresentationCompositionPhase<Token, Token, Token, Token, Token, Token, Token>.Compose(
Token platform,
Token host,
Token content,
Token settings,
Token world,
Token interaction)
{
Assert.Same(Platform, platform);
Assert.Same(_host, host);
Assert.Same(_content, content);
Assert.Same(_settings, settings);
Assert.Same(_world, world);
Assert.Same(_interaction, interaction);
Record(6);
return _live;
}
Token ISessionPlayerCompositionPhase<Token, Token, Token, Token, Token, Token>.Compose(
Token ISessionPlayerCompositionPhase<Token, Token, Token, Token, Token, Token, Token>.Compose(
Token host,
Token content,
Token settings,
Token world,
Token interaction,
Token live)
{
Assert.Same(_host, host);
Assert.Same(_content, content);
Assert.Same(_settings, settings);
Assert.Same(_world, world);
Assert.Same(_interaction, interaction);
Assert.Same(_live, live);
@ -155,7 +222,8 @@ public sealed class GameWindowCompositionPipelineTests
return _session;
}
Token IFrameRootCompositionPhase<Token, Token, Token, Token, Token, Token, Token, Token>.Compose(
Token IFrameRootCompositionPhase<Token, Token, Token, Token, Token, Token, Token, Token, Token>.Compose(
Token platform,
Token host,
Token content,
Token settings,
@ -164,6 +232,7 @@ public sealed class GameWindowCompositionPipelineTests
Token live,
Token session)
{
Assert.Same(Platform, platform);
Assert.Same(_host, host);
Assert.Same(_content, content);
Assert.Same(_settings, settings);