diff --git a/Directory.Packages.props b/Directory.Packages.props index 6efc523..99c03ac 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,19 +1,25 @@ - - - true - true - - - - - - - - - - - - - - + + + true + true + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TypedSignalR.Client.sln b/TypedSignalR.Client.sln index f465083..7c496f7 100644 --- a/TypedSignalR.Client.sln +++ b/TypedSignalR.Client.sln @@ -36,6 +36,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Packages.props = Directory.Packages.props EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TypedSignalR.Client.SourceGeneratorTests", "tests\TypedSignalR.Client.SourceGeneratorTests\TypedSignalR.Client.SourceGeneratorTests.csproj", "{547B45CB-8CAD-6B6B-5E80-88AE3B93A43F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -86,6 +88,10 @@ Global {4AD46B59-DB78-465F-BF10-F0F74B34722D}.Debug|Any CPU.Build.0 = Debug|Any CPU {4AD46B59-DB78-465F-BF10-F0F74B34722D}.Release|Any CPU.ActiveCfg = Release|Any CPU {4AD46B59-DB78-465F-BF10-F0F74B34722D}.Release|Any CPU.Build.0 = Release|Any CPU + {547B45CB-8CAD-6B6B-5E80-88AE3B93A43F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {547B45CB-8CAD-6B6B-5E80-88AE3B93A43F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {547B45CB-8CAD-6B6B-5E80-88AE3B93A43F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {547B45CB-8CAD-6B6B-5E80-88AE3B93A43F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -102,6 +108,7 @@ Global {0628FEE3-2C6E-4C02-A398-4E55781A5A85} = {2F614DC6-F5D9-4872-9B4E-70F39B02D6EC} {4D174400-02DF-4816-8CFC-A94DB3DBBBFA} = {2F614DC6-F5D9-4872-9B4E-70F39B02D6EC} {4AD46B59-DB78-465F-BF10-F0F74B34722D} = {196DB73F-4D3E-4A90-AE48-40925CB33560} + {547B45CB-8CAD-6B6B-5E80-88AE3B93A43F} = {2F614DC6-F5D9-4872-9B4E-70F39B02D6EC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3C64E712-2479-4BF8-9169-B21DC3E787EC} diff --git a/src/TypedSignalR.Client/CodeAnalysis/MethodMetadata.cs b/src/TypedSignalR.Client/CodeAnalysis/MethodMetadata.cs index b974302..76db70e 100644 --- a/src/TypedSignalR.Client/CodeAnalysis/MethodMetadata.cs +++ b/src/TypedSignalR.Client/CodeAnalysis/MethodMetadata.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Microsoft.CodeAnalysis; @@ -12,6 +13,7 @@ public sealed class MethodMetadata public IReadOnlyList Parameters { get; } public string MethodName { get; } + public string SignalRMethodName { get; } public string ReturnType { get; } public bool IsGenericReturnType { get; } public string? GenericReturnTypeArgument { get; } @@ -25,6 +27,15 @@ public MethodMetadata(IMethodSymbol methodSymbol) .Select(x => new ParameterMetadata(x)) .ToArray(); + SignalRMethodName = + ( + methodSymbol.GetAttributes() + .FirstOrDefault(x => x.AttributeClass?.ToDisplayString() == "Microsoft.AspNetCore.SignalR.HubMethodNameAttribute") + ?.ConstructorArguments.SingleOrDefault() + ) + ?.Value?.ToString() + ?? MethodName; + ReturnType = methodSymbol.ReturnType.ToDisplayString(SymbolDisplayFormatRule.FullyQualifiedNullableReferenceTypeFormat); INamedTypeSymbol? returnTypeSymbol = methodSymbol.ReturnType as INamedTypeSymbol; diff --git a/src/TypedSignalR.Client/Templates/HubConnectionExtensionsBinderTemplate.cs b/src/TypedSignalR.Client/Templates/HubConnectionExtensionsBinderTemplate.cs index c037610..fc99520 100644 --- a/src/TypedSignalR.Client/Templates/HubConnectionExtensionsBinderTemplate.cs +++ b/src/TypedSignalR.Client/Templates/HubConnectionExtensionsBinderTemplate.cs @@ -106,7 +106,7 @@ private string CreateRegistrationString(TypeMetadata receiverType) private string CreateRegistrationStringCore(MethodMetadata method) { return $$""" - compositeDisposable.Add(global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.On(connection, nameof(receiver.{{method.MethodName}}), {{method.CreateParameterTypeArrayString(_specialSymbols)}}, HandlerConverter.Convert{{method.CreateTypeArgumentsStringForHandlerConverter(_specialSymbols)}}(receiver.{{method.MethodName}}))); + compositeDisposable.Add(global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.On(connection, "{{method.SignalRMethodName}}", {{method.CreateParameterTypeArrayString(_specialSymbols)}}, HandlerConverter.Convert{{method.CreateTypeArgumentsStringForHandlerConverter(_specialSymbols)}}(receiver.{{method.MethodName}}))); """; } } diff --git a/src/TypedSignalR.Client/Templates/MethodMetadataExtensions.cs b/src/TypedSignalR.Client/Templates/MethodMetadataExtensions.cs index 404fc02..bbd158e 100644 --- a/src/TypedSignalR.Client/Templates/MethodMetadataExtensions.cs +++ b/src/TypedSignalR.Client/Templates/MethodMetadataExtensions.cs @@ -278,7 +278,7 @@ private static string CreateUnaryMethodString(MethodMetadata method) return $$""" public {{method.ReturnType}} {{method.MethodName}}({{method.CreateParametersString()}}) { - return global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.InvokeCoreAsync{{method.CreateGenericReturnTypeArgumentString()}}(_connection, nameof({{method.MethodName}}), {{method.CreateArgumentsString()}}, _cancellationToken); + return global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.InvokeCoreAsync{{method.CreateGenericReturnTypeArgumentString()}}(_connection, "{{method.SignalRMethodName}}", {{method.CreateArgumentsString()}}, _cancellationToken); } """; } @@ -288,7 +288,7 @@ private static string CreateServerStreamingMethodAsAsyncEnumerableString(MethodM return $$""" public {{method.ReturnType}} {{method.MethodName}}({{method.CreateParametersString()}}) { - return _connection.StreamAsyncCore{{method.CreateGenericReturnTypeArgumentString()}}(nameof({{method.MethodName}}), {{method.CreateArgumentsStringExceptCancellationToken(specialSymbols)}}, {{method.CreateCancellationTokenString("_cancellationToken", specialSymbols)}}); + return _connection.StreamAsyncCore{{method.CreateGenericReturnTypeArgumentString()}}("{{method.SignalRMethodName}}", {{method.CreateArgumentsStringExceptCancellationToken(specialSymbols)}}, {{method.CreateCancellationTokenString("_cancellationToken", specialSymbols)}}); } """; } @@ -298,7 +298,7 @@ private static string CreateServerStreamingMethodAsTaskAsyncEnumerableString(Met return $$""" public {{method.ReturnType}} {{method.MethodName}}({{method.CreateParametersString()}}) { - var ret = _connection.StreamAsyncCore{{method.CreateGenericReturnTypeArgumentStringForStreaming()}}(nameof({{method.MethodName}}), {{method.CreateArgumentsStringExceptCancellationToken(specialSymbols)}}, {{method.CreateCancellationTokenString("_cancellationToken", specialSymbols)}}); + var ret = _connection.StreamAsyncCore{{method.CreateGenericReturnTypeArgumentStringForStreaming()}}("{{method.SignalRMethodName}}", {{method.CreateArgumentsStringExceptCancellationToken(specialSymbols)}}, {{method.CreateCancellationTokenString("_cancellationToken", specialSymbols)}}); return global::System.Threading.Tasks.Task.FromResult(ret); } """; @@ -309,7 +309,7 @@ private static string CreateServerStreamingMethodAsChannelString(MethodMetadata return $$""" public {{method.ReturnType}} {{method.MethodName}}({{method.CreateParametersString()}}) { - return global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.StreamAsChannelCoreAsync{{method.CreateGenericReturnTypeArgumentStringForStreaming()}}(_connection, nameof({{method.MethodName}}), {{method.CreateArgumentsStringExceptCancellationToken(specialSymbols)}}, {{method.CreateCancellationTokenString("_cancellationToken", specialSymbols)}}); + return global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.StreamAsChannelCoreAsync{{method.CreateGenericReturnTypeArgumentStringForStreaming()}}(_connection, "{{method.SignalRMethodName}}", {{method.CreateArgumentsStringExceptCancellationToken(specialSymbols)}}, {{method.CreateCancellationTokenString("_cancellationToken", specialSymbols)}}); } """; } @@ -319,7 +319,7 @@ private static string CreateClientStreamingMethodAsAsyncEnumerableString(MethodM return $$""" public {{method.ReturnType}} {{method.MethodName}}({{method.CreateParametersString()}}) { - return _connection.SendCoreAsync(nameof({{method.MethodName}}), {{method.CreateArgumentsString()}}, _cancellationToken); + return _connection.SendCoreAsync("{{method.SignalRMethodName}}", {{method.CreateArgumentsString()}}, _cancellationToken); } """; } @@ -330,7 +330,7 @@ private static string CreateClientStreamingMethodAsChannelString(MethodMetadata public {{method.ReturnType}} {{method.MethodName}}({{method.CreateParametersString()}}) { - return _connection.SendCoreAsync(nameof({{method.MethodName}}), {{method.CreateArgumentsString()}}, _cancellationToken); + return _connection.SendCoreAsync("{{method.SignalRMethodName}}", {{method.CreateArgumentsString()}}, _cancellationToken); } """; } diff --git a/tests/TypedSignalR.Client.SourceGeneratorTests/CompilationHelper.cs b/tests/TypedSignalR.Client.SourceGeneratorTests/CompilationHelper.cs new file mode 100644 index 0000000..9c81ff9 --- /dev/null +++ b/tests/TypedSignalR.Client.SourceGeneratorTests/CompilationHelper.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Xunit; + +namespace TypedSignalR.Client.SourceGeneratorTests; + +using System.Collections.Generic; +using global::TypedSignalR.Client; + +public static class CompilationHelper +{ + public static (ImmutableArray diagnostics, Dictionary outputs) GetGeneratedOutput(string source) + { + const LanguageVersion LanguageVersion = LanguageVersion.CSharp12; + + var generator = new SourceGenerator(); + + var sourceSyntaxTree = CSharpSyntaxTree.ParseText(source, path: "source.cs"); + var parsingOptions = new CSharpParseOptions(LanguageVersion); + var sourceSyntaxTreeWithOptions = sourceSyntaxTree.WithRootAndOptions(sourceSyntaxTree.GetRoot(), parsingOptions); + + var references = AppDomain.CurrentDomain.GetAssemblies() + .Where(assembly => !assembly.IsDynamic && !string.IsNullOrWhiteSpace(assembly.Location)) + .Select(assembly => MetadataReference.CreateFromFile(assembly.Location)) + .Concat([ + MetadataReference.CreateFromFile(generator.GetType().Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.Threading.Tasks.Task).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Microsoft.AspNetCore.SignalR.HubMethodNameAttribute).Assembly.Location), + MetadataReference.CreateFromFile(typeof(Microsoft.AspNetCore.SignalR.Client.HubConnection).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute).Assembly.Location), + MetadataReference.CreateFromFile(typeof(System.CodeDom.Compiler.GeneratedCodeAttribute).Assembly.Location) + ]); + + var compilation = CSharpCompilation.Create( + "generator", + [sourceSyntaxTreeWithOptions], + references, + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + + GeneratorDriver driver = + CSharpGeneratorDriver.Create( + [generator.AsSourceGenerator()], + driverOptions: new GeneratorDriverOptions( + disabledOutputs: IncrementalGeneratorOutputKind.None, + trackIncrementalGeneratorSteps: true), + optionsProvider: null, + parseOptions: new CSharpParseOptions(LanguageVersion)); + + driver = driver.RunGenerators(compilation); + + var runResult = driver.GetRunResult(); + + return (runResult.Diagnostics, runResult.Results.SelectMany(r => r.GeneratedSources).ToDictionary(s => s.HintName, s => s.SourceText.ToString())); + } +} diff --git a/tests/TypedSignalR.Client.SourceGeneratorTests/HubMethodNameTests.cs b/tests/TypedSignalR.Client.SourceGeneratorTests/HubMethodNameTests.cs new file mode 100644 index 0000000..5a5eff2 --- /dev/null +++ b/tests/TypedSignalR.Client.SourceGeneratorTests/HubMethodNameTests.cs @@ -0,0 +1,1214 @@ +using System.Threading.Tasks; +using TypedSignalR.Client.SourceGeneratorTests; +using Xunit; + +namespace TypedSignalR.Client.SourceGenerator.Tests; + +public class HubMethodNameTests +{ + [Fact] + public async Task InvokerMethodWithoutUseHubMethodName() + { + // Arrange + + var source = """ + using Microsoft.AspNetCore.SignalR; + using Microsoft.AspNetCore.SignalR.Client; + using TypedSignalR.Client; + + public interface IHubInvokerContractWithHubMethodName + { + System.Threading.Tasks.Task SendMessage(); + } + + public static class HubConnectionExtensions + { + public static IHubInvokerContractWithHubMethodName CreateHubProxy(this HubConnection connection) + { + return connection.CreateHubProxy(); + } + } + """; + + // Act + + var (diagnostics, outputs) = CompilationHelper.GetGeneratedOutput(source); + + // Assert + + Assert.Empty(diagnostics); + + Assert.Equal(4, outputs.Count); + + Assert_TypedSignalR_Client_Components_Generated(outputs); + + Assert_TypedSignalR_Client_HubConnectionExtensions_Generated(outputs); + + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + #pragma warning disable CS8767 + #pragma warning disable CS8613 + namespace TypedSignalR.Client + { + internal static partial class HubConnectionExtensions + { + private static partial global::System.Collections.Generic.Dictionary CreateBinders() + { + var binders = new global::System.Collections.Generic.Dictionary(); + + + return binders; + } + } + } + #pragma warning restore CS8613 + #pragma warning restore CS8767 + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.HubConnectionExtensions.Binder.Generated.cs"]); + + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + #pragma warning disable CS8767 + #pragma warning disable CS8613 + namespace TypedSignalR.Client + { + internal static partial class HubConnectionExtensions + { + private sealed class HubInvokerFor_global__IHubInvokerContractWithHubMethodName : global::IHubInvokerContractWithHubMethodName, IHubInvoker + { + private readonly global::Microsoft.AspNetCore.SignalR.Client.HubConnection _connection; + private readonly global::System.Threading.CancellationToken _cancellationToken; + + public HubInvokerFor_global__IHubInvokerContractWithHubMethodName(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken) + { + _connection = connection; + _cancellationToken = cancellationToken; + } + + public global::System.Threading.Tasks.Task SendMessage() + { + return global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.InvokeCoreAsync(_connection, "SendMessage", global::System.Array.Empty(), _cancellationToken); + } + } + + private sealed class HubInvokerFactoryFor_global__IHubInvokerContractWithHubMethodName : IHubInvokerFactory + { + public global::IHubInvokerContractWithHubMethodName CreateHubInvoker(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken) + { + return new HubInvokerFor_global__IHubInvokerContractWithHubMethodName(connection, cancellationToken); + } + } + + private static partial global::System.Collections.Generic.Dictionary CreateFactories() + { + var factories = new global::System.Collections.Generic.Dictionary(); + + factories.Add(typeof(global::IHubInvokerContractWithHubMethodName), new HubInvokerFactoryFor_global__IHubInvokerContractWithHubMethodName()); + + return factories; + } + } + } + #pragma warning restore CS8613 + #pragma warning restore CS8767 + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.HubConnectionExtensions.HubInvoker.Generated.cs"]); + } + + [Fact] + public async Task InvokerMethodWithUseHubMethodName() + { + // Arrange + + var source = """ + using Microsoft.AspNetCore.SignalR; + using Microsoft.AspNetCore.SignalR.Client; + using TypedSignalR.Client; + + public interface IHubInvokerContractWithHubMethodName + { + [HubMethodName("SendMessage")] + System.Threading.Tasks.Task SendMessageAsync(); + } + + public static class HubConnectionExtensions + { + public static IHubInvokerContractWithHubMethodName CreateHubProxy(this HubConnection connection) + { + return connection.CreateHubProxy(); + } + } + """; + + // Act + + var (diagnostics, outputs) = CompilationHelper.GetGeneratedOutput(source); + + // Assert + + Assert.Empty(diagnostics); + + Assert.Equal(4, outputs.Count); + + Assert_TypedSignalR_Client_Components_Generated(outputs); + + Assert_TypedSignalR_Client_HubConnectionExtensions_Generated(outputs); + + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + #pragma warning disable CS8767 + #pragma warning disable CS8613 + namespace TypedSignalR.Client + { + internal static partial class HubConnectionExtensions + { + private static partial global::System.Collections.Generic.Dictionary CreateBinders() + { + var binders = new global::System.Collections.Generic.Dictionary(); + + + return binders; + } + } + } + #pragma warning restore CS8613 + #pragma warning restore CS8767 + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.HubConnectionExtensions.Binder.Generated.cs"]); + + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + #pragma warning disable CS8767 + #pragma warning disable CS8613 + namespace TypedSignalR.Client + { + internal static partial class HubConnectionExtensions + { + private sealed class HubInvokerFor_global__IHubInvokerContractWithHubMethodName : global::IHubInvokerContractWithHubMethodName, IHubInvoker + { + private readonly global::Microsoft.AspNetCore.SignalR.Client.HubConnection _connection; + private readonly global::System.Threading.CancellationToken _cancellationToken; + + public HubInvokerFor_global__IHubInvokerContractWithHubMethodName(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken) + { + _connection = connection; + _cancellationToken = cancellationToken; + } + + public global::System.Threading.Tasks.Task SendMessageAsync() + { + return global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.InvokeCoreAsync(_connection, "SendMessage", global::System.Array.Empty(), _cancellationToken); + } + } + + private sealed class HubInvokerFactoryFor_global__IHubInvokerContractWithHubMethodName : IHubInvokerFactory + { + public global::IHubInvokerContractWithHubMethodName CreateHubInvoker(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken) + { + return new HubInvokerFor_global__IHubInvokerContractWithHubMethodName(connection, cancellationToken); + } + } + + private static partial global::System.Collections.Generic.Dictionary CreateFactories() + { + var factories = new global::System.Collections.Generic.Dictionary(); + + factories.Add(typeof(global::IHubInvokerContractWithHubMethodName), new HubInvokerFactoryFor_global__IHubInvokerContractWithHubMethodName()); + + return factories; + } + } + } + #pragma warning restore CS8613 + #pragma warning restore CS8767 + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.HubConnectionExtensions.HubInvoker.Generated.cs"]); + } + + [Fact] + public async Task ReceiverMethodWithoutUseHubMethodName() + { + // Arrange + + var source = """ + using Microsoft.AspNetCore.SignalR; + using Microsoft.AspNetCore.SignalR.Client; + using TypedSignalR.Client; + + public interface IHubReceiverContractWithHubMethodName + { + System.Threading.Tasks.Task ReceiveMessage(); + } + + public static class HubConnectionExtensions + { + public static IDisposable Register(this HubConnection connection, IHubReceiverContractWithHubMethodName receiver) + { + return connection.Register(receiver); + } + } + """; + + // Act + + var (diagnostics, outputs) = CompilationHelper.GetGeneratedOutput(source); + + // Assert + + Assert.Empty(diagnostics); + + Assert.Equal(4, outputs.Count); + + Assert_TypedSignalR_Client_Components_Generated(outputs); + + Assert_TypedSignalR_Client_HubConnectionExtensions_Generated(outputs); + + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + #pragma warning disable CS8767 + #pragma warning disable CS8613 + namespace TypedSignalR.Client + { + internal static partial class HubConnectionExtensions + { + private sealed class BinderFor_global__IHubReceiverContractWithHubMethodName : IReceiverBinder + { + public global::System.IDisposable Bind(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::IHubReceiverContractWithHubMethodName receiver) + { + var compositeDisposable = new CompositeDisposable(1); + + compositeDisposable.Add(global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.On(connection, "ReceiveMessage", global::System.Type.EmptyTypes, HandlerConverter.Convert(receiver.ReceiveMessage))); + + return compositeDisposable; + } + } + + private static partial global::System.Collections.Generic.Dictionary CreateBinders() + { + var binders = new global::System.Collections.Generic.Dictionary(); + + binders.Add(typeof(global::IHubReceiverContractWithHubMethodName), new BinderFor_global__IHubReceiverContractWithHubMethodName()); + + return binders; + } + } + } + #pragma warning restore CS8613 + #pragma warning restore CS8767 + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.HubConnectionExtensions.Binder.Generated.cs"]); + + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + #pragma warning disable CS8767 + #pragma warning disable CS8613 + namespace TypedSignalR.Client + { + internal static partial class HubConnectionExtensions + { + private static partial global::System.Collections.Generic.Dictionary CreateFactories() + { + var factories = new global::System.Collections.Generic.Dictionary(); + + + return factories; + } + } + } + #pragma warning restore CS8613 + #pragma warning restore CS8767 + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.HubConnectionExtensions.HubInvoker.Generated.cs"]); + } + + [Fact] + public async Task ReceiverMethodWithUseHubMethodName() + { + // Arrange + + var source = """ + using Microsoft.AspNetCore.SignalR; + using Microsoft.AspNetCore.SignalR.Client; + using TypedSignalR.Client; + + public interface IHubReceiverContractWithHubMethodName + { + [HubMethodName("ReceiveMessage")] + System.Threading.Tasks.Task ReceiveMessageAsync(); + } + + public static class HubConnectionExtensions + { + public static IDisposable Register(this HubConnection connection, IHubReceiverContractWithHubMethodName receiver) + { + return connection.Register(receiver); + } + } + """; + + // Act + + var (diagnostics, outputs) = CompilationHelper.GetGeneratedOutput(source); + + // Assert + + Assert.Empty(diagnostics); + + Assert.Equal(4, outputs.Count); + + Assert_TypedSignalR_Client_Components_Generated(outputs); + + Assert_TypedSignalR_Client_HubConnectionExtensions_Generated(outputs); + + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + #pragma warning disable CS8767 + #pragma warning disable CS8613 + namespace TypedSignalR.Client + { + internal static partial class HubConnectionExtensions + { + private sealed class BinderFor_global__IHubReceiverContractWithHubMethodName : IReceiverBinder + { + public global::System.IDisposable Bind(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::IHubReceiverContractWithHubMethodName receiver) + { + var compositeDisposable = new CompositeDisposable(1); + + compositeDisposable.Add(global::Microsoft.AspNetCore.SignalR.Client.HubConnectionExtensions.On(connection, "ReceiveMessage", global::System.Type.EmptyTypes, HandlerConverter.Convert(receiver.ReceiveMessageAsync))); + + return compositeDisposable; + } + } + + private static partial global::System.Collections.Generic.Dictionary CreateBinders() + { + var binders = new global::System.Collections.Generic.Dictionary(); + + binders.Add(typeof(global::IHubReceiverContractWithHubMethodName), new BinderFor_global__IHubReceiverContractWithHubMethodName()); + + return binders; + } + } + } + #pragma warning restore CS8613 + #pragma warning restore CS8767 + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.HubConnectionExtensions.Binder.Generated.cs"]); + + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + #pragma warning disable CS8767 + #pragma warning disable CS8613 + namespace TypedSignalR.Client + { + internal static partial class HubConnectionExtensions + { + private static partial global::System.Collections.Generic.Dictionary CreateFactories() + { + var factories = new global::System.Collections.Generic.Dictionary(); + + + return factories; + } + } + } + #pragma warning restore CS8613 + #pragma warning restore CS8767 + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.HubConnectionExtensions.HubInvoker.Generated.cs"]); + } + + private static void Assert_TypedSignalR_Client_Components_Generated(System.Collections.Generic.Dictionary outputs) + { + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + namespace TypedSignalR.Client + { + internal interface IHubConnectionObserver + { + global::System.Threading.Tasks.Task OnClosed(global::System.Exception? exception); + global::System.Threading.Tasks.Task OnReconnected(string? connectionId); + global::System.Threading.Tasks.Task OnReconnecting(global::System.Exception? exception); + } + + internal interface IHubInvoker + { + } + + internal interface IHubInvokerFactory + { + } + + internal interface IHubInvokerFactory : IHubInvokerFactory + { + T CreateHubInvoker(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken); + } + + internal interface IReceiverBinder + { + } + + internal interface IReceiverBinder : IReceiverBinder + { + global::System.IDisposable Bind(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, T receiver); + } + } + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.Components.Generated.cs"]); + } + + private static void Assert_TypedSignalR_Client_HubConnectionExtensions_Generated(System.Collections.Generic.Dictionary outputs) + { + Assert.Equal( + """ + // + // THIS (.cs) FILE IS GENERATED BY TypedSignalR.Client + // + #nullable enable + #pragma warning disable CS1591 + namespace TypedSignalR.Client + { + internal static partial class HubConnectionExtensions + { + public static THub CreateHubProxy(this global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, global::System.Threading.CancellationToken cancellationToken = default) + { + var factory = HubInvokerFactoryProvider.GetHubInvokerFactory(); + + if (factory is null) + { + throw new global::System.InvalidOperationException($"Failed to create a hub proxy. TypedSignalR.Client did not generate source code to create a hub proxy, which type is {typeof(THub)}."); + } + + return factory.CreateHubInvoker(connection, cancellationToken); + } + + public static global::System.IDisposable Register(this global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, TReceiver receiver) + { + if (receiver is null) + { + throw new global::System.ArgumentNullException(nameof(receiver)); + } + + if (typeof(TReceiver) == typeof(IHubConnectionObserver)) + { + return new HubConnectionObserverSubscription(connection, (IHubConnectionObserver)receiver); + } + + var binder = ReceiverBinderProvider.GetReceiverBinder(); + + if (binder is null) + { + throw new global::System.InvalidOperationException($"Failed to register a receiver. TypedSignalR.Client did not generate source code to register a receiver, which type is {typeof(TReceiver)}."); + } + + var subscription = binder.Bind(connection, receiver); + + if (receiver is IHubConnectionObserver hubConnectionObserver) + { + subscription = new CompositeDisposable(new[] { subscription, new HubConnectionObserverSubscription(connection, hubConnectionObserver) }); + } + + return subscription; + } + } + + internal static partial class HubConnectionExtensions + { + private static partial global::System.Collections.Generic.Dictionary CreateFactories(); + private static partial global::System.Collections.Generic.Dictionary CreateBinders(); + + private static class HubInvokerFactoryProvider + { + private static readonly global::System.Collections.Generic.Dictionary Factories; + + static HubInvokerFactoryProvider() + { + Factories = CreateFactories(); + } + + public static IHubInvokerFactory? GetHubInvokerFactory() + { + return Cache.HubInvokerFactory; + } + + private static class Cache + { + public static readonly IHubInvokerFactory? HubInvokerFactory = default; + + static Cache() + { + if (Factories.TryGetValue(typeof(T), out var hubInvokerFactory)) + { + HubInvokerFactory = hubInvokerFactory as IHubInvokerFactory; + } + } + } + } + + private static class ReceiverBinderProvider + { + private static readonly global::System.Collections.Generic.Dictionary Binders; + + static ReceiverBinderProvider() + { + Binders = CreateBinders(); + } + + public static IReceiverBinder? GetReceiverBinder() + { + return Cache.ReceiverBinder; + } + + private static class Cache + { + public static readonly IReceiverBinder? ReceiverBinder = default; + + static Cache() + { + if (Binders.TryGetValue(typeof(T), out var receiverBinder)) + { + ReceiverBinder = receiverBinder as IReceiverBinder; + } + } + } + } + + private sealed class HubConnectionObserverSubscription : global::System.IDisposable + { + private readonly global::Microsoft.AspNetCore.SignalR.Client.HubConnection _connection; + private readonly IHubConnectionObserver _hubConnectionObserver; + + private int _disposed = 0; + + public HubConnectionObserverSubscription(global::Microsoft.AspNetCore.SignalR.Client.HubConnection connection, IHubConnectionObserver hubConnectionObserver) + { + _connection = connection; + _hubConnectionObserver = hubConnectionObserver; + + _connection.Closed += hubConnectionObserver.OnClosed; + _connection.Reconnected += hubConnectionObserver.OnReconnected; + _connection.Reconnecting += hubConnectionObserver.OnReconnecting; + } + + public void Dispose() + { + if (global::System.Threading.Interlocked.Exchange(ref _disposed, 1) == 0) + { + _connection.Closed -= _hubConnectionObserver.OnClosed; + _connection.Reconnected -= _hubConnectionObserver.OnReconnected; + _connection.Reconnecting -= _hubConnectionObserver.OnReconnecting; + } + } + } + + private sealed class CompositeDisposable : global::System.IDisposable + { + private readonly object _gate = new object(); + private readonly global::System.Collections.Generic.List _disposables; + + private bool _disposed; + + public CompositeDisposable() + { + _disposables = new global::System.Collections.Generic.List(); + } + + public CompositeDisposable(global::System.IDisposable[] disposables) + { + _disposables = new global::System.Collections.Generic.List(disposables); + } + + public CompositeDisposable(int capacity) + { + if (capacity < 0) + { + throw new global::System.ArgumentOutOfRangeException(nameof(capacity)); + } + + _disposables = new global::System.Collections.Generic.List(capacity); + } + + public void Add(global::System.IDisposable item) + { + bool shouldDispose = false; + + lock (_gate) + { + shouldDispose = _disposed; + + if (!_disposed) + { + _disposables.Add(item); + } + } + + if (shouldDispose) + { + item.Dispose(); + } + } + + public void Dispose() + { + var currentDisposables = default(global::System.Collections.Generic.List); + + lock (_gate) + { + if (_disposed) + { + return; + } + + _disposed = true; + currentDisposables = _disposables; + } + + foreach (var item in currentDisposables) + { + if (item is not null) + { + item.Dispose(); + } + } + + currentDisposables.Clear(); + } + } + + // It is not possible to avoid boxing. + // This is a limitation caused by the SignalR implementation. + private static class HandlerConverter + { + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler(); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!, (T16)args[15]!); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler(default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, default); + } + + public static global::System.Func Convert(global::System.Func handler) + { + return args => handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!, default); + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler().ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!, (T16)args[15]!).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler(default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, default).ConfigureAwait(false); + return result; + }; + } + + public static global::System.Func> Convert(global::System.Func> handler) + { + return async args => + { + var result = await handler((T1)args[0]!, (T2)args[1]!, (T3)args[2]!, (T4)args[3]!, (T5)args[4]!, (T6)args[5]!, (T7)args[6]!, (T8)args[7]!, (T9)args[8]!, (T10)args[9]!, (T11)args[10]!, (T12)args[11]!, (T13)args[12]!, (T14)args[13]!, (T15)args[14]!, default).ConfigureAwait(false); + return result; + }; + } + } + } + } + #pragma warning restore CS1591 + + """.Replace("\r\n", "\n"), + outputs["TypedSignalR.Client.HubConnectionExtensions.Generated.cs"]); + } +} diff --git a/tests/TypedSignalR.Client.SourceGeneratorTests/TypedSignalR.Client.SourceGeneratorTests.csproj b/tests/TypedSignalR.Client.SourceGeneratorTests/TypedSignalR.Client.SourceGeneratorTests.csproj new file mode 100644 index 0000000..dd42560 --- /dev/null +++ b/tests/TypedSignalR.Client.SourceGeneratorTests/TypedSignalR.Client.SourceGeneratorTests.csproj @@ -0,0 +1,33 @@ + + + + net8.0 + enable + false + true + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + +