using AcDream.App.Composition; namespace AcDream.App.Tests.Composition; public sealed class GameWindowCompositionPipelineTests { [Theory] [InlineData(1)] [InlineData(2)] [InlineData(3)] [InlineData(4)] [InlineData(5)] [InlineData(6)] [InlineData(7)] [InlineData(8)] [InlineData(9)] public void FailureRunsExactlyTheRequiredPrefix(int failingPhase) { var phases = new RecordingPhases(failingPhase); GameWindowCompositionPipeline pipeline = phases.BuildPipeline(); Assert.Throws(() => pipeline.Run(phases.Platform)); Assert.Equal( Enumerable.Range(1, failingPhase).Select(value => $"phase-{value}"), phases.Calls); } [Fact] public void SuccessPassesExactResultsAndStartsSessionLast() { var phases = new RecordingPhases(failingPhase: 0); GameWindowCompositionPipeline pipeline = phases.BuildPipeline(); pipeline.Run(phases.Platform); Assert.Equal( Enumerable.Range(1, 9).Select(value => $"phase-{value}"), phases.Calls); Assert.Equal("phase-9", phases.Calls[^1]); } private sealed record Token(int Phase); private sealed class RecordingPhases(int failingPhase) : IHostInputCameraCompositionPhase, IContentEffectsAudioCompositionPhase, ISettingsDevToolsCompositionPhase, IWorldRenderCompositionPhase, IInteractionUiCompositionPhase, ILivePresentationCompositionPhase, ISessionPlayerCompositionPhase, IFrameRootCompositionPhase, ISessionStartCompositionPhase { public Token Platform { get; } = new(0); public List Calls { get; } = []; private readonly Token _host = new(1); private readonly Token _content = new(2); private readonly Token _settings = new(3); private readonly Token _world = new(4); private readonly Token _interaction = new(5); private readonly Token _live = new(6); private readonly Token _session = new(7); private readonly Token _frame = new(8); public GameWindowCompositionPipeline BuildPipeline() => new(this, this, this, this, this, this, this, this, this); Token IHostInputCameraCompositionPhase.Compose(Token platform) { Assert.Same(Platform, platform); Record(1); return _host; } Token IContentEffectsAudioCompositionPhase.Compose( Token platform, Token host) { Assert.Same(Platform, platform); Assert.Same(_host, host); Record(2); return _content; } Token ISettingsDevToolsCompositionPhase.Compose( Token platform, Token host, Token content) { Assert.Same(Platform, platform); Assert.Same(_host, host); Assert.Same(_content, content); Record(3); return _settings; } Token IWorldRenderCompositionPhase.Compose( Token platform, Token content, Token settings) { Assert.Same(Platform, platform); Assert.Same(_content, content); Assert.Same(_settings, settings); Record(4); return _world; } Token IInteractionUiCompositionPhase.Compose( Token host, Token content, Token settings, Token world) { Assert.Same(_host, host); Assert.Same(_content, content); Assert.Same(_settings, settings); Assert.Same(_world, world); Record(5); return _interaction; } Token ILivePresentationCompositionPhase.Compose( Token host, Token content, Token world, Token interaction) { Assert.Same(_host, host); Assert.Same(_content, content); Assert.Same(_world, world); Assert.Same(_interaction, interaction); Record(6); return _live; } Token ISessionPlayerCompositionPhase.Compose( Token host, Token content, Token world, Token interaction, Token live) { Assert.Same(_host, host); Assert.Same(_content, content); Assert.Same(_world, world); Assert.Same(_interaction, interaction); Assert.Same(_live, live); Record(7); return _session; } Token IFrameRootCompositionPhase.Compose( Token host, Token settings, Token world, Token interaction, Token live, Token session) { Assert.Same(_host, host); Assert.Same(_settings, settings); Assert.Same(_world, world); Assert.Same(_interaction, interaction); Assert.Same(_live, live); Assert.Same(_session, session); Record(8); return _frame; } void ISessionStartCompositionPhase.Start(Token frame) { Assert.Same(_frame, frame); Record(9); } private void Record(int phase) { Calls.Add($"phase-{phase}"); if (failingPhase == phase) throw new InvalidOperationException($"phase {phase} failed"); } } }