using System.Collections.Concurrent; using TeamsISO.Engine.Interop; using TeamsISO.Engine.Pipeline; namespace TeamsISO.Engine.Tests.Fakes; /// /// In-memory test double for . Tests configure source lists and frame /// queues; the fake feeds those into engine code as if a real NDI runtime were present. /// public sealed class FakeNdiInterop : INdiInterop { public List Sources { get; } = new(); public ConcurrentDictionary> ReceiverFrames { get; } = new(); public ConcurrentDictionary> SentFrames { get; } = new(); public string RuntimeVersion { get; set; } = "6.0.0"; public Dictionary ReceiverCreatedCount { get; } = new(); public Dictionary SenderCreatedCount { get; } = new(); /// Last groups string seen by ; null = default Public. public string? LastFinderGroups { get; private set; } /// Per-output groups string seen by ; null = default Public. public Dictionary SenderGroups { get; } = new(); public NdiFindHandle CreateFinder(string? groups = null) { LastFinderGroups = groups; return new FakeFindHandle(); } public IReadOnlyList GetCurrentSources(NdiFindHandle finder) => Sources.ToArray(); public NdiReceiverHandle CreateReceiver(string sourceFullName) { ReceiverCreatedCount[sourceFullName] = ReceiverCreatedCount.GetValueOrDefault(sourceFullName) + 1; ReceiverFrames.GetOrAdd(sourceFullName, _ => new ConcurrentQueue()); return new FakeReceiverHandle(sourceFullName); } public RawFrame? CaptureFrame(NdiReceiverHandle receiver, int timeoutMs) { var key = ((FakeReceiverHandle)receiver).Source; if (ReceiverFrames.TryGetValue(key, out var q) && q.TryDequeue(out var frame)) return frame; return null; // simulate timeout } public NdiSenderHandle CreateSender(string outputName, string? groups = null) { SenderCreatedCount[outputName] = SenderCreatedCount.GetValueOrDefault(outputName) + 1; SenderGroups[outputName] = groups; SentFrames.GetOrAdd(outputName, _ => new List()); return new FakeSenderHandle(outputName); } public void SendFrame(NdiSenderHandle sender, ProcessedFrame frame) { var key = ((FakeSenderHandle)sender).Output; SentFrames[key].Add(frame); } public string GetRuntimeVersion() => RuntimeVersion; private sealed class FakeFindHandle : NdiFindHandle { public override void Dispose() { } } private sealed class FakeReceiverHandle : NdiReceiverHandle { public string Source { get; } public FakeReceiverHandle(string source) => Source = source; public override void Dispose() { } } private sealed class FakeSenderHandle : NdiSenderHandle { public string Output { get; } public FakeSenderHandle(string output) => Output = output; public override void Dispose() { } } }