using System.Diagnostics; using AcDream.App.Rendering; namespace AcDream.App.Tests.Rendering; public sealed class LinuxMonotonicFramePacingWaiterTests { [Theory] [InlineData(1L, 1_000_000_000L, 1L)] [InlineData(1L, 3L, 333_333_334L)] [InlineData(15L, 1_000L, 15_000_000L)] [InlineData(6_060L, 1_000_000L, 6_060_000L)] public void TickConversionRoundsUpWithoutReturningZero( long ticks, long frequency, long expected) { Assert.Equal( expected, LinuxMonotonicFramePacingWaiter .ConvertTicksToNanoseconds(ticks, frequency)); } [Fact] public void PlatformFactorySelectsCurrentOperatingSystem() { IFramePacingWaiter waiter = PlatformFramePacingWaiterFactory .ForCurrentProcess() .Create(); if (OperatingSystem.IsWindows()) { Assert.IsType( waiter); ((IDisposable)waiter).Dispose(); return; } if (OperatingSystem.IsLinux()) { Assert.IsType(waiter); ((IDisposable)waiter).Dispose(); return; } throw new PlatformNotSupportedException(); } [Fact] public void LinuxWaitBlocksUntilRequestedMonotonicDeadline() { if (!OperatingSystem.IsLinux()) return; LinuxMonotonicFramePacingWaiter waiter = LinuxMonotonicFramePacingWaiter.Create(); long start = Stopwatch.GetTimestamp(); waiter.Wait( durationTicks: Stopwatch.Frequency / 200L, clockFrequency: Stopwatch.Frequency); TimeSpan elapsed = Stopwatch.GetElapsedTime(start); Assert.True( elapsed >= TimeSpan.FromMilliseconds(4), $"Linux monotonic wait returned after {elapsed.TotalMilliseconds:F3} ms."); Assert.True( elapsed < TimeSpan.FromSeconds(1), $"Linux monotonic wait stalled for {elapsed.TotalMilliseconds:F3} ms."); } [Fact] public void LinuxWaiterRejectsUseAfterDisposal() { if (!OperatingSystem.IsLinux()) return; LinuxMonotonicFramePacingWaiter waiter = LinuxMonotonicFramePacingWaiter.Create(); waiter.Dispose(); Assert.Throws( () => waiter.Wait(1, Stopwatch.Frequency)); } }