tests + fixes

This commit is contained in:
Christian Köllner 2020-04-04 14:55:31 +02:00
parent d7f937a9c0
commit fef879de9f
4 changed files with 356 additions and 65 deletions

View File

@ -1,4 +1,5 @@
using Capnproto_test.Capnp.Test; using Capnp.Net.Runtime.Tests.GenImpls;
using Capnproto_test.Capnp.Test;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -791,5 +792,179 @@ namespace Capnp.Net.Runtime.Tests
var kind = loed.Cast(_ => _.Kind).Take(1).Single(); var kind = loed.Cast(_ => _.Kind).Take(1).Single();
Assert.AreEqual(ObjectKind.Nil, kind); Assert.AreEqual(ObjectKind.Nil, kind);
} }
[TestMethod]
public void DeserializerStateBadConv()
{
SerializerState s = null;
Assert.ThrowsException<ArgumentNullException>(() => (DeserializerState)s);
s = new DynamicSerializerState();
Assert.ThrowsException<InvalidOperationException>(() => (DeserializerState)s);
}
[TestMethod]
public void BadPointers()
{
var data = new ulong[1];
var wf = new WireFrame(new Memory<ulong>[] { new Memory<ulong>(data) });
var d0 = DeserializerState.CreateRoot(wf);
Assert.AreEqual(ObjectKind.Nil, d0.Kind);
WirePointer p = default;
p.BeginStruct(1, 0);
p.Offset = 0;
data[0] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.BeginList(ListKind.ListOfBits, 64);
data[0] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.BeginList(ListKind.ListOfBytes, 8);
data[0] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.BeginList(ListKind.ListOfEmpty, 6400);
data[0] = p;
var d1 = DeserializerState.CreateRoot(wf);
p.BeginList(ListKind.ListOfInts, 2);
data[0] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.BeginList(ListKind.ListOfLongs, 1);
data[0] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.BeginList(ListKind.ListOfPointers, 1);
data[0] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.BeginList(ListKind.ListOfShorts, 4);
data[0] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.BeginList(ListKind.ListOfStructs, 1);
data[0] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.SetFarPointer(0, 0, false);
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.SetFarPointer(1, 0, false);
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.SetFarPointer(0, 1, false);
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
p.SetFarPointer(0, 0, true);
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf));
var data2 = new ulong[3];
var wf2 = new WireFrame(new Memory<ulong>[] { new Memory<ulong>(data2) });
p.BeginList(ListKind.ListOfStructs, 1);
data2[0] = p;
data2[1] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf2));
p.SetFarPointer(0, 1, true);
data2[0] = p;
data2[1] = 0;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf2));
p.SetFarPointer(0, 1, false);
data2[1] = p;
data2[2] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf2));
p.SetFarPointer(0, 2, true);
data2[0] = p;
Assert.ThrowsException<DeserializationException>(() => DeserializerState.CreateRoot(wf2));
}
[TestMethod]
public void ReadCap1()
{
var mb = MessageBuilder.Create();
var dss = mb.CreateObject<DynamicSerializerState>();
dss.SetStruct(0, 1);
DeserializerState ds = dss;
Assert.ThrowsException<ArgumentOutOfRangeException>(() => ds.ReadCap(-1));
Assert.ThrowsException<InvalidOperationException>(() => ds.ReadCap(0));
}
[TestMethod]
public void ReadCap2()
{
var mb = MessageBuilder.Create();
mb.InitCapTable();
var dss1 = mb.CreateObject<DynamicSerializerState>();
var dss2 = mb.CreateObject<DynamicSerializerState>();
dss2.SetStruct(1, 1);
dss1.SetStruct(0, 2);
dss1.Link(0, dss2);
dss1.LinkToCapability(1, 7);
var d = (DeserializerState)dss1;
Assert.ThrowsException<Rpc.RpcException>(() => d.ReadCap(0));
Assert.ThrowsException<Rpc.RpcException>(() => d.ReadCap(1));
}
[TestMethod]
public void Read1()
{
var mb = MessageBuilder.Create();
var dss = mb.CreateObject<DynamicSerializerState>();
dss.SetStruct(1, 0);
dss.WriteData(0, ulong.MaxValue);
var d = (DeserializerState)dss;
Assert.AreEqual(ushort.MaxValue, d.ReadDataUShort(48));
Assert.ThrowsException<ArgumentOutOfRangeException>(() => d.ReadDataUShort(49));
Assert.AreEqual((ushort)0, d.ReadDataUShort(64));
Assert.IsNotNull(d.StructReadPointer(7));
Assert.ThrowsException<DeserializationException>(() => d.RequireCapList<ITestInterface>());
}
[TestMethod]
public void Read2()
{
var mb = MessageBuilder.Create();
var dss = mb.CreateObject<ListOfBitsSerializer>();
dss.Init(50);
var d = (DeserializerState)dss;
Assert.ThrowsException<DeserializationException>(() => d.ReadDataUInt(0));
Assert.ThrowsException<DeserializationException>(() => d.StructReadPointer(0));
}
[TestMethod]
public void ReadCapList()
{
var mb = MessageBuilder.Create();
mb.InitCapTable();
var dss = mb.CreateObject<DynamicSerializerState>();
dss.SetStruct(0, 1);
var loc = mb.CreateObject<ListOfCapsSerializer<ITestInterface>>();
loc.Init(1);
loc[0] = new TestInterfaceImpl2();
dss.LinkObject(0, loc);
var d = (DeserializerState)dss;
var cl = d.ReadCapList<ITestInterface>(0);
Assert.AreEqual(1, cl.Count);
Assert.IsNotNull(cl[0]);
}
[TestMethod]
public void ReadCap()
{
var dss = DynamicSerializerState.CreateForRpc();
dss.SetStruct(0, 1);
dss.LinkObject<ITestInterface>(0, new TestInterfaceImpl2());
var d = (DeserializerState)dss;
Assert.IsNotNull(d.ReadCap(0));
Assert.IsNotNull(d.ReadCap<ITestInterface>(0));
}
[TestMethod]
public void RequireCap1()
{
var dss = DynamicSerializerState.CreateForRpc();
dss.SetStruct(1, 1);
var d = (DeserializerState)dss;
Assert.ThrowsException<DeserializationException>(() => d.RequireCap<ITestInterface>());
}
[TestMethod]
public void RequireCap2()
{
DeserializerState d = default;
d.Kind = ObjectKind.Capability;
Assert.ThrowsException<InvalidOperationException>(() => d.RequireCap<ITestInterface>());
}
} }
} }

