mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-26 20:50:53 +08:00
eb252af7b3
* fix(system-service): preserve notice screen skip flag * test(bink): avoid frame timing flake on CI
108 lines
3.0 KiB
C#
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()
|
|
{
|
|
}
|
|
}
|
|
}
|