using Capnp.Rpc; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading; using System.Threading.Tasks; using Capnproto_test.Capnp.Test; using CapnpGen; namespace Capnp.Net.Runtime.Tests.GenImpls { class Common { static byte[] Data(string s) => System.Text.Encoding.UTF8.GetBytes(s); static bool DataSequenceEqual(IEnumerable> seq1, IEnumerable> seq2) { return seq1.Zip(seq2, (s1, s2) => s1.SequenceEqual(s2)).All(_ => _); } public static void InitTestMessage(TestAllTypes s) { s.BoolField = true; s.Int8Field = -123; s.Int16Field = -12345; s.Int32Field = -12345678; s.Int64Field = -123456789012345; s.UInt8Field = 234; s.UInt16Field = 45678; s.UInt32Field = 3456789012; s.UInt64Field = 12345678901234567890; s.Float32Field = 1234.5f; s.Float64Field = -123e45; s.TextField = "foo"; s.DataField = Data("bar"); { s.StructField = new TestAllTypes(); var sub = s.StructField; sub.BoolField = true; sub.Int8Field = -12; sub.Int16Field = 3456; sub.Int32Field = -78901234; sub.Int64Field = 56789012345678; sub.UInt8Field = 90; sub.UInt16Field = 1234; sub.UInt32Field = 56789012; sub.UInt64Field = 345678901234567890; sub.Float32Field = -1.25e-10f; sub.Float64Field = 345; sub.TextField = "baz"; sub.DataField = Data("qux"); { sub.StructField = new TestAllTypes() { TextField = "nested", StructField = new TestAllTypes() { TextField = "really nested" } }; } sub.EnumField = TestEnum.baz; sub.VoidList = 3; sub.BoolList = new bool[] { false, true, false, true, true }; sub.Int8List = new sbyte[] { 12, -34, -0x80, 0x7f }; sub.Int16List = new short[] { 1234, -5678, -0x8000, 0x7fff }; sub.Int32List = new int[] { 12345678, -90123456, -0x7fffffff - 1, 0x7fffffff }; sub.Int64List = new long[] { 123456789012345, -678901234567890, -0x7fffffffffffffff - 1, 0x7fffffffffffffff }; sub.UInt8List = new byte[] { 12, 34, 0, 0xff }; sub.UInt16List = new ushort[] { 1234, 5678, 0, 0xffff }; sub.UInt32List = new uint[] { 12345678u, 90123456u, 0u, 0xffffffffu }; sub.UInt64List = new ulong[] { 123456789012345, 678901234567890, 0, 0xffffffffffffffff }; sub.Float32List = new float[] { 0, 1234567, 1e37f, -1e37f, 1e-37f, -1e-37f }; sub.Float64List = new double[] { 0, 123456789012345, 1e306, -1e306, 1e-306, -1e-306 }; sub.TextList = new string[] { "quux", "corge", "grault" }; sub.DataList = new byte[][] { Data("garply"), Data("waldo"), Data("fred") }; sub.StructList = new TestAllTypes[] { new TestAllTypes() { TextField = "x structlist 1" }, new TestAllTypes() { TextField = "x structlist 2" }, new TestAllTypes() { TextField = "x structlist 3" } }; sub.EnumList = new TestEnum[] { TestEnum.qux, TestEnum.bar, TestEnum.grault }; } s.EnumField = TestEnum.corge; s.VoidList = 6; s.BoolList = new bool[] { true, false, false, true }; s.Int8List = new sbyte[] { 111, -111 }; s.Int16List = new short[] { 11111, -11111 }; s.Int32List = new int[] { 111111111, -111111111 }; s.Int64List = new long[] { 1111111111111111111, -1111111111111111111 }; s.UInt8List = new byte[] { 111, 222 }; s.UInt16List = new ushort[] { 33333, 44444 }; s.UInt32List = new uint[] { 3333333333 }; s.UInt64List = new ulong[] { 11111111111111111111 }; s.Float32List = new float[] { 5555.5f, float.PositiveInfinity, float.NegativeInfinity, float.NaN }; s.Float64List = new double[] { 7777.75, double.PositiveInfinity, double.NegativeInfinity, double.NaN }; s.TextList = new string[] { "plugh", "xyzzy", "thud" }; s.DataList = new byte[][] { Data("oops"), Data("exhausted"), Data("rfc3092") }; { s.StructList = new TestAllTypes[] { new TestAllTypes() { TextField = "structlist 1" }, new TestAllTypes() { TextField = "structlist 2" }, new TestAllTypes() { TextField = "structlist 3" } }; } s.EnumList = new TestEnum[] { TestEnum.foo, TestEnum.garply }; } public static void CheckTestMessage(TestAllTypes s) { var sub = s.StructField; Assert.IsTrue(sub.BoolField); Assert.AreEqual(-12, sub.Int8Field); Assert.AreEqual(3456, sub.Int16Field); Assert.AreEqual(-78901234, sub.Int32Field); Assert.AreEqual(56789012345678, sub.Int64Field); Assert.AreEqual(90, sub.UInt8Field); Assert.AreEqual(1234, sub.UInt16Field); Assert.AreEqual(56789012u, sub.UInt32Field); Assert.AreEqual(345678901234567890ul, sub.UInt64Field); Assert.AreEqual(-1.25e-10f, sub.Float32Field); Assert.AreEqual(345.0, sub.Float64Field); Assert.AreEqual("baz", sub.TextField); Assert.IsTrue(Data("qux").SequenceEqual(sub.DataField)); { var subsub = sub.StructField; Assert.AreEqual("nested", subsub.TextField); Assert.AreEqual("really nested", subsub.StructField.TextField); } Assert.AreEqual(TestEnum.baz, sub.EnumField); Assert.AreEqual(3, sub.VoidList); Assert.IsTrue(sub.BoolList.SequenceEqual(new bool[] { false, true, false, true, true })); Assert.IsTrue(sub.Int8List.SequenceEqual(new sbyte[] { 12, -34, -0x80, 0x7f })); Assert.IsTrue(sub.Int16List.SequenceEqual(new short[] { 1234, -5678, -0x8000, 0x7fff })); Assert.IsTrue(sub.Int32List.SequenceEqual(new int[] { 12345678, -90123456, -0x7fffffff - 1, 0x7fffffff })); Assert.IsTrue(sub.Int64List.SequenceEqual(new long[] { 123456789012345, -678901234567890, -0x7fffffffffffffff - 1, 0x7fffffffffffffff })); Assert.IsTrue(sub.UInt8List.SequenceEqual(new byte[] { 12, 34, 0, 0xff })); Assert.IsTrue(sub.UInt16List.SequenceEqual(new ushort[] { 1234, 5678, 0, 0xffff })); Assert.IsTrue(sub.UInt32List.SequenceEqual(new uint[] { 12345678, 90123456, 0u, 0xffffffff })); Assert.IsTrue(sub.UInt64List.SequenceEqual(new ulong[] { 123456789012345, 678901234567890, 0, 0xffffffffffffffff })); Assert.IsTrue(sub.Float32List.SequenceEqual(new float[] { 0.0f, 1234567.0f, 1e37f, -1e37f, 1e-37f, -1e-37f })); Assert.IsTrue(sub.Float64List.SequenceEqual(new double[] { 0.0, 123456789012345.0, 1e306, -1e306, 1e-306, -1e-306 })); Assert.IsTrue(sub.TextList.SequenceEqual(new string[] { "quux", "corge", "grault" })); Assert.IsTrue(DataSequenceEqual(sub.DataList, new byte[][] { Data("garply"), Data("waldo"), Data("fred") })); { var list = sub.StructList; Assert.AreEqual(3, list.Count); Assert.AreEqual("x structlist 1", list[0].TextField); Assert.AreEqual("x structlist 2", list[1].TextField); Assert.AreEqual("x structlist 3", list[2].TextField); } Assert.IsTrue(sub.EnumList.SequenceEqual(new TestEnum[] { TestEnum.qux, TestEnum.bar, TestEnum.grault })); Assert.AreEqual(TestEnum.corge, s.EnumField); Assert.AreEqual(6, s.VoidList); Assert.IsTrue(s.BoolList.SequenceEqual(new bool[] { true, false, false, true })); Assert.IsTrue(s.Int8List.SequenceEqual(new sbyte[] { 111, -111 })); Assert.IsTrue(s.Int16List.SequenceEqual(new short[] { 11111, -11111 })); Assert.IsTrue(s.Int32List.SequenceEqual(new int[] { 111111111, -111111111 })); Assert.IsTrue(s.Int64List.SequenceEqual(new long[] { 1111111111111111111, -1111111111111111111 })); Assert.IsTrue(s.UInt8List.SequenceEqual(new byte[] { 111, 222 })); Assert.IsTrue(s.UInt16List.SequenceEqual(new ushort[] { 33333, 44444 })); Assert.IsTrue(s.UInt32List.SequenceEqual(new uint[] { 3333333333 })); Assert.IsTrue(s.UInt64List.SequenceEqual(new ulong[] { 11111111111111111111 })); { var list = s.Float32List; Assert.AreEqual(4, list.Count); Assert.AreEqual(5555.5f, list[0]); Assert.AreEqual(float.PositiveInfinity, list[1]); Assert.AreEqual(float.NegativeInfinity, list[2]); Assert.IsTrue(float.IsNaN(list[3])); } { var list = s.Float64List; Assert.AreEqual(4, list.Count); Assert.AreEqual(7777.75, list[0]); Assert.IsTrue(double.IsPositiveInfinity(list[1])); Assert.IsTrue(double.IsNegativeInfinity(list[2])); Assert.IsTrue(double.IsNaN(list[3])); } Assert.IsTrue(s.TextList.SequenceEqual(new string[] { "plugh", "xyzzy", "thud" })); Assert.IsTrue(DataSequenceEqual(s.DataList, new byte[][] { Data("oops"), Data("exhausted"), Data("rfc3092") })); { var list = s.StructList; Assert.AreEqual(3, list.Count); Assert.AreEqual("structlist 1", list[0].TextField); Assert.AreEqual("structlist 2", list[1].TextField); Assert.AreEqual("structlist 3", list[2].TextField); } Assert.IsTrue(s.EnumList.SequenceEqual(new TestEnum[] { TestEnum.foo, TestEnum.garply })); } public static void CheckTestMessageAllZero(TestAllTypes s) { Assert.IsFalse(s.BoolField); Assert.AreEqual(0, s.Int8Field); Assert.AreEqual(0, s.Int16Field); Assert.AreEqual(0, s.Int32Field); Assert.AreEqual(0, s.Int64Field); Assert.AreEqual(0, s.UInt8Field); Assert.AreEqual(0, s.UInt16Field); Assert.AreEqual(0, s.UInt32Field); Assert.AreEqual(0, s.UInt64Field); Assert.AreEqual(0f, s.Float32Field); Assert.AreEqual(0.0, s.Float64Field); Assert.AreEqual(string.Empty, s.TextField); Assert.IsTrue(Data(string.Empty).SequenceEqual(s.DataField)); { var sub = s.StructField; Assert.IsFalse(sub.BoolField); Assert.AreEqual(0, sub.Int8Field); Assert.AreEqual(0, sub.Int16Field); Assert.AreEqual(0, sub.Int32Field); Assert.AreEqual(0, sub.Int64Field); Assert.AreEqual(0, sub.UInt8Field); Assert.AreEqual(0, sub.UInt16Field); Assert.AreEqual(0, sub.UInt32Field); Assert.AreEqual(0, sub.UInt64Field); Assert.AreEqual(0f, sub.Float32Field); Assert.AreEqual(0.0, sub.Float64Field); Assert.AreEqual(string.Empty, sub.TextField); Assert.AreEqual(Data(string.Empty), sub.DataField); { var subsub = sub.StructField; Assert.AreEqual(string.Empty, subsub.TextField); Assert.AreEqual(string.Empty, subsub.StructField.TextField); } Assert.AreEqual(0, sub.VoidList); Assert.AreEqual(0, sub.BoolList.Count); Assert.AreEqual(0, sub.Int8List.Count); Assert.AreEqual(0, sub.Int16List.Count); Assert.AreEqual(0, sub.Int32List.Count); Assert.AreEqual(0, sub.Int64List.Count); Assert.AreEqual(0, sub.UInt8List.Count); Assert.AreEqual(0, sub.UInt16List.Count); Assert.AreEqual(0, sub.UInt32List.Count); Assert.AreEqual(0, sub.UInt64List.Count); Assert.AreEqual(0, sub.Float32List.Count); Assert.AreEqual(0, sub.Float64List.Count); Assert.AreEqual(0, sub.TextList.Count); Assert.AreEqual(0, sub.DataList.Count); Assert.AreEqual(0, sub.StructList.Count); } Assert.AreEqual(0, s.VoidList); Assert.AreEqual(0, s.BoolList.Count); Assert.AreEqual(0, s.Int8List.Count); Assert.AreEqual(0, s.Int16List.Count); Assert.AreEqual(0, s.Int32List.Count); Assert.AreEqual(0, s.Int64List.Count); Assert.AreEqual(0, s.UInt8List.Count); Assert.AreEqual(0, s.UInt16List.Count); Assert.AreEqual(0, s.UInt32List.Count); Assert.AreEqual(0, s.UInt64List.Count); Assert.AreEqual(0, s.Float32List.Count); Assert.AreEqual(0, s.Float64List.Count); Assert.AreEqual(0, s.TextList.Count); Assert.AreEqual(0, s.DataList.Count); Assert.AreEqual(0, s.StructList.Count); } public static void InitListDefaults(TestLists lists) { lists.List0 = new TestLists.Struct0[] { new TestLists.Struct0(), new TestLists.Struct0() }; lists.List1 = new TestLists.Struct1[] { new TestLists.Struct1() { F = true }, new TestLists.Struct1() { F = false }, new TestLists.Struct1() { F = true }, new TestLists.Struct1() { F = true } }; lists.List8 = new TestLists.Struct8[] { new TestLists.Struct8() { F = 123 }, new TestLists.Struct8() { F = 45 } }; lists.List16 = new TestLists.Struct16[] { new TestLists.Struct16() { F = 12345 }, new TestLists.Struct16() { F = 6789 } }; lists.List32 = new TestLists.Struct32[] { new TestLists.Struct32() { F = 123456789 }, new TestLists.Struct32() { F = 234567890 } }; lists.List64 = new TestLists.Struct64[] { new TestLists.Struct64() { F = 1234567890123456 }, new TestLists.Struct64() { F = 2345678901234567} }; lists.ListP = new TestLists.StructP[] { new TestLists.StructP() { F = "foo" }, new TestLists.StructP() { F = "bar" } }; lists.Int32ListList = new int[][] { new int[] { 1, 2, 3 }, new int[] { 4, 5 }, new int[] { 12341234 } }; lists.TextListList = new string[][] { new string[] { "foo", "bar" }, new string[] { "baz" }, new string[] { "qux", "corge" } }; lists.StructListList = new TestAllTypes[][] { new TestAllTypes[] { new TestAllTypes() { Int32Field = 123 }, new TestAllTypes() { Int32Field = 456 } }, new TestAllTypes[] { new TestAllTypes() { Int32Field = 789 } } }; } public static void CheckListDefault(TestLists lists) { Assert.AreEqual(2, lists.List0.Count); Assert.AreEqual(4, lists.List1.Count); Assert.AreEqual(2, lists.List8.Count); Assert.AreEqual(2, lists.List16.Count); Assert.AreEqual(2, lists.List32.Count); Assert.AreEqual(2, lists.List64.Count); Assert.AreEqual(2, lists.ListP.Count); Assert.IsTrue(lists.List1[0].F); Assert.IsFalse(lists.List1[1].F); Assert.IsTrue(lists.List1[2].F); Assert.IsTrue(lists.List1[3].F); Assert.AreEqual(123, lists.List8[0].F); Assert.AreEqual(45, lists.List8[1].F); Assert.AreEqual(12345, lists.List16[0].F); Assert.AreEqual(6789, lists.List16[1].F); Assert.AreEqual(123456789, lists.List32[0].F); Assert.AreEqual(234567890, lists.List32[1].F); Assert.AreEqual(1234567890123456, lists.List64[0].F); Assert.AreEqual(2345678901234567, lists.List64[1].F); Assert.AreEqual("foo", lists.ListP[0].F); Assert.AreEqual("bar", lists.ListP[1].F); Assert.AreEqual(3, lists.Int32ListList.Count); Assert.IsTrue(lists.Int32ListList[0].SequenceEqual(new int[] { 1, 2, 3 })); Assert.IsTrue(lists.Int32ListList[1].SequenceEqual(new int[] { 4, 5 })); Assert.IsTrue(lists.Int32ListList[2].SequenceEqual(new int[] { 12341234 })); Assert.AreEqual(3, lists.TextListList.Count); Assert.IsTrue(lists.TextListList[0].SequenceEqual(new string[] { "foo", "bar" })); Assert.IsTrue(lists.TextListList[1].SequenceEqual(new string[] { "baz" })); Assert.IsTrue(lists.TextListList[2].SequenceEqual(new string[] { "qux", "corge" })); Assert.AreEqual(2, lists.StructListList.Count); Assert.AreEqual(2, lists.StructListList[0].Count); Assert.AreEqual(123, lists.StructListList[0][0]); Assert.AreEqual(456, lists.StructListList[0][1]); Assert.AreEqual(1, lists.StructListList[1].Count); Assert.AreEqual(789, lists.StructListList[1][0]); } } class Counters { public int CallCount; public int HandleCount; } #region TestInterface class TestInterfaceImpl : ITestInterface { readonly TaskCompletionSource _tcs; protected readonly Counters _counters; public TestInterfaceImpl(Counters counters, TaskCompletionSource tcs) { _tcs = tcs; _counters = counters; } public TestInterfaceImpl(Counters counters) { _counters = counters; } public Task Bar(CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task Baz(TestAllTypes s, CancellationToken cancellationToken) { Interlocked.Increment(ref _counters.CallCount); Common.CheckTestMessage(s); return Task.CompletedTask; } public void Dispose() { _tcs?.TrySetResult(0); Assert.IsFalse(IsDisposed); IsDisposed = true; DisposeCallStack = Environment.StackTrace; } public string DisposeCallStack { get; private set; } public bool IsDisposed { get; private set; } public virtual Task Foo(uint i, bool j, CancellationToken cancellationToken) { Interlocked.Increment(ref _counters.CallCount); Assert.AreEqual(123u, i); Assert.IsTrue(j); return Task.FromResult("foo"); } } class TestInterfaceImpl2 : ITestInterface { public Task Bar(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task Baz(TestAllTypes s, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public void Dispose() { Assert.IsFalse(IsDisposed); IsDisposed = true; } public bool IsDisposed { get; private set; } public Task Foo(uint i, bool j, CancellationToken cancellationToken_ = default) { Assert.AreEqual(123u, i); Assert.IsTrue(j); return Task.FromResult("bar"); } } #endregion TestInterface #region TestExtends class TestExtendsImpl : TestInterfaceImpl, ITestExtends { public TestExtendsImpl(Counters counters) : base(counters) { } public override Task Foo(uint i, bool j, CancellationToken cancellationToken) { Interlocked.Increment(ref _counters.CallCount); Assert.AreEqual(321u, i); Assert.IsFalse(j); return Task.FromResult("bar"); } public Task Corge(TestAllTypes s, CancellationToken cancellationToken) { throw new NotImplementedException(); } public Task Grault(CancellationToken cancellationToken) { Interlocked.Increment(ref _counters.CallCount); var result = new TestAllTypes(); Common.InitTestMessage(result); return Task.FromResult(result); } public Task Qux(CancellationToken cancellationToken) { throw new NotImplementedException(); } } #endregion TestExtends #region TestPipeline class TestPipelineImpl : ITestPipeline { protected readonly Counters _counters; public TestPipelineImpl(Counters counters) { _counters = counters; } public void Dispose() { } public async Task<(string, TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_) { using (inCap) { Interlocked.Increment(ref _counters.CallCount); Assert.AreEqual(234u, n); var s = await inCap.Cast(true).Foo(123, true, cancellationToken_); Assert.AreEqual("foo", s); return ("bar", new TestPipeline.AnyBox() { Cap = BareProxy.FromImpl(new TestExtendsImpl(_counters)) }); } } public async Task<(string, TestPipeline.Box)> GetCap(uint n, ITestInterface inCap, CancellationToken cancellationToken_) { using (inCap) { Interlocked.Increment(ref _counters.CallCount); Assert.AreEqual(234u, n); var s = await inCap.Foo(123, true, cancellationToken_); Assert.AreEqual("foo", s); return ("bar", new TestPipeline.Box() { Cap = new TestExtendsImpl(_counters) }); } } public Task TestPointers(ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_) { throw new NotImplementedException(); } } class TestPipelineImpl2 : ITestPipeline { readonly Task _deblock; readonly TestInterfaceImpl2 _timpl2; public TestPipelineImpl2(Task deblock) { _deblock = deblock; _timpl2 = new TestInterfaceImpl2(); } public void Dispose() { } public bool IsChildCapDisposed => _timpl2.IsDisposed; public Task<(string, TestPipeline.AnyBox)> GetAnyCap(uint n, BareProxy inCap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public async Task<(string, TestPipeline.Box)> GetCap(uint n, ITestInterface inCap, CancellationToken cancellationToken_ = default) { using (inCap) { await _deblock; return ("hello", new TestPipeline.Box() { Cap = _timpl2 }); } } public Task TestPointers(ITestInterface cap, object obj, IReadOnlyList list, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } } #endregion TestPipeline #region TestCallOrder class TestCallOrderImpl : ITestCallOrder { readonly object _lock = new object(); uint _counter; ILogger Logger { get; } = Logging.CreateLogger(); public uint? CountToDispose { get; set; } public void Dispose() { lock (_lock) { Assert.IsTrue(!CountToDispose.HasValue || _counter == CountToDispose, $"Must not dispose at this point: {_counter} {Thread.CurrentThread.Name}"); } } public Task GetCallSequence(uint expected, CancellationToken cancellationToken_) { lock (_lock) { return Task.FromResult(_counter++); } } public uint Count { get { lock (_lock) { return _counter; } } } } #endregion TestCallOrder #region TestTailCaller class TestTailCallerImpl : ITestTailCaller { readonly Counters _counters; public TestTailCallerImpl(Counters counters) { _counters = counters; } public void Dispose() { } public Task Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); using (callee) { return callee.Foo(i, "from TestTailCaller", cancellationToken_); } } } class TestTailCallerImpl2 : ITestTailCaller { ITestCallOrder _keeper; public TestTailCallerImpl2() { } public void Dispose() { _keeper?.Dispose(); } public Task Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_) { using (callee) { if (_keeper == null) { var task = callee.Foo(i, "from TestTailCaller", cancellationToken_); _keeper = task.C(); return task; } else { return Task.FromResult( new TestTailCallee.TailResult() { C = _keeper }); } } } } class TestTailCallerImpl3 : ITestTailCaller { public TestTailCallerImpl3() { } public void Dispose() { } public Task Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_) { using (callee) { var task1 = callee.Foo(i, "from TestTailCaller 1", cancellationToken_); async void FinishTask() { var r = await task1; r.C.Dispose(); } FinishTask(); var task2 = callee.Foo(i, "from TestTailCaller 2", cancellationToken_); async void AssertIsTailCall() { try { await task2; Assert.Fail("Not a tail call"); } catch (TailCallNoDataException) { } } AssertIsTailCall(); return task2; } } } class TestTailCallerImpl4 : ITestTailCaller { public TestTailCallerImpl4() { } public void Dispose() { } public async Task Foo(int i, ITestTailCallee callee, CancellationToken cancellationToken_) { await Task.Yield(); using (callee) { return await callee.Foo(i, "from TestTailCaller", cancellationToken_); } } } #endregion TestTailCaller #region TestTailCallee class TestTailCalleeImpl : ITestTailCallee { readonly Counters _counters; public TestTailCalleeImpl(Counters counters) { _counters = counters; } public void Dispose() { IsDisposed = true; } public bool IsDisposed { get; private set; } public Task Foo(int i, string t, CancellationToken cancellationToken_) { Assert.IsFalse(IsDisposed); Interlocked.Increment(ref _counters.CallCount); var result = new TestTailCallee.TailResult() { I = (uint)i, T = t, C = new TestCallOrderImpl() }; return Task.FromResult(result); } } #endregion TestTailCallee #region TestMoreStuff class TestMoreStuffImpl : ITestMoreStuff { readonly TaskCompletionSource _echoAllowed = new TaskCompletionSource(); readonly Counters _counters; public TestMoreStuffImpl(Counters counters) { _counters = counters; } public ITestInterface ClientToHold { get; set; } public void EnableEcho() { _echoAllowed.SetResult(0); } public async Task CallFoo(ITestInterface cap, CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); using (cap) { string s = await cap.Foo(123, true, cancellationToken_); Assert.AreEqual("foo", s); } return "bar"; } public async Task CallFooWhenResolved(ITestInterface cap, CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); using (cap) { await ((Proxy)cap).WhenResolved; string s = await cap.Foo(123, true, cancellationToken_); Assert.AreEqual("foo", s); } return "bar"; } public async Task CallHeld(CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); string s = await ClientToHold.Foo(123, true, cancellationToken_); Assert.AreEqual("foo", s); return "bar"; } public void Dispose() { ClientToHold?.Dispose(); ClientToHold = null; } public Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); return Task.FromResult(cap); } public Task ExpectCancel(ITestInterface cap, CancellationToken cancellationToken_) { return NeverReturn(cap, cancellationToken_); } public Task GetCallSequence(uint expected, CancellationToken cancellationToken_) { return Task.FromResult((uint)(Interlocked.Increment(ref _counters.CallCount) - 1)); } public Task GetEnormousString(CancellationToken cancellationToken_) { return Task.FromResult(new string(new char[100000000])); } public Task GetHandle(CancellationToken cancellationToken_) { return Task.FromResult((ITestHandle)new TestHandleImpl(_counters)); } public Task GetHeld(CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); return Task.FromResult(Proxy.Share(ClientToHold)); } public Task GetNull(CancellationToken cancellationToken_) { return Task.FromResult(default(ITestMoreStuff)); } public Task Hold(ITestInterface cap, CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); ClientToHold?.Dispose(); ClientToHold = cap; return Task.CompletedTask; } public Task<(string, string)> MethodWithDefaults(string a, uint b, string c, CancellationToken cancellationToken_) { throw new NotImplementedException(); } public Task MethodWithNullDefault(string a, ITestInterface b, CancellationToken cancellationToken_) { throw new NotImplementedException(); } public async Task NeverReturn(ITestInterface cap, CancellationToken cancellationToken_) { Interlocked.Increment(ref _counters.CallCount); try { var tcs = new TaskCompletionSource(); using (cancellationToken_.Register(() => tcs.SetResult(0))) { await tcs.Task; throw new TaskCanceledException(); } } finally { cap.Dispose(); } } } class TestMoreStuffImpl2 : ITestMoreStuff { readonly TaskCompletionSource _echo = new TaskCompletionSource(); readonly TaskCompletionSource _held = new TaskCompletionSource(); ITestCallOrder _cap; int _callCount; public TestMoreStuffImpl2() { } public async Task CallFoo(ITestInterface cap, CancellationToken cancellationToken_) { using (cap) { string s = await cap.Foo(123, true, cancellationToken_); Assert.AreEqual("foo", s); } return "bar"; } public Task CallFooWhenResolved(ITestInterface cap, CancellationToken cancellationToken_) { throw new NotImplementedException(); } public Task CallHeld(CancellationToken cancellationToken_) { throw new NotImplementedException(); } public void Dispose() { } public Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_) { _cap = cap; return Task.FromResult(_echo.Task.Eager(true)); } public void EnableEcho() { _echo.SetResult(_cap); } public Task ExpectCancel(ITestInterface cap, CancellationToken cancellationToken_) { throw new NotImplementedException(); } public Task GetCallSequence(uint expected, CancellationToken cancellationToken_) { return Task.FromResult((uint)(Interlocked.Increment(ref _callCount) - 1)); } public Task GetEnormousString(CancellationToken cancellationToken_) { return Task.FromResult(new string(new char[100000000])); } public Task GetHandle(CancellationToken cancellationToken_) { throw new NotImplementedException(); } public Task GetHeld(CancellationToken cancellationToken_) { return _held.Task; } public Task GetNull(CancellationToken cancellationToken_) { return Task.FromResult(default(ITestMoreStuff)); } public async Task Hold(ITestInterface cap, CancellationToken cancellationToken_) { try { var unwrapped = await cap.Unwrap(); _held.SetResult(unwrapped); } catch (System.Exception exception) when (exception.Message == new TaskCanceledException().Message) { _held.SetCanceled(); } catch (System.Exception exception) { _held.SetException(exception); } } public Task<(string, string)> MethodWithDefaults(string a, uint b, string c, CancellationToken cancellationToken_) { throw new NotImplementedException(); } public Task MethodWithNullDefault(string a, ITestInterface b, CancellationToken cancellationToken_) { throw new NotImplementedException(); } public Task NeverReturn(ITestInterface cap, CancellationToken cancellationToken_) { throw new NotImplementedException(); } } class TestMoreStuffImpl3 : ITestMoreStuff, ITestCallOrder { readonly TaskCompletionSource _heldCap = new TaskCompletionSource(); public Task CallFoo(ITestInterface cap, CancellationToken cancellationToken_ = default) { using (cap) { return cap.Foo(123, true); } } public Task CallFooWhenResolved(ITestInterface Cap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task CallHeld(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public async void Dispose() { using (var cap = await _heldCap.Task) { } } int _echoCounter; public Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_ = default) { if (_echoCounter++ < 20) { return Task.FromResult(((Proxy)cap).Cast(false).Echo(cap).Eager()); } else { return Task.FromResult(cap); } } public Task ExpectCancel(ITestInterface Cap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } uint _counter; public Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) { Assert.AreEqual(_counter, expected); return Task.FromResult(_counter++); } public Task GetEnormousString(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task GetHandle(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public async Task GetHeld(CancellationToken cancellationToken_ = default) { return await _heldCap.Task; } public Task GetNull(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task Hold(ITestInterface Cap, CancellationToken cancellationToken_ = default) { _heldCap.SetResult(Cap); return Task.CompletedTask; } public Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task MethodWithNullDefault(string A, ITestInterface B, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task NeverReturn(ITestInterface Cap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } } class TestMoreStuffImpl4 : ITestMoreStuff, ITestCallOrder { readonly TaskCompletionSource _heldCap = new TaskCompletionSource(); public Task CallFoo(ITestInterface cap, CancellationToken cancellationToken_ = default) { using (cap) { return cap.Foo(123, true); } } public Task CallFooWhenResolved(ITestInterface Cap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task CallHeld(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public async void Dispose() { using (var cap = await _heldCap.Task) { } } public Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_ = default) { using (var target = ((Proxy)cap).Cast(false)) { return Task.FromResult(target.Echo(cap).Eager()); } } public Task ExpectCancel(ITestInterface Cap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } uint _counter; public Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) { Assert.AreEqual(_counter, expected); return Task.FromResult(_counter++); } public Task GetEnormousString(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task GetHandle(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task GetHeld(CancellationToken cancellationToken_ = default) { return Task.FromResult(_heldCap.Task.Eager(true)); } public Task GetNull(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task Hold(ITestInterface Cap, CancellationToken cancellationToken_ = default) { _heldCap.SetResult(Cap); return Task.CompletedTask; } public Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task MethodWithNullDefault(string A, ITestInterface B, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task NeverReturn(ITestInterface Cap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } } class TestMoreStuffImpl5 : ITestMoreStuff, ITestCallOrder { readonly TaskCompletionSource _heldCap = new TaskCompletionSource(); public Task CallFoo(ITestInterface cap, CancellationToken cancellationToken_ = default) { using (cap) { return cap.Foo(123, true); } } public Task CallFooWhenResolved(ITestInterface Cap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task CallHeld(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public async void Dispose() { using (var cap = await _heldCap.Task) { } } TaskCompletionSource _echoEnabled = new TaskCompletionSource(); public void EnableEcho() => _echoEnabled.SetResult(0); public async Task Echo(ITestCallOrder cap, CancellationToken cancellationToken_ = default) { await _echoEnabled.Task; return cap; } public Task ExpectCancel(ITestInterface Cap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } uint _counter; public Task GetCallSequence(uint expected, CancellationToken cancellationToken_ = default) { Assert.AreEqual(_counter, expected); return Task.FromResult(_counter++); } public Task GetEnormousString(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task GetHandle(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task GetHeld(CancellationToken cancellationToken_ = default) { return Task.FromResult(_heldCap.Task.Eager(true)); } public Task GetNull(CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task Hold(ITestInterface Cap, CancellationToken cancellationToken_ = default) { _heldCap.SetResult(Cap); return Task.CompletedTask; } public Task<(string, string)> MethodWithDefaults(string A, uint B, string C, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task MethodWithNullDefault(string A, ITestInterface B, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } public Task NeverReturn(ITestInterface Cap, CancellationToken cancellationToken_ = default) { throw new NotImplementedException(); } } #endregion TestMoreStuff #region TestHandle class TestHandleImpl : ITestHandle, IDisposable { readonly Counters _counters; public TestHandleImpl(Counters counters) { _counters = counters; Interlocked.Increment(ref _counters.HandleCount); } public void Dispose() { Interlocked.Decrement(ref _counters.HandleCount); } } #endregion TestHandle #region B2 class B2Impl : CapnpGen.IB2 { string _s; public void Dispose() { } public Task MethodA(string param1, CancellationToken cancellationToken_ = default) { _s = param1; return Task.CompletedTask; } public Task MethodB(long param1, CancellationToken cancellationToken_ = default) { return Task.FromResult(_s); } } #endregion B2 #region Issue25 class Issue25AImpl : CapnpGen.IIssue25A { public void Dispose() { } public Task MethodA(CancellationToken cancellationToken_ = default) { return Task.FromResult(123L); } } class CapHolderImpl : CapnpGen.ICapHolder where T: class { T _cap; public CapHolderImpl(T cap) { _cap = cap; } public Task Cap(CancellationToken cancellationToken_ = default) { return Task.FromResult(_cap); } public void Dispose() { } } class CapHolderAImpl : CapnpGen.ICapHolderA { IIssue25A _a; public CapHolderAImpl(IIssue25A a) { _a = a; } public Task Cap(CancellationToken cancellationToken_ = default) { return Task.FromResult(_a); } public void Dispose() { } } class Issue25BImpl : CapnpGen.IIssue25B { Issue25AImpl _a = new Issue25AImpl(); public void Dispose() { } public Task> GetAinCapHolderAnyPointer(CancellationToken cancellationToken_ = default) { return Task.FromResult>(new CapHolderImpl(_a)); } public Task> GetAinCapHolderGenericA(CancellationToken cancellationToken_ = default) { return Task.FromResult>(new CapHolderImpl(_a)); } public Task GetAinCapHolderNonGenericA(CancellationToken cancellationToken_ = default) { return Task.FromResult(new CapHolderAImpl(_a)); } } #endregion }