diff --git a/src/Orleans.Core/Core/GrainInterfaceTypeToGrainTypeResolver.cs b/src/Orleans.Core/Core/GrainInterfaceTypeToGrainTypeResolver.cs index 416ba6d5f2..121749be45 100644 --- a/src/Orleans.Core/Core/GrainInterfaceTypeToGrainTypeResolver.cs +++ b/src/Orleans.Core/Core/GrainInterfaceTypeToGrainTypeResolver.cs @@ -86,7 +86,7 @@ public GrainType GetGrainType(GrainInterfaceType interfaceType, string prefix) if (GenericGrainType.TryParse(result, out var genericGrainType) && !genericGrainType.IsConstructed) { - result = genericGrainType.GrainType.GetConstructed(genericInterface.Value); + result = genericGrainType.GetConstructed(genericInterface); } return result; @@ -149,7 +149,7 @@ public bool TryGetGrainType(GrainInterfaceType interfaceType, out GrainType resu } else { - result = genericGrainType.GrainType.GetConstructed(genericInterface.Value); + result = genericGrainType.GetConstructed(genericInterface); } } else diff --git a/src/Orleans.Core/IDs/GenericGrainInterfaceType.cs b/src/Orleans.Core/IDs/GenericGrainInterfaceType.cs index 52a413c702..189b7052cd 100644 --- a/src/Orleans.Core/IDs/GenericGrainInterfaceType.cs +++ b/src/Orleans.Core/IDs/GenericGrainInterfaceType.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics.CodeAnalysis; using Orleans.Serialization.TypeSystem; using Orleans.Utilities; @@ -14,9 +15,10 @@ public readonly struct GenericGrainInterfaceType /// Initializes a new instance of the struct. /// /// The underlying grain interface type. - private GenericGrainInterfaceType(GrainInterfaceType value) + private GenericGrainInterfaceType(GrainInterfaceType value, int arity) { Value = value; + Arity = arity; } /// @@ -24,6 +26,11 @@ private GenericGrainInterfaceType(GrainInterfaceType value) /// public GrainInterfaceType Value { get; } + /// + /// The arity of the generic type. + /// + public int Arity { get; } + /// /// Returns if this instance contains concrete type parameters. /// @@ -34,9 +41,16 @@ private GenericGrainInterfaceType(GrainInterfaceType value) /// public static bool TryParse(GrainInterfaceType grainType, out GenericGrainInterfaceType result) { - if (!grainType.IsDefault && TypeConverterExtensions.IsGenericType(grainType.Value)) + if (grainType.IsDefault) + { + result = default; + return false; + } + + var arity = TypeConverterExtensions.GetGenericTypeArity(grainType.Value); + if (arity > 0) { - result = new GenericGrainInterfaceType(grainType); + result = new GenericGrainInterfaceType(grainType, arity); return true; } @@ -50,7 +64,7 @@ public static bool TryParse(GrainInterfaceType grainType, out GenericGrainInterf public GenericGrainInterfaceType GetGenericGrainType() { var generic = TypeConverterExtensions.GetDeconstructed(Value.Value); - return new GenericGrainInterfaceType(new GrainInterfaceType(generic)); + return new GenericGrainInterfaceType(new GrainInterfaceType(generic), Arity); } /// @@ -58,8 +72,13 @@ public GenericGrainInterfaceType GetGenericGrainType() /// public GenericGrainInterfaceType Construct(TypeConverter formatter, params Type[] typeArguments) { + if (Arity != typeArguments.Length) + { + ThrowIncorrectArgumentLength(typeArguments); + } + var constructed = formatter.GetConstructed(this.Value.Value, typeArguments); - return new GenericGrainInterfaceType(new GrainInterfaceType(constructed)); + return new GenericGrainInterfaceType(new GrainInterfaceType(constructed), Arity); } /// @@ -71,5 +90,8 @@ public GenericGrainInterfaceType Construct(TypeConverter formatter, params Type[ /// Returns a UTF8 interpretation of the current instance. /// public override string ToString() => Value.ToString(); + + [DoesNotReturn] + private void ThrowIncorrectArgumentLength(Type[] typeArguments) => throw new ArgumentException($"Incorrect number of type arguments, {typeArguments.Length}, to construct a generic grain type with arity {Arity}.", nameof(typeArguments)); } } diff --git a/src/Orleans.Core/IDs/GenericGrainType.cs b/src/Orleans.Core/IDs/GenericGrainType.cs index 93b8d3dde7..c57a353fab 100644 --- a/src/Orleans.Core/IDs/GenericGrainType.cs +++ b/src/Orleans.Core/IDs/GenericGrainType.cs @@ -1,4 +1,6 @@ using System; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; using Orleans.Serialization.TypeSystem; using Orleans.Utilities; @@ -14,9 +16,11 @@ namespace Orleans.Runtime /// Initializes a new instance of the struct. /// /// The underlying grain type. - private GenericGrainType(GrainType grainType) + /// The generic arity of the grain type. + private GenericGrainType(GrainType grainType, int arity) { GrainType = grainType; + Arity = arity; } /// @@ -24,6 +28,11 @@ private GenericGrainType(GrainType grainType) /// public GrainType GrainType { get; } + /// + /// The generic arity of the grain type. + /// + public int Arity { get; } + /// /// Returns if this instance contains concrete type parameters. /// @@ -34,9 +43,10 @@ private GenericGrainType(GrainType grainType) /// public static bool TryParse(GrainType grainType, out GenericGrainType result) { - if (TypeConverterExtensions.IsGenericType(grainType.Value)) + var arity = TypeConverterExtensions.GetGenericTypeArity(grainType.Value); + if (arity > 0) { - result = new GenericGrainType(grainType); + result = new GenericGrainType(grainType, arity); return true; } @@ -50,7 +60,7 @@ public static bool TryParse(GrainType grainType, out GenericGrainType result) public GenericGrainType GetUnconstructedGrainType() { var generic = TypeConverterExtensions.GetDeconstructed(GrainType.Value); - return new GenericGrainType(new GrainType(generic)); + return new GenericGrainType(new GrainType(generic), Arity); } /// @@ -58,13 +68,21 @@ public GenericGrainType GetUnconstructedGrainType() /// public GenericGrainType Construct(TypeConverter formatter, params Type[] typeArguments) { + if (Arity != typeArguments.Length) + { + ThrowIncorrectArgumentLength(typeArguments); + } + var constructed = formatter.GetConstructed(this.GrainType.Value, typeArguments); - return new GenericGrainType(new GrainType(constructed)); + return new GenericGrainType(new GrainType(constructed), Arity); } + /// - /// Returns the type arguments which this instance was constructed with. + /// Gets the type arguments using the provided type converter. /// - public Type[] GetArguments(TypeConverter formatter) => formatter.GetArguments(this.GrainType.Value); + /// The type converter + /// The type arguments. + public Type[] GetArguments(TypeConverter converter) => converter.GetArguments(this.GrainType.Value); /// public override string ToString() => this.GrainType.ToString(); @@ -77,5 +95,8 @@ public GenericGrainType Construct(TypeConverter formatter, params Type[] typeArg /// public override int GetHashCode() => this.GrainType.GetHashCode(); + + [DoesNotReturn] + private void ThrowIncorrectArgumentLength(Type[] typeArguments) => throw new ArgumentException($"Incorrect number of type arguments, {typeArguments.Length}, to construct a generic grain type with arity {Arity}.", nameof(typeArguments)); } } diff --git a/src/Orleans.Core/Manifest/GrainTypeResolver.cs b/src/Orleans.Core/Manifest/GrainTypeResolver.cs index 8a01c56d6b..72624e7a9d 100644 --- a/src/Orleans.Core/Manifest/GrainTypeResolver.cs +++ b/src/Orleans.Core/Manifest/GrainTypeResolver.cs @@ -95,7 +95,8 @@ private GrainType AddGenericParameters(GrainType grainType, Type type) && !type.ContainsGenericParameters && !genericGrainType.IsConstructed) { - grainType = genericGrainType.Construct(_typeConverter, type.GetGenericArguments()).GrainType; + var typeArguments = type.GetGenericArguments(); + grainType = genericGrainType.Construct(_typeConverter, typeArguments).GrainType; } return grainType; diff --git a/src/Orleans.Core/Utils/TypeConverterExtensions.cs b/src/Orleans.Core/Utils/TypeConverterExtensions.cs index 6d9f67f06a..026e72e573 100644 --- a/src/Orleans.Core/Utils/TypeConverterExtensions.cs +++ b/src/Orleans.Core/Utils/TypeConverterExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Buffers.Text; +using System.Diagnostics.CodeAnalysis; using System.Text; using Orleans.Runtime; using Orleans.Serialization.TypeSystem; @@ -19,6 +20,36 @@ internal static class TypeConverterExtensions /// public static bool IsGenericType(IdSpan type) => type.AsSpan().IndexOf((byte)GenericTypeIndicator) >= 0; + /// + /// Returns the generic arity of the specified grain type. + /// + public static int GetGenericTypeArity(IdSpan type) + { + var typeSpan = type.AsSpan(); + var startIndex = typeSpan.IndexOf((byte)GenericTypeIndicator) + 1; + if (startIndex <= 0 || startIndex >= typeSpan.Length) + { + return 0; + } + + int endIndex; + for (endIndex = startIndex; endIndex < typeSpan.Length; endIndex++) + { + var c = typeSpan[endIndex]; + if (c is < ((byte)'0') or > ((byte)'9')) + { + break; + } + } + + if (endIndex > startIndex && Utf8Parser.TryParse(typeSpan[startIndex..endIndex], out int arity, out _)) + { + return arity; + } + + throw new InvalidOperationException($"Unable to parse arity from type \"{type}\""); + } + /// /// Returns true if the provided type string is a constructed generic type. /// @@ -65,8 +96,15 @@ public static IdSpan GetConstructed(this TypeConverter formatter, IdSpan unconst /// /// Returns the constructed form of the provided generic grain type using the type arguments from the provided constructed interface type. /// - public static GrainType GetConstructed(this GrainType grainType, GrainInterfaceType typeArguments) + public static GrainType GetConstructed(this GenericGrainType genericGrainType, GenericGrainInterfaceType genericGrainInterfaceType) { + if (genericGrainType.Arity != genericGrainInterfaceType.Arity) + { + ThrowGenericArityMismatch(genericGrainType, genericGrainInterfaceType); + } + + var grainType = genericGrainType.GrainType; + var typeArguments = genericGrainInterfaceType.Value; var args = typeArguments.Value.AsSpan(); var index = args.IndexOf((byte)StartArgument); if (index <= 0) return grainType; // if no type arguments are provided, then the current logic expects the unconstructed form (but the grain call is going to fail later anyway...) @@ -112,5 +150,9 @@ public static Type[] GetArguments(this TypeConverter formatter, IdSpan construct return result; } + + [DoesNotReturn] + private static void ThrowGenericArityMismatch(GenericGrainType genericGrainType, GenericGrainInterfaceType genericInterfaceType) + => throw new ArgumentException($"Cannot construct generic grain \"{genericGrainType.GrainType}\" using arguments from generic interface \"{genericInterfaceType}\" because the generic arities are not equal: {genericGrainType.Arity} is not equal to {genericInterfaceType.Arity}."); } } diff --git a/test/DefaultCluster.Tests/GenericGrainTests.cs b/test/DefaultCluster.Tests/GenericGrainTests.cs index e00abd5b3b..1db9272514 100644 --- a/test/DefaultCluster.Tests/GenericGrainTests.cs +++ b/test/DefaultCluster.Tests/GenericGrainTests.cs @@ -11,6 +11,7 @@ namespace DefaultCluster.Tests.General /// /// Unit tests for grains implementing generic interfaces /// + [TestCategory("BVT"), TestCategory("Generics")] public class GenericGrainTests : HostedTestClusterEnsureDefaultStarted { private static int grainId = 0; @@ -21,17 +22,17 @@ public GenericGrainTests(DefaultClusterFixture fixture) : base(fixture) public TGrainInterface GetGrain(long i) where TGrainInterface : IGrainWithIntegerKey { - return this.GrainFactory.GetGrain(i); + return this.GrainFactory.GetGrain(i); } public TGrainInterface GetGrain() where TGrainInterface : IGrainWithIntegerKey { - return this.GrainFactory.GetGrain(GetRandomGrainId()); + return this.GrainFactory.GetGrain(GetRandomGrainId()); } /// Can instantiate multiple concrete grain types that implement /// different specializations of the same generic interface - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_ConcreteGrainWithGenericInterfaceGetGrain() { var grainOfIntFloat1 = GetGrain>(); @@ -52,7 +53,7 @@ public async Task GenericGrainTests_ConcreteGrainWithGenericInterfaceGetGrain() } /// Multiple GetGrain requests with the same id return the same concrete grain - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_ConcreteGrainWithGenericInterfaceMultiplicity() { var grainId = GetRandomGrainId(); @@ -67,7 +68,7 @@ public async Task GenericGrainTests_ConcreteGrainWithGenericInterfaceMultiplicit } /// Can instantiate generic grain specializations - [Theory, TestCategory("BVT"), TestCategory("Generics")] + [Theory] [InlineData(1.2f)] [InlineData(3.4f)] [InlineData("5.6")] @@ -80,13 +81,13 @@ public async Task GenericGrainTests_SimpleGenericGrainGetGrain(T setValue) // generic grain implementation does not change the set value: await grain.Transform(); - + T result = await grain.Get(); - - Assert.Equal(setValue, result); + + Assert.Equal(setValue, result); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_SimpleGenericGrainGetGrain_ArrayTypeParameter() { var grain = GetGrain>(); @@ -96,13 +97,13 @@ public async Task GenericGrainTests_SimpleGenericGrainGetGrain_ArrayTypeParamete // generic grain implementation does not change the set value: await grain.Transform(); - + var result = await grain.Get(); - - Assert.Equal(expected, result); + + Assert.Equal(expected, result); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_GenericGrainInheritingArray() { var grain = GetGrain>(); @@ -111,12 +112,12 @@ public async Task GenericGrainTests_GenericGrainInheritingArray() await grain.Set(expected); var result = await grain.Get(); - - Assert.Equal(expected, result); + + Assert.Equal(expected, result); } /// Can instantiate grains that implement generic interfaces with generic type parameters - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_GenericInterfaceWithGenericParametersGetGrain() { @@ -133,7 +134,7 @@ public async Task GenericGrainTests_GenericInterfaceWithGenericParametersGetGrai /// Multiple GetGrain requests with the same id return the same generic grain specialization - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_SimpleGenericGrainMultiplicity() { var grainId = GetRandomGrainId(); @@ -150,7 +151,7 @@ public async Task GenericGrainTests_SimpleGenericGrainMultiplicity() /// If both a concrete implementation and a generic implementation of a /// generic interface exist, prefer the concrete implementation. - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_PreferConcreteGrainImplementationOfGenericInterface() { var grainOfDouble1 = GetGrain>(); @@ -171,7 +172,7 @@ public async Task GenericGrainTests_PreferConcreteGrainImplementationOfGenericIn } /// Multiple GetGrain requests with the same id return the same concrete grain implementation - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_PreferConcreteGrainImplementationOfGenericInterfaceMultiplicity() { var grainId = GetRandomGrainId(); @@ -189,7 +190,7 @@ public async Task GenericGrainTests_PreferConcreteGrainImplementationOfGenericIn } /// Can instantiate concrete grains that implement multiple generic interfaces - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_ConcreteGrainWithMultipleGenericInterfacesGetGrain() { var grain1 = GetGrain>(); @@ -210,7 +211,7 @@ public async Task GenericGrainTests_ConcreteGrainWithMultipleGenericInterfacesGe } /// Multiple GetGrain requests with the same id and interface return the same concrete grain implementation - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_ConcreteGrainWithMultipleGenericInterfacesMultiplicity1() { var grainId = GetRandomGrainId(); @@ -230,7 +231,7 @@ public async Task GenericGrainTests_ConcreteGrainWithMultipleGenericInterfacesMu } /// Multiple GetGrain requests with the same id and different interfaces return the same concrete grain implementation - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_ConcreteGrainWithMultipleGenericInterfacesMultiplicity2() { var grainId = GetRandomGrainId(); @@ -248,7 +249,7 @@ public async Task GenericGrainTests_ConcreteGrainWithMultipleGenericInterfacesMu Assert.Equal("100", floatResult); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainTests_UseGenericFactoryInsideGrain() { var grainId = GetRandomGrainId(); @@ -259,21 +260,21 @@ public async Task GenericGrainTests_UseGenericFactoryInsideGrain() } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_SimpleGrain_GetGrain() { - var grain = this.GrainFactory.GetGrain>(grainId++); + var grain = this.GrainFactory.GetGrain>(grainId++); await grain.GetA(); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_SimpleGrainControlFlow() { var a = Random.Shared.Next(100); var b = a + 1; var expected = a + "x" + b; - var grain = this.GrainFactory.GetGrain>(grainId++); + var grain = this.GrainFactory.GetGrain>(grainId++); await grain.SetA(a); @@ -283,14 +284,14 @@ public async Task Generic_SimpleGrainControlFlow() Assert.Equal(expected, stringPromise.Result); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public void Generic_SimpleGrainControlFlow_Blocking() { var a = Random.Shared.Next(100); var b = a + 1; var expected = a + "x" + b; - var grain = this.GrainFactory.GetGrain>(grainId++); + var grain = this.GrainFactory.GetGrain>(grainId++); // explicitly use .Wait() and .Result to make sure the client does not deadlock in these cases. grain.SetA(a).Wait(); @@ -301,14 +302,14 @@ public void Generic_SimpleGrainControlFlow_Blocking() Assert.Equal(expected, stringPromise.Result); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_SimpleGrainDataFlow() { var a = Random.Shared.Next(100); var b = a + 1; var expected = a + "x" + b; - var grain = this.GrainFactory.GetGrain>(grainId++); + var grain = this.GrainFactory.GetGrain>(grainId++); var setAPromise = grain.SetA(a); var setBPromise = grain.SetB(b); @@ -318,34 +319,34 @@ public async Task Generic_SimpleGrainDataFlow() Assert.Equal(expected, x); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_SimpleGrain2_GetGrain() { - var g1 = this.GrainFactory.GetGrain>(grainId++); - var g2 = this.GrainFactory.GetGrain>(grainId++); - var g3 = this.GrainFactory.GetGrain>(grainId++); + var g1 = this.GrainFactory.GetGrain>(grainId++); + var g2 = this.GrainFactory.GetGrain>(grainId++); + var g3 = this.GrainFactory.GetGrain>(grainId++); await g1.GetA(); await g2.GetA(); await g3.GetA(); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_SimpleGrainGenericParameterWithMultipleArguments_GetGrain() { - var g1 = this.GrainFactory.GetGrain>>(GetRandomGrainId()); + var g1 = this.GrainFactory.GetGrain>>(GetRandomGrainId()); await g1.GetA(); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_SimpleGrainControlFlow2_GetAB() { var a = Random.Shared.Next(100); var b = a + 1; var expected = a + "x" + b; - var g1 = this.GrainFactory.GetGrain>(grainId++); - var g2 = this.GrainFactory.GetGrain>(grainId++); - var g3 = this.GrainFactory.GetGrain>(grainId++); + var g1 = this.GrainFactory.GetGrain>(grainId++); + var g2 = this.GrainFactory.GetGrain>(grainId++); + var g3 = this.GrainFactory.GetGrain>(grainId++); string r1 = await g1.GetAxB(a, b); string r2 = await g2.GetAxB(a, b); @@ -355,31 +356,31 @@ public async Task Generic_SimpleGrainControlFlow2_GetAB() Assert.Equal(expected, r3); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_SimpleGrainControlFlow3() { - ISimpleGenericGrain2 g = this.GrainFactory.GetGrain>(grainId++); + ISimpleGenericGrain2 g = this.GrainFactory.GetGrain>(grainId++); await g.SetA(3); await g.SetB(1.25f); Assert.Equal("3x1.25", await g.GetAxB()); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_BasicGrainControlFlow() { - IBasicGenericGrain g = this.GrainFactory.GetGrain>(0); + IBasicGenericGrain g = this.GrainFactory.GetGrain>(0); await g.SetA(3); await g.SetB(1.25f); Assert.Equal("3x1.25", await g.GetAxB()); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GrainWithListFields() { string a = Random.Shared.Next(100).ToString(CultureInfo.InvariantCulture); string b = Random.Shared.Next(100).ToString(CultureInfo.InvariantCulture); - var g1 = this.GrainFactory.GetGrain(grainId++); + var g1 = this.GrainFactory.GetGrain(grainId++); var p1 = g1.AddItem(a); var p2 = g1.AddItem(b); @@ -392,14 +393,14 @@ public async Task GrainWithListFields() string.Format("Result: r[0]={0}, r[1]={1}", r1[0], r1[1])); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_GrainWithListFields() { int a = Random.Shared.Next(100); int b = Random.Shared.Next(100); - var g1 = this.GrainFactory.GetGrain>(grainId++); + var g1 = this.GrainFactory.GetGrain>(grainId++); var p1 = g1.AddItem(a); var p2 = g1.AddItem(b); @@ -412,20 +413,20 @@ public async Task Generic_GrainWithListFields() string.Format("Result: r[0]={0}, r[1]={1}", r1[0], r1[1])); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_GrainWithNoProperties_ControlFlow() { int a = Random.Shared.Next(100); int b = Random.Shared.Next(100); string expected = a + "x" + b; - var g1 = this.GrainFactory.GetGrain>(grainId++); + var g1 = this.GrainFactory.GetGrain>(grainId++); string r1 = await g1.GetAxB(a, b); Assert.Equal(expected, r1); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GrainWithNoProperties_ControlFlow() { int a = Random.Shared.Next(100); @@ -433,29 +434,29 @@ public async Task GrainWithNoProperties_ControlFlow() string expected = a + "x" + b; long grainId = GetRandomGrainId(); - var g1 = this.GrainFactory.GetGrain(grainId); + var g1 = this.GrainFactory.GetGrain(grainId); string r1 = await g1.GetAxB(a, b); Assert.Equal(expected, r1); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_ReaderWriterGrain1() { int a = Random.Shared.Next(100); - var g = this.GrainFactory.GetGrain>(grainId++); + var g = this.GrainFactory.GetGrain>(grainId++); await g.SetValue(a); var res = await g.GetValue(); Assert.Equal(a, res); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_ReaderWriterGrain2() { int a = Random.Shared.Next(100); string b = "bbbbb"; - var g = this.GrainFactory.GetGrain>(grainId++); + var g = this.GrainFactory.GetGrain>(grainId++); await g.SetValue1(a); await g.SetValue2(b); var r1 = await g.GetValue1(); @@ -464,14 +465,14 @@ public async Task Generic_ReaderWriterGrain2() Assert.Equal(b, r2); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_ReaderWriterGrain3() { int a = Random.Shared.Next(100); string b = "bbbbb"; double c = 3.145; - var g = this.GrainFactory.GetGrain>(grainId++); + var g = this.GrainFactory.GetGrain>(grainId++); await g.SetValue1(a); await g.SetValue2(b); await g.SetValue3(c); @@ -483,12 +484,12 @@ public async Task Generic_ReaderWriterGrain3() Assert.Equal(c, r3); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_Non_Primitive_Type_Argument() { - IEchoHubGrain g1 = this.GrainFactory.GetGrain>(1); - IEchoHubGrain g2 = this.GrainFactory.GetGrain>(1); - IEchoHubGrain g3 = this.GrainFactory.GetGrain>(1); + IEchoHubGrain g1 = this.GrainFactory.GetGrain>(1); + IEchoHubGrain g2 = this.GrainFactory.GetGrain>(1); + IEchoHubGrain g3 = this.GrainFactory.GetGrain>(1); Assert.NotEqual((GrainReference)g1, (GrainReference)g2); Assert.NotEqual((GrainReference)g1, (GrainReference)g3); @@ -503,40 +504,40 @@ public async Task Generic_Non_Primitive_Type_Argument() Assert.Equal(3m, await g3.GetX()); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_Echo_Chain_1() { const string msg1 = "Hello from EchoGenericChainGrain-1"; - IEchoGenericChainGrain g1 = this.GrainFactory.GetGrain>(GetRandomGrainId()); + IEchoGenericChainGrain g1 = this.GrainFactory.GetGrain>(GetRandomGrainId()); string received = await g1.Echo(msg1); Assert.Equal(msg1, received); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_Echo_Chain_2() { const string msg2 = "Hello from EchoGenericChainGrain-2"; - IEchoGenericChainGrain g2 = this.GrainFactory.GetGrain>(GetRandomGrainId()); + IEchoGenericChainGrain g2 = this.GrainFactory.GetGrain>(GetRandomGrainId()); string received = await g2.Echo2(msg2); Assert.Equal(msg2, received); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_Echo_Chain_3() { const string msg3 = "Hello from EchoGenericChainGrain-3"; - IEchoGenericChainGrain g3 = this.GrainFactory.GetGrain>(GetRandomGrainId()); + IEchoGenericChainGrain g3 = this.GrainFactory.GetGrain>(GetRandomGrainId()); string received = await g3.Echo3(msg3); Assert.Equal(msg3, received); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_Echo_Chain_4() { const string msg4 = "Hello from EchoGenericChainGrain-4"; @@ -547,7 +548,7 @@ public async Task Generic_Echo_Chain_4() Assert.Equal(msg4, received); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_Echo_Chain_5() { const string msg5 = "Hello from EchoGenericChainGrain-5"; @@ -558,7 +559,7 @@ public async Task Generic_Echo_Chain_5() Assert.Equal(msg5, received); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_Echo_Chain_6() { const string msg6 = "Hello from EchoGenericChainGrain-6"; @@ -570,108 +571,84 @@ public async Task Generic_Echo_Chain_6() } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_1Argument_GenericCallOnly() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid(), "UnitTests.Grains.Generic1ArgumentGrain"); + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid(), "UnitTests.Grains.Generic1ArgumentGrain"); var s1 = Guid.NewGuid().ToString(); var s2 = await grain.Ping(s1); Assert.Equal(s1, s2); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] - public async Task Generic_1Argument_NonGenericCallFirst() + [Fact] + public void Generic_1Argument_NonGenericCallFirst() { - - var id = Guid.NewGuid(); - var nonGenericFacet = this.GrainFactory.GetGrain(id, "UnitTests.Grains.Generic1ArgumentGrain"); - await Assert.ThrowsAsync(async () => - { - try - { - await nonGenericFacet.Ping(); - } - catch (AggregateException exc) - { - throw exc.GetBaseException(); - } - }); + Assert.Throws(() => this.GrainFactory.GetGrain(Guid.NewGuid(), "UnitTests.Grains.Generic1ArgumentGrain")); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task Generic_1Argument_GenericCallFirst() { var id = Guid.NewGuid(); - var grain = this.GrainFactory.GetGrain>(id, "UnitTests.Grains.Generic1ArgumentGrain"); + var grain = this.GrainFactory.GetGrain>(id, "UnitTests.Grains.Generic1ArgumentGrain"); var s1 = Guid.NewGuid().ToString(); var s2 = await grain.Ping(s1); Assert.Equal(s1, s2); - var nonGenericFacet = this.GrainFactory.GetGrain(id, "UnitTests.Grains.Generic1ArgumentGrain"); - await Assert.ThrowsAsync(async () => - { - try - { - await nonGenericFacet.Ping(); - } - catch (AggregateException exc) - { - throw exc.GetBaseException(); - } - }); + Assert.Throws(() => this.GrainFactory.GetGrain(id, "UnitTests.Grains.Generic1ArgumentGrain")); } - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task DifferentTypeArgsProduceIndependentActivations() { - var grain1 = this.GrainFactory.GetGrain>(0); + var grain1 = this.GrainFactory.GetGrain>(0); await grain1.SetValue(123); - var grain2 = this.GrainFactory.GetGrain>(0); + var grain2 = this.GrainFactory.GetGrain>(0); var v = await grain2.GetValue(); Assert.Null(v); } - [Fact, TestCategory("BVT"), TestCategory("Generics"), TestCategory("Echo")] + [Fact, TestCategory("Echo")] public async Task Generic_PingSelf() { var id = Guid.NewGuid(); - var grain = this.GrainFactory.GetGrain>(id); + var grain = this.GrainFactory.GetGrain>(id); var s1 = Guid.NewGuid().ToString(); var s2 = await grain.PingSelf(s1); Assert.Equal(s1, s2); } - [Fact, TestCategory("BVT"), TestCategory("Generics"), TestCategory("Echo")] + [Fact, TestCategory("Echo")] public async Task Generic_PingOther() { var id = Guid.NewGuid(); var targetId = Guid.NewGuid(); - var grain = this.GrainFactory.GetGrain>(id); - var target = this.GrainFactory.GetGrain>(targetId); + var grain = this.GrainFactory.GetGrain>(id); + var target = this.GrainFactory.GetGrain>(targetId); var s1 = Guid.NewGuid().ToString(); var s2 = await grain.PingOther(target, s1); Assert.Equal(s1, s2); } - [Fact, TestCategory("BVT"), TestCategory("Generics"), TestCategory("Echo")] + [Fact, TestCategory("Echo")] public async Task Generic_PingSelfThroughOther() { var id = Guid.NewGuid(); var targetId = Guid.NewGuid(); - var grain = this.GrainFactory.GetGrain>(id); - var target = this.GrainFactory.GetGrain>(targetId); + var grain = this.GrainFactory.GetGrain>(id); + var target = this.GrainFactory.GetGrain>(targetId); var s1 = Guid.NewGuid().ToString(); var s2 = await grain.PingSelfThroughOther(target, s1); Assert.Equal(s1, s2); } - [Fact, TestCategory("BVT"), TestCategory("Generics"), TestCategory("ActivateDeactivate")] + [Fact, TestCategory("ActivateDeactivate")] public async Task Generic_ScheduleDelayedPingAndDeactivate() { var id = Guid.NewGuid(); var targetId = Guid.NewGuid(); - var grain = this.GrainFactory.GetGrain>(id); - var target = this.GrainFactory.GetGrain>(targetId); + var grain = this.GrainFactory.GetGrain>(id); + var target = this.GrainFactory.GetGrain>(targetId); var s1 = Guid.NewGuid().ToString(); await grain.ScheduleDelayedPingToSelfAndDeactivate(target, s1, TimeSpan.FromSeconds(5)); await Task.Delay(TimeSpan.FromSeconds(6)); @@ -679,19 +656,19 @@ public async Task Generic_ScheduleDelayedPingAndDeactivate() Assert.Equal(s1, s2); } - [Fact, TestCategory("BVT"), TestCategory("Generics"), TestCategory("Serialization")] + [Fact, TestCategory("Serialization")] public async Task SerializationTests_Generic_CircularReferenceTest() { var grainId = Guid.NewGuid(); - var grain = this.GrainFactory.GetGrain(primaryKey: grainId, keyExtension: grainId.ToString("N")); + var grain = this.GrainFactory.GetGrain(primaryKey: grainId, keyExtension: grainId.ToString("N")); _ = await grain.GetState(); } - - [Fact, TestCategory("BVT"), TestCategory("Generics")] + + [Fact] public async Task Generic_GrainWithTypeConstraints() { var grainId = Guid.NewGuid().ToString(); - var grain = this.GrainFactory.GetGrain, int, string>>(grainId); + var grain = this.GrainFactory.GetGrain, int, string>>(grainId); var result = await grain.GetCount(); Assert.Equal(0, result); await grain.Add(42); @@ -715,7 +692,7 @@ public async Task Generic_GrainWithTypeConstraints() } } - [Fact, TestCategory("BVT"), TestCategory("Persistence")] + [Fact, TestCategory("Persistence")] public async Task Generic_GrainWithValueTypeState() { Guid id = Guid.NewGuid(); @@ -731,10 +708,10 @@ public async Task Generic_GrainWithValueTypeState() Assert.Equal(expectedValue, await grain.GetStateData()); } - [Fact(Skip = "https://github.com/dotnet/orleans/issues/1655 Casting from non-generic to generic interface fails with an obscure error message"), TestCategory("Functional"), TestCategory("Cast"), TestCategory("Generics")] - public async Task Generic_CastToGenericInterfaceAfterActivation() + [Fact, TestCategory("Cast")] + public async Task Generic_CastToGenericInterfaceAfterActivation() { - var grain = this.GrainFactory.GetGrain(Guid.NewGuid()); + var grain = this.GrainFactory.GetGrain(Guid.NewGuid()); await grain.DoSomething(); //activates original grain type here var castRef = grain.AsReference>(); @@ -744,9 +721,10 @@ public async Task Generic_CastToGenericInterfaceAfterActivation() Assert.Equal("Hello!", result); } - [Fact(Skip= "https://github.com/dotnet/orleans/issues/1655 Casting from non-generic to generic interface fails with an obscure error message"), TestCategory("Functional"), TestCategory("Cast"), TestCategory("Generics")] - public async Task Generic_CastToDifferentlyConcretizedGenericInterfaceBeforeActivation() { - var grain = this.GrainFactory.GetGrain(Guid.NewGuid()); + [Fact, TestCategory("Cast")] + public async Task Generic_CastToDifferentlyConcretizedGenericInterfaceBeforeActivation() + { + var grain = this.GrainFactory.GetGrain(Guid.NewGuid()); var castRef = grain.AsReference>(); @@ -754,10 +732,11 @@ public async Task Generic_CastToDifferentlyConcretizedGenericInterfaceBeforeActi Assert.Equal("Hello!", result); } - - [Fact, TestCategory("BVT"), TestCategory("Cast")] - public async Task Generic_CastToDifferentlyConcretizedInterfaceBeforeActivation() { - var grain = this.GrainFactory.GetGrain(Guid.NewGuid()); + + [Fact, TestCategory("Cast")] + public async Task Generic_CastToDifferentlyConcretizedInterfaceBeforeActivation() + { + var grain = this.GrainFactory.GetGrain(Guid.NewGuid()); var castRef = grain.AsReference(); @@ -765,10 +744,11 @@ public async Task Generic_CastToDifferentlyConcretizedInterfaceBeforeActivation( Assert.Equal("Hello!", result); } - - [Fact, TestCategory("BVT"), TestCategory("Cast"), TestCategory("Generics")] - public async Task Generic_CastGenericInterfaceToNonGenericInterfaceBeforeActivation() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); + + [Fact, TestCategory("Cast")] + public async Task Generic_CastGenericInterfaceToNonGenericInterfaceBeforeActivation() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var castRef = grain.AsReference(); @@ -776,13 +756,13 @@ public async Task Generic_CastGenericInterfaceToNonGenericInterfaceBeforeActivat Assert.Equal("Hello!", result); } - + /// /// Tests that generic grains can have generic state and that the parameters to the Grain{TState} /// class do not have to match the parameters to the grain class itself. /// /// - [Fact, TestCategory("BVT"), TestCategory("Generics")] + [Fact] public async Task GenericGrainStateParameterMismatchTest() { var grain = this.GrainFactory.GetGrain, string>>(Guid.NewGuid()); @@ -794,288 +774,198 @@ public async Task GenericGrainStateParameterMismatchTest() namespace Generic.EdgeCases { using UnitTests.GrainInterfaces.Generic.EdgeCases; + using UnitTests.Grains.Generic.EdgeCases; - + [TestCategory("BVT"), TestCategory("Generics")] public class GenericEdgeCaseTests : HostedTestClusterEnsureDefaultStarted { public GenericEdgeCaseTests(DefaultClusterFixture fixture) : base(fixture) { } - private static async Task GetConcreteGenArgs(IBasicGrain @this) { + private static async Task GetConcreteGenArgs(IBasicGrain @this) + { var genArgTypeNames = await @this.ConcreteGenArgTypeNames(); - - return genArgTypeNames.Select(n => Type.GetType(n)) - .ToArray(); + return genArgTypeNames.Select(Type.GetType).ToArray(); } - - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_PartiallySpecifyingGenericGrainFulfilsInterface() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); + [Fact(Skip = "Currently unsupported")] + public async Task Generic_PartiallySpecifyingGenericGrainFulfilsInterface() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var concreteGenArgs = await GetConcreteGenArgs(grain); - - Assert.True( - concreteGenArgs.SequenceEqual(new[] { typeof(int) }) - ); + Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(int) })); } - - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_GenericGrainCanReuseOwnGenArgRepeatedly() { - //resolves correctly but can't be activated: too many gen args supplied for concrete class - - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); + [Fact(Skip = "Currently unsupported")] + public async Task Generic_GenericGrainCanReuseOwnGenArgRepeatedly() + { + // Resolves correctly but can't be activated: too many gen args supplied for concrete class + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var concreteGenArgs = await GetConcreteGenArgs(grain); - - Assert.True( - concreteGenArgs.SequenceEqual(new[] { typeof(int) }) - ); + Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(int) })); } - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_PartiallySpecifyingGenericInterfaceIsCastable() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); - + [Fact] + public async Task Generic_PartiallySpecifyingGenericInterfaceIsCastable() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); await grain.Hello(); - var castRef = grain.AsReference>(); - var response = await castRef.Hello(); - Assert.Equal("Hello!", response); } - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_PartiallySpecifyingGenericInterfaceIsCastable_Activating() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); - + [Fact] + public async Task Generic_PartiallySpecifyingGenericInterfaceIsCastable_Activating() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var castRef = grain.AsReference>(); - var response = await castRef.Hello(); - Assert.Equal("Hello!", response); } - - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_RepeatedRearrangedGenArgsResolved() { - //again resolves to the correct generic type definition, but fails on activation as too many args - //gen args aren't being properly inferred from matched concrete type - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); + [Fact(Skip = "Currently unsupported")] + public async Task Generic_RepeatedRearrangedGenArgsResolved() + { + // Again resolves to the correct generic type definition, but fails on activation as too many args + // gen args aren't being properly inferred from matched concrete type + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var concreteGenArgs = await GetConcreteGenArgs(grain); - - Assert.True( - concreteGenArgs.SequenceEqual(new[] { typeof(string), typeof(int) }) - ); + Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(string), typeof(int) })); } - - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_RepeatedGenArgsWorkAmongstInterfacesInTypeResolution() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); + [Fact] + public async Task Generic_RepeatedGenArgsWorkAmongstInterfacesInTypeResolution() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var concreteGenArgs = await GetConcreteGenArgs(grain); - - Assert.True( - concreteGenArgs.SequenceEqual(Enumerable.Empty()) - ); + Assert.True(concreteGenArgs.SequenceEqual(Enumerable.Empty())); } - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_RepeatedGenArgsWorkAmongstInterfacesInCasting() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); - + [Fact] + public async Task Generic_RepeatedGenArgsWorkAmongstInterfacesInCasting() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); await grain.Hello(); - var castRef = grain.AsReference>(); - var response = await castRef.Hello(); - Assert.Equal("Hello!", response); } - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_RepeatedGenArgsWorkAmongstInterfacesInCasting_Activating() { - //Only errors on invocation: wrong arity again - - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); - + [Fact] + public async Task Generic_RepeatedGenArgsWorkAmongstInterfacesInCasting_Activating() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var castRef = grain.AsReference>(); - var response = await castRef.Hello(); - Assert.Equal("Hello!", response); } - - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_RearrangedGenArgsOfCorrectArityAreResolved() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); + [Fact(Skip = "Currently unsupported")] + public async Task Generic_RearrangedGenArgsOfCorrectArityAreResolved() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var concreteGenArgs = await GetConcreteGenArgs(grain); - - Assert.True( - concreteGenArgs.SequenceEqual(new[] { typeof(long), typeof(int) }) - ); + Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(long), typeof(int) })); } - - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_RearrangedGenArgsOfCorrectNumberAreCastable() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); + [Fact] + public async Task Generic_RearrangedGenArgsOfCorrectNumberAreCastable() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); await grain.Hello(); - var castRef = grain.AsReference>(); - var response = await castRef.Hello(); - Assert.Equal("Hello!", response); } - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_RearrangedGenArgsOfCorrectNumberAreCastable_Activating() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); - + [Fact] + public async Task Generic_RearrangedGenArgsOfCorrectNumberAreCastable_Activating() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var castRef = grain.AsReference>(); - var response = await castRef.Hello(); - Assert.Equal("Hello!", response); } + public interface IFullySpecifiedGenericInterface : IBasicGrain + { } + public interface IDerivedFromMultipleSpecializationsOfSameInterface : IFullySpecifiedGenericInterface, IFullySpecifiedGenericInterface + { } - //************************************************************************************************************** - //************************************************************************************************************** - - //Below must be commented out, as supplying multiple fully-specified generic interfaces - //to a class causes the codegen to fall over, stopping all other tests from working. - - //See new test here of the bit causing the issue - type info conflation: - //UnitTests.CodeGeneration.CodeGeneratorTests.CodeGen_EncounteredFullySpecifiedInterfacesAreEncodedDistinctly() - - - //public interface IFullySpecifiedGenericInterface : IBasicGrain - //{ } - - //public interface IDerivedFromMultipleSpecializationsOfSameInterface : IFullySpecifiedGenericInterface, IFullySpecifiedGenericInterface - //{ } - - //public class GrainFulfillingMultipleSpecializationsOfSameInterfaceViaIntermediate : BasicGrain, IDerivedFromMultipleSpecializationsOfSameInterface - //{ } - - - //[Fact, TestCategory("Generics")] - //public async Task CastingBetweenFullySpecifiedGenericInterfaces() - //{ - // //Is this legitimate? Solely in the realm of virtual grain interfaces - no special knowledge of implementation implicated, only of interface hierarchy - - // //codegen falling over: duplicate key when both specializations are matched to same concrete type - - // var grain = this.GrainFactory.GetGrain(Guid.NewGuid()); - - // await grain.Hello(); - - // var castRef = grain.AsReference>(); - - // await castRef.Hello(); - - // var castRef2 = castRef.AsReference>(); - - // await castRef2.Hello(); - //} - - //******************************************************************************************************* - - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_CanCastToFullySpecifiedInterfaceUnrelatedToConcreteGenArgs() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); + public class GrainFulfillingMultipleSpecializationsOfSameInterfaceViaIntermediate : BasicGrain, IDerivedFromMultipleSpecializationsOfSameInterface + { } + [Fact] + public async Task CastingBetweenFullySpecifiedGenericInterfaces() + { + var grain = this.GrainFactory.GetGrain(Guid.NewGuid()); await grain.Hello(); + var castRef = grain.AsReference>(); + await castRef.Hello(); + var castRef2 = castRef.AsReference>(); + await castRef2.Hello(); + } + [Fact] + public async Task Generic_CanCastToFullySpecifiedInterfaceUnrelatedToConcreteGenArgs() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); + await grain.Hello(); _ = grain.AsReference>(); - var response = await grain.Hello(); - Assert.Equal("Hello!", response); } - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_CanCastToFullySpecifiedInterfaceUnrelatedToConcreteGenArgs_Activating() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); - + [Fact] + public async Task Generic_CanCastToFullySpecifiedInterfaceUnrelatedToConcreteGenArgs_Activating() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); _ = grain.AsReference>(); - var response = await grain.Hello(); - Assert.Equal("Hello!", response); } - - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_GenArgsCanBeFurtherSpecialized() { - var grain = this.GrainFactory.GetGrain>>(Guid.NewGuid()); + [Fact(Skip = "Currently unsupported")] + public async Task Generic_GenArgsCanBeFurtherSpecialized() + { + var grain = this.GrainFactory.GetGrain>>(Guid.NewGuid()); var concreteGenArgs = await GetConcreteGenArgs(grain); - - Assert.True( - concreteGenArgs.SequenceEqual(new[] { typeof(int) }) - ); + Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(int) })); } - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_GenArgsCanBeFurtherSpecializedIntoArrays() { - var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); - + [Fact(Skip = "Currently unsupported")] + public async Task Generic_GenArgsCanBeFurtherSpecializedIntoArrays() + { + var grain = this.GrainFactory.GetGrain>(Guid.NewGuid()); var concreteGenArgs = await GetConcreteGenArgs(grain); - - Assert.True( - concreteGenArgs.SequenceEqual(new[] { typeof(long) }) - ); + Assert.True(concreteGenArgs.SequenceEqual(new[] { typeof(long) })); } - - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_CanCastBetweenInterfacesWithFurtherSpecializedGenArgs() { - var grain = this.GrainFactory.GetGrain>>(Guid.NewGuid()); + [Fact(Skip = "Currently unsupported")] + public async Task Generic_CanCastBetweenInterfacesWithFurtherSpecializedGenArgs() + { + var grain = this.GrainFactory.GetGrain>>(Guid.NewGuid()); await grain.Hello(); _ = grain.AsReference>(); - var response = await grain.Hello(); - Assert.Equal("Hello!", response); } - - [Fact(Skip = "Currently unsupported"), TestCategory("Generics")] - public async Task Generic_CanCastBetweenInterfacesWithFurtherSpecializedGenArgs_Activating() { - var grain = this.GrainFactory.GetGrain>>(Guid.NewGuid()); + [Fact(Skip = "Currently unsupported")] + public async Task Generic_CanCastBetweenInterfacesWithFurtherSpecializedGenArgs_Activating() + { + var grain = this.GrainFactory.GetGrain>>(Guid.NewGuid()); _ = grain.AsReference>(); var response = await grain.Hello(); Assert.Equal("Hello!", response); } - } - - } - - } \ No newline at end of file diff --git a/test/Grains/TestGrains/GenericGrains.cs b/test/Grains/TestGrains/GenericGrains.cs index 7907c624a8..04a7a51999 100644 --- a/test/Grains/TestGrains/GenericGrains.cs +++ b/test/Grains/TestGrains/GenericGrains.cs @@ -742,7 +742,6 @@ public Task RoundTrip(C value) } } - public class NonGenericCastableGrain : Grain, INonGenericCastableGrain, ISomeGenericGrain, IIndependentlyConcretizedGenericGrain, IIndependentlyConcretizedGrain { public Task DoSomething() { @@ -754,7 +753,6 @@ public Task Hello() { } } - public class GenericCastableGrain : Grain, IGenericCastableGrain, INonGenericCastGrain { public Task Hello() { @@ -773,11 +771,9 @@ public Task Set(T[] value) } } - public class IndepedentlyConcretizedGenericGrain : Grain, IIndependentlyConcretizedGenericGrain, IIndependentlyConcretizedGrain + public class IndependentlyConcretizedGenericGrain : Grain, IIndependentlyConcretizedGenericGrain, IIndependentlyConcretizedGrain { - public Task Hello() { - return Task.FromResult("I have been independently concretized!"); - } + public Task Hello() => Task.FromResult("I have been independently concretized!"); } public interface IReducer @@ -785,7 +781,6 @@ public interface IReducer Task Handle(TState prevState, TAction act); } - [Serializable] [GenerateSerializer] public class Reducer1Action { } @@ -842,25 +837,23 @@ namespace Generic.EdgeCases using System.Linq; using UnitTests.GrainInterfaces.Generic.EdgeCases; - public abstract class BasicGrain : Grain { - public Task Hello() { + public Task Hello() + { return Task.FromResult("Hello!"); } - public Task ConcreteGenArgTypeNames() { + public Task ConcreteGenArgTypeNames() + { var grainType = GetImmediateSubclass(this.GetType()); - - return Task.FromResult( - grainType.GetGenericArguments() - .Select(t => t.FullName) - .ToArray() - ); + return Task.FromResult(grainType.GetGenericArguments().Select(t => t.FullName).ToArray()); } - private Type GetImmediateSubclass(Type subject) { - if(subject.BaseType == typeof(BasicGrain)) { + private Type GetImmediateSubclass(Type subject) + { + if(subject.BaseType == typeof(BasicGrain)) + { return subject; } @@ -868,39 +861,30 @@ private Type GetImmediateSubclass(Type subject) { } } - - public class PartiallySpecifyingGrain : BasicGrain, IGrainWithTwoGenArgs { } - public class GrainWithPartiallySpecifyingInterface : BasicGrain, IPartiallySpecifyingInterface { } - public class GrainSpecifyingSameGenArgTwice : BasicGrain, IGrainReceivingRepeatedGenArgs { } - public class SpecifyingRepeatedGenArgsAmongstOthers : BasicGrain, IReceivingRepeatedGenArgsAmongstOthers { } public class GrainForTestingCastingBetweenInterfacesWithReusedGenArgs : BasicGrain, ISpecifyingGenArgsRepeatedlyToParentInterface { } - public class SpecifyingSameGenArgsButRearranged : BasicGrain, IReceivingRearrangedGenArgs { } - public class GrainForTestingCastingWithRearrangedGenArgs : BasicGrain, ISpecifyingRearrangedGenArgsToParentInterface { } - public class GrainWithGenArgsUnrelatedToFullySpecifiedGenericInterface : BasicGrain, IArbitraryInterface, IInterfaceUnrelatedToConcreteGenArgs { } - public class GrainSupplyingFurtherSpecializedGenArg : BasicGrain, IInterfaceTakingFurtherSpecializedGenArg> { } @@ -910,8 +894,5 @@ public class GrainSupplyingGenArgSpecializedIntoArray : BasicGrain, IInterfac public class GrainForCastingBetweenInterfacesOfFurtherSpecializedGenArgs : BasicGrain, IAnotherReceivingFurtherSpecializedGenArg>, IYetOneMoreReceivingFurtherSpecializedGenArg { } - - } - }