View File

@ -7,6 +7,9 @@ using Capnp.Rpc;
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Diagnostics; using System.Diagnostics;
using System.Threading.Tasks.Dataflow;
using Capnp.Net.Runtime.Tests.GenImpls;
using Capnproto_test.Capnp.Test;
namespace Capnp.Net.Runtime.Tests namespace Capnp.Net.Runtime.Tests
{ {
@ -42,7 +45,7 @@ namespace Capnp.Net.Runtime.Tests
}); });
} }
int MediumTimeout => Debugger.IsAttached ? Timeout.Infinite : 2000; int MediumNonDbgTimeout => Debugger.IsAttached ? Timeout.Infinite : 2000;
[TestMethod] [TestMethod]
public void CreateAndDispose() public void CreateAndDispose()
@ -66,7 +69,7 @@ namespace Capnp.Net.Runtime.Tests
try try
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
} }
catch (System.Exception e) catch (System.Exception e)
@ -95,13 +98,13 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
server.Main = new ProvidedCapabilityMock(); server.Main = new ProvidedCapabilityMock();
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
var resolving = main as IResolvingCapability; var resolving = main as IResolvingCapability;
Assert.IsTrue(resolving.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout));
} }
} }
@ -114,12 +117,12 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
var resolving = main as IResolvingCapability; var resolving = main as IResolvingCapability;
Assert.IsTrue(Assert.ThrowsExceptionAsync<RpcException>(() => resolving.WhenResolved).Wait(MediumTimeout)); Assert.IsTrue(Assert.ThrowsExceptionAsync<RpcException>(() => resolving.WhenResolved).Wait(MediumNonDbgTimeout));
} }
} }
@ -132,19 +135,19 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
using (var answer = main.Call(0x1234567812345678, 0x3333, args)) using (var answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
(var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result;
Assert.AreEqual<ulong>(0x1234567812345678, interfaceId); Assert.AreEqual<ulong>(0x1234567812345678, interfaceId);
Assert.AreEqual<ushort>(0x3333, methodId); Assert.AreEqual<ushort>(0x3333, methodId);
@ -156,7 +159,7 @@ namespace Capnp.Net.Runtime.Tests
result.WriteData(0, 654321); result.WriteData(0, 654321);
mock.Return.SetResult(result); mock.Return.SetResult(result);
Assert.IsTrue(answer.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout));
var outresult = answer.WhenReturned.Result; var outresult = answer.WhenReturned.Result;
Assert.AreEqual(ObjectKind.Struct, outresult.Kind); Assert.AreEqual(ObjectKind.Struct, outresult.Kind);
Assert.AreEqual(654321, outresult.ReadDataInt(0)); Assert.AreEqual(654321, outresult.ReadDataInt(0));
@ -173,19 +176,19 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
using (var answer = main.Call(0x1234567812345678, 0x3333, args)) using (var answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
(var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result;
Assert.AreEqual<ulong>(0x1234567812345678, interfaceId); Assert.AreEqual<ulong>(0x1234567812345678, interfaceId);
Assert.AreEqual<ushort>(0x3333, methodId); Assert.AreEqual<ushort>(0x3333, methodId);
@ -194,7 +197,7 @@ namespace Capnp.Net.Runtime.Tests
mock.Return.SetCanceled(); mock.Return.SetCanceled();
Assert.IsTrue(Assert.ThrowsExceptionAsync<TaskCanceledException>(() => answer.WhenReturned).Wait(MediumTimeout)); Assert.IsTrue(Assert.ThrowsExceptionAsync<TaskCanceledException>(() => answer.WhenReturned).Wait(MediumNonDbgTimeout));
} }
} }
} }
@ -212,21 +215,21 @@ namespace Capnp.Net.Runtime.Tests
try try
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
var resolving = main as IResolvingCapability; var resolving = main as IResolvingCapability;
Assert.IsTrue(resolving.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(resolving.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
CancellationToken ctx; CancellationToken ctx;
using (var answer = main.Call(0x1234567812345678, 0x3333, args)) using (var answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
(var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result;
Assert.AreEqual<ulong>(0x1234567812345678, interfaceId); Assert.AreEqual<ulong>(0x1234567812345678, interfaceId);
Assert.AreEqual<ushort>(0x3333, methodId); Assert.AreEqual<ushort>(0x3333, methodId);
@ -235,7 +238,7 @@ namespace Capnp.Net.Runtime.Tests
ctx = ct; ctx = ct;
} }
Assert.IsTrue(SpinWait.SpinUntil(() => ctx.IsCancellationRequested, MediumTimeout)); Assert.IsTrue(SpinWait.SpinUntil(() => ctx.IsCancellationRequested, MediumNonDbgTimeout));
} }
finally finally
{ {
@ -256,13 +259,13 @@ namespace Capnp.Net.Runtime.Tests
try try
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
@ -270,7 +273,7 @@ namespace Capnp.Net.Runtime.Tests
IPromisedAnswer answer; IPromisedAnswer answer;
using (answer = main.Call(0x1234567812345678, 0x3333, args)) using (answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
(var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result;
Assert.AreEqual<ulong>(0x1234567812345678, interfaceId); Assert.AreEqual<ulong>(0x1234567812345678, interfaceId);
Assert.AreEqual<ushort>(0x3333, methodId); Assert.AreEqual<ushort>(0x3333, methodId);
@ -279,7 +282,7 @@ namespace Capnp.Net.Runtime.Tests
ctx = ct; ctx = ct;
} }
Assert.IsTrue(SpinWait.SpinUntil(() => ctx.IsCancellationRequested, MediumTimeout)); Assert.IsTrue(SpinWait.SpinUntil(() => ctx.IsCancellationRequested, MediumNonDbgTimeout));
var mbr = MessageBuilder.Create(); var mbr = MessageBuilder.Create();
mbr.InitCapTable(); mbr.InitCapTable();
@ -290,7 +293,7 @@ namespace Capnp.Net.Runtime.Tests
// Even after the client cancelled the call, the server must still send // Even after the client cancelled the call, the server must still send
// a response. // a response.
Assert.IsTrue(answer.WhenReturned.ContinueWith(t => { }).Wait(MediumTimeout)); Assert.IsTrue(answer.WhenReturned.ContinueWith(t => { }).Wait(MediumNonDbgTimeout));
} }
finally finally
{ {
@ -315,19 +318,19 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
using (var answer = main.Call(0x1234567812345678, 0x3333, args)) using (var answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
(var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result;
Assert.AreEqual<ulong>(0x1234567812345678, interfaceId); Assert.AreEqual<ulong>(0x1234567812345678, interfaceId);
Assert.AreEqual<ushort>(0x3333, methodId); Assert.AreEqual<ushort>(0x3333, methodId);
@ -337,7 +340,7 @@ namespace Capnp.Net.Runtime.Tests
mock.Return.SetException(new MyTestException()); mock.Return.SetException(new MyTestException());
var exTask = Assert.ThrowsExceptionAsync<RpcException>(() => answer.WhenReturned); var exTask = Assert.ThrowsExceptionAsync<RpcException>(() => answer.WhenReturned);
Assert.IsTrue(exTask.Wait(MediumTimeout)); Assert.IsTrue(exTask.Wait(MediumNonDbgTimeout));
Assert.IsTrue(exTask.Result.Message.Contains(new MyTestException().Message)); Assert.IsTrue(exTask.Result.Message.Contains(new MyTestException().Message));
} }
} }
@ -352,19 +355,19 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
using (var answer = main.Call(0x1234567812345678, 0x3333, args)) using (var answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
var pipelined = (BareProxy)CapabilityReflection.CreateProxy<BareProxy>(answer.Access( var pipelined = (BareProxy)CapabilityReflection.CreateProxy<BareProxy>(answer.Access(
new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) }))); new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) })));
@ -391,10 +394,10 @@ namespace Capnp.Net.Runtime.Tests
mock.Return.SetResult(result); mock.Return.SetResult(result);
Assert.IsTrue(answer.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout));
Assert.IsFalse(ct.IsCancellationRequested); Assert.IsFalse(ct.IsCancellationRequested);
Assert.IsTrue(mock2.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock2.WhenCalled.Wait(MediumNonDbgTimeout));
(var interfaceId2, var methodId2, var inargs2, var ct2) = mock2.WhenCalled.Result; (var interfaceId2, var methodId2, var inargs2, var ct2) = mock2.WhenCalled.Result;
Assert.AreEqual<ulong>(0x8765432187654321, interfaceId2); Assert.AreEqual<ulong>(0x8765432187654321, interfaceId2);
@ -407,7 +410,7 @@ namespace Capnp.Net.Runtime.Tests
result2.WriteData(0, 222222); result2.WriteData(0, 222222);
mock2.Return.SetResult(result2); mock2.Return.SetResult(result2);
Assert.IsTrue(answer2.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer2.WhenReturned.Wait(MediumNonDbgTimeout));
var outresult2 = answer2.WhenReturned.Result; var outresult2 = answer2.WhenReturned.Result;
Assert.AreEqual(ObjectKind.Struct, outresult2.Kind); Assert.AreEqual(ObjectKind.Struct, outresult2.Kind);
Assert.AreEqual(222222, outresult2.ReadDataInt(0)); Assert.AreEqual(222222, outresult2.ReadDataInt(0));
@ -425,19 +428,19 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
using (var answer = main.Call(0x1234567812345678, 0x3333, args)) using (var answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
(var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result; (var interfaceId, var methodId, var inargs, var ct) = mock.WhenCalled.Result;
Assert.AreEqual<ulong>(0x1234567812345678, interfaceId); Assert.AreEqual<ulong>(0x1234567812345678, interfaceId);
@ -467,8 +470,8 @@ namespace Capnp.Net.Runtime.Tests
using (var answer2 = pipelined.Call(0x8765432187654321, 0x4444, args2)) using (var answer2 = pipelined.Call(0x8765432187654321, 0x4444, args2))
{ {
Assert.IsTrue(answer.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout));
Assert.IsTrue(mock2.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock2.WhenCalled.Wait(MediumNonDbgTimeout));
(var interfaceId2, var methodId2, var inargs2, var ct2) = mock2.WhenCalled.Result; (var interfaceId2, var methodId2, var inargs2, var ct2) = mock2.WhenCalled.Result;
Assert.AreEqual<ulong>(0x8765432187654321, interfaceId2); Assert.AreEqual<ulong>(0x8765432187654321, interfaceId2);
@ -481,7 +484,7 @@ namespace Capnp.Net.Runtime.Tests
result2.WriteData(0, 222222); result2.WriteData(0, 222222);
mock2.Return.SetResult(result2); mock2.Return.SetResult(result2);
Assert.IsTrue(answer2.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer2.WhenReturned.Wait(MediumNonDbgTimeout));
var outresult2 = answer2.WhenReturned.Result; var outresult2 = answer2.WhenReturned.Result;
Assert.AreEqual(ObjectKind.Struct, outresult2.Kind); Assert.AreEqual(ObjectKind.Struct, outresult2.Kind);
Assert.AreEqual(222222, outresult2.ReadDataInt(0)); Assert.AreEqual(222222, outresult2.ReadDataInt(0));
@ -501,19 +504,19 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
using (var answer = main.Call(0x1234567812345678, 0x3333, args)) using (var answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
var pipelined = (BareProxy)CapabilityReflection.CreateProxy<BareProxy>(answer.Access(new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) }))); var pipelined = (BareProxy)CapabilityReflection.CreateProxy<BareProxy>(answer.Access(new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) })));
@ -545,7 +548,7 @@ namespace Capnp.Net.Runtime.Tests
mock.Return.SetResult(result); mock.Return.SetResult(result);
Assert.IsTrue(answer.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer.WhenReturned.Wait(MediumNonDbgTimeout));
Assert.IsFalse(ct.IsCancellationRequested); Assert.IsFalse(ct.IsCancellationRequested);
var args4 = DynamicSerializerState.CreateForRpc(); var args4 = DynamicSerializerState.CreateForRpc();
@ -564,10 +567,10 @@ namespace Capnp.Net.Runtime.Tests
var call4 = mock2.WhenCalled; var call4 = mock2.WhenCalled;
var call5 = mock2.WhenCalled; var call5 = mock2.WhenCalled;
Assert.IsTrue(call2.Wait(MediumTimeout)); Assert.IsTrue(call2.Wait(MediumNonDbgTimeout));
Assert.IsTrue(call3.Wait(MediumTimeout)); Assert.IsTrue(call3.Wait(MediumNonDbgTimeout));
Assert.IsTrue(call4.Wait(MediumTimeout)); Assert.IsTrue(call4.Wait(MediumNonDbgTimeout));
Assert.IsTrue(call5.Wait(MediumTimeout)); Assert.IsTrue(call5.Wait(MediumNonDbgTimeout));
Assert.AreEqual<ulong>(0x1111111111111111, call2.Result.InterfaceId); Assert.AreEqual<ulong>(0x1111111111111111, call2.Result.InterfaceId);
Assert.AreEqual<ulong>(0x2222222222222222, call3.Result.InterfaceId); Assert.AreEqual<ulong>(0x2222222222222222, call3.Result.InterfaceId);
@ -594,10 +597,10 @@ namespace Capnp.Net.Runtime.Tests
ret5.WriteData(0, -4); ret5.WriteData(0, -4);
call5.Result.Result.SetResult(ret5); call5.Result.Result.SetResult(ret5);
Assert.IsTrue(answer2.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer2.WhenReturned.Wait(MediumNonDbgTimeout));
Assert.IsTrue(answer3.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer3.WhenReturned.Wait(MediumNonDbgTimeout));
Assert.IsTrue(answer4.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer4.WhenReturned.Wait(MediumNonDbgTimeout));
Assert.IsTrue(answer5.WhenReturned.Wait(MediumTimeout)); Assert.IsTrue(answer5.WhenReturned.Wait(MediumNonDbgTimeout));
Assert.AreEqual(-1, answer2.WhenReturned.Result.ReadDataInt(0)); Assert.AreEqual(-1, answer2.WhenReturned.Result.ReadDataInt(0));
Assert.AreEqual(-2, answer3.WhenReturned.Result.ReadDataInt(0)); Assert.AreEqual(-2, answer3.WhenReturned.Result.ReadDataInt(0));
@ -618,20 +621,20 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
BareProxy pipelined; BareProxy pipelined;
using (var answer = main.Call(0x1234567812345678, 0x3333, args)) using (var answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
pipelined = (BareProxy)CapabilityReflection.CreateProxy<BareProxy>( pipelined = (BareProxy)CapabilityReflection.CreateProxy<BareProxy>(
answer.Access(new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) }))); answer.Access(new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) })));
@ -665,20 +668,20 @@ namespace Capnp.Net.Runtime.Tests
using (client) using (client)
{ {
client.WhenConnected.Wait(); client.WhenConnected.Wait();
SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumTimeout); SpinWait.SpinUntil(() => server.ConnectionCount > 0, MediumNonDbgTimeout);
Assert.AreEqual(1, server.ConnectionCount); Assert.AreEqual(1, server.ConnectionCount);
var mock = new ProvidedCapabilityMock(); var mock = new ProvidedCapabilityMock();
server.Main = mock; server.Main = mock;
var main = client.GetMain<BareProxy>(); var main = client.GetMain<BareProxy>();
Assert.IsTrue(main.WhenResolved.Wait(MediumTimeout)); Assert.IsTrue(main.WhenResolved.Wait(MediumNonDbgTimeout));
var args = DynamicSerializerState.CreateForRpc(); var args = DynamicSerializerState.CreateForRpc();
args.SetStruct(1, 0); args.SetStruct(1, 0);
args.WriteData(0, 123456); args.WriteData(0, 123456);
IPromisedAnswer answer2; IPromisedAnswer answer2;
using (var answer = main.Call(0x1234567812345678, 0x3333, args)) using (var answer = main.Call(0x1234567812345678, 0x3333, args))
{ {
Assert.IsTrue(mock.WhenCalled.Wait(MediumTimeout)); Assert.IsTrue(mock.WhenCalled.Wait(MediumNonDbgTimeout));
var pipelined = (BareProxy)CapabilityReflection.CreateProxy<BareProxy>(answer.Access(new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) }))); var pipelined = (BareProxy)CapabilityReflection.CreateProxy<BareProxy>(answer.Access(new MemberAccessPath(new MemberAccessPath.MemberAccess[] { new MemberAccessPath.StructMemberAccess(1) })));
@ -696,7 +699,7 @@ namespace Capnp.Net.Runtime.Tests
var tcs = new TaskCompletionSource<int>(); var tcs = new TaskCompletionSource<int>();
using (ct.Register(() => tcs.SetResult(0))) using (ct.Register(() => tcs.SetResult(0)))
{ {
Assert.IsTrue(tcs.Task.Wait(MediumTimeout)); Assert.IsTrue(tcs.Task.Wait(MediumNonDbgTimeout));
} }
var mock2 = new ProvidedCapabilityMock(); var mock2 = new ProvidedCapabilityMock();
@ -710,9 +713,100 @@ namespace Capnp.Net.Runtime.Tests
mock.Return.SetResult(result); mock.Return.SetResult(result);
Assert.IsTrue(Assert.ThrowsExceptionAsync<TaskCanceledException>( Assert.IsTrue(Assert.ThrowsExceptionAsync<TaskCanceledException>(
() => answer2.WhenReturned).Wait(MediumTimeout)); () => answer2.WhenReturned).Wait(MediumNonDbgTimeout));
} }
} }
} }
[TestMethod]
public void Server()
{
var cbb = new BufferBlock<IConnection>();
var server = new TcpRpcServer();
server.Main = new TestInterfaceImpl2();
bool init = true;
var tracer = new FrameTracing.RpcFrameTracer(Console.Out);
server.OnConnectionChanged += (s, a) =>
{
var c = a.Connection;
if (init)
{
Assert.ThrowsException<ArgumentNullException>(() => c.AttachTracer(null));
c.AttachTracer(tracer);
Assert.ThrowsException<ArgumentNullException>(() => c.InjectMidlayer(null));
c.InjectMidlayer(_ => _);
Assert.IsFalse(c.IsComputing);
Assert.IsFalse(c.IsWaitingForData);
Assert.AreEqual(ConnectionState.Initializing, c.State);
Assert.IsNotNull(c.RemotePort);
Assert.AreEqual(TcpPort, c.LocalPort);
Assert.AreEqual(0L, c.RecvCount);
Assert.AreEqual(0L, c.SendCount);
}
else
{
Assert.ThrowsException<InvalidOperationException>(() => c.AttachTracer(tracer));
Assert.ThrowsException<InvalidOperationException>(() => c.InjectMidlayer(_ => _));
Assert.AreEqual(ConnectionState.Down, c.State);
}
cbb.Post(c);
};
Assert.ThrowsException<InvalidOperationException>(() => server.StopListening());
server.StartAccepting(IPAddress.Any, TcpPort);
Assert.IsTrue(server.IsAlive);
Assert.ThrowsException<InvalidOperationException>(() => server.StartAccepting(IPAddress.Any, TcpPort));
var server2 = new TcpRpcServer();
Assert.ThrowsException<SocketException>(() => server2.StartAccepting(IPAddress.Any, TcpPort));
var client1 = new TcpRpcClient("localhost", TcpPort);
var c1 = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout));
Assert.IsNotNull(c1);
Assert.AreEqual(1, server.ConnectionCount);
Assert.AreEqual(c1, server.Connections[0]);
Assert.AreEqual(ConnectionState.Active, c1.State);
var proxy = client1.GetMain<ITestInterface>();
Assert.IsTrue(proxy is IResolvingCapability r && r.WhenResolved.Wait(MediumNonDbgTimeout));
Assert.IsTrue(c1.RecvCount > 0);
Assert.IsTrue(c1.SendCount > 0);
var client2 = new TcpRpcClient("localhost", TcpPort);
var c2 = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout));
Assert.IsNotNull(c2);
Assert.AreEqual(2, server.ConnectionCount);
Assert.AreEqual(c2, server.Connections[1]);
init = false;
client1.Dispose();
var c1d = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout));
Assert.IsNotNull(c1d);
Assert.AreEqual(1, server.ConnectionCount);
Assert.AreEqual(c2, server.Connections[0]);
Assert.IsTrue(SpinWait.SpinUntil(() => c1d.State == ConnectionState.Down, MediumNonDbgTimeout));
client2.Dispose();
var c2d = cbb.Receive(TimeSpan.FromMilliseconds(MediumNonDbgTimeout));
Assert.IsNotNull(c2d);
Assert.AreEqual(0, server.ConnectionCount);
Assert.IsTrue(SpinWait.SpinUntil(() => c2d.State == ConnectionState.Down, MediumNonDbgTimeout));
server.StopListening();
Assert.IsFalse(server.IsAlive);
Assert.ThrowsException<InvalidOperationException>(() => server.StopListening());
for (int i = 0; i < 100; i++)
{
server.StartAccepting(IPAddress.Any, TcpPort);
Assert.IsTrue(server.IsAlive);
server.StopListening();
Assert.IsFalse(server.IsAlive);
}
server.Dispose();
}
} }
} }

