using System; using Xunit; using ytLive.Services; namespace ytLive.Tests; /// /// The capture conversion ring () is a pure, /// deterministic piece of — the WGC /// pool/session layer is WinRT and exercised only on Windows at runtime. These tests /// pin the slice-16 no-lap contract: a slot is never rewritten within redLine rents /// of its last hand-out (the 1742 tear — a ring slot rewritten under the consumer's /// read handed the compositor one new-top/old-bottom frame). /// public class ScreenCaptureFrameSourceTests { [Fact] public void PublishGate_TryPublish_OnlyStrictlyNewerWins() { // Slice 17: overlapping conversions can finish out of order; the monotonic // gate must keep a slow OLDER completion from overwriting a newer LatestFrame. var gate = new MonotonicGate(); Assert.True(gate.TryPublish(1)); Assert.True(gate.TryPublish(2)); Assert.False(gate.TryPublish(1)); // stale replay (older than 2) Assert.True(gate.TryPublish(3)); Assert.False(gate.TryPublish(3)); // duplicate — never accepted twice Assert.False(gate.TryPublish(2)); // late older completion Assert.False(gate.TryPublish(long.MinValue)); Assert.True(gate.TryPublish(long.MaxValue)); } [Fact] public void Ring_NoLap_ReusesOnlyAfterRedLineRents() { // Depth 3 / redLine 4: the ring is narrower than its safety distance, so the // red-line skip is actually exercised (the production 8/4 config can never // block a rotation — the ring cycles before any slot comes due). var ring = new FrameRingBuffer(depth: 3, redLine: 4); const int size = 100; var a = ring.Rent(size); var b = ring.Rent(size); var c = ring.Rent(size); Assert.NotSame(a, b); Assert.NotSame(b, c); Assert.NotSame(a, c); Assert.Equal(3, ring.ConsumeAllocations()); // 4th rent arrives while all three slots are inside their red line: the ring // must hand out a fresh buffer instead of rewriting a still-loaned slot. var d = ring.Rent(size); Assert.NotSame(d, a); Assert.NotSame(d, b); Assert.NotSame(d, c); Assert.Equal(1, ring.ConsumeAllocations()); // 5th rent: slot a (handed at seq 1, revisited at seq 5 = exactly redLine) // is reusable, and reuse is an in-place recycle, not a fresh allocation. Assert.Same(a, ring.Rent(size)); Assert.Equal(0, ring.ConsumeAllocations()); // The production-sized ring (8/4, what ScreenCaptureFrameSource uses) settles // at 8 buffers and recycles them forever — no growth under steady capture. var prod = new FrameRingBuffer(depth: 8, redLine: 4); var first = new byte[8][]; for (var i = 0; i < 8; i++) first[i] = prod.Rent(size); for (var i = 8; i < 200; i++) Assert.Same(first[i % 8], prod.Rent(size)); Assert.Equal(8, prod.ConsumeAllocations()); } }