diff --git a/README.md b/README.md index d9c25e1bd..968a18441 100644 --- a/README.md +++ b/README.md @@ -296,6 +296,7 @@ Refit's generated-request runtime helpers. This default path reduces runtime reflection, method metadata lookup, object-array argument packing, and delegate construction for request shapes the generator can safely model. It currently covers common request features including: +* parameters that appear in the path template * static `[Headers]` * dynamic `[Header]` parameters * `[HeaderCollection]` dictionaries diff --git a/src/InterfaceStubGenerator.Shared/Emitter.Inline.cs b/src/InterfaceStubGenerator.Shared/Emitter.Inline.cs index 9fa14df4f..1e0a77533 100644 --- a/src/InterfaceStubGenerator.Shared/Emitter.Inline.cs +++ b/src/InterfaceStubGenerator.Shared/Emitter.Inline.cs @@ -2,6 +2,7 @@ // ReactiveUI and Contributors licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. using System.Diagnostics.CodeAnalysis; +using System.Text; namespace Refit.Generator; @@ -112,8 +113,28 @@ private static string BuildInlineRefitMethod( var bodyParameter = FindRequestParameter(request, RequestParameterKind.Body); var cancellationTokenExpression = BuildCancellationTokenExpression(request); var bufferBodyExpression = BuildBufferBodyExpression(bodyParameter, settingsLocal); + + // Build path + var parameterInfoNames = GetParameterInfoUniqueNames(request, uniqueNames); + var parameters = GetParametersArg(request, parameterInfoNames); + var paramInfoSb = new StringBuilder(); + + foreach (var parameter in request.Parameters) + { + if (parameter.Kind is not RequestParameterKind.Path) + { + continue; + } + + var parameterName = parameterInfoNames[parameter.Name]; + BuildParameterInfoField(parameter, methodModel.DeclaredMethod, parameterName, paramInfoSb); + } + + var pathExpression = parameters.Length > 0 + ? $"global::Refit.GeneratedRequestRunner.BuildRequestPath({ToCSharpStringLiteral(request.Path)}, {settingsLocal}.AllowUnmatchedRouteParameters{parameters})" + : ToCSharpStringLiteral(request.Path); var requestUriExpression = - $"global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, {ToCSharpStringLiteral(request.Path)}, {settingsLocal}.UrlResolution)"; + $"global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, {pathExpression}, {settingsLocal}.UrlResolution)"; var (formFieldsSource, formFieldsFieldName) = BuildFormFieldsField(bodyParameter, uniqueNames); var contentSource = bodyParameter is null ? string.Empty : BuildInlineContent(bodyParameter, requestLocal, settingsLocal, formFieldsFieldName); var headerSource = BuildInlineHeaders(request, requestLocal); @@ -123,7 +144,7 @@ private static string BuildInlineRefitMethod( var bodyIndent = Indent(MethodBodyIndentation); return $$""" - {{formFieldsSource}}{{BuildMethodOpening(methodModel, isExplicit, isExplicit, interfaceModel.SupportsNullable)}}{{bodyIndent}}var {{settingsLocal}} = {{settingsFieldName}}; + {{paramInfoSb}}{{formFieldsSource}}{{BuildMethodOpening(methodModel, isExplicit, isExplicit, interfaceModel.SupportsNullable)}}{{bodyIndent}}var {{settingsLocal}} = {{settingsFieldName}}; {{bodyIndent}}var {{requestLocal}} = new global::System.Net.Http.HttpRequestMessage({{ToHttpMethodExpression(request.HttpMethod)}}, {{requestUriExpression}}); {{bodyIndent}}#if NET6_0_OR_GREATER {{bodyIndent}}{{requestLocal}}.Version = {{settingsLocal}}.Version; @@ -132,6 +153,138 @@ private static string BuildInlineRefitMethod( {{contentSource}}{{headerSource}}{{requestPropertySource}}{{returnSource}}{{methodIndent}}} """; + + static string GetParameterInfoFieldName(string parameterName, UniqueNameBuilder uniqueNames) => + uniqueNames.New($"______{parameterName}AttributeProvider"); + + static StringBuilder AppendSeparator(int i, StringBuilder sb, string separator = ", ") + { + return i <= 0 ? sb : sb.Append(separator); + } + static StringBuilder AppendJoining(string value, int i, StringBuilder sb, string separator = ", ") + { + return AppendSeparator(i, sb, separator).Append(value); + } + + static void AppendAttributeValue(ParameterAttributeModel attribute, StringBuilder sb0) + { + _ = sb0.Append("new ").Append(attribute.TypeExpression).Append('('); + var i = 0; + + foreach (var argument in attribute.ConstructorArguments) + { + _ = AppendJoining(argument, i++, sb0); + } + + _ = sb0.Append(')'); + if (attribute.NamedArguments.Count < 1) + { + return; + } + + i = 0; + _ = sb0.Append("{ "); + foreach (var named in attribute.NamedArguments) + { + _ = AppendSeparator(i++, sb0); + _ = sb0.Append(named.Name).Append(" = ").Append(named.ValueExpression); + } + + _ = sb0.Append(" }"); + } + static void BuildParameterInfoField(RequestParameterModel parameter, string method, string paramInfoFieldName, StringBuilder sb) + { + // Build the initializer. + var memberIndent = Indent(MethodMemberIndentation); + Dictionary> grouped = new(); + + foreach (var attribute in parameter.Attributes) + { + var key = $"typeof({attribute.TypeExpression})"; + if (grouped.TryGetValue(key, out var groupedAttributes)) + { + groupedAttributes.Add(attribute); + } + else + { + grouped.Add(key, [attribute]); + } + } + + const string dictType = "global::System.Collections.Generic.Dictionary"; + _ = sb.AppendLine().Append(memberIndent).Append("/// Cached attribute provider for the generated ") + .Append(ToXmlDocumentationText(method)).Append(" method's ").Append(ToXmlDocumentationText(parameter.Name)).AppendLine(" parameter.") + .Append(memberIndent).Append("private static readonly global::Refit.GeneratedParameterAttributeProvider ").Append(paramInfoFieldName).Append(" = ") + .Append("new global::Refit.GeneratedParameterAttributeProvider(new ").Append(dictType).Append("()"); + var i = 0; + if (grouped.Count > 0) + { + _ = sb.Append(" {"); + foreach (var kv in grouped) + { + _ = AppendJoining("{ ", i++, sb).Append(kv.Key).Append(", new object[] { "); + foreach (var arg in kv.Value) + { + AppendAttributeValue(arg, sb); + } + + _ = sb.Append("} }"); + } + + _ = sb.Append('}'); + } + + _ = sb.AppendLine(");"); + } + + static Dictionary GetParameterInfoUniqueNames( + RequestModel request, + UniqueNameBuilder uniqueNames) + { + var dict = new Dictionary(); + foreach (var parameter in request.Parameters) + { + if (parameter.Kind is not RequestParameterKind.Path) + { + continue; + } + + var parameterInfoFieldName = GetParameterInfoFieldName(parameter.Name, uniqueNames); + dict.Add(parameter.Name, parameterInfoFieldName); + } + + return dict; + } + static string GetParametersArg(RequestModel request, Dictionary uniqueNameLookup) + { + var parametersSb = new StringBuilder(); + var pathLength = request.Path.Length; + foreach (var parameter in request.Parameters) + { + if (parameter.Kind is not RequestParameterKind.Path || parameter.Locations is null) + { + continue; + } + + foreach (var location in parameter.Locations) + { + var start = location.Start.GetOffset(pathLength); + var end = location.End.GetOffset(pathLength); + _ = parametersSb.Append(", ").Append("((").Append(start).Append(", ").Append(end).Append("), "); + var parameterInfoFieldName = uniqueNameLookup[parameter.Name]; + _ = parametersSb.Append("_settings.UrlParameterFormatter.Format(") + .Append(parameter.Name) + .Append(", ") + .Append(parameterInfoFieldName) + .Append(", ") + .Append("typeof(").Append(parameter.Type).Append(')') + .Append(')'); + _ = parametersSb.Append(')'); + } + } + + return parametersSb.ToString(); + } } /// Builds request content assignment for an inline generated method. diff --git a/src/InterfaceStubGenerator.Shared/Models/NamedAttributeArgument.cs b/src/InterfaceStubGenerator.Shared/Models/NamedAttributeArgument.cs new file mode 100644 index 000000000..17dd9e411 --- /dev/null +++ b/src/InterfaceStubGenerator.Shared/Models/NamedAttributeArgument.cs @@ -0,0 +1,10 @@ +// Copyright (c) 2019-2026 ReactiveUI and Contributors. All rights reserved. +// ReactiveUI and Contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace Refit.Generator; + +/// A named attribute argument assignment already rendered as source expressions. +/// The argument name. +/// The argument value expression. +internal sealed record NamedAttributeArgument(string Name, string ValueExpression); diff --git a/src/InterfaceStubGenerator.Shared/Models/ParameterAttributeModel.cs b/src/InterfaceStubGenerator.Shared/Models/ParameterAttributeModel.cs new file mode 100644 index 000000000..2c64f3672 --- /dev/null +++ b/src/InterfaceStubGenerator.Shared/Models/ParameterAttributeModel.cs @@ -0,0 +1,17 @@ +// Copyright (c) 2019-2026 ReactiveUI and Contributors. All rights reserved. +// ReactiveUI and Contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace Refit.Generator; + +/// +/// A precomputed attribute to re-emit onto a generated parameter's attribute provider. The parser flattens the +/// Roslyn AttributeData into value-typed expressions so no symbols are held in the incremental cache. +/// +/// The fully-qualified attribute type expression, e.g. global::Refit.AliasAsAttribute. +/// The attribute's constructor argument expressions, in order. +/// The attribute's named argument assignments. +internal sealed record ParameterAttributeModel( + string TypeExpression, + ImmutableEquatableArray ConstructorArguments, + ImmutableEquatableArray NamedArguments); diff --git a/src/InterfaceStubGenerator.Shared/Models/RequestParameterKind.cs b/src/InterfaceStubGenerator.Shared/Models/RequestParameterKind.cs index 91965b396..286d460d2 100644 --- a/src/InterfaceStubGenerator.Shared/Models/RequestParameterKind.cs +++ b/src/InterfaceStubGenerator.Shared/Models/RequestParameterKind.cs @@ -22,5 +22,8 @@ internal enum RequestParameterKind Property, /// The parameter supplies the request cancellation token. - CancellationToken + CancellationToken, + + /// The parameter supplies a value for a placeholder in the path. + Path } diff --git a/src/InterfaceStubGenerator.Shared/Models/RequestParameterModel.cs b/src/InterfaceStubGenerator.Shared/Models/RequestParameterModel.cs index 7bc4cc1bf..7655217f8 100644 --- a/src/InterfaceStubGenerator.Shared/Models/RequestParameterModel.cs +++ b/src/InterfaceStubGenerator.Shared/Models/RequestParameterModel.cs @@ -1,11 +1,14 @@ // Copyright (c) 2019-2026 ReactiveUI and Contributors. All rights reserved. // ReactiveUI and Contributors licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. + namespace Refit.Generator; /// Parsed request-binding metadata for one method parameter. /// The parameter metadata name. /// The fully-qualified parameter type. +/// The parameter's location in the URL template string, when this is a path parameter. +/// The parameter's attributes. /// The generated request binding kind. /// Whether generated code must null-check the parameter before dereferencing. /// The request header name, when this is a header parameter. @@ -15,6 +18,8 @@ namespace Refit.Generator; internal sealed record RequestParameterModel( string Name, string Type, + ImmutableEquatableArray? Locations, + ImmutableEquatableArray Attributes, RequestParameterKind Kind, bool CanBeNull, string HeaderName, diff --git a/src/InterfaceStubGenerator.Shared/Parser.Request.Helpers.cs b/src/InterfaceStubGenerator.Shared/Parser.Request.Helpers.cs index ceebc73bc..ec05fd628 100644 --- a/src/InterfaceStubGenerator.Shared/Parser.Request.Helpers.cs +++ b/src/InterfaceStubGenerator.Shared/Parser.Request.Helpers.cs @@ -30,13 +30,49 @@ internal static partial class Parser /// Determines whether the initial inline emitter can use the path as a literal URI. /// The path to inspect. /// when the path is supported. - internal static bool IsConstantPathSupported(string path) => - (path.Length == 0 || path[0] == '/') - && path.IndexOf('{') < 0 - && path.IndexOf('}') < 0 - && path.IndexOf('\\') < 0 - && path.IndexOf('\r') < 0 - && path.IndexOf('\n') < 0; + internal static bool IsPathSupported(string path) + { + return (path.Length == 0 || path[0] == '/') + && IsPathTemplateValid(path) + && path.IndexOf('\\') < 0 + && path.IndexOf('\r') < 0 + && path.IndexOf('\n') < 0; + + static bool IsPathTemplateValid(in ReadOnlySpan path) + { + var openingBraces = 0; + var closingBraces = 0; + + foreach (var c in path) + { + switch (c) + { + case '/' when openingBraces != closingBraces: + return false; + case '/': + { + openingBraces = 0; + closingBraces = 0; + break; + } + + case '{': + { + ++openingBraces; + break; + } + + case '}': + { + ++closingBraces; + break; + } + } + } + + return openingBraces == closingBraces; + } + } /// Normalizes constant inline paths to match the reflection request builder URI cleanup. /// The source path from the HTTP method attribute. diff --git a/src/InterfaceStubGenerator.Shared/Parser.Request.cs b/src/InterfaceStubGenerator.Shared/Parser.Request.cs index d5e33bc53..9bad517ba 100644 --- a/src/InterfaceStubGenerator.Shared/Parser.Request.cs +++ b/src/InterfaceStubGenerator.Shared/Parser.Request.cs @@ -1,11 +1,11 @@ // Copyright (c) 2019-2026 ReactiveUI and Contributors. All rights reserved. // ReactiveUI and Contributors licenses this file to you under the MIT license. // See the LICENSE file in the project root for full license information. -using System; -using System.Collections.Generic; + using System.Collections.Immutable; using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; namespace Refit.Generator; @@ -34,8 +34,10 @@ private static RequestModel ParseRequest( var httpMethod = GetHttpMethodName(httpMethodAttribute.AttributeClass); var path = GetHttpPath(httpMethodAttribute); + var normalizedPath = NormalizeConstantPathForInline(path); + var pathParameters = ExtractPathParameterPlaceholderNames(normalizedPath); var returnTypes = GetRequestReturnTypes(methodSymbol); - var parameters = ParseRequestParameters(methodSymbol.Parameters, out var parameterEligibility); + var parameters = ParseRequestParameters(methodSymbol.Parameters, pathParameters.ToImmutableDictionary(pathParameters.Comparer), out var parameterEligibility); var staticHeaders = ParseStaticHeaders(methodSymbol); var canGenerateInline = @@ -43,13 +45,13 @@ private static RequestModel ParseRequest( && returnTypeInfo is ReturnTypeInfo.AsyncVoid or ReturnTypeInfo.AsyncResult or ReturnTypeInfo.AsyncEnumerable && methodSymbol.TypeParameters.Length == 0 && httpMethod.Length > 0 - && IsConstantPathSupported(path) + && IsPathSupported(path) && IsSupportedInlineBody(parameters) && !HasUnsupportedInlineRequestMetadata(methodSymbol); return new( httpMethod, - NormalizeConstantPathForInline(path), + normalizedPath, returnTypes.ResultType, returnTypes.DeserializedResultType, returnTypes.IsApiResponse, @@ -57,6 +59,48 @@ private static RequestModel ParseRequest( canGenerateInline, staticHeaders, parameters); + + static Dictionary> ExtractPathParameterPlaceholderNames(string path) + { + var pathSpan = path.AsSpan(); + + var i = pathSpan.IndexOf('{'); + if (i < 0) + { + return []; + } + + var paramNames = new Dictionary>(StringComparer.OrdinalIgnoreCase); + var j = i + pathSpan[i..].IndexOfAny('}', '/'); + while (i < pathSpan.Length && j > i) + { + if (pathSpan[j] == '}') + { + var paramName = pathSpan[(i + 1)..j].ToString(); + var location = new Range(i, j + 1); + if (paramNames.TryGetValue(paramName, out var values)) + { + values.Add(location); + } + else + { + paramNames[paramName] = [location]; + } + } + + var i2 = pathSpan[j..].IndexOf('{'); + if (i2 < 0) + { + break; + } + + i = j; + i += i2; + j = i + pathSpan[i..].IndexOfAny('}', '/'); + } + + return paramNames; + } } /// Gets the HTTP method name represented by a Refit method attribute. @@ -213,10 +257,12 @@ private static void AddHeadersAttributeValues(List headers, Attribu /// Parses request parameter bindings for the conservative initial inline path. /// The method parameters. + /// The placeholder names in the URL with their locations. /// Receives whether every parameter is supported. /// The parsed request parameter models. private static ImmutableEquatableArray ParseRequestParameters( in ImmutableArray parameters, + in ImmutableDictionary> parameterLocations, out bool canGenerateInline) { if (parameters.Length == 0) @@ -233,7 +279,11 @@ private static ImmutableEquatableArray ParseRequestParame for (var i = 0; i < parameters.Length; i++) { - var parsedParameter = ParseRequestParameter(parameters[i]); + var parameter = parameters[i]; + var aliasAttr = parameter.GetAttributes().FirstOrDefault(static a => a.AttributeClass?.ToDisplayString() == "Refit.AliasAsAttribute"); + var name = aliasAttr is not null ? GetFirstStringArgument(aliasAttr) ?? parameter.Name : parameter.Name; + _ = parameterLocations.TryGetValue(name, out var location); + var parsedParameter = ParseRequestParameter(parameter, location?.ToImmutableEquatableArray()); requestParameters[i] = parsedParameter.Parameter; bodyCount += parsedParameter.BodyCount; cancellationTokenCount += parsedParameter.CancellationTokenCount; @@ -251,8 +301,9 @@ private static ImmutableEquatableArray ParseRequestParame /// Parses one request parameter binding. /// The parameter to parse. + /// The parameter's locations in the URL template string. This is null if the parameter has no placeholder in the URL i.e. not a path parameter. /// The parsed parameter and eligibility counters. - private static ParsedRequestParameter ParseRequestParameter(IParameterSymbol parameter) + private static ParsedRequestParameter ParseRequestParameter(IParameterSymbol parameter, ImmutableEquatableArray? locations) { var parameterType = parameter.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); var canBeNull = CanBeNull(parameter.Type, parameter.NullableAnnotation); @@ -262,6 +313,8 @@ private static ParsedRequestParameter ParseRequestParameter(IParameterSymbol par new( parameter.MetadataName, parameterType, + locations, + BuildParameterAttributes(parameter), RequestParameterKind.CancellationToken, canBeNull, string.Empty, @@ -294,9 +347,47 @@ private static ParsedRequestParameter ParseRequestParameter(IParameterSymbol par 1); } - return TryParsePropertyParameter(parameter, parameterType, out var propertyParameter) - ? new(propertyParameter, true, 0, 0, 0) + if (TryParsePropertyParameter(parameter, parameterType, out var propertyParameter)) + { + return new(propertyParameter, true, 0, 0, 0); + } + + return locations is {} l && IsSimpleType(parameter.Type) + ? new(PathRequestParameter(parameter, parameterType, l), true, 0, 0, 0) : new(UnsupportedRequestParameter(parameter, parameterType), false, 0, 0, 0); + + [SuppressMessage( + "Maintainability", + "SST1442: Functions should keep branching complexity low", + Justification = "There are a lot of simple types supported and matching on them is a simple pattern match")] + static bool IsSimpleType(ITypeSymbol type) + { + var underlyingType = GetUnderlyingType(type); + + return IsGuid(underlyingType) || IsDateTimeOffset(underlyingType) || + underlyingType.SpecialType is SpecialType.System_String or SpecialType.System_DateTime + or SpecialType.System_Int32 + or SpecialType.System_Int64 + or SpecialType.System_Int16 + or SpecialType.System_Enum + or SpecialType.System_UInt32 or SpecialType.System_UInt64 + or SpecialType.System_UInt16 or SpecialType.System_Char or SpecialType.System_Boolean + or SpecialType.System_Byte or SpecialType.System_Decimal or SpecialType.System_Double + or SpecialType.System_Single; + + static ITypeSymbol GetUnderlyingType(ITypeSymbol type) + { + return type is INamedTypeSymbol + { + OriginalDefinition.SpecialType: SpecialType.System_Nullable_T + } nullable + ? nullable.TypeArguments[0] + : type; + } + + static bool IsGuid(ITypeSymbol type) => type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) is "System.Guid"; + static bool IsDateTimeOffset(ITypeSymbol type) => type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) is "System.DateTimeOffset"; + } } /// Determines whether a type is or nullable . @@ -336,6 +427,8 @@ private static bool TryParseBodyParameter( bodyParameter = new( parameter.MetadataName, parameterType, + null, + BuildParameterAttributes(parameter), RequestParameterKind.Body, CanBeNull(parameter.Type, parameter.NullableAnnotation), string.Empty, @@ -351,6 +444,8 @@ private static bool TryParseBodyParameter( bodyParameter = new( parameter.MetadataName, parameterType, + null, + BuildParameterAttributes(parameter), RequestParameterKind.Unsupported, CanBeNull(parameter.Type, parameter.NullableAnnotation), string.Empty, @@ -579,6 +674,8 @@ private static bool TryParseHeaderParameter( headerParameter = new( parameter.MetadataName, parameterType, + null, + BuildParameterAttributes(parameter), RequestParameterKind.Header, CanBeNull(parameter.Type, parameter.NullableAnnotation), headerName.Trim(), @@ -614,6 +711,8 @@ private static bool TryParseHeaderCollectionParameter( headerCollectionParameter = new( parameter.MetadataName, parameterType, + null, + BuildParameterAttributes(parameter), RequestParameterKind.HeaderCollection, CanBeNull(parameter.Type, parameter.NullableAnnotation), string.Empty, @@ -655,6 +754,8 @@ private static bool TryParsePropertyParameter( propertyParameter = new( parameter.MetadataName, parameterType, + null, + BuildParameterAttributes(parameter), RequestParameterKind.Property, CanBeNull(parameter.Type, parameter.NullableAnnotation), string.Empty, @@ -678,6 +779,8 @@ private static RequestParameterModel UnsupportedRequestParameter( new( parameter.MetadataName, parameterType, + null, + BuildParameterAttributes(parameter), RequestParameterKind.Unsupported, CanBeNull(parameter.Type, parameter.NullableAnnotation), string.Empty, @@ -685,6 +788,95 @@ private static RequestParameterModel UnsupportedRequestParameter( string.Empty, BodyBufferMode.None); + /// Builds a path request parameter model. + /// The parameter symbol. + /// The parameter type. + /// The parameter's location in the URL. + /// The path request model. + private static RequestParameterModel PathRequestParameter( + IParameterSymbol parameter, + string parameterType, + ImmutableEquatableArray locations) => + new( + parameter.MetadataName, + parameterType, + locations, + BuildParameterAttributes(parameter), + RequestParameterKind.Path, + CanBeNull(parameter.Type, parameter.NullableAnnotation), + string.Empty, + string.Empty, + string.Empty, + BodyBufferMode.None); + + /// + /// Flattens a parameter's attributes into value-typed models so the incremental generator cache holds no + /// Roslyn symbols. Attribute type names and argument expressions are precomputed for the emitter. + /// + /// The parameter to inspect. + /// The precomputed attribute models. + private static ImmutableEquatableArray BuildParameterAttributes(IParameterSymbol parameter) + { + var attributes = parameter.GetAttributes(); + if (attributes.Length == 0) + { + return ImmutableEquatableArray.Empty; + } + + var models = new List(attributes.Length); + foreach (var attribute in attributes) + { + if (attribute.AttributeClass is null) + { + continue; + } + + var constructorArguments = new List(attribute.ConstructorArguments.Length); + foreach (var argument in attribute.ConstructorArguments) + { + constructorArguments.Add(ConstantValueToString(argument)); + } + + var namedArguments = new List(attribute.NamedArguments.Length); + foreach (var named in attribute.NamedArguments) + { + namedArguments.Add(new(named.Key, ConstantValueToString(named.Value))); + } + + models.Add(new( + attribute.AttributeClass.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), + constructorArguments.ToImmutableEquatableArray(), + namedArguments.ToImmutableEquatableArray())); + } + + return models.ToImmutableEquatableArray(); + } + + /// Renders a typed constant attribute argument as the C# source expression the emitter writes. + /// The typed constant. + /// The source expression, or "null" when the value is null. + private static string ConstantValueToString(TypedConstant argument) + { + var result = string.Empty; + + if (!argument.IsNull) + { + result = argument.Kind switch + { + TypedConstantKind.Enum => + $"({argument.Type!.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)}){argument.Value!}", + TypedConstantKind.Primitive => SymbolDisplay.FormatPrimitive(argument.Value!, true, false) ?? string.Empty, + TypedConstantKind.Type => + $"typeof({argument.Type!.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)})", + TypedConstantKind.Array => + $"new[] {{ {string.Join(", ", argument.Values.Select(ConstantValueToString))} }}", + _ => throw new NotSupportedException($"The type {argument.Kind} is not supported.") + }; + } + + return result.Length > 0 ? result : "null"; + } + /// Determines whether generated code needs a null-safe dereference for a parameter value. /// The parameter type. /// The parameter nullable annotation. diff --git a/src/Polyfills/NotNullAttribute.cs b/src/Polyfills/NotNullAttribute.cs index 0f5090435..d3c5554f5 100644 --- a/src/Polyfills/NotNullAttribute.cs +++ b/src/Polyfills/NotNullAttribute.cs @@ -3,8 +3,6 @@ // See the LICENSE file in the project root for full license information. #if !NETCOREAPP3_0_OR_GREATER && !NETSTANDARD2_1_OR_GREATER -using System.Diagnostics; - namespace System.Diagnostics.CodeAnalysis; /// Specifies that an input value is not null after the method returns. diff --git a/src/Refit/GeneratedParameterAttributeProvider.cs b/src/Refit/GeneratedParameterAttributeProvider.cs new file mode 100644 index 000000000..da14e349b --- /dev/null +++ b/src/Refit/GeneratedParameterAttributeProvider.cs @@ -0,0 +1,41 @@ +// Copyright (c) 2019-2026 ReactiveUI and Contributors. All rights reserved. +// ReactiveUI and Contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System.Reflection; + +namespace Refit; + +/// Provides parameter attributes for generated code. +/// The attribute information. +public sealed class GeneratedParameterAttributeProvider(Dictionary attributes) : ICustomAttributeProvider +{ + /// List of all attributes. + private readonly Lazy _allAttributesCache = new(() => + { + var allAttributes = new List(); + foreach (var value in attributes.Values) + { + allAttributes.AddRange(value); + } + + return allAttributes.ToArray(); + }); + + /// + public object[] GetCustomAttributes(bool inherit) => _allAttributesCache.Value; + + /// + public object[] GetCustomAttributes(Type attributeType, bool inherit) + { + if (attributeType is null) + { + throw new ArgumentNullException(nameof(attributeType)); + } + + return attributes.TryGetValue(attributeType, out var matches) ? matches : []; + } + + /// + public bool IsDefined(Type attributeType, bool inherit) => attributes.ContainsKey(attributeType); +} diff --git a/src/Refit/GeneratedRequestRunner.cs b/src/Refit/GeneratedRequestRunner.cs index eb0f75aca..4a09b2875 100644 --- a/src/Refit/GeneratedRequestRunner.cs +++ b/src/Refit/GeneratedRequestRunner.cs @@ -28,11 +28,63 @@ public static Uri BuildRelativeUri(HttpClient client, string relativePath, UrlRe } var basePath = client.BaseAddress?.AbsolutePath - ?? throw new InvalidOperationException("BaseAddress must be set on the HttpClient instance"); + ?? throw new InvalidOperationException("BaseAddress must be set on the HttpClient instance"); basePath = basePath == "/" ? string.Empty : basePath.TrimEnd('/'); return new(basePath + relativePath, UriKind.Relative); } + /// Builds the request path for a generated request from a template. + /// The method's relative path, including any leading slash and query string. + /// Whether to allow unmatched URL parameters. + /// The replacement uri parameters. + /// A path with all the placeholder parameters in the path template replaced. + /// + /// A URI template parameter is not available in the provided parameter array and unmatched URL parameters aren't allowed. + /// + public static string BuildRequestPath( + string relativePathTemplate, + bool allowUnmatchedParameter, + params ((int startIdx, int endIdx) range, string? value)[] uriParams) + { + if (uriParams.Length == 0 && allowUnmatchedParameter) + { + return relativePathTemplate; + } + + var pathSpan = relativePathTemplate.AsSpan(); + using var sb = new ValueStringBuilder(stackalloc char[256]); + var pos = 0; + foreach (var ((startIdx, endIdx), value) in uriParams) + { + sb.Append(pathSpan[pos..startIdx]); + if (value is not null) + { + sb.Append(StringHelpers.EscapeDataString(value)); + } + + pos = endIdx; + } + + sb.Append(pathSpan[pos..]); + + var path = sb.ToString(); + var i = path.IndexOf('{'); + if (i < 0 || allowUnmatchedParameter) + { + return path; + } + + var j = path.AsSpan(i).IndexOfAny('}', '/'); + if (j < 0 || path[j += i] != '}') + { + return path; + } + + var key = path[(i + 1)..j]; + throw new ArgumentException( + $"URL {relativePathTemplate} has parameter {{{key}}}, but no method parameter matches"); + } + /// Sends a generated request with no response body, throwing on HTTP errors. /// The HTTP client to send with. /// The generated request message. @@ -131,8 +183,8 @@ await RequestExecutionHelpers.SendVoidAsync( using var linked = CancellationTokenSource.CreateLinkedTokenSource(methodCancellationToken, cancellationToken); await foreach (var item in RequestExecutionHelpers - .StreamResponseAsync(client, request, settings, true, linked.Token) - .ConfigureAwait(false)) + .StreamResponseAsync(client, request, settings, true, linked.Token) + .ConfigureAwait(false)) { yield return item; } @@ -293,7 +345,7 @@ public static HttpContent CreateUrlEncodedBodyContent< // The descriptor path only matches the reflection path when the serializer resolves field names from // attributes the generator already inlined (the built-in System.Text.Json serializer); otherwise fall back. var useDescriptors = body is not null and not System.Collections.IDictionary - && settings.ContentSerializer is SystemTextJsonContentSerializer; + && settings.ContentSerializer is SystemTextJsonContentSerializer; return new FormUrlEncodedContent( useDescriptors diff --git a/src/Refit/PublicAPI/net10.0/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net10.0/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net10.0/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net10.0/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/PublicAPI/net11.0/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net11.0/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net11.0/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net11.0/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/PublicAPI/net462/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net462/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net462/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net462/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/PublicAPI/net470/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net470/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net470/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net470/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/PublicAPI/net471/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net471/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net471/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net471/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/PublicAPI/net472/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net472/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net472/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net472/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/PublicAPI/net48/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net48/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net48/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net48/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/PublicAPI/net481/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net481/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net481/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net481/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net8.0/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/PublicAPI/net9.0/PublicAPI.Unshipped.txt b/src/Refit/PublicAPI/net9.0/PublicAPI.Unshipped.txt index 7dc5c5811..28efbdefc 100644 --- a/src/Refit/PublicAPI/net9.0/PublicAPI.Unshipped.txt +++ b/src/Refit/PublicAPI/net9.0/PublicAPI.Unshipped.txt @@ -1 +1,7 @@ #nullable enable +Refit.GeneratedParameterAttributeProvider +Refit.GeneratedParameterAttributeProvider.GeneratedParameterAttributeProvider(System.Collections.Generic.Dictionary! attributes) -> void +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.GetCustomAttributes(System.Type! attributeType, bool inherit) -> object![]! +Refit.GeneratedParameterAttributeProvider.IsDefined(System.Type! attributeType, bool inherit) -> bool +static Refit.GeneratedRequestRunner.BuildRequestPath(string! relativePathTemplate, bool allowUnmatchedParameter, params ((int startIdx, int endIdx) range, string? value)[]! uriParams) -> string! diff --git a/src/Refit/ValueStringBuilder.cs b/src/Refit/ValueStringBuilder.cs index 7d681548a..557ef5f7a 100644 --- a/src/Refit/ValueStringBuilder.cs +++ b/src/Refit/ValueStringBuilder.cs @@ -10,6 +10,7 @@ namespace Refit; // From https://github/dotnet/runtime/blob/main/src/libraries/Common/src/System/Text/ValueStringBuilder.cs /// A stack-allocated string builder that grows using pooled buffers. +[DebuggerDisplay("{DebuggerDisplay,nq}")] internal ref struct ValueStringBuilder { /// The pooled array currently backing the builder, if one has been rented. @@ -57,6 +58,11 @@ public int Length /// Gets the underlying storage of the builder. public readonly Span RawChars => _chars; + /// Gets the DebuggerDisplay attribute. + /// ToString() clears the builder, so we need a side-effect free debugger display. + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private readonly string DebuggerDisplay => AsSpan().ToString(); + /// Gets a reference to the character at the specified index. /// The zero-based index of the character. /// A reference to the character at the index. diff --git a/src/tests/Refit.GeneratorTests/GeneratedRequestBuildingTests.cs b/src/tests/Refit.GeneratorTests/GeneratedRequestBuildingTests.cs index 5ebc80a32..7fe79cdca 100644 --- a/src/tests/Refit.GeneratorTests/GeneratedRequestBuildingTests.cs +++ b/src/tests/Refit.GeneratorTests/GeneratedRequestBuildingTests.cs @@ -453,9 +453,6 @@ public async Task SwitchOnFallsBackForUnsupportedInlinePathAndMetadata() [Get("relative")] Task Relative(); - [Get("/users/{id}")] - Task Templated(int id); - [Get("/bad\r\npath")] Task ControlCharacters(); @@ -1049,4 +1046,136 @@ public interface IGeneratedClient await Assert.That(generated).Contains("static body => (object?)body.@BaseValue"); await Assert.That(generated).Contains("\"secret-\""); } + + /// Verifies that path parameters are supported by the source generator. + /// A task representing the asynchronous test. + [Test] + public async Task EmitsInlineConstructionForPathParameters() + { + const string source = + """ + using System.Threading.Tasks; + using Refit; + + namespace RefitGeneratorTest; + + public interface IGeneratedClient + { + [Get("/a/{aVal}")] + Task Sample(int aVal); + } + """; + + var result = Fixture.RunGenerator(source, generatedRequestBuilding: true); + var generated = result.GeneratedSources[GeneratedClientHintName]; + + await Assert.That(result.CompilesWithoutErrors).IsTrue(); + await Assert.That(generated).Contains("""GeneratedRequestRunner.BuildRequestPath("/a/{aVal}", refitSettings.AllowUnmatchedRouteParameters, ((3, 9), """); + } + + /// Verifies that path parameters are supported by the source generator. + /// A task representing the asynchronous test. + [Test] + public async Task UsesGeneratedRequestBuilderForTemplatedQueryParameters() + { + const string source = + """ + using System.Threading.Tasks; + using Refit; + + namespace RefitGeneratorTest; + + public interface IGeneratedClient + { + [Get("/a?b={bVal}")] + Task Sample(string bVal); + } + """; + + var result = Fixture.RunGenerator(source, generatedRequestBuilding: true); + var generated = result.GeneratedSources[GeneratedClientHintName]; + + await Assert.That(result.CompilesWithoutErrors).IsTrue(); + await Assert.That(generated).Contains("""GeneratedRequestRunner.BuildRequestPath("/a?b={bVal}", refitSettings.AllowUnmatchedRouteParameters, ((5, 11), """); + } + + /// Verifies that non-templated parameters are not supported by the source generator. + /// A task representing the asynchronous test. + [Test] + public async Task UsesFallbackForNonTemplatedQueryParameters() + { + const string source = + """ + using System.Threading.Tasks; + using Refit; + + namespace RefitGeneratorTest; + + public interface IGeneratedClient + { + [Get("/a")] + Task Sample(string bVal); + } + """; + + var result = Fixture.RunGenerator(source, generatedRequestBuilding: true); + var generated = result.GeneratedSources[GeneratedClientHintName]; + + await Assert.That(result.CompilesWithoutErrors).IsTrue(); + await Assert.That(generated).Contains(ReflectiveRequestBuilderCall); + } + + /// Verifies that dotted path parameters are not supported by the source generator. + /// A task representing the asynchronous test. + [Test] + public async Task UsesFallbackForDottedPathPlaceholders() + { + const string source = + """ + using System.Threading.Tasks; + using Refit; + + namespace RefitGeneratorTest; + + public record class Data(string Value); + + public interface IGeneratedClient + { + [Get("/a/{data.Value}")] + Task Sample(Data data); + } + """; + + var result = Fixture.RunGenerator(source, generatedRequestBuilding: true); + var generated = result.GeneratedSources[GeneratedClientHintName]; + + await Assert.That(result.CompilesWithoutErrors).IsTrue(); + await Assert.That(generated).Contains(ReflectiveRequestBuilderCall); + } + + /// Verifies that round trip path parameters are not supported by the source generator. + /// A task representing the asynchronous test. + [Test] + public async Task UsesFallbackForRoundTripPathPlaceholders() + { + const string source = + """ + using System.Threading.Tasks; + using Refit; + + namespace RefitGeneratorTest; + + public interface IGeneratedClient + { + [Get("/a/{**path}")] + Task Sample(string path); + } + """; + + var result = Fixture.RunGenerator(source, generatedRequestBuilding: true); + var generated = result.GeneratedSources[GeneratedClientHintName]; + + await Assert.That(result.CompilesWithoutErrors).IsTrue(); + await Assert.That(generated).Contains(ReflectiveRequestBuilderCall); + } } diff --git a/src/tests/Refit.GeneratorTests/GeneratorComponentTests.cs b/src/tests/Refit.GeneratorTests/GeneratorComponentTests.cs index 57920411c..8352f27f4 100644 --- a/src/tests/Refit.GeneratorTests/GeneratorComponentTests.cs +++ b/src/tests/Refit.GeneratorTests/GeneratorComponentTests.cs @@ -537,7 +537,7 @@ private static TypeConstraint Constraint(KnownTypeConstraint known, params strin /// The body buffer mode. /// The request parameter model. private static RequestParameterModel CreateBody(string serializationMethod, BodyBufferMode bufferMode) => - new("body", StringTypeName, RequestParameterKind.Body, false, string.Empty, string.Empty, serializationMethod, bufferMode); + new("body", StringTypeName, null, ImmutableEquatableArray.Empty, RequestParameterKind.Body, false, string.Empty, string.Empty, serializationMethod, bufferMode); /// Creates an interface property model. /// The property name. @@ -653,13 +653,13 @@ public async Task InlinePathHelpers_NormalizeAndClassifyPaths() await Assert.That(Parser.NormalizeConstantPathForInline("/path?")).IsEqualTo(SimplePath); await Assert.That(Parser.NormalizeConstantPathForInline("/path?& \t =drop")).IsEqualTo(SimplePath); await Assert.That(Parser.NormalizeConstantPathForInline("/path?one=1&&two=2#fragment")).IsEqualTo("/path?one=1&two=2"); - await Assert.That(Parser.IsConstantPathSupported(string.Empty)).IsTrue(); - await Assert.That(Parser.IsConstantPathSupported(SimplePath)).IsTrue(); - await Assert.That(Parser.IsConstantPathSupported("relative")).IsFalse(); - await Assert.That(Parser.IsConstantPathSupported("/{id}")).IsFalse(); - await Assert.That(Parser.IsConstantPathSupported("/id}")).IsFalse(); - await Assert.That(Parser.IsConstantPathSupported("/line\nbreak")).IsFalse(); - await Assert.That(Parser.IsConstantPathSupported("/line\rbreak")).IsFalse(); + await Assert.That(Parser.IsPathSupported(string.Empty)).IsTrue(); + await Assert.That(Parser.IsPathSupported(SimplePath)).IsTrue(); + await Assert.That(Parser.IsPathSupported("relative")).IsFalse(); + await Assert.That(Parser.IsPathSupported("/{id}")).IsTrue(); + await Assert.That(Parser.IsPathSupported("/id}")).IsFalse(); + await Assert.That(Parser.IsPathSupported("/line\nbreak")).IsFalse(); + await Assert.That(Parser.IsPathSupported("/line\rbreak")).IsFalse(); await Assert.That(Parser.IsWhiteSpace(" \t", 0, WhitespaceLength)).IsTrue(); await Assert.That(Parser.IsWhiteSpace(" a", 0, WhitespaceLength)).IsFalse(); } @@ -710,13 +710,23 @@ public async Task BodyAndDisposalHelpers_ClassifySupportedValues() /// Creates a non-body parameter model. /// The request parameter model. private static RequestParameterModel CreateHeaderParameter() => - new("query", "string", RequestParameterKind.Header, true, string.Empty, string.Empty, string.Empty, BodyBufferMode.None); + new("query", "string", null, ImmutableEquatableArray.Empty, RequestParameterKind.Header, true, string.Empty, string.Empty, string.Empty, BodyBufferMode.None); /// Creates a body parameter model. /// The serialization method name. /// The request parameter model. private static RequestParameterModel CreateBody(string serializationMethod) => - new("body", "string", RequestParameterKind.Body, false, string.Empty, string.Empty, serializationMethod, BodyBufferMode.Buffered); + new( + "body", + "string", + null, + ImmutableEquatableArray.Empty, + RequestParameterKind.Body, + false, + string.Empty, + string.Empty, + serializationMethod, + BodyBufferMode.Buffered); } /// Tests for the ITypeSymbol generator extension helpers. diff --git a/src/tests/Refit.GeneratorTests/ModuleInitializer.cs b/src/tests/Refit.GeneratorTests/ModuleInitializer.cs index 3c226b76e..0fe9d556b 100644 --- a/src/tests/Refit.GeneratorTests/ModuleInitializer.cs +++ b/src/tests/Refit.GeneratorTests/ModuleInitializer.cs @@ -20,6 +20,10 @@ public static void Init() DerivePathInfo((file, _, type, method) => new(Path.Combine(Path.GetDirectoryName(file) ?? AppContext.BaseDirectory, "_snapshots"), type.Name, method.Name)); + // The generated GeneratedCodeAttribute stamps the generator assembly version, which is not stable + // across builds and CI. Scrub the line so snapshots stay version-independent. + VerifierSettings.ScrubLinesContaining("System.CodeDom.Compiler.GeneratedCodeAttribute"); + VerifySourceGenerators.Initialize(); VerifyDiffPlex.Initialize(OutputType.Compact); } diff --git a/src/tests/Refit.GeneratorTests/ParameterTests.cs b/src/tests/Refit.GeneratorTests/ParameterTests.cs index 258fbd270..ef88234cf 100644 --- a/src/tests/Refit.GeneratorTests/ParameterTests.cs +++ b/src/tests/Refit.GeneratorTests/ParameterTests.cs @@ -45,4 +45,34 @@ public Task NullableValueTypeRouteParameter() => [Get("/users/{user}")] Task Get(int? user); """); + + /// Verifies generation for a nullable value-type route parameter. + /// A task representing the asynchronous test. + [Test] + public Task ValueTypeRouteParameterWithAttribute() => + Fixture.VerifyForBody( + """ + [Get("/todos/{id}")] + Task Get([Query(Format = "00")]int? id); + """); + + /// Verifies generation for a nullable value-type route parameter. + /// A task representing the asynchronous test. + [Test] + public Task ValueTypeRouteParameterInQueryWithAttribute() => + Fixture.VerifyForBody( + """ + [Get("/todos?q={q}")] + Task Find([Query]string? q); + """); + + /// Verifies generation for a nullable value-type route parameter. + /// A task representing the asynchronous test. + [Test] + public Task ValueTypeRouteParameterInQueryWithoutAttribute() => + Fixture.VerifyForBody( + """ + [Get("/todos?q={q}")] + Task Find(string? q); + """); } diff --git a/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#Generated.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#Generated.g.verified.cs index f0c17e991..df87006ac 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#Generated.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#Generated.g.verified.cs @@ -7,7 +7,6 @@ namespace Refit.Implementation { /// Registers generated Refit factories for interfaces discovered at compile time. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#IGeneratedClient.g.verified.cs index b0dff45b6..9cfd3b608 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#PreserveAttribute.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#PreserveAttribute.g.verified.cs index b04c4a6a9..d8d210e83 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#PreserveAttribute.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/GeneratedTest.ShouldEmitAllFiles#PreserveAttribute.g.verified.cs @@ -7,7 +7,6 @@ namespace RefitInternalGenerated { /// Identifies generated members that should be preserved by tools that honor this attribute. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] [global::System.AttributeUsage (global::System.AttributeTargets.Class | global::System.AttributeTargets.Struct | global::System.AttributeTargets.Enum | global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Method | global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Event | global::System.AttributeTargets.Interface | global::System.AttributeTargets.Delegate)] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#Generated.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#Generated.g.verified.cs index 29c86c781..e5a15b916 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#Generated.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#Generated.g.verified.cs @@ -7,7 +7,6 @@ namespace Refit.Implementation { /// Registers generated Refit factories for interfaces discovered at compile time. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#IGitHubApi.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#IGitHubApi.g.verified.cs index 96c0e5a96..63729e544 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#IGitHubApi.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#IGitHubApi.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::Refit.Tests.IGitHubApi. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] @@ -38,67 +37,89 @@ public RefitTestsIGitHubApi(global::System.Net.Http.HttpClient client, global::R _settings = requestBuilder.Settings; } + /// Cached attribute provider for the generated GetUser method's userName parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______userNameAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); - /// Cached parameter type array for the generated GetUser method. - private static readonly global::System.Type[] ______typeParameters = new global::System.Type[] { typeof(string) }; /// - public async global::System.Threading.Tasks.Task GetUser(string @userName) + public global::System.Threading.Tasks.Task GetUser(string @userName) { - var refitArguments = new object[] { @userName }; - var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUser", ______typeParameters ); - - return await ((global::System.Threading.Tasks.Task)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/users/{username}", refitSettings.AllowUnmatchedRouteParameters, ((7, 17), _settings.UrlParameterFormatter.Format(userName, ______userNameAttributeProvider, typeof(string)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.SetHeader(refitRequest, "User-Agent", "Refit Integration Tests"); + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::Refit.Tests.IGitHubApi)); + return global::Refit.GeneratedRequestRunner.SendAsync( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); } /// Cached parameter type array for the generated GetUserObservable method. - private static readonly global::System.Type[] ______typeParameters0 = new global::System.Type[] { typeof(string) }; + private static readonly global::System.Type[] ______typeParameters = new global::System.Type[] { typeof(string) }; /// public global::System.IObservable GetUserObservable(string @userName) { var refitArguments = new object[] { @userName }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserObservable", ______typeParameters0 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserObservable", ______typeParameters ); return (global::System.IObservable)refitFunc(this.Client, refitArguments); } /// Cached parameter type array for the generated GetUserCamelCase method. - private static readonly global::System.Type[] ______typeParameters1 = new global::System.Type[] { typeof(string) }; + private static readonly global::System.Type[] ______typeParameters0 = new global::System.Type[] { typeof(string) }; /// public global::System.IObservable GetUserCamelCase(string @userName) { var refitArguments = new object[] { @userName }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserCamelCase", ______typeParameters1 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserCamelCase", ______typeParameters0 ); return (global::System.IObservable)refitFunc(this.Client, refitArguments); } + /// Cached attribute provider for the generated GetOrgMembers method's orgName parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______orgNameAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); - /// Cached parameter type array for the generated GetOrgMembers method. - private static readonly global::System.Type[] ______typeParameters2 = new global::System.Type[] { typeof(string), typeof(global::System.Threading.CancellationToken) }; /// - public async global::System.Threading.Tasks.Task> GetOrgMembers(string @orgName, global::System.Threading.CancellationToken @cancellationToken) + public global::System.Threading.Tasks.Task> GetOrgMembers(string @orgName, global::System.Threading.CancellationToken @cancellationToken) { - var refitArguments = new object[] { @orgName, @cancellationToken }; - var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetOrgMembers", ______typeParameters2 ); - - return await ((global::System.Threading.Tasks.Task>)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/orgs/{orgname}/members", refitSettings.AllowUnmatchedRouteParameters, ((6, 15), _settings.UrlParameterFormatter.Format(orgName, ______orgNameAttributeProvider, typeof(string)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.SetHeader(refitRequest, "User-Agent", "Refit Integration Tests"); + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::Refit.Tests.IGitHubApi)); + return global::Refit.GeneratedRequestRunner.SendAsync, global::System.Collections.Generic.List>( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + @cancellationToken); } /// Cached parameter type array for the generated FindUsers method. - private static readonly global::System.Type[] ______typeParameters3 = new global::System.Type[] { typeof(string) }; + private static readonly global::System.Type[] ______typeParameters1 = new global::System.Type[] { typeof(string) }; /// public async global::System.Threading.Tasks.Task FindUsers(string @q) { var refitArguments = new object[] { @q }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("FindUsers", ______typeParameters3 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("FindUsers", ______typeParameters1 ); return await ((global::System.Threading.Tasks.Task)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); } @@ -176,67 +197,78 @@ public RefitTestsIGitHubApi(global::System.Net.Http.HttpClient client, global::R global::System.Threading.CancellationToken.None); } + /// Cached attribute provider for the generated GetUserWithMetadata method's userName parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______userNameAttributeProvider0 = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); - /// Cached parameter type array for the generated GetUserWithMetadata method. - private static readonly global::System.Type[] ______typeParameters4 = new global::System.Type[] { typeof(string), typeof(global::System.Threading.CancellationToken) }; /// - public async global::System.Threading.Tasks.Task> GetUserWithMetadata(string @userName, global::System.Threading.CancellationToken @cancellationToken) + public global::System.Threading.Tasks.Task> GetUserWithMetadata(string @userName, global::System.Threading.CancellationToken @cancellationToken) { - var refitArguments = new object[] { @userName, @cancellationToken }; - var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserWithMetadata", ______typeParameters4 ); - - return await ((global::System.Threading.Tasks.Task>)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/users/{username}", refitSettings.AllowUnmatchedRouteParameters, ((7, 17), _settings.UrlParameterFormatter.Format(userName, ______userNameAttributeProvider0, typeof(string)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.SetHeader(refitRequest, "User-Agent", "Refit Integration Tests"); + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::Refit.Tests.IGitHubApi)); + return global::Refit.GeneratedRequestRunner.SendAsync, global::Refit.Tests.User>( + this.Client, + refitRequest, + refitSettings, + true, + true, + false, + @cancellationToken); } /// Cached parameter type array for the generated GetUserObservableWithMetadata method. - private static readonly global::System.Type[] ______typeParameters5 = new global::System.Type[] { typeof(string) }; + private static readonly global::System.Type[] ______typeParameters2 = new global::System.Type[] { typeof(string) }; /// public global::System.IObservable> GetUserObservableWithMetadata(string @userName) { var refitArguments = new object[] { @userName }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserObservableWithMetadata", ______typeParameters5 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserObservableWithMetadata", ______typeParameters2 ); return (global::System.IObservable>)refitFunc(this.Client, refitArguments); } /// Cached parameter type array for the generated GetUserIApiResponseObservableWithMetadata method. - private static readonly global::System.Type[] ______typeParameters6 = new global::System.Type[] { typeof(string) }; + private static readonly global::System.Type[] ______typeParameters3 = new global::System.Type[] { typeof(string) }; /// public global::System.IObservable> GetUserIApiResponseObservableWithMetadata(string @userName) { var refitArguments = new object[] { @userName }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserIApiResponseObservableWithMetadata", ______typeParameters6 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserIApiResponseObservableWithMetadata", ______typeParameters3 ); return (global::System.IObservable>)refitFunc(this.Client, refitArguments); } /// Cached parameter type array for the generated CreateUser method. - private static readonly global::System.Type[] ______typeParameters7 = new global::System.Type[] { typeof(global::Refit.Tests.User) }; + private static readonly global::System.Type[] ______typeParameters4 = new global::System.Type[] { typeof(global::Refit.Tests.User) }; /// public async global::System.Threading.Tasks.Task CreateUser(global::Refit.Tests.User @user) { var refitArguments = new object[] { @user }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("CreateUser", ______typeParameters7 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("CreateUser", ______typeParameters4 ); return await ((global::System.Threading.Tasks.Task)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); } /// Cached parameter type array for the generated CreateUserWithMetadata method. - private static readonly global::System.Type[] ______typeParameters8 = new global::System.Type[] { typeof(global::Refit.Tests.User) }; + private static readonly global::System.Type[] ______typeParameters5 = new global::System.Type[] { typeof(global::Refit.Tests.User) }; /// public async global::System.Threading.Tasks.Task> CreateUserWithMetadata(global::Refit.Tests.User @user) { var refitArguments = new object[] { @user }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("CreateUserWithMetadata", ______typeParameters8 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("CreateUserWithMetadata", ______typeParameters5 ); return await ((global::System.Threading.Tasks.Task>)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); } diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#IGitHubApiDisposable.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#IGitHubApiDisposable.g.verified.cs index 9ce93f6b4..221793e49 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#IGitHubApiDisposable.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#IGitHubApiDisposable.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::Refit.Tests.IGitHubApiDisposable. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#INestedGitHubApi.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#INestedGitHubApi.g.verified.cs index 75d86fb40..60944b232 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#INestedGitHubApi.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#INestedGitHubApi.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::Refit.Tests.TestNested.INestedGitHubApi. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] @@ -38,67 +37,89 @@ public RefitTestsTestNestedINestedGitHubApi(global::System.Net.Http.HttpClient c _settings = requestBuilder.Settings; } + /// Cached attribute provider for the generated GetUser method's userName parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______userNameAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); - /// Cached parameter type array for the generated GetUser method. - private static readonly global::System.Type[] ______typeParameters = new global::System.Type[] { typeof(string) }; /// - public async global::System.Threading.Tasks.Task GetUser(string @userName) + public global::System.Threading.Tasks.Task GetUser(string @userName) { - var refitArguments = new object[] { @userName }; - var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUser", ______typeParameters ); - - return await ((global::System.Threading.Tasks.Task)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/users/{username}", refitSettings.AllowUnmatchedRouteParameters, ((7, 17), _settings.UrlParameterFormatter.Format(userName, ______userNameAttributeProvider, typeof(string)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.SetHeader(refitRequest, "User-Agent", "Refit Integration Tests"); + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::Refit.Tests.TestNested.INestedGitHubApi)); + return global::Refit.GeneratedRequestRunner.SendAsync( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); } /// Cached parameter type array for the generated GetUserObservable method. - private static readonly global::System.Type[] ______typeParameters0 = new global::System.Type[] { typeof(string) }; + private static readonly global::System.Type[] ______typeParameters = new global::System.Type[] { typeof(string) }; /// public global::System.IObservable GetUserObservable(string @userName) { var refitArguments = new object[] { @userName }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserObservable", ______typeParameters0 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserObservable", ______typeParameters ); return (global::System.IObservable)refitFunc(this.Client, refitArguments); } /// Cached parameter type array for the generated GetUserCamelCase method. - private static readonly global::System.Type[] ______typeParameters1 = new global::System.Type[] { typeof(string) }; + private static readonly global::System.Type[] ______typeParameters0 = new global::System.Type[] { typeof(string) }; /// public global::System.IObservable GetUserCamelCase(string @userName) { var refitArguments = new object[] { @userName }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserCamelCase", ______typeParameters1 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetUserCamelCase", ______typeParameters0 ); return (global::System.IObservable)refitFunc(this.Client, refitArguments); } + /// Cached attribute provider for the generated GetOrgMembers method's orgName parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______orgNameAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); - /// Cached parameter type array for the generated GetOrgMembers method. - private static readonly global::System.Type[] ______typeParameters2 = new global::System.Type[] { typeof(string) }; /// - public async global::System.Threading.Tasks.Task> GetOrgMembers(string @orgName) + public global::System.Threading.Tasks.Task> GetOrgMembers(string @orgName) { - var refitArguments = new object[] { @orgName }; - var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("GetOrgMembers", ______typeParameters2 ); - - return await ((global::System.Threading.Tasks.Task>)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/orgs/{orgname}/members", refitSettings.AllowUnmatchedRouteParameters, ((6, 15), _settings.UrlParameterFormatter.Format(orgName, ______orgNameAttributeProvider, typeof(string)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.SetHeader(refitRequest, "User-Agent", "Refit Integration Tests"); + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::Refit.Tests.TestNested.INestedGitHubApi)); + return global::Refit.GeneratedRequestRunner.SendAsync, global::System.Collections.Generic.List>( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); } /// Cached parameter type array for the generated FindUsers method. - private static readonly global::System.Type[] ______typeParameters3 = new global::System.Type[] { typeof(string) }; + private static readonly global::System.Type[] ______typeParameters1 = new global::System.Type[] { typeof(string) }; /// public async global::System.Threading.Tasks.Task FindUsers(string @q) { var refitArguments = new object[] { @q }; var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("FindUsers", ______typeParameters3 ); + var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("FindUsers", ______typeParameters1 ); return await ((global::System.Threading.Tasks.Task)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); } diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#PreserveAttribute.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#PreserveAttribute.g.verified.cs index b04c4a6a9..d8d210e83 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#PreserveAttribute.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.FindInterfacesSmokeTest#PreserveAttribute.g.verified.cs @@ -7,7 +7,6 @@ namespace RefitInternalGenerated { /// Identifies generated members that should be preserved by tools that honor this attribute. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] [global::System.AttributeUsage (global::System.AttributeTargets.Class | global::System.AttributeTargets.Struct | global::System.AttributeTargets.Enum | global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Method | global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Event | global::System.AttributeTargets.Interface | global::System.AttributeTargets.Delegate)] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#Generated.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#Generated.g.verified.cs index d729e2e20..f0da813d0 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#Generated.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#Generated.g.verified.cs @@ -7,7 +7,6 @@ namespace Refit.Implementation { /// Registers generated Refit factories for interfaces discovered at compile time. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#IServiceWithoutNamespace.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#IServiceWithoutNamespace.g.verified.cs index 1fbd4ae66..3b460d932 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#IServiceWithoutNamespace.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#IServiceWithoutNamespace.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::IServiceWithoutNamespace. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#PreserveAttribute.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#PreserveAttribute.g.verified.cs index b04c4a6a9..d8d210e83 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#PreserveAttribute.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceStubGeneratorTests.GenerateInterfaceStubsWithoutNamespaceSmokeTest#PreserveAttribute.g.verified.cs @@ -7,7 +7,6 @@ namespace RefitInternalGenerated { /// Identifies generated members that should be preserved by tools that honor this attribute. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] [global::System.AttributeUsage (global::System.AttributeTargets.Class | global::System.AttributeTargets.Struct | global::System.AttributeTargets.Enum | global::System.AttributeTargets.Constructor | global::System.AttributeTargets.Method | global::System.AttributeTargets.Property | global::System.AttributeTargets.Field | global::System.AttributeTargets.Event | global::System.AttributeTargets.Interface | global::System.AttributeTargets.Delegate)] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.ContainedInterfaceTest#IContainedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.ContainedInterfaceTest#IContainedInterface.g.verified.cs index eda3937d5..45da4d764 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.ContainedInterfaceTest#IContainedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.ContainedInterfaceTest#IContainedInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.ContainerType.IContainedInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DefaultInterfaceMethod#IGeneratedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DefaultInterfaceMethod#IGeneratedInterface.g.verified.cs index 7e46697f8..a6a283c34 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DefaultInterfaceMethod#IGeneratedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DefaultInterfaceMethod#IGeneratedInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DerivedDefaultInterfaceMethod#IBaseInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DerivedDefaultInterfaceMethod#IBaseInterface.g.verified.cs index 6629efbba..c0f76014a 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DerivedDefaultInterfaceMethod#IBaseInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DerivedDefaultInterfaceMethod#IBaseInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IBaseInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DerivedDefaultInterfaceMethod#IGeneratedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DerivedDefaultInterfaceMethod#IGeneratedInterface.g.verified.cs index afd9f3b8b..d4a745169 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DerivedDefaultInterfaceMethod#IGeneratedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DerivedDefaultInterfaceMethod#IGeneratedInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DisposableTest#IGeneratedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DisposableTest#IGeneratedInterface.g.verified.cs index 58b09775a..6a57aeac3 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DisposableTest#IGeneratedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.DisposableTest#IGeneratedInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::IGeneratedInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.GlobalNamespaceTest#IGeneratedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.GlobalNamespaceTest#IGeneratedInterface.g.verified.cs index bf0b761a2..809f5244d 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.GlobalNamespaceTest#IGeneratedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.GlobalNamespaceTest#IGeneratedInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::IGeneratedInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceDerivedFromRefitBaseTest#IBaseInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceDerivedFromRefitBaseTest#IBaseInterface.g.verified.cs index 150c4b046..14bbeb787 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceDerivedFromRefitBaseTest#IBaseInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceDerivedFromRefitBaseTest#IBaseInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IBaseInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceDerivedFromRefitBaseTest#IDerivedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceDerivedFromRefitBaseTest#IDerivedInterface.g.verified.cs index 38698b2c1..4110bd76c 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceDerivedFromRefitBaseTest#IDerivedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceDerivedFromRefitBaseTest#IDerivedInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IDerivedInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceWithGenericConstraint#IGeneratedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceWithGenericConstraint#IGeneratedInterface.g.verified.cs index 429c4e99b..c07005410 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceWithGenericConstraint#IGeneratedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfaceWithGenericConstraint#IGeneratedInterface.g.verified.cs @@ -15,7 +15,6 @@ internal partial class Generated /// The generated interface type parameter. /// The generated interface type parameter. /// The generated interface type parameter. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentCasing#IApi.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentCasing#IApi.g.verified.cs index 7cec662d7..bc60f420b 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentCasing#IApi.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentCasing#IApi.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IApi. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentCasing#Iapi1.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentCasing#Iapi1.g.verified.cs index fb3213a7e..1daf8765b 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentCasing#Iapi1.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentCasing#Iapi1.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.Iapi. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentSignature#IApi.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentSignature#IApi.g.verified.cs index 7cec662d7..bc60f420b 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentSignature#IApi.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentSignature#IApi.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IApi. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentSignature#IApi1.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentSignature#IApi1.g.verified.cs index 6e3b30d39..341e04c28 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentSignature#IApi1.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.InterfacesWithDifferentSignature#IApi1.g.verified.cs @@ -11,7 +11,6 @@ internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IApi<T>. /// The generated interface type parameter. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.NestedNamespaceTest#IGeneratedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.NestedNamespaceTest#IGeneratedInterface.g.verified.cs index da838cde3..397539c3f 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.NestedNamespaceTest#IGeneratedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.NestedNamespaceTest#IGeneratedInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::Nested.RefitGeneratorTest.IGeneratedInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.NonRefitMethodShouldRaiseDiagnostic#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.NonRefitMethodShouldRaiseDiagnostic#IGeneratedClient.g.verified.cs index 235397314..7cd8c9e71 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.NonRefitMethodShouldRaiseDiagnostic#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.NonRefitMethodShouldRaiseDiagnostic#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromBaseTest#IGeneratedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromBaseTest#IGeneratedInterface.g.verified.cs index 22adcf944..4d89badce 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromBaseTest#IGeneratedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromBaseTest#IGeneratedInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromRefitBaseTest#IBaseInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromRefitBaseTest#IBaseInterface.g.verified.cs index 6629efbba..c0f76014a 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromRefitBaseTest#IBaseInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromRefitBaseTest#IBaseInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IBaseInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromRefitBaseTest#IGeneratedInterface.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromRefitBaseTest#IGeneratedInterface.g.verified.cs index afd9f3b8b..d4a745169 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromRefitBaseTest#IGeneratedInterface.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/InterfaceTests.RefitInterfaceDerivedFromRefitBaseTest#IGeneratedInterface.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedInterface. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/MethodTests.MethodsWithGenericConstraints#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/MethodTests.MethodsWithGenericConstraints#IGeneratedClient.g.verified.cs index 03931457e..81fb52332 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/MethodTests.MethodsWithGenericConstraints#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/MethodTests.MethodsWithGenericConstraints#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.NullableRouteParameter#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.NullableRouteParameter#IGeneratedClient.g.verified.cs index 1fdc7da7f..84fb5e16f 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.NullableRouteParameter#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.NullableRouteParameter#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] @@ -38,17 +37,35 @@ public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient cli _settings = requestBuilder.Settings; } + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class for generated-only execution. + /// The HTTP client used by the generated implementation. + /// The settings used by the generated implementation. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.RefitSettings settings) + { + Client = client; + _settings = settings; + } + /// Cached attribute provider for the generated Get method's user parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______userAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); - /// Cached parameter type array for the generated Get method. - private static readonly global::System.Type[] ______typeParameters = new global::System.Type[] { typeof(string) }; /// - public async global::System.Threading.Tasks.Task Get(string? @user) + public global::System.Threading.Tasks.Task Get(string? @user) { - var refitArguments = new object[] { @user }; - var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("Get", ______typeParameters ); - - return await ((global::System.Threading.Tasks.Task)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/users/{user}", refitSettings.AllowUnmatchedRouteParameters, ((7, 13), _settings.UrlParameterFormatter.Format(user, ______userAttributeProvider, typeof(string)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::RefitGeneratorTest.IGeneratedClient)); + return global::Refit.GeneratedRequestRunner.SendAsync( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); } } } diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.NullableValueTypeRouteParameter#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.NullableValueTypeRouteParameter#IGeneratedClient.g.verified.cs index 950d6f8fd..6f52f05b1 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.NullableValueTypeRouteParameter#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.NullableValueTypeRouteParameter#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] @@ -38,17 +37,35 @@ public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient cli _settings = requestBuilder.Settings; } + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class for generated-only execution. + /// The HTTP client used by the generated implementation. + /// The settings used by the generated implementation. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.RefitSettings settings) + { + Client = client; + _settings = settings; + } + /// Cached attribute provider for the generated Get method's user parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______userAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); - /// Cached parameter type array for the generated Get method. - private static readonly global::System.Type[] ______typeParameters = new global::System.Type[] { typeof(int?) }; /// - public async global::System.Threading.Tasks.Task Get(int? @user) + public global::System.Threading.Tasks.Task Get(int? @user) { - var refitArguments = new object[] { @user }; - var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("Get", ______typeParameters ); - - return await ((global::System.Threading.Tasks.Task)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/users/{user}", refitSettings.AllowUnmatchedRouteParameters, ((7, 13), _settings.UrlParameterFormatter.Format(user, ______userAttributeProvider, typeof(int?)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::RefitGeneratorTest.IGeneratedClient)); + return global::Refit.GeneratedRequestRunner.SendAsync( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); } } } diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.RouteParameter#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.RouteParameter#IGeneratedClient.g.verified.cs index ffd0bc687..d1c17a64e 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.RouteParameter#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.RouteParameter#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] @@ -38,17 +37,35 @@ public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient cli _settings = requestBuilder.Settings; } + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class for generated-only execution. + /// The HTTP client used by the generated implementation. + /// The settings used by the generated implementation. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.RefitSettings settings) + { + Client = client; + _settings = settings; + } + /// Cached attribute provider for the generated Get method's user parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______userAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); - /// Cached parameter type array for the generated Get method. - private static readonly global::System.Type[] ______typeParameters = new global::System.Type[] { typeof(string) }; /// - public async global::System.Threading.Tasks.Task Get(string @user) + public global::System.Threading.Tasks.Task Get(string @user) { - var refitArguments = new object[] { @user }; - var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("Get", ______typeParameters ); - - return await ((global::System.Threading.Tasks.Task)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/users/{user}", refitSettings.AllowUnmatchedRouteParameters, ((7, 13), _settings.UrlParameterFormatter.Format(user, ______userAttributeProvider, typeof(string)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::RefitGeneratorTest.IGeneratedClient)); + return global::Refit.GeneratedRequestRunner.SendAsync( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); } } } diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameter#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameter#IGeneratedClient.g.verified.cs index a99489183..b9f666d6c 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameter#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameter#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] @@ -38,17 +37,35 @@ public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient cli _settings = requestBuilder.Settings; } + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class for generated-only execution. + /// The HTTP client used by the generated implementation. + /// The settings used by the generated implementation. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.RefitSettings settings) + { + Client = client; + _settings = settings; + } + /// Cached attribute provider for the generated Get method's user parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______userAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); - /// Cached parameter type array for the generated Get method. - private static readonly global::System.Type[] ______typeParameters = new global::System.Type[] { typeof(int) }; /// - public async global::System.Threading.Tasks.Task Get(int @user) + public global::System.Threading.Tasks.Task Get(int @user) { - var refitArguments = new object[] { @user }; - var refitRequestBuilder = _requestBuilder ?? throw new global::System.InvalidOperationException("This generated Refit method requires a request builder."); - var refitFunc = refitRequestBuilder.BuildRestResultFuncForMethod("Get", ______typeParameters ); - - return await ((global::System.Threading.Tasks.Task)refitFunc(this.Client, refitArguments)).ConfigureAwait(false); + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/users/{user}", refitSettings.AllowUnmatchedRouteParameters, ((7, 13), _settings.UrlParameterFormatter.Format(user, ______userAttributeProvider, typeof(int)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::RefitGeneratorTest.IGeneratedClient)); + return global::Refit.GeneratedRequestRunner.SendAsync( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); } } } diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameterInQueryWithAttribute#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameterInQueryWithAttribute#IGeneratedClient.g.verified.cs new file mode 100644 index 000000000..3c36e583b --- /dev/null +++ b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameterInQueryWithAttribute#IGeneratedClient.g.verified.cs @@ -0,0 +1,72 @@ +//HintName: IGeneratedClient.g.cs +// + +#nullable enable annotations +#nullable disable warnings + +namespace Refit.Implementation +{ + /// Contains generated Refit implementation types. + internal partial class Generated + { + /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Diagnostics.DebuggerNonUserCode] + [global::RefitInternalGenerated.PreserveAttribute] + [global::System.Reflection.Obfuscation(Exclude=true)] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + private sealed class RefitGeneratorTestIGeneratedClient + : global::RefitGeneratorTest.IGeneratedClient + { + /// The request builder used to create Refit method delegates. + private readonly global::Refit.IRequestBuilder? _requestBuilder; + + /// The settings used by this generated Refit implementation. + private readonly global::Refit.RefitSettings _settings; + + /// Gets the HTTP client used by this generated Refit implementation. + public global::System.Net.Http.HttpClient Client { get; } + + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class. + /// The HTTP client used by the generated implementation. + /// The request builder used to create Refit method delegates. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.IRequestBuilder requestBuilder) + { + Client = client; + _requestBuilder = requestBuilder; + _settings = requestBuilder.Settings; + } + + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class for generated-only execution. + /// The HTTP client used by the generated implementation. + /// The settings used by the generated implementation. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.RefitSettings settings) + { + Client = client; + _settings = settings; + } + /// Cached attribute provider for the generated Find method's q parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______qAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary() {{ typeof(global::Refit.QueryAttribute), new object[] { new global::Refit.QueryAttribute()} }}); + + /// + public global::System.Threading.Tasks.Task Find(string? @q) + { + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/todos?q={q}", refitSettings.AllowUnmatchedRouteParameters, ((9, 12), _settings.UrlParameterFormatter.Format(q, ______qAttributeProvider, typeof(string)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::RefitGeneratorTest.IGeneratedClient)); + return global::Refit.GeneratedRequestRunner.SendAsync( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); + } + } + } +} diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameterInQueryWithoutAttribute#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameterInQueryWithoutAttribute#IGeneratedClient.g.verified.cs new file mode 100644 index 000000000..8e4b7cac6 --- /dev/null +++ b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameterInQueryWithoutAttribute#IGeneratedClient.g.verified.cs @@ -0,0 +1,72 @@ +//HintName: IGeneratedClient.g.cs +// + +#nullable enable annotations +#nullable disable warnings + +namespace Refit.Implementation +{ + /// Contains generated Refit implementation types. + internal partial class Generated + { + /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Diagnostics.DebuggerNonUserCode] + [global::RefitInternalGenerated.PreserveAttribute] + [global::System.Reflection.Obfuscation(Exclude=true)] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + private sealed class RefitGeneratorTestIGeneratedClient + : global::RefitGeneratorTest.IGeneratedClient + { + /// The request builder used to create Refit method delegates. + private readonly global::Refit.IRequestBuilder? _requestBuilder; + + /// The settings used by this generated Refit implementation. + private readonly global::Refit.RefitSettings _settings; + + /// Gets the HTTP client used by this generated Refit implementation. + public global::System.Net.Http.HttpClient Client { get; } + + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class. + /// The HTTP client used by the generated implementation. + /// The request builder used to create Refit method delegates. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.IRequestBuilder requestBuilder) + { + Client = client; + _requestBuilder = requestBuilder; + _settings = requestBuilder.Settings; + } + + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class for generated-only execution. + /// The HTTP client used by the generated implementation. + /// The settings used by the generated implementation. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.RefitSettings settings) + { + Client = client; + _settings = settings; + } + /// Cached attribute provider for the generated Find method's q parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______qAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary()); + + /// + public global::System.Threading.Tasks.Task Find(string? @q) + { + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/todos?q={q}", refitSettings.AllowUnmatchedRouteParameters, ((9, 12), _settings.UrlParameterFormatter.Format(q, ______qAttributeProvider, typeof(string)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::RefitGeneratorTest.IGeneratedClient)); + return global::Refit.GeneratedRequestRunner.SendAsync( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); + } + } + } +} diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameterWithAttribute#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameterWithAttribute#IGeneratedClient.g.verified.cs new file mode 100644 index 000000000..5475971a5 --- /dev/null +++ b/src/tests/Refit.GeneratorTests/_snapshots/ParameterTests.ValueTypeRouteParameterWithAttribute#IGeneratedClient.g.verified.cs @@ -0,0 +1,72 @@ +//HintName: IGeneratedClient.g.cs +// + +#nullable enable annotations +#nullable disable warnings + +namespace Refit.Implementation +{ + /// Contains generated Refit implementation types. + internal partial class Generated + { + /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Diagnostics.DebuggerNonUserCode] + [global::RefitInternalGenerated.PreserveAttribute] + [global::System.Reflection.Obfuscation(Exclude=true)] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + private sealed class RefitGeneratorTestIGeneratedClient + : global::RefitGeneratorTest.IGeneratedClient + { + /// The request builder used to create Refit method delegates. + private readonly global::Refit.IRequestBuilder? _requestBuilder; + + /// The settings used by this generated Refit implementation. + private readonly global::Refit.RefitSettings _settings; + + /// Gets the HTTP client used by this generated Refit implementation. + public global::System.Net.Http.HttpClient Client { get; } + + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class. + /// The HTTP client used by the generated implementation. + /// The request builder used to create Refit method delegates. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.IRequestBuilder requestBuilder) + { + Client = client; + _requestBuilder = requestBuilder; + _settings = requestBuilder.Settings; + } + + /// Initializes a new instance of the RefitGeneratorTestIGeneratedClient class for generated-only execution. + /// The HTTP client used by the generated implementation. + /// The settings used by the generated implementation. + public RefitGeneratorTestIGeneratedClient(global::System.Net.Http.HttpClient client, global::Refit.RefitSettings settings) + { + Client = client; + _settings = settings; + } + /// Cached attribute provider for the generated Get method's id parameter. + private static readonly global::Refit.GeneratedParameterAttributeProvider ______idAttributeProvider = new global::Refit.GeneratedParameterAttributeProvider(new global::System.Collections.Generic.Dictionary() {{ typeof(global::Refit.QueryAttribute), new object[] { new global::Refit.QueryAttribute(){ Format = "00" }} }}); + + /// + public global::System.Threading.Tasks.Task Get(int? @id) + { + var refitSettings = _settings; + var refitRequest = new global::System.Net.Http.HttpRequestMessage(global::System.Net.Http.HttpMethod.Get, global::Refit.GeneratedRequestRunner.BuildRelativeUri(this.Client, global::Refit.GeneratedRequestRunner.BuildRequestPath("/todos/{id}", refitSettings.AllowUnmatchedRouteParameters, ((7, 11), _settings.UrlParameterFormatter.Format(id, ______idAttributeProvider, typeof(int?)))), refitSettings.UrlResolution)); + #if NET6_0_OR_GREATER + refitRequest.Version = refitSettings.Version; + refitRequest.VersionPolicy = refitSettings.VersionPolicy; + #endif + global::Refit.GeneratedRequestRunner.AddConfiguredRequestOptions(refitRequest, refitSettings, typeof(global::RefitGeneratorTest.IGeneratedClient)); + return global::Refit.GeneratedRequestRunner.SendAsync( + this.Client, + refitRequest, + refitSettings, + false, + true, + false, + global::System.Threading.CancellationToken.None); + } + } + } +} diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericConstraintReturnTask#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericConstraintReturnTask#IGeneratedClient.g.verified.cs index ac2d2acf2..4252d445b 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericConstraintReturnTask#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericConstraintReturnTask#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericStructConstraintReturnTask#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericStructConstraintReturnTask#IGeneratedClient.g.verified.cs index bc4b8b388..7558812dc 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericStructConstraintReturnTask#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericStructConstraintReturnTask#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericTaskShouldWork#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericTaskShouldWork#IGeneratedClient.g.verified.cs index b0dff45b6..9cfd3b608 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericTaskShouldWork#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericTaskShouldWork#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericUnmanagedConstraintReturnTask#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericUnmanagedConstraintReturnTask#IGeneratedClient.g.verified.cs index 882a4eb43..55050accd 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericUnmanagedConstraintReturnTask#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericUnmanagedConstraintReturnTask#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericValueTaskShouldWork#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericValueTaskShouldWork#IGeneratedClient.g.verified.cs index af5557ff9..37006cc1f 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericValueTaskShouldWork#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.GenericValueTaskShouldWork#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnIObservable#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnIObservable#IGeneratedClient.g.verified.cs index 4e69bbb68..c7d4abca6 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnIObservable#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnIObservable#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnNullableObject#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnNullableObject#IGeneratedClient.g.verified.cs index b0dff45b6..9cfd3b608 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnNullableObject#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnNullableObject#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnNullableValueType#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnNullableValueType#IGeneratedClient.g.verified.cs index ccac7894f..deddf3c9b 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnNullableValueType#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnNullableValueType#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnUnsupportedType#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnUnsupportedType#IGeneratedClient.g.verified.cs index ed1e5f2ad..0b5c0d8b1 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnUnsupportedType#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ReturnUnsupportedType#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ValueTaskApiResponseShouldWork#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ValueTaskApiResponseShouldWork#IGeneratedClient.g.verified.cs index 0f8ad6746..67fccee82 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ValueTaskApiResponseShouldWork#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.ValueTaskApiResponseShouldWork#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.VoidTaskShouldWork#IGeneratedClient.g.verified.cs b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.VoidTaskShouldWork#IGeneratedClient.g.verified.cs index 52cf7135a..98229724b 100644 --- a/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.VoidTaskShouldWork#IGeneratedClient.g.verified.cs +++ b/src/tests/Refit.GeneratorTests/_snapshots/ReturnTypeTests.VoidTaskShouldWork#IGeneratedClient.g.verified.cs @@ -10,7 +10,6 @@ namespace Refit.Implementation internal partial class Generated { /// Generated Refit implementation for global::RefitGeneratorTest.IGeneratedClient. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("InterfaceStubGeneratorV2", "12.0.0.0")] [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] [global::System.Diagnostics.DebuggerNonUserCode] [global::RefitInternalGenerated.PreserveAttribute] diff --git a/src/tests/Refit.Newtonsoft.Json.Tests/RestServiceIntegrationTests.GitHub.cs b/src/tests/Refit.Newtonsoft.Json.Tests/RestServiceIntegrationTests.GitHub.cs index ebc96bcb1..3210e8213 100644 --- a/src/tests/Refit.Newtonsoft.Json.Tests/RestServiceIntegrationTests.GitHub.cs +++ b/src/tests/Refit.Newtonsoft.Json.Tests/RestServiceIntegrationTests.GitHub.cs @@ -423,7 +423,9 @@ public async Task RequestCanceledBeforeResponseRead() await Assert.That(result!.InnerException).IsNotNull(); await Assert.That(result.InnerException).IsTypeOf(); - await AssertStackTraceContains(nameof(IGitHubApi.GetOrgMembers), result.StackTrace); + + // Source generated requests directly return the SendAsync task so won't contain the caller stack frame. + await AssertStackTraceContains(nameof(GeneratedRequestRunner.SendAsync), result.StackTrace); } /// Verifies cancellation before the response is read surfaces in the API response error. diff --git a/src/tests/Refit.Tests/GeneratedFactoryApiClient.cs b/src/tests/Refit.Tests/GeneratedFactoryApiClient.cs index aec513873..8083f86c9 100644 --- a/src/tests/Refit.Tests/GeneratedFactoryApiClient.cs +++ b/src/tests/Refit.Tests/GeneratedFactoryApiClient.cs @@ -24,4 +24,7 @@ internal sealed class GeneratedFactoryApiClient(HttpClient client, IRequestBuild /// public Task GetById(string id) => Task.CompletedTask; + + /// + public Task GetQuery(string id) => Task.CompletedTask; } diff --git a/src/tests/Refit.Tests/GeneratedParameterAttributeProvider.GetCustomAttributesTests.cs b/src/tests/Refit.Tests/GeneratedParameterAttributeProvider.GetCustomAttributesTests.cs new file mode 100644 index 000000000..9a174beaa --- /dev/null +++ b/src/tests/Refit.Tests/GeneratedParameterAttributeProvider.GetCustomAttributesTests.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2019-2026 ReactiveUI and Contributors. All rights reserved. +// ReactiveUI and Contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace Refit.Tests; + +/// GeneratedParameterAttributeProvider tests. +public partial class GeneratedParameterAttributeProviderTests +{ + /// Test throws ArgumentNullException for null type. + [Test] + public void GetCustomAttributesThrowsForNullType() + { + var provider = new GeneratedParameterAttributeProvider(new Dictionary()); + +#nullable disable + _ = Assert.Throws(() => _ = provider.GetCustomAttributes(null, false)); +#nullable restore + } + + /// Test GetCustomAttributes returns an empty array for empty provider. + /// A task representing the asynchronous test. + [Test] + public async Task GetCustomAttributesReturnsEmptyArrayForEmptyProvider() + { + var provider = new GeneratedParameterAttributeProvider(new Dictionary()); + + var result = provider.GetCustomAttributes(typeof(QueryAttribute), false); + + await Assert.That(result).IsEmpty(); + } + + /// Test GetCustomAttributes returns an array. + /// A task representing the asynchronous test. + [Test] + public async Task GetCustomAttributesReturnsAttributesArray() + { + var provider = + new GeneratedParameterAttributeProvider(new Dictionary + { + { typeof(QueryAttribute), [new QueryAttribute()] } + }); + + var result = provider.GetCustomAttributes(typeof(QueryAttribute), false); + + await Assert.That(result).IsNotEmpty().And.HasSingleItem().And.ContainsOnly(o => o is QueryAttribute); + } + + /// Test GetCustomAttributes with no type returns an array of all attributes. + /// A task representing the asynchronous test. + [Test] + public async Task GetCustomAttributesWithNoTypeReturnsAttributesArray() + { + var provider = + new GeneratedParameterAttributeProvider(new Dictionary + { + { typeof(QueryAttribute), [new QueryAttribute()] }, + { typeof(AliasAsAttribute), [new AliasAsAttribute("foo")] } + }); + + const int expectedCount = 2; + + var result = provider.GetCustomAttributes(false); + + await Assert.That(result).IsNotEmpty().And.HasCountBetween(expectedCount, expectedCount).And.ContainsOnly(o => o is QueryAttribute or AliasAsAttribute); + } +} diff --git a/src/tests/Refit.Tests/GeneratedParameterAttributeProvider.IsDefinedTests.cs b/src/tests/Refit.Tests/GeneratedParameterAttributeProvider.IsDefinedTests.cs new file mode 100644 index 000000000..f76a2e71b --- /dev/null +++ b/src/tests/Refit.Tests/GeneratedParameterAttributeProvider.IsDefinedTests.cs @@ -0,0 +1,47 @@ +// Copyright (c) 2019-2026 ReactiveUI and Contributors. All rights reserved. +// ReactiveUI and Contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace Refit.Tests; + +/// GeneratedParameterAttributeProvider tests. +public partial class GeneratedParameterAttributeProviderTests +{ + /// Test IsDefined returns false for empty provider. + /// A task representing the asynchronous test. + [Test] + public async Task IsDefinedReturnsFalseForEmptyProvider() + { + var provider = new GeneratedParameterAttributeProvider(new Dictionary()); + + var isDefined = provider.IsDefined(typeof(QueryAttribute), false); + + await Assert.That(isDefined).IsFalse(); + } + + /// Test IsDefined returns false when type doesn't exist. + /// A task representing the asynchronous test. + [Test] + public async Task IsDefinedReturnsFalseForUnavailableTypeInProvider() + { + var provider = new GeneratedParameterAttributeProvider( + new Dictionary { { typeof(AliasAsAttribute), [new AliasAsAttribute("foo")] } }); + + var isDefined = provider.IsDefined(typeof(QueryAttribute), false); + + await Assert.That(isDefined).IsFalse(); + } + + /// Test IsDefined returns true when type exists. + /// A task representing the asynchronous test. + [Test] + public async Task IsDefinedReturnsTrueForAvailableTypeInProvider() + { + var provider = new GeneratedParameterAttributeProvider( + new Dictionary { { typeof(QueryAttribute), [new QueryAttribute()] } }); + + var isDefined = provider.IsDefined(typeof(QueryAttribute), false); + + await Assert.That(isDefined).IsTrue(); + } +} diff --git a/src/tests/Refit.Tests/GeneratedRequestRunnerTests.BuildRequestPath.cs b/src/tests/Refit.Tests/GeneratedRequestRunnerTests.BuildRequestPath.cs new file mode 100644 index 000000000..42a9be5a9 --- /dev/null +++ b/src/tests/Refit.Tests/GeneratedRequestRunnerTests.BuildRequestPath.cs @@ -0,0 +1,84 @@ +// Copyright (c) 2019-2026 ReactiveUI and Contributors. All rights reserved. +// ReactiveUI and Contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace Refit.Tests; + +/// Tests for building request paths with route parameters via . +public partial class GeneratedRequestRunnerTests +{ + /// Verifies BuildRequestPath returns a path with substituted parameters. + /// The expected result. + /// The templated path. + /// Whether unmatched route parameters are supported. + /// The URI parameters. + /// A task that represents the asynchronous operation. + [Test] + [InstanceMethodDataSource(typeof(GeneratedRequestRunnerTestsDataSources), nameof(GeneratedRequestRunnerTestsDataSources.BuildRequestPathReplacesParametersData))] + public async Task BuildRequestPathReplacesParameters(string expectedResult, string path, bool allowUnmatchedRouteParameters, params ((int start, int end) location, string? value)[] uriParams) + { + var result = GeneratedRequestRunner.BuildRequestPath(path, allowUnmatchedRouteParameters, uriParams); + + await Assert.That(result).EqualTo(expectedResult); + } + + /// Verifies BuildRequestPath fails when a parameter is not provided. + /// A task that represents the asynchronous operation. + [Test] + public async Task BuildRequestPathFailsOnParameterNotFound() => + await Assert + .That(() => + { + var result = GeneratedRequestRunner.BuildRequestPath("/user/{id}", false); + Console.WriteLine(result); + }).Throws() + .WithMessage("URL /user/{id} has parameter {id}, but no method parameter matches", StringComparison.Ordinal); + + /// Provides test data for . + internal static class GeneratedRequestRunnerTestsDataSources + { + /// Data source for the test. + /// Test data. + internal static + IEnumerable> BuildRequestPathReplacesParametersData() + { + const string usersId = "/users/{id}"; + const string usersIdOrders = "/users/{id}/orders"; + const string rowCol = "/foo/row_{idx}/col_{idx}"; + + yield return new(("/users/20", usersId, false, Bind(usersId, "20"))); + yield return new(("/users/20", usersId, true, Bind(usersId, "20"))); + yield return new(("/users/20/", $"{usersId}/", true, Bind(usersId, "20"))); + yield return new(("/users/20/foo{bar", $"{usersId}/foo{{bar", false, Bind(usersId, "20"))); + yield return new(("/users/20/foo}{bar", $"{usersId}/foo}}{{bar", false, Bind(usersId, "20"))); + yield return new(("/users/20/orders", usersIdOrders, false, Bind(usersIdOrders, "20"))); + yield return new(("/users/", usersId, false, Bind(usersId, (string?)null))); + yield return new(("/foo/row_2/col_2", rowCol, false, Bind(rowCol, "2", "2"))); + yield return new(("/users/{id}", usersId, true, [])); + yield return new(("/users/%7B20%7D", usersId, true, Bind(usersId, "{20}"))); + } + + /// Builds parameter locations by scanning the template for {placeholder} spans. + /// The templated path. + /// The value for each placeholder, in order. + /// The located parameters paired with their values. + private static ((int start, int end) location, string? value)[] Bind(string template, params string?[] values) + { + var located = new List<((int start, int end) location, string? value)>(); + var search = 0; + var index = 0; + int open; + while ((open = template.IndexOf('{', search)) >= 0) + { + var close = template.IndexOf('}', open) + 1; + located.Add(((open, close), values[index])); + search = close; + index++; + } + + return [.. located]; + } + } +} diff --git a/src/tests/Refit.Tests/GeneratedRequestRunnerTests.cs b/src/tests/Refit.Tests/GeneratedRequestRunnerTests.cs index 8e3d0d967..580e53b6a 100644 --- a/src/tests/Refit.Tests/GeneratedRequestRunnerTests.cs +++ b/src/tests/Refit.Tests/GeneratedRequestRunnerTests.cs @@ -9,7 +9,7 @@ namespace Refit.Tests; /// Tests for the generated request runtime helper. -public class GeneratedRequestRunnerTests +public partial class GeneratedRequestRunnerTests { /// Relative request path shared by the generated-runner fixtures. private const string RelativeResourcePath = "/resource"; diff --git a/src/tests/Refit.Tests/IApiWithDecimal.cs b/src/tests/Refit.Tests/IApiWithDecimal.cs index 7cddfa2a2..1dde6611e 100644 --- a/src/tests/Refit.Tests/IApiWithDecimal.cs +++ b/src/tests/Refit.Tests/IApiWithDecimal.cs @@ -14,4 +14,10 @@ public interface IApiWithDecimal /// The response body as a string. [Get("/withDecimal")] Task GetWithDecimal(decimal value); + + /// Gets a response sending a decimal query value. + /// The decimal value to send. + /// The response body as a string. + [Get("/withDecimal?value={value}")] + Task GetWithDecimalGenerated(decimal value); } diff --git a/src/tests/Refit.Tests/IGeneratedFactoryApi.cs b/src/tests/Refit.Tests/IGeneratedFactoryApi.cs index d67cd29d3..0ff15e4d3 100644 --- a/src/tests/Refit.Tests/IGeneratedFactoryApi.cs +++ b/src/tests/Refit.Tests/IGeneratedFactoryApi.cs @@ -19,4 +19,10 @@ public interface IGeneratedFactoryApi /// A task that completes when the request finishes. [Get("/generated/{id}")] Task GetById(string id); + + /// Gets the generated endpoint with a query parameter. + /// The generated endpoint identifier. + /// A task that completes when the request finishes. + [Get("/generated")] + Task GetQuery(string id); } diff --git a/src/tests/Refit.Tests/IGeneratedParametersApi.cs b/src/tests/Refit.Tests/IGeneratedParametersApi.cs new file mode 100644 index 000000000..b2e60470a --- /dev/null +++ b/src/tests/Refit.Tests/IGeneratedParametersApi.cs @@ -0,0 +1,48 @@ +// Copyright (c) 2019-2026 ReactiveUI and Contributors. All rights reserved. +// ReactiveUI and Contributors licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace Refit.Tests; + +/// A Refit API surface used to exercise generated URL parameter formatting. +public interface IGeneratedParametersApi +{ + /// Gets a value using a simple string path parameter. + /// The path parameter value. + /// The response body. + [Get("/{value}")] + Task GetPath(string value); + + /// Gets a value using a simple string query parameter. + /// The query parameter value. + /// The response body. + [Get("/?q={queryKey}")] + Task GetQuery(string queryKey); + + /// Gets a value using a simple string query parameter. + /// The query parameter value. + /// The response body. + [Get("/?q={q}")] + Task GetQueryAlias([AliasAs("q")]string queryKey); + + /// Gets something where multiple parameters appear within a single URL segment. + /// The identifier appearing in the segment. + /// The width value appearing in the segment. + /// The height value appearing in the segment. + /// A task whose result is the fetched string. + [Get("/{id}/{width}x{height}/foo")] + Task FetchSomethingWithMultipleParametersPerSegment(int id, int width, int height); + + /// Gets something where multiple parameters appear within a single URL segment. + /// The identifier appearing in the segment. + /// The width value appearing in the segment. + /// A task whose result is the fetched string. + [Get("/{id}/{width}x{width}/foo")] + Task FetchSomethingWithMultipleRepeatedParametersPerSegment(int id, int width); + + /// Gets a value using a nullable parameter. + /// The parameter value. + /// The response body. + [Get("/a/{value}/b")] + Task GetNullableParam(int? value); +} diff --git a/src/tests/Refit.Tests/RequestBuilderTests.cs b/src/tests/Refit.Tests/RequestBuilderTests.cs index ce94be26e..f232b67e9 100644 --- a/src/tests/Refit.Tests/RequestBuilderTests.cs +++ b/src/tests/Refit.Tests/RequestBuilderTests.cs @@ -745,4 +745,17 @@ public async Task MultipleParametersInTheSameSegmentAreGeneratedProperly() var uri = new Uri(new(ApiBaseUrl), output.RequestUri!); await Assert.That(uri.PathAndQuery).IsEqualTo("/6/1024x768/foo"); } + + /// Verifies a simple string path parameter is formatted with the expected metadata. + /// A task that represents the asynchronous test. + [Test] + public async Task UrlParameterShouldWorkWithGeneratedCode() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod(nameof(IBasicApi.GetParam)); + var output = await factory([nameof(IBasicApi.GetParam)]); + + var uri = new Uri(new("http://api"), output.RequestUri!); + await Assert.That(uri.PathAndQuery).IsEqualTo($"/{nameof(IBasicApi.GetParam)}"); + } } diff --git a/src/tests/Refit.Tests/RestServiceIntegrationTests.cs b/src/tests/Refit.Tests/RestServiceIntegrationTests.cs index 407b9a215..2baf447ff 100644 --- a/src/tests/Refit.Tests/RestServiceIntegrationTests.cs +++ b/src/tests/Refit.Tests/RestServiceIntegrationTests.cs @@ -21,6 +21,9 @@ public partial class RestServiceIntegrationTests /// Base URL used by the mock HTTP handler exchanges. private const string BaseUrl = "http://foo"; + /// Query key used by the decimal query-parameter exchanges. + private const string DecimalQueryKey = "value"; + /// Base URL including a trailing slash. private const string BaseUrlWithSlash = "http://foo/"; @@ -983,7 +986,7 @@ public async Task GetWithDecimal() var handler = new StubHttp { { - new RouteMatcher { Method = HttpMethod.Get, Template = "http://foo/withDecimal", ExactQueryParams = [("value", "3.456")] }, + new RouteMatcher { Method = HttpMethod.Get, Template = "http://foo/withDecimal", ExactQueryParams = [(DecimalQueryKey, "3.456")] }, Reply.Json("Ok") }, }; @@ -996,6 +999,136 @@ public async Task GetWithDecimal() await handler.VerifyAllCalledAsync(); } + /// Verifies a decimal query parameter is formatted correctly. + /// A task representing the asynchronous test. + [Test] + public async Task GetWithDecimalGenerated() + { + var handler = new StubHttp + { + { + new RouteMatcher { Method = HttpMethod.Get, Template = "http://foo/withDecimal", ExactQueryParams = [(DecimalQueryKey, "3.456")] }, + Reply.Json("Ok") + }, + }; + var fixture = handler.CreateClient(BaseUrl); + + const decimal val = 3.456M; + + _ = await fixture.GetWithDecimalGenerated(val); + + await handler.VerifyAllCalledAsync(); + } + + /// Verifies a path parameter is formatted correctly. + /// A task representing the asynchronous test. + [Test] + public async Task GetWithPathParameterGenerated() + { + var handler = new StubHttp + { + { Route.Get("http://foo/bar"), Reply.Json("Ok") }, + }; + var fixture = handler.CreateGeneratedClient(BaseUrl); + + _ = await fixture.GetPath("bar"); + + await handler.VerifyAllCalledAsync(); + } + + /// Verifies a query parameter is formatted correctly. + /// A task representing the asynchronous test. + [Test] + public async Task GetWithQueryParameterGenerated() + { + var handler = new StubHttp + { + { + new RouteMatcher { Method = HttpMethod.Get, Template = "http://foo/", ExactQueryParams = [("q", "bar")] }, + Reply.Json("Ok") + }, + }; + var fixture = handler.CreateGeneratedClient(BaseUrl); + + _ = await fixture.GetQuery("bar"); + + await handler.VerifyAllCalledAsync(); + } + + /// Verifies an aliased query parameter is formatted correctly. + /// A task representing the asynchronous test. + [Test] + public async Task GetWithAliasedQueryParameterGenerated() + { + var handler = new StubHttp + { + { + new RouteMatcher { Method = HttpMethod.Get, Template = "http://foo/", ExactQueryParams = [("q", "bar")] }, + Reply.Json("Ok") + }, + }; + var fixture = handler.CreateGeneratedClient(BaseUrl); + + _ = await fixture.GetQueryAlias("bar"); + + await handler.VerifyAllCalledAsync(); + } + + /// Verifies a URL with multiple query parameters is formatted correctly. + /// A task representing the asynchronous test. + [Test] + public async Task GetWithMultipleParametersGenerated() + { + const int id = 1; + const int width = 800; + const int height = 600; + + var handler = new StubHttp + { + { Route.Get("http://foo/1/800x600/foo"), Reply.Json("Ok") }, + }; + var fixture = handler.CreateGeneratedClient(BaseUrl); + + _ = await fixture.FetchSomethingWithMultipleParametersPerSegment(id, width, height); + + await handler.VerifyAllCalledAsync(); + } + + /// Verifies a URL with multiple repeated query parameters is formatted correctly. + /// A task representing the asynchronous test. + [Test] + public async Task GetWithMultipleRepeatedParametersGenerated() + { + const int id = 1; + const int size = 300; + + var handler = new StubHttp + { + { Route.Get("http://foo/1/300x300/foo"), Reply.Json("Ok") }, + }; + var fixture = handler.CreateGeneratedClient(BaseUrl); + + _ = await fixture.FetchSomethingWithMultipleRepeatedParametersPerSegment(id, size); + + await handler.VerifyAllCalledAsync(); + } + + /// Verifies a URL with a nullable parameters is formatted correctly. + /// A task representing the asynchronous test. + [Test] + public async Task GetWithNullableParameterGenerated() + { + var handler = new StubHttp + { + { Route.Get("http://foo/a//b"), Reply.Json("Ok") }, + }; + var fixture = handler.CreateGeneratedClient(BaseUrl); + + _ = await fixture.GetNullableParam(null); + + await handler.VerifyAllCalledAsync(); + } + /// Opens the embedded test resource at the given relative path as a stream. /// The path of the embedded resource relative to the assembly root. /// A stream over the matching embedded resource. diff --git a/src/tests/Refit.Tests/TestUrlFormatter.cs b/src/tests/Refit.Tests/TestUrlFormatter.cs index a5e607d07..f4380f861 100644 --- a/src/tests/Refit.Tests/TestUrlFormatter.cs +++ b/src/tests/Refit.Tests/TestUrlFormatter.cs @@ -86,6 +86,29 @@ private static bool SameMetadata(ICustomAttributeProvider actual, ICustomAttribu && a.Member.Module == b.Member.Module, (MemberInfo a, MemberInfo b) => a.MetadataToken == b.MetadataToken && a.Module == b.Module, - _ => Equals(actual, expected), + _ => SameAttributes(actual, expected), }; + + /// + /// Compares two providers of different kinds by the attributes they expose. Generated request + /// building supplies a synthetic instead of the + /// reflection , so the formatter matches on the attribute metadata both + /// providers carry rather than on the concrete provider type. + /// + /// The attribute provider received by the formatter. + /// The attribute provider the test expects. + /// if both expose the same attribute types. + private static bool SameAttributes(ICustomAttributeProvider actual, ICustomAttributeProvider expected) + { + static string[] AttributeTypeNames(ICustomAttributeProvider provider) + { + var names = provider.GetCustomAttributes(false) + .Select(static attribute => attribute.GetType().FullName ?? string.Empty) + .ToArray(); + Array.Sort(names, StringComparer.Ordinal); + return names; + } + + return AttributeTypeNames(actual).SequenceEqual(AttributeTypeNames(expected)); + } }