From fc6af91833bb2a35cb9e5705d91f6d47ae25bda5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6llner?= Date: Wed, 26 Feb 2020 22:04:59 +0100 Subject: [PATCH] added cap list serializer TC bugfixes --- .../Capnp.Net.Runtime.Tests.Core21.csproj | 1 - Capnp.Net.Runtime.Tests/SerializationTests.cs | 67 +++++++++++- Capnp.Net.Runtime.Tests/TestInterfaces.cs | 102 ------------------ Capnp.Net.Runtime/ListDeserializer.cs | 2 +- Capnp.Net.Runtime/ListOfBitsSerializer.cs | 4 + Capnp.Net.Runtime/ListOfCapsSerializer.cs | 21 +++- .../ListOfPointersDeserializer.cs | 4 +- Capnp.Net.Runtime/ListSerializerHelper.cs | 13 +++ 8 files changed, 103 insertions(+), 111 deletions(-) delete mode 100644 Capnp.Net.Runtime.Tests/TestInterfaces.cs create mode 100644 Capnp.Net.Runtime/ListSerializerHelper.cs diff --git a/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj b/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj index fd9eafd..5eac70b 100644 --- a/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj +++ b/Capnp.Net.Runtime.Tests.Core21/Capnp.Net.Runtime.Tests.Core21.csproj @@ -34,7 +34,6 @@ - diff --git a/Capnp.Net.Runtime.Tests/SerializationTests.cs b/Capnp.Net.Runtime.Tests/SerializationTests.cs index 9ce7fdd..3ea4f63 100644 --- a/Capnp.Net.Runtime.Tests/SerializationTests.cs +++ b/Capnp.Net.Runtime.Tests/SerializationTests.cs @@ -1,4 +1,6 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Capnp.Net.Runtime.Tests.GenImpls; +using Capnproto_test.Capnp.Test; +using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.Collections.Generic; using System.Linq; @@ -32,12 +34,17 @@ namespace Capnp.Net.Runtime.Tests var b = MessageBuilder.Create(); var list = b.CreateObject(); Assert.ThrowsException(() => list.Init(-1)); + // Assert.AreEqual(0, list.Count); // Bug or feature? Uninitialized list's Count is -1 + Assert.ThrowsException(() => { var _ = list[0]; }); + Assert.ThrowsException(() => { list[0] = false; }); list.Init(130); list[63] = true; list[65] = true; list[66] = true; list[65] = false; list[129] = true; + Assert.ThrowsException(() => { var _ = list[130]; }); + Assert.ThrowsException(() => { list[130] = false; }); Assert.IsFalse(list[0]); Assert.IsTrue(list[63]); Assert.IsFalse(list[64]); @@ -59,5 +66,63 @@ namespace Capnp.Net.Runtime.Tests var list3 = d.RequireList().CastBool(); CheckList(list3); } + + [TestMethod] + public void ListOfCaps() + { + var b = MessageBuilder.Create(); + b.InitCapTable(); + var list = b.CreateObject>(); + Assert.ThrowsException(() => list.Init(-1)); + Assert.ThrowsException(() => { var _ = list[0]; }); + Assert.ThrowsException(() => { list[0] = null; }); + list.Init(5); + Assert.ThrowsException(() => list.Init(1)); + var c1 = new Counters(); + var cap1 = new TestInterfaceImpl(c1); + var c2 = new Counters(); + var cap2 = new TestInterfaceImpl(c2); + list[0] = null; + list[1] = cap1; + list[2] = cap2; + list[3] = cap1; + list[4] = cap2; + list[3] = null; + Assert.IsTrue(list.All(p => p is Rpc.Proxy)); + var proxies = list.Cast().ToArray(); + Assert.IsTrue(proxies[0].IsNull); + Assert.IsFalse(proxies[1].IsNull); + Assert.IsTrue(proxies[3].IsNull); + list[2].Foo(123u, true).Wait(); + Assert.AreEqual(0, c1.CallCount); + Assert.AreEqual(1, c2.CallCount); + list[4].Foo(123u, true).Wait(); + Assert.AreEqual(2, c2.CallCount); + + var list2 = b.CreateObject>(); + list2.Init(null); + list2.Init(list); + proxies = list2.Cast().ToArray(); + Assert.IsTrue(proxies[0].IsNull); + Assert.IsFalse(proxies[1].IsNull); + Assert.IsTrue(proxies[3].IsNull); + list2[2].Foo(123u, true).Wait(); + Assert.AreEqual(0, c1.CallCount); + Assert.AreEqual(3, c2.CallCount); + list2[4].Foo(123u, true).Wait(); + Assert.AreEqual(4, c2.CallCount); + + DeserializerState d = list2; + var list3 = d.RequireList().CastCapList(); + proxies = list3.Cast().ToArray(); + Assert.IsTrue(proxies[0].IsNull); + Assert.IsFalse(proxies[1].IsNull); + Assert.IsTrue(proxies[3].IsNull); + list3[2].Foo(123u, true).Wait(); + Assert.AreEqual(0, c1.CallCount); + Assert.AreEqual(5, c2.CallCount); + list3[4].Foo(123u, true).Wait(); + Assert.AreEqual(6, c2.CallCount); + } } } diff --git a/Capnp.Net.Runtime.Tests/TestInterfaces.cs b/Capnp.Net.Runtime.Tests/TestInterfaces.cs deleted file mode 100644 index 3d22d54..0000000 --- a/Capnp.Net.Runtime.Tests/TestInterfaces.cs +++ /dev/null @@ -1,102 +0,0 @@ -using Capnp.Rpc; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace Capnp.Net.Runtime.Tests.ManualImpls -{ - // [Skeleton(typeof(TestInterfaceSkeleton))] - // [Proxy(typeof(TestInterfaceProxy))] - // interface ITestInterface: IDisposable - // { - // Task Foo(uint i, bool j); - // Task Bar(); - // Task Baz(int s); - // } - - // [Skeleton(typeof(TestExtendsSkeleton))] - // [Proxy(typeof(TestExtendsProxy))] - // interface ITestExtends: ITestInterface, IDisposable - // { - // void Qux(); - // Task Corge(int x); - // Task Grault(); - // } - - // interface ITestExtends2: ITestExtends, IDisposable - // { - // } - - // struct Box - // { - // public ITestExtends Cap { get; set; } - // } - - // struct AnyBox - // { - // public object Cap { get; set; } - // } - - // [Skeleton(typeof(TestPipelineSkeleton))] - // [Proxy(typeof(TestPipelineProxy))] - // interface ITestPipeline: IDisposable - // { - // Task<(string, Box)> GetCap(uint n, ITestInterface inCap); - // Task TestPointers(ITestExtends cap, DeserializerState obj, IReadOnlyList list); - // Task<(string, AnyBox)> GetAnyCap(uint n, object inCap); - // } - - // [Skeleton(typeof(TestCallOrderSkeleton))] - // [Proxy(typeof(TestCallOrderProxy))] - // interface ITestCallOrder : IDisposable - // { - // Task GetCallSequence(uint expected); - // } - - // struct TailResult - // { - // public uint I { get; set; } - // public string T { get; set; } - // public ITestCallOrder C { get; set; } - //} - - // [Skeleton(typeof(TestTailCalleeSkeleton))] - // [Proxy(typeof(TestTailCalleeProxy))] - // interface ITestTailCallee: IDisposable - // { - // Task Foo(int i, string t); - // } - - // [Skeleton(typeof(TestTailCallerSkeleton))] - // [Proxy(typeof(TestTailCallerProxy))] - // interface ITestTailCaller: IDisposable - // { - // Task Foo(int i, ITestTailCallee c); - // } - - // [Skeleton(typeof(TestHandleSkeleton))] - // [Proxy(typeof(TestHandleProxy))] - // interface ITestHandle: IDisposable { } - - - // [Skeleton(typeof(TestMoreStuffSkeleton))] - // [Proxy(typeof(TestMoreStuffProxy))] - // interface ITestMoreStuff: ITestCallOrder - // { - // Task CallFoo(ITestInterface cap); - // Task CallFooWhenResolved(ITestInterface cap); - // Task NeverReturn(ITestInterface cap, CancellationToken ct); - // Task Hold(ITestInterface cap); - // Task CallHeld(); - // Task GetHeld(); - // Task Echo(ITestCallOrder cap); - // Task ExpectCancel(ITestInterface cap, CancellationToken ct); - // Task<(string, string)> MethodWithDefaults(string a, uint b, string c); - // void MethodWithNullDefault(string a, ITestInterface b); - // Task GetHandle(); - // Task GetNull(); - // Task GetEnormousString(); - // } -} - diff --git a/Capnp.Net.Runtime/ListDeserializer.cs b/Capnp.Net.Runtime/ListDeserializer.cs index 8db896b..67d65c4 100644 --- a/Capnp.Net.Runtime/ListDeserializer.cs +++ b/Capnp.Net.Runtime/ListDeserializer.cs @@ -89,7 +89,7 @@ namespace Capnp /// Capability list representation /// If this kind of list cannot be represented as list of capabilities (because it is a list of non-pointers) /// If does not qualify as capability interface. - public virtual IReadOnlyList> CastCapList() where T: class + public virtual IReadOnlyList CastCapList() where T: class { throw new NotSupportedException("This kind of list does not contain nested lists"); } diff --git a/Capnp.Net.Runtime/ListOfBitsSerializer.cs b/Capnp.Net.Runtime/ListOfBitsSerializer.cs index af0eed8..2e5a94f 100644 --- a/Capnp.Net.Runtime/ListOfBitsSerializer.cs +++ b/Capnp.Net.Runtime/ListOfBitsSerializer.cs @@ -51,6 +51,8 @@ namespace Capnp { get { + ListSerializerHelper.EnsureAllocated(this); + if (index < 0 || index >= Count) throw new IndexOutOfRangeException(); @@ -61,6 +63,8 @@ namespace Capnp } set { + ListSerializerHelper.EnsureAllocated(this); + if (index < 0 || index >= Count) throw new IndexOutOfRangeException(); diff --git a/Capnp.Net.Runtime/ListOfCapsSerializer.cs b/Capnp.Net.Runtime/ListOfCapsSerializer.cs index eef1d7c..3b71b21 100644 --- a/Capnp.Net.Runtime/ListOfCapsSerializer.cs +++ b/Capnp.Net.Runtime/ListOfCapsSerializer.cs @@ -35,16 +35,29 @@ namespace Capnp [AllowNull] public T this[int index] { - get => (Rpc.CapabilityReflection.CreateProxy(DecodeCapPointer(index)) as T)!; + get + { + ListSerializerHelper.EnsureAllocated(this); + + try + { + return (Rpc.CapabilityReflection.CreateProxy(DecodeCapPointer(index)) as T)!; + } + catch (ArgumentOutOfRangeException) + { + throw new IndexOutOfRangeException(); + } + } set { - if (!IsAllocated) - throw new InvalidOperationException("Call Init() first"); + ListSerializerHelper.EnsureAllocated(this); if (index < 0 || index >= RawData.Length) throw new IndexOutOfRangeException("index out of range"); - RawData[index] = ProvideCapability(value); + var p = default(WirePointer); + p.SetCapability(ProvideCapability(value)); + RawData[index] = p; } } diff --git a/Capnp.Net.Runtime/ListOfPointersDeserializer.cs b/Capnp.Net.Runtime/ListOfPointersDeserializer.cs index 520e0e7..09aa786 100644 --- a/Capnp.Net.Runtime/ListOfPointersDeserializer.cs +++ b/Capnp.Net.Runtime/ListOfPointersDeserializer.cs @@ -83,9 +83,9 @@ namespace Capnp /// /// Capability interface /// The desired representation. Since it is evaluated lazily, type conflicts will not happen before accessing the resulting list's elements. - public override IReadOnlyList> CastCapList() + public override IReadOnlyList CastCapList() { - return this.LazyListSelect(d => d.RequireCapList()); + return State.RequireCapList(); } } } \ No newline at end of file diff --git a/Capnp.Net.Runtime/ListSerializerHelper.cs b/Capnp.Net.Runtime/ListSerializerHelper.cs new file mode 100644 index 0000000..5e76b8d --- /dev/null +++ b/Capnp.Net.Runtime/ListSerializerHelper.cs @@ -0,0 +1,13 @@ +using System; + +namespace Capnp +{ + static class ListSerializerHelper + { + public static void EnsureAllocated(SerializerState serializer) + { + if (!serializer.IsAllocated) + throw new InvalidOperationException("Call Init() first"); + } + } +} \ No newline at end of file