Files
sharpemu/tests/SharpEmu.Libs.Tests/Bink/BinkFramePlaybackTests.cs
T
Kurt Himebauch eb252af7b3 unstub: preserve notice screen skip flag (#559)
* fix(system-service): preserve notice screen skip flag

* test(bink): avoid frame timing flake on CI
2026-07-23 12:32:49 +03:00

108 lines
3.0 KiB
C#

// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using SharpEmu.Libs.Bink;
using Xunit;
namespace SharpEmu.Libs.Tests.Bink;
public sealed class BinkFramePlaybackTests
{
[Fact]
public void FramesAdvanceAccordingToMovieClock()
{
using var playback = new BinkFramePlayback(new SequenceDecoder(1, 2, 3));
Assert.Equal(1, WaitForAdvancedFrame(playback)[0]);
Assert.True(playback.TryGetFrame(true, out var heldFrame, out var advanced));
Assert.False(advanced);
Assert.Equal(1, heldFrame[0]);
Assert.Equal(2, WaitForAdvancedFrame(playback)[0]);
Assert.Equal(3, WaitForAdvancedFrame(playback)[0]);
}
private static byte[] WaitForAdvancedFrame(BinkFramePlayback playback)
{
var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(2);
while (DateTime.UtcNow < deadline)
{
if (playback.TryGetFrame(true, out var frame, out var advanced) && advanced)
{
return frame;
}
Thread.Sleep(1);
}
throw new TimeoutException("The decoder did not produce a frame.");
}
[Fact]
public void FirstFrameWaitsUntilPresentationStarts()
{
using var playback = new BinkFramePlayback(new SequenceDecoder(1, 2));
var first = WaitForFrame(playback, advanceClock: false);
Assert.Equal(1, first[0]);
Thread.Sleep(100);
Assert.True(playback.TryGetFrame(false, out var held, out var advanced));
Assert.False(advanced);
Assert.Equal(1, held[0]);
Assert.True(playback.TryGetFrame(true, out held, out advanced));
Assert.False(advanced);
Assert.Equal(1, held[0]);
Assert.Equal(2, WaitForAdvancedFrame(playback)[0]);
}
private static byte[] WaitForFrame(
BinkFramePlayback playback,
bool advanceClock)
{
var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(2);
while (DateTime.UtcNow < deadline)
{
if (playback.TryGetFrame(advanceClock, out var frame, out _))
{
return frame;
}
Thread.Sleep(1);
}
throw new TimeoutException("The decoder did not produce a frame.");
}
private sealed class SequenceDecoder(params byte[] values) : IBinkFrameDecoder
{
private int _index;
public uint Width => 1;
public uint Height => 1;
// Keep frame boundaries far enough apart that a loaded CI runner cannot
// skip an expected frame between polling iterations.
public uint FramesPerSecondNumerator => 2;
public uint FramesPerSecondDenominator => 1;
public bool TryDecodeNextFrame(Span<byte> destination)
{
if (_index >= values.Length)
{
return false;
}
destination.Fill(values[_index++]);
return true;
}
public void Dispose()
{
}
}
}