From 1c0666d96f3ead95cf9db84141cf731384ab2a04 Mon Sep 17 00:00:00 2001 From: Geir Fiksdal Date: Mon, 10 Jun 2024 13:35:33 +0200 Subject: [PATCH] Adding codec to serialize F# Unit --- Orleans.sln | 7 ++ .../FSharpCodecs.cs | 25 ++++++ .../SerializationTests/SerializationTests.cs | 69 -------------- .../Orleans.Serialization.FSharp.Tests.fsproj | 23 +++++ .../SerializationTests.fs | 89 +++++++++++++++++++ .../BuiltInCodecTests.cs | 13 +++ 6 files changed, 157 insertions(+), 69 deletions(-) create mode 100644 test/Orleans.Serialization.FSharp.Tests/Orleans.Serialization.FSharp.Tests.fsproj create mode 100644 test/Orleans.Serialization.FSharp.Tests/SerializationTests.fs diff --git a/Orleans.sln b/Orleans.sln index 3281faaf42..cc74583dc7 100644 --- a/Orleans.sln +++ b/Orleans.sln @@ -229,6 +229,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DashboardToy.Frontend", "pl EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DashboardToy.AppHost", "playground\DashboardToy\DashboardToy.AppHost\DashboardToy.AppHost.csproj", "{84B44F1D-B7FE-40E3-82F0-730A55AC8613}" EndProject +Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Orleans.Serialization.FSharp.Tests", "test\Orleans.Serialization.FSharp.Tests\Orleans.Serialization.FSharp.Tests.fsproj", "{B2D53D3C-E44A-4C9B-AAEE-28FB8C1BDF62}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -603,6 +605,10 @@ Global {84B44F1D-B7FE-40E3-82F0-730A55AC8613}.Debug|Any CPU.Build.0 = Debug|Any CPU {84B44F1D-B7FE-40E3-82F0-730A55AC8613}.Release|Any CPU.ActiveCfg = Release|Any CPU {84B44F1D-B7FE-40E3-82F0-730A55AC8613}.Release|Any CPU.Build.0 = Release|Any CPU + {B2D53D3C-E44A-4C9B-AAEE-28FB8C1BDF62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B2D53D3C-E44A-4C9B-AAEE-28FB8C1BDF62}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B2D53D3C-E44A-4C9B-AAEE-28FB8C1BDF62}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B2D53D3C-E44A-4C9B-AAEE-28FB8C1BDF62}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -714,6 +720,7 @@ Global {316CDCC7-323F-4264-9FC9-667662BB1F80} = {A41DE3D1-F8AA-4234-BE6F-3C9646A1507A} {C4DD4F96-3EC6-47C6-97AA-9B14F0F2099B} = {316CDCC7-323F-4264-9FC9-667662BB1F80} {84B44F1D-B7FE-40E3-82F0-730A55AC8613} = {316CDCC7-323F-4264-9FC9-667662BB1F80} + {B2D53D3C-E44A-4C9B-AAEE-28FB8C1BDF62} = {A6573187-FD0D-4DF7-91D1-03E07E470C0A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7BFB3429-B5BB-4DB1-95B4-67D77A864952} diff --git a/src/Orleans.Serialization.FSharp/FSharpCodecs.cs b/src/Orleans.Serialization.FSharp/FSharpCodecs.cs index 5e8f6be26d..ee476bb729 100644 --- a/src/Orleans.Serialization.FSharp/FSharpCodecs.cs +++ b/src/Orleans.Serialization.FSharp/FSharpCodecs.cs @@ -13,6 +13,31 @@ namespace Orleans.Serialization { + /// + /// Serializer for + /// + [RegisterSerializer] + public sealed class FSharpUnitCodec : IFieldCodec + { + public void WriteField(ref Writer writer, uint fieldIdDelta, Type expectedType, Unit value) where TBufferWriter : IBufferWriter => + ReferenceCodec.WriteNullReference(ref writer, fieldIdDelta); + + public Unit ReadValue(ref Reader reader, Field field) + { + field.EnsureWireType(WireType.Reference); + ReferenceCodec.MarkValueField(reader.Session); + var reference = reader.ReadVarUInt32(); + if (reference != 0) throw new ReferenceNotFoundException(typeof(Unit), reference); + return null; + } + } + + /// + /// Copier for + /// + [RegisterCopier] + public sealed class FSharpUnitCopier : ShallowCopier; + /// /// Serializer for . /// diff --git a/test/DefaultCluster.Tests/SerializationTests/SerializationTests.cs b/test/DefaultCluster.Tests/SerializationTests/SerializationTests.cs index 623122a0c4..2590a85073 100644 --- a/test/DefaultCluster.Tests/SerializationTests/SerializationTests.cs +++ b/test/DefaultCluster.Tests/SerializationTests/SerializationTests.cs @@ -1,5 +1,4 @@ using TestExtensions; -using UnitTests.FSharpTypes; using UnitTests.GrainInterfaces; using Xunit; @@ -95,73 +94,5 @@ public void Serialization_DefaultActivatorValueTypeWithUseActivator_Phase2() Assert.IsAssignableFrom(copy); Assert.Equal(4, ((DefaultActivatorValueTypeWithUseActivator)copy).Value); } - - [Fact, TestCategory("BVT"), TestCategory("Serialization")] - public void Serialization_Roundtrip_FSharp_SingleCaseDiscriminatedUnion() - { - var du = SingleCaseDU.ofInt(1); - var copy = HostedCluster.RoundTripSerializationForTesting(du); - - Assert.IsAssignableFrom(copy); - Assert.Equal(du, copy); - } - - [Fact, TestCategory("BVT"), TestCategory("Serialization")] - public void Serialization_Roundtrip_FSharp_DoubleCaseDiscriminatedUnion() - { - var case1 = DoubleCaseDU.NewCase1("case 1"); - var case2 = DoubleCaseDU.NewCase2(2); - - var copyCase1 = HostedCluster.RoundTripSerializationForTesting(case1); - var copyCase2 = HostedCluster.RoundTripSerializationForTesting(case2); - - Assert.IsAssignableFrom(copyCase1); - Assert.IsAssignableFrom(copyCase2); - Assert.Equal(case1, copyCase1); - Assert.Equal(case2, copyCase2); - } - - [Fact, TestCategory("BVT"), TestCategory("Serialization")] - public void Serialization_Roundtrip_FSharp_TripleCaseDiscriminatedUnion() - { - var case1 = TripleCaseDU.NewCase1("case 1"); - var case2 = TripleCaseDU.NewCase2(2); - var case3 = TripleCaseDU.NewCase3('a'); - - var copyCase1 = HostedCluster.RoundTripSerializationForTesting(case1); - var copyCase2 = HostedCluster.RoundTripSerializationForTesting(case2); - var copyCase3 = HostedCluster.RoundTripSerializationForTesting(case3); - - Assert.IsAssignableFrom(copyCase1); - Assert.IsAssignableFrom(copyCase2); - Assert.IsAssignableFrom(copyCase3); - Assert.Equal(case1, copyCase1); - Assert.Equal(case2, copyCase2); - Assert.Equal(case3, copyCase3); - } - - [Fact(Skip = "DUs with 4 or more cases fail when trying to instanciate Case{1-4}-classes via RuntimeHelpers.GetUninitializedObject when deserializing"), - TestCategory("BVT"), TestCategory("Serialization")] - public void Serialization_Roundtrip_FSharp_QuadrupleCaseDiscriminatedUnion() - { - var case1 = QuadrupleCaseDU.NewCase1("case 1"); - var case2 = QuadrupleCaseDU.NewCase2(2); - var case3 = QuadrupleCaseDU.NewCase3('a'); - var case4 = QuadrupleCaseDU.NewCase4(1); - - var copyCase1 = HostedCluster.RoundTripSerializationForTesting(case1); - var copyCase2 = HostedCluster.RoundTripSerializationForTesting(case2); - var copyCase3 = HostedCluster.RoundTripSerializationForTesting(case3); - var copyCase4 = HostedCluster.RoundTripSerializationForTesting(case4); - - Assert.IsAssignableFrom(copyCase1); - Assert.IsAssignableFrom(copyCase2); - Assert.IsAssignableFrom(copyCase3); - Assert.IsAssignableFrom(copyCase4); - Assert.Equal(case1, copyCase1); - Assert.Equal(case2, copyCase2); - Assert.Equal(case3, copyCase3); - Assert.Equal(case4, copyCase4); - } } } \ No newline at end of file diff --git a/test/Orleans.Serialization.FSharp.Tests/Orleans.Serialization.FSharp.Tests.fsproj b/test/Orleans.Serialization.FSharp.Tests/Orleans.Serialization.FSharp.Tests.fsproj new file mode 100644 index 0000000000..3c52da56d9 --- /dev/null +++ b/test/Orleans.Serialization.FSharp.Tests/Orleans.Serialization.FSharp.Tests.fsproj @@ -0,0 +1,23 @@ + + + latest + $(TestTargetFrameworks) + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/Orleans.Serialization.FSharp.Tests/SerializationTests.fs b/test/Orleans.Serialization.FSharp.Tests/SerializationTests.fs new file mode 100644 index 0000000000..0991c2ae62 --- /dev/null +++ b/test/Orleans.Serialization.FSharp.Tests/SerializationTests.fs @@ -0,0 +1,89 @@ +namespace TestFSharpSerialization + +open TestExtensions +open UnitTests.FSharpTypes +open Xunit + +[] +type DefaultClusterTestCollection() = interface ICollectionFixture; + +type FSharpSerializationTests(fixture: DefaultClusterFixture) = + inherit HostedTestClusterEnsureDefaultStarted(fixture) + + let cluster = fixture.HostedCluster + + [] + let Serialization_Roundtrip_FSharp_Unit () = + let roundtripped = cluster.RoundTripSerializationForTesting () + let copy = cluster.DeepCopy () + Assert.Equal((), roundtripped) + Assert.Equal((), copy) + + [] + let Serialization_Roundtrip_FSharp_SingleCaseDiscriminatedUnion () = + let du = SingleCaseDU.Case1 1 + let roundtripped = cluster.RoundTripSerializationForTesting du + let copy = cluster.DeepCopy du + Assert.Equal(du, roundtripped) + Assert.Equal(du, copy) + + [] + let Serialization_Roundtrip_FSharp_DoubleCaseDiscriminatedUnion () = + let case1 = DoubleCaseDU.Case1 "case 1" + let case2 = DoubleCaseDU.Case2 2 + + let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1 + let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2 + let copyCase1 = cluster.DeepCopy case1 + let copyCase2 = cluster.DeepCopy case2 + + Assert.Equal(case1, roundtrippedCase1) + Assert.Equal(case2, roundtrippedCase2) + Assert.Equal(case1, copyCase1) + Assert.Equal(case2, copyCase2) + + [] + let Serialization_Roundtrip_FSharp_TripleCaseDiscriminatedUnion () = + let case1 = TripleCaseDU.Case1 "case 1" + let case2 = TripleCaseDU.Case2 2 + let case3 = TripleCaseDU.Case3 'a' + + let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1 + let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2 + let roundtrippedCase3 = cluster.RoundTripSerializationForTesting case3 + let copyCase1 = cluster.DeepCopy case1 + let copyCase2 = cluster.DeepCopy case2 + let copyCase3 = cluster.DeepCopy case3 + + Assert.Equal(case1, roundtrippedCase1) + Assert.Equal(case2, roundtrippedCase2) + Assert.Equal(case3, roundtrippedCase3) + Assert.Equal(case1, copyCase1) + Assert.Equal(case2, copyCase2) + Assert.Equal(case3, copyCase3) + + [] + [] + let Serialization_Roundtrip_FSharp_QuadrupleCaseDiscriminatedUnion () = + let case1 = QuadrupleCaseDU.Case1 "case 1" + let case2 = QuadrupleCaseDU.Case2 2 + let case3 = QuadrupleCaseDU.Case3 'a' + let case4 = QuadrupleCaseDU.Case4 1uy + + let roundtrippedCase1 = cluster.RoundTripSerializationForTesting case1 + let roundtrippedCase2 = cluster.RoundTripSerializationForTesting case2 + let roundtrippedCase3 = cluster.RoundTripSerializationForTesting case3 + let roundtrippedCase4 = cluster.RoundTripSerializationForTesting case4 + let copyCase1 = cluster.DeepCopy case1 + let copyCase2 = cluster.DeepCopy case2 + let copyCase3 = cluster.DeepCopy case3 + let copyCase4 = cluster.DeepCopy case4 + + Assert.Equal(case1, roundtrippedCase1); + Assert.Equal(case2, roundtrippedCase2); + Assert.Equal(case3, roundtrippedCase3); + Assert.Equal(case4, roundtrippedCase4); + Assert.Equal(case1, copyCase1); + Assert.Equal(case2, copyCase2); + Assert.Equal(case3, copyCase3); + Assert.Equal(case4, copyCase4); \ No newline at end of file diff --git a/test/Orleans.Serialization.UnitTests/BuiltInCodecTests.cs b/test/Orleans.Serialization.UnitTests/BuiltInCodecTests.cs index c659e2b178..6344f4769e 100644 --- a/test/Orleans.Serialization.UnitTests/BuiltInCodecTests.cs +++ b/test/Orleans.Serialization.UnitTests/BuiltInCodecTests.cs @@ -3156,6 +3156,19 @@ public class UriCopierTests(ITestOutputHelper output) : CopierTester true; } + public class FSharpUnitTests(ITestOutputHelper output) : FieldCodecTester(output) + { + protected override Unit CreateValue() => null; + protected override Unit[] TestValues => [null]; + } + + public class FSharpUnitCopierTests(ITestOutputHelper output) : CopierTester(output) + { + protected override bool IsImmutable => true; + protected override Unit CreateValue() => null; + protected override Unit[] TestValues => [null]; + } + public class FSharpOptionTests(ITestOutputHelper output) : FieldCodecTester, FSharpOptionCodec>(output) { protected override FSharpOption[] TestValues => [null, FSharpOption.None, FSharpOption.Some(Guid.Empty), FSharpOption.Some(Guid.NewGuid())];