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() { }
}
}