test(app): freeze GameWindow lifecycle boundaries

Pin the accepted startup, input, frame, resize, shutdown, and native-window order before Slice 8 moves those edges, while deleting only unread duplicate state and test-only GameWindow facades.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-22 09:27:55 +02:00
parent 20ebf217e2
commit 476c2e6de1
7 changed files with 380 additions and 56 deletions

View file

@ -78,4 +78,85 @@ public sealed class ResourceShutdownTransactionTests
Assert.Equal(1, calls);
Assert.True(transaction.IsComplete);
}
[Fact]
public void PersistentFailuresInOneStageAreAllAttemptedAndNamed()
{
int firstCalls = 0;
int secondCalls = 0;
var transaction = new ResourceShutdownTransaction(
new ResourceShutdownStage("owners",
[
new("first", () =>
{
firstCalls++;
throw new InvalidOperationException("first failure");
}),
new("second", () =>
{
secondCalls++;
throw new InvalidOperationException("second failure");
}),
]));
AggregateException error = Assert.Throws<AggregateException>(
transaction.CompleteOrThrow);
Assert.True(firstCalls > 0);
Assert.Equal(firstCalls, secondCalls);
Assert.Contains(
error.InnerExceptions,
exception => exception.Message.Contains("first", StringComparison.Ordinal));
Assert.Contains(
error.InnerExceptions,
exception => exception.Message.Contains("second", StringComparison.Ordinal));
Assert.False(transaction.IsComplete);
}
[Fact]
public void ExplicitRetryAfterFailedCompletionDoesNotReplaySuccessfulOperations()
{
int completeCalls = 0;
int pendingCalls = 0;
bool allowPending = false;
var transaction = new ResourceShutdownTransaction(
new ResourceShutdownStage("owners",
[
new("complete", () => completeCalls++),
new("pending", () =>
{
pendingCalls++;
if (!allowPending)
throw new InvalidOperationException("not yet");
}),
]));
Assert.Throws<AggregateException>(transaction.CompleteOrThrow);
int pendingCallsBeforeRetry = pendingCalls;
allowPending = true;
transaction.CompleteOrThrow();
Assert.Equal(1, completeCalls);
Assert.Equal(pendingCallsBeforeRetry + 1, pendingCalls);
Assert.True(transaction.IsComplete);
}
[Fact]
public void EmptyStagesConvergeWithoutSkippingLaterOperations()
{
int calls = 0;
var transaction = new ResourceShutdownTransaction(
new ResourceShutdownStage("empty", []),
new ResourceShutdownStage("owner",
[
new("owner", () => calls++),
]),
new ResourceShutdownStage("empty tail", []));
transaction.CompleteOrThrow();
Assert.Equal(1, calls);
Assert.True(transaction.IsComplete);
}
}