using System.Runtime.InteropServices; using NucleicProtocol.Interop; namespace NucleicApp.Tests; internal sealed class FakeNativeProtocol : INativeProtocol { private NativeProtocolCallback? eventCallback; private NativeProtocolCallback? stateCallback; private nint context; public string? ConfigurationJson { get; private set; } public string? RendezvousJson { get; private set; } public List Intents { get; } = []; public bool Closed { get; private set; } public string ProjectionResult { get; set; } = "{\"splices\":[],\"version\":1}"; public nint ClientCreate(string configurationJson) { ConfigurationJson = configurationJson; return 11; } public void ClientSetCallbacks( nint handle, NativeProtocolCallback? eventCallback, NativeProtocolCallback? stateCallback, nint context) { this.eventCallback = eventCallback; this.stateCallback = stateCallback; this.context = context; } public int ClientConnectLocal(nint handle, string rendezvousJson) { RendezvousJson = rendezvousJson; return 0; } public int ClientConnectRemote(nint handle, string endpointJson) => 0; public int ClientPair(nint handle, string pairingCode) => 0; public int ClientSendIntent(nint handle, string clientMessageJson) { Intents.Add(clientMessageJson); return 0; } public void ClientClose(nint handle) => Closed = true; public nint ProjectionCreate() => 22; public nint ProjectionApply(nint projection, string hostMessageJson) => Marshal.StringToCoTaskMemUTF8(ProjectionResult); public void ProjectionFree(nint projection) { } public string CopyAndFreeString(nint value) { try { return Marshal.PtrToStringUTF8(value)!; } finally { Marshal.FreeCoTaskMem(value); } } public void EmitEvent(string json) => Emit(eventCallback, json); public void EmitState(string json) => Emit(stateCallback, json); private void Emit(NativeProtocolCallback? callback, string json) { var pointer = Marshal.StringToCoTaskMemUTF8(json); try { callback?.Invoke(context, pointer); } finally { Marshal.FreeCoTaskMem(pointer); } } } internal sealed class FakeProtocolClient : IProtocolClient { public event Action? MessageJsonReceived; public event Action? StateJsonReceived; public HostdRendezvous? Rendezvous { get; private set; } public List Intents { get; } = []; public Queue ConnectLocalResults { get; } = []; public int ConnectLocalCount { get; private set; } public bool Disposed { get; private set; } public ProtocolResult ConnectLocal(HostdRendezvous rendezvous) { ConnectLocalCount++; Rendezvous = rendezvous; return ConnectLocalResults.TryDequeue(out var result) ? result : ProtocolResult.Ok; } public ProtocolResult ConnectRemote(string endpointJson) => ProtocolResult.Ok; public ProtocolResult Pair(string pairingCode) => ProtocolResult.Ok; public ProtocolResult SendIntent(string clientMessageJson) { Intents.Add(clientMessageJson); return ProtocolResult.Ok; } public void Dispose() => Disposed = true; public void EmitMessage(string json) => MessageJsonReceived?.Invoke(json); public void EmitState(string json) => StateJsonReceived?.Invoke(json); } internal sealed class FakeProtocolClientFactory(FakeProtocolClient client) : IProtocolClientFactory { public ProtocolClientConfiguration? Configuration { get; private set; } public IProtocolClient Create(ProtocolClientConfiguration configuration) { Configuration = configuration; return client; } } internal static class TestRepository { public static string Root { get { var current = new DirectoryInfo(AppContext.BaseDirectory); while (current is not null) { if (Directory.Exists(Path.Combine(current.FullName, "fixtures", "protocol-abi"))) return current.FullName; current = current.Parent; } throw new DirectoryNotFoundException("could not locate repository fixtures"); } } public static string Fixture(string side, string name) => File.ReadAllText( Path.Combine(Root, "fixtures", "protocol-abi", "v1", side, name + ".json")); }