acdream/tests/AcDream.App.Tests/Composition/AnimationHookRegistrationSetTests.cs
Erik 60a1698ce7 refactor(app): compose content effects and audio startup
Move Phase-2 startup behind typed composition/publication boundaries, replace the GameWindow-capturing PhysicsScript gate with a focused deferred source, and own animation-hook registrations reversibly. Make OpenAL construction and teardown transactional so every device, context, source, and buffer prefix is retryable without replay.
2026-07-22 15:36:05 +02:00

77 lines
2.3 KiB
C#

using System.Numerics;
using AcDream.App.Composition;
using AcDream.Core.Physics;
using DatReaderWriter.Types;
namespace AcDream.App.Tests.Composition;
public sealed class AnimationHookRegistrationSetTests
{
[Fact]
public void CleanupUnregistersInReverseAndNeverReplaysSuccessfulEdges()
{
var calls = new List<string>();
var first = new Sink("first");
var second = new Sink("second");
var third = new Sink("third");
bool failSecond = true;
var registrations = new AnimationHookRegistrationSet(
sink => calls.Add($"add:{((Sink)sink).Name}"),
sink =>
{
string name = ((Sink)sink).Name;
calls.Add($"remove:{name}");
if (name == "second" && failSecond)
throw new InvalidOperationException("synthetic removal failure");
});
registrations.Register(first);
registrations.Register(second);
registrations.Register(third);
Assert.Throws<AggregateException>(registrations.Dispose);
Assert.False(registrations.IsCleanupComplete);
failSecond = false;
registrations.Dispose();
registrations.Dispose();
Assert.True(registrations.IsCleanupComplete);
Assert.Equal(
[
"add:first", "add:second", "add:third",
"remove:third", "remove:second", "remove:first",
"remove:second",
],
calls);
}
[Fact]
public void DuplicateRegistrationIsIdempotentAndClosedSetRejectsNewEdges()
{
int adds = 0;
int removes = 0;
var sink = new Sink("only");
var registrations = new AnimationHookRegistrationSet(
_ => adds++,
_ => removes++);
registrations.Register(sink);
registrations.Register(sink);
registrations.Dispose();
Assert.Equal(1, adds);
Assert.Equal(1, removes);
Assert.Throws<ObjectDisposedException>(() =>
registrations.Register(new Sink("late")));
}
private sealed class Sink(string name) : IAnimationHookSink
{
public string Name { get; } = name;
public void OnHook(
uint entityId,
Vector3 entityWorldPosition,
AnimationHook hook)
{
}
}
}