View File

@ -203,6 +203,10 @@ namespace Capnp
GetRawBytes(); GetRawBytes();
break; break;
case ObjectKind.ListOfShorts:
GetRawShorts();
break;
case ObjectKind.ListOfInts: case ObjectKind.ListOfInts:
GetRawInts(); GetRawInts();
break; break;
@ -303,6 +307,8 @@ namespace Capnp
case ListKind.ListOfStructs: case ListKind.ListOfStructs:
{ {
if (Offset >= CurrentSegment.Length)
throw new DeserializationException("List of composites pointer exceeds segment bounds");
WirePointer tag = CurrentSegment[Offset]; WirePointer tag = CurrentSegment[Offset];
if (tag.Kind != PointerKind.Struct) if (tag.Kind != PointerKind.Struct)
throw new DeserializationException("Unexpected: List of composites with non-struct type tag"); throw new DeserializationException("Unexpected: List of composites with non-struct type tag");
@ -326,6 +332,10 @@ namespace Capnp
if (pointer.IsDoubleFar) if (pointer.IsDoubleFar)
{ {
CurrentSegmentIndex = pointer.TargetSegmentIndex; CurrentSegmentIndex = pointer.TargetSegmentIndex;
if (pointer.LandingPadOffset >= CurrentSegment.Length - 1)
throw new DeserializationException("Error decoding double-far pointer: exceeds segment bounds");
Offset = 0; Offset = 0;
WirePointer pointer1 = CurrentSegment[pointer.LandingPadOffset]; WirePointer pointer1 = CurrentSegment[pointer.LandingPadOffset];
@ -373,14 +383,14 @@ namespace Capnp
/// </summary> /// </summary>
/// <param name="offset">Offset relative to this.Offset within current segment</param> /// <param name="offset">Offset relative to this.Offset within current segment</param>
/// <returns>the low-level capability object, or null if it is a null pointer</returns> /// <returns>the low-level capability object, or null if it is a null pointer</returns>
/// <exception cref="IndexOutOfRangeException">offset negative or out of range</exception> /// <exception cref="ArgumentOutOfRangeException">offset negative or out of range</exception>
/// <exception cref="InvalidOperationException">capability table not set</exception> /// <exception cref="InvalidOperationException">capability table not set</exception>
/// <exception cref="Rpc.RpcException">not a capability pointer or invalid capability index</exception> /// <exception cref="Rpc.RpcException">not a capability pointer or invalid capability index</exception>
internal Rpc.ConsumedCapability? DecodeCapPointer(int offset) internal Rpc.ConsumedCapability? DecodeCapPointer(int offset)
{ {
if (offset < 0) if (offset < 0)
{ {
throw new IndexOutOfRangeException(nameof(offset)); throw new ArgumentOutOfRangeException(nameof(offset));
} }
if (Caps == null) if (Caps == null)
@ -677,7 +687,7 @@ namespace Capnp
throw new DeserializationException("Expected a capability"); throw new DeserializationException("Expected a capability");
if (Caps == null) if (Caps == null)
throw new InvalidOperationException("Capability table not set. This is a bug."); throw new InvalidOperationException("Capability table not set");
return (Rpc.CapabilityReflection.CreateProxy<T>(Caps[(int)CapabilityIndex]) as T)!; return (Rpc.CapabilityReflection.CreateProxy<T>(Caps[(int)CapabilityIndex]) as T)!;
} }

View File

@ -18,15 +18,26 @@ namespace Capnp.FrameTracing
readonly Stopwatch _timer = new Stopwatch(); readonly Stopwatch _timer = new Stopwatch();
readonly TextWriter _traceWriter; readonly TextWriter _traceWriter;
readonly bool _disposeWriter;
/// <summary> /// <summary>
/// Constructs an instance /// Constructs an instance
/// </summary> /// </summary>
/// <param name="traceWriter">textual logging target</param> /// <param name="traceWriter">textual logging target</param>
public RpcFrameTracer(TextWriter traceWriter) public RpcFrameTracer(TextWriter traceWriter): this(traceWriter, true)
{
}
/// <summary>
/// Constructs an instance
/// </summary>
/// <param name="traceWriter">textual logging target</param>
/// <param name="dispose">whether to dispose the writer when tracing is finished</param>
public RpcFrameTracer(TextWriter traceWriter, bool dispose)
{ {
_traceWriter = traceWriter ?? throw new ArgumentNullException(nameof(traceWriter)); _traceWriter = traceWriter ?? throw new ArgumentNullException(nameof(traceWriter));
_traceWriter.WriteLine(Header); _traceWriter.WriteLine(Header);
_disposeWriter = dispose;
} }
/// <summary> /// <summary>
@ -35,6 +46,7 @@ namespace Capnp.FrameTracing
public void Dispose() public void Dispose()
{ {
_traceWriter.WriteLine("<end of trace>"); _traceWriter.WriteLine("<end of trace>");
if (_disposeWriter)
_traceWriter.Dispose(); _traceWriter.Dispose();
} }