From c490a06d693ae96630fa2ffacc6328df880a3ace Mon Sep 17 00:00:00 2001 From: Chris Pulman Date: Sun, 26 May 2024 18:59:29 +0100 Subject: [PATCH] Update Net 8 Support to use Netx.x instead of Nestandard2.1 Remove Net 7.0 --- Directory.Build.targets | 10 - .../Refit.HttpClientFactory.csproj | 2 +- .../Refit.Newtonsoft.Json.csproj | 2 +- .../AuthenticatedClientHandlerTests.cs | 533 +- ...rSeparatedPropertyNamesContractResolver.cs | 59 +- Refit.Tests/ExceptionFactoryTests.cs | 173 +- Refit.Tests/FormValueMultimapTests.cs | 481 +- Refit.Tests/GitHubApi.cs | 193 +- .../HttpClientFactoryExtensionsTests.cs | 317 +- Refit.Tests/IDefaultInterfaceMethodTests.cs | 131 +- Refit.Tests/IInterfaceWithoutRefit.cs | 9 +- Refit.Tests/InheritedGenericInterfacesApi.cs | 137 +- .../InheritedInterfacesInSeparateFileApi.cs | 11 +- Refit.Tests/IntegrationTestHelper.cs | 33 +- Refit.Tests/InterfaceStubGenerator.cs | 457 +- Refit.Tests/MethodOverloads.cs | 327 +- Refit.Tests/MultipartTests.cs | 1513 ++-- Refit.Tests/MyQueryParams.cs | 43 +- Refit.Tests/NullableReferenceTypes.cs | 187 +- Refit.Tests/PartialInterfacesApi.First.cs | 11 +- Refit.Tests/PartialInterfacesApi.Second.cs | 11 +- Refit.Tests/Refit.Tests.csproj | 2 +- Refit.Tests/RequestBuilder.cs | 6841 ++++++++--------- Refit.Tests/ResponseTests.cs | 821 +- Refit.Tests/RestService.cs | 3587 +++++---- Refit.Tests/SerializedContentTests.cs | 281 +- Refit.Tests/TypeCollisionApiA.cs | 21 +- Refit.Tests/TypeCollisionApiB.cs | 21 +- Refit.Tests/UseCultureAttribute.cs | 155 +- ...crementalSourceGeneratorVerifier`1+Test.cs | 79 +- ...arpIncrementalSourceGeneratorVerifier`1.cs | 9 +- .../CSharpSourceGeneratorVerifier`1+Test.cs | 45 +- .../CSharpSourceGeneratorVerifier`1.cs | 9 +- Refit.Tests/Verifiers/CSharpVerifierHelper.cs | 43 +- Refit.Tests/XmlContentSerializerTests.cs | 223 +- Refit.Xml/Refit.Xml.csproj | 2 +- ...PooledBufferWriter.Stream.NETStandard21.cs | 2 +- Refit/Buffers/PooledBufferWriter.Stream.cs | 2 +- Refit/Refit.csproj | 14 +- Refit/RestMethodInfo.cs | 6 +- 40 files changed, 8385 insertions(+), 8418 deletions(-) delete mode 100644 Directory.Build.targets diff --git a/Directory.Build.targets b/Directory.Build.targets deleted file mode 100644 index 27227ad74..000000000 --- a/Directory.Build.targets +++ /dev/null @@ -1,10 +0,0 @@ - - - - - $(DefineConstants);NET5_0_OR_GREATER - - - - - diff --git a/Refit.HttpClientFactory/Refit.HttpClientFactory.csproj b/Refit.HttpClientFactory/Refit.HttpClientFactory.csproj index 4aad7255f..7fdec8b0f 100644 --- a/Refit.HttpClientFactory/Refit.HttpClientFactory.csproj +++ b/Refit.HttpClientFactory/Refit.HttpClientFactory.csproj @@ -3,7 +3,7 @@ Refit HTTP Client Factory Extensions Refit HTTP Client Factory Extensions - net462;netstandard2.0;net6.0;net7.0;net8.0 + net462;netstandard2.0;net6.0;net8.0 enable diff --git a/Refit.Newtonsoft.Json/Refit.Newtonsoft.Json.csproj b/Refit.Newtonsoft.Json/Refit.Newtonsoft.Json.csproj index 7c7174142..03f8cbaa5 100644 --- a/Refit.Newtonsoft.Json/Refit.Newtonsoft.Json.csproj +++ b/Refit.Newtonsoft.Json/Refit.Newtonsoft.Json.csproj @@ -3,7 +3,7 @@ Refit Serializer for Newtonsoft.Json ($(TargetFramework)) Refit Serializers for Newtonsoft.Json - net462;netstandard2.0;netstandard2.1 + net462;netstandard2.0;net6.0;net7.0;net8.0 true Refit enable diff --git a/Refit.Tests/AuthenticatedClientHandlerTests.cs b/Refit.Tests/AuthenticatedClientHandlerTests.cs index 1c028ee1c..33969a040 100644 --- a/Refit.Tests/AuthenticatedClientHandlerTests.cs +++ b/Refit.Tests/AuthenticatedClientHandlerTests.cs @@ -9,347 +9,346 @@ using Refit; // for the code gen using Xunit; -namespace Refit.Tests +namespace Refit.Tests; + +public class AuthenticatedClientHandlerTests { - public class AuthenticatedClientHandlerTests + public interface IMyAuthenticatedService { - public interface IMyAuthenticatedService - { - [Get("/unauth")] - Task GetUnauthenticated(); - - [Get("/auth")] - [Headers("Authorization: Bearer")] - Task GetAuthenticated(); - - [Get("/auth")] - Task GetAuthenticatedWithTokenInMethod([Authorize("Bearer")] string token); - - [Get("/auth")] - Task GetAuthenticatedWithAuthorizeAttributeAndHeaderCollection( - [Authorize("Bearer")] string token, - [HeaderCollection] IDictionary headers - ); - - [Get("/auth")] - Task GetAuthenticatedWithTokenInHeaderCollection( - [HeaderCollection] IDictionary headers - ); - - [Post("/auth/{id}")] - Task PostAuthenticatedWithTokenInHeaderCollection( - int id, - SomeRequestData content, - [HeaderCollection] IDictionary headers - ); - } - - public interface IInheritedAuthenticatedServiceWithHeaders - : IAuthenticatedServiceWithHeaders - { - [Get("/get-inherited-thing")] - Task GetInheritedThing(); - } + [Get("/unauth")] + Task GetUnauthenticated(); + [Get("/auth")] [Headers("Authorization: Bearer")] - public interface IAuthenticatedServiceWithHeaders - { - [Get("/get-base-thing")] - Task GetThingFromBase(); - } + Task GetAuthenticated(); + + [Get("/auth")] + Task GetAuthenticatedWithTokenInMethod([Authorize("Bearer")] string token); + + [Get("/auth")] + Task GetAuthenticatedWithAuthorizeAttributeAndHeaderCollection( + [Authorize("Bearer")] string token, + [HeaderCollection] IDictionary headers + ); + + [Get("/auth")] + Task GetAuthenticatedWithTokenInHeaderCollection( + [HeaderCollection] IDictionary headers + ); + + [Post("/auth/{id}")] + Task PostAuthenticatedWithTokenInHeaderCollection( + int id, + SomeRequestData content, + [HeaderCollection] IDictionary headers + ); + } - [Fact] - public void DefaultHandlerIsHttpClientHandler() - { - var handler = new AuthenticatedHttpClientHandler( - ((_, _) => Task.FromResult(string.Empty)) - ); + public interface IInheritedAuthenticatedServiceWithHeaders + : IAuthenticatedServiceWithHeaders + { + [Get("/get-inherited-thing")] + Task GetInheritedThing(); + } - Assert.IsType(handler.InnerHandler); - } + [Headers("Authorization: Bearer")] + public interface IAuthenticatedServiceWithHeaders + { + [Get("/get-base-thing")] + Task GetThingFromBase(); + } - [Fact] - public void NullTokenGetterThrows() - { - Assert.Throws(() => new AuthenticatedHttpClientHandler(null)); - } + [Fact] + public void DefaultHandlerIsHttpClientHandler() + { + var handler = new AuthenticatedHttpClientHandler( + ((_, _) => Task.FromResult(string.Empty)) + ); - [Fact] - public async void AuthenticatedHandlerIgnoresUnAuth() + Assert.IsType(handler.InnerHandler); + } + + [Fact] + public void NullTokenGetterThrows() + { + Assert.Throws(() => new AuthenticatedHttpClientHandler(null)); + } + + [Fact] + public async void AuthenticatedHandlerIgnoresUnAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() - { - AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"), - HttpMessageHandlerFactory = () => handler - }; + AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"), + HttpMessageHandlerFactory = () => handler + }; - handler - .Expect(HttpMethod.Get, "http://api/unauth") - .With(msg => msg.Headers.Authorization == null) - .Respond("text/plain", "Ok"); + handler + .Expect(HttpMethod.Get, "http://api/unauth") + .With(msg => msg.Headers.Authorization == null) + .Respond("text/plain", "Ok"); - var fixture = RestService.For("http://api", settings); + var fixture = RestService.For("http://api", settings); - var result = await fixture.GetUnauthenticated(); + var result = await fixture.GetUnauthenticated(); - handler.VerifyNoOutstandingExpectation(); + handler.VerifyNoOutstandingExpectation(); - Assert.Equal("Ok", result); - } + Assert.Equal("Ok", result); + } - [Fact] - public async void AuthenticatedHandlerUsesAuth() + [Fact] + public async void AuthenticatedHandlerUsesAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() - { - AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"), - HttpMessageHandlerFactory = () => handler - }; + AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"), + HttpMessageHandlerFactory = () => handler + }; - handler - .Expect(HttpMethod.Get, "http://api/auth") - .WithHeaders("Authorization", "Bearer tokenValue") - .Respond("text/plain", "Ok"); + handler + .Expect(HttpMethod.Get, "http://api/auth") + .WithHeaders("Authorization", "Bearer tokenValue") + .Respond("text/plain", "Ok"); - var fixture = RestService.For("http://api", settings); + var fixture = RestService.For("http://api", settings); - var result = await fixture.GetAuthenticated(); + var result = await fixture.GetAuthenticated(); - handler.VerifyNoOutstandingExpectation(); + handler.VerifyNoOutstandingExpectation(); - Assert.Equal("Ok", result); - } + Assert.Equal("Ok", result); + } - [Fact] - public async void AuthenticatedHandlerWithParamUsesAuth() + [Fact] + public async void AuthenticatedHandlerWithParamUsesAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() - { - AuthorizationHeaderValueGetter = (request, _) => Task.FromResult("tokenValue"), - HttpMessageHandlerFactory = () => handler - }; + AuthorizationHeaderValueGetter = (request, _) => Task.FromResult("tokenValue"), + HttpMessageHandlerFactory = () => handler + }; - handler - .Expect(HttpMethod.Get, "http://api/auth") - .WithHeaders("Authorization", "Bearer tokenValue") - .Respond("text/plain", "Ok"); + handler + .Expect(HttpMethod.Get, "http://api/auth") + .WithHeaders("Authorization", "Bearer tokenValue") + .Respond("text/plain", "Ok"); - var fixture = RestService.For("http://api", settings); + var fixture = RestService.For("http://api", settings); - var result = await fixture.GetAuthenticated(); + var result = await fixture.GetAuthenticated(); - handler.VerifyNoOutstandingExpectation(); + handler.VerifyNoOutstandingExpectation(); - Assert.Equal("Ok", result); - } + Assert.Equal("Ok", result); + } - [Fact] - public async void AuthenticatedHandlerWithTokenInParameterUsesAuth() - { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + [Fact] + public async void AuthenticatedHandlerWithTokenInParameterUsesAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + + handler + .Expect(HttpMethod.Get, "http://api/auth") + .WithHeaders("Authorization", "Bearer tokenValue") + .Respond("text/plain", "Ok"); - handler - .Expect(HttpMethod.Get, "http://api/auth") - .WithHeaders("Authorization", "Bearer tokenValue") - .Respond("text/plain", "Ok"); + var fixture = RestService.For("http://api", settings); - var fixture = RestService.For("http://api", settings); + var result = await fixture.GetAuthenticatedWithTokenInMethod("tokenValue"); - var result = await fixture.GetAuthenticatedWithTokenInMethod("tokenValue"); + handler.VerifyNoOutstandingExpectation(); - handler.VerifyNoOutstandingExpectation(); + Assert.Equal("Ok", result); + } - Assert.Equal("Ok", result); - } + [Fact] + public async void AuthenticatedHandlerWithTokenInHeaderCollectionUsesAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - [Fact] - public async void AuthenticatedHandlerWithTokenInHeaderCollectionUsesAuth() + var headers = new Dictionary { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + { "User-Agent", "Refit" }, + { "Authorization", "Bearer tokenValue" } + }; - var headers = new Dictionary - { - { "User-Agent", "Refit" }, - { "Authorization", "Bearer tokenValue" } - }; + handler + .Expect(HttpMethod.Get, "http://api/auth") + .WithHeaders(headers) + .Respond("text/plain", "Ok"); - handler - .Expect(HttpMethod.Get, "http://api/auth") - .WithHeaders(headers) - .Respond("text/plain", "Ok"); + var fixture = RestService.For("http://api", settings); - var fixture = RestService.For("http://api", settings); + var result = await fixture.GetAuthenticatedWithTokenInHeaderCollection(headers); - var result = await fixture.GetAuthenticatedWithTokenInHeaderCollection(headers); + handler.VerifyNoOutstandingExpectation(); - handler.VerifyNoOutstandingExpectation(); + Assert.Equal("Ok", result); + } - Assert.Equal("Ok", result); - } + [Fact] + public async void AuthenticatedHandlerWithAuthorizeAttributeAndHeaderCollectionUsesAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - [Fact] - public async void AuthenticatedHandlerWithAuthorizeAttributeAndHeaderCollectionUsesAuth() + var expectedHeaders = new Dictionary { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + { "Authorization", "Bearer tokenValue" }, + { "User-Agent", "Refit" }, + { "X-Forwarded-For", "Refit" } + }; - var expectedHeaders = new Dictionary - { - { "Authorization", "Bearer tokenValue" }, - { "User-Agent", "Refit" }, - { "X-Forwarded-For", "Refit" } - }; + var headerCollectionHeaders = new Dictionary + { + { "User-Agent", "Refit" }, + { "X-Forwarded-For", "Refit" } + }; - var headerCollectionHeaders = new Dictionary - { - { "User-Agent", "Refit" }, - { "X-Forwarded-For", "Refit" } - }; + handler + .Expect(HttpMethod.Get, "http://api/auth") + .WithHeaders(expectedHeaders) + .Respond("text/plain", "Ok"); - handler - .Expect(HttpMethod.Get, "http://api/auth") - .WithHeaders(expectedHeaders) - .Respond("text/plain", "Ok"); + var fixture = RestService.For("http://api", settings); - var fixture = RestService.For("http://api", settings); + var result = await fixture.GetAuthenticatedWithAuthorizeAttributeAndHeaderCollection( + "tokenValue", + headerCollectionHeaders + ); - var result = await fixture.GetAuthenticatedWithAuthorizeAttributeAndHeaderCollection( - "tokenValue", - headerCollectionHeaders - ); + handler.VerifyNoOutstandingExpectation(); - handler.VerifyNoOutstandingExpectation(); + Assert.Equal("Ok", result); + } - Assert.Equal("Ok", result); - } + [Fact] + public async void AuthenticatedHandlerWithDuplicatedAuthorizationHeaderUsesAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - [Fact] - public async void AuthenticatedHandlerWithDuplicatedAuthorizationHeaderUsesAuth() + var expectedHeaders = new Dictionary { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - - var expectedHeaders = new Dictionary - { - { "Authorization", "Bearer tokenValue2" }, - { "User-Agent", "Refit" }, - { "X-Forwarded-For", "Refit" } - }; - - var headerCollectionHeaders = new Dictionary - { - { "Authorization", "Bearer tokenValue2" }, - { "User-Agent", "Refit" }, - { "X-Forwarded-For", "Refit" } - }; - - handler - .Expect(HttpMethod.Get, "http://api/auth") - .WithHeaders(expectedHeaders) - .Respond("text/plain", "Ok"); - - var fixture = RestService.For("http://api", settings); - - var result = await fixture.GetAuthenticatedWithAuthorizeAttributeAndHeaderCollection( - "tokenValue", - headerCollectionHeaders - ); - - handler.VerifyNoOutstandingExpectation(); - - Assert.Equal("Ok", result); - } - - [Fact] - public async void AuthenticatedHandlerPostTokenInHeaderCollectionUsesAuth() + { "Authorization", "Bearer tokenValue2" }, + { "User-Agent", "Refit" }, + { "X-Forwarded-For", "Refit" } + }; + + var headerCollectionHeaders = new Dictionary { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + { "Authorization", "Bearer tokenValue2" }, + { "User-Agent", "Refit" }, + { "X-Forwarded-For", "Refit" } + }; - var id = 1; - var someRequestData = new SomeRequestData { ReadablePropertyName = 1 }; + handler + .Expect(HttpMethod.Get, "http://api/auth") + .WithHeaders(expectedHeaders) + .Respond("text/plain", "Ok"); - var headers = new Dictionary - { - { "Authorization", "Bearer tokenValue2" }, - { "ThingId", id.ToString() } - }; + var fixture = RestService.For("http://api", settings); - handler - .Expect(HttpMethod.Post, $"http://api/auth/{id}") - .WithHeaders(headers) - .Respond("text/plain", "Ok"); + var result = await fixture.GetAuthenticatedWithAuthorizeAttributeAndHeaderCollection( + "tokenValue", + headerCollectionHeaders + ); - var fixture = RestService.For("http://api", settings); + handler.VerifyNoOutstandingExpectation(); - var result = await fixture.PostAuthenticatedWithTokenInHeaderCollection( - id, - someRequestData, - headers - ); + Assert.Equal("Ok", result); + } - handler.VerifyNoOutstandingExpectation(); + [Fact] + public async void AuthenticatedHandlerPostTokenInHeaderCollectionUsesAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - Assert.Equal("Ok", result); - } + var id = 1; + var someRequestData = new SomeRequestData { ReadablePropertyName = 1 }; - [Fact] - public async void AuthentictedMethodFromBaseClassWithHeadersAttributeUsesAuth() + var headers = new Dictionary { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() - { - AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"), - HttpMessageHandlerFactory = () => handler - }; + { "Authorization", "Bearer tokenValue2" }, + { "ThingId", id.ToString() } + }; - handler - .Expect(HttpMethod.Get, "http://api/get-base-thing") - .WithHeaders("Authorization", "Bearer tokenValue") - .Respond("text/plain", "Ok"); + handler + .Expect(HttpMethod.Post, $"http://api/auth/{id}") + .WithHeaders(headers) + .Respond("text/plain", "Ok"); - var fixture = RestService.For( - "http://api", - settings - ); + var fixture = RestService.For("http://api", settings); - var result = await fixture.GetThingFromBase(); + var result = await fixture.PostAuthenticatedWithTokenInHeaderCollection( + id, + someRequestData, + headers + ); - handler.VerifyNoOutstandingExpectation(); + handler.VerifyNoOutstandingExpectation(); - Assert.Equal("Ok", result); - } + Assert.Equal("Ok", result); + } + + [Fact] + public async void AuthentictedMethodFromBaseClassWithHeadersAttributeUsesAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() + { + AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"), + HttpMessageHandlerFactory = () => handler + }; + + handler + .Expect(HttpMethod.Get, "http://api/get-base-thing") + .WithHeaders("Authorization", "Bearer tokenValue") + .Respond("text/plain", "Ok"); + + var fixture = RestService.For( + "http://api", + settings + ); - [Fact] - public async void AuthentictedMethodFromInheritedClassWithHeadersAttributeUsesAuth() + var result = await fixture.GetThingFromBase(); + + handler.VerifyNoOutstandingExpectation(); + + Assert.Equal("Ok", result); + } + + [Fact] + public async void AuthentictedMethodFromInheritedClassWithHeadersAttributeUsesAuth() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() - { - AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"), - HttpMessageHandlerFactory = () => handler - }; + AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"), + HttpMessageHandlerFactory = () => handler + }; - handler - .Expect(HttpMethod.Get, "http://api/get-inherited-thing") - .WithHeaders("Authorization", "Bearer tokenValue") - .Respond("text/plain", "Ok"); + handler + .Expect(HttpMethod.Get, "http://api/get-inherited-thing") + .WithHeaders("Authorization", "Bearer tokenValue") + .Respond("text/plain", "Ok"); - var fixture = RestService.For( - "http://api", - settings - ); + var fixture = RestService.For( + "http://api", + settings + ); - var result = await fixture.GetInheritedThing(); + var result = await fixture.GetInheritedThing(); - handler.VerifyNoOutstandingExpectation(); + handler.VerifyNoOutstandingExpectation(); - Assert.Equal("Ok", result); - } + Assert.Equal("Ok", result); } } diff --git a/Refit.Tests/DeliminatorSeparatedPropertyNamesContractResolver.cs b/Refit.Tests/DeliminatorSeparatedPropertyNamesContractResolver.cs index 76840648b..3df2387d3 100644 --- a/Refit.Tests/DeliminatorSeparatedPropertyNamesContractResolver.cs +++ b/Refit.Tests/DeliminatorSeparatedPropertyNamesContractResolver.cs @@ -4,46 +4,45 @@ using System.Globalization; using Newtonsoft.Json.Serialization; -namespace Refit.Tests +namespace Refit.Tests; + +public class DeliminatorSeparatedPropertyNamesContractResolver : DefaultContractResolver { - public class DeliminatorSeparatedPropertyNamesContractResolver : DefaultContractResolver + readonly string separator; + + protected DeliminatorSeparatedPropertyNamesContractResolver(char separator) { - readonly string separator; + this.separator = separator.ToString(CultureInfo.InvariantCulture); + } - protected DeliminatorSeparatedPropertyNamesContractResolver(char separator) - { - this.separator = separator.ToString(CultureInfo.InvariantCulture); - } + protected override string ResolvePropertyName(string propertyName) + { + var parts = new List(); + var currentWord = new StringBuilder(); - protected override string ResolvePropertyName(string propertyName) + foreach (var c in propertyName.ToCharArray()) { - var parts = new List(); - var currentWord = new StringBuilder(); - - foreach (var c in propertyName.ToCharArray()) - { - if (Char.IsUpper(c) && currentWord.Length > 0) - { - parts.Add(currentWord.ToString()); - currentWord.Clear(); - } - - currentWord.Append(char.ToLower(c)); - } - - if (currentWord.Length > 0) + if (Char.IsUpper(c) && currentWord.Length > 0) { parts.Add(currentWord.ToString()); + currentWord.Clear(); } - return String.Join(separator, parts.ToArray()); + currentWord.Append(char.ToLower(c)); } - } - public class SnakeCasePropertyNamesContractResolver - : DeliminatorSeparatedPropertyNamesContractResolver - { - public SnakeCasePropertyNamesContractResolver() - : base('_') { } + if (currentWord.Length > 0) + { + parts.Add(currentWord.ToString()); + } + + return String.Join(separator, parts.ToArray()); } } + +public class SnakeCasePropertyNamesContractResolver + : DeliminatorSeparatedPropertyNamesContractResolver +{ + public SnakeCasePropertyNamesContractResolver() + : base('_') { } +} diff --git a/Refit.Tests/ExceptionFactoryTests.cs b/Refit.Tests/ExceptionFactoryTests.cs index 6ddb43486..ea2bba891 100644 --- a/Refit.Tests/ExceptionFactoryTests.cs +++ b/Refit.Tests/ExceptionFactoryTests.cs @@ -9,111 +9,110 @@ using Xunit; -namespace Refit.Tests +namespace Refit.Tests; + +public class ExceptionFactoryTests { - public class ExceptionFactoryTests + public interface IMyService { - public interface IMyService - { - [Get("/get-with-result")] - Task GetWithResult(); + [Get("/get-with-result")] + Task GetWithResult(); - [Put("/put-without-result")] - Task PutWithoutResult(); - } + [Put("/put-without-result")] + Task PutWithoutResult(); + } - [Fact] - public async Task ProvideFactoryWhichAlwaysReturnsNull_WithResult() + [Fact] + public async Task ProvideFactoryWhichAlwaysReturnsNull_WithResult() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() - { - HttpMessageHandlerFactory = () => handler, - ExceptionFactory = _ => Task.FromResult(null) - }; + HttpMessageHandlerFactory = () => handler, + ExceptionFactory = _ => Task.FromResult(null) + }; - handler - .Expect(HttpMethod.Get, "http://api/get-with-result") - .Respond(HttpStatusCode.NotFound, new StringContent("error-result")); + handler + .Expect(HttpMethod.Get, "http://api/get-with-result") + .Respond(HttpStatusCode.NotFound, new StringContent("error-result")); - var fixture = RestService.For("http://api", settings); + var fixture = RestService.For("http://api", settings); - var result = await fixture.GetWithResult(); + var result = await fixture.GetWithResult(); - handler.VerifyNoOutstandingExpectation(); + handler.VerifyNoOutstandingExpectation(); - Assert.Equal("error-result", result); - } + Assert.Equal("error-result", result); + } - [Fact] - public async Task ProvideFactoryWhichAlwaysReturnsNull_WithoutResult() + [Fact] + public async Task ProvideFactoryWhichAlwaysReturnsNull_WithoutResult() + { + var handler = new MockHttpMessageHandler(); + var settings = new RefitSettings() { - var handler = new MockHttpMessageHandler(); - var settings = new RefitSettings() - { - HttpMessageHandlerFactory = () => handler, - ExceptionFactory = _ => Task.FromResult(null) - }; + HttpMessageHandlerFactory = () => handler, + ExceptionFactory = _ => Task.FromResult(null) + }; - handler - .Expect(HttpMethod.Put, "http://api/put-without-result") - .Respond(HttpStatusCode.NotFound); + handler + .Expect(HttpMethod.Put, "http://api/put-without-result") + .Respond(HttpStatusCode.NotFound); - var fixture = RestService.For("http://api", settings); + var fixture = RestService.For("http://api", settings); - await fixture.PutWithoutResult(); + await fixture.PutWithoutResult(); - handler.VerifyNoOutstandingExpectation(); - } + handler.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task ProvideFactoryWhichAlwaysReturnsException_WithResult() + [Fact] + public async Task ProvideFactoryWhichAlwaysReturnsException_WithResult() + { + var handler = new MockHttpMessageHandler(); + var exception = new Exception("I like to fail"); + var settings = new RefitSettings() { - var handler = new MockHttpMessageHandler(); - var exception = new Exception("I like to fail"); - var settings = new RefitSettings() - { - HttpMessageHandlerFactory = () => handler, - ExceptionFactory = _ => Task.FromResult(exception) - }; - - handler - .Expect(HttpMethod.Get, "http://api/get-with-result") - .Respond(HttpStatusCode.OK, new StringContent("success-result")); - - var fixture = RestService.For("http://api", settings); - - var thrownException = await Assert.ThrowsAsync( - () => fixture.GetWithResult() - ); - Assert.Equal(exception, thrownException); - - handler.VerifyNoOutstandingExpectation(); - } - - [Fact] - public async Task ProvideFactoryWhichAlwaysReturnsException_WithoutResult() + HttpMessageHandlerFactory = () => handler, + ExceptionFactory = _ => Task.FromResult(exception) + }; + + handler + .Expect(HttpMethod.Get, "http://api/get-with-result") + .Respond(HttpStatusCode.OK, new StringContent("success-result")); + + var fixture = RestService.For("http://api", settings); + + var thrownException = await Assert.ThrowsAsync( + () => fixture.GetWithResult() + ); + Assert.Equal(exception, thrownException); + + handler.VerifyNoOutstandingExpectation(); + } + + [Fact] + public async Task ProvideFactoryWhichAlwaysReturnsException_WithoutResult() + { + var handler = new MockHttpMessageHandler(); + var exception = new Exception("I like to fail"); + var settings = new RefitSettings() { - var handler = new MockHttpMessageHandler(); - var exception = new Exception("I like to fail"); - var settings = new RefitSettings() - { - HttpMessageHandlerFactory = () => handler, - ExceptionFactory = _ => Task.FromResult(exception) - }; - - handler - .Expect(HttpMethod.Put, "http://api/put-without-result") - .Respond(HttpStatusCode.OK); - - var fixture = RestService.For("http://api", settings); - - var thrownException = await Assert.ThrowsAsync( - () => fixture.PutWithoutResult() - ); - Assert.Equal(exception, thrownException); - - handler.VerifyNoOutstandingExpectation(); - } + HttpMessageHandlerFactory = () => handler, + ExceptionFactory = _ => Task.FromResult(exception) + }; + + handler + .Expect(HttpMethod.Put, "http://api/put-without-result") + .Respond(HttpStatusCode.OK); + + var fixture = RestService.For("http://api", settings); + + var thrownException = await Assert.ThrowsAsync( + () => fixture.PutWithoutResult() + ); + Assert.Equal(exception, thrownException); + + handler.VerifyNoOutstandingExpectation(); } } diff --git a/Refit.Tests/FormValueMultimapTests.cs b/Refit.Tests/FormValueMultimapTests.cs index 7f829b95c..30ead5998 100644 --- a/Refit.Tests/FormValueMultimapTests.cs +++ b/Refit.Tests/FormValueMultimapTests.cs @@ -7,300 +7,299 @@ using Xunit; -namespace Refit.Tests +namespace Refit.Tests; + +public class FormValueMultimapTests { - public class FormValueMultimapTests - { - readonly RefitSettings settings = new(); + readonly RefitSettings settings = new(); - [Fact] - public void EmptyIfNullPassedIn() - { - var target = new FormValueMultimap(null, settings); - Assert.Empty(target); - } + [Fact] + public void EmptyIfNullPassedIn() + { + var target = new FormValueMultimap(null, settings); + Assert.Empty(target); + } - [Fact] - public void LoadsFromDictionary() - { - var source = new Dictionary { { "foo", "bar" }, { "xyz", "123" } }; + [Fact] + public void LoadsFromDictionary() + { + var source = new Dictionary { { "foo", "bar" }, { "xyz", "123" } }; - var target = new FormValueMultimap(source, settings); + var target = new FormValueMultimap(source, settings); - Assert.Equal(source, target); - } + Assert.Equal(source, target); + } - [Fact] - public void LoadsFromObject() - { - var source = new ObjectTestClass { A = "1", B = "2" }; - var expected = new Dictionary { { "A", "1" }, { "B", "2" }, }; + [Fact] + public void LoadsFromObject() + { + var source = new ObjectTestClass { A = "1", B = "2" }; + var expected = new Dictionary { { "A", "1" }, { "B", "2" }, }; - var actual = new FormValueMultimap(source, settings); + var actual = new FormValueMultimap(source, settings); - Assert.Equal(expected, actual); - } + Assert.Equal(expected, actual); + } - [Fact] - public void LoadFromObjectWithCollections() + [Fact] + public void LoadFromObjectWithCollections() + { + var source = new ObjectWithRepeatedFieldsTestClass { - var source = new ObjectWithRepeatedFieldsTestClass - { - A = new List { 1, 2 }, - B = new HashSet { "set1", "set2" }, - C = new HashSet { 1, 2 }, - D = new List { 0.1, 1.0 }, - E = new List { true, false } - }; - var expected = new List> - { - new KeyValuePair("A", "01"), - new KeyValuePair("A", "02"), - new KeyValuePair("B", "set1,set2"), - new KeyValuePair("C", "01 02"), - new KeyValuePair("D", "0.10\t1.00"), - // The default behavior is to capitalize booleans. This is not a requirement. - new KeyValuePair("E", "True|False") - }; - - var actual = new FormValueMultimap(source, settings); - - Assert.Equal(expected, actual); - } - - [Fact] - public void DefaultCollectionFormatCanBeSpecifiedInSettings_Multi() + A = new List { 1, 2 }, + B = new HashSet { "set1", "set2" }, + C = new HashSet { 1, 2 }, + D = new List { 0.1, 1.0 }, + E = new List { true, false } + }; + var expected = new List> { - var settingsWithCollectionFormat = new RefitSettings - { - CollectionFormat = CollectionFormat.Multi - }; - var source = new ObjectWithRepeatedFieldsTestClass - { - // Members have explicit CollectionFormat - A = new List { 1, 2 }, - B = new HashSet { "set1", "set2" }, - C = new HashSet { 1, 2 }, - D = new List { 0.1, 1.0 }, - E = new List { true, false }, - // Member has no explicit CollectionFormat - F = new[] { 1, 2, 3 } - }; - var expected = new List> - { - new KeyValuePair("A", "01"), - new KeyValuePair("A", "02"), - new KeyValuePair("B", "set1,set2"), - new KeyValuePair("C", "01 02"), - new KeyValuePair("D", "0.10\t1.00"), - new KeyValuePair("E", "True|False"), - new KeyValuePair("F", "1"), - new KeyValuePair("F", "2"), - new KeyValuePair("F", "3"), - }; - - var actual = new FormValueMultimap(source, settingsWithCollectionFormat); - - Assert.Equal(expected, actual); - } - - [Theory] - [InlineData(CollectionFormat.Csv, "1,2,3")] - [InlineData(CollectionFormat.Pipes, "1|2|3")] - [InlineData(CollectionFormat.Ssv, "1 2 3")] - [InlineData(CollectionFormat.Tsv, "1\t2\t3")] - public void DefaultCollectionFormatCanBeSpecifiedInSettings( - CollectionFormat format, - string expectedFormat - ) + new KeyValuePair("A", "01"), + new KeyValuePair("A", "02"), + new KeyValuePair("B", "set1,set2"), + new KeyValuePair("C", "01 02"), + new KeyValuePair("D", "0.10\t1.00"), + // The default behavior is to capitalize booleans. This is not a requirement. + new KeyValuePair("E", "True|False") + }; + + var actual = new FormValueMultimap(source, settings); + + Assert.Equal(expected, actual); + } + + [Fact] + public void DefaultCollectionFormatCanBeSpecifiedInSettings_Multi() + { + var settingsWithCollectionFormat = new RefitSettings { - var settingsWithCollectionFormat = new RefitSettings { CollectionFormat = format }; - var source = new ObjectWithRepeatedFieldsTestClass - { - // Members have explicit CollectionFormat - A = new List { 1, 2 }, - B = new HashSet { "set1", "set2" }, - C = new HashSet { 1, 2 }, - D = new List { 0.1, 1.0 }, - E = new List { true, false }, - // Member has no explicit CollectionFormat - F = new[] { 1, 2, 3 } - }; - var expected = new List> - { - new KeyValuePair("A", "01"), - new KeyValuePair("A", "02"), - new KeyValuePair("B", "set1,set2"), - new KeyValuePair("C", "01 02"), - new KeyValuePair("D", "0.10\t1.00"), - new KeyValuePair("E", "True|False"), - new KeyValuePair("F", expectedFormat), - }; - - var actual = new FormValueMultimap(source, settingsWithCollectionFormat); - - Assert.Equal(expected, actual); - } - - public class ObjectTestClass + CollectionFormat = CollectionFormat.Multi + }; + var source = new ObjectWithRepeatedFieldsTestClass { - public string A { get; set; } - public string B { get; set; } - public string C { get; set; } - } + // Members have explicit CollectionFormat + A = new List { 1, 2 }, + B = new HashSet { "set1", "set2" }, + C = new HashSet { 1, 2 }, + D = new List { 0.1, 1.0 }, + E = new List { true, false }, + // Member has no explicit CollectionFormat + F = new[] { 1, 2, 3 } + }; + var expected = new List> + { + new KeyValuePair("A", "01"), + new KeyValuePair("A", "02"), + new KeyValuePair("B", "set1,set2"), + new KeyValuePair("C", "01 02"), + new KeyValuePair("D", "0.10\t1.00"), + new KeyValuePair("E", "True|False"), + new KeyValuePair("F", "1"), + new KeyValuePair("F", "2"), + new KeyValuePair("F", "3"), + }; + + var actual = new FormValueMultimap(source, settingsWithCollectionFormat); + + Assert.Equal(expected, actual); + } - public class ObjectWithRepeatedFieldsTestClass + [Theory] + [InlineData(CollectionFormat.Csv, "1,2,3")] + [InlineData(CollectionFormat.Pipes, "1|2|3")] + [InlineData(CollectionFormat.Ssv, "1 2 3")] + [InlineData(CollectionFormat.Tsv, "1\t2\t3")] + public void DefaultCollectionFormatCanBeSpecifiedInSettings( + CollectionFormat format, + string expectedFormat + ) + { + var settingsWithCollectionFormat = new RefitSettings { CollectionFormat = format }; + var source = new ObjectWithRepeatedFieldsTestClass + { + // Members have explicit CollectionFormat + A = new List { 1, 2 }, + B = new HashSet { "set1", "set2" }, + C = new HashSet { 1, 2 }, + D = new List { 0.1, 1.0 }, + E = new List { true, false }, + // Member has no explicit CollectionFormat + F = new[] { 1, 2, 3 } + }; + var expected = new List> { - [Query(CollectionFormat.Multi, Format = "00")] - public IList A { get; set; } + new KeyValuePair("A", "01"), + new KeyValuePair("A", "02"), + new KeyValuePair("B", "set1,set2"), + new KeyValuePair("C", "01 02"), + new KeyValuePair("D", "0.10\t1.00"), + new KeyValuePair("E", "True|False"), + new KeyValuePair("F", expectedFormat), + }; + + var actual = new FormValueMultimap(source, settingsWithCollectionFormat); + + Assert.Equal(expected, actual); + } - [Query(CollectionFormat.Csv)] - public ISet B { get; set; } + public class ObjectTestClass + { + public string A { get; set; } + public string B { get; set; } + public string C { get; set; } + } - [Query(CollectionFormat.Ssv, Format = "00")] - public HashSet C { get; set; } + public class ObjectWithRepeatedFieldsTestClass + { + [Query(CollectionFormat.Multi, Format = "00")] + public IList A { get; set; } - [Query(CollectionFormat.Tsv, Format = "0.00")] - public IList D { get; set; } + [Query(CollectionFormat.Csv)] + public ISet B { get; set; } - [Query(CollectionFormat.Pipes)] - public IList E { get; set; } + [Query(CollectionFormat.Ssv, Format = "00")] + public HashSet C { get; set; } - [Query] - public int[] F { get; set; } - } + [Query(CollectionFormat.Tsv, Format = "0.00")] + public IList D { get; set; } - [Fact] - public void ExcludesPropertiesWithInaccessibleGetters() - { - var source = new ClassWithInaccessibleGetters { A = "Foo", B = "Bar" }; - var expected = new Dictionary { { "C", "FooBar" } }; + [Query(CollectionFormat.Pipes)] + public IList E { get; set; } - var actual = new FormValueMultimap(source, settings); + [Query] + public int[] F { get; set; } + } - Assert.Equal(expected, actual); - } + [Fact] + public void ExcludesPropertiesWithInaccessibleGetters() + { + var source = new ClassWithInaccessibleGetters { A = "Foo", B = "Bar" }; + var expected = new Dictionary { { "C", "FooBar" } }; - public class ClassWithInaccessibleGetters - { - public string A { internal get; set; } - public string B { private get; set; } - public string C => A + B; - } + var actual = new FormValueMultimap(source, settings); - [Fact] - public void LoadsFromAnonymousType() - { - var source = new { foo = "bar", xyz = 123 }; + Assert.Equal(expected, actual); + } - var expected = new Dictionary { { "foo", "bar" }, { "xyz", "123" } }; + public class ClassWithInaccessibleGetters + { + public string A { internal get; set; } + public string B { private get; set; } + public string C => A + B; + } - var actual = new FormValueMultimap(source, settings); + [Fact] + public void LoadsFromAnonymousType() + { + var source = new { foo = "bar", xyz = 123 }; - Assert.Equal(expected, actual); - } + var expected = new Dictionary { { "foo", "bar" }, { "xyz", "123" } }; - [Fact] - public void UsesAliasAsAttribute() - { - var source = new AliasingTestClass { Foo = "abc" }; + var actual = new FormValueMultimap(source, settings); - var target = new FormValueMultimap(source, settings); + Assert.Equal(expected, actual); + } - Assert.DoesNotContain("Foo", target.Keys); - Assert.Contains("f", target.Keys); - Assert.Equal("abc", target.FirstOrDefault(entry => entry.Key == "f").Value); - } + [Fact] + public void UsesAliasAsAttribute() + { + var source = new AliasingTestClass { Foo = "abc" }; - [Fact] - public void UsesJsonPropertyAttribute() - { - var source = new AliasingTestClass { Bar = "xyz" }; + var target = new FormValueMultimap(source, settings); - var target = new FormValueMultimap(source, settings); + Assert.DoesNotContain("Foo", target.Keys); + Assert.Contains("f", target.Keys); + Assert.Equal("abc", target.FirstOrDefault(entry => entry.Key == "f").Value); + } - Assert.DoesNotContain("Bar", target.Keys); - Assert.Contains("b", target.Keys); - Assert.Equal("xyz", target.FirstOrDefault(entry => entry.Key == "b").Value); - } + [Fact] + public void UsesJsonPropertyAttribute() + { + var source = new AliasingTestClass { Bar = "xyz" }; - [Fact] - public void UsesQueryPropertyAttribute() - { - var source = new AliasingTestClass { Frob = 4 }; + var target = new FormValueMultimap(source, settings); - var target = new FormValueMultimap(source, settings); + Assert.DoesNotContain("Bar", target.Keys); + Assert.Contains("b", target.Keys); + Assert.Equal("xyz", target.FirstOrDefault(entry => entry.Key == "b").Value); + } - Assert.DoesNotContain("Bar", target.Keys); - Assert.Contains("prefix-fr", target.Keys); - Assert.Equal("4.0", target.FirstOrDefault(entry => entry.Key == "prefix-fr").Value); - } + [Fact] + public void UsesQueryPropertyAttribute() + { + var source = new AliasingTestClass { Frob = 4 }; - [Fact] - public void GivesPrecedenceToAliasAs() - { - var source = new AliasingTestClass { Baz = "123" }; + var target = new FormValueMultimap(source, settings); + + Assert.DoesNotContain("Bar", target.Keys); + Assert.Contains("prefix-fr", target.Keys); + Assert.Equal("4.0", target.FirstOrDefault(entry => entry.Key == "prefix-fr").Value); + } - var target = new FormValueMultimap(source, settings); + [Fact] + public void GivesPrecedenceToAliasAs() + { + var source = new AliasingTestClass { Baz = "123" }; - Assert.DoesNotContain("Bar", target.Keys); - Assert.DoesNotContain("z", target.Keys); - Assert.Contains("a", target.Keys); - Assert.Equal("123", target.FirstOrDefault(entry => entry.Key == "a").Value); - } + var target = new FormValueMultimap(source, settings); - [Fact] - public void SkipsNullValuesFromDictionary() - { - var source = new Dictionary { { "foo", "bar" }, { "xyz", null } }; + Assert.DoesNotContain("Bar", target.Keys); + Assert.DoesNotContain("z", target.Keys); + Assert.Contains("a", target.Keys); + Assert.Equal("123", target.FirstOrDefault(entry => entry.Key == "a").Value); + } - var target = new FormValueMultimap(source, settings); + [Fact] + public void SkipsNullValuesFromDictionary() + { + var source = new Dictionary { { "foo", "bar" }, { "xyz", null } }; + + var target = new FormValueMultimap(source, settings); - Assert.Single(target); - Assert.Contains("foo", target.Keys); - } + Assert.Single(target); + Assert.Contains("foo", target.Keys); + } - [Fact] - public void SerializesEnumWithEnumMemberAttribute() + [Fact] + public void SerializesEnumWithEnumMemberAttribute() + { + var source = new Dictionary() { - var source = new Dictionary() - { - { "A", EnumWithEnumMember.A }, - { "B", EnumWithEnumMember.B } - }; + { "A", EnumWithEnumMember.A }, + { "B", EnumWithEnumMember.B } + }; - var expected = new Dictionary { { "A", "A" }, { "B", "b" } }; + var expected = new Dictionary { { "A", "A" }, { "B", "b" } }; - var actual = new FormValueMultimap(source, settings); + var actual = new FormValueMultimap(source, settings); - Assert.Equal(expected, actual); - } + Assert.Equal(expected, actual); + } - public class AliasingTestClass - { - [AliasAs("f")] - public string Foo { get; set; } + public class AliasingTestClass + { + [AliasAs("f")] + public string Foo { get; set; } - [JsonProperty(PropertyName = "b")] - [JsonPropertyName("b")] - public string Bar { get; set; } + [JsonProperty(PropertyName = "b")] + [JsonPropertyName("b")] + public string Bar { get; set; } - [AliasAs("a")] - [JsonProperty(PropertyName = "z")] - [JsonPropertyName("z")] - public string Baz { get; set; } + [AliasAs("a")] + [JsonProperty(PropertyName = "z")] + [JsonPropertyName("z")] + public string Baz { get; set; } - [Query("-", "prefix", "0.0")] - [AliasAs("fr")] - public int? Frob { get; set; } - } + [Query("-", "prefix", "0.0")] + [AliasAs("fr")] + public int? Frob { get; set; } + } - public enum EnumWithEnumMember - { - A, + public enum EnumWithEnumMember + { + A, - [EnumMember(Value = "b")] - B - } + [EnumMember(Value = "b")] + B } } diff --git a/Refit.Tests/GitHubApi.cs b/Refit.Tests/GitHubApi.cs index 60fbbb7a6..2b739c157 100644 --- a/Refit.Tests/GitHubApi.cs +++ b/Refit.Tests/GitHubApi.cs @@ -9,50 +9,104 @@ using static System.Math; // This is here to verify https://github.com/reactiveui/refit/issues/283 -namespace Refit.Tests +namespace Refit.Tests; + +public record User { - public record User - { - public string Login { get; set; } - public int Id { get; set; } - public string AvatarUrl { get; set; } - public string GravatarId { get; set; } - public string Url { get; set; } - public string HtmlUrl { get; set; } - public string FollowersUrl { get; set; } - public string FollowingUrl { get; set; } - public string GistsUrl { get; set; } - public string StarredUrl { get; set; } - public string SubscriptionsUrl { get; set; } - public string OrganizationsUrl { get; set; } - public string ReposUrl { get; set; } - public string EventsUrl { get; set; } - public string ReceivedEventsUrl { get; set; } - public string Type { get; set; } - public string Name { get; set; } - public string Company { get; set; } - public string Blog { get; set; } - public string Location { get; set; } - public string Email { get; set; } - public bool? Hireable { get; set; } - public string Bio { get; set; } - public int PublicRepos { get; set; } - public int Followers { get; set; } - public int Following { get; set; } - public string CreatedAt { get; set; } - public string UpdatedAt { get; set; } - public int PublicGists { get; set; } - } + public string Login { get; set; } + public int Id { get; set; } + public string AvatarUrl { get; set; } + public string GravatarId { get; set; } + public string Url { get; set; } + public string HtmlUrl { get; set; } + public string FollowersUrl { get; set; } + public string FollowingUrl { get; set; } + public string GistsUrl { get; set; } + public string StarredUrl { get; set; } + public string SubscriptionsUrl { get; set; } + public string OrganizationsUrl { get; set; } + public string ReposUrl { get; set; } + public string EventsUrl { get; set; } + public string ReceivedEventsUrl { get; set; } + public string Type { get; set; } + public string Name { get; set; } + public string Company { get; set; } + public string Blog { get; set; } + public string Location { get; set; } + public string Email { get; set; } + public bool? Hireable { get; set; } + public string Bio { get; set; } + public int PublicRepos { get; set; } + public int Followers { get; set; } + public int Following { get; set; } + public string CreatedAt { get; set; } + public string UpdatedAt { get; set; } + public int PublicGists { get; set; } +} - public class UserSearchResult - { - public int TotalCount { get; set; } - public bool IncompleteResults { get; set; } - public IList Items { get; set; } - } +public class UserSearchResult +{ + public int TotalCount { get; set; } + public bool IncompleteResults { get; set; } + public IList Items { get; set; } +} + +[Headers("User-Agent: Refit Integration Tests")] +public interface IGitHubApi +{ + [Get("/users/{username}")] + Task GetUser(string userName); + + [Get("/users/{username}")] + IObservable GetUserObservable(string userName); + + [Get("/users/{userName}")] + IObservable GetUserCamelCase(string userName); + + [Get("/orgs/{orgname}/members")] + Task> GetOrgMembers( + string orgName, + CancellationToken cancellationToken = default + ); + + [Get("/search/users")] + Task FindUsers(string q); + + [Get("/")] + Task GetIndex(); + + [Get("/")] + IObservable GetIndexObservable(); + + [Get("/give-me-some-404-action")] + Task NothingToSeeHere(); + + [Get("/give-me-some-404-action")] + Task> NothingToSeeHereWithMetadata(); + + [Get("/users/{username}")] + Task> GetUserWithMetadata(string userName); + + [Get("/users/{username}")] + IObservable> GetUserObservableWithMetadata(string userName); + + [Post("/users")] + Task CreateUser(User user); + + [Post("/users")] + Task> CreateUserWithMetadata(User user); +} + +public interface IGitHubApiDisposable : IDisposable +{ + [Get("whatever")] + Task RefitMethod(); +} +public class TestNested +{ [Headers("User-Agent: Refit Integration Tests")] - public interface IGitHubApi + public interface INestedGitHubApi { [Get("/users/{username}")] Task GetUser(string userName); @@ -64,10 +118,7 @@ public interface IGitHubApi IObservable GetUserCamelCase(string userName); [Get("/orgs/{orgname}/members")] - Task> GetOrgMembers( - string orgName, - CancellationToken cancellationToken = default - ); + Task> GetOrgMembers(string orgName); [Get("/search/users")] Task FindUsers(string q); @@ -79,58 +130,6 @@ Task> GetOrgMembers( IObservable GetIndexObservable(); [Get("/give-me-some-404-action")] - Task NothingToSeeHere(); - - [Get("/give-me-some-404-action")] - Task> NothingToSeeHereWithMetadata(); - - [Get("/users/{username}")] - Task> GetUserWithMetadata(string userName); - - [Get("/users/{username}")] - IObservable> GetUserObservableWithMetadata(string userName); - - [Post("/users")] - Task CreateUser(User user); - - [Post("/users")] - Task> CreateUserWithMetadata(User user); - } - - public interface IGitHubApiDisposable : IDisposable - { - [Get("whatever")] - Task RefitMethod(); - } - - public class TestNested - { - [Headers("User-Agent: Refit Integration Tests")] - public interface INestedGitHubApi - { - [Get("/users/{username}")] - Task GetUser(string userName); - - [Get("/users/{username}")] - IObservable GetUserObservable(string userName); - - [Get("/users/{userName}")] - IObservable GetUserCamelCase(string userName); - - [Get("/orgs/{orgname}/members")] - Task> GetOrgMembers(string orgName); - - [Get("/search/users")] - Task FindUsers(string q); - - [Get("/")] - Task GetIndex(); - - [Get("/")] - IObservable GetIndexObservable(); - - [Get("/give-me-some-404-action")] - Task NothingToSeeHere(); - } + Task NothingToSeeHere(); } } diff --git a/Refit.Tests/HttpClientFactoryExtensionsTests.cs b/Refit.Tests/HttpClientFactoryExtensionsTests.cs index 3113e66d5..9dc666e5d 100644 --- a/Refit.Tests/HttpClientFactoryExtensionsTests.cs +++ b/Refit.Tests/HttpClientFactoryExtensionsTests.cs @@ -1,167 +1,166 @@ using Microsoft.Extensions.Options; -namespace Refit.Tests +namespace Refit.Tests; + +using Microsoft.Extensions.DependencyInjection; + +using System.Text.Json; +using Xunit; + +public class HttpClientFactoryExtensionsTests { - using Microsoft.Extensions.DependencyInjection; + class User { } + + class Role { } + + [Fact] + public void GenericHttpClientsAreAssignedUniqueNames() + { + var services = new ServiceCollection(); + + var userClientName = services.AddRefitClient>().Name; + var roleClientName = services.AddRefitClient>().Name; + + Assert.NotEqual(userClientName, roleClientName); + } + + [Fact] + public void HttpClientServicesAreAddedCorrectlyGivenGenericArgument() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddRefitClient(); + Assert.Contains( + serviceCollection, + z => z.ServiceType == typeof(SettingsFor) + ); + Assert.Contains( + serviceCollection, + z => z.ServiceType == typeof(IRequestBuilder) + ); + } + + [Fact] + public void HttpClientServicesAreAddedCorrectlyGivenTypeArgument() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddRefitClient(typeof(IFooWithOtherAttribute)); + Assert.Contains( + serviceCollection, + z => z.ServiceType == typeof(SettingsFor) + ); + Assert.Contains( + serviceCollection, + z => z.ServiceType == typeof(IRequestBuilder) + ); + } + + [Fact] + public void HttpClientReturnsClientGivenGenericArgument() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddRefitClient(); + var serviceProvider = serviceCollection.BuildServiceProvider(); + Assert.NotNull(serviceProvider.GetService()); + } + + [Fact] + public void HttpClientReturnsClientGivenTypeArgument() + { + var serviceCollection = new ServiceCollection(); + serviceCollection.AddRefitClient(typeof(IFooWithOtherAttribute)); + var serviceProvider = serviceCollection.BuildServiceProvider(); + Assert.NotNull(serviceProvider.GetService()); + } + + [Fact] + public void HttpClientSettingsAreInjectableGivenGenericArgument() + { + var serviceCollection = new ServiceCollection().Configure( + o => o.Serializer = new SystemTextJsonContentSerializer(new JsonSerializerOptions()) + ); + serviceCollection.AddRefitClient( + _ => + new RefitSettings() + { + ContentSerializer = _.GetRequiredService< + IOptions + >().Value.Serializer + } + ); + var serviceProvider = serviceCollection.BuildServiceProvider(); + Assert.Same( + serviceProvider.GetRequiredService>().Value.Serializer, + serviceProvider + .GetRequiredService>() + .Settings!.ContentSerializer + ); + } - using System.Text.Json; - using Xunit; + [Fact] + public void HttpClientSettingsAreInjectableGivenTypeArgument() + { + var serviceCollection = new ServiceCollection().Configure( + o => o.Serializer = new SystemTextJsonContentSerializer(new JsonSerializerOptions()) + ); + serviceCollection.AddRefitClient( + typeof(IFooWithOtherAttribute), + _ => + new RefitSettings() + { + ContentSerializer = _.GetRequiredService< + IOptions + >().Value.Serializer + } + ); + var serviceProvider = serviceCollection.BuildServiceProvider(); + Assert.Same( + serviceProvider.GetRequiredService>().Value.Serializer, + serviceProvider + .GetRequiredService>() + .Settings!.ContentSerializer + ); + } + + [Fact] + public void HttpClientSettingsCanBeProvidedStaticallyGivenGenericArgument() + { + var contentSerializer = new SystemTextJsonContentSerializer( + new JsonSerializerOptions() + ); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddRefitClient( + new RefitSettings() { ContentSerializer = contentSerializer } + ); + var serviceProvider = serviceCollection.BuildServiceProvider(); + Assert.Same( + contentSerializer, + serviceProvider + .GetRequiredService>() + .Settings!.ContentSerializer + ); + } + + [Fact] + public void HttpClientSettingsCanBeProvidedStaticallyGivenTypeArgument() + { + var contentSerializer = new SystemTextJsonContentSerializer( + new JsonSerializerOptions() + ); + var serviceCollection = new ServiceCollection(); + serviceCollection.AddRefitClient( + new RefitSettings() { ContentSerializer = contentSerializer } + ); + var serviceProvider = serviceCollection.BuildServiceProvider(); + Assert.Same( + contentSerializer, + serviceProvider + .GetRequiredService>() + .Settings!.ContentSerializer + ); + } - public class HttpClientFactoryExtensionsTests + class ClientOptions { - class User { } - - class Role { } - - [Fact] - public void GenericHttpClientsAreAssignedUniqueNames() - { - var services = new ServiceCollection(); - - var userClientName = services.AddRefitClient>().Name; - var roleClientName = services.AddRefitClient>().Name; - - Assert.NotEqual(userClientName, roleClientName); - } - - [Fact] - public void HttpClientServicesAreAddedCorrectlyGivenGenericArgument() - { - var serviceCollection = new ServiceCollection(); - serviceCollection.AddRefitClient(); - Assert.Contains( - serviceCollection, - z => z.ServiceType == typeof(SettingsFor) - ); - Assert.Contains( - serviceCollection, - z => z.ServiceType == typeof(IRequestBuilder) - ); - } - - [Fact] - public void HttpClientServicesAreAddedCorrectlyGivenTypeArgument() - { - var serviceCollection = new ServiceCollection(); - serviceCollection.AddRefitClient(typeof(IFooWithOtherAttribute)); - Assert.Contains( - serviceCollection, - z => z.ServiceType == typeof(SettingsFor) - ); - Assert.Contains( - serviceCollection, - z => z.ServiceType == typeof(IRequestBuilder) - ); - } - - [Fact] - public void HttpClientReturnsClientGivenGenericArgument() - { - var serviceCollection = new ServiceCollection(); - serviceCollection.AddRefitClient(); - var serviceProvider = serviceCollection.BuildServiceProvider(); - Assert.NotNull(serviceProvider.GetService()); - } - - [Fact] - public void HttpClientReturnsClientGivenTypeArgument() - { - var serviceCollection = new ServiceCollection(); - serviceCollection.AddRefitClient(typeof(IFooWithOtherAttribute)); - var serviceProvider = serviceCollection.BuildServiceProvider(); - Assert.NotNull(serviceProvider.GetService()); - } - - [Fact] - public void HttpClientSettingsAreInjectableGivenGenericArgument() - { - var serviceCollection = new ServiceCollection().Configure( - o => o.Serializer = new SystemTextJsonContentSerializer(new JsonSerializerOptions()) - ); - serviceCollection.AddRefitClient( - _ => - new RefitSettings() - { - ContentSerializer = _.GetRequiredService< - IOptions - >().Value.Serializer - } - ); - var serviceProvider = serviceCollection.BuildServiceProvider(); - Assert.Same( - serviceProvider.GetRequiredService>().Value.Serializer, - serviceProvider - .GetRequiredService>() - .Settings!.ContentSerializer - ); - } - - [Fact] - public void HttpClientSettingsAreInjectableGivenTypeArgument() - { - var serviceCollection = new ServiceCollection().Configure( - o => o.Serializer = new SystemTextJsonContentSerializer(new JsonSerializerOptions()) - ); - serviceCollection.AddRefitClient( - typeof(IFooWithOtherAttribute), - _ => - new RefitSettings() - { - ContentSerializer = _.GetRequiredService< - IOptions - >().Value.Serializer - } - ); - var serviceProvider = serviceCollection.BuildServiceProvider(); - Assert.Same( - serviceProvider.GetRequiredService>().Value.Serializer, - serviceProvider - .GetRequiredService>() - .Settings!.ContentSerializer - ); - } - - [Fact] - public void HttpClientSettingsCanBeProvidedStaticallyGivenGenericArgument() - { - var contentSerializer = new SystemTextJsonContentSerializer( - new JsonSerializerOptions() - ); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddRefitClient( - new RefitSettings() { ContentSerializer = contentSerializer } - ); - var serviceProvider = serviceCollection.BuildServiceProvider(); - Assert.Same( - contentSerializer, - serviceProvider - .GetRequiredService>() - .Settings!.ContentSerializer - ); - } - - [Fact] - public void HttpClientSettingsCanBeProvidedStaticallyGivenTypeArgument() - { - var contentSerializer = new SystemTextJsonContentSerializer( - new JsonSerializerOptions() - ); - var serviceCollection = new ServiceCollection(); - serviceCollection.AddRefitClient( - new RefitSettings() { ContentSerializer = contentSerializer } - ); - var serviceProvider = serviceCollection.BuildServiceProvider(); - Assert.Same( - contentSerializer, - serviceProvider - .GetRequiredService>() - .Settings!.ContentSerializer - ); - } - - class ClientOptions - { - public SystemTextJsonContentSerializer Serializer { get; set; } - } + public SystemTextJsonContentSerializer Serializer { get; set; } } } diff --git a/Refit.Tests/IDefaultInterfaceMethodTests.cs b/Refit.Tests/IDefaultInterfaceMethodTests.cs index 25dce0d71..1112d53e2 100644 --- a/Refit.Tests/IDefaultInterfaceMethodTests.cs +++ b/Refit.Tests/IDefaultInterfaceMethodTests.cs @@ -10,94 +10,93 @@ using Xunit; -namespace Refit.Tests +namespace Refit.Tests; + +public interface IHaveDims { - public interface IHaveDims - { - [Get("")] - internal Task GetInternal(); + [Get("")] + internal Task GetInternal(); - // DIMs require C# 8.0 which requires .NET Core 3.x or .NET Standard 2.1 + // DIMs require C# 8.0 which requires .NET Core 3.x or .NET Standard 2.1 #if NETCOREAPP3_1_OR_GREATER - private Task GetPrivate() - { - return GetInternal(); - } - - Task GetDim() - { - return GetPrivate(); - } - - static string GetStatic() - { - return nameof(IHaveDims); - } -#endif + private Task GetPrivate() + { + return GetInternal(); } - // DIMs require C# 8.0 which requires .NET Core 3.x or .NET Standard 2.1 + Task GetDim() + { + return GetPrivate(); + } + + static string GetStatic() + { + return nameof(IHaveDims); + } +#endif +} + +// DIMs require C# 8.0 which requires .NET Core 3.x or .NET Standard 2.1 #if NETCOREAPP3_1_OR_GREATER - public class DefaultInterfaceMethodTests +public class DefaultInterfaceMethodTests +{ + [Fact] + public async Task InternalInterfaceMemberTest() { - [Fact] - public async Task InternalInterfaceMemberTest() - { - var mockHttp = new MockHttpMessageHandler(); + var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/") - .Respond(HttpStatusCode.OK, "text/html", "OK"); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/") + .Respond(HttpStatusCode.OK, "text/html", "OK"); - var fixture = RestService.For("https://httpbin.org/", settings); - var plainText = await fixture.GetInternal(); + var fixture = RestService.For("https://httpbin.org/", settings); + var plainText = await fixture.GetInternal(); - Assert.True(!string.IsNullOrWhiteSpace(plainText)); - } + Assert.True(!string.IsNullOrWhiteSpace(plainText)); + } - [Fact] - public async Task DimTest() - { - var mockHttp = new MockHttpMessageHandler(); + [Fact] + public async Task DimTest() + { + var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/") - .Respond(HttpStatusCode.OK, "text/html", "OK"); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/") + .Respond(HttpStatusCode.OK, "text/html", "OK"); - var fixture = RestService.For("https://httpbin.org/", settings); - var plainText = await fixture.GetDim(); + var fixture = RestService.For("https://httpbin.org/", settings); + var plainText = await fixture.GetDim(); - Assert.True(!string.IsNullOrWhiteSpace(plainText)); - } + Assert.True(!string.IsNullOrWhiteSpace(plainText)); + } - [Fact] - public async Task InternalDimTest() - { - var mockHttp = new MockHttpMessageHandler(); + [Fact] + public async Task InternalDimTest() + { + var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/") - .Respond(HttpStatusCode.OK, "text/html", "OK"); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/") + .Respond(HttpStatusCode.OK, "text/html", "OK"); - var fixture = RestService.For("https://httpbin.org/", settings); - var plainText = await fixture.GetInternal(); + var fixture = RestService.For("https://httpbin.org/", settings); + var plainText = await fixture.GetInternal(); - Assert.True(!string.IsNullOrWhiteSpace(plainText)); - } + Assert.True(!string.IsNullOrWhiteSpace(plainText)); + } - [Fact] - public void StaticInterfaceMethodTest() - { - var plainText = IHaveDims.GetStatic(); + [Fact] + public void StaticInterfaceMethodTest() + { + var plainText = IHaveDims.GetStatic(); - Assert.True(!string.IsNullOrWhiteSpace(plainText)); - } + Assert.True(!string.IsNullOrWhiteSpace(plainText)); } -#endif } +#endif diff --git a/Refit.Tests/IInterfaceWithoutRefit.cs b/Refit.Tests/IInterfaceWithoutRefit.cs index d21ab86df..1e8eef2e9 100644 --- a/Refit.Tests/IInterfaceWithoutRefit.cs +++ b/Refit.Tests/IInterfaceWithoutRefit.cs @@ -4,10 +4,9 @@ using System.Text; using System.Threading.Tasks; -namespace Refit.Tests +namespace Refit.Tests; + +public interface IInterfaceWithoutRefit { - public interface IInterfaceWithoutRefit - { - Task DoSomething(); - } + Task DoSomething(); } diff --git a/Refit.Tests/InheritedGenericInterfacesApi.cs b/Refit.Tests/InheritedGenericInterfacesApi.cs index d506d961d..5aea963df 100644 --- a/Refit.Tests/InheritedGenericInterfacesApi.cs +++ b/Refit.Tests/InheritedGenericInterfacesApi.cs @@ -5,74 +5,73 @@ using Refit; // InterfaceStubGenerator looks for this using static System.Math; // This is here to verify https://github.com/reactiveui/refit/issues/283 -namespace Refit.Tests +namespace Refit.Tests; + +public class DataEntity { } + +public interface IDataApiA : IDataCrudApi +{ + [Get("")] + Task PingA(); +} + +public interface IDataApiB : IDataCrudApi +{ + [Get("")] + Task PingB(); +} + +public interface IDataCrudApi : IDataCrudApi + where T : class +{ + [Post("")] + Task Copy([Body] T payload); +} + +public interface IDataCrudApi + where T : class +{ + [Post("")] + Task Create([Body] T payload); + + [Get("")] + Task> ReadAll() + where TFoo : new(); + + [Get("")] + Task> ReadAll() + where TFoo : new() + where TBar : struct; + + [Get("/{key}")] + Task ReadOne(TKey key); + + [Put("/{key}")] + Task Update(TKey key, [Body] T payload); + + [Delete("/{key}")] + Task Delete(TKey key); + + [Get("")] + Task ReadAllClasses() + where TFoo : class, new(); +} + +public class DatasetQueryItem + where TResultRow : class, new() +{ + [JsonProperty("global_id")] + public long GlobalId { get; set; } + + public long Number { get; set; } + + [JsonProperty("Cells")] + public TResultRow Value { get; set; } +} + +public interface IDataMosApi { - public class DataEntity { } - - public interface IDataApiA : IDataCrudApi - { - [Get("")] - Task PingA(); - } - - public interface IDataApiB : IDataCrudApi - { - [Get("")] - Task PingB(); - } - - public interface IDataCrudApi : IDataCrudApi - where T : class - { - [Post("")] - Task Copy([Body] T payload); - } - - public interface IDataCrudApi - where T : class - { - [Post("")] - Task Create([Body] T payload); - - [Get("")] - Task> ReadAll() - where TFoo : new(); - - [Get("")] - Task> ReadAll() - where TFoo : new() - where TBar : struct; - - [Get("/{key}")] - Task ReadOne(TKey key); - - [Put("/{key}")] - Task Update(TKey key, [Body] T payload); - - [Delete("/{key}")] - Task Delete(TKey key); - - [Get("")] - Task ReadAllClasses() - where TFoo : class, new(); - } - - public class DatasetQueryItem - where TResultRow : class, new() - { - [JsonProperty("global_id")] - public long GlobalId { get; set; } - - public long Number { get; set; } - - [JsonProperty("Cells")] - public TResultRow Value { get; set; } - } - - public interface IDataMosApi - { - [Get("/datasets/{dataSet}/rows")] - Task[]> GetDataSetItems() - where TResulRow : class, new(); - } + [Get("/datasets/{dataSet}/rows")] + Task[]> GetDataSetItems() + where TResulRow : class, new(); } diff --git a/Refit.Tests/InheritedInterfacesInSeparateFileApi.cs b/Refit.Tests/InheritedInterfacesInSeparateFileApi.cs index 9a006b559..1e3e95fea 100644 --- a/Refit.Tests/InheritedInterfacesInSeparateFileApi.cs +++ b/Refit.Tests/InheritedInterfacesInSeparateFileApi.cs @@ -2,11 +2,10 @@ using Refit; // InterfaceStubGenerator looks for this -namespace Refit.Tests.SeparateNamespace +namespace Refit.Tests.SeparateNamespace; + +public interface InheritedInterfacesInSeparateFileApi : IAmInterfaceF_RequireUsing { - public interface InheritedInterfacesInSeparateFileApi : IAmInterfaceF_RequireUsing - { - [Get("/get")] - Task Get(int i); - } + [Get("/get")] + Task Get(int i); } diff --git a/Refit.Tests/IntegrationTestHelper.cs b/Refit.Tests/IntegrationTestHelper.cs index d912e9f19..9c7c751b7 100644 --- a/Refit.Tests/IntegrationTestHelper.cs +++ b/Refit.Tests/IntegrationTestHelper.cs @@ -9,26 +9,25 @@ using System.Threading; using System.Threading.Tasks; -namespace Refit.Tests +namespace Refit.Tests; + +public static class IntegrationTestHelper { - public static class IntegrationTestHelper + public static string GetPath(params string[] paths) { - public static string GetPath(params string[] paths) - { - var ret = GetIntegrationTestRootDirectory(); - return (new FileInfo(paths.Aggregate(ret, Path.Combine))).FullName; - } + var ret = GetIntegrationTestRootDirectory(); + return (new FileInfo(paths.Aggregate(ret, Path.Combine))).FullName; + } - public static string GetIntegrationTestRootDirectory( - [CallerFilePath] string filePath = default - ) - { - // XXX: This is an evil hack, but it's okay for a unit test - // We can't use Assembly.Location because unit test runners love - // to move stuff to temp directories - var di = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(filePath))); + public static string GetIntegrationTestRootDirectory( + [CallerFilePath] string filePath = default + ) + { + // XXX: This is an evil hack, but it's okay for a unit test + // We can't use Assembly.Location because unit test runners love + // to move stuff to temp directories + var di = new DirectoryInfo(Path.Combine(Path.GetDirectoryName(filePath))); - return di.FullName; - } + return di.FullName; } } diff --git a/Refit.Tests/InterfaceStubGenerator.cs b/Refit.Tests/InterfaceStubGenerator.cs index ff7dedbf8..25fec2091 100644 --- a/Refit.Tests/InterfaceStubGenerator.cs +++ b/Refit.Tests/InterfaceStubGenerator.cs @@ -18,128 +18,136 @@ using VerifyCS = Refit.Tests.CSharpSourceGeneratorVerifier; using VerifyCSV2 = Refit.Tests.CSharpIncrementalSourceGeneratorVerifier; -namespace Refit.Tests +namespace Refit.Tests; + +public class InterfaceStubGeneratorTests { - public class InterfaceStubGeneratorTests - { - static readonly MetadataReference RefitAssembly = MetadataReference.CreateFromFile( - typeof(GetAttribute).Assembly.Location, - documentation: XmlDocumentationProvider.CreateFromFile( - Path.ChangeExtension(typeof(GetAttribute).Assembly.Location, ".xml") - ) - ); + static readonly MetadataReference RefitAssembly = MetadataReference.CreateFromFile( + typeof(GetAttribute).Assembly.Location, + documentation: XmlDocumentationProvider.CreateFromFile( + Path.ChangeExtension(typeof(GetAttribute).Assembly.Location, ".xml") + ) + ); - static readonly ReferenceAssemblies ReferenceAssemblies; + static readonly ReferenceAssemblies ReferenceAssemblies; - static InterfaceStubGeneratorTests() - { -#if NET5_0 - ReferenceAssemblies = ReferenceAssemblies.Net.Net50; -#elif NET6_0 - ReferenceAssemblies = ReferenceAssemblies.Net.Net60; -#elif NET7_0 - ReferenceAssemblies = ReferenceAssemblies.Net.Net70; + static InterfaceStubGeneratorTests() + { +#if NET6_0 + ReferenceAssemblies = ReferenceAssemblies.Net.Net60; +#elif NET8_0 + ReferenceAssemblies = ReferenceAssemblies.Net.Net80; #else - ReferenceAssemblies = ReferenceAssemblies.Default.AddPackages( - ImmutableArray.Create(new PackageIdentity("System.Text.Json", "7.0.2")) - ); + ReferenceAssemblies = ReferenceAssemblies.Default.AddPackages( + ImmutableArray.Create(new PackageIdentity("System.Text.Json", "7.0.2")) + ); #endif #if NET461 - ReferenceAssemblies = ReferenceAssemblies - .AddAssemblies(ImmutableArray.Create("System.Web")) - .AddPackages( - ImmutableArray.Create(new PackageIdentity("System.Net.Http", "4.3.4")) - ); + ReferenceAssemblies = ReferenceAssemblies + .AddAssemblies(ImmutableArray.Create("System.Web")) + .AddPackages( + ImmutableArray.Create(new PackageIdentity("System.Net.Http", "4.3.4")) + ); #endif - } - - [Fact(Skip = "Generator in test issue")] - public void GenerateInterfaceStubsSmokeTest() - { - var fixture = new InterfaceStubGenerator(); + } - var driver = CSharpGeneratorDriver.Create(fixture); + [Fact(Skip = "Generator in test issue")] + public void GenerateInterfaceStubsSmokeTest() + { + var fixture = new InterfaceStubGenerator(); - var inputCompilation = CreateCompilation( - IntegrationTestHelper.GetPath("RestService.cs"), - IntegrationTestHelper.GetPath("GitHubApi.cs"), - IntegrationTestHelper.GetPath("InheritedInterfacesApi.cs"), - IntegrationTestHelper.GetPath("InheritedGenericInterfacesApi.cs") - ); + var driver = CSharpGeneratorDriver.Create(fixture); - var diags = inputCompilation.GetDiagnostics(); + var inputCompilation = CreateCompilation( + IntegrationTestHelper.GetPath("RestService.cs"), + IntegrationTestHelper.GetPath("GitHubApi.cs"), + IntegrationTestHelper.GetPath("InheritedInterfacesApi.cs"), + IntegrationTestHelper.GetPath("InheritedGenericInterfacesApi.cs") + ); - // Make sure we don't have any errors - Assert.Empty(diags.Where(d => d.Severity == DiagnosticSeverity.Error)); + var diags = inputCompilation.GetDiagnostics(); - var rundriver = driver.RunGeneratorsAndUpdateCompilation( - inputCompilation, - out var outputCompiliation, - out var diagnostics - ); + // Make sure we don't have any errors + Assert.Empty(diags.Where(d => d.Severity == DiagnosticSeverity.Error)); - var runResult = rundriver.GetRunResult(); + var rundriver = driver.RunGeneratorsAndUpdateCompilation( + inputCompilation, + out var outputCompiliation, + out var diagnostics + ); - var generated = runResult.Results[0]; + var runResult = rundriver.GetRunResult(); - var text = generated.GeneratedSources.First().SourceText.ToString(); + var generated = runResult.Results[0]; - Assert.Contains("IGitHubApi", text); - Assert.Contains("IAmInterfaceC", text); - } + var text = generated.GeneratedSources.First().SourceText.ToString(); - static Compilation CreateCompilation(params string[] sourceFiles) - { - var keyReferences = new[] - { - typeof(Binder), - typeof(GetAttribute), - typeof(RichardSzalay.MockHttp.MockHttpMessageHandler), - typeof(System.Reactive.Unit), - typeof(System.Linq.Enumerable), - typeof(Newtonsoft.Json.JsonConvert), - typeof(Xunit.FactAttribute), - typeof(System.Net.Http.HttpContent), - typeof(ModelObject), - typeof(Attribute) - }; - - return CSharpCompilation.Create( - "compilation", - sourceFiles.Select(source => CSharpSyntaxTree.ParseText(File.ReadAllText(source))), - keyReferences.Select(t => MetadataReference.CreateFromFile(t.Assembly.Location)), - new CSharpCompilationOptions(OutputKind.ConsoleApplication) - ); - } + Assert.Contains("IGitHubApi", text); + Assert.Contains("IAmInterfaceC", text); + } - [Fact] - public async Task NoRefitInterfacesSmokeTest() + static CSharpCompilation CreateCompilation(params string[] sourceFiles) + { + var keyReferences = new[] { - var input = File.ReadAllText( - IntegrationTestHelper.GetPath("IInterfaceWithoutRefit.cs") - ); + typeof(Binder), + typeof(GetAttribute), + typeof(RichardSzalay.MockHttp.MockHttpMessageHandler), + typeof(System.Reactive.Unit), + typeof(System.Linq.Enumerable), + typeof(Newtonsoft.Json.JsonConvert), + typeof(Xunit.FactAttribute), + typeof(System.Net.Http.HttpContent), + typeof(ModelObject), + typeof(Attribute) + }; + + return CSharpCompilation.Create( + "compilation", + sourceFiles.Select(source => CSharpSyntaxTree.ParseText(File.ReadAllText(source))), + keyReferences.Select(t => MetadataReference.CreateFromFile(t.Assembly.Location)), + new CSharpCompilationOptions(OutputKind.ConsoleApplication) + ); + } - await new VerifyCS.Test - { - ReferenceAssemblies = ReferenceAssemblies, - TestState = { AdditionalReferences = { RefitAssembly }, Sources = { input }, }, - }.RunAsync(); + [Fact] + public async Task NoRefitInterfacesSmokeTest() + { +#if NET462 + var input = File.ReadAllText( + IntegrationTestHelper.GetPath("IInterfaceWithoutRefit.cs") + ); +#else + var input = await File.ReadAllTextAsync( + IntegrationTestHelper.GetPath("IInterfaceWithoutRefit.cs") + ); +#endif - await new VerifyCSV2.Test - { - ReferenceAssemblies = ReferenceAssemblies, - TestState = { AdditionalReferences = { RefitAssembly }, Sources = { input }, }, - }.RunAsync(); - } + await new VerifyCS.Test + { + ReferenceAssemblies = ReferenceAssemblies, + TestState = { AdditionalReferences = { RefitAssembly }, Sources = { input }, }, + }.RunAsync(); - [Fact] - public async Task FindInterfacesSmokeTest() + await new VerifyCSV2.Test { - var input = File.ReadAllText(IntegrationTestHelper.GetPath("GitHubApi.cs")); + ReferenceAssemblies = ReferenceAssemblies, + TestState = { AdditionalReferences = { RefitAssembly }, Sources = { input }, }, + }.RunAsync(); + } + + [Fact] + public async Task FindInterfacesSmokeTest() + { +#if NET462 + var input = File.ReadAllText(IntegrationTestHelper.GetPath("GitHubApi.cs")); +#else + var input = await File.ReadAllTextAsync(IntegrationTestHelper.GetPath("GitHubApi.cs")); +#endif - var output1 = - @" + var output1 = + @" #pragma warning disable namespace RefitInternalGenerated { @@ -159,8 +167,8 @@ sealed class PreserveAttribute : global::System.Attribute #pragma warning restore "; - var output1_5 = - @" + var output1_5 = + @" #pragma warning disable namespace Refit.Implementation { @@ -178,7 +186,7 @@ internal static partial class Generated #pragma warning restore "; - var output2 = """ + var output2 = """ #nullable disable #pragma warning disable namespace Refit.Implementation @@ -642,8 +650,8 @@ public RefitTestsIGitHubApi(global::System.Net.Http.HttpClient client, global::R #pragma warning restore """; - var output3 = - @"#nullable disable + var output3 = + @"#nullable disable #pragma warning disable namespace Refit.Implementation { @@ -715,7 +723,7 @@ public RefitTestsIGitHubApiDisposable(global::System.Net.Http.HttpClient client, #pragma warning restore "; - var output4 = """ + var output4 = """ #nullable disable #pragma warning disable namespace Refit.Implementation @@ -1014,51 +1022,57 @@ public RefitTestsTestNestedINestedGitHubApi(global::System.Net.Http.HttpClient c """; - await new VerifyCS.Test + await new VerifyCS.Test + { + ReferenceAssemblies = ReferenceAssemblies, + TestState = { - ReferenceAssemblies = ReferenceAssemblies, - TestState = + AdditionalReferences = { RefitAssembly }, + Sources = { input }, + GeneratedSources = { - AdditionalReferences = { RefitAssembly }, - Sources = { input }, - GeneratedSources = - { - (typeof(InterfaceStubGenerator), "PreserveAttribute.g.cs", output1), - (typeof(InterfaceStubGenerator), "Generated.g.cs", output1_5), - (typeof(InterfaceStubGenerator), "IGitHubApi.g.cs", output2), - (typeof(InterfaceStubGenerator), "IGitHubApiDisposable.g.cs", output3), - (typeof(InterfaceStubGenerator), "INestedGitHubApi.g.cs", output4), - }, + (typeof(InterfaceStubGenerator), "PreserveAttribute.g.cs", output1), + (typeof(InterfaceStubGenerator), "Generated.g.cs", output1_5), + (typeof(InterfaceStubGenerator), "IGitHubApi.g.cs", output2), + (typeof(InterfaceStubGenerator), "IGitHubApiDisposable.g.cs", output3), + (typeof(InterfaceStubGenerator), "INestedGitHubApi.g.cs", output4), }, - }.RunAsync(); + }, + }.RunAsync(); - await new VerifyCSV2.Test + await new VerifyCSV2.Test + { + ReferenceAssemblies = ReferenceAssemblies, + TestState = { - ReferenceAssemblies = ReferenceAssemblies, - TestState = + AdditionalReferences = { RefitAssembly }, + Sources = { input }, + GeneratedSources = { - AdditionalReferences = { RefitAssembly }, - Sources = { input }, - GeneratedSources = - { - (typeof(InterfaceStubGeneratorV2), "PreserveAttribute.g.cs", output1), - (typeof(InterfaceStubGeneratorV2), "Generated.g.cs", output1_5), - (typeof(InterfaceStubGeneratorV2), "IGitHubApi.g.cs", output2), - (typeof(InterfaceStubGeneratorV2), "IGitHubApiDisposable.g.cs", output3), - (typeof(InterfaceStubGeneratorV2), "INestedGitHubApi.g.cs", output4), - }, + (typeof(InterfaceStubGeneratorV2), "PreserveAttribute.g.cs", output1), + (typeof(InterfaceStubGeneratorV2), "Generated.g.cs", output1_5), + (typeof(InterfaceStubGeneratorV2), "IGitHubApi.g.cs", output2), + (typeof(InterfaceStubGeneratorV2), "IGitHubApiDisposable.g.cs", output3), + (typeof(InterfaceStubGeneratorV2), "INestedGitHubApi.g.cs", output4), }, - }.RunAsync(); - } + }, + }.RunAsync(); + } - [Fact] - public async Task GenerateInterfaceStubsWithoutNamespaceSmokeTest() - { - var input = File.ReadAllText( - IntegrationTestHelper.GetPath("IServiceWithoutNamespace.cs") - ); - var output1 = - @" + [Fact] + public async Task GenerateInterfaceStubsWithoutNamespaceSmokeTest() + { +#if NET462 + var input = File.ReadAllText( + IntegrationTestHelper.GetPath("IServiceWithoutNamespace.cs") + ); +#else + var input = await File.ReadAllTextAsync( + IntegrationTestHelper.GetPath("IServiceWithoutNamespace.cs") + ); +#endif + var output1 = + @" #pragma warning disable namespace RefitInternalGenerated { @@ -1077,8 +1091,8 @@ sealed class PreserveAttribute : global::System.Attribute } #pragma warning restore "; - var output1_5 = - @" + var output1_5 = + @" #pragma warning disable namespace Refit.Implementation { @@ -1096,8 +1110,8 @@ internal static partial class Generated #pragma warning restore "; - var output2 = - @"#nullable disable + var output2 = + @"#nullable disable #pragma warning disable namespace Refit.Implementation { @@ -1194,103 +1208,102 @@ public IServiceWithoutNamespace(global::System.Net.Http.HttpClient client, globa #pragma warning restore "; - await new VerifyCS.Test + await new VerifyCS.Test + { + ReferenceAssemblies = ReferenceAssemblies, + TestState = { - ReferenceAssemblies = ReferenceAssemblies, - TestState = + AdditionalReferences = { RefitAssembly }, + Sources = { input }, + GeneratedSources = { - AdditionalReferences = { RefitAssembly }, - Sources = { input }, - GeneratedSources = - { - (typeof(InterfaceStubGenerator), "PreserveAttribute.g.cs", output1), - (typeof(InterfaceStubGenerator), "Generated.g.cs", output1_5), - (typeof(InterfaceStubGenerator), "IServiceWithoutNamespace.g.cs", output2), - }, + (typeof(InterfaceStubGenerator), "PreserveAttribute.g.cs", output1), + (typeof(InterfaceStubGenerator), "Generated.g.cs", output1_5), + (typeof(InterfaceStubGenerator), "IServiceWithoutNamespace.g.cs", output2), }, - }.RunAsync(); + }, + }.RunAsync(); - await new VerifyCSV2.Test + await new VerifyCSV2.Test + { + ReferenceAssemblies = ReferenceAssemblies, + TestState = { - ReferenceAssemblies = ReferenceAssemblies, - TestState = + AdditionalReferences = { RefitAssembly }, + Sources = { input }, + GeneratedSources = { - AdditionalReferences = { RefitAssembly }, - Sources = { input }, - GeneratedSources = - { - (typeof(InterfaceStubGeneratorV2), "PreserveAttribute.g.cs", output1), - (typeof(InterfaceStubGeneratorV2), "Generated.g.cs", output1_5), - ( - typeof(InterfaceStubGeneratorV2), - "IServiceWithoutNamespace.g.cs", - output2 - ), - }, + (typeof(InterfaceStubGeneratorV2), "PreserveAttribute.g.cs", output1), + (typeof(InterfaceStubGeneratorV2), "Generated.g.cs", output1_5), + ( + typeof(InterfaceStubGeneratorV2), + "IServiceWithoutNamespace.g.cs", + output2 + ), }, - }.RunAsync(); - } - } - - public static class ThisIsDumbButMightHappen - { - public const string PeopleDoWeirdStuff = "But we don't let them"; + }, + }.RunAsync(); } +} - public interface IAmARefitInterfaceButNobodyUsesMe - { - [Get("whatever")] - Task RefitMethod(); +public static class ThisIsDumbButMightHappen +{ + public const string PeopleDoWeirdStuff = "But we don't let them"; +} - [Refit.GetAttribute("something-else")] - Task AnotherRefitMethod(); +public interface IAmARefitInterfaceButNobodyUsesMe +{ + [Get("whatever")] + Task RefitMethod(); - [Get(ThisIsDumbButMightHappen.PeopleDoWeirdStuff)] - Task NoConstantsAllowed(); + [Refit.GetAttribute("something-else")] + Task AnotherRefitMethod(); - [Get("spaces-shouldnt-break-me")] - Task SpacesShouldntBreakMe(); + [Get(ThisIsDumbButMightHappen.PeopleDoWeirdStuff)] + Task NoConstantsAllowed(); - // We don't need an explicit test for this because if it isn't supported we can't compile - [Get("anything")] - Task ReservedWordsForParameterNames(int @int, string @string, float @long); - } + [Get("spaces-shouldnt-break-me")] + Task SpacesShouldntBreakMe(); - public interface IAmNotARefitInterface - { - Task NotARefitMethod(); - } + // We don't need an explicit test for this because if it isn't supported we can't compile + [Get("anything")] + Task ReservedWordsForParameterNames(int @int, string @string, float @long); +} - public interface IBoringCrudApi - where T : class - { - [Post("")] - Task Create([Body] T paylod); +public interface IAmNotARefitInterface +{ + Task NotARefitMethod(); +} - [Get("")] - Task> ReadAll(); +public interface IBoringCrudApi + where T : class +{ + [Post("")] + Task Create([Body] T paylod); - [Get("/{key}")] - Task ReadOne(TKey key); + [Get("")] + Task> ReadAll(); - [Put("/{key}")] - Task Update(TKey key, [Body] T payload); + [Get("/{key}")] + Task ReadOne(TKey key); - [Delete("/{key}")] - Task Delete(TKey key); - } + [Put("/{key}")] + Task Update(TKey key, [Body] T payload); - public interface INonGenericInterfaceWithGenericMethod - { - [Post("")] - Task PostMessage([Body] T message) - where T : IMessage; - - [Post("")] - Task PostMessage([Body] T message, U param1, V param2) - where T : IMessage - where U : T; - } + [Delete("/{key}")] + Task Delete(TKey key); +} - public interface IMessage; +public interface INonGenericInterfaceWithGenericMethod +{ + [Post("")] + Task PostMessage([Body] T message) + where T : IMessage; + + [Post("")] + Task PostMessage([Body] T message, U param1, V param2) + where T : IMessage + where U : T; } + +public interface IMessage; diff --git a/Refit.Tests/MethodOverloads.cs b/Refit.Tests/MethodOverloads.cs index 589dc8449..2d97e4052 100644 --- a/Refit.Tests/MethodOverloads.cs +++ b/Refit.Tests/MethodOverloads.cs @@ -7,228 +7,227 @@ using RichardSzalay.MockHttp; using Xunit; -namespace Refit.Tests +namespace Refit.Tests; + +public interface IUseOverloadedMethods { - public interface IUseOverloadedMethods - { - [Get("")] - Task Get(); + [Get("")] + Task Get(); - [Get("/status/{httpstatuscode}")] - Task Get(int httpstatuscode); - } + [Get("/status/{httpstatuscode}")] + Task Get(int httpstatuscode); +} - public interface IUseOverloadedGenericMethods - where TResponse : class - where THeader : struct - { - [Get("")] - Task Get(); +public interface IUseOverloadedGenericMethods + where TResponse : class + where THeader : struct +{ + [Get("")] + Task Get(); - [Get("/get")] - Task Get(TParam param, [Header("X-Refit")] THeader header); + [Get("/get")] + Task Get(TParam param, [Header("X-Refit")] THeader header); - [Get("/get")] - Task Get(THeader param, [Header("X-Refit")] TParam header); + [Get("/get")] + Task Get(THeader param, [Header("X-Refit")] TParam header); - [Get("/status/{httpstatuscode}")] - Task Get(int httpstatuscode); + [Get("/status/{httpstatuscode}")] + Task Get(int httpstatuscode); - [Get("/get")] - Task Get(int someVal); + [Get("/get")] + Task Get(int someVal); - [Get("/get")] - Task Get(TInput input); + [Get("/get")] + Task Get(TInput input); - [Get("/get")] - Task Get(TInput1 input1, TInput2 input2); - } + [Get("/get")] + Task Get(TInput1 input1, TInput2 input2); +} - public class MethodOverladTests +public class MethodOverladTests +{ + [Fact] + public async Task BasicMethodOverloadTest() { - [Fact] - public async Task BasicMethodOverloadTest() - { - var mockHttp = new MockHttpMessageHandler(); + var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/") - .Respond(HttpStatusCode.OK, "text/html", "OK"); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/") + .Respond(HttpStatusCode.OK, "text/html", "OK"); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/status/403") - .Respond(HttpStatusCode.Forbidden); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/status/403") + .Respond(HttpStatusCode.Forbidden); - var fixture = RestService.For("https://httpbin.org/", settings); - var plainText = await fixture.Get(); + var fixture = RestService.For("https://httpbin.org/", settings); + var plainText = await fixture.Get(); - var resp = await fixture.Get(403); + var resp = await fixture.Get(403); - Assert.True(!string.IsNullOrWhiteSpace(plainText)); - Assert.Equal(HttpStatusCode.Forbidden, resp.StatusCode); - } + Assert.True(!string.IsNullOrWhiteSpace(plainText)); + Assert.Equal(HttpStatusCode.Forbidden, resp.StatusCode); + } - [Fact] - public async Task GenericMethodOverloadTest1() - { - var mockHttp = new MockHttpMessageHandler(); + [Fact] + public async Task GenericMethodOverloadTest1() + { + var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/") - .Respond(HttpStatusCode.OK, "text/html", "OK"); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/") + .Respond(HttpStatusCode.OK, "text/html", "OK"); - var fixture = RestService.For>( - "https://httpbin.org/", - settings - ); - var plainText = await fixture.Get(); + var fixture = RestService.For>( + "https://httpbin.org/", + settings + ); + var plainText = await fixture.Get(); - Assert.True(!string.IsNullOrWhiteSpace(plainText)); - } - - [Fact] - public async Task GenericMethodOverloadTest2() - { - var mockHttp = new MockHttpMessageHandler(); + Assert.True(!string.IsNullOrWhiteSpace(plainText)); + } - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + [Fact] + public async Task GenericMethodOverloadTest2() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/status/403") - .Respond(HttpStatusCode.Forbidden); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For>( - "https://httpbin.org/", - settings - ); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/status/403") + .Respond(HttpStatusCode.Forbidden); - var resp = await fixture.Get(403); + var fixture = RestService.For>( + "https://httpbin.org/", + settings + ); - Assert.Equal(HttpStatusCode.Forbidden, resp.StatusCode); - } + var resp = await fixture.Get(403); - [Fact] - public async Task GenericMethodOverloadTest3() - { - var mockHttp = new MockHttpMessageHandler(); + Assert.Equal(HttpStatusCode.Forbidden, resp.StatusCode); + } - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + [Fact] + public async Task GenericMethodOverloadTest3() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .WithQueryString("someVal", "201") - .Respond("application/json", "some-T-value"); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For>( - "https://httpbin.org/", - settings - ); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .WithQueryString("someVal", "201") + .Respond("application/json", "some-T-value"); - var result = await fixture.Get(201); + var fixture = RestService.For>( + "https://httpbin.org/", + settings + ); - Assert.Equal("some-T-value", result); - } + var result = await fixture.Get(201); - [Fact] - public async Task GenericMethodOverloadTest4() - { - var mockHttp = new MockHttpMessageHandler(); + Assert.Equal("some-T-value", result); + } - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + [Fact] + public async Task GenericMethodOverloadTest4() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .WithHeaders("X-Refit", "99") - .WithQueryString("param", "foo") - .Respond( - "application/json", - "{\"url\": \"https://httpbin.org/get\", \"args\": {\"param\": \"foo\"}}" - ); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For>( - "https://httpbin.org/", - settings + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .WithHeaders("X-Refit", "99") + .WithQueryString("param", "foo") + .Respond( + "application/json", + "{\"url\": \"https://httpbin.org/get\", \"args\": {\"param\": \"foo\"}}" ); - var result = await fixture.Get("foo", 99); + var fixture = RestService.For>( + "https://httpbin.org/", + settings + ); - Assert.Equal("foo", result.Args["param"]); - } + var result = await fixture.Get("foo", 99); - [Fact] - public async Task GenericMethodOverloadTest5() - { - var mockHttp = new MockHttpMessageHandler(); + Assert.Equal("foo", result.Args["param"]); + } - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + [Fact] + public async Task GenericMethodOverloadTest5() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .WithHeaders("X-Refit", "foo") - .WithQueryString("param", "99") - .Respond( - "application/json", - "{\"url\": \"https://httpbin.org/get\", \"args\": {\"param\": \"99\"}}" - ); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For>( - "https://httpbin.org/", - settings + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .WithHeaders("X-Refit", "foo") + .WithQueryString("param", "99") + .Respond( + "application/json", + "{\"url\": \"https://httpbin.org/get\", \"args\": {\"param\": \"99\"}}" ); - var result = await fixture.Get(99, "foo"); + var fixture = RestService.For>( + "https://httpbin.org/", + settings + ); - Assert.Equal("99", result.Args["param"]); - } + var result = await fixture.Get(99, "foo"); - [Fact] - public async Task GenericMethodOverloadTest6() - { - var mockHttp = new MockHttpMessageHandler(); + Assert.Equal("99", result.Args["param"]); + } - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + [Fact] + public async Task GenericMethodOverloadTest6() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .WithQueryString("input", "99") - .Respond("application/json", "generic-output"); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For>( - "https://httpbin.org/", - settings - ); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .WithQueryString("input", "99") + .Respond("application/json", "generic-output"); - var result = await fixture.Get(99); + var fixture = RestService.For>( + "https://httpbin.org/", + settings + ); - Assert.Equal("generic-output", result); - } + var result = await fixture.Get(99); - [Fact] - public async Task GenericMethodOverloadTest7() - { - var mockHttp = new MockHttpMessageHandler(); + Assert.Equal("generic-output", result); + } - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + [Fact] + public async Task GenericMethodOverloadTest7() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .WithQueryString( - new Dictionary() { { "input1", "str" }, { "input2", "3" } } - ) - .Respond("application/json", "Ok"); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For>( - "https://httpbin.org/", - settings - ); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .WithQueryString( + new Dictionary() { { "input1", "str" }, { "input2", "3" } } + ) + .Respond("application/json", "Ok"); + + var fixture = RestService.For>( + "https://httpbin.org/", + settings + ); - await fixture.Get("str", 3); + await fixture.Get("str", 3); - mockHttp.VerifyNoOutstandingExpectation(); - } + mockHttp.VerifyNoOutstandingExpectation(); } } diff --git a/Refit.Tests/MultipartTests.cs b/Refit.Tests/MultipartTests.cs index ce35bebcf..cb3638f3f 100644 --- a/Refit.Tests/MultipartTests.cs +++ b/Refit.Tests/MultipartTests.cs @@ -13,930 +13,929 @@ using System.Text; using System.Net.Http.Headers; -namespace Refit.Tests -{ - public interface IRunscopeApi - { - [Multipart] - [Post("/")] - Task UploadStream(Stream stream); - - [Multipart("-----SomeCustomBoundary")] - [Post("/")] - Task UploadStreamWithCustomBoundary(Stream stream); - - [Multipart] - [Post("/")] - Task UploadStreamPart(StreamPart stream); - - [Multipart] - [Post("/")] - Task UploadStreamPart( - [Query] ModelObject someQueryParams, - StreamPart stream - ); +namespace Refit.Tests; - [Multipart] - [Post("/")] - Task UploadBytes(byte[] bytes); +public interface IRunscopeApi +{ + [Multipart] + [Post("/")] + Task UploadStream(Stream stream); + + [Multipart("-----SomeCustomBoundary")] + [Post("/")] + Task UploadStreamWithCustomBoundary(Stream stream); + + [Multipart] + [Post("/")] + Task UploadStreamPart(StreamPart stream); + + [Multipart] + [Post("/")] + Task UploadStreamPart( + [Query] ModelObject someQueryParams, + StreamPart stream + ); + + [Multipart] + [Post("/")] + Task UploadBytes(byte[] bytes); + + [Multipart] + [Post("/")] + Task UploadBytesPart( + [AliasAs("ByteArrayPartParamAlias")] ByteArrayPart bytes + ); + + [Multipart] + [Post("/")] + Task UploadString([AliasAs("SomeStringAlias")] string someString); + + [Multipart] + [Post("/")] + Task UploadStringWithHeaderAndRequestProperty( + [Header("Authorization")] string authorization, + [Property("SomeProperty")] string someProperty, + [AliasAs("SomeStringAlias")] string someString + ); + + [Multipart] + [Post("/")] + Task UploadFileInfo( + IEnumerable fileInfos, + FileInfo anotherFile + ); + + [Multipart] + [Post("/")] + Task UploadFileInfoPart( + IEnumerable fileInfos, + FileInfoPart anotherFile + ); + + [Multipart] + [Post("/")] + Task UploadJsonObject(ModelObject theObject); + + [Multipart] + [Post("/")] + Task UploadJsonObjects(IEnumerable theObjects); + + [Multipart] + [Post("/")] + Task UploadMixedObjects( + IEnumerable theObjects, + AnotherModel anotherModel, + FileInfo aFile, + AnEnum anEnum, + string aString, + int anInt + ); + + [Multipart] + [Post("/")] + Task UploadHttpContent(HttpContent content); +} - [Multipart] - [Post("/")] - Task UploadBytesPart( - [AliasAs("ByteArrayPartParamAlias")] ByteArrayPart bytes - ); +public class ModelObject +{ + public string Property1 { get; set; } + public string Property2 { get; set; } +} - [Multipart] - [Post("/")] - Task UploadString([AliasAs("SomeStringAlias")] string someString); +public class AnotherModel +{ + public string[] Foos { get; set; } +} - [Multipart] - [Post("/")] - Task UploadStringWithHeaderAndRequestProperty( - [Header("Authorization")] string authorization, - [Property("SomeProperty")] string someProperty, - [AliasAs("SomeStringAlias")] string someString - ); +public enum AnEnum +{ + Val1, + Val2 +} - [Multipart] - [Post("/")] - Task UploadFileInfo( - IEnumerable fileInfos, - FileInfo anotherFile - ); +public class MultipartTests +{ + const string BaseAddress = "https://api/"; - [Multipart] - [Post("/")] - Task UploadFileInfoPart( - IEnumerable fileInfos, - FileInfoPart anotherFile - ); + [Fact] + public async Task MultipartUploadShouldWorkWithStream() + { + var handler = new MockHttpMessageHandler + { + Asserts = async content => + { + var parts = content.ToList(); - [Multipart] - [Post("/")] - Task UploadJsonObject(ModelObject theObject); - - [Multipart] - [Post("/")] - Task UploadJsonObjects(IEnumerable theObjects); - - [Multipart] - [Post("/")] - Task UploadMixedObjects( - IEnumerable theObjects, - AnotherModel anotherModel, - FileInfo aFile, - AnEnum anEnum, - string aString, - int anInt - ); + Assert.Single(parts); - [Multipart] - [Post("/")] - Task UploadHttpContent(HttpContent content); - } + Assert.Equal("stream", parts[0].Headers.ContentDisposition.Name); + Assert.Equal("stream", parts[0].Headers.ContentDisposition.FileName); - public class ModelObject - { - public string Property1 { get; set; } - public string Property2 { get; set; } - } + using var str = await parts[0].ReadAsStreamAsync(); + using var src = GetTestFileStream("Test Files/Test.pdf"); + Assert.True(StreamsEqual(src, str)); + } + }; - public class AnotherModel - { - public string[] Foos { get; set; } - } + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - public enum AnEnum - { - Val1, - Val2 + using var stream = GetTestFileStream("Test Files/Test.pdf"); + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadStream(stream); } - public class MultipartTests + [Fact] + public async Task MultipartUploadShouldWorkWithStreamAndCustomBoundary() { - const string BaseAddress = "https://api/"; - - [Fact] - public async Task MultipartUploadShouldWorkWithStream() + var handler = new MockHttpMessageHandler { - var handler = new MockHttpMessageHandler + Asserts = async content => { - Asserts = async content => - { - var parts = content.ToList(); + var parts = content.ToList(); - Assert.Single(parts); + Assert.Single(parts); - Assert.Equal("stream", parts[0].Headers.ContentDisposition.Name); - Assert.Equal("stream", parts[0].Headers.ContentDisposition.FileName); + Assert.Equal("stream", parts[0].Headers.ContentDisposition.Name); + Assert.Equal("stream", parts[0].Headers.ContentDisposition.FileName); - using var str = await parts[0].ReadAsStreamAsync(); - using var src = GetTestFileStream("Test Files/Test.pdf"); - Assert.True(StreamsEqual(src, str)); - } - }; + using var str = await parts[0].ReadAsStreamAsync(); + using var src = GetTestFileStream("Test Files/Test.pdf"); + Assert.True(StreamsEqual(src, str)); + } + }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - using var stream = GetTestFileStream("Test Files/Test.pdf"); + using (var stream = GetTestFileStream("Test Files/Test.pdf")) + { var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadStream(stream); + var result = await fixture.UploadStreamWithCustomBoundary(stream); } - [Fact] - public async Task MultipartUploadShouldWorkWithStreamAndCustomBoundary() + var input = typeof(IRunscopeApi); + var methodFixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == "UploadStreamWithCustomBoundary") + ); + Assert.Equal("-----SomeCustomBoundary", methodFixture.MultipartBoundary); + } + + [Fact] + public async Task MultipartUploadShouldWorkWithByteArray() + { + var handler = new MockHttpMessageHandler { - var handler = new MockHttpMessageHandler + Asserts = async content => { - Asserts = async content => - { - var parts = content.ToList(); + var parts = content.ToList(); - Assert.Single(parts); + Assert.Single(parts); - Assert.Equal("stream", parts[0].Headers.ContentDisposition.Name); - Assert.Equal("stream", parts[0].Headers.ContentDisposition.FileName); + Assert.Equal("bytes", parts[0].Headers.ContentDisposition.Name); + Assert.Equal("bytes", parts[0].Headers.ContentDisposition.FileName); + Assert.Null(parts[0].Headers.ContentType); + using var str = await parts[0].ReadAsStreamAsync(); + using var src = GetTestFileStream("Test Files/Test.pdf"); + Assert.True(StreamsEqual(src, str)); + } + }; - using var str = await parts[0].ReadAsStreamAsync(); - using var src = GetTestFileStream("Test Files/Test.pdf"); - Assert.True(StreamsEqual(src, str)); - } - }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + using var stream = GetTestFileStream("Test Files/Test.pdf"); + using var reader = new BinaryReader(stream); + var bytes = reader.ReadBytes((int)stream.Length); - using (var stream = GetTestFileStream("Test Files/Test.pdf")) - { - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadStreamWithCustomBoundary(stream); - } + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadBytes(bytes); + } - var input = typeof(IRunscopeApi); - var methodFixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == "UploadStreamWithCustomBoundary") - ); - Assert.Equal("-----SomeCustomBoundary", methodFixture.MultipartBoundary); - } + [Fact] + public async Task MultipartUploadShouldWorkWithFileInfo() + { + var fileName = Path.GetTempFileName(); + var name = Path.GetFileName(fileName); - [Fact] - public async Task MultipartUploadShouldWorkWithByteArray() + var handler = new MockHttpMessageHandler { - var handler = new MockHttpMessageHandler + Asserts = async content => { - Asserts = async content => + var parts = content.ToList(); + + Assert.Equal(3, parts.Count); + + Assert.Equal("fileInfos", parts[0].Headers.ContentDisposition.Name); + Assert.Equal(name, parts[0].Headers.ContentDisposition.FileName); + Assert.Null(parts[0].Headers.ContentType); + using (var str = await parts[0].ReadAsStreamAsync()) + using (var src = GetTestFileStream("Test Files/Test.pdf")) { - var parts = content.ToList(); + Assert.True(StreamsEqual(src, str)); + } - Assert.Single(parts); + Assert.Equal("fileInfos", parts[1].Headers.ContentDisposition.Name); + Assert.Equal(name, parts[1].Headers.ContentDisposition.FileName); + Assert.Null(parts[1].Headers.ContentType); + using (var str = await parts[1].ReadAsStreamAsync()) + using (var src = GetTestFileStream("Test Files/Test.pdf")) + { + Assert.True(StreamsEqual(src, str)); + } - Assert.Equal("bytes", parts[0].Headers.ContentDisposition.Name); - Assert.Equal("bytes", parts[0].Headers.ContentDisposition.FileName); - Assert.Null(parts[0].Headers.ContentType); - using var str = await parts[0].ReadAsStreamAsync(); - using var src = GetTestFileStream("Test Files/Test.pdf"); + Assert.Equal("anotherFile", parts[2].Headers.ContentDisposition.Name); + Assert.Equal(name, parts[2].Headers.ContentDisposition.FileName); + Assert.Null(parts[2].Headers.ContentType); + using (var str = await parts[2].ReadAsStreamAsync()) + using (var src = GetTestFileStream("Test Files/Test.pdf")) + { Assert.True(StreamsEqual(src, str)); } - }; + } + }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + try + { using var stream = GetTestFileStream("Test Files/Test.pdf"); - using var reader = new BinaryReader(stream); - var bytes = reader.ReadBytes((int)stream.Length); + using var outStream = File.OpenWrite(fileName); + await stream.CopyToAsync(outStream); + await outStream.FlushAsync(); + outStream.Close(); var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadBytes(bytes); + var result = await fixture.UploadFileInfo( + new[] { new FileInfo(fileName), new FileInfo(fileName) }, + new FileInfo(fileName) + ); } - - [Fact] - public async Task MultipartUploadShouldWorkWithFileInfo() + finally { - var fileName = Path.GetTempFileName(); - var name = Path.GetFileName(fileName); - - var handler = new MockHttpMessageHandler - { - Asserts = async content => - { - var parts = content.ToList(); - - Assert.Equal(3, parts.Count); - - Assert.Equal("fileInfos", parts[0].Headers.ContentDisposition.Name); - Assert.Equal(name, parts[0].Headers.ContentDisposition.FileName); - Assert.Null(parts[0].Headers.ContentType); - using (var str = await parts[0].ReadAsStreamAsync()) - using (var src = GetTestFileStream("Test Files/Test.pdf")) - { - Assert.True(StreamsEqual(src, str)); - } - - Assert.Equal("fileInfos", parts[1].Headers.ContentDisposition.Name); - Assert.Equal(name, parts[1].Headers.ContentDisposition.FileName); - Assert.Null(parts[1].Headers.ContentType); - using (var str = await parts[1].ReadAsStreamAsync()) - using (var src = GetTestFileStream("Test Files/Test.pdf")) - { - Assert.True(StreamsEqual(src, str)); - } - - Assert.Equal("anotherFile", parts[2].Headers.ContentDisposition.Name); - Assert.Equal(name, parts[2].Headers.ContentDisposition.FileName); - Assert.Null(parts[2].Headers.ContentType); - using (var str = await parts[2].ReadAsStreamAsync()) - using (var src = GetTestFileStream("Test Files/Test.pdf")) - { - Assert.True(StreamsEqual(src, str)); - } - } - }; - - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - - try - { - using var stream = GetTestFileStream("Test Files/Test.pdf"); - using var outStream = File.OpenWrite(fileName); - await stream.CopyToAsync(outStream); - await outStream.FlushAsync(); - outStream.Close(); - - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadFileInfo( - new[] { new FileInfo(fileName), new FileInfo(fileName) }, - new FileInfo(fileName) - ); - } - finally - { - File.Delete(fileName); - } + File.Delete(fileName); } + } - [Fact] - public async Task MultipartUploadShouldWorkWithString() - { - const string text = "This is random text"; + [Fact] + public async Task MultipartUploadShouldWorkWithString() + { + const string text = "This is random text"; - var handler = new MockHttpMessageHandler + var handler = new MockHttpMessageHandler + { + Asserts = async content => { - Asserts = async content => - { - var parts = content.ToList(); + var parts = content.ToList(); - Assert.Single(parts); + Assert.Single(parts); - Assert.Equal("SomeStringAlias", parts[0].Headers.ContentDisposition.Name); - Assert.Null(parts[0].Headers.ContentDisposition.FileName); - Assert.Equal("text/plain", parts[0].Headers.ContentType.MediaType); - Assert.Equal("utf-8", parts[0].Headers.ContentType.CharSet); - var str = await parts[0].ReadAsStringAsync(); - Assert.Equal(text, str); - } - }; + Assert.Equal("SomeStringAlias", parts[0].Headers.ContentDisposition.Name); + Assert.Null(parts[0].Headers.ContentDisposition.FileName); + Assert.Equal("text/plain", parts[0].Headers.ContentType.MediaType); + Assert.Equal("utf-8", parts[0].Headers.ContentType.CharSet); + var str = await parts[0].ReadAsStringAsync(); + Assert.Equal(text, str); + } + }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadString(text); - } + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadString(text); + } - [Fact] - public async Task MultipartUploadShouldWorkWithHeaderAndRequestProperty() - { - const string text = "This is random text"; - const string someHeader = "someHeader"; - const string someProperty = "someProperty"; + [Fact] + public async Task MultipartUploadShouldWorkWithHeaderAndRequestProperty() + { + const string text = "This is random text"; + const string someHeader = "someHeader"; + const string someProperty = "someProperty"; - var handler = new MockHttpMessageHandler + var handler = new MockHttpMessageHandler + { + RequestAsserts = message => { - RequestAsserts = message => - { - Assert.Equal(someHeader, message.Headers.Authorization.ToString()); + Assert.Equal(someHeader, message.Headers.Authorization.ToString()); #if NET6_0_OR_GREATER - Assert.Equal(3, message.Options.Count()); - Assert.Equal( - someProperty, - ((IDictionary)message.Options)["SomeProperty"] - ); + Assert.Equal(3, message.Options.Count()); + Assert.Equal( + someProperty, + ((IDictionary)message.Options)["SomeProperty"] + ); #endif #pragma warning disable CS0618 // Type or member is obsolete - Assert.Equal(3, message.Properties.Count); - Assert.Equal(someProperty, message.Properties["SomeProperty"]); + Assert.Equal(3, message.Properties.Count); + Assert.Equal(someProperty, message.Properties["SomeProperty"]); #pragma warning restore CS0618 // Type or member is obsolete - }, - Asserts = async content => - { - var parts = content.ToList(); + }, + Asserts = async content => + { + var parts = content.ToList(); - Assert.Single(parts); + Assert.Single(parts); - Assert.Equal("SomeStringAlias", parts[0].Headers.ContentDisposition.Name); - Assert.Null(parts[0].Headers.ContentDisposition.FileName); - Assert.Equal("text/plain", parts[0].Headers.ContentType.MediaType); - Assert.Equal("utf-8", parts[0].Headers.ContentType.CharSet); - var str = await parts[0].ReadAsStringAsync(); - Assert.Equal(text, str); - } - }; + Assert.Equal("SomeStringAlias", parts[0].Headers.ContentDisposition.Name); + Assert.Null(parts[0].Headers.ContentDisposition.FileName); + Assert.Equal("text/plain", parts[0].Headers.ContentType.MediaType); + Assert.Equal("utf-8", parts[0].Headers.ContentType.CharSet); + var str = await parts[0].ReadAsStringAsync(); + Assert.Equal(text, str); + } + }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadStringWithHeaderAndRequestProperty( - someHeader, - someProperty, - text - ); - } + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadStringWithHeaderAndRequestProperty( + someHeader, + someProperty, + text + ); + } - [Fact] - public async Task MultipartUploadShouldWorkWithStreamPart() + [Fact] + public async Task MultipartUploadShouldWorkWithStreamPart() + { + var handler = new MockHttpMessageHandler { - var handler = new MockHttpMessageHandler + Asserts = async content => { - Asserts = async content => - { - var parts = content.ToList(); + var parts = content.ToList(); - Assert.Single(parts); + Assert.Single(parts); - Assert.Equal("stream", parts[0].Headers.ContentDisposition.Name); - Assert.Equal( - "test-streampart.pdf", - parts[0].Headers.ContentDisposition.FileName - ); - Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); + Assert.Equal("stream", parts[0].Headers.ContentDisposition.Name); + Assert.Equal( + "test-streampart.pdf", + parts[0].Headers.ContentDisposition.FileName + ); + Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); - using var str = await parts[0].ReadAsStreamAsync(); - using var src = GetTestFileStream("Test Files/Test.pdf"); - Assert.True(StreamsEqual(src, str)); - } - }; + using var str = await parts[0].ReadAsStreamAsync(); + using var src = GetTestFileStream("Test Files/Test.pdf"); + Assert.True(StreamsEqual(src, str)); + } + }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - using var stream = GetTestFileStream("Test Files/Test.pdf"); - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadStreamPart( - new StreamPart(stream, "test-streampart.pdf", "application/pdf") - ); - } + using var stream = GetTestFileStream("Test Files/Test.pdf"); + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadStreamPart( + new StreamPart(stream, "test-streampart.pdf", "application/pdf") + ); + } - [Fact] - public async Task MultipartUploadShouldWorkWithStreamPartWithNamedMultipart() + [Fact] + public async Task MultipartUploadShouldWorkWithStreamPartWithNamedMultipart() + { + var handler = new MockHttpMessageHandler { - var handler = new MockHttpMessageHandler + Asserts = async content => { - Asserts = async content => - { - var parts = content.ToList(); + var parts = content.ToList(); - Assert.Single(parts); + Assert.Single(parts); - Assert.Equal("test-stream", parts[0].Headers.ContentDisposition.Name); - Assert.Equal( - "test-streampart.pdf", - parts[0].Headers.ContentDisposition.FileName - ); - Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); + Assert.Equal("test-stream", parts[0].Headers.ContentDisposition.Name); + Assert.Equal( + "test-streampart.pdf", + parts[0].Headers.ContentDisposition.FileName + ); + Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); - using var str = await parts[0].ReadAsStreamAsync(); - using var src = GetTestFileStream("Test Files/Test.pdf"); - Assert.True(StreamsEqual(src, str)); - } - }; + using var str = await parts[0].ReadAsStreamAsync(); + using var src = GetTestFileStream("Test Files/Test.pdf"); + Assert.True(StreamsEqual(src, str)); + } + }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - using var stream = GetTestFileStream("Test Files/Test.pdf"); - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadStreamPart( - new StreamPart(stream, "test-streampart.pdf", "application/pdf", "test-stream") - ); - } + using var stream = GetTestFileStream("Test Files/Test.pdf"); + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadStreamPart( + new StreamPart(stream, "test-streampart.pdf", "application/pdf", "test-stream") + ); + } - [Fact] - public async Task MultipartUploadShouldWorkWithStreamPartAndQuery() + [Fact] + public async Task MultipartUploadShouldWorkWithStreamPartAndQuery() + { + var handler = new MockHttpMessageHandler { - var handler = new MockHttpMessageHandler + RequestAsserts = request => { - RequestAsserts = request => - { - Assert.Equal("?Property1=test&Property2=test2", request.RequestUri.Query); - }, - Asserts = async content => - { - var parts = content.ToList(); + Assert.Equal("?Property1=test&Property2=test2", request.RequestUri.Query); + }, + Asserts = async content => + { + var parts = content.ToList(); - Assert.Single(parts); + Assert.Single(parts); - Assert.Equal("stream", parts[0].Headers.ContentDisposition.Name); - Assert.Equal( - "test-streampart.pdf", - parts[0].Headers.ContentDisposition.FileName - ); - Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); + Assert.Equal("stream", parts[0].Headers.ContentDisposition.Name); + Assert.Equal( + "test-streampart.pdf", + parts[0].Headers.ContentDisposition.FileName + ); + Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); - using var str = await parts[0].ReadAsStreamAsync(); - using var src = GetTestFileStream("Test Files/Test.pdf"); - Assert.True(StreamsEqual(src, str)); - } - }; + using var str = await parts[0].ReadAsStreamAsync(); + using var src = GetTestFileStream("Test Files/Test.pdf"); + Assert.True(StreamsEqual(src, str)); + } + }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - using var stream = GetTestFileStream("Test Files/Test.pdf"); - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadStreamPart( - new ModelObject() { Property1 = "test", Property2 = "test2" }, - new StreamPart(stream, "test-streampart.pdf", "application/pdf") - ); - } + using var stream = GetTestFileStream("Test Files/Test.pdf"); + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadStreamPart( + new ModelObject() { Property1 = "test", Property2 = "test2" }, + new StreamPart(stream, "test-streampart.pdf", "application/pdf") + ); + } - [Fact] - public async Task MultipartUploadShouldWorkWithByteArrayPart() + [Fact] + public async Task MultipartUploadShouldWorkWithByteArrayPart() + { + var handler = new MockHttpMessageHandler { - var handler = new MockHttpMessageHandler + Asserts = async content => { - Asserts = async content => - { - var parts = content.ToList(); - - Assert.Single(parts); - - Assert.Equal( - "ByteArrayPartParamAlias", - parts[0].Headers.ContentDisposition.Name - ); - Assert.Equal( - "test-bytearraypart.pdf", - parts[0].Headers.ContentDisposition.FileName - ); - Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); - - using var str = await parts[0].ReadAsStreamAsync(); - using var src = GetTestFileStream("Test Files/Test.pdf"); - Assert.True(StreamsEqual(src, str)); - } - }; + var parts = content.ToList(); - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + Assert.Single(parts); - using var stream = GetTestFileStream("Test Files/Test.pdf"); - using var reader = new BinaryReader(stream); - var bytes = reader.ReadBytes((int)stream.Length); + Assert.Equal( + "ByteArrayPartParamAlias", + parts[0].Headers.ContentDisposition.Name + ); + Assert.Equal( + "test-bytearraypart.pdf", + parts[0].Headers.ContentDisposition.FileName + ); + Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadBytesPart( - new ByteArrayPart(bytes, "test-bytearraypart.pdf", "application/pdf") - ); - } + using var str = await parts[0].ReadAsStreamAsync(); + using var src = GetTestFileStream("Test Files/Test.pdf"); + Assert.True(StreamsEqual(src, str)); + } + }; - [Fact] - public async Task MultipartUploadShouldWorkWithFileInfoPart() - { - var fileName = Path.GetTempFileName(); + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + + using var stream = GetTestFileStream("Test Files/Test.pdf"); + using var reader = new BinaryReader(stream); + var bytes = reader.ReadBytes((int)stream.Length); + + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadBytesPart( + new ByteArrayPart(bytes, "test-bytearraypart.pdf", "application/pdf") + ); + } - var handler = new MockHttpMessageHandler + [Fact] + public async Task MultipartUploadShouldWorkWithFileInfoPart() + { + var fileName = Path.GetTempFileName(); + + var handler = new MockHttpMessageHandler + { + Asserts = async content => { - Asserts = async content => + var parts = content.ToList(); + + Assert.Equal(3, parts.Count); + + Assert.Equal("fileInfos", parts[0].Headers.ContentDisposition.Name); + Assert.Equal( + "test-fileinfopart.pdf", + parts[0].Headers.ContentDisposition.FileName + ); + Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); + using (var str = await parts[0].ReadAsStreamAsync()) + using (var src = GetTestFileStream("Test Files/Test.pdf")) { - var parts = content.ToList(); + Assert.True(StreamsEqual(src, str)); + } - Assert.Equal(3, parts.Count); + Assert.Equal("fileInfos", parts[1].Headers.ContentDisposition.Name); + Assert.Equal( + "test-fileinfopart2.pdf", + parts[1].Headers.ContentDisposition.FileName + ); + Assert.Null(parts[1].Headers.ContentType); + using (var str = await parts[1].ReadAsStreamAsync()) + using (var src = GetTestFileStream("Test Files/Test.pdf")) + { + Assert.True(StreamsEqual(src, str)); + } - Assert.Equal("fileInfos", parts[0].Headers.ContentDisposition.Name); - Assert.Equal( - "test-fileinfopart.pdf", - parts[0].Headers.ContentDisposition.FileName - ); - Assert.Equal("application/pdf", parts[0].Headers.ContentType.MediaType); - using (var str = await parts[0].ReadAsStreamAsync()) - using (var src = GetTestFileStream("Test Files/Test.pdf")) - { - Assert.True(StreamsEqual(src, str)); - } - - Assert.Equal("fileInfos", parts[1].Headers.ContentDisposition.Name); - Assert.Equal( - "test-fileinfopart2.pdf", - parts[1].Headers.ContentDisposition.FileName - ); - Assert.Null(parts[1].Headers.ContentType); - using (var str = await parts[1].ReadAsStreamAsync()) - using (var src = GetTestFileStream("Test Files/Test.pdf")) - { - Assert.True(StreamsEqual(src, str)); - } - - Assert.Equal("anotherFile", parts[2].Headers.ContentDisposition.Name); - Assert.Equal( - "additionalfile.pdf", - parts[2].Headers.ContentDisposition.FileName - ); - Assert.Equal("application/pdf", parts[2].Headers.ContentType.MediaType); - using (var str = await parts[2].ReadAsStreamAsync()) - using (var src = GetTestFileStream("Test Files/Test.pdf")) - { - Assert.True(StreamsEqual(src, str)); - } + Assert.Equal("anotherFile", parts[2].Headers.ContentDisposition.Name); + Assert.Equal( + "additionalfile.pdf", + parts[2].Headers.ContentDisposition.FileName + ); + Assert.Equal("application/pdf", parts[2].Headers.ContentType.MediaType); + using (var str = await parts[2].ReadAsStreamAsync()) + using (var src = GetTestFileStream("Test Files/Test.pdf")) + { + Assert.True(StreamsEqual(src, str)); } - }; + } + }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - try - { - using var stream = GetTestFileStream("Test Files/Test.pdf"); - using var outStream = File.OpenWrite(fileName); - await stream.CopyToAsync(outStream); - await outStream.FlushAsync(); - outStream.Close(); - - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadFileInfoPart( - new[] - { - new FileInfoPart( - new FileInfo(fileName), - "test-fileinfopart.pdf", - "application/pdf" - ), - new FileInfoPart( - new FileInfo(fileName), - "test-fileinfopart2.pdf", - contentType: null - ) - }, + try + { + using var stream = GetTestFileStream("Test Files/Test.pdf"); + using var outStream = File.OpenWrite(fileName); + await stream.CopyToAsync(outStream); + await outStream.FlushAsync(); + outStream.Close(); + + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadFileInfoPart( + new[] + { + new FileInfoPart( + new FileInfo(fileName), + "test-fileinfopart.pdf", + "application/pdf" + ), new FileInfoPart( new FileInfo(fileName), - fileName: "additionalfile.pdf", - contentType: "application/pdf" + "test-fileinfopart2.pdf", + contentType: null ) - ); - } - finally - { - File.Delete(fileName); - } + }, + new FileInfoPart( + new FileInfo(fileName), + fileName: "additionalfile.pdf", + contentType: "application/pdf" + ) + ); } + finally + { + File.Delete(fileName); + } + } - [Theory] - [InlineData(typeof(NewtonsoftJsonContentSerializer), "application/json")] - [InlineData(typeof(SystemTextJsonContentSerializer), "application/json")] - [InlineData(typeof(XmlContentSerializer), "application/xml")] - public async Task MultipartUploadShouldWorkWithAnObject( - Type contentSerializerType, - string mediaType + [Theory] + [InlineData(typeof(NewtonsoftJsonContentSerializer), "application/json")] + [InlineData(typeof(SystemTextJsonContentSerializer), "application/json")] + [InlineData(typeof(XmlContentSerializer), "application/xml")] + public async Task MultipartUploadShouldWorkWithAnObject( + Type contentSerializerType, + string mediaType + ) + { + if ( + Activator.CreateInstance(contentSerializerType) + is not IHttpContentSerializer serializer ) { - if ( - Activator.CreateInstance(contentSerializerType) - is not IHttpContentSerializer serializer - ) - { - throw new ArgumentException( - $"{contentSerializerType.FullName} does not implement {nameof(IHttpContentSerializer)}" - ); - } + throw new ArgumentException( + $"{contentSerializerType.FullName} does not implement {nameof(IHttpContentSerializer)}" + ); + } - var model1 = new ModelObject { Property1 = "M1.prop1", Property2 = "M1.prop2" }; + var model1 = new ModelObject { Property1 = "M1.prop1", Property2 = "M1.prop2" }; - var handler = new MockHttpMessageHandler + var handler = new MockHttpMessageHandler + { + Asserts = async content => { - Asserts = async content => - { - var parts = content.ToList(); - - Assert.Single(parts); - - Assert.Equal("theObject", parts[0].Headers.ContentDisposition.Name); - Assert.Null(parts[0].Headers.ContentDisposition.FileName); - Assert.Equal(mediaType, parts[0].Headers.ContentType.MediaType); - var result0 = await serializer - .FromHttpContentAsync(parts[0]) - .ConfigureAwait(false); - Assert.Equal(model1.Property1, result0.Property1); - Assert.Equal(model1.Property2, result0.Property2); - } - }; + var parts = content.ToList(); - var settings = new RefitSettings() - { - HttpMessageHandlerFactory = () => handler, - ContentSerializer = serializer - }; + Assert.Single(parts); - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadJsonObject(model1); - } + Assert.Equal("theObject", parts[0].Headers.ContentDisposition.Name); + Assert.Null(parts[0].Headers.ContentDisposition.FileName); + Assert.Equal(mediaType, parts[0].Headers.ContentType.MediaType); + var result0 = await serializer + .FromHttpContentAsync(parts[0]) + .ConfigureAwait(false); + Assert.Equal(model1.Property1, result0.Property1); + Assert.Equal(model1.Property2, result0.Property2); + } + }; - [Theory] - [InlineData(typeof(NewtonsoftJsonContentSerializer), "application/json")] - [InlineData(typeof(SystemTextJsonContentSerializer), "application/json")] - [InlineData(typeof(XmlContentSerializer), "application/xml")] - public async Task MultipartUploadShouldWorkWithObjects( - Type contentSerializerType, - string mediaType - ) + var settings = new RefitSettings() { - if ( - Activator.CreateInstance(contentSerializerType) - is not IHttpContentSerializer serializer - ) - { - throw new ArgumentException( - $"{contentSerializerType.FullName} does not implement {nameof(IHttpContentSerializer)}" - ); - } + HttpMessageHandlerFactory = () => handler, + ContentSerializer = serializer + }; - var model1 = new ModelObject { Property1 = "M1.prop1", Property2 = "M1.prop2" }; + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadJsonObject(model1); + } - var model2 = new ModelObject { Property1 = "M2.prop1" }; + [Theory] + [InlineData(typeof(NewtonsoftJsonContentSerializer), "application/json")] + [InlineData(typeof(SystemTextJsonContentSerializer), "application/json")] + [InlineData(typeof(XmlContentSerializer), "application/xml")] + public async Task MultipartUploadShouldWorkWithObjects( + Type contentSerializerType, + string mediaType + ) + { + if ( + Activator.CreateInstance(contentSerializerType) + is not IHttpContentSerializer serializer + ) + { + throw new ArgumentException( + $"{contentSerializerType.FullName} does not implement {nameof(IHttpContentSerializer)}" + ); + } - var handler = new MockHttpMessageHandler - { - Asserts = async content => - { - var parts = content.ToList(); - - Assert.Equal(2, parts.Count); - - Assert.Equal("theObjects", parts[0].Headers.ContentDisposition.Name); - Assert.Null(parts[0].Headers.ContentDisposition.FileName); - Assert.Equal(mediaType, parts[0].Headers.ContentType.MediaType); - var result0 = await serializer - .FromHttpContentAsync(parts[0]) - .ConfigureAwait(false); - Assert.Equal(model1.Property1, result0.Property1); - Assert.Equal(model1.Property2, result0.Property2); - - Assert.Equal("theObjects", parts[1].Headers.ContentDisposition.Name); - Assert.Null(parts[1].Headers.ContentDisposition.FileName); - Assert.Equal(mediaType, parts[1].Headers.ContentType.MediaType); - var result1 = await serializer - .FromHttpContentAsync(parts[1]) - .ConfigureAwait(false); - Assert.Equal(model2.Property1, result1.Property1); - Assert.Equal(model2.Property2, result1.Property2); - } - }; + var model1 = new ModelObject { Property1 = "M1.prop1", Property2 = "M1.prop2" }; - var settings = new RefitSettings() - { - HttpMessageHandlerFactory = () => handler, - ContentSerializer = serializer - }; + var model2 = new ModelObject { Property1 = "M2.prop1" }; - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadJsonObjects(new[] { model1, model2 }); - } + var handler = new MockHttpMessageHandler + { + Asserts = async content => + { + var parts = content.ToList(); + + Assert.Equal(2, parts.Count); + + Assert.Equal("theObjects", parts[0].Headers.ContentDisposition.Name); + Assert.Null(parts[0].Headers.ContentDisposition.FileName); + Assert.Equal(mediaType, parts[0].Headers.ContentType.MediaType); + var result0 = await serializer + .FromHttpContentAsync(parts[0]) + .ConfigureAwait(false); + Assert.Equal(model1.Property1, result0.Property1); + Assert.Equal(model1.Property2, result0.Property2); + + Assert.Equal("theObjects", parts[1].Headers.ContentDisposition.Name); + Assert.Null(parts[1].Headers.ContentDisposition.FileName); + Assert.Equal(mediaType, parts[1].Headers.ContentType.MediaType); + var result1 = await serializer + .FromHttpContentAsync(parts[1]) + .ConfigureAwait(false); + Assert.Equal(model2.Property1, result1.Property1); + Assert.Equal(model2.Property2, result1.Property2); + } + }; - [Fact] - public async Task MultipartUploadShouldWorkWithMixedTypes() + var settings = new RefitSettings() { - var fileName = Path.GetTempFileName(); - var name = Path.GetFileName(fileName); + HttpMessageHandlerFactory = () => handler, + ContentSerializer = serializer + }; - var model1 = new ModelObject { Property1 = "M1.prop1", Property2 = "M1.prop2" }; + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadJsonObjects(new[] { model1, model2 }); + } - var model2 = new ModelObject { Property1 = "M2.prop1" }; + [Fact] + public async Task MultipartUploadShouldWorkWithMixedTypes() + { + var fileName = Path.GetTempFileName(); + var name = Path.GetFileName(fileName); - var anotherModel = new AnotherModel { Foos = new[] { "bar1", "bar2" } }; + var model1 = new ModelObject { Property1 = "M1.prop1", Property2 = "M1.prop2" }; - var handler = new MockHttpMessageHandler - { - Asserts = async content => - { - var parts = content.ToList(); - - Assert.Equal(7, parts.Count); - - Assert.Equal("theObjects", parts[0].Headers.ContentDisposition.Name); - Assert.Null(parts[0].Headers.ContentDisposition.FileName); - Assert.Equal("application/json", parts[0].Headers.ContentType.MediaType); - var result0 = JsonConvert.DeserializeObject( - await parts[0].ReadAsStringAsync().ConfigureAwait(false) - ); - Assert.Equal(model1.Property1, result0.Property1); - Assert.Equal(model1.Property2, result0.Property2); - - Assert.Equal("theObjects", parts[1].Headers.ContentDisposition.Name); - Assert.Null(parts[1].Headers.ContentDisposition.FileName); - Assert.Equal("application/json", parts[1].Headers.ContentType.MediaType); - var result1 = JsonConvert.DeserializeObject( - await parts[1].ReadAsStringAsync().ConfigureAwait(false) - ); - Assert.Equal(model2.Property1, result1.Property1); - Assert.Equal(model2.Property2, result1.Property2); - - Assert.Equal("anotherModel", parts[2].Headers.ContentDisposition.Name); - Assert.Null(parts[2].Headers.ContentDisposition.FileName); - Assert.Equal("application/json", parts[2].Headers.ContentType.MediaType); - var result2 = JsonConvert.DeserializeObject( - await parts[2].ReadAsStringAsync().ConfigureAwait(false) - ); - Assert.Equal(2, result2.Foos.Length); - Assert.Equal("bar1", result2.Foos[0]); - Assert.Equal("bar2", result2.Foos[1]); - - Assert.Equal("aFile", parts[3].Headers.ContentDisposition.Name); - Assert.Equal(name, parts[3].Headers.ContentDisposition.FileName); - Assert.Null(parts[3].Headers.ContentType); - using (var str = await parts[3].ReadAsStreamAsync()) - using (var src = GetTestFileStream("Test Files/Test.pdf")) - { - Assert.True(StreamsEqual(src, str)); - } - - Assert.Equal("anEnum", parts[4].Headers.ContentDisposition.Name); - Assert.Null(parts[4].Headers.ContentDisposition.FileName); - Assert.Equal("application/json", parts[4].Headers.ContentType.MediaType); - var result4 = JsonConvert.DeserializeObject( - await parts[4].ReadAsStringAsync().ConfigureAwait(false) - ); - Assert.Equal(AnEnum.Val2, result4); - - Assert.Equal("aString", parts[5].Headers.ContentDisposition.Name); - Assert.Null(parts[5].Headers.ContentDisposition.FileName); - Assert.Equal("text/plain", parts[5].Headers.ContentType.MediaType); - Assert.Equal("utf-8", parts[5].Headers.ContentType.CharSet); - Assert.Equal("frob", await parts[5].ReadAsStringAsync()); - - Assert.Equal("anInt", parts[6].Headers.ContentDisposition.Name); - Assert.Null(parts[6].Headers.ContentDisposition.FileName); - Assert.Equal("application/json", parts[6].Headers.ContentType.MediaType); - var result6 = JsonConvert.DeserializeObject( - await parts[6].ReadAsStringAsync().ConfigureAwait(false) - ); - Assert.Equal(42, result6); - } - }; - - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + var model2 = new ModelObject { Property1 = "M2.prop1" }; - try - { - using var stream = GetTestFileStream("Test Files/Test.pdf"); - using var outStream = File.OpenWrite(fileName); - await stream.CopyToAsync(outStream); - await outStream.FlushAsync(); - outStream.Close(); - - var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadMixedObjects( - new[] { model1, model2 }, - anotherModel, - new FileInfo(fileName), - AnEnum.Val2, - "frob", - 42 - ); - } - finally - { - File.Delete(fileName); - } - } + var anotherModel = new AnotherModel { Foos = new[] { "bar1", "bar2" } }; - [Fact] - public async Task MultipartUploadShouldWorkWithHttpContent() + var handler = new MockHttpMessageHandler { - var httpContent = new StringContent("some text", Encoding.ASCII, "application/custom"); - httpContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") + Asserts = async content => { - Name = "myName", - FileName = "myFileName", - }; + var parts = content.ToList(); - var handler = new MockHttpMessageHandler - { - Asserts = async content => + Assert.Equal(7, parts.Count); + + Assert.Equal("theObjects", parts[0].Headers.ContentDisposition.Name); + Assert.Null(parts[0].Headers.ContentDisposition.FileName); + Assert.Equal("application/json", parts[0].Headers.ContentType.MediaType); + var result0 = JsonConvert.DeserializeObject( + await parts[0].ReadAsStringAsync().ConfigureAwait(false) + ); + Assert.Equal(model1.Property1, result0.Property1); + Assert.Equal(model1.Property2, result0.Property2); + + Assert.Equal("theObjects", parts[1].Headers.ContentDisposition.Name); + Assert.Null(parts[1].Headers.ContentDisposition.FileName); + Assert.Equal("application/json", parts[1].Headers.ContentType.MediaType); + var result1 = JsonConvert.DeserializeObject( + await parts[1].ReadAsStringAsync().ConfigureAwait(false) + ); + Assert.Equal(model2.Property1, result1.Property1); + Assert.Equal(model2.Property2, result1.Property2); + + Assert.Equal("anotherModel", parts[2].Headers.ContentDisposition.Name); + Assert.Null(parts[2].Headers.ContentDisposition.FileName); + Assert.Equal("application/json", parts[2].Headers.ContentType.MediaType); + var result2 = JsonConvert.DeserializeObject( + await parts[2].ReadAsStringAsync().ConfigureAwait(false) + ); + Assert.Equal(2, result2.Foos.Length); + Assert.Equal("bar1", result2.Foos[0]); + Assert.Equal("bar2", result2.Foos[1]); + + Assert.Equal("aFile", parts[3].Headers.ContentDisposition.Name); + Assert.Equal(name, parts[3].Headers.ContentDisposition.FileName); + Assert.Null(parts[3].Headers.ContentType); + using (var str = await parts[3].ReadAsStreamAsync()) + using (var src = GetTestFileStream("Test Files/Test.pdf")) { - var parts = content.ToList(); + Assert.True(StreamsEqual(src, str)); + } - Assert.Single(parts); + Assert.Equal("anEnum", parts[4].Headers.ContentDisposition.Name); + Assert.Null(parts[4].Headers.ContentDisposition.FileName); + Assert.Equal("application/json", parts[4].Headers.ContentType.MediaType); + var result4 = JsonConvert.DeserializeObject( + await parts[4].ReadAsStringAsync().ConfigureAwait(false) + ); + Assert.Equal(AnEnum.Val2, result4); + + Assert.Equal("aString", parts[5].Headers.ContentDisposition.Name); + Assert.Null(parts[5].Headers.ContentDisposition.FileName); + Assert.Equal("text/plain", parts[5].Headers.ContentType.MediaType); + Assert.Equal("utf-8", parts[5].Headers.ContentType.CharSet); + Assert.Equal("frob", await parts[5].ReadAsStringAsync()); + + Assert.Equal("anInt", parts[6].Headers.ContentDisposition.Name); + Assert.Null(parts[6].Headers.ContentDisposition.FileName); + Assert.Equal("application/json", parts[6].Headers.ContentType.MediaType); + var result6 = JsonConvert.DeserializeObject( + await parts[6].ReadAsStringAsync().ConfigureAwait(false) + ); + Assert.Equal(42, result6); + } + }; - Assert.Equal("myName", parts[0].Headers.ContentDisposition.Name); - Assert.Equal("myFileName", parts[0].Headers.ContentDisposition.FileName); - Assert.Equal("application/custom", parts[0].Headers.ContentType.MediaType); - var result0 = await parts[0].ReadAsStringAsync().ConfigureAwait(false); - Assert.Equal("some text", result0); - } - }; + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; + try + { + using var stream = GetTestFileStream("Test Files/Test.pdf"); + using var outStream = File.OpenWrite(fileName); + await stream.CopyToAsync(outStream); + await outStream.FlushAsync(); + outStream.Close(); var fixture = RestService.For(BaseAddress, settings); - var result = await fixture.UploadHttpContent(httpContent); + var result = await fixture.UploadMixedObjects( + new[] { model1, model2 }, + anotherModel, + new FileInfo(fileName), + AnEnum.Val2, + "frob", + 42 + ); } - - [Fact] - public void MultiPartConstructorShouldThrowArgumentNullExceptionWhenNoFileName() + finally { - Assert.Throws(() => - { - var byteArrayPart = new ByteArrayPart(Array.Empty(), null, "application/pdf"); - }); + File.Delete(fileName); } + } - [Fact] - public void FileInfoPartConstructorShouldThrowArgumentNullExceptionWhenNoFileInfo() + [Fact] + public async Task MultipartUploadShouldWorkWithHttpContent() + { + var httpContent = new StringContent("some text", Encoding.ASCII, "application/custom"); + httpContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { - Assert.Throws(() => - { - var fileInfoPart = new FileInfoPart(null, "file.pdf", "application/pdf"); - }); - } + Name = "myName", + FileName = "myFileName", + }; - internal static Stream GetTestFileStream(string relativeFilePath) + var handler = new MockHttpMessageHandler { - const char namespaceSeparator = '.'; - - // get calling assembly - var assembly = Assembly.GetCallingAssembly(); + Asserts = async content => + { + var parts = content.ToList(); - // compute resource name suffix - var relativeName = - "." - + relativeFilePath - .Replace('\\', namespaceSeparator) - .Replace('/', namespaceSeparator) - .Replace(' ', '_'); + Assert.Single(parts); - // get resource stream - var fullName = assembly - .GetManifestResourceNames() - .FirstOrDefault( - name => name.EndsWith(relativeName, StringComparison.InvariantCulture) - ); - if (fullName == null) - { - throw new Exception( - $"Unable to find resource for path \"{relativeFilePath}\". Resource with name ending on \"{relativeName}\" was not found in assembly." - ); + Assert.Equal("myName", parts[0].Headers.ContentDisposition.Name); + Assert.Equal("myFileName", parts[0].Headers.ContentDisposition.FileName); + Assert.Equal("application/custom", parts[0].Headers.ContentType.MediaType); + var result0 = await parts[0].ReadAsStringAsync().ConfigureAwait(false); + Assert.Equal("some text", result0); } + }; - var stream = assembly.GetManifestResourceStream(fullName); - if (stream == null) - { - throw new Exception( - $"Unable to find resource for path \"{relativeFilePath}\". Resource named \"{fullName}\" was not found in assembly." - ); - } + var settings = new RefitSettings() { HttpMessageHandlerFactory = () => handler }; - return stream; - } + var fixture = RestService.For(BaseAddress, settings); + var result = await fixture.UploadHttpContent(httpContent); + } - static bool StreamsEqual(Stream a, Stream b) + [Fact] + public void MultiPartConstructorShouldThrowArgumentNullExceptionWhenNoFileName() + { + Assert.Throws(() => { - if (a == null && b == null) - return true; - if (a == null || b == null) - { - throw new ArgumentNullException(a == null ? "a" : "b"); - } + var byteArrayPart = new ByteArrayPart(Array.Empty(), null, "application/pdf"); + }); + } - if (a.Length < b.Length) - return false; - if (a.Length > b.Length) - return false; + [Fact] + public void FileInfoPartConstructorShouldThrowArgumentNullExceptionWhenNoFileInfo() + { + Assert.Throws(() => + { + var fileInfoPart = new FileInfoPart(null, "file.pdf", "application/pdf"); + }); + } - for (var i = 0; i < a.Length; i++) - { - var aByte = a.ReadByte(); - var bByte = b.ReadByte(); - if (aByte != bByte) - return false; - } + internal static Stream GetTestFileStream(string relativeFilePath) + { + const char namespaceSeparator = '.'; + + // get calling assembly + var assembly = Assembly.GetCallingAssembly(); + + // compute resource name suffix + var relativeName = + "." + + relativeFilePath + .Replace('\\', namespaceSeparator) + .Replace('/', namespaceSeparator) + .Replace(' ', '_'); + + // get resource stream + var fullName = assembly + .GetManifestResourceNames() + .FirstOrDefault( + name => name.EndsWith(relativeName, StringComparison.InvariantCulture) + ); + if (fullName == null) + { + throw new Exception( + $"Unable to find resource for path \"{relativeFilePath}\". Resource with name ending on \"{relativeName}\" was not found in assembly." + ); + } + var stream = assembly.GetManifestResourceStream(fullName); + if (stream == null) + { + throw new Exception( + $"Unable to find resource for path \"{relativeFilePath}\". Resource named \"{fullName}\" was not found in assembly." + ); + } + + return stream; + } + + static bool StreamsEqual(Stream a, Stream b) + { + if (a == null && b == null) return true; + if (a == null || b == null) + { + throw new ArgumentNullException(a == null ? "a" : "b"); } - class MockHttpMessageHandler : HttpMessageHandler + if (a.Length < b.Length) + return false; + if (a.Length > b.Length) + return false; + + for (var i = 0; i < a.Length; i++) { - public Action RequestAsserts { get; set; } - public Func Asserts { get; set; } + var aByte = a.ReadByte(); + var bByte = b.ReadByte(); + if (aByte != bByte) + return false; + } - protected override async Task SendAsync( - HttpRequestMessage request, - CancellationToken cancellationToken - ) - { - RequestAsserts?.Invoke(request); - var content = request.Content as MultipartFormDataContent; - Assert.IsType(content); - Assert.NotNull(Asserts); + return true; + } - await Asserts(content); + class MockHttpMessageHandler : HttpMessageHandler + { + public Action RequestAsserts { get; set; } + public Func Asserts { get; set; } - return new HttpResponseMessage(HttpStatusCode.OK); - } + protected override async Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken + ) + { + RequestAsserts?.Invoke(request); + var content = request.Content as MultipartFormDataContent; + Assert.IsType(content); + Assert.NotNull(Asserts); + + await Asserts(content); + + return new HttpResponseMessage(HttpStatusCode.OK); } } } diff --git a/Refit.Tests/MyQueryParams.cs b/Refit.Tests/MyQueryParams.cs index ede5b3e83..717a81a26 100644 --- a/Refit.Tests/MyQueryParams.cs +++ b/Refit.Tests/MyQueryParams.cs @@ -2,34 +2,33 @@ using System.Collections.Generic; using System.Text; -namespace Refit.Tests +namespace Refit.Tests; + +public record MySimpleQueryParams { - public record MySimpleQueryParams - { - public string FirstName { get; set; } + public string FirstName { get; set; } - [AliasAs("lName")] - public string LastName { get; set; } - } + [AliasAs("lName")] + public string LastName { get; set; } +} - public class MyComplexQueryParams - { - public string FirstName { get; set; } +public class MyComplexQueryParams +{ + public string FirstName { get; set; } - public string LastName { get; set; } + public string LastName { get; set; } - [AliasAs("Addr")] - public Address Address { get; set; } = new Address(); + [AliasAs("Addr")] + public Address Address { get; set; } = new Address(); - public Dictionary MetaData { get; set; } = new Dictionary(); + public Dictionary MetaData { get; set; } = new Dictionary(); - public List Other { get; set; } = new List(); - } + public List Other { get; set; } = new List(); +} - public record Address - { - [AliasAs("Zip")] - public int Postcode { get; set; } - public string Street { get; set; } - } +public record Address +{ + [AliasAs("Zip")] + public int Postcode { get; set; } + public string Street { get; set; } } diff --git a/Refit.Tests/NullableReferenceTypes.cs b/Refit.Tests/NullableReferenceTypes.cs index 8ab2d19a6..dd913dcc2 100644 --- a/Refit.Tests/NullableReferenceTypes.cs +++ b/Refit.Tests/NullableReferenceTypes.cs @@ -3,99 +3,98 @@ using System.Threading.Tasks; using Refit; // InterfaceStubGenerator looks for this -namespace Refit.Tests +namespace Refit.Tests; + +interface IGenericWithResultService +{ + [Get("/")] + Task Get(); +} + +interface IGenericWithNullableValueService +{ + [Get("/")] + Task Get(); +} + +interface IGenericNullableReferenceService +{ + [Get("/")] + Task? Get(); +} + +interface IGenericNullableValueService { - interface IGenericWithResultService - { - [Get("/")] - Task Get(); - } - - interface IGenericWithNullableValueService - { - [Get("/")] - Task Get(); - } - - interface IGenericNullableReferenceService - { - [Get("/")] - Task? Get(); - } - - interface IGenericNullableValueService - { - [Get("/")] - ValueTask? Get(); - } - - interface IGenericNullableWithNullableReferenceService - { - [Get("/")] - Task? Get(); - } - - interface IGenericNullableWithNullableValueService - { - [Get("/")] - ValueTask? Get(); - } - - interface INullableReferenceService - { - [Get("/")] - string? Get(); - } - - interface INullableValueService - { - [Get("/")] - int? Get(); - } - - interface IReferenceAndValueParametersService - { - [Get("/")] - Task Get(string? reference, int? value); - } - - interface IGenericNullableReferenceParameterService - { - [Get("/")] - Task Get(System.Collections.Generic.List? reference); - } - - interface IGenericWithNullableReferenceParameterService - { - [Get("/")] - Task Get(System.Collections.Generic.List reference); - } - - interface IGenericNullableWithNullableReferenceParameterService - { - [Get("/")] - Task Get(System.Collections.Generic.List? reference); - } - - interface ICustomNullableReferenceService - { - [Get("/")] - CustomReferenceType? Get(); - } - - interface ICustomNullableValueService - { - [Get("/")] - CustomValueType? Get(); - } - - interface ICustomReferenceAndValueParametersService - { - [Get("/")] - Task Get(CustomReferenceType? reference, CustomValueType? value); - } - - class CustomReferenceType { } - - class CustomValueType { } + [Get("/")] + ValueTask? Get(); } + +interface IGenericNullableWithNullableReferenceService +{ + [Get("/")] + Task? Get(); +} + +interface IGenericNullableWithNullableValueService +{ + [Get("/")] + ValueTask? Get(); +} + +interface INullableReferenceService +{ + [Get("/")] + string? Get(); +} + +interface INullableValueService +{ + [Get("/")] + int? Get(); +} + +interface IReferenceAndValueParametersService +{ + [Get("/")] + Task Get(string? reference, int? value); +} + +interface IGenericNullableReferenceParameterService +{ + [Get("/")] + Task Get(System.Collections.Generic.List? reference); +} + +interface IGenericWithNullableReferenceParameterService +{ + [Get("/")] + Task Get(System.Collections.Generic.List reference); +} + +interface IGenericNullableWithNullableReferenceParameterService +{ + [Get("/")] + Task Get(System.Collections.Generic.List? reference); +} + +interface ICustomNullableReferenceService +{ + [Get("/")] + CustomReferenceType? Get(); +} + +interface ICustomNullableValueService +{ + [Get("/")] + CustomValueType? Get(); +} + +interface ICustomReferenceAndValueParametersService +{ + [Get("/")] + Task Get(CustomReferenceType? reference, CustomValueType? value); +} + +class CustomReferenceType { } + +class CustomValueType { } diff --git a/Refit.Tests/PartialInterfacesApi.First.cs b/Refit.Tests/PartialInterfacesApi.First.cs index 76b6e11ef..3b1c24235 100644 --- a/Refit.Tests/PartialInterfacesApi.First.cs +++ b/Refit.Tests/PartialInterfacesApi.First.cs @@ -1,11 +1,10 @@ using System.Threading.Tasks; using Refit; // InterfaceStubGenerator looks for this -namespace Refit.Tests +namespace Refit.Tests; + +public partial interface PartialInterfacesApi { - public partial interface PartialInterfacesApi - { - [Get("/get?result=First")] - Task First(); - } + [Get("/get?result=First")] + Task First(); } diff --git a/Refit.Tests/PartialInterfacesApi.Second.cs b/Refit.Tests/PartialInterfacesApi.Second.cs index 3c43249d8..df75eac1a 100644 --- a/Refit.Tests/PartialInterfacesApi.Second.cs +++ b/Refit.Tests/PartialInterfacesApi.Second.cs @@ -1,11 +1,10 @@ using System.Threading.Tasks; using Refit; // InterfaceStubGenerator looks for this -namespace Refit.Tests +namespace Refit.Tests; + +public partial interface PartialInterfacesApi { - public partial interface PartialInterfacesApi - { - [Get("/get?result=Second")] - Task Second(); - } + [Get("/get?result=Second")] + Task Second(); } diff --git a/Refit.Tests/Refit.Tests.csproj b/Refit.Tests/Refit.Tests.csproj index 752e54f57..8d436be51 100644 --- a/Refit.Tests/Refit.Tests.csproj +++ b/Refit.Tests/Refit.Tests.csproj @@ -3,7 +3,7 @@ - net462;net6.0;net7.0;net8.0 + net462;net6.0;net8.0 false https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json $(NoWarn);CS1591;CA1819;CA2000;CA2007;CA1056;CA1707;CA1861;xUnit1031 diff --git a/Refit.Tests/RequestBuilder.cs b/Refit.Tests/RequestBuilder.cs index 48ca590e2..a1ceff4c9 100644 --- a/Refit.Tests/RequestBuilder.cs +++ b/Refit.Tests/RequestBuilder.cs @@ -14,3922 +14,3921 @@ using Xunit; -namespace Refit.Tests +namespace Refit.Tests; + +[Headers("User-Agent: RefitTestClient", "Api-Version: 1")] +public interface IRestMethodInfoTests { - [Headers("User-Agent: RefitTestClient", "Api-Version: 1")] - public interface IRestMethodInfoTests - { - [Get("@)!@_!($_!@($\\\\|||::::")] - Task GarbagePath(); + [Get("@)!@_!($_!@($\\\\|||::::")] + Task GarbagePath(); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffMissingParameters(); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuff(int id); + + [Get("/foo/bar/{id}?param1={id}¶m2={id}")] + Task FetchSomeStuffWithTheSameId(int id); + + [Get("/foo/bar?param=first {id} and second {id}")] + Task FetchSomeStuffWithTheIdInAParameterMultipleTimes(int id); + + [Get("/foo/bar/{**path}/{id}")] + Task FetchSomeStuffWithRoundTrippingParam(string path, int id); + + [Get("/foo/bar/{**path}/{id}")] + Task FetchSomeStuffWithNonStringRoundTrippingParam(int path, int id); + + [Get("/foo/bar/{id}?baz=bamf")] + Task FetchSomeStuffWithHardcodedQueryParam(int id); + + [Get("/foo/bar/{id}?baz=bamf")] + Task FetchSomeStuffWithQueryParam(int id, string search); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithAlias([AliasAs("id")] int anId); + + [Get("/foo/bar/{width}x{height}")] + Task FetchAnImage(int width, int height); + + [Get("/foo/bar/{id}")] + IObservable FetchSomeStuffWithBody( + [AliasAs("id")] int anId, + [Body] Dictionary theData + ); + + [Post("/foo/bar/{id}")] + IObservable PostSomeUrlEncodedStuff( + [AliasAs("id")] int anId, + [Body(BodySerializationMethod.UrlEncoded)] Dictionary theData + ); + + [Get("/foo/bar/{id}")] + IObservable FetchSomeStuffWithAuthorizationSchemeSpecified( + [AliasAs("id")] int anId, + [Authorize("Bearer")] string token + ); + + [Get("/foo/bar/{id}")] + [Headers("Api-Version: 2", "Accept: application/json")] + Task FetchSomeStuffWithHardcodedHeaders(int id); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicHeader( + int id, + [Header("Authorization")] string authorization + ); + + [Get("/foo")] + Task FetchSomeStuffWithDynamicHeaderQueryParamAndArrayQueryParam( + [Header("Authorization")] string authorization, + int id, + [Query(CollectionFormat.Multi)] string[] someArray, + [Property("SomeProperty")] object someValue + ); + + #region [HeaderCollection] interface methods + + [Get("/foo/bar/{id}")] + [Headers( + "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", + "Accept: application/json" + )] + Task FetchSomeStuffWithDynamicHeaderCollection( + int id, + [HeaderCollection] IDictionary headers + ); + + [Put("/foo/bar/{id}")] + Task PutSomeStuffWithCustomHeaderCollection( + int id, + [Body] object body, + [HeaderCollection] IDictionary headers + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithCustomHeaderCollection( + int id, + [Body] object body, + [HeaderCollection] IDictionary headers + ); + + [Patch("/foo/bar/{id}")] + Task PatchSomeStuffWithCustomHeaderCollection( + int id, + [Body] object body, + [HeaderCollection] IDictionary headers + ); + + [Put("/foo/bar/{id}")] + Task PutSomeStuffWithoutBodyAndCustomHeaderCollection( + int id, + [HeaderCollection] IDictionary headers + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithoutBodyAndCustomHeaderCollection( + int id, + [HeaderCollection] IDictionary headers + ); + + [Patch("/foo/bar/{id}")] + Task PatchSomeStuffWithoutBodyAndCustomHeaderCollection( + int id, + [HeaderCollection] IDictionary headers + ); + + [Put("/foo/bar/{id}")] + Task PutSomeStuffWithInferredBodyAndWithDynamicHeaderCollection( + int id, + [HeaderCollection] IDictionary headers, + object inferredBody + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithInferredBodyAndWithDynamicHeaderCollection( + int id, + [HeaderCollection] IDictionary headers, + object inferredBody + ); + + [Patch("/foo/bar/{id}")] + Task PatchSomeStuffWithInferredBodyAndWithDynamicHeaderCollection( + int id, + [HeaderCollection] IDictionary headers, + object inferredBody + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicHeaderCollectionAndAuthorize( + int id, + [Authorize] string value, + [HeaderCollection] IDictionary headers + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithDynamicHeaderCollectionAndAuthorize( + int id, + [Authorize] string value, + [HeaderCollection] IDictionary headers + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeader( + int id, + [Header("Authorization")] string value, + [HeaderCollection] IDictionary headers + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithDynamicHeaderCollectionAndDynamicHeader( + int id, + [Header("Authorization")] string value, + [HeaderCollection] IDictionary headers + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped( + int id, + [HeaderCollection] IDictionary headers, + [Header("Authorization")] string value + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithPathMemberInCustomHeaderAndDynamicHeaderCollection( + [Header("X-PathMember")] int id, + [HeaderCollection] IDictionary headers + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithPathMemberInCustomHeaderAndDynamicHeaderCollection( + [Header("X-PathMember")] int id, + [HeaderCollection] IDictionary headers + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithHeaderCollection( + int id, + [HeaderCollection] IDictionary headers, + int baz + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithHeaderCollection( + int id, + [HeaderCollection] IDictionary headers, + int baz + ); + + [Get("/foo/bar")] + Task FetchSomeStuffWithDuplicateHeaderCollection( + [HeaderCollection] IDictionary headers, + [HeaderCollection] IDictionary headers2 + ); + + [Post("/foo/bar")] + Task PostSomeStuffWithDuplicateHeaderCollection( + [HeaderCollection] IDictionary headers, + [HeaderCollection] IDictionary headers2 + ); + + [Get("/foo")] + Task FetchSomeStuffWithHeaderCollectionQueryParamAndArrayQueryParam( + [HeaderCollection] IDictionary headers, + int id, + [Query(CollectionFormat.Multi)] string[] someArray, + [Property("SomeProperty")] object someValue + ); + + [Post("/foo")] + Task PostSomeStuffWithHeaderCollectionQueryParamAndArrayQueryParam( + [HeaderCollection] IDictionary headers, + int id, + [Query(CollectionFormat.Multi)] string[] someArray, + [Property("SomeProperty")] object someValue + ); + + [Get("/foo")] + Task FetchSomeStuffWithHeaderCollectionOfUnsupportedType( + [HeaderCollection] string headers + ); + + [Post("/foo")] + Task PostSomeStuffWithHeaderCollectionOfUnsupportedType( + [HeaderCollection] string headers + ); + + #endregion + + #region [Property] interface methods + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someValue + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithDynamicRequestProperty( + int id, + [Body] object body, + [Property("SomeProperty")] object someValue + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithDynamicRequestProperties( + int id, + [Body] object body, + [Property("SomeProperty")] object someValue, + [Property("SomeOtherProperty")] object someOtherValue + ); + + [Put("/foo/bar/{id}")] + Task PutSomeStuffWithoutBodyAndWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someValue + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithoutBodyAndWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someValue + ); + + [Patch("/foo/bar/{id}")] + Task PatchSomeStuffWithoutBodyAndWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someValue + ); + + [Put("/foo/bar/{id}")] + Task PutSomeStuffWithInferredBodyAndWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someValue, + object inferredBody + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithInferredBodyAndWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someValue, + object inferredBody + ); + + [Patch("/foo/bar/{id}")] + Task PatchSomeStuffWithInferredBodyAndWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someValue, + object inferredBody + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey( + int id, + [Property("SomeProperty")] object someValue1, + [Property("SomeProperty")] object someValue2 + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicRequestPropertyWithoutKey( + int id, + [Property] object someValue, + [Property("")] object someOtherValue + ); + + #endregion + + [Post("/foo/{id}")] + Task OhYeahValueTypes(int id, [Body(buffered: true)] int whatever); + + [Post("/foo/{id}")] + Task OhYeahValueTypesUnbuffered(int id, [Body(buffered: false)] int whatever); + + [Post("/foo/{id}")] + Task PullStreamMethod(int id, [Body(buffered: true)] Dictionary theData); + + [Post("/foo/{id}")] + Task VoidPost(int id); + + [Post("/foo/{id}")] + string AsyncOnlyBuddy(int id); + + [Patch("/foo/{id}")] + IObservable PatchSomething(int id, [Body] string someAttribute); + + [Options("/foo/{id}")] + Task SendOptions(int id, [Body] string someAttribute); + + [Post("/foo/{id}")] + Task> PostReturnsApiResponse(int id); + + [Post("/foo/{id}")] + Task PostReturnsNonApiResponse(int id); + + [Post("/foo")] + Task PostWithBodyDetected(Dictionary theData); + + [Get("/foo")] + Task GetWithBodyDetected(Dictionary theData); + + [Put("/foo")] + Task PutWithBodyDetected(Dictionary theData); + + [Patch("/foo")] + Task PatchWithBodyDetected(Dictionary theData); + + [Post("/foo")] + Task TooManyComplexTypes(Dictionary theData, Dictionary theData1); + + [Post("/foo")] + Task ManyComplexTypes( + Dictionary theData, + [Body] Dictionary theData1 + ); + + [Post("/foo")] + Task PostWithDictionaryQuery([Query] Dictionary theData); + + [Post("/foo")] + Task PostWithComplexTypeQuery([Query] ComplexQueryObject queryParams); + + [Post("/foo")] + Task ImpliedComplexQueryType( + ComplexQueryObject queryParams, + [Body] Dictionary theData1 + ); + + [Get("/api/{id}")] + Task MultipleQueryAttributes( + int id, + [Query] string text = null, + [Query] int? optionalId = null, + [Query(CollectionFormat = CollectionFormat.Multi)] string[] filters = null + ); + + [Get("/api/{id}")] + Task NullableValues( + int id, + string text = null, + int? optionalId = null, + [Query(CollectionFormat = CollectionFormat.Multi)] string[] filters = null + ); - [Get("/foo/bar/{id}")] - Task FetchSomeStuffMissingParameters(); + [Get("/api/{id}")] + Task IEnumerableThrowingError([Query(CollectionFormat.Multi)] IEnumerable values); - [Get("/foo/bar/{id}")] - Task FetchSomeStuff(int id); + [Get("/foo")] + List InvalidGenericReturnType(); +} - [Get("/foo/bar/{id}?param1={id}¶m2={id}")] - Task FetchSomeStuffWithTheSameId(int id); +public enum TestEnum +{ + A, + B, + C +} - [Get("/foo/bar?param=first {id} and second {id}")] - Task FetchSomeStuffWithTheIdInAParameterMultipleTimes(int id); +public class ComplexQueryObject +{ + [AliasAs("test-query-alias")] + public string TestAlias1 { get; set; } - [Get("/foo/bar/{**path}/{id}")] - Task FetchSomeStuffWithRoundTrippingParam(string path, int id); + public string TestAlias2 { get; set; } - [Get("/foo/bar/{**path}/{id}")] - Task FetchSomeStuffWithNonStringRoundTrippingParam(int path, int id); + public IEnumerable TestCollection { get; set; } - [Get("/foo/bar/{id}?baz=bamf")] - Task FetchSomeStuffWithHardcodedQueryParam(int id); + [AliasAs("test-dictionary-alias")] + public Dictionary TestAliasedDictionary { get; set; } - [Get("/foo/bar/{id}?baz=bamf")] - Task FetchSomeStuffWithQueryParam(int id, string search); + public Dictionary TestDictionary { get; set; } - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithAlias([AliasAs("id")] int anId); + [AliasAs("listOfEnumMulti")] + [Query(CollectionFormat.Multi)] + public List EnumCollectionMulti { get; set; } - [Get("/foo/bar/{width}x{height}")] - Task FetchAnImage(int width, int height); + [Query(CollectionFormat.Multi)] + public List ObjectCollectionMulti { get; set; } - [Get("/foo/bar/{id}")] - IObservable FetchSomeStuffWithBody( - [AliasAs("id")] int anId, - [Body] Dictionary theData - ); + [Query(CollectionFormat.Csv)] + public List EnumCollectionCsv { get; set; } - [Post("/foo/bar/{id}")] - IObservable PostSomeUrlEncodedStuff( - [AliasAs("id")] int anId, - [Body(BodySerializationMethod.UrlEncoded)] Dictionary theData - ); + [AliasAs("listOfObjectsCsv")] + [Query(CollectionFormat.Csv)] + public List ObjectCollectionCcv { get; set; } +} - [Get("/foo/bar/{id}")] - IObservable FetchSomeStuffWithAuthorizationSchemeSpecified( - [AliasAs("id")] int anId, - [Authorize("Bearer")] string token - ); +public class RestMethodInfoTests +{ + [Fact] + public void TooManyComplexTypesThrows() + { + var input = typeof(IRestMethodInfoTests); - [Get("/foo/bar/{id}")] - [Headers("Api-Version: 2", "Accept: application/json")] - Task FetchSomeStuffWithHardcodedHeaders(int id); + Assert.Throws(() => + { + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.TooManyComplexTypes)) + ); + }); + } - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicHeader( - int id, - [Header("Authorization")] string authorization + [Fact] + public void ManyComplexTypes() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.ManyComplexTypes)) ); - [Get("/foo")] - Task FetchSomeStuffWithDynamicHeaderQueryParamAndArrayQueryParam( - [Header("Authorization")] string authorization, - int id, - [Query(CollectionFormat.Multi)] string[] someArray, - [Property("SomeProperty")] object someValue + Assert.Single(fixture.QueryParameterMap); + Assert.NotNull(fixture.BodyParameterInfo); + Assert.Equal(1, fixture.BodyParameterInfo.Item3); + } + + [Theory] + [InlineData(nameof(IRestMethodInfoTests.PutWithBodyDetected))] + [InlineData(nameof(IRestMethodInfoTests.PostWithBodyDetected))] + [InlineData(nameof(IRestMethodInfoTests.PatchWithBodyDetected))] + public void DefaultBodyParameterDetected(string interfaceMethodName) + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) ); - #region [HeaderCollection] interface methods + Assert.Empty(fixture.QueryParameterMap); + Assert.NotNull(fixture.BodyParameterInfo); + } - [Get("/foo/bar/{id}")] - [Headers( - "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", - "Accept: application/json" - )] - Task FetchSomeStuffWithDynamicHeaderCollection( - int id, - [HeaderCollection] IDictionary headers + [Fact] + public void DefaultBodyParameterNotDetectedForGet() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.GetWithBodyDetected)) ); - [Put("/foo/bar/{id}")] - Task PutSomeStuffWithCustomHeaderCollection( - int id, - [Body] object body, - [HeaderCollection] IDictionary headers - ); + Assert.Single(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); + } - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithCustomHeaderCollection( - int id, - [Body] object body, - [HeaderCollection] IDictionary headers + [Fact] + public void PostWithDictionaryQueryParameter() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.PostWithDictionaryQuery)) ); - [Patch("/foo/bar/{id}")] - Task PatchSomeStuffWithCustomHeaderCollection( - int id, - [Body] object body, - [HeaderCollection] IDictionary headers - ); + Assert.Single(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); + } - [Put("/foo/bar/{id}")] - Task PutSomeStuffWithoutBodyAndCustomHeaderCollection( - int id, - [HeaderCollection] IDictionary headers + [Fact] + public void PostWithObjectQueryParameterHasSingleQueryParameterValue() + { + var input = typeof(IRestMethodInfoTests); + var fixtureParams = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.PostWithComplexTypeQuery)) ); - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithoutBodyAndCustomHeaderCollection( - int id, - [HeaderCollection] IDictionary headers - ); + Assert.Single(fixtureParams.QueryParameterMap); + Assert.Equal("queryParams", fixtureParams.QueryParameterMap[0]); + Assert.Null(fixtureParams.BodyParameterInfo); + } - [Patch("/foo/bar/{id}")] - Task PatchSomeStuffWithoutBodyAndCustomHeaderCollection( - int id, - [HeaderCollection] IDictionary headers - ); + [Fact] + public void PostWithObjectQueryParameterHasCorrectQuerystring() + { + var fixture = new RequestBuilderImplementation(); - [Put("/foo/bar/{id}")] - Task PutSomeStuffWithInferredBodyAndWithDynamicHeaderCollection( - int id, - [HeaderCollection] IDictionary headers, - object inferredBody + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.PostWithComplexTypeQuery) ); - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithInferredBodyAndWithDynamicHeaderCollection( - int id, - [HeaderCollection] IDictionary headers, - object inferredBody - ); + var param = new ComplexQueryObject { TestAlias1 = "one", TestAlias2 = "two" }; - [Patch("/foo/bar/{id}")] - Task PatchSomeStuffWithInferredBodyAndWithDynamicHeaderCollection( - int id, - [HeaderCollection] IDictionary headers, - object inferredBody - ); + var output = factory(new object[] { param }); - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicHeaderCollectionAndAuthorize( - int id, - [Authorize] string value, - [HeaderCollection] IDictionary headers - ); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithDynamicHeaderCollectionAndAuthorize( - int id, - [Authorize] string value, - [HeaderCollection] IDictionary headers - ); + Assert.Equal("/foo?test-query-alias=one&TestAlias2=two", uri.PathAndQuery); + } - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeader( - int id, - [Header("Authorization")] string value, - [HeaderCollection] IDictionary headers - ); + [Fact] + public void PostWithObjectQueryParameterWithEnumList_Multi() + { + var fixture = new RequestBuilderImplementation(); - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithDynamicHeaderCollectionAndDynamicHeader( - int id, - [Header("Authorization")] string value, - [HeaderCollection] IDictionary headers + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.PostWithComplexTypeQuery) ); - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped( - int id, - [HeaderCollection] IDictionary headers, - [Header("Authorization")] string value - ); + var param = new ComplexQueryObject + { + EnumCollectionMulti = new List { TestEnum.A, TestEnum.B } + }; - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithPathMemberInCustomHeaderAndDynamicHeaderCollection( - [Header("X-PathMember")] int id, - [HeaderCollection] IDictionary headers - ); + var output = factory(new object[] { param }); - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithPathMemberInCustomHeaderAndDynamicHeaderCollection( - [Header("X-PathMember")] int id, - [HeaderCollection] IDictionary headers + Assert.Equal( + "/foo?listOfEnumMulti=A&listOfEnumMulti=B", + output.RequestUri.PathAndQuery ); + } - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithHeaderCollection( - int id, - [HeaderCollection] IDictionary headers, - int baz - ); + [Fact] + public void PostWithObjectQueryParameterWithObjectListWithProvidedEnumValues_Multi() + { + var fixture = new RequestBuilderImplementation(); - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithHeaderCollection( - int id, - [HeaderCollection] IDictionary headers, - int baz + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.PostWithComplexTypeQuery) ); - [Get("/foo/bar")] - Task FetchSomeStuffWithDuplicateHeaderCollection( - [HeaderCollection] IDictionary headers, - [HeaderCollection] IDictionary headers2 - ); + var param = new ComplexQueryObject + { + ObjectCollectionMulti = new List { TestEnum.A, TestEnum.B } + }; - [Post("/foo/bar")] - Task PostSomeStuffWithDuplicateHeaderCollection( - [HeaderCollection] IDictionary headers, - [HeaderCollection] IDictionary headers2 - ); + var output = factory(new object[] { param }); - [Get("/foo")] - Task FetchSomeStuffWithHeaderCollectionQueryParamAndArrayQueryParam( - [HeaderCollection] IDictionary headers, - int id, - [Query(CollectionFormat.Multi)] string[] someArray, - [Property("SomeProperty")] object someValue + Assert.Equal( + "/foo?ObjectCollectionMulti=A&ObjectCollectionMulti=B", + output.RequestUri.PathAndQuery ); + } - [Post("/foo")] - Task PostSomeStuffWithHeaderCollectionQueryParamAndArrayQueryParam( - [HeaderCollection] IDictionary headers, - int id, - [Query(CollectionFormat.Multi)] string[] someArray, - [Property("SomeProperty")] object someValue - ); + [Fact] + public void PostWithObjectQueryParameterWithEnumList_Csv() + { + var fixture = new RequestBuilderImplementation(); - [Get("/foo")] - Task FetchSomeStuffWithHeaderCollectionOfUnsupportedType( - [HeaderCollection] string headers + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.PostWithComplexTypeQuery) ); - [Post("/foo")] - Task PostSomeStuffWithHeaderCollectionOfUnsupportedType( - [HeaderCollection] string headers - ); + var param = new ComplexQueryObject + { + EnumCollectionCsv = new List { TestEnum.A, TestEnum.B } + }; - #endregion + var output = factory(new object[] { param }); - #region [Property] interface methods + Assert.Equal("/foo?EnumCollectionCsv=A%2CB", output.RequestUri.PathAndQuery); + } + + [Fact] + public void PostWithObjectQueryParameterWithObjectListWithProvidedEnumValues_Csv() + { + var fixture = new RequestBuilderImplementation(); - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someValue + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.PostWithComplexTypeQuery) ); - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithDynamicRequestProperty( - int id, - [Body] object body, - [Property("SomeProperty")] object someValue + var param = new ComplexQueryObject + { + ObjectCollectionCcv = new List { TestEnum.A, TestEnum.B } + }; + + var output = factory(new object[] { param }); + + Assert.Equal("/foo?listOfObjectsCsv=A%2CB", output.RequestUri.PathAndQuery); + } + + [Fact] + public void ObjectQueryParameterWithInnerCollectionHasCorrectQuerystring() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.ComplexTypeQueryWithInnerCollection) ); - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithDynamicRequestProperties( - int id, - [Body] object body, - [Property("SomeProperty")] object someValue, - [Property("SomeOtherProperty")] object someOtherValue + var param = new ComplexQueryObject { TestCollection = new[] { 1, 2, 3 } }; + var output = factory(new object[] { param }); + var uri = new Uri(new Uri("http://api"), output.RequestUri); + + Assert.Equal("/foo?TestCollection=1%2C2%2C3", uri.PathAndQuery); + } + + [Fact] + public void MultipleQueryAttributesWithNulls() + { + var input = typeof(IRestMethodInfoTests); + var fixtureParams = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.MultipleQueryAttributes)) ); - [Put("/foo/bar/{id}")] - Task PutSomeStuffWithoutBodyAndWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someValue + Assert.Equal(3, fixtureParams.QueryParameterMap.Count); + } + + [Fact] + public void GarbagePathsShouldThrow() + { + var shouldDie = true; + + try + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.GarbagePath)) + ); + } + catch (ArgumentException) + { + shouldDie = false; + } + + Assert.False(shouldDie); + } + + [Fact] + public void MissingParametersShouldBlowUp() + { + var shouldDie = true; + + try + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof(IRestMethodInfoTests.FetchSomeStuffMissingParameters) + ) + ); + } + catch (ArgumentException) + { + shouldDie = false; + } + + Assert.False(shouldDie); + } + + [Fact] + public void ParameterMappingSmokeTest() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuff)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); + } + + [Fact] + public void ParameterMappingWithTheSameIdInAFewPlaces() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithTheSameId)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); + } + + [Fact] + public void ParameterMappingWithTheSameIdInTheQueryParameter() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof( + IRestMethodInfoTests.FetchSomeStuffWithTheIdInAParameterMultipleTimes + ) + ) ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); + } - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithoutBodyAndWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someValue + [Fact] + public void ParameterMappingWithRoundTrippingSmokeTest() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof(IRestMethodInfoTests.FetchSomeStuffWithRoundTrippingParam) + ) ); + Assert.Equal("path", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.RoundTripping, fixture.ParameterMap[0].Type); + Assert.Equal("id", fixture.ParameterMap[1].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[1].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); + } + + [Fact] + public void ParameterMappingWithNonStringRoundTrippingShouldThrow() + { + var input = typeof(IRestMethodInfoTests); + Assert.Throws(() => + { + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof( + IRestMethodInfoTests.FetchSomeStuffWithNonStringRoundTrippingParam + ) + ) + ); + }); + } + + [Fact] + public void ParameterMappingWithQuerySmokeTest() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithQueryParam)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Equal("search", fixture.QueryParameterMap[1]); + Assert.Null(fixture.BodyParameterInfo); + } - [Patch("/foo/bar/{id}")] - Task PatchSomeStuffWithoutBodyAndWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someValue + [Fact] + public void ParameterMappingWithHardcodedQuerySmokeTest() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof(IRestMethodInfoTests.FetchSomeStuffWithHardcodedQueryParam) + ) ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); + } + + [Fact] + public void AliasMappingShouldWork() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithAlias)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); + } + + [Fact] + public void MultipleParametersPerSegmentShouldWork() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchAnImage)) + ); + Assert.Equal("width", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Equal("height", fixture.ParameterMap[1].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[1].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); + } + + [Fact] + public void FindTheBodyParameter() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithBody)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + + Assert.NotNull(fixture.BodyParameterInfo); + Assert.Empty(fixture.QueryParameterMap); + Assert.Equal(1, fixture.BodyParameterInfo.Item3); + } - [Put("/foo/bar/{id}")] - Task PutSomeStuffWithInferredBodyAndWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someValue, - object inferredBody + [Fact] + public void FindTheAuthorizeParameter() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof( + IRestMethodInfoTests.FetchSomeStuffWithAuthorizationSchemeSpecified + ) + ) ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + + Assert.NotNull(fixture.AuthorizeParameterInfo); + Assert.Empty(fixture.QueryParameterMap); + Assert.Equal(1, fixture.AuthorizeParameterInfo.Item2); + } + + [Fact] + public void AllowUrlEncodedContent() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.PostSomeUrlEncodedStuff)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + + Assert.NotNull(fixture.BodyParameterInfo); + Assert.Empty(fixture.QueryParameterMap); + Assert.Equal(BodySerializationMethod.UrlEncoded, fixture.BodyParameterInfo.Item1); + } - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithInferredBodyAndWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someValue, - object inferredBody + [Fact] + public void HardcodedHeadersShouldWork() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof(IRestMethodInfoTests.FetchSomeStuffWithHardcodedHeaders) + ) ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.BodyParameterInfo); - [Patch("/foo/bar/{id}")] - Task PatchSomeStuffWithInferredBodyAndWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someValue, - object inferredBody + Assert.True( + fixture.Headers.ContainsKey("Api-Version"), + "Headers include Api-Version header" ); + Assert.Equal("2", fixture.Headers["Api-Version"]); + Assert.True( + fixture.Headers.ContainsKey("User-Agent"), + "Headers include User-Agent header" + ); + Assert.Equal("RefitTestClient", fixture.Headers["User-Agent"]); + Assert.True(fixture.Headers.ContainsKey("Accept"), "Headers include Accept header"); + Assert.Equal("application/json", fixture.Headers["Accept"]); + Assert.Equal(3, fixture.Headers.Count); + } - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey( - int id, - [Property("SomeProperty")] object someValue1, - [Property("SomeProperty")] object someValue2 + [Fact] + public void DynamicHeadersShouldWork() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeader) + ) ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.PropertyParameterMap); + Assert.Null(fixture.BodyParameterInfo); - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicRequestPropertyWithoutKey( - int id, - [Property] object someValue, - [Property("")] object someOtherValue + Assert.Equal("Authorization", fixture.HeaderParameterMap[1]); + Assert.True( + fixture.Headers.ContainsKey("User-Agent"), + "Headers include User-Agent header" ); + Assert.Equal("RefitTestClient", fixture.Headers["User-Agent"]); + Assert.Equal(2, fixture.Headers.Count); + } - #endregion + #region [HeaderCollection] Tests - [Post("/foo/{id}")] - Task OhYeahValueTypes(int id, [Body(buffered: true)] int whatever); + [Fact] + public void DynamicHeaderCollectionShouldWork() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof( + IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollection + ) + ) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.Empty(fixture.PropertyParameterMap); + Assert.Null(fixture.BodyParameterInfo); + + Assert.True( + fixture.Headers.ContainsKey("Authorization"), + "Headers include Authorization header" + ); + Assert.Equal( + "SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", + fixture.Headers["Authorization"] + ); + Assert.True(fixture.Headers.ContainsKey("Accept"), "Headers include Accept header"); + Assert.Equal("application/json", fixture.Headers["Accept"]); + Assert.True( + fixture.Headers.ContainsKey("User-Agent"), + "Headers include User-Agent header" + ); + Assert.Equal("RefitTestClient", fixture.Headers["User-Agent"]); + Assert.True( + fixture.Headers.ContainsKey("Api-Version"), + "Headers include Api-Version header" + ); + Assert.Equal("1", fixture.Headers["Api-Version"]); + + Assert.Equal(4, fixture.Headers.Count); + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); + } - [Post("/foo/{id}")] - Task OhYeahValueTypesUnbuffered(int id, [Body(buffered: false)] int whatever); + [Theory] + [InlineData(nameof(IRestMethodInfoTests.PutSomeStuffWithCustomHeaderCollection))] + [InlineData(nameof(IRestMethodInfoTests.PostSomeStuffWithCustomHeaderCollection))] + [InlineData(nameof(IRestMethodInfoTests.PatchSomeStuffWithCustomHeaderCollection))] + public void DynamicHeaderCollectionShouldWorkWithBody(string interfaceMethodName) + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.Empty(fixture.PropertyParameterMap); + Assert.NotNull(fixture.BodyParameterInfo); + Assert.Null(fixture.AuthorizeParameterInfo); + + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(2)); + } - [Post("/foo/{id}")] - Task PullStreamMethod(int id, [Body(buffered: true)] Dictionary theData); + [Theory] + [InlineData(nameof(IRestMethodInfoTests.PutSomeStuffWithoutBodyAndCustomHeaderCollection))] + [InlineData(nameof(IRestMethodInfoTests.PostSomeStuffWithoutBodyAndCustomHeaderCollection))] + [InlineData( + nameof(IRestMethodInfoTests.PatchSomeStuffWithoutBodyAndCustomHeaderCollection) + )] + public void DynamicHeaderCollectionShouldWorkWithoutBody(string interfaceMethodName) + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.Empty(fixture.PropertyParameterMap); + Assert.Null(fixture.BodyParameterInfo); + Assert.Null(fixture.AuthorizeParameterInfo); + + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); + } - [Post("/foo/{id}")] - Task VoidPost(int id); + [Theory] + [InlineData( + nameof(IRestMethodInfoTests.PutSomeStuffWithInferredBodyAndWithDynamicHeaderCollection) + )] + [InlineData( + nameof(IRestMethodInfoTests.PostSomeStuffWithInferredBodyAndWithDynamicHeaderCollection) + )] + [InlineData( + nameof( + IRestMethodInfoTests.PatchSomeStuffWithInferredBodyAndWithDynamicHeaderCollection + ) + )] + public void DynamicHeaderCollectionShouldWorkWithInferredBody(string interfaceMethodName) + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.Empty(fixture.PropertyParameterMap); + Assert.NotNull(fixture.BodyParameterInfo); + Assert.Null(fixture.AuthorizeParameterInfo); + + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); + Assert.Equal(2, fixture.BodyParameterInfo.Item3); + } - [Post("/foo/{id}")] - string AsyncOnlyBuddy(int id); + [Theory] + [InlineData( + nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollectionAndAuthorize) + )] + [InlineData( + nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicHeaderCollectionAndAuthorize) + )] + public void DynamicHeaderCollectionShouldWorkWithAuthorize(string interfaceMethodName) + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.Empty(fixture.PropertyParameterMap); + Assert.Null(fixture.BodyParameterInfo); + + Assert.NotNull(fixture.AuthorizeParameterInfo); + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(2)); + } - [Patch("/foo/{id}")] - IObservable PatchSomething(int id, [Body] string someAttribute); + [Theory] + [InlineData( + nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeader) + )] + [InlineData( + nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicHeaderCollectionAndDynamicHeader) + )] + public void DynamicHeaderCollectionShouldWorkWithDynamicHeader(string interfaceMethodName) + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.AuthorizeParameterInfo); + Assert.Empty(fixture.PropertyParameterMap); + Assert.Null(fixture.BodyParameterInfo); + + Assert.Single(fixture.HeaderParameterMap); + Assert.Equal("Authorization", fixture.HeaderParameterMap[1]); + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(2)); + + input = typeof(IRestMethodInfoTests); + fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof( + IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped + ) + ) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.AuthorizeParameterInfo); + Assert.Empty(fixture.PropertyParameterMap); + Assert.Null(fixture.BodyParameterInfo); + + Assert.Single(fixture.HeaderParameterMap); + Assert.Equal("Authorization", fixture.HeaderParameterMap[2]); + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); + } - [Options("/foo/{id}")] - Task SendOptions(int id, [Body] string someAttribute); + [Theory] + [InlineData( + nameof( + IRestMethodInfoTests.FetchSomeStuffWithPathMemberInCustomHeaderAndDynamicHeaderCollection + ) + )] + [InlineData( + nameof( + IRestMethodInfoTests.PostSomeStuffWithPathMemberInCustomHeaderAndDynamicHeaderCollection + ) + )] + public void DynamicHeaderCollectionShouldWorkWithPathMemberDynamicHeader( + string interfaceMethodName + ) + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Null(fixture.AuthorizeParameterInfo); + Assert.Empty(fixture.PropertyParameterMap); + Assert.Null(fixture.BodyParameterInfo); + + Assert.Single(fixture.HeaderParameterMap); + Assert.Equal("X-PathMember", fixture.HeaderParameterMap[0]); + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); + } - [Post("/foo/{id}")] - Task> PostReturnsApiResponse(int id); + [Theory] + [InlineData(nameof(IRestMethodInfoTests.FetchSomeStuffWithHeaderCollection))] + [InlineData(nameof(IRestMethodInfoTests.PostSomeStuffWithHeaderCollection))] + public void DynamicHeaderCollectionInMiddleOfParamsShouldWork(string interfaceMethodName) + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Null(fixture.AuthorizeParameterInfo); + Assert.Empty(fixture.PropertyParameterMap); + Assert.Null(fixture.BodyParameterInfo); + + Assert.Equal("baz", fixture.QueryParameterMap[2]); + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); + } - [Post("/foo/{id}")] - Task PostReturnsNonApiResponse(int id); + [Theory] + [InlineData(nameof(IRestMethodInfoTests.FetchSomeStuffWithDuplicateHeaderCollection))] + [InlineData(nameof(IRestMethodInfoTests.PostSomeStuffWithDuplicateHeaderCollection))] + public void DynamicHeaderCollectionShouldOnlyAllowOne(string interfaceMethodName) + { + var input = typeof(IRestMethodInfoTests); - [Post("/foo")] - Task PostWithBodyDetected(Dictionary theData); + Assert.Throws( + () => + new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ) + ); + } - [Get("/foo")] - Task GetWithBodyDetected(Dictionary theData); + [Theory] + [InlineData( + nameof( + IRestMethodInfoTests.FetchSomeStuffWithHeaderCollectionQueryParamAndArrayQueryParam + ) + )] + [InlineData( + nameof( + IRestMethodInfoTests.PostSomeStuffWithHeaderCollectionQueryParamAndArrayQueryParam + ) + )] + public void DynamicHeaderCollectionShouldWorkWithProperty(string interfaceMethodName) + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Null(fixture.BodyParameterInfo); + Assert.Null(fixture.AuthorizeParameterInfo); - [Put("/foo")] - Task PutWithBodyDetected(Dictionary theData); + Assert.Equal(2, fixture.QueryParameterMap.Count); + Assert.Equal("id", fixture.QueryParameterMap[1]); + Assert.Equal("someArray", fixture.QueryParameterMap[2]); - [Patch("/foo")] - Task PatchWithBodyDetected(Dictionary theData); + Assert.Single(fixture.PropertyParameterMap); - [Post("/foo")] - Task TooManyComplexTypes(Dictionary theData, Dictionary theData1); + Assert.Single(fixture.HeaderCollectionParameterMap); + Assert.True(fixture.HeaderCollectionParameterMap.Contains(0)); + } - [Post("/foo")] - Task ManyComplexTypes( - Dictionary theData, - [Body] Dictionary theData1 + [Theory] + [InlineData( + nameof(IRestMethodInfoTests.FetchSomeStuffWithHeaderCollectionOfUnsupportedType) + )] + [InlineData( + nameof(IRestMethodInfoTests.PostSomeStuffWithHeaderCollectionOfUnsupportedType) + )] + public void DynamicHeaderCollectionShouldOnlyWorkWithSupportedSemantics( + string interfaceMethodName + ) + { + var input = typeof(IRestMethodInfoTests); + Assert.Throws( + () => + new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ) ); + } - [Post("/foo")] - Task PostWithDictionaryQuery([Query] Dictionary theData); + #endregion - [Post("/foo")] - Task PostWithComplexTypeQuery([Query] ComplexQueryObject queryParams); + #region [Property] Tests - [Post("/foo")] - Task ImpliedComplexQueryType( - ComplexQueryObject queryParams, - [Body] Dictionary theData1 + [Fact] + public void DynamicRequestPropertiesShouldWork() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestProperty) + ) ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.Null(fixture.BodyParameterInfo); - [Get("/api/{id}")] - Task MultipleQueryAttributes( - int id, - [Query] string text = null, - [Query] int? optionalId = null, - [Query(CollectionFormat = CollectionFormat.Multi)] string[] filters = null - ); + Assert.Equal("SomeProperty", fixture.PropertyParameterMap[1]); + } - [Get("/api/{id}")] - Task NullableValues( - int id, - string text = null, - int? optionalId = null, - [Query(CollectionFormat = CollectionFormat.Multi)] string[] filters = null + [Fact] + public void DynamicRequestPropertyShouldWorkWithBody() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicRequestProperty) + ) ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.NotNull(fixture.BodyParameterInfo); + Assert.Null(fixture.AuthorizeParameterInfo); + Assert.Empty(fixture.HeaderCollectionParameterMap); - [Get("/api/{id}")] - Task IEnumerableThrowingError([Query(CollectionFormat.Multi)] IEnumerable values); + Assert.Equal("SomeProperty", fixture.PropertyParameterMap[2]); + } + + [Fact] + public void DynamicRequestPropertiesShouldWorkWithBody() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof( + IRestMethodInfoTests.PostSomeStuffWithDynamicRequestProperties + ) + ) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.NotNull(fixture.BodyParameterInfo); + Assert.Null(fixture.AuthorizeParameterInfo); + Assert.Empty(fixture.HeaderCollectionParameterMap); - [Get("/foo")] - List InvalidGenericReturnType(); + Assert.Equal("SomeProperty", fixture.PropertyParameterMap[2]); + Assert.Equal("SomeOtherProperty", fixture.PropertyParameterMap[3]); } - public enum TestEnum + [Theory] + [InlineData( + nameof(IRestMethodInfoTests.PutSomeStuffWithoutBodyAndWithDynamicRequestProperty) + )] + [InlineData( + nameof(IRestMethodInfoTests.PostSomeStuffWithoutBodyAndWithDynamicRequestProperty) + )] + [InlineData( + nameof(IRestMethodInfoTests.PatchSomeStuffWithoutBodyAndWithDynamicRequestProperty) + )] + public void DynamicRequestPropertyShouldWorkWithoutBody(string interfaceMethodName) { - A, - B, - C + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.Null(fixture.BodyParameterInfo); + Assert.Null(fixture.AuthorizeParameterInfo); + Assert.Empty(fixture.HeaderCollectionParameterMap); + + Assert.Equal("SomeProperty", fixture.PropertyParameterMap[1]); } - public class ComplexQueryObject + [Theory] + [InlineData( + nameof(IRestMethodInfoTests.PutSomeStuffWithInferredBodyAndWithDynamicRequestProperty) + )] + [InlineData( + nameof(IRestMethodInfoTests.PostSomeStuffWithInferredBodyAndWithDynamicRequestProperty) + )] + [InlineData( + nameof(IRestMethodInfoTests.PatchSomeStuffWithInferredBodyAndWithDynamicRequestProperty) + )] + public void DynamicRequestPropertyShouldWorkWithInferredBody(string interfaceMethodName) { - [AliasAs("test-query-alias")] - public string TestAlias1 { get; set; } + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == interfaceMethodName) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.NotNull(fixture.BodyParameterInfo); + Assert.Null(fixture.AuthorizeParameterInfo); + Assert.Empty(fixture.HeaderCollectionParameterMap); + + Assert.Equal("SomeProperty", fixture.PropertyParameterMap[1]); + Assert.Equal(2, fixture.BodyParameterInfo.Item3); + } - public string TestAlias2 { get; set; } + [Fact] + public void DynamicRequestPropertiesWithoutKeysShouldDefaultKeyToParameterName() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof( + IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithoutKey + ) + ) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.Null(fixture.BodyParameterInfo); - public IEnumerable TestCollection { get; set; } + Assert.Equal("someValue", fixture.PropertyParameterMap[1]); + Assert.Equal("someOtherValue", fixture.PropertyParameterMap[2]); + } - [AliasAs("test-dictionary-alias")] - public Dictionary TestAliasedDictionary { get; set; } + [Fact] + public void DynamicRequestPropertiesWithDuplicateKeysDontBlowUp() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof( + IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey + ) + ) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Empty(fixture.HeaderParameterMap); + Assert.Null(fixture.BodyParameterInfo); - public Dictionary TestDictionary { get; set; } + Assert.Equal("SomeProperty", fixture.PropertyParameterMap[1]); + Assert.Equal("SomeProperty", fixture.PropertyParameterMap[2]); + } - [AliasAs("listOfEnumMulti")] - [Query(CollectionFormat.Multi)] - public List EnumCollectionMulti { get; set; } + #endregion - [Query(CollectionFormat.Multi)] - public List ObjectCollectionMulti { get; set; } + [Fact] + public void ValueTypesDontBlowUpBuffered() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.OhYeahValueTypes)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Equal(BodySerializationMethod.Default, fixture.BodyParameterInfo.Item1); + Assert.True(fixture.BodyParameterInfo.Item2); // buffered default + Assert.Equal(1, fixture.BodyParameterInfo.Item3); + + Assert.Equal(typeof(bool), fixture.ReturnResultType); + } - [Query(CollectionFormat.Csv)] - public List EnumCollectionCsv { get; set; } + [Fact] + public void ValueTypesDontBlowUpUnBuffered() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.OhYeahValueTypesUnbuffered)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Equal(BodySerializationMethod.Default, fixture.BodyParameterInfo.Item1); + Assert.False(fixture.BodyParameterInfo.Item2); // unbuffered specified + Assert.Equal(1, fixture.BodyParameterInfo.Item3); + + Assert.Equal(typeof(bool), fixture.ReturnResultType); + } - [AliasAs("listOfObjectsCsv")] - [Query(CollectionFormat.Csv)] - public List ObjectCollectionCcv { get; set; } + [Fact] + public void StreamMethodPullWorks() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.PullStreamMethod)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); + Assert.Empty(fixture.QueryParameterMap); + Assert.Equal(BodySerializationMethod.Default, fixture.BodyParameterInfo.Item1); + Assert.True(fixture.BodyParameterInfo.Item2); + Assert.Equal(1, fixture.BodyParameterInfo.Item3); + + Assert.Equal(typeof(bool), fixture.ReturnResultType); } - public class RestMethodInfoTests + [Fact] + public void ReturningTaskShouldWork() { - [Fact] - public void TooManyComplexTypesThrows() - { - var input = typeof(IRestMethodInfoTests); + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.VoidPost)) + ); + Assert.Equal("id", fixture.ParameterMap[0].Name); + Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Throws(() => - { - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.TooManyComplexTypes)) - ); - }); - } + Assert.Equal(typeof(Task), fixture.ReturnType); + Assert.Equal(typeof(void), fixture.ReturnResultType); + } - [Fact] - public void ManyComplexTypes() + [Fact] + public void SyncMethodsShouldThrow() + { + var shouldDie = true; + + try { var input = typeof(IRestMethodInfoTests); var fixture = new RestMethodInfoInternal( input, input .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.ManyComplexTypes)) + .First(x => x.Name == nameof(IRestMethodInfoTests.AsyncOnlyBuddy)) ); - - Assert.Single(fixture.QueryParameterMap); - Assert.NotNull(fixture.BodyParameterInfo); - Assert.Equal(1, fixture.BodyParameterInfo.Item3); } - - [Theory] - [InlineData(nameof(IRestMethodInfoTests.PutWithBodyDetected))] - [InlineData(nameof(IRestMethodInfoTests.PostWithBodyDetected))] - [InlineData(nameof(IRestMethodInfoTests.PatchWithBodyDetected))] - public void DefaultBodyParameterDetected(string interfaceMethodName) + catch (ArgumentException) { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - - Assert.Empty(fixture.QueryParameterMap); - Assert.NotNull(fixture.BodyParameterInfo); + shouldDie = false; } - [Fact] - public void DefaultBodyParameterNotDetectedForGet() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.GetWithBodyDetected)) - ); - - Assert.Single(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void PostWithDictionaryQueryParameter() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.PostWithDictionaryQuery)) - ); - - Assert.Single(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void PostWithObjectQueryParameterHasSingleQueryParameterValue() - { - var input = typeof(IRestMethodInfoTests); - var fixtureParams = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.PostWithComplexTypeQuery)) - ); - - Assert.Single(fixtureParams.QueryParameterMap); - Assert.Equal("queryParams", fixtureParams.QueryParameterMap[0]); - Assert.Null(fixtureParams.BodyParameterInfo); - } - - [Fact] - public void PostWithObjectQueryParameterHasCorrectQuerystring() - { - var fixture = new RequestBuilderImplementation(); - - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.PostWithComplexTypeQuery) - ); - - var param = new ComplexQueryObject { TestAlias1 = "one", TestAlias2 = "two" }; - - var output = factory(new object[] { param }); - - var uri = new Uri(new Uri("http://api"), output.RequestUri); - - Assert.Equal("/foo?test-query-alias=one&TestAlias2=two", uri.PathAndQuery); - } - - [Fact] - public void PostWithObjectQueryParameterWithEnumList_Multi() - { - var fixture = new RequestBuilderImplementation(); - - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.PostWithComplexTypeQuery) - ); - - var param = new ComplexQueryObject - { - EnumCollectionMulti = new List { TestEnum.A, TestEnum.B } - }; - - var output = factory(new object[] { param }); - - Assert.Equal( - "/foo?listOfEnumMulti=A&listOfEnumMulti=B", - output.RequestUri.PathAndQuery - ); - } - - [Fact] - public void PostWithObjectQueryParameterWithObjectListWithProvidedEnumValues_Multi() - { - var fixture = new RequestBuilderImplementation(); - - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.PostWithComplexTypeQuery) - ); - - var param = new ComplexQueryObject - { - ObjectCollectionMulti = new List { TestEnum.A, TestEnum.B } - }; - - var output = factory(new object[] { param }); - - Assert.Equal( - "/foo?ObjectCollectionMulti=A&ObjectCollectionMulti=B", - output.RequestUri.PathAndQuery - ); - } - - [Fact] - public void PostWithObjectQueryParameterWithEnumList_Csv() - { - var fixture = new RequestBuilderImplementation(); - - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.PostWithComplexTypeQuery) - ); - - var param = new ComplexQueryObject - { - EnumCollectionCsv = new List { TestEnum.A, TestEnum.B } - }; - - var output = factory(new object[] { param }); - - Assert.Equal("/foo?EnumCollectionCsv=A%2CB", output.RequestUri.PathAndQuery); - } - - [Fact] - public void PostWithObjectQueryParameterWithObjectListWithProvidedEnumValues_Csv() - { - var fixture = new RequestBuilderImplementation(); - - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.PostWithComplexTypeQuery) - ); - - var param = new ComplexQueryObject - { - ObjectCollectionCcv = new List { TestEnum.A, TestEnum.B } - }; - - var output = factory(new object[] { param }); - - Assert.Equal("/foo?listOfObjectsCsv=A%2CB", output.RequestUri.PathAndQuery); - } - - [Fact] - public void ObjectQueryParameterWithInnerCollectionHasCorrectQuerystring() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.ComplexTypeQueryWithInnerCollection) - ); - - var param = new ComplexQueryObject { TestCollection = new[] { 1, 2, 3 } }; - var output = factory(new object[] { param }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - - Assert.Equal("/foo?TestCollection=1%2C2%2C3", uri.PathAndQuery); - } - - [Fact] - public void MultipleQueryAttributesWithNulls() - { - var input = typeof(IRestMethodInfoTests); - var fixtureParams = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.MultipleQueryAttributes)) - ); - - Assert.Equal(3, fixtureParams.QueryParameterMap.Count); - } - - [Fact] - public void GarbagePathsShouldThrow() - { - var shouldDie = true; - - try - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.GarbagePath)) - ); - } - catch (ArgumentException) - { - shouldDie = false; - } - - Assert.False(shouldDie); - } - - [Fact] - public void MissingParametersShouldBlowUp() - { - var shouldDie = true; - - try - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof(IRestMethodInfoTests.FetchSomeStuffMissingParameters) - ) - ); - } - catch (ArgumentException) - { - shouldDie = false; - } - - Assert.False(shouldDie); - } - - [Fact] - public void ParameterMappingSmokeTest() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuff)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void ParameterMappingWithTheSameIdInAFewPlaces() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithTheSameId)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void ParameterMappingWithTheSameIdInTheQueryParameter() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof( - IRestMethodInfoTests.FetchSomeStuffWithTheIdInAParameterMultipleTimes - ) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void ParameterMappingWithRoundTrippingSmokeTest() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof(IRestMethodInfoTests.FetchSomeStuffWithRoundTrippingParam) - ) - ); - Assert.Equal("path", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.RoundTripping, fixture.ParameterMap[0].Type); - Assert.Equal("id", fixture.ParameterMap[1].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[1].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void ParameterMappingWithNonStringRoundTrippingShouldThrow() - { - var input = typeof(IRestMethodInfoTests); - Assert.Throws(() => - { - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof( - IRestMethodInfoTests.FetchSomeStuffWithNonStringRoundTrippingParam - ) - ) - ); - }); - } - - [Fact] - public void ParameterMappingWithQuerySmokeTest() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithQueryParam)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Equal("search", fixture.QueryParameterMap[1]); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void ParameterMappingWithHardcodedQuerySmokeTest() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof(IRestMethodInfoTests.FetchSomeStuffWithHardcodedQueryParam) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void AliasMappingShouldWork() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithAlias)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void MultipleParametersPerSegmentShouldWork() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.FetchAnImage)) - ); - Assert.Equal("width", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Equal("height", fixture.ParameterMap[1].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[1].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - } - - [Fact] - public void FindTheBodyParameter() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithBody)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - - Assert.NotNull(fixture.BodyParameterInfo); - Assert.Empty(fixture.QueryParameterMap); - Assert.Equal(1, fixture.BodyParameterInfo.Item3); - } - - [Fact] - public void FindTheAuthorizeParameter() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof( - IRestMethodInfoTests.FetchSomeStuffWithAuthorizationSchemeSpecified - ) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - - Assert.NotNull(fixture.AuthorizeParameterInfo); - Assert.Empty(fixture.QueryParameterMap); - Assert.Equal(1, fixture.AuthorizeParameterInfo.Item2); - } - - [Fact] - public void AllowUrlEncodedContent() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.PostSomeUrlEncodedStuff)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - - Assert.NotNull(fixture.BodyParameterInfo); - Assert.Empty(fixture.QueryParameterMap); - Assert.Equal(BodySerializationMethod.UrlEncoded, fixture.BodyParameterInfo.Item1); - } - - [Fact] - public void HardcodedHeadersShouldWork() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof(IRestMethodInfoTests.FetchSomeStuffWithHardcodedHeaders) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.True( - fixture.Headers.ContainsKey("Api-Version"), - "Headers include Api-Version header" - ); - Assert.Equal("2", fixture.Headers["Api-Version"]); - Assert.True( - fixture.Headers.ContainsKey("User-Agent"), - "Headers include User-Agent header" - ); - Assert.Equal("RefitTestClient", fixture.Headers["User-Agent"]); - Assert.True(fixture.Headers.ContainsKey("Accept"), "Headers include Accept header"); - Assert.Equal("application/json", fixture.Headers["Accept"]); - Assert.Equal(3, fixture.Headers.Count); - } - - [Fact] - public void DynamicHeadersShouldWork() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => x.Name == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeader) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.PropertyParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.Equal("Authorization", fixture.HeaderParameterMap[1]); - Assert.True( - fixture.Headers.ContainsKey("User-Agent"), - "Headers include User-Agent header" - ); - Assert.Equal("RefitTestClient", fixture.Headers["User-Agent"]); - Assert.Equal(2, fixture.Headers.Count); - } - - #region [HeaderCollection] Tests - - [Fact] - public void DynamicHeaderCollectionShouldWork() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof( - IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollection - ) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.Empty(fixture.PropertyParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.True( - fixture.Headers.ContainsKey("Authorization"), - "Headers include Authorization header" - ); - Assert.Equal( - "SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", - fixture.Headers["Authorization"] - ); - Assert.True(fixture.Headers.ContainsKey("Accept"), "Headers include Accept header"); - Assert.Equal("application/json", fixture.Headers["Accept"]); - Assert.True( - fixture.Headers.ContainsKey("User-Agent"), - "Headers include User-Agent header" - ); - Assert.Equal("RefitTestClient", fixture.Headers["User-Agent"]); - Assert.True( - fixture.Headers.ContainsKey("Api-Version"), - "Headers include Api-Version header" - ); - Assert.Equal("1", fixture.Headers["Api-Version"]); - - Assert.Equal(4, fixture.Headers.Count); - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); - } - - [Theory] - [InlineData(nameof(IRestMethodInfoTests.PutSomeStuffWithCustomHeaderCollection))] - [InlineData(nameof(IRestMethodInfoTests.PostSomeStuffWithCustomHeaderCollection))] - [InlineData(nameof(IRestMethodInfoTests.PatchSomeStuffWithCustomHeaderCollection))] - public void DynamicHeaderCollectionShouldWorkWithBody(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.Empty(fixture.PropertyParameterMap); - Assert.NotNull(fixture.BodyParameterInfo); - Assert.Null(fixture.AuthorizeParameterInfo); - - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(2)); - } - - [Theory] - [InlineData(nameof(IRestMethodInfoTests.PutSomeStuffWithoutBodyAndCustomHeaderCollection))] - [InlineData(nameof(IRestMethodInfoTests.PostSomeStuffWithoutBodyAndCustomHeaderCollection))] - [InlineData( - nameof(IRestMethodInfoTests.PatchSomeStuffWithoutBodyAndCustomHeaderCollection) - )] - public void DynamicHeaderCollectionShouldWorkWithoutBody(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.Empty(fixture.PropertyParameterMap); - Assert.Null(fixture.BodyParameterInfo); - Assert.Null(fixture.AuthorizeParameterInfo); - - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); - } - - [Theory] - [InlineData( - nameof(IRestMethodInfoTests.PutSomeStuffWithInferredBodyAndWithDynamicHeaderCollection) - )] - [InlineData( - nameof(IRestMethodInfoTests.PostSomeStuffWithInferredBodyAndWithDynamicHeaderCollection) - )] - [InlineData( - nameof( - IRestMethodInfoTests.PatchSomeStuffWithInferredBodyAndWithDynamicHeaderCollection - ) - )] - public void DynamicHeaderCollectionShouldWorkWithInferredBody(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.Empty(fixture.PropertyParameterMap); - Assert.NotNull(fixture.BodyParameterInfo); - Assert.Null(fixture.AuthorizeParameterInfo); - - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); - Assert.Equal(2, fixture.BodyParameterInfo.Item3); - } - - [Theory] - [InlineData( - nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollectionAndAuthorize) - )] - [InlineData( - nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicHeaderCollectionAndAuthorize) - )] - public void DynamicHeaderCollectionShouldWorkWithAuthorize(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.Empty(fixture.PropertyParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.NotNull(fixture.AuthorizeParameterInfo); - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(2)); - } - - [Theory] - [InlineData( - nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeader) - )] - [InlineData( - nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicHeaderCollectionAndDynamicHeader) - )] - public void DynamicHeaderCollectionShouldWorkWithDynamicHeader(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Empty(fixture.PropertyParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.Single(fixture.HeaderParameterMap); - Assert.Equal("Authorization", fixture.HeaderParameterMap[1]); - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(2)); - - input = typeof(IRestMethodInfoTests); - fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof( - IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped - ) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Empty(fixture.PropertyParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.Single(fixture.HeaderParameterMap); - Assert.Equal("Authorization", fixture.HeaderParameterMap[2]); - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); - } - - [Theory] - [InlineData( - nameof( - IRestMethodInfoTests.FetchSomeStuffWithPathMemberInCustomHeaderAndDynamicHeaderCollection - ) - )] - [InlineData( - nameof( - IRestMethodInfoTests.PostSomeStuffWithPathMemberInCustomHeaderAndDynamicHeaderCollection - ) - )] - public void DynamicHeaderCollectionShouldWorkWithPathMemberDynamicHeader( - string interfaceMethodName - ) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Empty(fixture.PropertyParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.Single(fixture.HeaderParameterMap); - Assert.Equal("X-PathMember", fixture.HeaderParameterMap[0]); - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); - } - - [Theory] - [InlineData(nameof(IRestMethodInfoTests.FetchSomeStuffWithHeaderCollection))] - [InlineData(nameof(IRestMethodInfoTests.PostSomeStuffWithHeaderCollection))] - public void DynamicHeaderCollectionInMiddleOfParamsShouldWork(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Empty(fixture.PropertyParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.Equal("baz", fixture.QueryParameterMap[2]); - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(1)); - } - - [Theory] - [InlineData(nameof(IRestMethodInfoTests.FetchSomeStuffWithDuplicateHeaderCollection))] - [InlineData(nameof(IRestMethodInfoTests.PostSomeStuffWithDuplicateHeaderCollection))] - public void DynamicHeaderCollectionShouldOnlyAllowOne(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - - Assert.Throws( - () => - new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ) - ); - } - - [Theory] - [InlineData( - nameof( - IRestMethodInfoTests.FetchSomeStuffWithHeaderCollectionQueryParamAndArrayQueryParam - ) - )] - [InlineData( - nameof( - IRestMethodInfoTests.PostSomeStuffWithHeaderCollectionQueryParamAndArrayQueryParam - ) - )] - public void DynamicHeaderCollectionShouldWorkWithProperty(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Null(fixture.BodyParameterInfo); - Assert.Null(fixture.AuthorizeParameterInfo); - - Assert.Equal(2, fixture.QueryParameterMap.Count); - Assert.Equal("id", fixture.QueryParameterMap[1]); - Assert.Equal("someArray", fixture.QueryParameterMap[2]); - - Assert.Single(fixture.PropertyParameterMap); - - Assert.Single(fixture.HeaderCollectionParameterMap); - Assert.True(fixture.HeaderCollectionParameterMap.Contains(0)); - } - - [Theory] - [InlineData( - nameof(IRestMethodInfoTests.FetchSomeStuffWithHeaderCollectionOfUnsupportedType) - )] - [InlineData( - nameof(IRestMethodInfoTests.PostSomeStuffWithHeaderCollectionOfUnsupportedType) - )] - public void DynamicHeaderCollectionShouldOnlyWorkWithSupportedSemantics( - string interfaceMethodName - ) - { - var input = typeof(IRestMethodInfoTests); - Assert.Throws( - () => - new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ) - ); - } - - #endregion - - #region [Property] Tests - - [Fact] - public void DynamicRequestPropertiesShouldWork() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof(IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestProperty) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.Equal("SomeProperty", fixture.PropertyParameterMap[1]); - } - - [Fact] - public void DynamicRequestPropertyShouldWorkWithBody() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof(IRestMethodInfoTests.PostSomeStuffWithDynamicRequestProperty) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.NotNull(fixture.BodyParameterInfo); - Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Empty(fixture.HeaderCollectionParameterMap); - - Assert.Equal("SomeProperty", fixture.PropertyParameterMap[2]); - } - - [Fact] - public void DynamicRequestPropertiesShouldWorkWithBody() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof( - IRestMethodInfoTests.PostSomeStuffWithDynamicRequestProperties - ) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.NotNull(fixture.BodyParameterInfo); - Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Empty(fixture.HeaderCollectionParameterMap); - - Assert.Equal("SomeProperty", fixture.PropertyParameterMap[2]); - Assert.Equal("SomeOtherProperty", fixture.PropertyParameterMap[3]); - } - - [Theory] - [InlineData( - nameof(IRestMethodInfoTests.PutSomeStuffWithoutBodyAndWithDynamicRequestProperty) - )] - [InlineData( - nameof(IRestMethodInfoTests.PostSomeStuffWithoutBodyAndWithDynamicRequestProperty) - )] - [InlineData( - nameof(IRestMethodInfoTests.PatchSomeStuffWithoutBodyAndWithDynamicRequestProperty) - )] - public void DynamicRequestPropertyShouldWorkWithoutBody(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.Null(fixture.BodyParameterInfo); - Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Empty(fixture.HeaderCollectionParameterMap); - - Assert.Equal("SomeProperty", fixture.PropertyParameterMap[1]); - } - - [Theory] - [InlineData( - nameof(IRestMethodInfoTests.PutSomeStuffWithInferredBodyAndWithDynamicRequestProperty) - )] - [InlineData( - nameof(IRestMethodInfoTests.PostSomeStuffWithInferredBodyAndWithDynamicRequestProperty) - )] - [InlineData( - nameof(IRestMethodInfoTests.PatchSomeStuffWithInferredBodyAndWithDynamicRequestProperty) - )] - public void DynamicRequestPropertyShouldWorkWithInferredBody(string interfaceMethodName) - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == interfaceMethodName) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.NotNull(fixture.BodyParameterInfo); - Assert.Null(fixture.AuthorizeParameterInfo); - Assert.Empty(fixture.HeaderCollectionParameterMap); - - Assert.Equal("SomeProperty", fixture.PropertyParameterMap[1]); - Assert.Equal(2, fixture.BodyParameterInfo.Item3); - } - - [Fact] - public void DynamicRequestPropertiesWithoutKeysShouldDefaultKeyToParameterName() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof( - IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithoutKey - ) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.Equal("someValue", fixture.PropertyParameterMap[1]); - Assert.Equal("someOtherValue", fixture.PropertyParameterMap[2]); - } - - [Fact] - public void DynamicRequestPropertiesWithDuplicateKeysDontBlowUp() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof( - IRestMethodInfoTests.FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey - ) - ) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Empty(fixture.HeaderParameterMap); - Assert.Null(fixture.BodyParameterInfo); - - Assert.Equal("SomeProperty", fixture.PropertyParameterMap[1]); - Assert.Equal("SomeProperty", fixture.PropertyParameterMap[2]); - } - - #endregion - - [Fact] - public void ValueTypesDontBlowUpBuffered() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.OhYeahValueTypes)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Equal(BodySerializationMethod.Default, fixture.BodyParameterInfo.Item1); - Assert.True(fixture.BodyParameterInfo.Item2); // buffered default - Assert.Equal(1, fixture.BodyParameterInfo.Item3); - - Assert.Equal(typeof(bool), fixture.ReturnResultType); - } - - [Fact] - public void ValueTypesDontBlowUpUnBuffered() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.OhYeahValueTypesUnbuffered)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Equal(BodySerializationMethod.Default, fixture.BodyParameterInfo.Item1); - Assert.False(fixture.BodyParameterInfo.Item2); // unbuffered specified - Assert.Equal(1, fixture.BodyParameterInfo.Item3); - - Assert.Equal(typeof(bool), fixture.ReturnResultType); - } - - [Fact] - public void StreamMethodPullWorks() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.PullStreamMethod)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - Assert.Empty(fixture.QueryParameterMap); - Assert.Equal(BodySerializationMethod.Default, fixture.BodyParameterInfo.Item1); - Assert.True(fixture.BodyParameterInfo.Item2); - Assert.Equal(1, fixture.BodyParameterInfo.Item3); - - Assert.Equal(typeof(bool), fixture.ReturnResultType); - } - - [Fact] - public void ReturningTaskShouldWork() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.VoidPost)) - ); - Assert.Equal("id", fixture.ParameterMap[0].Name); - Assert.Equal(ParameterType.Normal, fixture.ParameterMap[0].Type); - - Assert.Equal(typeof(Task), fixture.ReturnType); - Assert.Equal(typeof(void), fixture.ReturnResultType); - } - - [Fact] - public void SyncMethodsShouldThrow() - { - var shouldDie = true; - - try - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.AsyncOnlyBuddy)) - ); - } - catch (ArgumentException) - { - shouldDie = false; - } - - Assert.False(shouldDie); - } - - [Fact] - public void UsingThePatchAttributeSetsTheCorrectMethod() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PatchSomething)) - ); - - Assert.Equal("PATCH", fixture.HttpMethod.Method); - } - - [Fact] - public void UsingOptionsAttribute() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input.GetMethods().First(x => x.Name == nameof(IDummyHttpApi.SendOptions)) - ); - - Assert.Equal("OPTIONS", fixture.HttpMethod.Method); - } - - [Fact] - public void ApiResponseShouldBeSet() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.PostReturnsApiResponse)) - ); - - Assert.True(fixture.IsApiResponse); - } - - [Fact] - public void ApiResponseShouldNotBeSet() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First(x => x.Name == nameof(IRestMethodInfoTests.PostReturnsNonApiResponse)) - ); - - Assert.False(fixture.IsApiResponse); - } - - [Fact] - public void ParameterMappingWithHeaderQueryParamAndQueryArrayParam() - { - var input = typeof(IRestMethodInfoTests); - var fixture = new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => - x.Name - == nameof( - IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderQueryParamAndArrayQueryParam - ) - ) - ); - - Assert.Equal("GET", fixture.HttpMethod.Method); - Assert.Equal(2, fixture.QueryParameterMap.Count); - Assert.Single(fixture.HeaderParameterMap); - Assert.Single(fixture.PropertyParameterMap); - } - - [Fact] - public void GenericReturnTypeIsNotTaskOrObservableShouldThrow() - { - var input = typeof(IRestMethodInfoTests); - Assert.Throws( - () => - new RestMethodInfoInternal( - input, - input - .GetMethods() - .First( - x => x.Name == nameof(IRestMethodInfoTests.InvalidGenericReturnType) - ) - ) - ); - } - } - - [Headers("User-Agent: RefitTestClient", "Api-Version: 1")] - public interface IDummyHttpApi - { - [Get("/foo/bar/{id}")] - Task> FetchSomeStringWithMetadata(int id); - - [Get("/foo/bar/{id}")] - Task FetchSomeStuff(int id); - - [Get("/foo/bar/{**path}/{id}")] - Task FetchSomeStuffWithRoundTrippingParam(string path, int id); - - [Get("/foo/bar/{id}?baz=bamf")] - Task FetchSomeStuffWithHardcodedQueryParameter(int id); - - [Get("/foo/bar/{id}?baz=bamf")] - Task FetchSomeStuffWithHardcodedAndOtherQueryParameters( - int id, - [AliasAs("search_for")] string searchQuery - ); - - [Get("/{id}/{width}x{height}/foo")] - Task FetchSomethingWithMultipleParametersPerSegment(int id, int width, int height); - - [Get("/foo/bar/{id}")] - [Headers("Api-Version: 2", "Accept: application/json")] - Task FetchSomeStuffWithHardcodedHeaders(int id); - - [Get("/foo/bar/{id}")] - [Headers("Api-Version")] - Task FetchSomeStuffWithNullHardcodedHeader(int id); - - [Get("/foo/bar/{id}")] - [Headers("Api-Version: ")] - Task FetchSomeStuffWithEmptyHardcodedHeader(int id); - - [Get("/foo/bar/{id}?param1={id}¶m2={id}")] - Task FetchSomeStuffWithTheSameId(int id); - - [Get("/foo/bar?param=first {id} and second {id}")] - Task FetchSomeStuffWithTheIdInAParameterMultipleTimes(int id); - - [Post("/foo/bar/{id}")] - [Headers("Content-Type: literally/anything")] - Task PostSomeStuffWithHardCodedContentTypeHeader(int id, [Body] string content); - - [Get("/foo/bar/{id}")] - [Headers("Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==")] - Task FetchSomeStuffWithDynamicHeader( - int id, - [Header("Authorization")] string authorization - ); - - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithCustomHeader(int id, [Header("X-Emoji")] string custom); - - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithPathMemberInCustomHeader( - [Header("X-PathMember")] int id, - [Header("X-Emoji")] string custom - ); - - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithCustomHeader( - int id, - [Body] object body, - [Header("X-Emoji")] string emoji - ); - - [Get("/foo/bar/{id}")] - [Headers( - "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", - "Accept: application/json" - )] - Task FetchSomeStuffWithDynamicHeaderCollection( - int id, - [HeaderCollection] IDictionary headers - ); - - [Delete("/foo/bar/{id}")] - [Headers( - "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", - "Accept: application/json" - )] - Task DeleteSomeStuffWithDynamicHeaderCollection( - int id, - [HeaderCollection] IDictionary headers - ); - - [Put("/foo/bar/{id}")] - [Headers( - "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", - "Accept: application/json" - )] - Task PutSomeStuffWithDynamicHeaderCollection( - int id, - [HeaderCollection] IDictionary headers - ); - - [Post("/foo/bar/{id}")] - [Headers( - "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", - "Accept: application/json" - )] - Task PostSomeStuffWithDynamicHeaderCollection( - int id, - [HeaderCollection] IDictionary headers - ); - - [Patch("/foo/bar/{id}")] - [Headers( - "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", - "Accept: application/json" - )] - Task PatchSomeStuffWithDynamicHeaderCollection( - int id, - [HeaderCollection] IDictionary headers - ); - - [Get("/foo/bar/{id}")] - [Headers("Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==")] - Task FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeader( - int id, - [Header("Authorization")] string value, - [HeaderCollection] IDictionary headers - ); - - [Get("/foo/bar/{id}")] - [Headers("Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==")] - Task FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped( - int id, - [HeaderCollection] IDictionary headers, - [Header("Authorization")] string value - ); - - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someProperty - ); - - [Delete("/foo/bar/{id}")] - Task DeleteSomeStuffWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someProperty - ); - - [Put("/foo/bar/{id}")] - Task PutSomeStuffWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someProperty - ); - - [Post("/foo/bar/{id}")] - Task PostSomeStuffWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someProperty - ); - - [Patch("/foo/bar/{id}")] - Task PatchSomeStuffWithDynamicRequestProperty( - int id, - [Property("SomeProperty")] object someProperty - ); - - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey( - int id, - [Property("SomeProperty")] object someValue1, - [Property("SomeProperty")] object someValue2 - ); - - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithDynamicRequestPropertyWithoutKey( - int id, - [Property] object someValue, - [Property("")] object someOtherValue - ); - - [Get("/string")] - Task FetchSomeStuffWithoutFullPath(); - - [Get("/void")] - Task FetchSomeStuffWithVoid(); - - [Get("/void/{id}/path")] - Task FetchSomeStuffWithVoidAndQueryAlias( - string id, - [AliasAs("a")] string valueA, - [AliasAs("b")] string valueB - ); - - [Get("/foo")] - Task FetchSomeStuffWithNonFormattableQueryParams(bool b, char c); - - [Post("/foo/bar/{id}")] - Task PostSomeUrlEncodedStuff( - int id, - [Body(BodySerializationMethod.UrlEncoded)] object content - ); - - [Post("/foo/bar/{id}")] - Task PostSomeAliasedUrlEncodedStuff( - int id, - [Body(BodySerializationMethod.UrlEncoded)] SomeRequestData content - ); - - string SomeOtherMethod(); - - [Put("/foo/bar/{id}")] - Task PutSomeContentWithAuthorization( - int id, - [Body] object content, - [Header("Authorization")] string authorization - ); + Assert.False(shouldDie); + } - [Put("/foo/bar/{id}")] - Task PutSomeStuffWithDynamicContentType( - int id, - [Body] string content, - [Header("Content-Type")] string contentType + [Fact] + public void UsingThePatchAttributeSetsTheCorrectMethod() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == nameof(IRestMethodInfoTests.PatchSomething)) ); - [Post("/foo/bar/{id}")] - Task PostAValueType(int id, [Body] Guid? content); - - [Patch("/foo/bar/{id}")] - IObservable PatchSomething(int id, [Body] string someAttribute); - - [Options("/foo/bar/{id}")] - Task SendOptions(int id, [Body] string someAttribute); - - [Get("/foo/bar/{id}")] - Task FetchSomeStuffWithQueryFormat([Query(Format = "0.0")] int id); - - [Get("/query")] - Task QueryWithEnumerable(IEnumerable numbers); - - [Get("/query")] - Task QueryWithArray(int[] numbers); - - [Get("/query?q1={param1}&q2={param2}")] - Task QueryWithExplicitParameters(string param1, string param2); - - [Get("/query")] - Task QueryWithArrayFormattedAsMulti([Query(CollectionFormat.Multi)] int[] numbers); - - [Get("/query")] - Task QueryWithArrayFormattedAsCsv([Query(CollectionFormat.Csv)] int[] numbers); - - [Get("/query")] - Task QueryWithArrayFormattedAsSsv([Query(CollectionFormat.Ssv)] int[] numbers); - - [Get("/query")] - Task QueryWithArrayFormattedAsTsv([Query(CollectionFormat.Tsv)] int[] numbers); - - [Get("/query")] - Task QueryWithArrayFormattedAsPipes([Query(CollectionFormat.Pipes)] int[] numbers); - - [Get("/foo")] - Task ComplexQueryObjectWithDictionary([Query] ComplexQueryObject query); - - [Get("/foo")] - Task QueryWithDictionaryWithEnumKey([Query] IDictionary query); + Assert.Equal("PATCH", fixture.HttpMethod.Method); + } - [Get("/foo")] - Task QueryWithDictionaryWithPrefix( - [Query(".", "dictionary")] IDictionary query + [Fact] + public void UsingOptionsAttribute() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input.GetMethods().First(x => x.Name == nameof(IDummyHttpApi.SendOptions)) ); - [Get("/foo")] - Task QueryWithDictionaryWithNumericKey([Query] IDictionary query); + Assert.Equal("OPTIONS", fixture.HttpMethod.Method); + } - [Get("/query")] - Task QueryWithEnumerableFormattedAsMulti( - [Query(CollectionFormat.Multi)] IEnumerable lines + [Fact] + public void ApiResponseShouldBeSet() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.PostReturnsApiResponse)) ); - [Get("/query")] - Task QueryWithEnumerableFormattedAsCsv( - [Query(CollectionFormat.Csv)] IEnumerable lines - ); + Assert.True(fixture.IsApiResponse); + } - [Get("/query")] - Task QueryWithEnumerableFormattedAsSsv( - [Query(CollectionFormat.Ssv)] IEnumerable lines + [Fact] + public void ApiResponseShouldNotBeSet() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First(x => x.Name == nameof(IRestMethodInfoTests.PostReturnsNonApiResponse)) ); - [Get("/query")] - Task QueryWithEnumerableFormattedAsTsv( - [Query(CollectionFormat.Tsv)] IEnumerable lines - ); + Assert.False(fixture.IsApiResponse); + } - [Get("/query")] - Task QueryWithEnumerableFormattedAsPipes( - [Query(CollectionFormat.Pipes)] IEnumerable lines + [Fact] + public void ParameterMappingWithHeaderQueryParamAndQueryArrayParam() + { + var input = typeof(IRestMethodInfoTests); + var fixture = new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => + x.Name + == nameof( + IRestMethodInfoTests.FetchSomeStuffWithDynamicHeaderQueryParamAndArrayQueryParam + ) + ) ); - [Get("/query")] - Task QueryWithObjectWithPrivateGetters(Person person); - - [Multipart] - [Post("/foo?&name={name}")] - Task PostWithQueryStringParameters(FileInfo source, string name); - - [Get("/query")] - Task QueryWithEnum(FooWithEnumMember foo); - - [Get("/query")] - Task QueryWithTypeWithEnum(TypeFooWithEnumMember foo); + Assert.Equal("GET", fixture.HttpMethod.Method); + Assert.Equal(2, fixture.QueryParameterMap.Count); + Assert.Single(fixture.HeaderParameterMap); + Assert.Single(fixture.PropertyParameterMap); + } - [Get("/api/{id}")] - Task QueryWithOptionalParameters( - int id, - [Query] string text = null, - [Query] int? optionalId = null, - [Query(CollectionFormat = CollectionFormat.Multi)] string[] filters = null + [Fact] + public void GenericReturnTypeIsNotTaskOrObservableShouldThrow() + { + var input = typeof(IRestMethodInfoTests); + Assert.Throws( + () => + new RestMethodInfoInternal( + input, + input + .GetMethods() + .First( + x => x.Name == nameof(IRestMethodInfoTests.InvalidGenericReturnType) + ) + ) ); + } +} - [Delete("/api/bar")] - Task ClearWithEnumMember([Query] FooWithEnumMember foo); - - [Delete("/api/v1/video")] - Task Clear([Query] int playerIndex); - - [Multipart] - [Post("/blobstorage/{**filepath}")] - Task Blob_Post_Byte(string filepath, [AliasAs("attachment")] ByteArrayPart byteArray); - - [Multipart] - [Post("/companies/{companyId}/{path}")] - Task> UploadFile( - int companyId, - string path, - [AliasAs("file")] StreamPart stream, - [Header("Authorization")] string authorization, - bool overwrite = false, - [AliasAs("fileMetadata")] string metadata = null - ); +[Headers("User-Agent: RefitTestClient", "Api-Version: 1")] +public interface IDummyHttpApi +{ + [Get("/foo/bar/{id}")] + Task> FetchSomeStringWithMetadata(int id); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuff(int id); + + [Get("/foo/bar/{**path}/{id}")] + Task FetchSomeStuffWithRoundTrippingParam(string path, int id); + + [Get("/foo/bar/{id}?baz=bamf")] + Task FetchSomeStuffWithHardcodedQueryParameter(int id); + + [Get("/foo/bar/{id}?baz=bamf")] + Task FetchSomeStuffWithHardcodedAndOtherQueryParameters( + int id, + [AliasAs("search_for")] string searchQuery + ); + + [Get("/{id}/{width}x{height}/foo")] + Task FetchSomethingWithMultipleParametersPerSegment(int id, int width, int height); + + [Get("/foo/bar/{id}")] + [Headers("Api-Version: 2", "Accept: application/json")] + Task FetchSomeStuffWithHardcodedHeaders(int id); + + [Get("/foo/bar/{id}")] + [Headers("Api-Version")] + Task FetchSomeStuffWithNullHardcodedHeader(int id); + + [Get("/foo/bar/{id}")] + [Headers("Api-Version: ")] + Task FetchSomeStuffWithEmptyHardcodedHeader(int id); + + [Get("/foo/bar/{id}?param1={id}¶m2={id}")] + Task FetchSomeStuffWithTheSameId(int id); + + [Get("/foo/bar?param=first {id} and second {id}")] + Task FetchSomeStuffWithTheIdInAParameterMultipleTimes(int id); + + [Post("/foo/bar/{id}")] + [Headers("Content-Type: literally/anything")] + Task PostSomeStuffWithHardCodedContentTypeHeader(int id, [Body] string content); + + [Get("/foo/bar/{id}")] + [Headers("Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==")] + Task FetchSomeStuffWithDynamicHeader( + int id, + [Header("Authorization")] string authorization + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithCustomHeader(int id, [Header("X-Emoji")] string custom); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithPathMemberInCustomHeader( + [Header("X-PathMember")] int id, + [Header("X-Emoji")] string custom + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithCustomHeader( + int id, + [Body] object body, + [Header("X-Emoji")] string emoji + ); + + [Get("/foo/bar/{id}")] + [Headers( + "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", + "Accept: application/json" + )] + Task FetchSomeStuffWithDynamicHeaderCollection( + int id, + [HeaderCollection] IDictionary headers + ); + + [Delete("/foo/bar/{id}")] + [Headers( + "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", + "Accept: application/json" + )] + Task DeleteSomeStuffWithDynamicHeaderCollection( + int id, + [HeaderCollection] IDictionary headers + ); + + [Put("/foo/bar/{id}")] + [Headers( + "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", + "Accept: application/json" + )] + Task PutSomeStuffWithDynamicHeaderCollection( + int id, + [HeaderCollection] IDictionary headers + ); + + [Post("/foo/bar/{id}")] + [Headers( + "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", + "Accept: application/json" + )] + Task PostSomeStuffWithDynamicHeaderCollection( + int id, + [HeaderCollection] IDictionary headers + ); + + [Patch("/foo/bar/{id}")] + [Headers( + "Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", + "Accept: application/json" + )] + Task PatchSomeStuffWithDynamicHeaderCollection( + int id, + [HeaderCollection] IDictionary headers + ); + + [Get("/foo/bar/{id}")] + [Headers("Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==")] + Task FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeader( + int id, + [Header("Authorization")] string value, + [HeaderCollection] IDictionary headers + ); + + [Get("/foo/bar/{id}")] + [Headers("Authorization: SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==")] + Task FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped( + int id, + [HeaderCollection] IDictionary headers, + [Header("Authorization")] string value + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someProperty + ); + + [Delete("/foo/bar/{id}")] + Task DeleteSomeStuffWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someProperty + ); + + [Put("/foo/bar/{id}")] + Task PutSomeStuffWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someProperty + ); + + [Post("/foo/bar/{id}")] + Task PostSomeStuffWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someProperty + ); + + [Patch("/foo/bar/{id}")] + Task PatchSomeStuffWithDynamicRequestProperty( + int id, + [Property("SomeProperty")] object someProperty + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey( + int id, + [Property("SomeProperty")] object someValue1, + [Property("SomeProperty")] object someValue2 + ); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithDynamicRequestPropertyWithoutKey( + int id, + [Property] object someValue, + [Property("")] object someOtherValue + ); + + [Get("/string")] + Task FetchSomeStuffWithoutFullPath(); + + [Get("/void")] + Task FetchSomeStuffWithVoid(); + + [Get("/void/{id}/path")] + Task FetchSomeStuffWithVoidAndQueryAlias( + string id, + [AliasAs("a")] string valueA, + [AliasAs("b")] string valueB + ); + + [Get("/foo")] + Task FetchSomeStuffWithNonFormattableQueryParams(bool b, char c); + + [Post("/foo/bar/{id}")] + Task PostSomeUrlEncodedStuff( + int id, + [Body(BodySerializationMethod.UrlEncoded)] object content + ); + + [Post("/foo/bar/{id}")] + Task PostSomeAliasedUrlEncodedStuff( + int id, + [Body(BodySerializationMethod.UrlEncoded)] SomeRequestData content + ); + + string SomeOtherMethod(); + + [Put("/foo/bar/{id}")] + Task PutSomeContentWithAuthorization( + int id, + [Body] object content, + [Header("Authorization")] string authorization + ); + + [Put("/foo/bar/{id}")] + Task PutSomeStuffWithDynamicContentType( + int id, + [Body] string content, + [Header("Content-Type")] string contentType + ); + + [Post("/foo/bar/{id}")] + Task PostAValueType(int id, [Body] Guid? content); + + [Patch("/foo/bar/{id}")] + IObservable PatchSomething(int id, [Body] string someAttribute); + + [Options("/foo/bar/{id}")] + Task SendOptions(int id, [Body] string someAttribute); + + [Get("/foo/bar/{id}")] + Task FetchSomeStuffWithQueryFormat([Query(Format = "0.0")] int id); + + [Get("/query")] + Task QueryWithEnumerable(IEnumerable numbers); + + [Get("/query")] + Task QueryWithArray(int[] numbers); + + [Get("/query?q1={param1}&q2={param2}")] + Task QueryWithExplicitParameters(string param1, string param2); + + [Get("/query")] + Task QueryWithArrayFormattedAsMulti([Query(CollectionFormat.Multi)] int[] numbers); + + [Get("/query")] + Task QueryWithArrayFormattedAsCsv([Query(CollectionFormat.Csv)] int[] numbers); + + [Get("/query")] + Task QueryWithArrayFormattedAsSsv([Query(CollectionFormat.Ssv)] int[] numbers); + + [Get("/query")] + Task QueryWithArrayFormattedAsTsv([Query(CollectionFormat.Tsv)] int[] numbers); + + [Get("/query")] + Task QueryWithArrayFormattedAsPipes([Query(CollectionFormat.Pipes)] int[] numbers); + + [Get("/foo")] + Task ComplexQueryObjectWithDictionary([Query] ComplexQueryObject query); + + [Get("/foo")] + Task QueryWithDictionaryWithEnumKey([Query] IDictionary query); + + [Get("/foo")] + Task QueryWithDictionaryWithPrefix( + [Query(".", "dictionary")] IDictionary query + ); + + [Get("/foo")] + Task QueryWithDictionaryWithNumericKey([Query] IDictionary query); + + [Get("/query")] + Task QueryWithEnumerableFormattedAsMulti( + [Query(CollectionFormat.Multi)] IEnumerable lines + ); + + [Get("/query")] + Task QueryWithEnumerableFormattedAsCsv( + [Query(CollectionFormat.Csv)] IEnumerable lines + ); + + [Get("/query")] + Task QueryWithEnumerableFormattedAsSsv( + [Query(CollectionFormat.Ssv)] IEnumerable lines + ); + + [Get("/query")] + Task QueryWithEnumerableFormattedAsTsv( + [Query(CollectionFormat.Tsv)] IEnumerable lines + ); + + [Get("/query")] + Task QueryWithEnumerableFormattedAsPipes( + [Query(CollectionFormat.Pipes)] IEnumerable lines + ); + + [Get("/query")] + Task QueryWithObjectWithPrivateGetters(Person person); + + [Multipart] + [Post("/foo?&name={name}")] + Task PostWithQueryStringParameters(FileInfo source, string name); + + [Get("/query")] + Task QueryWithEnum(FooWithEnumMember foo); + + [Get("/query")] + Task QueryWithTypeWithEnum(TypeFooWithEnumMember foo); + + [Get("/api/{id}")] + Task QueryWithOptionalParameters( + int id, + [Query] string text = null, + [Query] int? optionalId = null, + [Query(CollectionFormat = CollectionFormat.Multi)] string[] filters = null + ); + + [Delete("/api/bar")] + Task ClearWithEnumMember([Query] FooWithEnumMember foo); + + [Delete("/api/v1/video")] + Task Clear([Query] int playerIndex); + + [Multipart] + [Post("/blobstorage/{**filepath}")] + Task Blob_Post_Byte(string filepath, [AliasAs("attachment")] ByteArrayPart byteArray); + + [Multipart] + [Post("/companies/{companyId}/{path}")] + Task> UploadFile( + int companyId, + string path, + [AliasAs("file")] StreamPart stream, + [Header("Authorization")] string authorization, + bool overwrite = false, + [AliasAs("fileMetadata")] string metadata = null + ); + + [Post("/foo")] + Task PostWithComplexTypeQuery([Query] ComplexQueryObject queryParams); + + [Get("/foo")] + Task ComplexTypeQueryWithInnerCollection([Query] ComplexQueryObject queryParams); + + [Get("/api/{obj.someProperty}")] + Task QueryWithOptionalParametersPathBoundObject( + PathBoundObject obj, + [Query] string text = null, + [Query] int? optionalId = null, + [Query(CollectionFormat = CollectionFormat.Multi)] string[] filters = null + ); + + [Headers("Accept:application/json", "X-API-V: 125")] + [Get("/api/someModule/deviceList?controlId={control_id}")] + Task QueryWithHeadersBeforeData( + [Header("Authorization")] string authorization, + [Header("X-Lng")] string twoLetterLang, + string search, + [AliasAs("control_id")] string controlId, + string secret + ); + + [Get("/query")] + [QueryUriFormat(UriFormat.Unescaped)] + Task UnescapedQueryParams(string q); + + [Get("/query")] + [QueryUriFormat(UriFormat.Unescaped)] + Task UnescapedQueryParamsWithFilter(string q, string filter); + + [Get("/api/foo/{id}/file_{id}?query={id}")] + Task SomeApiThatUsesParameterMoreThanOnceInTheUrl(string id); +} - [Post("/foo")] - Task PostWithComplexTypeQuery([Query] ComplexQueryObject queryParams); +interface ICancellableMethods +{ + [Get("/foo")] + Task GetWithCancellation(CancellationToken token = default); - [Get("/foo")] - Task ComplexTypeQueryWithInnerCollection([Query] ComplexQueryObject queryParams); + [Get("/foo")] + Task GetWithCancellationAndReturn(CancellationToken token = default); +} - [Get("/api/{obj.someProperty}")] - Task QueryWithOptionalParametersPathBoundObject( - PathBoundObject obj, - [Query] string text = null, - [Query] int? optionalId = null, - [Query(CollectionFormat = CollectionFormat.Multi)] string[] filters = null - ); +public enum FooWithEnumMember +{ + A, - [Headers("Accept:application/json", "X-API-V: 125")] - [Get("/api/someModule/deviceList?controlId={control_id}")] - Task QueryWithHeadersBeforeData( - [Header("Authorization")] string authorization, - [Header("X-Lng")] string twoLetterLang, - string search, - [AliasAs("control_id")] string controlId, - string secret - ); + [EnumMember(Value = "b")] + B +} - [Get("/query")] - [QueryUriFormat(UriFormat.Unescaped)] - Task UnescapedQueryParams(string q); +public class TypeFooWithEnumMember +{ + [AliasAs("foo")] + public FooWithEnumMember Foo { get; set; } +} - [Get("/query")] - [QueryUriFormat(UriFormat.Unescaped)] - Task UnescapedQueryParamsWithFilter(string q, string filter); +public class SomeRequestData +{ + [AliasAs("rpn")] + public int ReadablePropertyName { get; set; } +} - [Get("/api/foo/{id}/file_{id}?query={id}")] - Task SomeApiThatUsesParameterMoreThanOnceInTheUrl(string id); - } +public class Person +{ + public string FirstName { private get; set; } + public string LastName { private get; set; } + public string FullName => $"{FirstName} {LastName}"; +} - interface ICancellableMethods +public class TestHttpMessageHandler : HttpMessageHandler +{ + public HttpRequestMessage RequestMessage { get; private set; } + public int MessagesSent { get; set; } + public HttpContent Content { get; set; } + public Func ContentFactory { get; set; } + public CancellationToken CancellationToken { get; set; } + public string SendContent { get; set; } + + public TestHttpMessageHandler(string content = "test") { - [Get("/foo")] - Task GetWithCancellation(CancellationToken token = default); - - [Get("/foo")] - Task GetWithCancellationAndReturn(CancellationToken token = default); + Content = new StringContent(content); + ContentFactory = () => Content; } - public enum FooWithEnumMember + protected override async Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken + ) { - A, + if (request == null) + { + throw new ArgumentNullException(nameof(request)); + } - [EnumMember(Value = "b")] - B - } + RequestMessage = request; + if (request.Content != null) + { + SendContent = await request.Content + .ReadAsStringAsync(cancellationToken) + .ConfigureAwait(false); + } - public class TypeFooWithEnumMember - { - [AliasAs("foo")] - public FooWithEnumMember Foo { get; set; } - } + CancellationToken = cancellationToken; + MessagesSent++; - public class SomeRequestData - { - [AliasAs("rpn")] - public int ReadablePropertyName { get; set; } + return new HttpResponseMessage(HttpStatusCode.OK) { Content = ContentFactory() }; } +} - public class Person - { - public string FirstName { private get; set; } - public string LastName { private get; set; } - public string FullName => $"{FirstName} {LastName}"; - } +public class TestUrlParameterFormatter(string constantOutput) : IUrlParameterFormatter +{ + public string Format(object value, ICustomAttributeProvider attributeProvider, Type type) => constantOutput; +} - public class TestHttpMessageHandler : HttpMessageHandler +// Converts enums to ints and adds a suffix to strings to test that both dictionary keys and values are formatted. +public class TestEnumUrlParameterFormatter : DefaultUrlParameterFormatter +{ + public override string Format( + object parameterValue, + ICustomAttributeProvider attributeProvider, + Type type + ) { - public HttpRequestMessage RequestMessage { get; private set; } - public int MessagesSent { get; set; } - public HttpContent Content { get; set; } - public Func ContentFactory { get; set; } - public CancellationToken CancellationToken { get; set; } - public string SendContent { get; set; } - - public TestHttpMessageHandler(string content = "test") + if (parameterValue is TestEnum enumValue) { - Content = new StringContent(content); - ContentFactory = () => Content; + var enumBackingValue = (int)enumValue; + return enumBackingValue.ToString(); } - protected override async Task SendAsync( - HttpRequestMessage request, - CancellationToken cancellationToken - ) + if (parameterValue is string stringValue) { - if (request == null) - { - throw new ArgumentNullException(nameof(request)); - } - - RequestMessage = request; - if (request.Content != null) - { - SendContent = await request.Content - .ReadAsStringAsync(cancellationToken) - .ConfigureAwait(false); - } - - CancellationToken = cancellationToken; - MessagesSent++; - - return new HttpResponseMessage(HttpStatusCode.OK) { Content = ContentFactory() }; + return $"{stringValue}{StringParameterSuffix}"; } - } - public class TestUrlParameterFormatter(string constantOutput) : IUrlParameterFormatter - { - public string Format(object value, ICustomAttributeProvider attributeProvider, Type type) => constantOutput; + return base.Format(parameterValue, attributeProvider, type); } - // Converts enums to ints and adds a suffix to strings to test that both dictionary keys and values are formatted. - public class TestEnumUrlParameterFormatter : DefaultUrlParameterFormatter + public static string StringParameterSuffix => "suffix"; +} + +public class TestEnumerableUrlParameterFormatter : DefaultUrlParameterFormatter +{ + public override string Format( + object parameterValue, + ICustomAttributeProvider attributeProvider, + Type type + ) { - public override string Format( - object parameterValue, - ICustomAttributeProvider attributeProvider, - Type type - ) + if (parameterValue is IEnumerable enu) { - if (parameterValue is TestEnum enumValue) - { - var enumBackingValue = (int)enumValue; - return enumBackingValue.ToString(); - } - - if (parameterValue is string stringValue) - { - return $"{stringValue}{StringParameterSuffix}"; - } - - return base.Format(parameterValue, attributeProvider, type); + return string.Join(",", enu.Select(o => base.Format(o, attributeProvider, type))); + } + if (parameterValue is IEnumerable en) + { + return string.Join( + ",", + en.Cast().Select(o => base.Format(o, attributeProvider, type)) + ); } - public static string StringParameterSuffix => "suffix"; + return base.Format(parameterValue, attributeProvider, type); } +} - public class TestEnumerableUrlParameterFormatter : DefaultUrlParameterFormatter +public class RequestBuilderTests +{ + [Fact] + public void MethodsShouldBeCancellableDefault() { - public override string Format( - object parameterValue, - ICustomAttributeProvider attributeProvider, - Type type - ) - { - if (parameterValue is IEnumerable enu) - { - return string.Join(",", enu.Select(o => base.Format(o, attributeProvider, type))); - } - if (parameterValue is IEnumerable en) - { - return string.Join( - ",", - en.Cast().Select(o => base.Format(o, attributeProvider, type)) - ); - } + var fixture = new RequestBuilderImplementation(); + var factory = fixture.RunRequest("GetWithCancellation"); + var output = factory(Array.Empty()); - return base.Format(parameterValue, attributeProvider, type); - } + var uri = new Uri(new Uri("http://api"), output.RequestMessage.RequestUri); + Assert.Equal("/foo", uri.PathAndQuery); + Assert.False(output.CancellationToken.IsCancellationRequested); } - public class RequestBuilderTests + [Fact] + public void MethodsShouldBeCancellableWithToken() { - [Fact] - public void MethodsShouldBeCancellableDefault() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.RunRequest("GetWithCancellation"); - var output = factory(Array.Empty()); + var fixture = new RequestBuilderImplementation(); + var factory = fixture.RunRequest("GetWithCancellation"); - var uri = new Uri(new Uri("http://api"), output.RequestMessage.RequestUri); - Assert.Equal("/foo", uri.PathAndQuery); - Assert.False(output.CancellationToken.IsCancellationRequested); - } + var cts = new CancellationTokenSource(); - [Fact] - public void MethodsShouldBeCancellableWithToken() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.RunRequest("GetWithCancellation"); + var output = factory(new object[] { cts.Token }); - var cts = new CancellationTokenSource(); + var uri = new Uri(new Uri("http://api"), output.RequestMessage.RequestUri); + Assert.Equal("/foo", uri.PathAndQuery); + Assert.False(output.CancellationToken.IsCancellationRequested); + } - var output = factory(new object[] { cts.Token }); + [Fact] + public void MethodsShouldBeCancellableWithTokenDoesCancel() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.RunRequest("GetWithCancellation"); - var uri = new Uri(new Uri("http://api"), output.RequestMessage.RequestUri); - Assert.Equal("/foo", uri.PathAndQuery); - Assert.False(output.CancellationToken.IsCancellationRequested); - } + var cts = new CancellationTokenSource(); + cts.Cancel(); - [Fact] - public void MethodsShouldBeCancellableWithTokenDoesCancel() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.RunRequest("GetWithCancellation"); + var output = factory(new object[] { cts.Token }); + Assert.True(output.CancellationToken.IsCancellationRequested); + } + + [Fact] + public void HttpContentAsApiResponseTest() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRestResultFuncForMethod("PostFileUploadWithMetadata"); + var testHttpMessageHandler = new TestHttpMessageHandler(); + var retContent = new StreamContent(new MemoryStream()); + testHttpMessageHandler.Content = retContent; + + var mpc = new MultipartContent("foosubtype"); + + var task = + (Task>) + factory( + new HttpClient(testHttpMessageHandler) + { + BaseAddress = new Uri("http://api/") + }, + new object[] { mpc } + ); + task.Wait(); - var cts = new CancellationTokenSource(); - cts.Cancel(); + Assert.NotNull(task.Result.Headers); + Assert.True(task.Result.IsSuccessStatusCode); + Assert.NotNull(task.Result.ReasonPhrase); + Assert.False(task.Result.StatusCode == default); + Assert.NotNull(task.Result.Version); - var output = factory(new object[] { cts.Token }); - Assert.True(output.CancellationToken.IsCancellationRequested); - } + Assert.Equal(testHttpMessageHandler.RequestMessage.Content, mpc); + Assert.Equal(retContent, task.Result.Content); + } - [Fact] - public void HttpContentAsApiResponseTest() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRestResultFuncForMethod("PostFileUploadWithMetadata"); - var testHttpMessageHandler = new TestHttpMessageHandler(); - var retContent = new StreamContent(new MemoryStream()); - testHttpMessageHandler.Content = retContent; - - var mpc = new MultipartContent("foosubtype"); - - var task = - (Task>) - factory( - new HttpClient(testHttpMessageHandler) - { - BaseAddress = new Uri("http://api/") - }, - new object[] { mpc } - ); - task.Wait(); + [Fact] + public void HttpContentTest() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRestResultFuncForMethod("PostFileUpload"); + var testHttpMessageHandler = new TestHttpMessageHandler(); + var retContent = new StreamContent(new MemoryStream()); + testHttpMessageHandler.Content = retContent; + + var mpc = new MultipartContent("foosubtype"); + + var task = + (Task) + factory( + new HttpClient(testHttpMessageHandler) + { + BaseAddress = new Uri("http://api/") + }, + new object[] { mpc } + ); + task.Wait(); - Assert.NotNull(task.Result.Headers); - Assert.True(task.Result.IsSuccessStatusCode); - Assert.NotNull(task.Result.ReasonPhrase); - Assert.False(task.Result.StatusCode == default); - Assert.NotNull(task.Result.Version); + Assert.Equal(testHttpMessageHandler.RequestMessage.Content, mpc); + Assert.Equal(retContent, task.Result); + } - Assert.Equal(testHttpMessageHandler.RequestMessage.Content, mpc); - Assert.Equal(retContent, task.Result.Content); - } + [Fact] + public void StreamResponseAsApiResponseTest() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRestResultFuncForMethod("GetRemoteFileWithMetadata"); + var testHttpMessageHandler = new TestHttpMessageHandler(); + var streamResponse = new MemoryStream(); + var reponseContent = "A remote file"; + testHttpMessageHandler.Content = new StreamContent(streamResponse); + + var writer = new StreamWriter(streamResponse); + writer.Write(reponseContent); + writer.Flush(); + streamResponse.Seek(0L, SeekOrigin.Begin); + + var task = + (Task>) + factory( + new HttpClient(testHttpMessageHandler) + { + BaseAddress = new Uri("http://api/") + }, + new object[] { "test-file" } + ); + task.Wait(); - [Fact] - public void HttpContentTest() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRestResultFuncForMethod("PostFileUpload"); - var testHttpMessageHandler = new TestHttpMessageHandler(); - var retContent = new StreamContent(new MemoryStream()); - testHttpMessageHandler.Content = retContent; - - var mpc = new MultipartContent("foosubtype"); - - var task = - (Task) - factory( - new HttpClient(testHttpMessageHandler) - { - BaseAddress = new Uri("http://api/") - }, - new object[] { mpc } - ); - task.Wait(); + Assert.NotNull(task.Result.Headers); + Assert.True(task.Result.IsSuccessStatusCode); + Assert.NotNull(task.Result.ReasonPhrase); + Assert.False(task.Result.StatusCode == default); + Assert.NotNull(task.Result.Version); - Assert.Equal(testHttpMessageHandler.RequestMessage.Content, mpc); - Assert.Equal(retContent, task.Result); - } + using var reader = new StreamReader(task.Result.Content); + Assert.Equal(reponseContent, reader.ReadToEnd()); + } - [Fact] - public void StreamResponseAsApiResponseTest() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRestResultFuncForMethod("GetRemoteFileWithMetadata"); - var testHttpMessageHandler = new TestHttpMessageHandler(); - var streamResponse = new MemoryStream(); - var reponseContent = "A remote file"; - testHttpMessageHandler.Content = new StreamContent(streamResponse); - - var writer = new StreamWriter(streamResponse); - writer.Write(reponseContent); - writer.Flush(); - streamResponse.Seek(0L, SeekOrigin.Begin); - - var task = - (Task>) - factory( - new HttpClient(testHttpMessageHandler) - { - BaseAddress = new Uri("http://api/") - }, - new object[] { "test-file" } - ); - task.Wait(); + [Fact] + public void StreamResponseTest() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRestResultFuncForMethod("GetRemoteFile"); + var testHttpMessageHandler = new TestHttpMessageHandler(); + var streamResponse = new MemoryStream(); + var reponseContent = "A remote file"; + testHttpMessageHandler.Content = new StreamContent(streamResponse); + + var writer = new StreamWriter(streamResponse); + writer.Write(reponseContent); + writer.Flush(); + streamResponse.Seek(0L, SeekOrigin.Begin); + + var task = + (Task) + factory( + new HttpClient(testHttpMessageHandler) + { + BaseAddress = new Uri("http://api/") + }, + new object[] { "test-file" } + ); + task.Wait(); - Assert.NotNull(task.Result.Headers); - Assert.True(task.Result.IsSuccessStatusCode); - Assert.NotNull(task.Result.ReasonPhrase); - Assert.False(task.Result.StatusCode == default); - Assert.NotNull(task.Result.Version); + using var reader = new StreamReader(task.Result); + Assert.Equal(reponseContent, reader.ReadToEnd()); + } - using var reader = new StreamReader(task.Result.Content); - Assert.Equal(reponseContent, reader.ReadToEnd()); - } + [Fact] + public void MethodsThatDontHaveAnHttpMethodShouldFail() + { + var failureMethods = new[] { "SomeOtherMethod", "weofjwoeijfwe", null, }; + + var successMethods = new[] { "FetchSomeStuff", }; - [Fact] - public void StreamResponseTest() + foreach (var v in failureMethods) { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRestResultFuncForMethod("GetRemoteFile"); - var testHttpMessageHandler = new TestHttpMessageHandler(); - var streamResponse = new MemoryStream(); - var reponseContent = "A remote file"; - testHttpMessageHandler.Content = new StreamContent(streamResponse); - - var writer = new StreamWriter(streamResponse); - writer.Write(reponseContent); - writer.Flush(); - streamResponse.Seek(0L, SeekOrigin.Begin); - - var task = - (Task) - factory( - new HttpClient(testHttpMessageHandler) - { - BaseAddress = new Uri("http://api/") - }, - new object[] { "test-file" } - ); - task.Wait(); + var shouldDie = true; - using var reader = new StreamReader(task.Result); - Assert.Equal(reponseContent, reader.ReadToEnd()); + try + { + var fixture = new RequestBuilderImplementation(); + fixture.BuildRequestFactoryForMethod(v); + } + catch (Exception) + { + shouldDie = false; + } + Assert.False(shouldDie); } - [Fact] - public void MethodsThatDontHaveAnHttpMethodShouldFail() + foreach (var v in successMethods) { - var failureMethods = new[] { "SomeOtherMethod", "weofjwoeijfwe", null, }; - - var successMethods = new[] { "FetchSomeStuff", }; + var shouldDie = false; - foreach (var v in failureMethods) + try { - var shouldDie = true; - - try - { - var fixture = new RequestBuilderImplementation(); - fixture.BuildRequestFactoryForMethod(v); - } - catch (Exception) - { - shouldDie = false; - } - Assert.False(shouldDie); + var fixture = new RequestBuilderImplementation(); + fixture.BuildRequestFactoryForMethod(v); } - - foreach (var v in successMethods) + catch (Exception) { - var shouldDie = false; - - try - { - var fixture = new RequestBuilderImplementation(); - fixture.BuildRequestFactoryForMethod(v); - } - catch (Exception) - { - shouldDie = true; - } - - Assert.False(shouldDie); + shouldDie = true; } + + Assert.False(shouldDie); } + } - [Fact] - public void HardcodedQueryParamShouldBeInUrl() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithHardcodedQueryParameter" - ); - var output = factory(new object[] { 6 }); + [Fact] + public void HardcodedQueryParamShouldBeInUrl() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithHardcodedQueryParameter" + ); + var output = factory(new object[] { 6 }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/foo/bar/6?baz=bamf", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/foo/bar/6?baz=bamf", uri.PathAndQuery); + } - [Fact] - public void ParameterizedQueryParamsShouldBeInUrl() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithHardcodedAndOtherQueryParameters" - ); - var output = factory(new object[] { 6, "foo" }); + [Fact] + public void ParameterizedQueryParamsShouldBeInUrl() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithHardcodedAndOtherQueryParameters" + ); + var output = factory(new object[] { 6, "foo" }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/foo/bar/6?baz=bamf&search_for=foo", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/foo/bar/6?baz=bamf&search_for=foo", uri.PathAndQuery); + } - [Fact] - public void ParameterizedValuesShouldBeInUrlMoreThanOnce() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.SomeApiThatUsesParameterMoreThanOnceInTheUrl) - ); - var output = factory(new object[] { 6 }); + [Fact] + public void ParameterizedValuesShouldBeInUrlMoreThanOnce() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.SomeApiThatUsesParameterMoreThanOnceInTheUrl) + ); + var output = factory(new object[] { 6 }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/api/foo/6/file_6?query=6", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/api/foo/6/file_6?query=6", uri.PathAndQuery); + } - [Theory] - [InlineData("aaa/bbb", "/foo/bar/aaa/bbb/1")] - [InlineData("aaa/bbb/ccc", "/foo/bar/aaa/bbb/ccc/1")] - [InlineData("aaa", "/foo/bar/aaa/1")] - [InlineData("aa a/bb-b", "/foo/bar/aa%20a/bb-b/1")] - public void RoundTrippingParameterizedQueryParamsShouldBeInUrl( - string path, - string expectedQuery - ) - { - var fixture = new RequestBuilderImplementation(); + [Theory] + [InlineData("aaa/bbb", "/foo/bar/aaa/bbb/1")] + [InlineData("aaa/bbb/ccc", "/foo/bar/aaa/bbb/ccc/1")] + [InlineData("aaa", "/foo/bar/aaa/1")] + [InlineData("aa a/bb-b", "/foo/bar/aa%20a/bb-b/1")] + public void RoundTrippingParameterizedQueryParamsShouldBeInUrl( + string path, + string expectedQuery + ) + { + var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithRoundTrippingParam" - ); - var output = factory(new object[] { path, 1 }); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithRoundTrippingParam" + ); + var output = factory(new object[] { path, 1 }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal(expectedQuery, uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal(expectedQuery, uri.PathAndQuery); + } - [Fact] - public void ParameterizedNullQueryParamsShouldBeBlankInUrl() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("PostWithQueryStringParameters"); - var output = factory( - new object[] { new FileInfo(typeof(RequestBuilderTests).Assembly.Location), null } - ); + [Fact] + public void ParameterizedNullQueryParamsShouldBeBlankInUrl() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("PostWithQueryStringParameters"); + var output = factory( + new object[] { new FileInfo(typeof(RequestBuilderTests).Assembly.Location), null } + ); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/foo?name=", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/foo?name=", uri.PathAndQuery); + } - [Fact] - public void ParametersShouldBePutAsExplicitQueryString() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.QueryWithExplicitParameters) - ); - var output = factory(new object[] { "value1", "value2" }); + [Fact] + public void ParametersShouldBePutAsExplicitQueryString() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.QueryWithExplicitParameters) + ); + var output = factory(new object[] { "value1", "value2" }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/query?q2=value2&q1=value1", uri.PathAndQuery); - } + Assert.Equal("/query?q2=value2&q1=value1", uri.PathAndQuery); + } - [Fact] - public void QueryParamShouldFormat() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithQueryFormat"); - var output = factory(new object[] { 6 }); + [Fact] + public void QueryParamShouldFormat() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithQueryFormat"); + var output = factory(new object[] { 6 }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/foo/bar/6.0", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/foo/bar/6.0", uri.PathAndQuery); + } - [Fact] - public void ParameterizedQueryParamsShouldBeInUrlAndValuesEncoded() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithHardcodedAndOtherQueryParameters" - ); - var output = factory(new object[] { 6, "push!=pull&push" }); + [Fact] + public void ParameterizedQueryParamsShouldBeInUrlAndValuesEncoded() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithHardcodedAndOtherQueryParameters" + ); + var output = factory(new object[] { 6, "push!=pull&push" }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/foo/bar/6?baz=bamf&search_for=push%21%3Dpull%26push", uri.PathAndQuery); - } + Assert.Equal("/foo/bar/6?baz=bamf&search_for=push%21%3Dpull%26push", uri.PathAndQuery); + } - [Fact] - public void ParameterizedQueryParamsShouldBeInUrlAndValuesEncodedWhenMixedReplacementAndQuery() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithVoidAndQueryAlias" - ); - var output = factory(new object[] { "6 & 7/8", "test@example.com", "push!=pull" }); + [Fact] + public void ParameterizedQueryParamsShouldBeInUrlAndValuesEncodedWhenMixedReplacementAndQuery() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithVoidAndQueryAlias" + ); + var output = factory(new object[] { "6 & 7/8", "test@example.com", "push!=pull" }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal( - "/void/6%20%26%207%2F8/path?a=test%40example.com&b=push%21%3Dpull", - uri.PathAndQuery - ); - } + Assert.Equal( + "/void/6%20%26%207%2F8/path?a=test%40example.com&b=push%21%3Dpull", + uri.PathAndQuery + ); + } - [Fact] - public void QueryParamWithPathDelimiterShouldBeEncoded() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithVoidAndQueryAlias" - ); - var output = factory(new object[] { "6/6", "test@example.com", "push!=pull" }); + [Fact] + public void QueryParamWithPathDelimiterShouldBeEncoded() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithVoidAndQueryAlias" + ); + var output = factory(new object[] { "6/6", "test@example.com", "push!=pull" }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal( - "/void/6%2F6/path?a=test%40example.com&b=push%21%3Dpull", - uri.PathAndQuery - ); - } + Assert.Equal( + "/void/6%2F6/path?a=test%40example.com&b=push%21%3Dpull", + uri.PathAndQuery + ); + } - [Fact] - public void ParameterizedQueryParamsShouldBeInUrlAndValuesEncodedWhenMixedReplacementAndQueryBadId() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithVoidAndQueryAlias" - ); - var output = factory(new object[] { "6", "test@example.com", "push!=pull" }); + [Fact] + public void ParameterizedQueryParamsShouldBeInUrlAndValuesEncodedWhenMixedReplacementAndQueryBadId() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithVoidAndQueryAlias" + ); + var output = factory(new object[] { "6", "test@example.com", "push!=pull" }); + + var uri = new Uri(new Uri("http://api"), output.RequestUri); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/void/6/path?a=test%40example.com&b=push%21%3Dpull", uri.PathAndQuery); + } + + [Fact] + public void NonFormattableQueryParamsShouldBeIncluded() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithNonFormattableQueryParams" + ); + var output = factory(new object[] { true, 'x' }); - Assert.Equal("/void/6/path?a=test%40example.com&b=push%21%3Dpull", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); - [Fact] - public void NonFormattableQueryParamsShouldBeIncluded() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithNonFormattableQueryParams" - ); - var output = factory(new object[] { true, 'x' }); + Assert.Equal("/foo?b=True&c=x", uri.PathAndQuery); + } - var uri = new Uri(new Uri("http://api"), output.RequestUri); + [Fact] + public void MultipleParametersInTheSameSegmentAreGeneratedProperly() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomethingWithMultipleParametersPerSegment" + ); + var output = factory(new object[] { 6, 1024, 768 }); - Assert.Equal("/foo?b=True&c=x", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/6/1024x768/foo", uri.PathAndQuery); + } - [Fact] - public void MultipleParametersInTheSameSegmentAreGeneratedProperly() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomethingWithMultipleParametersPerSegment" - ); - var output = factory(new object[] { 6, 1024, 768 }); + [Fact] + public void HardcodedHeadersShouldBeInHeaders() + { + var fixture = new RequestBuilderImplementation(); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/6/1024x768/foo", uri.PathAndQuery); - } + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.FetchSomeStuffWithHardcodedHeaders) + ); + var output = factory(new object[] { 6 }); - [Fact] - public void HardcodedHeadersShouldBeInHeaders() - { - var fixture = new RequestBuilderImplementation(); + Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); + Assert.Equal("RefitTestClient", output.Headers.UserAgent.ToString()); + Assert.True( + output.Headers.Contains("Api-Version"), + "Headers include Api-Version header" + ); + Assert.Equal("2", output.Headers.GetValues("Api-Version").Single()); + Assert.True(output.Headers.Contains("Accept"), "Headers include Accept header"); + Assert.Equal("application/json", output.Headers.Accept.ToString()); + } - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.FetchSomeStuffWithHardcodedHeaders) - ); - var output = factory(new object[] { 6 }); + [Fact] + public void EmptyHardcodedHeadersShouldBeInHeaders() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithEmptyHardcodedHeader" + ); + var output = factory(new object[] { 6 }); - Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); - Assert.Equal("RefitTestClient", output.Headers.UserAgent.ToString()); - Assert.True( - output.Headers.Contains("Api-Version"), - "Headers include Api-Version header" - ); - Assert.Equal("2", output.Headers.GetValues("Api-Version").Single()); - Assert.True(output.Headers.Contains("Accept"), "Headers include Accept header"); - Assert.Equal("application/json", output.Headers.Accept.ToString()); - } + Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); + Assert.Equal("RefitTestClient", output.Headers.UserAgent.ToString()); + Assert.True( + output.Headers.Contains("Api-Version"), + "Headers include Api-Version header" + ); + Assert.Equal("", output.Headers.GetValues("Api-Version").Single()); + } - [Fact] - public void EmptyHardcodedHeadersShouldBeInHeaders() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithEmptyHardcodedHeader" - ); - var output = factory(new object[] { 6 }); + [Fact] + public void NullHardcodedHeadersShouldNotBeInHeaders() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithNullHardcodedHeader" + ); + var output = factory(new object[] { 6 }); - Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); - Assert.Equal("RefitTestClient", output.Headers.UserAgent.ToString()); - Assert.True( - output.Headers.Contains("Api-Version"), - "Headers include Api-Version header" - ); - Assert.Equal("", output.Headers.GetValues("Api-Version").Single()); - } + Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); + Assert.Equal("RefitTestClient", output.Headers.UserAgent.ToString()); + Assert.False( + output.Headers.Contains("Api-Version"), + "Headers include Api-Version header" + ); + } - [Fact] - public void NullHardcodedHeadersShouldNotBeInHeaders() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithNullHardcodedHeader" - ); - var output = factory(new object[] { 6 }); + [Fact] + public void ReadStringContentWithMetadata() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRestResultFuncForMethod("FetchSomeStringWithMetadata"); + var testHttpMessageHandler = new TestHttpMessageHandler(); + + var task = + (Task>) + factory( + new HttpClient(testHttpMessageHandler) + { + BaseAddress = new Uri("http://api/") + }, + new object[] { 42 } + ); + task.Wait(); - Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); - Assert.Equal("RefitTestClient", output.Headers.UserAgent.ToString()); - Assert.False( - output.Headers.Contains("Api-Version"), - "Headers include Api-Version header" - ); - } + Assert.NotNull(task.Result.Headers); + Assert.True(task.Result.IsSuccessStatusCode); + Assert.NotNull(task.Result.ReasonPhrase); + Assert.False(task.Result.StatusCode == default); + Assert.NotNull(task.Result.Version); - [Fact] - public void ReadStringContentWithMetadata() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRestResultFuncForMethod("FetchSomeStringWithMetadata"); - var testHttpMessageHandler = new TestHttpMessageHandler(); - - var task = - (Task>) - factory( - new HttpClient(testHttpMessageHandler) - { - BaseAddress = new Uri("http://api/") - }, - new object[] { 42 } - ); - task.Wait(); + Assert.Equal("test", task.Result.Content); + } - Assert.NotNull(task.Result.Headers); - Assert.True(task.Result.IsSuccessStatusCode); - Assert.NotNull(task.Result.ReasonPhrase); - Assert.False(task.Result.StatusCode == default); - Assert.NotNull(task.Result.Version); + [Fact] + public void ContentHeadersCanBeHardcoded() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "PostSomeStuffWithHardCodedContentTypeHeader" + ); + var output = factory(new object[] { 6, "stuff" }); - Assert.Equal("test", task.Result.Content); - } + Assert.True( + output.Content.Headers.Contains("Content-Type"), + "Content headers include Content-Type header" + ); + Assert.Equal("literally/anything", output.Content.Headers.ContentType.ToString()); + } - [Fact] - public void ContentHeadersCanBeHardcoded() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "PostSomeStuffWithHardCodedContentTypeHeader" - ); - var output = factory(new object[] { 6, "stuff" }); + [Fact] + public void DynamicHeaderShouldBeInHeaders() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithDynamicHeader"); + var output = factory(new object[] { 6, "Basic RnVjayB5ZWFoOmhlYWRlcnMh" }); - Assert.True( - output.Content.Headers.Contains("Content-Type"), - "Content headers include Content-Type header" - ); - Assert.Equal("literally/anything", output.Content.Headers.ContentType.ToString()); - } + Assert.NotNull(output.Headers.Authorization); //, "Headers include Authorization header"); + Assert.Equal("RnVjayB5ZWFoOmhlYWRlcnMh", output.Headers.Authorization.Parameter); + } - [Fact] - public void DynamicHeaderShouldBeInHeaders() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithDynamicHeader"); - var output = factory(new object[] { 6, "Basic RnVjayB5ZWFoOmhlYWRlcnMh" }); + [Fact] + public void CustomDynamicHeaderShouldBeInHeaders() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithCustomHeader"); + var output = factory(new object[] { 6, ":joy_cat:" }); - Assert.NotNull(output.Headers.Authorization); //, "Headers include Authorization header"); - Assert.Equal("RnVjayB5ZWFoOmhlYWRlcnMh", output.Headers.Authorization.Parameter); - } + Assert.True(output.Headers.Contains("X-Emoji"), "Headers include X-Emoji header"); + Assert.Equal(":joy_cat:", output.Headers.GetValues("X-Emoji").First()); + } - [Fact] - public void CustomDynamicHeaderShouldBeInHeaders() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithCustomHeader"); - var output = factory(new object[] { 6, ":joy_cat:" }); + [Fact] + public void EmptyDynamicHeaderShouldBeInHeaders() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithCustomHeader"); + var output = factory(new object[] { 6, "" }); - Assert.True(output.Headers.Contains("X-Emoji"), "Headers include X-Emoji header"); - Assert.Equal(":joy_cat:", output.Headers.GetValues("X-Emoji").First()); - } + Assert.True(output.Headers.Contains("X-Emoji"), "Headers include X-Emoji header"); + Assert.Equal("", output.Headers.GetValues("X-Emoji").First()); + } - [Fact] - public void EmptyDynamicHeaderShouldBeInHeaders() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithCustomHeader"); - var output = factory(new object[] { 6, "" }); + [Fact] + public void NullDynamicHeaderShouldNotBeInHeaders() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithDynamicHeader"); + var output = factory(new object[] { 6, null }); - Assert.True(output.Headers.Contains("X-Emoji"), "Headers include X-Emoji header"); - Assert.Equal("", output.Headers.GetValues("X-Emoji").First()); - } + Assert.Null(output.Headers.Authorization); //, "Headers include Authorization header"); + } - [Fact] - public void NullDynamicHeaderShouldNotBeInHeaders() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuffWithDynamicHeader"); - var output = factory(new object[] { 6, null }); + [Fact] + public void PathMemberAsCustomDynamicHeaderShouldBeInHeaders() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "FetchSomeStuffWithPathMemberInCustomHeader" + ); + var output = factory(new object[] { 6, ":joy_cat:" }); - Assert.Null(output.Headers.Authorization); //, "Headers include Authorization header"); - } + Assert.True( + output.Headers.Contains("X-PathMember"), + "Headers include X-PathMember header" + ); + Assert.Equal("6", output.Headers.GetValues("X-PathMember").First()); + } - [Fact] - public void PathMemberAsCustomDynamicHeaderShouldBeInHeaders() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "FetchSomeStuffWithPathMemberInCustomHeader" - ); - var output = factory(new object[] { 6, ":joy_cat:" }); + [Fact] + public void AddCustomHeadersToRequestHeadersOnly() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("PostSomeStuffWithCustomHeader"); + var output = factory(new object[] { 6, new { Foo = "bar" }, ":smile_cat:" }); - Assert.True( - output.Headers.Contains("X-PathMember"), - "Headers include X-PathMember header" - ); - Assert.Equal("6", output.Headers.GetValues("X-PathMember").First()); - } + Assert.True( + output.Headers.Contains("Api-Version"), + "Headers include Api-Version header" + ); + Assert.True(output.Headers.Contains("X-Emoji"), "Headers include X-Emoji header"); + Assert.False( + output.Content.Headers.Contains("Api-Version"), + "Content headers include Api-Version header" + ); + Assert.False( + output.Content.Headers.Contains("X-Emoji"), + "Content headers include X-Emoji header" + ); + } - [Fact] - public void AddCustomHeadersToRequestHeadersOnly() + [Theory] + [InlineData(nameof(IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollection))] + [InlineData(nameof(IDummyHttpApi.DeleteSomeStuffWithDynamicHeaderCollection))] + [InlineData(nameof(IDummyHttpApi.PutSomeStuffWithDynamicHeaderCollection))] + [InlineData(nameof(IDummyHttpApi.PostSomeStuffWithDynamicHeaderCollection))] + [InlineData(nameof(IDummyHttpApi.PatchSomeStuffWithDynamicHeaderCollection))] + public void HeaderCollectionShouldBeInHeaders(string interfaceMethodName) + { + var headerCollection = new Dictionary { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("PostSomeStuffWithCustomHeader"); - var output = factory(new object[] { 6, new { Foo = "bar" }, ":smile_cat:" }); + { "key1", "val1" }, + { "key2", "val2" } + }; - Assert.True( - output.Headers.Contains("Api-Version"), - "Headers include Api-Version header" - ); - Assert.True(output.Headers.Contains("X-Emoji"), "Headers include X-Emoji header"); - Assert.False( - output.Content.Headers.Contains("Api-Version"), - "Content headers include Api-Version header" - ); - Assert.False( - output.Content.Headers.Contains("X-Emoji"), - "Content headers include X-Emoji header" - ); - } + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod(interfaceMethodName); + var output = factory(new object[] { 6, headerCollection }); - [Theory] - [InlineData(nameof(IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollection))] - [InlineData(nameof(IDummyHttpApi.DeleteSomeStuffWithDynamicHeaderCollection))] - [InlineData(nameof(IDummyHttpApi.PutSomeStuffWithDynamicHeaderCollection))] - [InlineData(nameof(IDummyHttpApi.PostSomeStuffWithDynamicHeaderCollection))] - [InlineData(nameof(IDummyHttpApi.PatchSomeStuffWithDynamicHeaderCollection))] - public void HeaderCollectionShouldBeInHeaders(string interfaceMethodName) - { - var headerCollection = new Dictionary - { - { "key1", "val1" }, - { "key2", "val2" } - }; - - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod(interfaceMethodName); - var output = factory(new object[] { 6, headerCollection }); - - Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); - Assert.Equal("RefitTestClient", output.Headers.GetValues("User-Agent").First()); - Assert.True( - output.Headers.Contains("Api-Version"), - "Headers include Api-Version header" - ); - Assert.Equal("1", output.Headers.GetValues("Api-Version").First()); + Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); + Assert.Equal("RefitTestClient", output.Headers.GetValues("User-Agent").First()); + Assert.True( + output.Headers.Contains("Api-Version"), + "Headers include Api-Version header" + ); + Assert.Equal("1", output.Headers.GetValues("Api-Version").First()); - Assert.True( - output.Headers.Contains("Authorization"), - "Headers include Authorization header" - ); - Assert.Equal( - "SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", - output.Headers.GetValues("Authorization").First() - ); - Assert.True(output.Headers.Contains("Accept"), "Headers include Accept header"); - Assert.Equal("application/json", output.Headers.GetValues("Accept").First()); + Assert.True( + output.Headers.Contains("Authorization"), + "Headers include Authorization header" + ); + Assert.Equal( + "SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", + output.Headers.GetValues("Authorization").First() + ); + Assert.True(output.Headers.Contains("Accept"), "Headers include Accept header"); + Assert.Equal("application/json", output.Headers.GetValues("Accept").First()); - Assert.True(output.Headers.Contains("key1"), "Headers include key1 header"); - Assert.Equal("val1", output.Headers.GetValues("key1").First()); - Assert.True(output.Headers.Contains("key2"), "Headers include key2 header"); - Assert.Equal("val2", output.Headers.GetValues("key2").First()); - } + Assert.True(output.Headers.Contains("key1"), "Headers include key1 header"); + Assert.Equal("val1", output.Headers.GetValues("key1").First()); + Assert.True(output.Headers.Contains("key2"), "Headers include key2 header"); + Assert.Equal("val2", output.Headers.GetValues("key2").First()); + } - [Fact] - public void LastWriteWinsWhenHeaderCollectionAndDynamicHeader() + [Fact] + public void LastWriteWinsWhenHeaderCollectionAndDynamicHeader() + { + var authHeader = "LetMeIn"; + var headerCollection = new Dictionary { - var authHeader = "LetMeIn"; - var headerCollection = new Dictionary - { - { "Authorization", "OpenSesame" } - }; + { "Authorization", "OpenSesame" } + }; - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeader) - ); - var output = factory(new object[] { 6, authHeader, headerCollection }); + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeader) + ); + var output = factory(new object[] { 6, authHeader, headerCollection }); - Assert.True( - output.Headers.Contains("Authorization"), - "Headers include Authorization header" - ); - Assert.Equal("OpenSesame", output.Headers.GetValues("Authorization").First()); + Assert.True( + output.Headers.Contains("Authorization"), + "Headers include Authorization header" + ); + Assert.Equal("OpenSesame", output.Headers.GetValues("Authorization").First()); - fixture = new RequestBuilderImplementation(); - factory = fixture.BuildRequestFactoryForMethod( - nameof( - IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped - ) - ); - output = factory(new object[] { 6, headerCollection, authHeader }); + fixture = new RequestBuilderImplementation(); + factory = fixture.BuildRequestFactoryForMethod( + nameof( + IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollectionAndDynamicHeaderOrderFlipped + ) + ); + output = factory(new object[] { 6, headerCollection, authHeader }); - Assert.True( - output.Headers.Contains("Authorization"), - "Headers include Authorization header" - ); - Assert.Equal(authHeader, output.Headers.GetValues("Authorization").First()); - } + Assert.True( + output.Headers.Contains("Authorization"), + "Headers include Authorization header" + ); + Assert.Equal(authHeader, output.Headers.GetValues("Authorization").First()); + } - [Theory] - [InlineData(nameof(IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollection))] - [InlineData(nameof(IDummyHttpApi.DeleteSomeStuffWithDynamicHeaderCollection))] - [InlineData(nameof(IDummyHttpApi.PutSomeStuffWithDynamicHeaderCollection))] - [InlineData(nameof(IDummyHttpApi.PostSomeStuffWithDynamicHeaderCollection))] - [InlineData(nameof(IDummyHttpApi.PatchSomeStuffWithDynamicHeaderCollection))] - public void NullHeaderCollectionDoesntBlowUp(string interfaceMethodName) - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod(interfaceMethodName); - var output = factory(new object[] { 6, null }); - - Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); - Assert.Equal("RefitTestClient", output.Headers.GetValues("User-Agent").First()); - Assert.True( - output.Headers.Contains("Api-Version"), - "Headers include Api-Version header" - ); - Assert.Equal("1", output.Headers.GetValues("Api-Version").First()); + [Theory] + [InlineData(nameof(IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollection))] + [InlineData(nameof(IDummyHttpApi.DeleteSomeStuffWithDynamicHeaderCollection))] + [InlineData(nameof(IDummyHttpApi.PutSomeStuffWithDynamicHeaderCollection))] + [InlineData(nameof(IDummyHttpApi.PostSomeStuffWithDynamicHeaderCollection))] + [InlineData(nameof(IDummyHttpApi.PatchSomeStuffWithDynamicHeaderCollection))] + public void NullHeaderCollectionDoesntBlowUp(string interfaceMethodName) + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod(interfaceMethodName); + var output = factory(new object[] { 6, null }); - Assert.True( - output.Headers.Contains("Authorization"), - "Headers include Authorization header" - ); - Assert.Equal( - "SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", - output.Headers.GetValues("Authorization").First() - ); - Assert.True(output.Headers.Contains("Accept"), "Headers include Accept header"); - Assert.Equal("application/json", output.Headers.GetValues("Accept").First()); - } + Assert.True(output.Headers.Contains("User-Agent"), "Headers include User-Agent header"); + Assert.Equal("RefitTestClient", output.Headers.GetValues("User-Agent").First()); + Assert.True( + output.Headers.Contains("Api-Version"), + "Headers include Api-Version header" + ); + Assert.Equal("1", output.Headers.GetValues("Api-Version").First()); + + Assert.True( + output.Headers.Contains("Authorization"), + "Headers include Authorization header" + ); + Assert.Equal( + "SRSLY aHR0cDovL2kuaW1ndXIuY29tL0NGRzJaLmdpZg==", + output.Headers.GetValues("Authorization").First() + ); + Assert.True(output.Headers.Contains("Accept"), "Headers include Accept header"); + Assert.Equal("application/json", output.Headers.GetValues("Accept").First()); + } - [Fact] - public void HeaderCollectionCanUnsetHeaders() + [Fact] + public void HeaderCollectionCanUnsetHeaders() + { + var headerCollection = new Dictionary { - var headerCollection = new Dictionary - { - { "Authorization", "" }, - { "Api-Version", null } - }; + { "Authorization", "" }, + { "Api-Version", null } + }; - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollection) - ); - var output = factory(new object[] { 6, headerCollection }); + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.FetchSomeStuffWithDynamicHeaderCollection) + ); + var output = factory(new object[] { 6, headerCollection }); - Assert.True( - !output.Headers.Contains("Api-Version"), - "Headers does not include Api-Version header" - ); + Assert.True( + !output.Headers.Contains("Api-Version"), + "Headers does not include Api-Version header" + ); - Assert.True( - output.Headers.Contains("Authorization"), - "Headers include Authorization header" - ); - Assert.Equal("", output.Headers.GetValues("Authorization").First()); - } + Assert.True( + output.Headers.Contains("Authorization"), + "Headers include Authorization header" + ); + Assert.Equal("", output.Headers.GetValues("Authorization").First()); + } - [Theory] - [InlineData(nameof(IDummyHttpApi.FetchSomeStuffWithDynamicRequestProperty))] - [InlineData(nameof(IDummyHttpApi.DeleteSomeStuffWithDynamicRequestProperty))] - [InlineData(nameof(IDummyHttpApi.PutSomeStuffWithDynamicRequestProperty))] - [InlineData(nameof(IDummyHttpApi.PostSomeStuffWithDynamicRequestProperty))] - [InlineData(nameof(IDummyHttpApi.PatchSomeStuffWithDynamicRequestProperty))] - public void DynamicRequestPropertiesShouldBeInProperties(string interfaceMethodName) - { - var someProperty = new object(); - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod(interfaceMethodName); - var output = factory(new object[] { 6, someProperty }); + [Theory] + [InlineData(nameof(IDummyHttpApi.FetchSomeStuffWithDynamicRequestProperty))] + [InlineData(nameof(IDummyHttpApi.DeleteSomeStuffWithDynamicRequestProperty))] + [InlineData(nameof(IDummyHttpApi.PutSomeStuffWithDynamicRequestProperty))] + [InlineData(nameof(IDummyHttpApi.PostSomeStuffWithDynamicRequestProperty))] + [InlineData(nameof(IDummyHttpApi.PatchSomeStuffWithDynamicRequestProperty))] + public void DynamicRequestPropertiesShouldBeInProperties(string interfaceMethodName) + { + var someProperty = new object(); + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod(interfaceMethodName); + var output = factory(new object[] { 6, someProperty }); #if NET6_0_OR_GREATER - Assert.NotEmpty(output.Options); - Assert.Equal( - someProperty, - ((IDictionary)output.Options)["SomeProperty"] - ); + Assert.NotEmpty(output.Options); + Assert.Equal( + someProperty, + ((IDictionary)output.Options)["SomeProperty"] + ); #endif #pragma warning disable CS0618 // Type or member is obsolete - Assert.NotEmpty(output.Properties); - Assert.Equal(someProperty, output.Properties["SomeProperty"]); + Assert.NotEmpty(output.Properties); + Assert.Equal(someProperty, output.Properties["SomeProperty"]); #pragma warning restore CS0618 // Type or member is obsolete - } + } - [Fact] - public void OptionsFromSettingsShouldBeInProperties() - { - const string nameProp1 = "UnitTest.Property1"; - string valueProp1 = "TestValue"; - const string nameProp2 = "UnitTest.Property2"; - object valueProp2 = new List() { "123", "345" }; - var fixture = new RequestBuilderImplementation( - new RefitSettings() + [Fact] + public void OptionsFromSettingsShouldBeInProperties() + { + const string nameProp1 = "UnitTest.Property1"; + string valueProp1 = "TestValue"; + const string nameProp2 = "UnitTest.Property2"; + object valueProp2 = new List() { "123", "345" }; + var fixture = new RequestBuilderImplementation( + new RefitSettings() + { + HttpRequestMessageOptions = new Dictionary() { - HttpRequestMessageOptions = new Dictionary() - { - [nameProp1] = valueProp1, - [nameProp2] = valueProp2, - }, - } - ); - var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); - var output = factory(Array.Empty()); + [nameProp1] = valueProp1, + [nameProp2] = valueProp2, + }, + } + ); + var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); + var output = factory(Array.Empty()); #if NET6_0_OR_GREATER - Assert.NotEmpty(output.Options); - Assert.True( - output.Options.TryGetValue( - new HttpRequestOptionsKey(nameProp1), - out var resultValueProp1 - ) - ); - Assert.Equal(valueProp1, resultValueProp1); + Assert.NotEmpty(output.Options); + Assert.True( + output.Options.TryGetValue( + new HttpRequestOptionsKey(nameProp1), + out var resultValueProp1 + ) + ); + Assert.Equal(valueProp1, resultValueProp1); - Assert.True( - output.Options.TryGetValue( - new HttpRequestOptionsKey>(nameProp2), - out var resultValueProp2 - ) - ); - Assert.Equal(valueProp2, resultValueProp2); + Assert.True( + output.Options.TryGetValue( + new HttpRequestOptionsKey>(nameProp2), + out var resultValueProp2 + ) + ); + Assert.Equal(valueProp2, resultValueProp2); #else - Assert.NotEmpty(output.Properties); - Assert.True(output.Properties.TryGetValue(nameProp1, out var resultValueProp1)); - Assert.IsType(resultValueProp1); - Assert.Equal(valueProp1, (string)resultValueProp1); - - Assert.True(output.Properties.TryGetValue(nameProp2, out var resultValueProp2)); - Assert.IsType>(resultValueProp2); - Assert.Equal(valueProp2, (List)resultValueProp2); + Assert.NotEmpty(output.Properties); + Assert.True(output.Properties.TryGetValue(nameProp1, out var resultValueProp1)); + Assert.IsType(resultValueProp1); + Assert.Equal(valueProp1, (string)resultValueProp1); + + Assert.True(output.Properties.TryGetValue(nameProp2, out var resultValueProp2)); + Assert.IsType>(resultValueProp2); + Assert.Equal(valueProp2, (List)resultValueProp2); #endif - } + } - [Fact] - public void InterfaceTypeShouldBeInProperties() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); - var output = factory(Array.Empty()); + [Fact] + public void InterfaceTypeShouldBeInProperties() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); + var output = factory(Array.Empty()); #pragma warning disable CS0618 // Type or member is obsolete - Assert.NotEmpty(output.Properties); - Assert.Equal( - typeof(IContainAandB), - output.Properties[HttpRequestMessageOptions.InterfaceType] - ); + Assert.NotEmpty(output.Properties); + Assert.Equal( + typeof(IContainAandB), + output.Properties[HttpRequestMessageOptions.InterfaceType] + ); #pragma warning restore CS0618 // Type or member is obsolete - } + } - [Fact] - public void RestMethodInfoShouldBeInProperties() - { - var someProperty = new object(); - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); - var output = factory(new object[] { }); + [Fact] + public void RestMethodInfoShouldBeInProperties() + { + var someProperty = new object(); + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod(nameof(IContainAandB.Ping)); + var output = factory(new object[] { }); #if NET6_0_OR_GREATER - Assert.NotEmpty(output.Options); - Assert.True( - output.Options.TryGetValue( - new HttpRequestOptionsKey( - HttpRequestMessageOptions.RestMethodInfo - ), - out var restMethodInfo - ) - ); + Assert.NotEmpty(output.Options); + Assert.True( + output.Options.TryGetValue( + new HttpRequestOptionsKey( + HttpRequestMessageOptions.RestMethodInfo + ), + out var restMethodInfo + ) + ); #else - Assert.NotEmpty(output.Properties); - Assert.True( - output.Properties.TryGetValue( - HttpRequestMessageOptions.RestMethodInfo, - out var restMethodInfoObj - ) - ); - Assert.IsType(restMethodInfoObj); - var restMethodInfo = restMethodInfoObj as RestMethodInfo; + Assert.NotEmpty(output.Properties); + Assert.True( + output.Properties.TryGetValue( + HttpRequestMessageOptions.RestMethodInfo, + out var restMethodInfoObj + ) + ); + Assert.IsType(restMethodInfoObj); + var restMethodInfo = restMethodInfoObj as RestMethodInfo; #endif - Assert.Equal(nameof(IContainAandB.Ping), restMethodInfo.Name); - } + Assert.Equal(nameof(IContainAandB.Ping), restMethodInfo.Name); + } - [Fact] - public void DynamicRequestPropertiesWithDefaultKeysShouldBeInProperties() - { - var someProperty = new object(); - var someOtherProperty = new object(); - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.FetchSomeStuffWithDynamicRequestPropertyWithoutKey) - ); - var output = factory(new object[] { 6, someProperty, someOtherProperty }); + [Fact] + public void DynamicRequestPropertiesWithDefaultKeysShouldBeInProperties() + { + var someProperty = new object(); + var someOtherProperty = new object(); + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.FetchSomeStuffWithDynamicRequestPropertyWithoutKey) + ); + var output = factory(new object[] { 6, someProperty, someOtherProperty }); #if NET6_0_OR_GREATER - Assert.NotEmpty(output.Options); - Assert.Equal(someProperty, ((IDictionary)output.Options)["someValue"]); - Assert.Equal( - someOtherProperty, - ((IDictionary)output.Options)["someOtherValue"] - ); + Assert.NotEmpty(output.Options); + Assert.Equal(someProperty, ((IDictionary)output.Options)["someValue"]); + Assert.Equal( + someOtherProperty, + ((IDictionary)output.Options)["someOtherValue"] + ); #endif #pragma warning disable CS0618 // Type or member is obsolete - Assert.NotEmpty(output.Properties); - Assert.Equal(someProperty, output.Properties["someValue"]); - Assert.Equal(someOtherProperty, output.Properties["someOtherValue"]); + Assert.NotEmpty(output.Properties); + Assert.Equal(someProperty, output.Properties["someValue"]); + Assert.Equal(someOtherProperty, output.Properties["someOtherValue"]); #pragma warning restore CS0618 // Type or member is obsolete - } + } - [Fact] - public void DynamicRequestPropertiesWithDuplicateKeyShouldOverwritePreviousProperty() - { - var someProperty = new object(); - var someOtherProperty = new object(); - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey) - ); - var output = factory(new object[] { 6, someProperty, someOtherProperty }); + [Fact] + public void DynamicRequestPropertiesWithDuplicateKeyShouldOverwritePreviousProperty() + { + var someProperty = new object(); + var someOtherProperty = new object(); + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.FetchSomeStuffWithDynamicRequestPropertyWithDuplicateKey) + ); + var output = factory(new object[] { 6, someProperty, someOtherProperty }); #if NET6_0_OR_GREATER - Assert.Equal(3, output.Options.Count()); - Assert.Equal( - someOtherProperty, - ((IDictionary)output.Options)["SomeProperty"] - ); + Assert.Equal(3, output.Options.Count()); + Assert.Equal( + someOtherProperty, + ((IDictionary)output.Options)["SomeProperty"] + ); #endif #pragma warning disable CS0618 // Type or member is obsolete - Assert.Equal(3, output.Properties.Count); - Assert.Equal(someOtherProperty, output.Properties["SomeProperty"]); + Assert.Equal(3, output.Properties.Count); + Assert.Equal(someOtherProperty, output.Properties["SomeProperty"]); #pragma warning restore CS0618 // Type or member is obsolete - } + } - [Fact] - public void HttpClientShouldPrefixedAbsolutePathToTheRequestUri() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRestResultFuncForMethod("FetchSomeStuffWithoutFullPath"); - var testHttpMessageHandler = new TestHttpMessageHandler(); + [Fact] + public void HttpClientShouldPrefixedAbsolutePathToTheRequestUri() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRestResultFuncForMethod("FetchSomeStuffWithoutFullPath"); + var testHttpMessageHandler = new TestHttpMessageHandler(); - var task = (Task)factory( - new HttpClient(testHttpMessageHandler) - { - BaseAddress = new Uri("http://api/foo/bar") - }, - Array.Empty() - ); - task.Wait(); + var task = (Task)factory( + new HttpClient(testHttpMessageHandler) + { + BaseAddress = new Uri("http://api/foo/bar") + }, + Array.Empty() + ); + task.Wait(); - Assert.Equal( - "http://api/foo/bar/string", - testHttpMessageHandler.RequestMessage.RequestUri.ToString() - ); - } + Assert.Equal( + "http://api/foo/bar/string", + testHttpMessageHandler.RequestMessage.RequestUri.ToString() + ); + } - [Fact] - public void HttpClientForVoidMethodShouldPrefixedAbsolutePathToTheRequestUri() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRestResultFuncForMethod("FetchSomeStuffWithVoid"); - var testHttpMessageHandler = new TestHttpMessageHandler(); + [Fact] + public void HttpClientForVoidMethodShouldPrefixedAbsolutePathToTheRequestUri() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRestResultFuncForMethod("FetchSomeStuffWithVoid"); + var testHttpMessageHandler = new TestHttpMessageHandler(); - var task = (Task)factory( - new HttpClient(testHttpMessageHandler) - { - BaseAddress = new Uri("http://api/foo/bar") - }, - Array.Empty() - ); - task.Wait(); + var task = (Task)factory( + new HttpClient(testHttpMessageHandler) + { + BaseAddress = new Uri("http://api/foo/bar") + }, + Array.Empty() + ); + task.Wait(); - Assert.Equal( - "http://api/foo/bar/void", - testHttpMessageHandler.RequestMessage.RequestUri.ToString() - ); - } + Assert.Equal( + "http://api/foo/bar/void", + testHttpMessageHandler.RequestMessage.RequestUri.ToString() + ); + } - [Fact] - public void HttpClientShouldNotPrefixEmptyAbsolutePathToTheRequestUri() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRestResultFuncForMethod("FetchSomeStuff"); - var testHttpMessageHandler = new TestHttpMessageHandler(); + [Fact] + public void HttpClientShouldNotPrefixEmptyAbsolutePathToTheRequestUri() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRestResultFuncForMethod("FetchSomeStuff"); + var testHttpMessageHandler = new TestHttpMessageHandler(); - var task = (Task)factory( - new HttpClient(testHttpMessageHandler) { BaseAddress = new Uri("http://api/") }, - new object[] { 42 } - ); - task.Wait(); + var task = (Task)factory( + new HttpClient(testHttpMessageHandler) { BaseAddress = new Uri("http://api/") }, + new object[] { 42 } + ); + task.Wait(); - Assert.Equal( - "http://api/foo/bar/42", - testHttpMessageHandler.RequestMessage.RequestUri.ToString() - ); - } + Assert.Equal( + "http://api/foo/bar/42", + testHttpMessageHandler.RequestMessage.RequestUri.ToString() + ); + } - [Fact] - public void DontBlowUpWithDynamicAuthorizationHeaderAndContent() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("PutSomeContentWithAuthorization"); - var output = factory( - new object[] { 7, new { Octocat = "Dunetocat" }, "Basic RnVjayB5ZWFoOmhlYWRlcnMh" } - ); + [Fact] + public void DontBlowUpWithDynamicAuthorizationHeaderAndContent() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("PutSomeContentWithAuthorization"); + var output = factory( + new object[] { 7, new { Octocat = "Dunetocat" }, "Basic RnVjayB5ZWFoOmhlYWRlcnMh" } + ); - Assert.NotNull(output.Headers.Authorization); //, "Headers include Authorization header"); - Assert.Equal("RnVjayB5ZWFoOmhlYWRlcnMh", output.Headers.Authorization.Parameter); - } + Assert.NotNull(output.Headers.Authorization); //, "Headers include Authorization header"); + Assert.Equal("RnVjayB5ZWFoOmhlYWRlcnMh", output.Headers.Authorization.Parameter); + } - [Fact] - public void SuchFlexibleContentTypeWow() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "PutSomeStuffWithDynamicContentType" - ); - var output = factory( - new object[] { 7, "such \"refit\" is \"amaze\" wow", "text/dson" } - ); + [Fact] + public void SuchFlexibleContentTypeWow() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "PutSomeStuffWithDynamicContentType" + ); + var output = factory( + new object[] { 7, "such \"refit\" is \"amaze\" wow", "text/dson" } + ); - Assert.NotNull(output.Content); //, "Request has content"); - Assert.NotNull(output.Content.Headers.ContentType); //, "Headers include Content-Type header"); - Assert.Equal("text/dson", output.Content.Headers.ContentType.MediaType); //, "Content-Type header has the expected value"); - } + Assert.NotNull(output.Content); //, "Request has content"); + Assert.NotNull(output.Content.Headers.ContentType); //, "Headers include Content-Type header"); + Assert.Equal("text/dson", output.Content.Headers.ContentType.MediaType); //, "Content-Type header has the expected value"); + } - [Fact] - public void BodyContentGetsUrlEncoded() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.RunRequest("PostSomeUrlEncodedStuff"); - var output = factory( - new object[] + [Fact] + public void BodyContentGetsUrlEncoded() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.RunRequest("PostSomeUrlEncodedStuff"); + var output = factory( + new object[] + { + 6, + new { - 6, - new - { - Foo = "Something", - Bar = 100, - Baz = "" // explicitly use blank to preserve value that would be stripped if null - } + Foo = "Something", + Bar = 100, + Baz = "" // explicitly use blank to preserve value that would be stripped if null } - ); + } + ); - Assert.Equal("Foo=Something&Bar=100&Baz=", output.SendContent); - } + Assert.Equal("Foo=Something&Bar=100&Baz=", output.SendContent); + } - [Fact] - public void FormFieldGetsAliased() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.RunRequest("PostSomeAliasedUrlEncodedStuff"); - var output = factory( - new object[] - { - 6, - new SomeRequestData { ReadablePropertyName = 99 } - } - ); + [Fact] + public void FormFieldGetsAliased() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.RunRequest("PostSomeAliasedUrlEncodedStuff"); + var output = factory( + new object[] + { + 6, + new SomeRequestData { ReadablePropertyName = 99 } + } + ); - Assert.Equal("rpn=99", output.SendContent); - } + Assert.Equal("rpn=99", output.SendContent); + } - [Fact] - public void CustomParmeterFormatter() + [Fact] + public void CustomParmeterFormatter() + { + var settings = new RefitSettings { - var settings = new RefitSettings - { - UrlParameterFormatter = new TestUrlParameterFormatter("custom-parameter") - }; - var fixture = new RequestBuilderImplementation(settings); + UrlParameterFormatter = new TestUrlParameterFormatter("custom-parameter") + }; + var fixture = new RequestBuilderImplementation(settings); - var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuff"); - var output = factory(new object[] { 5 }); + var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuff"); + var output = factory(new object[] { 5 }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/foo/bar/custom-parameter", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/foo/bar/custom-parameter", uri.PathAndQuery); + } - [Fact] - public void QueryStringWithEnumerablesCanBeFormatted() + [Fact] + public void QueryStringWithEnumerablesCanBeFormatted() + { + var settings = new RefitSettings { - var settings = new RefitSettings - { - UrlParameterFormatter = new TestEnumerableUrlParameterFormatter() - }; - var fixture = new RequestBuilderImplementation(settings); + UrlParameterFormatter = new TestEnumerableUrlParameterFormatter() + }; + var fixture = new RequestBuilderImplementation(settings); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithEnumerable"); - var output = factory(new object[] { new int[] { 1, 2, 3 } }); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithEnumerable"); + var output = factory(new object[] { new int[] { 1, 2, 3 } }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/query?numbers=1%2C2%2C3", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/query?numbers=1%2C2%2C3", uri.PathAndQuery); + } - [Fact] - public void QueryStringWithArrayCanBeFormatted() + [Fact] + public void QueryStringWithArrayCanBeFormatted() + { + var settings = new RefitSettings { - var settings = new RefitSettings - { - UrlParameterFormatter = new TestEnumerableUrlParameterFormatter() - }; - var fixture = new RequestBuilderImplementation(settings); + UrlParameterFormatter = new TestEnumerableUrlParameterFormatter() + }; + var fixture = new RequestBuilderImplementation(settings); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithArray"); - var output = factory(new object[] { new int[] { 1, 2, 3 } }); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithArray"); + var output = factory(new object[] { new int[] { 1, 2, 3 } }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/query?numbers=1%2C2%2C3", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/query?numbers=1%2C2%2C3", uri.PathAndQuery); + } - [Fact] - public void QueryStringWithArrayCanBeFormattedByAttribute() - { - var fixture = new RequestBuilderImplementation(); + [Fact] + public void QueryStringWithArrayCanBeFormattedByAttribute() + { + var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("UnescapedQueryParams"); - var output = factory(new object[] { "Select+Id,Name+From+Account" }); + var factory = fixture.BuildRequestFactoryForMethod("UnescapedQueryParams"); + var output = factory(new object[] { "Select+Id,Name+From+Account" }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/query?q=Select+Id,Name+From+Account", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/query?q=Select+Id,Name+From+Account", uri.PathAndQuery); + } - [Fact] - public void QueryStringWithArrayCanBeFormattedByAttributeWithMultiple() - { - var fixture = new RequestBuilderImplementation(); + [Fact] + public void QueryStringWithArrayCanBeFormattedByAttributeWithMultiple() + { + var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("UnescapedQueryParamsWithFilter"); - var output = factory(new object[] { "Select+Id+From+Account", "*" }); + var factory = fixture.BuildRequestFactoryForMethod("UnescapedQueryParamsWithFilter"); + var output = factory(new object[] { "Select+Id+From+Account", "*" }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/query?q=Select+Id+From+Account&filter=*", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/query?q=Select+Id+From+Account&filter=*", uri.PathAndQuery); + } - [Fact] - public void QueryStringWithArrayCanBeFormattedByDefaultSetting() - { - var fixture = new RequestBuilderImplementation( - new RefitSettings { CollectionFormat = CollectionFormat.Multi } - ); + [Fact] + public void QueryStringWithArrayCanBeFormattedByDefaultSetting() + { + var fixture = new RequestBuilderImplementation( + new RefitSettings { CollectionFormat = CollectionFormat.Multi } + ); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithArray"); - var output = factory(new object[] { new[] { 1, 2, 3 } }); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithArray"); + var output = factory(new object[] { new[] { 1, 2, 3 } }); - Assert.Equal("/query?numbers=1&numbers=2&numbers=3", output.RequestUri.PathAndQuery); - } + Assert.Equal("/query?numbers=1&numbers=2&numbers=3", output.RequestUri.PathAndQuery); + } - [Fact] - public void DefaultCollectionFormatCanBeOverridenByQueryAttribute() - { - var fixture = new RequestBuilderImplementation( - new RefitSettings { CollectionFormat = CollectionFormat.Multi } - ); + [Fact] + public void DefaultCollectionFormatCanBeOverridenByQueryAttribute() + { + var fixture = new RequestBuilderImplementation( + new RefitSettings { CollectionFormat = CollectionFormat.Multi } + ); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithArrayFormattedAsCsv"); - var output = factory(new object[] { new[] { 1, 2, 3 } }); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithArrayFormattedAsCsv"); + var output = factory(new object[] { new[] { 1, 2, 3 } }); - Assert.Equal("/query?numbers=1%2C2%2C3", output.RequestUri.PathAndQuery); - } + Assert.Equal("/query?numbers=1%2C2%2C3", output.RequestUri.PathAndQuery); + } - [Fact] - public void RequestWithParameterInMultiplePlaces() - { - var fixture = new RequestBuilderImplementation(); + [Fact] + public void RequestWithParameterInMultiplePlaces() + { + var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.FetchSomeStuffWithTheSameId) - ); - var output = factory(new object[] { "theId" }); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.FetchSomeStuffWithTheSameId) + ); + var output = factory(new object[] { "theId" }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - var builder = new UriBuilder(uri); - var qs = QueryHelpers.ParseQuery(uri.Query); - Assert.Equal("/foo/bar/theId", builder.Path); - Assert.Equal("theId", qs["param1"]); - Assert.Equal("theId", qs["param2"]); - } + var builder = new UriBuilder(uri); + var qs = QueryHelpers.ParseQuery(uri.Query); + Assert.Equal("/foo/bar/theId", builder.Path); + Assert.Equal("theId", qs["param1"]); + Assert.Equal("theId", qs["param2"]); + } - [Fact] - public void RequestWithParameterInAQueryParameterMultipleTimes() - { - var fixture = new RequestBuilderImplementation(); + [Fact] + public void RequestWithParameterInAQueryParameterMultipleTimes() + { + var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.FetchSomeStuffWithTheIdInAParameterMultipleTimes) - ); - var output = factory(new object[] { "theId" }); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.FetchSomeStuffWithTheIdInAParameterMultipleTimes) + ); + var output = factory(new object[] { "theId" }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/foo/bar?param=first%20theId%20and%20second%20theId", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/foo/bar?param=first%20theId%20and%20second%20theId", uri.PathAndQuery); + } - [Theory] - [InlineData("QueryWithArrayFormattedAsMulti", "/query?numbers=1&numbers=2&numbers=3")] - [InlineData("QueryWithArrayFormattedAsCsv", "/query?numbers=1%2C2%2C3")] - [InlineData("QueryWithArrayFormattedAsSsv", "/query?numbers=1%202%203")] - [InlineData("QueryWithArrayFormattedAsTsv", "/query?numbers=1%092%093")] - [InlineData("QueryWithArrayFormattedAsPipes", "/query?numbers=1%7C2%7C3")] - public void QueryStringWithArrayFormatted(string apiMethodName, string expectedQuery) - { - var fixture = new RequestBuilderImplementation(); + [Theory] + [InlineData("QueryWithArrayFormattedAsMulti", "/query?numbers=1&numbers=2&numbers=3")] + [InlineData("QueryWithArrayFormattedAsCsv", "/query?numbers=1%2C2%2C3")] + [InlineData("QueryWithArrayFormattedAsSsv", "/query?numbers=1%202%203")] + [InlineData("QueryWithArrayFormattedAsTsv", "/query?numbers=1%092%093")] + [InlineData("QueryWithArrayFormattedAsPipes", "/query?numbers=1%7C2%7C3")] + public void QueryStringWithArrayFormatted(string apiMethodName, string expectedQuery) + { + var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod(apiMethodName); - var output = factory(new object[] { new[] { 1, 2, 3 } }); + var factory = fixture.BuildRequestFactoryForMethod(apiMethodName); + var output = factory(new object[] { new[] { 1, 2, 3 } }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal(expectedQuery, uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal(expectedQuery, uri.PathAndQuery); + } - [Fact] - public void QueryStringWithArrayFormattedAsSsvAndItemsFormattedIndividually() + [Fact] + public void QueryStringWithArrayFormattedAsSsvAndItemsFormattedIndividually() + { + var settings = new RefitSettings { - var settings = new RefitSettings - { - UrlParameterFormatter = new TestUrlParameterFormatter("custom-parameter") - }; - var fixture = new RequestBuilderImplementation(settings); + UrlParameterFormatter = new TestUrlParameterFormatter("custom-parameter") + }; + var fixture = new RequestBuilderImplementation(settings); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithArrayFormattedAsSsv"); - var output = factory(new object[] { new int[] { 1, 2, 3 } }); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithArrayFormattedAsSsv"); + var output = factory(new object[] { new int[] { 1, 2, 3 } }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal( - "/query?numbers=custom-parameter%20custom-parameter%20custom-parameter", - uri.PathAndQuery - ); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal( + "/query?numbers=custom-parameter%20custom-parameter%20custom-parameter", + uri.PathAndQuery + ); + } - [Fact] - public void QueryStringWithEnumerablesCanBeFormattedEnumerable() + [Fact] + public void QueryStringWithEnumerablesCanBeFormattedEnumerable() + { + var settings = new RefitSettings { - var settings = new RefitSettings - { - UrlParameterFormatter = new TestEnumerableUrlParameterFormatter() - }; - var fixture = new RequestBuilderImplementation(settings); + UrlParameterFormatter = new TestEnumerableUrlParameterFormatter() + }; + var fixture = new RequestBuilderImplementation(settings); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithEnumerable"); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithEnumerable"); - var list = new List { 1, 2, 3 }; + var list = new List { 1, 2, 3 }; - var output = factory(new object[] { list }); + var output = factory(new object[] { list }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/query?numbers=1%2C2%2C3", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/query?numbers=1%2C2%2C3", uri.PathAndQuery); + } - [Theory] - [InlineData( - "QueryWithEnumerableFormattedAsMulti", - "/query?lines=first&lines=second&lines=third" - )] - [InlineData("QueryWithEnumerableFormattedAsCsv", "/query?lines=first%2Csecond%2Cthird")] - [InlineData("QueryWithEnumerableFormattedAsSsv", "/query?lines=first%20second%20third")] - [InlineData("QueryWithEnumerableFormattedAsTsv", "/query?lines=first%09second%09third")] - [InlineData("QueryWithEnumerableFormattedAsPipes", "/query?lines=first%7Csecond%7Cthird")] - public void QueryStringWithEnumerableFormatted(string apiMethodName, string expectedQuery) - { - var fixture = new RequestBuilderImplementation(); + [Theory] + [InlineData( + "QueryWithEnumerableFormattedAsMulti", + "/query?lines=first&lines=second&lines=third" + )] + [InlineData("QueryWithEnumerableFormattedAsCsv", "/query?lines=first%2Csecond%2Cthird")] + [InlineData("QueryWithEnumerableFormattedAsSsv", "/query?lines=first%20second%20third")] + [InlineData("QueryWithEnumerableFormattedAsTsv", "/query?lines=first%09second%09third")] + [InlineData("QueryWithEnumerableFormattedAsPipes", "/query?lines=first%7Csecond%7Cthird")] + public void QueryStringWithEnumerableFormatted(string apiMethodName, string expectedQuery) + { + var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod(apiMethodName); + var factory = fixture.BuildRequestFactoryForMethod(apiMethodName); - var lines = new List { "first", "second", "third" }; + var lines = new List { "first", "second", "third" }; - var output = factory(new object[] { lines }); + var output = factory(new object[] { lines }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal(expectedQuery, uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal(expectedQuery, uri.PathAndQuery); + } - [Fact] - public void QueryStringExcludesPropertiesWithPrivateGetters() - { - var fixture = new RequestBuilderImplementation(); + [Fact] + public void QueryStringExcludesPropertiesWithPrivateGetters() + { + var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithObjectWithPrivateGetters"); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithObjectWithPrivateGetters"); - var person = new Person { FirstName = "Mickey", LastName = "Mouse" }; + var person = new Person { FirstName = "Mickey", LastName = "Mouse" }; - var output = factory(new object[] { person }); + var output = factory(new object[] { person }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/query?FullName=Mickey%20Mouse", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/query?FullName=Mickey%20Mouse", uri.PathAndQuery); + } - [Theory] - [InlineData(FooWithEnumMember.A, "/query?foo=A")] - [InlineData(FooWithEnumMember.B, "/query?foo=b")] - public void QueryStringUsesEnumMemberAttribute( - FooWithEnumMember queryParameter, - string expectedQuery - ) - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithEnum"); + [Theory] + [InlineData(FooWithEnumMember.A, "/query?foo=A")] + [InlineData(FooWithEnumMember.B, "/query?foo=b")] + public void QueryStringUsesEnumMemberAttribute( + FooWithEnumMember queryParameter, + string expectedQuery + ) + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithEnum"); - var output = factory(new object[] { queryParameter }); + var output = factory(new object[] { queryParameter }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal(expectedQuery, uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal(expectedQuery, uri.PathAndQuery); + } - [Theory] - [InlineData(FooWithEnumMember.A, "/query?foo=A")] - [InlineData(FooWithEnumMember.B, "/query?foo=b")] - public void QueryStringUsesEnumMemberAttributeInTypeWithEnum( - FooWithEnumMember queryParameter, - string expectedQuery - ) - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithTypeWithEnum"); + [Theory] + [InlineData(FooWithEnumMember.A, "/query?foo=A")] + [InlineData(FooWithEnumMember.B, "/query?foo=b")] + public void QueryStringUsesEnumMemberAttributeInTypeWithEnum( + FooWithEnumMember queryParameter, + string expectedQuery + ) + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithTypeWithEnum"); - var output = factory( - new object[] { new TypeFooWithEnumMember { Foo = queryParameter } } - ); + var output = factory( + new object[] { new TypeFooWithEnumMember { Foo = queryParameter } } + ); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal(expectedQuery, uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal(expectedQuery, uri.PathAndQuery); + } - [Theory] - [InlineData("/api/123?text=title&optionalId=999&filters=A&filters=B")] - public void TestNullableQueryStringParams(string expectedQuery) - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithOptionalParameters"); - var output = factory(new object[] { 123, "title", 999, new string[] { "A", "B" } }); + [Theory] + [InlineData("/api/123?text=title&optionalId=999&filters=A&filters=B")] + public void TestNullableQueryStringParams(string expectedQuery) + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithOptionalParameters"); + var output = factory(new object[] { 123, "title", 999, new string[] { "A", "B" } }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal(expectedQuery, uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal(expectedQuery, uri.PathAndQuery); + } - [Theory] - [InlineData("/api/123?text=title&filters=A&filters=B")] - public void TestNullableQueryStringParamsWithANull(string expectedQuery) - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("QueryWithOptionalParameters"); - var output = factory(new object[] { 123, "title", null, new string[] { "A", "B" } }); + [Theory] + [InlineData("/api/123?text=title&filters=A&filters=B")] + public void TestNullableQueryStringParamsWithANull(string expectedQuery) + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("QueryWithOptionalParameters"); + var output = factory(new object[] { 123, "title", null, new string[] { "A", "B" } }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal(expectedQuery, uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal(expectedQuery, uri.PathAndQuery); + } - [Theory] - [InlineData("/api/123?SomeProperty2=test&text=title&filters=A&filters=B")] - public void TestNullableQueryStringParamsWithANullAndPathBoundObject(string expectedQuery) - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - "QueryWithOptionalParametersPathBoundObject" - ); - var output = factory( - new object[] - { - new PathBoundObject() { SomeProperty = 123, SomeProperty2 = "test" }, - "title", - null, - new string[] { "A", "B" } - } - ); + [Theory] + [InlineData("/api/123?SomeProperty2=test&text=title&filters=A&filters=B")] + public void TestNullableQueryStringParamsWithANullAndPathBoundObject(string expectedQuery) + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + "QueryWithOptionalParametersPathBoundObject" + ); + var output = factory( + new object[] + { + new PathBoundObject() { SomeProperty = 123, SomeProperty2 = "test" }, + "title", + null, + new string[] { "A", "B" } + } + ); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal(expectedQuery, uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal(expectedQuery, uri.PathAndQuery); + } - [Fact] - [UseCulture("es-ES")] // Spain uses a , instead of a . - public void DefaultParameterFormatterIsInvariant() - { - var settings = new RefitSettings(); - var fixture = new RequestBuilderImplementation(settings); + [Fact] + [UseCulture("es-ES")] // Spain uses a , instead of a . + public void DefaultParameterFormatterIsInvariant() + { + var settings = new RefitSettings(); + var fixture = new RequestBuilderImplementation(settings); - var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuff"); - var output = factory(new object[] { 5.4 }); + var factory = fixture.BuildRequestFactoryForMethod("FetchSomeStuff"); + var output = factory(new object[] { 5.4 }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/foo/bar/5.4", uri.PathAndQuery); - } + var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/foo/bar/5.4", uri.PathAndQuery); + } - [Fact] - public void ICanPostAValueTypeIfIWantYoureNotTheBossOfMe() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.RunRequest("PostAValueType", "true"); - var guid = Guid.NewGuid(); - var expected = string.Format("\"{0}\"", guid); - var output = factory(new object[] { 7, guid }); + [Fact] + public void ICanPostAValueTypeIfIWantYoureNotTheBossOfMe() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.RunRequest("PostAValueType", "true"); + var guid = Guid.NewGuid(); + var expected = string.Format("\"{0}\"", guid); + var output = factory(new object[] { 7, guid }); - Assert.Equal(expected, output.SendContent); - } + Assert.Equal(expected, output.SendContent); + } - [Fact] - public void DeleteWithQuery() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("Clear"); + [Fact] + public void DeleteWithQuery() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("Clear"); - var output = factory(new object[] { 1 }); + var output = factory(new object[] { 1 }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/api/v1/video?playerIndex=1", uri.PathAndQuery); - } + Assert.Equal("/api/v1/video?playerIndex=1", uri.PathAndQuery); + } - [Fact] - public void ClearWithQuery() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod("ClearWithEnumMember"); + [Fact] + public void ClearWithQuery() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod("ClearWithEnumMember"); - var output = factory(new object[] { FooWithEnumMember.B }); + var output = factory(new object[] { FooWithEnumMember.B }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/api/bar?foo=b", uri.PathAndQuery); - } + Assert.Equal("/api/bar?foo=b", uri.PathAndQuery); + } - [Fact] - public void MultipartPostWithAliasAndHeader() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.RunRequest("UploadFile", "true"); + [Fact] + public void MultipartPostWithAliasAndHeader() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.RunRequest("UploadFile", "true"); - using var file = MultipartTests.GetTestFileStream("Test Files/Test.pdf"); + using var file = MultipartTests.GetTestFileStream("Test Files/Test.pdf"); - var sp = new StreamPart(file, "aFile"); + var sp = new StreamPart(file, "aFile"); - var output = factory(new object[] { 42, "aPath", sp, "theAuth", false, "theMeta" }); + var output = factory(new object[] { 42, "aPath", sp, "theAuth", false, "theMeta" }); - var uri = new Uri(new Uri("http://api"), output.RequestMessage.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestMessage.RequestUri); - Assert.Equal("/companies/42/aPath", uri.PathAndQuery); - Assert.Equal("theAuth", output.RequestMessage.Headers.Authorization.ToString()); - } + Assert.Equal("/companies/42/aPath", uri.PathAndQuery); + Assert.Equal("theAuth", output.RequestMessage.Headers.Authorization.ToString()); + } - [Fact] - public void PostBlobByteWithAlias() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.Blob_Post_Byte) - ); + [Fact] + public void PostBlobByteWithAlias() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.Blob_Post_Byte) + ); - var bytes = new byte[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + var bytes = new byte[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - var bap = new ByteArrayPart(bytes, "theBytes"); + var bap = new ByteArrayPart(bytes, "theBytes"); - var output = factory(new object[] { "the/path", bap }); + var output = factory(new object[] { "the/path", bap }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal("/blobstorage/the/path", uri.PathAndQuery); - } + Assert.Equal("/blobstorage/the/path", uri.PathAndQuery); + } - [Fact] - public void QueryWithAliasAndHeadersWorks() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.QueryWithHeadersBeforeData) - ); + [Fact] + public void QueryWithAliasAndHeadersWorks() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.QueryWithHeadersBeforeData) + ); - var authHeader = "theAuth"; - var langHeader = "LnG"; - var searchParam = "theSearchParam"; - var controlIdParam = "theControlId"; - var secretValue = "theSecret"; + var authHeader = "theAuth"; + var langHeader = "LnG"; + var searchParam = "theSearchParam"; + var controlIdParam = "theControlId"; + var secretValue = "theSecret"; - var output = factory( - new object[] { authHeader, langHeader, searchParam, controlIdParam, secretValue } - ); + var output = factory( + new object[] { authHeader, langHeader, searchParam, controlIdParam, secretValue } + ); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal( - $"/api/someModule/deviceList?controlId={controlIdParam}&search={searchParam}&secret={secretValue}", - uri.PathAndQuery - ); - Assert.Equal(langHeader, output.Headers.GetValues("X-LnG").FirstOrDefault()); - Assert.Equal(authHeader, output.Headers.Authorization?.Scheme); - } + Assert.Equal( + $"/api/someModule/deviceList?controlId={controlIdParam}&search={searchParam}&secret={secretValue}", + uri.PathAndQuery + ); + Assert.Equal(langHeader, output.Headers.GetValues("X-LnG").FirstOrDefault()); + Assert.Equal(authHeader, output.Headers.Authorization?.Scheme); + } - class RequestBuilderMock : IRequestBuilder - { - public int CallCount { get; private set; } + class RequestBuilderMock : IRequestBuilder + { + public int CallCount { get; private set; } - public Func BuildRestResultFuncForMethod( - string methodName, - Type[] parameterTypes = null, - Type[] genericArgumentTypes = null - ) - { - CallCount++; - return null; - } + public Func BuildRestResultFuncForMethod( + string methodName, + Type[] parameterTypes = null, + Type[] genericArgumentTypes = null + ) + { + CallCount++; + return null; } + } - [Fact] - public void CachedRequestBuilderCallInternalBuilderForParametersWithSameNamesButDifferentNamespaces() - { - var internalBuilder = new RequestBuilderMock(); - var cachedBuilder = new CachedRequestBuilderImplementation(internalBuilder); + [Fact] + public void CachedRequestBuilderCallInternalBuilderForParametersWithSameNamesButDifferentNamespaces() + { + var internalBuilder = new RequestBuilderMock(); + var cachedBuilder = new CachedRequestBuilderImplementation(internalBuilder); - cachedBuilder.BuildRestResultFuncForMethod( - "TestMethodName", - new[] { typeof(CollisionA.SomeType) } - ); - cachedBuilder.BuildRestResultFuncForMethod( - "TestMethodName", - new[] { typeof(CollisionB.SomeType) } - ); - cachedBuilder.BuildRestResultFuncForMethod( - "TestMethodName", - null, - new[] { typeof(CollisionA.SomeType) } - ); - cachedBuilder.BuildRestResultFuncForMethod( - "TestMethodName", - null, - new[] { typeof(CollisionB.SomeType) } - ); + cachedBuilder.BuildRestResultFuncForMethod( + "TestMethodName", + new[] { typeof(CollisionA.SomeType) } + ); + cachedBuilder.BuildRestResultFuncForMethod( + "TestMethodName", + new[] { typeof(CollisionB.SomeType) } + ); + cachedBuilder.BuildRestResultFuncForMethod( + "TestMethodName", + null, + new[] { typeof(CollisionA.SomeType) } + ); + cachedBuilder.BuildRestResultFuncForMethod( + "TestMethodName", + null, + new[] { typeof(CollisionB.SomeType) } + ); - Assert.Equal(4, internalBuilder.CallCount); - } + Assert.Equal(4, internalBuilder.CallCount); + } + + [Fact] + public void DictionaryQueryWithEnumKeyProducesCorrectQueryString() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.QueryWithDictionaryWithEnumKey) + ); - [Fact] - public void DictionaryQueryWithEnumKeyProducesCorrectQueryString() + var dict = new Dictionary { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.QueryWithDictionaryWithEnumKey) - ); + { TestEnum.A, "value1" }, + { TestEnum.B, "value2" }, + }; - var dict = new Dictionary - { - { TestEnum.A, "value1" }, - { TestEnum.B, "value2" }, - }; + var output = factory(new object[] { dict }); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - var output = factory(new object[] { dict }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/foo?A=value1&B=value2", uri.PathAndQuery); + } - Assert.Equal("/foo?A=value1&B=value2", uri.PathAndQuery); - } + [Fact] + public void DictionaryQueryWithPrefix() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.QueryWithDictionaryWithPrefix) + ); - [Fact] - public void DictionaryQueryWithPrefix() + var dict = new Dictionary { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.QueryWithDictionaryWithPrefix) - ); + { TestEnum.A, "value1" }, + { TestEnum.B, "value2" }, + }; - var dict = new Dictionary - { - { TestEnum.A, "value1" }, - { TestEnum.B, "value2" }, - }; + var output = factory(new object[] { dict }); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - var output = factory(new object[] { dict }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + Assert.Equal("/foo?dictionary.A=value1&dictionary.B=value2", uri.PathAndQuery); + } - Assert.Equal("/foo?dictionary.A=value1&dictionary.B=value2", uri.PathAndQuery); - } + [Fact] + public void DictionaryQueryWithNumericKeyProducesCorrectQueryString() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.QueryWithDictionaryWithNumericKey) + ); - [Fact] - public void DictionaryQueryWithNumericKeyProducesCorrectQueryString() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.QueryWithDictionaryWithNumericKey) - ); + var dict = new Dictionary { { 1, "value1" }, { 2, "value2" }, }; + + var output = factory(new object[] { dict }); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - var dict = new Dictionary { { 1, "value1" }, { 2, "value2" }, }; + Assert.Equal("/foo?1=value1&2=value2", uri.PathAndQuery); + } - var output = factory(new object[] { dict }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + [Fact] + public void DictionaryQueryWithCustomFormatterProducesCorrectQueryString() + { + var urlParameterFormatter = new TestEnumUrlParameterFormatter(); - Assert.Equal("/foo?1=value1&2=value2", uri.PathAndQuery); - } + var refitSettings = new RefitSettings { UrlParameterFormatter = urlParameterFormatter }; + var fixture = new RequestBuilderImplementation(refitSettings); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.QueryWithDictionaryWithEnumKey) + ); - [Fact] - public void DictionaryQueryWithCustomFormatterProducesCorrectQueryString() + var dict = new Dictionary { - var urlParameterFormatter = new TestEnumUrlParameterFormatter(); + { TestEnum.A, "value1" }, + { TestEnum.B, "value2" }, + }; - var refitSettings = new RefitSettings { UrlParameterFormatter = urlParameterFormatter }; - var fixture = new RequestBuilderImplementation(refitSettings); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.QueryWithDictionaryWithEnumKey) - ); + var output = factory(new object[] { dict }); + var uri = new Uri(new Uri("http://api"), output.RequestUri); + + Assert.Equal( + $"/foo?{(int)TestEnum.A}=value1{TestEnumUrlParameterFormatter.StringParameterSuffix}&{(int)TestEnum.B}=value2{TestEnumUrlParameterFormatter.StringParameterSuffix}", + uri.PathAndQuery + ); + } - var dict = new Dictionary + [Fact] + public void ComplexQueryObjectWithAliasedDictionaryProducesCorrectQueryString() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.ComplexQueryObjectWithDictionary) + ); + + var complexQuery = new ComplexQueryObject + { + TestAliasedDictionary = new Dictionary { { TestEnum.A, "value1" }, { TestEnum.B, "value2" }, - }; + }, + }; - var output = factory(new object[] { dict }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var output = factory(new object[] { complexQuery }); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal( - $"/foo?{(int)TestEnum.A}=value1{TestEnumUrlParameterFormatter.StringParameterSuffix}&{(int)TestEnum.B}=value2{TestEnumUrlParameterFormatter.StringParameterSuffix}", - uri.PathAndQuery - ); - } + Assert.Equal( + "/foo?test-dictionary-alias.A=value1&test-dictionary-alias.B=value2", + uri.PathAndQuery + ); + } - [Fact] - public void ComplexQueryObjectWithAliasedDictionaryProducesCorrectQueryString() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.ComplexQueryObjectWithDictionary) - ); + [Fact] + public void ComplexQueryObjectWithDictionaryProducesCorrectQueryString() + { + var fixture = new RequestBuilderImplementation(); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.ComplexQueryObjectWithDictionary) + ); - var complexQuery = new ComplexQueryObject + var complexQuery = new ComplexQueryObject + { + TestDictionary = new Dictionary { - TestAliasedDictionary = new Dictionary - { - { TestEnum.A, "value1" }, - { TestEnum.B, "value2" }, - }, - }; + { TestEnum.A, "value1" }, + { TestEnum.B, "value2" }, + }, + }; - var output = factory(new object[] { complexQuery }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); + var output = factory(new object[] { complexQuery }); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - Assert.Equal( - "/foo?test-dictionary-alias.A=value1&test-dictionary-alias.B=value2", - uri.PathAndQuery - ); - } + Assert.Equal("/foo?TestDictionary.A=value1&TestDictionary.B=value2", uri.PathAndQuery); + } - [Fact] - public void ComplexQueryObjectWithDictionaryProducesCorrectQueryString() - { - var fixture = new RequestBuilderImplementation(); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.ComplexQueryObjectWithDictionary) - ); + [Fact] + public void ComplexQueryObjectWithDictionaryAndCustomFormatterProducesCorrectQueryString() + { + var urlParameterFormatter = new TestEnumUrlParameterFormatter(); + var refitSettings = new RefitSettings { UrlParameterFormatter = urlParameterFormatter }; + var fixture = new RequestBuilderImplementation(refitSettings); + var factory = fixture.BuildRequestFactoryForMethod( + nameof(IDummyHttpApi.ComplexQueryObjectWithDictionary) + ); - var complexQuery = new ComplexQueryObject + var complexQuery = new ComplexQueryObject + { + TestDictionary = new Dictionary { - TestDictionary = new Dictionary - { - { TestEnum.A, "value1" }, - { TestEnum.B, "value2" }, - }, - }; - - var output = factory(new object[] { complexQuery }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); - - Assert.Equal("/foo?TestDictionary.A=value1&TestDictionary.B=value2", uri.PathAndQuery); - } + { TestEnum.A, "value1" }, + { TestEnum.B, "value2" }, + }, + }; - [Fact] - public void ComplexQueryObjectWithDictionaryAndCustomFormatterProducesCorrectQueryString() - { - var urlParameterFormatter = new TestEnumUrlParameterFormatter(); - var refitSettings = new RefitSettings { UrlParameterFormatter = urlParameterFormatter }; - var fixture = new RequestBuilderImplementation(refitSettings); - var factory = fixture.BuildRequestFactoryForMethod( - nameof(IDummyHttpApi.ComplexQueryObjectWithDictionary) - ); + var output = factory(new object[] { complexQuery }); + var uri = new Uri(new Uri("http://api"), output.RequestUri); - var complexQuery = new ComplexQueryObject - { - TestDictionary = new Dictionary - { - { TestEnum.A, "value1" }, - { TestEnum.B, "value2" }, - }, - }; + Assert.Equal( + $"/foo?TestDictionary.{(int)TestEnum.A}=value1{TestEnumUrlParameterFormatter.StringParameterSuffix}&TestDictionary.{(int)TestEnum.B}=value2{TestEnumUrlParameterFormatter.StringParameterSuffix}", + uri.PathAndQuery + ); + } +} - var output = factory(new object[] { complexQuery }); - var uri = new Uri(new Uri("http://api"), output.RequestUri); +static class RequestBuilderTestExtensions +{ + public static Func BuildRequestFactoryForMethod( + this IRequestBuilder builder, + string methodName, + string baseAddress = "http://api/" + ) + { + var factory = builder.BuildRestResultFuncForMethod(methodName); + var testHttpMessageHandler = new TestHttpMessageHandler(); - Assert.Equal( - $"/foo?TestDictionary.{(int)TestEnum.A}=value1{TestEnumUrlParameterFormatter.StringParameterSuffix}&TestDictionary.{(int)TestEnum.B}=value2{TestEnumUrlParameterFormatter.StringParameterSuffix}", - uri.PathAndQuery + return paramList => + { + var task = (Task)factory( + new HttpClient(testHttpMessageHandler) { BaseAddress = new Uri(baseAddress) }, + paramList ); - } + task.Wait(); + return testHttpMessageHandler.RequestMessage; + }; } - static class RequestBuilderTestExtensions + public static Func RunRequest( + this IRequestBuilder builder, + string methodName, + string returnContent = null, + string baseAddress = "http://api/" + ) { - public static Func BuildRequestFactoryForMethod( - this IRequestBuilder builder, - string methodName, - string baseAddress = "http://api/" - ) + var factory = builder.BuildRestResultFuncForMethod(methodName); + var testHttpMessageHandler = new TestHttpMessageHandler(); + if (returnContent != null) { - var factory = builder.BuildRestResultFuncForMethod(methodName); - var testHttpMessageHandler = new TestHttpMessageHandler(); - - return paramList => - { - var task = (Task)factory( - new HttpClient(testHttpMessageHandler) { BaseAddress = new Uri(baseAddress) }, - paramList - ); - task.Wait(); - return testHttpMessageHandler.RequestMessage; - }; + testHttpMessageHandler.Content = new StringContent(returnContent); } - public static Func RunRequest( - this IRequestBuilder builder, - string methodName, - string returnContent = null, - string baseAddress = "http://api/" - ) + return paramList => { - var factory = builder.BuildRestResultFuncForMethod(methodName); - var testHttpMessageHandler = new TestHttpMessageHandler(); - if (returnContent != null) + var task = (Task)factory( + new HttpClient(testHttpMessageHandler) { BaseAddress = new Uri(baseAddress) }, + paramList + ); + try { - testHttpMessageHandler.Content = new StringContent(returnContent); + task.Wait(); } + catch (AggregateException e) when (e.InnerException is TaskCanceledException) { } - return paramList => - { - var task = (Task)factory( - new HttpClient(testHttpMessageHandler) { BaseAddress = new Uri(baseAddress) }, - paramList - ); - try - { - task.Wait(); - } - catch (AggregateException e) when (e.InnerException is TaskCanceledException) { } - - return testHttpMessageHandler; - }; - } + return testHttpMessageHandler; + }; } } diff --git a/Refit.Tests/ResponseTests.cs b/Refit.Tests/ResponseTests.cs index 687cf6c0d..0d57e8761 100644 --- a/Refit.Tests/ResponseTests.cs +++ b/Refit.Tests/ResponseTests.cs @@ -16,502 +16,501 @@ using JsonSerializer = Newtonsoft.Json.JsonSerializer; using System.Text.Json.Serialization; -namespace Refit.Tests +namespace Refit.Tests; + +public class TestAliasObject +{ + [AliasAs("FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS")] + public string ShortNameForAlias { get; set; } + + [JsonProperty(PropertyName = "FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY")] + [JsonPropertyName("FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY")] + public string ShortNameForJsonProperty { get; set; } +} + +public class ResponseTests { - public class TestAliasObject + readonly MockHttpMessageHandler mockHandler; + readonly IMyAliasService fixture; + + public ResponseTests() { - [AliasAs("FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS")] - public string ShortNameForAlias { get; set; } + mockHandler = new MockHttpMessageHandler(); - [JsonProperty(PropertyName = "FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY")] - [JsonPropertyName("FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY")] - public string ShortNameForJsonProperty { get; set; } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHandler }; + + fixture = RestService.For("http://api", settings); } - public class ResponseTests + public interface IMyAliasService { - readonly MockHttpMessageHandler mockHandler; - readonly IMyAliasService fixture; + [Get("/aliasTest")] + Task GetTestObject(); - public ResponseTests() - { - mockHandler = new MockHttpMessageHandler(); + [Get("/GetApiResponseTestObject")] + Task> GetApiResponseTestObject(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHandler }; + [Get("/GetIApiResponse")] + Task GetIApiResponse(); + } - fixture = RestService.For("http://api", settings); - } + [Fact] + public async Task JsonPropertyCanBeUsedToAliasFieldNamesInResponses() + { + mockHandler + .Expect(HttpMethod.Get, "http://api/aliasTest") + .Respond( + "application/json", + "{\"FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS\": \"Hello\", \"FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY\": \"World\"}" + ); - public interface IMyAliasService - { - [Get("/aliasTest")] - Task GetTestObject(); + var result = await fixture.GetTestObject(); - [Get("/GetApiResponseTestObject")] - Task> GetApiResponseTestObject(); + Assert.Equal("World", result.ShortNameForJsonProperty); + } + + /// + /// Even though it may seem like AliasAs and JsonProperty are used interchangeably in some places, + /// when serializing responses, AliasAs will not work -- only JsonProperty will. + /// + [Fact] + public async Task AliasAsCannotBeUsedToAliasFieldNamesInResponses() + { + mockHandler + .Expect(HttpMethod.Get, "http://api/aliasTest") + .Respond( + "application/json", + "{\"FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS\": \"Hello\", \"FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY\": \"World\"}" + ); - [Get("/GetIApiResponse")] - Task GetIApiResponse(); - } + var result = await fixture.GetTestObject(); - [Fact] - public async Task JsonPropertyCanBeUsedToAliasFieldNamesInResponses() - { - mockHandler - .Expect(HttpMethod.Get, "http://api/aliasTest") - .Respond( - "application/json", - "{\"FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS\": \"Hello\", \"FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY\": \"World\"}" - ); - - var result = await fixture.GetTestObject(); - - Assert.Equal("World", result.ShortNameForJsonProperty); - } - - /// - /// Even though it may seem like AliasAs and JsonProperty are used interchangeably in some places, - /// when serializing responses, AliasAs will not work -- only JsonProperty will. - /// - [Fact] - public async Task AliasAsCannotBeUsedToAliasFieldNamesInResponses() - { - mockHandler - .Expect(HttpMethod.Get, "http://api/aliasTest") - .Respond( - "application/json", - "{\"FIELD_WE_SHOULD_SHORTEN_WITH_ALIAS_AS\": \"Hello\", \"FIELD_WE_SHOULD_SHORTEN_WITH_JSON_PROPERTY\": \"World\"}" - ); - - var result = await fixture.GetTestObject(); - - Assert.Null(result.ShortNameForAlias); - } - - /// - /// Test to verify if a ValidationException is thrown for a Bad Request in terms of RFC 7807 - /// - [Fact] - public async Task ThrowsValidationException() + Assert.Null(result.ShortNameForAlias); + } + + /// + /// Test to verify if a ValidationException is thrown for a Bad Request in terms of RFC 7807 + /// + [Fact] + public async Task ThrowsValidationException() + { + var expectedContent = new ProblemDetails { - var expectedContent = new ProblemDetails + Detail = "detail", + Errors = { - Detail = "detail", - Errors = - { - { "Field1", new string[] { "Problem1" } }, - { "Field2", new string[] { "Problem2" } } - }, - Instance = "instance", - Status = 1, - Title = "title", - Type = "type" - }; - var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) - { - Content = new StringContent(JsonConvert.SerializeObject(expectedContent)) - }; - expectedResponse.Content.Headers.ContentType = - new System.Net.Http.Headers.MediaTypeHeaderValue("application/problem+json"); - mockHandler - .Expect(HttpMethod.Get, "http://api/aliasTest") - .Respond(req => expectedResponse); - - var actualException = await Assert.ThrowsAsync( - () => fixture.GetTestObject() - ); - Assert.NotNull(actualException.Content); - Assert.Equal("detail", actualException.Content.Detail); - Assert.Equal("Problem1", actualException.Content.Errors["Field1"][0]); - Assert.Equal("Problem2", actualException.Content.Errors["Field2"][0]); - Assert.Equal("instance", actualException.Content.Instance); - Assert.Equal(1, actualException.Content.Status); - Assert.Equal("title", actualException.Content.Title); - Assert.Equal("type", actualException.Content.Type); - } - - /// - /// Test to verify if EnsureSuccessStatusCodeAsync throws a ValidationApiException for a Bad Request in terms of RFC 7807 - /// - [Fact] - public async Task When_BadRequest_EnsureSuccessStatusCodeAsync_ThrowsValidationException() + { "Field1", new string[] { "Problem1" } }, + { "Field2", new string[] { "Problem2" } } + }, + Instance = "instance", + Status = 1, + Title = "title", + Type = "type" + }; + var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) { - var expectedContent = new ProblemDetails - { - Detail = "detail", - Errors = - { - { "Field1", new string[] { "Problem1" } }, - { "Field2", new string[] { "Problem2" } } - }, - Instance = "instance", - Status = 1, - Title = "title", - Type = "type" - }; - - var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) - { - Content = new StringContent(JsonConvert.SerializeObject(expectedContent)) - }; - - expectedResponse.Content.Headers.ContentType = - new System.Net.Http.Headers.MediaTypeHeaderValue("application/problem+json"); - mockHandler - .Expect(HttpMethod.Get, "http://api/GetApiResponseTestObject") - .Respond(req => expectedResponse); - - using var response = await fixture.GetApiResponseTestObject(); - var actualException = await Assert.ThrowsAsync( - () => response.EnsureSuccessStatusCodeAsync() - ); + Content = new StringContent(JsonConvert.SerializeObject(expectedContent)) + }; + expectedResponse.Content.Headers.ContentType = + new System.Net.Http.Headers.MediaTypeHeaderValue("application/problem+json"); + mockHandler + .Expect(HttpMethod.Get, "http://api/aliasTest") + .Respond(req => expectedResponse); + + var actualException = await Assert.ThrowsAsync( + () => fixture.GetTestObject() + ); + Assert.NotNull(actualException.Content); + Assert.Equal("detail", actualException.Content.Detail); + Assert.Equal("Problem1", actualException.Content.Errors["Field1"][0]); + Assert.Equal("Problem2", actualException.Content.Errors["Field2"][0]); + Assert.Equal("instance", actualException.Content.Instance); + Assert.Equal(1, actualException.Content.Status); + Assert.Equal("title", actualException.Content.Title); + Assert.Equal("type", actualException.Content.Type); + } - Assert.NotNull(actualException.Content); - Assert.Equal("detail", actualException.Content.Detail); - Assert.Equal("Problem1", actualException.Content.Errors["Field1"][0]); - Assert.Equal("Problem2", actualException.Content.Errors["Field2"][0]); - Assert.Equal("instance", actualException.Content.Instance); - Assert.Equal(1, actualException.Content.Status); - Assert.Equal("title", actualException.Content.Title); - Assert.Equal("type", actualException.Content.Type); - } - - [Fact] - public async Task WhenProblemDetailsResponseContainsExtensions_ShouldHydrateExtensions() + /// + /// Test to verify if EnsureSuccessStatusCodeAsync throws a ValidationApiException for a Bad Request in terms of RFC 7807 + /// + [Fact] + public async Task When_BadRequest_EnsureSuccessStatusCodeAsync_ThrowsValidationException() + { + var expectedContent = new ProblemDetails { - var expectedContent = new + Detail = "detail", + Errors = { - Detail = "detail", - Instance = "instance", - Status = 1, - Title = "title", - Type = "type", - Foo = "bar", - Baz = 123d, - }; - - var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) - { - Content = new StringContent(JsonConvert.SerializeObject(expectedContent)) - }; - - expectedResponse.Content.Headers.ContentType = - new System.Net.Http.Headers.MediaTypeHeaderValue("application/problem+json"); - mockHandler - .Expect(HttpMethod.Get, "http://api/aliasTest") - .Respond(req => expectedResponse); - - mockHandler - .Expect(HttpMethod.Get, "http://api/soloyolo") - .Respond(req => expectedResponse); + { "Field1", new string[] { "Problem1" } }, + { "Field2", new string[] { "Problem2" } } + }, + Instance = "instance", + Status = 1, + Title = "title", + Type = "type" + }; + + var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) + { + Content = new StringContent(JsonConvert.SerializeObject(expectedContent)) + }; + + expectedResponse.Content.Headers.ContentType = + new System.Net.Http.Headers.MediaTypeHeaderValue("application/problem+json"); + mockHandler + .Expect(HttpMethod.Get, "http://api/GetApiResponseTestObject") + .Respond(req => expectedResponse); + + using var response = await fixture.GetApiResponseTestObject(); + var actualException = await Assert.ThrowsAsync( + () => response.EnsureSuccessStatusCodeAsync() + ); + + Assert.NotNull(actualException.Content); + Assert.Equal("detail", actualException.Content.Detail); + Assert.Equal("Problem1", actualException.Content.Errors["Field1"][0]); + Assert.Equal("Problem2", actualException.Content.Errors["Field2"][0]); + Assert.Equal("instance", actualException.Content.Instance); + Assert.Equal(1, actualException.Content.Status); + Assert.Equal("title", actualException.Content.Title); + Assert.Equal("type", actualException.Content.Type); + } - var actualException = await Assert.ThrowsAsync( - () => fixture.GetTestObject() - ); - Assert.NotNull(actualException.Content); - Assert.Equal("detail", actualException.Content.Detail); - Assert.Equal("instance", actualException.Content.Instance); - Assert.Equal(1, actualException.Content.Status); - Assert.Equal("title", actualException.Content.Title); - Assert.Equal("type", actualException.Content.Type); - - Assert.Collection( - actualException.Content.Extensions, - kvp => - Assert.Equal( - new KeyValuePair( - nameof(expectedContent.Foo), - expectedContent.Foo - ), - kvp + [Fact] + public async Task WhenProblemDetailsResponseContainsExtensions_ShouldHydrateExtensions() + { + var expectedContent = new + { + Detail = "detail", + Instance = "instance", + Status = 1, + Title = "title", + Type = "type", + Foo = "bar", + Baz = 123d, + }; + + var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) + { + Content = new StringContent(JsonConvert.SerializeObject(expectedContent)) + }; + + expectedResponse.Content.Headers.ContentType = + new System.Net.Http.Headers.MediaTypeHeaderValue("application/problem+json"); + mockHandler + .Expect(HttpMethod.Get, "http://api/aliasTest") + .Respond(req => expectedResponse); + + mockHandler + .Expect(HttpMethod.Get, "http://api/soloyolo") + .Respond(req => expectedResponse); + + var actualException = await Assert.ThrowsAsync( + () => fixture.GetTestObject() + ); + Assert.NotNull(actualException.Content); + Assert.Equal("detail", actualException.Content.Detail); + Assert.Equal("instance", actualException.Content.Instance); + Assert.Equal(1, actualException.Content.Status); + Assert.Equal("title", actualException.Content.Title); + Assert.Equal("type", actualException.Content.Type); + + Assert.Collection( + actualException.Content.Extensions, + kvp => + Assert.Equal( + new KeyValuePair( + nameof(expectedContent.Foo), + expectedContent.Foo ), - kvp => - Assert.Equal( - new KeyValuePair( - nameof(expectedContent.Baz), - expectedContent.Baz - ), - kvp - ) - ); - } + kvp + ), + kvp => + Assert.Equal( + new KeyValuePair( + nameof(expectedContent.Baz), + expectedContent.Baz + ), + kvp + ) + ); + } - [Fact] - public async Task WithNonSeekableStream_UsingSystemTextJsonContentSerializer() + [Fact] + public async Task WithNonSeekableStream_UsingSystemTextJsonContentSerializer() + { + var model = new TestAliasObject { - var model = new TestAliasObject - { - ShortNameForAlias = nameof( - WithNonSeekableStream_UsingSystemTextJsonContentSerializer - ), - ShortNameForJsonProperty = nameof(TestAliasObject) - }; + ShortNameForAlias = nameof( + WithNonSeekableStream_UsingSystemTextJsonContentSerializer + ), + ShortNameForJsonProperty = nameof(TestAliasObject) + }; - var localHandler = new MockHttpMessageHandler(); + var localHandler = new MockHttpMessageHandler(); - var settings = new RefitSettings(new SystemTextJsonContentSerializer()) - { - HttpMessageHandlerFactory = () => localHandler - }; + var settings = new RefitSettings(new SystemTextJsonContentSerializer()) + { + HttpMessageHandlerFactory = () => localHandler + }; - using var utf8BufferWriter = new PooledBufferWriter(); + using var utf8BufferWriter = new PooledBufferWriter(); - var utf8JsonWriter = new Utf8JsonWriter(utf8BufferWriter); + var utf8JsonWriter = new Utf8JsonWriter(utf8BufferWriter); - System.Text.Json.JsonSerializer.Serialize(utf8JsonWriter, model); + System.Text.Json.JsonSerializer.Serialize(utf8JsonWriter, model); - using var sourceStream = utf8BufferWriter.DetachStream(); + using var sourceStream = utf8BufferWriter.DetachStream(); - using var contentStream = new ThrowOnGetLengthMemoryStream { CanGetLength = true }; + using var contentStream = new ThrowOnGetLengthMemoryStream { CanGetLength = true }; - sourceStream.CopyTo(contentStream); + sourceStream.CopyTo(contentStream); - contentStream.Position = 0; + contentStream.Position = 0; - contentStream.CanGetLength = false; + contentStream.CanGetLength = false; - var httpContent = new StreamContent(contentStream) + var httpContent = new StreamContent(contentStream) + { + Headers = { - Headers = + ContentType = new MediaTypeHeaderValue("application/json") { - ContentType = new MediaTypeHeaderValue("application/json") - { - CharSet = Encoding.UTF8.WebName - } + CharSet = Encoding.UTF8.WebName } - }; + } + }; - var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) - { - Content = httpContent - }; + var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = httpContent + }; - expectedResponse.Content.Headers.ContentType = new MediaTypeHeaderValue( - "application/json" - ); - expectedResponse.StatusCode = HttpStatusCode.OK; + expectedResponse.Content.Headers.ContentType = new MediaTypeHeaderValue( + "application/json" + ); + expectedResponse.StatusCode = HttpStatusCode.OK; - localHandler - .Expect(HttpMethod.Get, "http://api/aliasTest") - .Respond(req => expectedResponse); + localHandler + .Expect(HttpMethod.Get, "http://api/aliasTest") + .Respond(req => expectedResponse); - var localFixture = RestService.For("http://api", settings); + var localFixture = RestService.For("http://api", settings); - var result = await localFixture.GetTestObject(); + var result = await localFixture.GetTestObject(); - Assert.NotNull(result); - Assert.Equal( - nameof(WithNonSeekableStream_UsingSystemTextJsonContentSerializer), - result.ShortNameForAlias - ); - Assert.Equal(nameof(TestAliasObject), result.ShortNameForJsonProperty); - } + Assert.NotNull(result); + Assert.Equal( + nameof(WithNonSeekableStream_UsingSystemTextJsonContentSerializer), + result.ShortNameForAlias + ); + Assert.Equal(nameof(TestAliasObject), result.ShortNameForJsonProperty); + } - [Fact] - public async Task BadRequestWithEmptyContent_ShouldReturnApiException() + [Fact] + public async Task BadRequestWithEmptyContent_ShouldReturnApiException() + { + var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) { - var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) - { - Content = new StringContent("Hello world") - }; - expectedResponse.Content.Headers.Clear(); + Content = new StringContent("Hello world") + }; + expectedResponse.Content.Headers.Clear(); - mockHandler - .Expect(HttpMethod.Get, "http://api/aliasTest") - .Respond(req => expectedResponse); + mockHandler + .Expect(HttpMethod.Get, "http://api/aliasTest") + .Respond(req => expectedResponse); - var actualException = await Assert.ThrowsAsync( - () => fixture.GetTestObject() - ); + var actualException = await Assert.ThrowsAsync( + () => fixture.GetTestObject() + ); - Assert.NotNull(actualException.Content); - Assert.Equal("Hello world", actualException.Content); - } + Assert.NotNull(actualException.Content); + Assert.Equal("Hello world", actualException.Content); + } - [Fact] - public async Task BadRequestWithEmptyContent_ShouldReturnApiResponse() + [Fact] + public async Task BadRequestWithEmptyContent_ShouldReturnApiResponse() + { + var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) { - var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) - { - Content = new StringContent("Hello world") - }; - expectedResponse.Content.Headers.Clear(); + Content = new StringContent("Hello world") + }; + expectedResponse.Content.Headers.Clear(); - mockHandler - .Expect(HttpMethod.Get, $"http://api/{nameof(fixture.GetApiResponseTestObject)}") - .Respond(req => expectedResponse); + mockHandler + .Expect(HttpMethod.Get, $"http://api/{nameof(fixture.GetApiResponseTestObject)}") + .Respond(req => expectedResponse); - var apiResponse = await fixture.GetApiResponseTestObject(); + var apiResponse = await fixture.GetApiResponseTestObject(); - Assert.NotNull(apiResponse); - Assert.NotNull(apiResponse.Error); - Assert.NotNull(apiResponse.Error.Content); - Assert.Equal("Hello world", apiResponse.Error.Content); - } + Assert.NotNull(apiResponse); + Assert.NotNull(apiResponse.Error); + Assert.NotNull(apiResponse.Error.Content); + Assert.Equal("Hello world", apiResponse.Error.Content); + } - [Fact] - public async Task BadRequestWithStringContent_ShouldReturnIApiResponse() + [Fact] + public async Task BadRequestWithStringContent_ShouldReturnIApiResponse() + { + var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) { - var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) - { - Content = new StringContent("Hello world") - }; - expectedResponse.Content.Headers.Clear(); + Content = new StringContent("Hello world") + }; + expectedResponse.Content.Headers.Clear(); - mockHandler - .Expect(HttpMethod.Get, $"http://api/{nameof(fixture.GetIApiResponse)}") - .Respond(req => expectedResponse); + mockHandler + .Expect(HttpMethod.Get, $"http://api/{nameof(fixture.GetIApiResponse)}") + .Respond(req => expectedResponse); - var apiResponse = await fixture.GetIApiResponse(); + var apiResponse = await fixture.GetIApiResponse(); - Assert.NotNull(apiResponse); - Assert.NotNull(apiResponse.Error); - Assert.NotNull(apiResponse.Error.Content); - Assert.Equal("Hello world", apiResponse.Error.Content); - } + Assert.NotNull(apiResponse); + Assert.NotNull(apiResponse.Error); + Assert.NotNull(apiResponse.Error.Content); + Assert.Equal("Hello world", apiResponse.Error.Content); + } - [Fact] - public async Task ValidationApiException_HydratesBaseContent() + [Fact] + public async Task ValidationApiException_HydratesBaseContent() + { + var expectedProblemDetails = new ProblemDetails { - var expectedProblemDetails = new ProblemDetails - { - Detail = "detail", - Instance = "instance", - Status = 1, - Title = "title", - Type = "type" - }; - var expectedContent = JsonConvert.SerializeObject(expectedProblemDetails); - var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) - { - Content = new StringContent(expectedContent) - }; - expectedResponse.Content.Headers.ContentType = new MediaTypeHeaderValue( - "application/problem+json" - ); - mockHandler - .Expect(HttpMethod.Get, "http://api/aliasTest") - .Respond(req => expectedResponse); - - var actualException = await Assert.ThrowsAsync( - () => fixture.GetTestObject() - ); - var actualBaseException = actualException as ApiException; - Assert.Equal(expectedContent, actualBaseException.Content); - } + Detail = "detail", + Instance = "instance", + Status = 1, + Title = "title", + Type = "type" + }; + var expectedContent = JsonConvert.SerializeObject(expectedProblemDetails); + var expectedResponse = new HttpResponseMessage(HttpStatusCode.BadRequest) + { + Content = new StringContent(expectedContent) + }; + expectedResponse.Content.Headers.ContentType = new MediaTypeHeaderValue( + "application/problem+json" + ); + mockHandler + .Expect(HttpMethod.Get, "http://api/aliasTest") + .Respond(req => expectedResponse); + + var actualException = await Assert.ThrowsAsync( + () => fixture.GetTestObject() + ); + var actualBaseException = actualException as ApiException; + Assert.Equal(expectedContent, actualBaseException.Content); + } - [Fact] - public async Task WithHtmlResponse_ShouldReturnApiException() + [Fact] + public async Task WithHtmlResponse_ShouldReturnApiException() + { + const string htmlResponse = "Hello world"; + var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) { - const string htmlResponse = "Hello world"; - var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(htmlResponse) - }; - expectedResponse.Content.Headers.Clear(); + Content = new StringContent(htmlResponse) + }; + expectedResponse.Content.Headers.Clear(); - mockHandler - .Expect(HttpMethod.Get, "http://api/aliasTest") - .Respond(req => expectedResponse); + mockHandler + .Expect(HttpMethod.Get, "http://api/aliasTest") + .Respond(req => expectedResponse); - var actualException = await Assert.ThrowsAsync( - () => fixture.GetTestObject() - ); + var actualException = await Assert.ThrowsAsync( + () => fixture.GetTestObject() + ); - Assert.IsType(actualException.InnerException); - Assert.NotNull(actualException.Content); - Assert.Equal(htmlResponse, actualException.Content); - } + Assert.IsType(actualException.InnerException); + Assert.NotNull(actualException.Content); + Assert.Equal(htmlResponse, actualException.Content); + } - [Fact] - public async Task WithHtmlResponse_ShouldReturnApiResponse() + [Fact] + public async Task WithHtmlResponse_ShouldReturnApiResponse() + { + const string htmlResponse = "Hello world"; + var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) { - const string htmlResponse = "Hello world"; - var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(htmlResponse) - }; - expectedResponse.Content.Headers.Clear(); + Content = new StringContent(htmlResponse) + }; + expectedResponse.Content.Headers.Clear(); - mockHandler - .Expect(HttpMethod.Get, $"http://api/{nameof(fixture.GetApiResponseTestObject)}") - .Respond(req => expectedResponse); + mockHandler + .Expect(HttpMethod.Get, $"http://api/{nameof(fixture.GetApiResponseTestObject)}") + .Respond(req => expectedResponse); - var apiResponse = await fixture.GetApiResponseTestObject(); + var apiResponse = await fixture.GetApiResponseTestObject(); - Assert.NotNull(apiResponse.Error); - Assert.IsType(apiResponse.Error.InnerException); - Assert.NotNull(apiResponse.Error.Content); - Assert.Equal(htmlResponse, apiResponse.Error.Content); - } + Assert.NotNull(apiResponse.Error); + Assert.IsType(apiResponse.Error.InnerException); + Assert.NotNull(apiResponse.Error.Content); + Assert.Equal(htmlResponse, apiResponse.Error.Content); + } - [Fact] - public async Task WithNonJsonResponseUsingNewtonsoftJsonContentSerializer_ShouldReturnApiException() + [Fact] + public async Task WithNonJsonResponseUsingNewtonsoftJsonContentSerializer_ShouldReturnApiException() + { + var settings = new RefitSettings { - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHandler, - ContentSerializer = new NewtonsoftJsonContentSerializer() - }; + HttpMessageHandlerFactory = () => mockHandler, + ContentSerializer = new NewtonsoftJsonContentSerializer() + }; - var newtonSoftFixture = RestService.For("http://api", settings); + var newtonSoftFixture = RestService.For("http://api", settings); - const string nonJsonResponse = "bad response"; - var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(nonJsonResponse) - }; - expectedResponse.Content.Headers.Clear(); + const string nonJsonResponse = "bad response"; + var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(nonJsonResponse) + }; + expectedResponse.Content.Headers.Clear(); - mockHandler - .Expect(HttpMethod.Get, "http://api/aliasTest") - .Respond(req => expectedResponse); + mockHandler + .Expect(HttpMethod.Get, "http://api/aliasTest") + .Respond(req => expectedResponse); - var actualException = await Assert.ThrowsAsync( - () => newtonSoftFixture.GetTestObject() - ); + var actualException = await Assert.ThrowsAsync( + () => newtonSoftFixture.GetTestObject() + ); - Assert.IsType(actualException.InnerException); - Assert.NotNull(actualException.Content); - Assert.Equal(nonJsonResponse, actualException.Content); - } + Assert.IsType(actualException.InnerException); + Assert.NotNull(actualException.Content); + Assert.Equal(nonJsonResponse, actualException.Content); + } - [Fact] - public async Task WithNonJsonResponseUsingNewtonsoftJsonContentSerializer_ShouldReturnApiResponse() + [Fact] + public async Task WithNonJsonResponseUsingNewtonsoftJsonContentSerializer_ShouldReturnApiResponse() + { + var settings = new RefitSettings { - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHandler, - ContentSerializer = new NewtonsoftJsonContentSerializer() - }; + HttpMessageHandlerFactory = () => mockHandler, + ContentSerializer = new NewtonsoftJsonContentSerializer() + }; - var newtonSoftFixture = RestService.For("http://api", settings); + var newtonSoftFixture = RestService.For("http://api", settings); - const string nonJsonResponse = "bad response"; - var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent(nonJsonResponse) - }; - expectedResponse.Content.Headers.Clear(); + const string nonJsonResponse = "bad response"; + var expectedResponse = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(nonJsonResponse) + }; + expectedResponse.Content.Headers.Clear(); - mockHandler - .Expect(HttpMethod.Get, $"http://api/{nameof(fixture.GetApiResponseTestObject)}") - .Respond(req => expectedResponse); + mockHandler + .Expect(HttpMethod.Get, $"http://api/{nameof(fixture.GetApiResponseTestObject)}") + .Respond(req => expectedResponse); - var apiResponse = await newtonSoftFixture.GetApiResponseTestObject(); + var apiResponse = await newtonSoftFixture.GetApiResponseTestObject(); - Assert.NotNull(apiResponse.Error); - Assert.IsType(apiResponse.Error.InnerException); - Assert.NotNull(apiResponse.Error.Content); - Assert.Equal(nonJsonResponse, apiResponse.Error.Content); - } + Assert.NotNull(apiResponse.Error); + Assert.IsType(apiResponse.Error.InnerException); + Assert.NotNull(apiResponse.Error.Content); + Assert.Equal(nonJsonResponse, apiResponse.Error.Content); } +} - public sealed class ThrowOnGetLengthMemoryStream : MemoryStream - { - public bool CanGetLength { get; set; } +public sealed class ThrowOnGetLengthMemoryStream : MemoryStream +{ + public bool CanGetLength { get; set; } - public override long Length => - CanGetLength ? base.Length : throw new NotSupportedException(); - } + public override long Length => + CanGetLength ? base.Length : throw new NotSupportedException(); } diff --git a/Refit.Tests/RestService.cs b/Refit.Tests/RestService.cs index 5f4d76523..9696f251d 100644 --- a/Refit.Tests/RestService.cs +++ b/Refit.Tests/RestService.cs @@ -17,2255 +17,2254 @@ using Xunit; -namespace Refit.Tests -{ +namespace Refit.Tests; + #pragma warning disable IDE1006 // Naming Styles - public class RootObject - { - public string _id { get; set; } - public string _rev { get; set; } - public string name { get; set; } - } +public class RootObject +{ + public string _id { get; set; } + public string _rev { get; set; } + public string name { get; set; } +} #pragma warning restore IDE1006 // Naming Styles - public class BigObject - { - public byte[] BigData { get; set; } - } +public class BigObject +{ + public byte[] BigData { get; set; } +} - [Headers("User-Agent: Refit Integration Tests")] - public interface INpmJs - { - [Get("/congruence")] - Task GetCongruence(); - } +[Headers("User-Agent: Refit Integration Tests")] +public interface INpmJs +{ + [Get("/congruence")] + Task GetCongruence(); +} - public interface IRequestBin - { - [Post("/1h3a5jm1")] - Task Post(); +public interface IRequestBin +{ + [Post("/1h3a5jm1")] + Task Post(); - [Post("/foo")] - Task PostRawStringDefault([Body] string str); + [Post("/foo")] + Task PostRawStringDefault([Body] string str); - [Post("/foo")] - Task PostRawStringJson([Body(BodySerializationMethod.Serialized)] string str); + [Post("/foo")] + Task PostRawStringJson([Body(BodySerializationMethod.Serialized)] string str); - [Post("/foo")] - Task PostRawStringUrlEncoded([Body(BodySerializationMethod.UrlEncoded)] string str); + [Post("/foo")] + Task PostRawStringUrlEncoded([Body(BodySerializationMethod.UrlEncoded)] string str); - [Post("/1h3a5jm1")] - Task PostGeneric(T param); + [Post("/1h3a5jm1")] + Task PostGeneric(T param); - [Post("/foo")] - Task PostVoidReturnBodyBuffered([Body(buffered: true)] T param); + [Post("/foo")] + Task PostVoidReturnBodyBuffered([Body(buffered: true)] T param); - [Post("/foo")] - Task PostNonVoidReturnBodyBuffered([Body(buffered: true)] T param); + [Post("/foo")] + Task PostNonVoidReturnBodyBuffered([Body(buffered: true)] T param); - [Post("/big")] - Task PostBig(BigObject big); + [Post("/big")] + Task PostBig(BigObject big); - [Get("/foo/{arguments}")] - Task SomeApiThatUsesVariableNameFromCodeGen(string arguments); - } + [Get("/foo/{arguments}")] + Task SomeApiThatUsesVariableNameFromCodeGen(string arguments); +} - public interface IApiBindPathToObject - { - [Get("/foos/{request.someProperty}/bar/{request.someProperty2}")] - Task GetFooBars(PathBoundObject request); +public interface IApiBindPathToObject +{ + [Get("/foos/{request.someProperty}/bar/{request.someProperty2}")] + Task GetFooBars(PathBoundObject request); - [Get("/foos/{Requestparams.SomeProperty}/bar/{requestParams.SoMeProPerty2}")] - Task GetFooBarsWithDifferentCasing(PathBoundObject requestParams); + [Get("/foos/{Requestparams.SomeProperty}/bar/{requestParams.SoMeProPerty2}")] + Task GetFooBarsWithDifferentCasing(PathBoundObject requestParams); - [Get("/foos/{id}/{request.someProperty}/bar/{request.someProperty2}")] - Task GetBarsByFoo(string id, PathBoundObject request); + [Get("/foos/{id}/{request.someProperty}/bar/{request.someProperty2}")] + Task GetBarsByFoo(string id, PathBoundObject request); - [Get("/foos/{someProperty}/bar/{request.someProperty2}")] - Task GetFooBars(PathBoundObject request, string someProperty); + [Get("/foos/{someProperty}/bar/{request.someProperty2}")] + Task GetFooBars(PathBoundObject request, string someProperty); - [Get("/foos/{request.someProperty}/bar")] - Task GetBarsByFoo(PathBoundObject request); + [Get("/foos/{request.someProperty}/bar")] + Task GetBarsByFoo(PathBoundObject request); - [Get("/foo")] - Task GetBarsWithCustomQueryFormat(PathBoundObjectWithQueryFormat request); + [Get("/foo")] + Task GetBarsWithCustomQueryFormat(PathBoundObjectWithQueryFormat request); - [Get("/foos/{request.someProperty}/bar/{request.someProperty3}")] - Task GetFooBarsDerived(PathBoundDerivedObject request); + [Get("/foos/{request.someProperty}/bar/{request.someProperty3}")] + Task GetFooBarsDerived(PathBoundDerivedObject request); - [Get("/foos/{request.values}")] - Task GetFoos(PathBoundList request); + [Get("/foos/{request.values}")] + Task GetFoos(PathBoundList request); - [Get("/foos2/{values}")] - Task GetFoos2(List values); + [Get("/foos2/{values}")] + Task GetFoos2(List values); - [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] - Task PostFooBar(PathBoundObject request, [Body] object someObject); + [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] + Task PostFooBar(PathBoundObject request, [Body] object someObject); - [Get("/foos/{request.someProperty}/bar/{request.someProperty2}")] - Task GetFooBars(PathBoundObjectWithQuery request); + [Get("/foos/{request.someProperty}/bar/{request.someProperty2}")] + Task GetFooBars(PathBoundObjectWithQuery request); - [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] - Task PostFooBar( - PathBoundObject request, - [Query] ModelObject someQueryParams - ); + [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] + Task PostFooBar( + PathBoundObject request, + [Query] ModelObject someQueryParams + ); - [Multipart] - [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] - Task PostFooBarStreamPart( - PathBoundObject request, - [Query] ModelObject someQueryParams, - StreamPart stream - ); + [Multipart] + [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] + Task PostFooBarStreamPart( + PathBoundObject request, + [Query] ModelObject someQueryParams, + StreamPart stream + ); - [Multipart] - [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] - Task PostFooBarStreamPart(PathBoundObject request, StreamPart stream); + [Multipart] + [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] + Task PostFooBarStreamPart(PathBoundObject request, StreamPart stream); - [Multipart] - [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] - Task PostFooBarStreamPart( - PathBoundObjectWithQuery request, - StreamPart stream - ); - } + [Multipart] + [Post("/foos/{request.someProperty}/bar/{request.someProperty2}")] + Task PostFooBarStreamPart( + PathBoundObjectWithQuery request, + StreamPart stream + ); +} - public class PathBoundList - { - public List Values { get; set; } - } +public class PathBoundList +{ + public List Values { get; set; } +} - public class PathBoundDerivedObject : PathBoundObject - { - public string SomeProperty3 { get; set; } - } +public class PathBoundDerivedObject : PathBoundObject +{ + public string SomeProperty3 { get; set; } +} - public class PathBoundObject - { - public int SomeProperty { get; set; } +public class PathBoundObject +{ + public int SomeProperty { get; set; } - public string SomeProperty2 { get; set; } - } + public string SomeProperty2 { get; set; } +} - public class PathBoundObjectWithQuery - { - public int SomeProperty { get; set; } +public class PathBoundObjectWithQuery +{ + public int SomeProperty { get; set; } - public string SomeProperty2 { get; set; } + public string SomeProperty2 { get; set; } - [Query] - public string SomeQuery { get; set; } - } + [Query] + public string SomeQuery { get; set; } +} - public class PathBoundObjectWithQueryFormat - { - [Query(Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'")] - public DateTime SomeQueryWithFormat { get; set; } - } +public class PathBoundObjectWithQueryFormat +{ + [Query(Format = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'")] + public DateTime SomeQueryWithFormat { get; set; } +} - public interface INoRefitHereBuddy - { - Task Post(); - } +public interface INoRefitHereBuddy +{ + Task Post(); +} - public interface IAmHalfRefit - { - [Post("/anything")] - Task Post(); +public interface IAmHalfRefit +{ + [Post("/anything")] + Task Post(); - Task Get(); - } + Task Get(); +} - public interface IRefitInterfaceWithStaticMethod - { - [Get("")] - Task Get(); +public interface IRefitInterfaceWithStaticMethod +{ + [Get("")] + Task Get(); #if NETCOREAPP3_1_OR_GREATER - public static IRefitInterfaceWithStaticMethod Create() - { - // This is a C# 8 factory method + public static IRefitInterfaceWithStaticMethod Create() + { + // This is a C# 8 factory method - return RestService.For("http://foo/"); - } -#endif + return RestService.For("http://foo/"); } +#endif +} - public class ErrorResponse - { - public string[] Errors { get; set; } - } +public class ErrorResponse +{ + public string[] Errors { get; set; } +} - public interface IHttpBinApi - where TResponse : class - where THeader : struct - { - [Get("")] - Task Get(TParam param, [Header("X-Refit")] THeader header); +public interface IHttpBinApi + where TResponse : class + where THeader : struct +{ + [Get("")] + Task Get(TParam param, [Header("X-Refit")] THeader header); - [Get("/get?hardcoded=true")] - Task GetQuery([Query("_")] TParam param); + [Get("/get?hardcoded=true")] + Task GetQuery([Query("_")] TParam param); - [Post("/post?hardcoded=true")] - Task PostQuery([Query("_")] TParam param); + [Post("/post?hardcoded=true")] + Task PostQuery([Query("_")] TParam param); - [Get("")] - Task GetQueryWithIncludeParameterName([Query(".", "search")] TParam param); + [Get("")] + Task GetQueryWithIncludeParameterName([Query(".", "search")] TParam param); - [Get("/get?hardcoded=true")] - Task GetQuery1([Query("_")] TParam param); - } + [Get("/get?hardcoded=true")] + Task GetQuery1([Query("_")] TParam param); +} - public interface IBrokenWebApi - { - [Post("/what-spec")] - Task PostAValue([Body] string derp); - } +public interface IBrokenWebApi +{ + [Post("/what-spec")] + Task PostAValue([Body] string derp); +} - public interface IHttpContentApi - { - [Post("/blah")] - Task PostFileUpload([Body] HttpContent content); +public interface IHttpContentApi +{ + [Post("/blah")] + Task PostFileUpload([Body] HttpContent content); - [Post("/blah")] - Task> PostFileUploadWithMetadata([Body] HttpContent content); - } + [Post("/blah")] + Task> PostFileUploadWithMetadata([Body] HttpContent content); +} - public interface IStreamApi - { - [Post("/{filename}")] - Task GetRemoteFile(string filename); +public interface IStreamApi +{ + [Post("/{filename}")] + Task GetRemoteFile(string filename); - [Post("/{filename}")] - Task> GetRemoteFileWithMetadata(string filename); - } + [Post("/{filename}")] + Task> GetRemoteFileWithMetadata(string filename); +} - public interface IApiWithDecimal - { - [Get("/withDecimal")] - Task GetWithDecimal(decimal value); - } +public interface IApiWithDecimal +{ + [Get("/withDecimal")] + Task GetWithDecimal(decimal value); +} - public interface IBodylessApi - { - [Post("/nobody")] - [Headers("Content-Type: application/x-www-form-urlencoded; charset=UTF-8")] - Task Post(); +public interface IBodylessApi +{ + [Post("/nobody")] + [Headers("Content-Type: application/x-www-form-urlencoded; charset=UTF-8")] + Task Post(); - [Get("/nobody")] - [Headers("Content-Type: application/x-www-form-urlencoded; charset=UTF-8")] - Task Get(); + [Get("/nobody")] + [Headers("Content-Type: application/x-www-form-urlencoded; charset=UTF-8")] + Task Get(); - [Head("/nobody")] - [Headers("Content-Type: application/x-www-form-urlencoded; charset=UTF-8")] - Task Head(); - } + [Head("/nobody")] + [Headers("Content-Type: application/x-www-form-urlencoded; charset=UTF-8")] + Task Head(); +} - public interface ITrimTrailingForwardSlashApi - { - HttpClient Client { get; } +public interface ITrimTrailingForwardSlashApi +{ + HttpClient Client { get; } - [Get("/someendpoint")] - Task Get(); - } + [Get("/someendpoint")] + Task Get(); +} - public interface IValidApi - { - [Get("/someendpoint")] - Task Get(); - } +public interface IValidApi +{ + [Get("/someendpoint")] + Task Get(); +} - public class HttpBinGet - { - public Dictionary Args { get; set; } - public Dictionary Headers { get; set; } - public string Origin { get; set; } - public string Url { get; set; } - } +public class HttpBinGet +{ + public Dictionary Args { get; set; } + public Dictionary Headers { get; set; } + public string Origin { get; set; } + public string Url { get; set; } +} - public class RestServiceIntegrationTests - { +public class RestServiceIntegrationTests +{ #if NETCOREAPP3_1_OR_GREATER - [Fact] - public void CanCreateInstanceUsingStaticMethod() - { - var instance = IRefitInterfaceWithStaticMethod.Create(); + [Fact] + public void CanCreateInstanceUsingStaticMethod() + { + var instance = IRefitInterfaceWithStaticMethod.Create(); - Assert.NotNull(instance); - } + Assert.NotNull(instance); + } #endif - [Fact] - public async Task CanAddContentHeadersToPostWithoutBody() - { - var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + [Fact] + public async Task CanAddContentHeadersToPostWithoutBody() + { + var mockHttp = new MockHttpMessageHandler(); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - mockHttp - .Expect(HttpMethod.Post, "http://foo/nobody") - // The content length header is set automatically by the HttpContent instance, - // so checking the header as a string doesn't work - .With(r => r.Content?.Headers.ContentLength == 0) - // But we added content type ourselves, so this should work - .WithHeaders("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") - .WithContent("") - .Respond("application/json", "Ok"); + mockHttp + .Expect(HttpMethod.Post, "http://foo/nobody") + // The content length header is set automatically by the HttpContent instance, + // so checking the header as a string doesn't work + .With(r => r.Content?.Headers.ContentLength == 0) + // But we added content type ourselves, so this should work + .WithHeaders("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8") + .WithContent("") + .Respond("application/json", "Ok"); - var fixture = RestService.For("http://foo", settings); + var fixture = RestService.For("http://foo", settings); - await fixture.Post(); + await fixture.Post(); - mockHttp.VerifyNoOutstandingExpectation(); - } + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task GetWithNoParametersTest() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/someendpoint") - .WithExactQueryString("") - .Respond("application/json", "Ok"); + [Fact] + public async Task GetWithNoParametersTest() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/someendpoint") + .WithExactQueryString("") + .Respond("application/json", "Ok"); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); - await fixture.Get(); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.Get(); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task BaseAddressFromHttpClientMatchesTest() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/someendpoint") - .WithExactQueryString("") - .Respond("application/json", "Ok"); + [Fact] + public async Task BaseAddressFromHttpClientMatchesTest() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/someendpoint") + .WithExactQueryString("") + .Respond("application/json", "Ok"); - var client = new HttpClient(mockHttp) { BaseAddress = new Uri("http://foo") }; + var client = new HttpClient(mockHttp) { BaseAddress = new Uri("http://foo") }; - var fixture = RestService.For(client); + var fixture = RestService.For(client); - await fixture.Get(); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.Get(); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task BaseAddressWithTrailingSlashFromHttpClientMatchesTest() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/someendpoint") - .WithExactQueryString("") - .Respond("application/json", "Ok"); + [Fact] + public async Task BaseAddressWithTrailingSlashFromHttpClientMatchesTest() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/someendpoint") + .WithExactQueryString("") + .Respond("application/json", "Ok"); - var client = new HttpClient(mockHttp) { BaseAddress = new Uri("http://foo/") }; + var client = new HttpClient(mockHttp) { BaseAddress = new Uri("http://foo/") }; - var fixture = RestService.For(client); + var fixture = RestService.For(client); - await fixture.Get(); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.Get(); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task BaseAddressWithTrailingSlashCalledBeforeFromHttpClientMatchesTest() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/someendpoint") - .WithExactQueryString("") - .Respond("application/json", "Ok"); + [Fact] + public async Task BaseAddressWithTrailingSlashCalledBeforeFromHttpClientMatchesTest() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/someendpoint") + .WithExactQueryString("") + .Respond("application/json", "Ok"); - var client = new HttpClient(mockHttp) { BaseAddress = new Uri("http://foo/") }; + var client = new HttpClient(mockHttp) { BaseAddress = new Uri("http://foo/") }; - await client.GetAsync("/firstRequest"); - ; + await client.GetAsync("/firstRequest"); + ; - var fixture = RestService.For(client); + var fixture = RestService.For(client); - await fixture.Get(); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.Get(); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task GetWithNoParametersTestTrailingSlashInBase() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/someendpoint") - .WithExactQueryString("") - .Respond("application/json", "Ok"); + [Fact] + public async Task GetWithNoParametersTestTrailingSlashInBase() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/someendpoint") + .WithExactQueryString("") + .Respond("application/json", "Ok"); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo/", settings); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo/", settings); - await fixture.Get(); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.Get(); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task GetWithPathBoundObject() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/foos/1/bar/barNone") - .WithExactQueryString("") - .Respond("application/json", "Ok"); + [Fact] + public async Task GetWithPathBoundObject() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/foos/1/bar/barNone") + .WithExactQueryString("") + .Respond("application/json", "Ok"); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); - await fixture.GetFooBars( - new PathBoundObject() { SomeProperty = 1, SomeProperty2 = "barNone" } - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.GetFooBars( + new PathBoundObject() { SomeProperty = 1, SomeProperty2 = "barNone" } + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task GetWithPathBoundObjectDifferentCasing() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/foos/1/bar/barNone") - .WithExactQueryString("") - .Respond("application/json", "Ok"); + [Fact] + public async Task GetWithPathBoundObjectDifferentCasing() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/foos/1/bar/barNone") + .WithExactQueryString("") + .Respond("application/json", "Ok"); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); - await fixture.GetFooBarsWithDifferentCasing( - new PathBoundObject() { SomeProperty = 1, SomeProperty2 = "barNone" } - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.GetFooBarsWithDifferentCasing( + new PathBoundObject() { SomeProperty = 1, SomeProperty2 = "barNone" } + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task GetWithPathBoundObjectAndParameter() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/foos/myId/22/bar/bart") - .WithExactQueryString("") - .Respond("application/json", "Ok"); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); - - await fixture.GetBarsByFoo( - "myId", - new PathBoundObject() { SomeProperty = 22, SomeProperty2 = "bart" } - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task GetWithPathBoundObjectAndParameter() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/foos/myId/22/bar/bart") + .WithExactQueryString("") + .Respond("application/json", "Ok"); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); + + await fixture.GetBarsByFoo( + "myId", + new PathBoundObject() { SomeProperty = 22, SomeProperty2 = "bart" } + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task GetWithPathBoundObjectAndParameterParameterPrecedence() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/foos/chooseMe/bar/barNone") - .WithExactQueryString( - new[] { new KeyValuePair("SomeProperty", "1") } - ) - .Respond("application/json", "Ok"); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); - - await fixture.GetFooBars( - new PathBoundObject() { SomeProperty = 1, SomeProperty2 = "barNone" }, - "chooseMe" - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task GetWithPathBoundObjectAndParameterParameterPrecedence() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/foos/chooseMe/bar/barNone") + .WithExactQueryString( + new[] { new KeyValuePair("SomeProperty", "1") } + ) + .Respond("application/json", "Ok"); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); + + await fixture.GetFooBars( + new PathBoundObject() { SomeProperty = 1, SomeProperty2 = "barNone" }, + "chooseMe" + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task GetWithPathBoundDerivedObject() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/foos/1/bar/test") - .WithExactQueryString( - new[] { new KeyValuePair("SomeProperty2", "barNone") } - ) - .Respond("application/json", "Ok"); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); - - await fixture.GetFooBarsDerived( - new PathBoundDerivedObject() - { - SomeProperty = 1, - SomeProperty2 = "barNone", - SomeProperty3 = "test" - } - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task GetWithPathBoundDerivedObject() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/foos/1/bar/test") + .WithExactQueryString( + new[] { new KeyValuePair("SomeProperty2", "barNone") } + ) + .Respond("application/json", "Ok"); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); + + await fixture.GetFooBarsDerived( + new PathBoundDerivedObject() + { + SomeProperty = 1, + SomeProperty2 = "barNone", + SomeProperty3 = "test" + } + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task GetWithPathBoundObjectAndQueryParameter() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/foos/22/bar") - .WithExactQueryString( - new[] { new KeyValuePair("SomeProperty2", "bart") } - ) - .Respond("application/json", "Ok"); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); - - await fixture.GetBarsByFoo( - new PathBoundObject() { SomeProperty = 22, SomeProperty2 = "bart" } - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task GetWithPathBoundObjectAndQueryParameter() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/foos/22/bar") + .WithExactQueryString( + new[] { new KeyValuePair("SomeProperty2", "bart") } + ) + .Respond("application/json", "Ok"); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); + + await fixture.GetBarsByFoo( + new PathBoundObject() { SomeProperty = 22, SomeProperty2 = "bart" } + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task PostFooBarPathBoundObject() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Post, "http://foo/foos/22/bar/bart") - .Respond("application/json", "Ok"); + [Fact] + public async Task PostFooBarPathBoundObject() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://foo/foos/22/bar/bart") + .Respond("application/json", "Ok"); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); - await fixture.PostFooBar( - new PathBoundObject() { SomeProperty = 22, SomeProperty2 = "bart" }, - new { } - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.PostFooBar( + new PathBoundObject() { SomeProperty = 22, SomeProperty2 = "bart" }, + new { } + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task PathBoundObjectsRespectFormatter() + [Fact] + public async Task PathBoundObjectsRespectFormatter() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/foos/22%2C23") + .Respond("application/json", "Ok"); + + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/foos/22%2C23") - .Respond("application/json", "Ok"); + HttpMessageHandlerFactory = () => mockHttp, + UrlParameterFormatter = new TestEnumerableUrlParameterFormatter() + }; + var fixture = RestService.For("http://foo", settings); - var settings = new RefitSettings + await fixture.GetFoos( + new PathBoundList() { - HttpMessageHandlerFactory = () => mockHttp, - UrlParameterFormatter = new TestEnumerableUrlParameterFormatter() - }; - var fixture = RestService.For("http://foo", settings); + Values = new List() { 22, 23 } + } + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - await fixture.GetFoos( - new PathBoundList() - { - Values = new List() { 22, 23 } - } - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task GetWithPathBoundObjectAndQuery() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/foos/1/bar/barNone") + .WithExactQueryString("SomeQuery=test") + .Respond("application/json", "Ok"); - [Fact] - public async Task GetWithPathBoundObjectAndQuery() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/foos/1/bar/barNone") - .WithExactQueryString("SomeQuery=test") - .Respond("application/json", "Ok"); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); + await fixture.GetFooBars( + new PathBoundObjectWithQuery() + { + SomeProperty = 1, + SomeProperty2 = "barNone", + SomeQuery = "test" + } + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - await fixture.GetFooBars( - new PathBoundObjectWithQuery() - { - SomeProperty = 1, - SomeProperty2 = "barNone", - SomeQuery = "test" - } - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task GetWithPathBoundObjectAndQueryWithFormat() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "http://foo/foo") + .WithExactQueryString("SomeQueryWithFormat=2020-03-05T13:55:00Z") + .Respond("application/json", "Ok"); - [Fact] - public async Task GetWithPathBoundObjectAndQueryWithFormat() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "http://foo/foo") - .WithExactQueryString("SomeQueryWithFormat=2020-03-05T13:55:00Z") - .Respond("application/json", "Ok"); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); + await fixture.GetBarsWithCustomQueryFormat( + new PathBoundObjectWithQueryFormat + { + SomeQueryWithFormat = new DateTime(2020, 03, 05, 13, 55, 00) + } + ); - await fixture.GetBarsWithCustomQueryFormat( - new PathBoundObjectWithQueryFormat - { - SomeQueryWithFormat = new DateTime(2020, 03, 05, 13, 55, 00) - } - ); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task GetWithPathBoundObjectAndQueryObject() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://foo/foos/1/bar/barNone") + .WithExactQueryString("Property1=test&Property2=test2") + .Respond("application/json", "Ok"); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); + + await fixture.PostFooBar( + new PathBoundObject() { SomeProperty = 1, SomeProperty2 = "barNone" }, + new ModelObject() { Property1 = "test", Property2 = "test2" } + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task GetWithPathBoundObjectAndQueryObject() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Post, "http://foo/foos/1/bar/barNone") - .WithExactQueryString("Property1=test&Property2=test2") - .Respond("application/json", "Ok"); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); - - await fixture.PostFooBar( - new PathBoundObject() { SomeProperty = 1, SomeProperty2 = "barNone" }, - new ModelObject() { Property1 = "test", Property2 = "test2" } - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task PostFooBarPathMultipart() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://foo/foos/22/bar/bar") + .WithExactQueryString("") + .Respond("application/json", "Ok"); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); + + using var stream = GetTestFileStream("Test Files/Test.pdf"); + await fixture.PostFooBarStreamPart( + new PathBoundObject() { SomeProperty = 22, SomeProperty2 = "bar" }, + new StreamPart(stream, "Test.pdf", "application/pdf") + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task PostFooBarPathMultipart() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Post, "http://foo/foos/22/bar/bar") - .WithExactQueryString("") - .Respond("application/json", "Ok"); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); - - using var stream = GetTestFileStream("Test Files/Test.pdf"); - await fixture.PostFooBarStreamPart( - new PathBoundObject() { SomeProperty = 22, SomeProperty2 = "bar" }, - new StreamPart(stream, "Test.pdf", "application/pdf") - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task PostFooBarPathQueryMultipart() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://foo/foos/22/bar/bar") + .WithExactQueryString("SomeQuery=test") + .Respond("application/json", "Ok"); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); + + using var stream = GetTestFileStream("Test Files/Test.pdf"); + await fixture.PostFooBarStreamPart( + new PathBoundObjectWithQuery() + { + SomeProperty = 22, + SomeProperty2 = "bar", + SomeQuery = "test" + }, + new StreamPart(stream, "Test.pdf", "application/pdf") + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task PostFooBarPathQueryMultipart() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Post, "http://foo/foos/22/bar/bar") - .WithExactQueryString("SomeQuery=test") - .Respond("application/json", "Ok"); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); - - using var stream = GetTestFileStream("Test Files/Test.pdf"); - await fixture.PostFooBarStreamPart( - new PathBoundObjectWithQuery() - { - SomeProperty = 22, - SomeProperty2 = "bar", - SomeQuery = "test" - }, - new StreamPart(stream, "Test.pdf", "application/pdf") - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task PostFooBarPathQueryObjectMultipart() + { + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://foo/foos/22/bar/bar") + .WithExactQueryString("Property1=test&Property2=test2") + .Respond("application/json", "Ok"); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://foo", settings); + + using var stream = GetTestFileStream("Test Files/Test.pdf"); + await fixture.PostFooBarStreamPart( + new PathBoundObject { SomeProperty = 22, SomeProperty2 = "bar" }, + new ModelObject() { Property1 = "test", Property2 = "test2" }, + new StreamPart(stream, "Test.pdf", "application/pdf") + ); + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task PostFooBarPathQueryObjectMultipart() - { - var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Post, "http://foo/foos/22/bar/bar") - .WithExactQueryString("Property1=test&Property2=test2") - .Respond("application/json", "Ok"); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); - - using var stream = GetTestFileStream("Test Files/Test.pdf"); - await fixture.PostFooBarStreamPart( - new PathBoundObject { SomeProperty = 22, SomeProperty2 = "bar" }, - new ModelObject() { Property1 = "test", Property2 = "test2" }, - new StreamPart(stream, "Test.pdf", "application/pdf") - ); - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task DoesntAddAutoAddContentToGetRequest() + { + var mockHttp = new MockHttpMessageHandler(); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task DoesntAddAutoAddContentToGetRequest() - { - var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + mockHttp + .Expect(HttpMethod.Get, "http://foo/nobody") + // We can't add HttpContent to a GET request, + // because HttpClient doesn't allow it and it will + // blow up at runtime + .With(r => r.Content == null) + .Respond("application/json", "Ok"); - mockHttp - .Expect(HttpMethod.Get, "http://foo/nobody") - // We can't add HttpContent to a GET request, - // because HttpClient doesn't allow it and it will - // blow up at runtime - .With(r => r.Content == null) - .Respond("application/json", "Ok"); + var fixture = RestService.For("http://foo", settings); - var fixture = RestService.For("http://foo", settings); + await fixture.Get(); - await fixture.Get(); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task DoesntAddAutoAddContentToHeadRequest() + { + var mockHttp = new MockHttpMessageHandler(); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task DoesntAddAutoAddContentToHeadRequest() - { - var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + mockHttp + .Expect(HttpMethod.Head, "http://foo/nobody") + // We can't add HttpContent to a HEAD request, + // because HttpClient doesn't allow it and it will + // blow up at runtime + .With(r => r.Content == null) + .Respond("application/json", "Ok"); - mockHttp - .Expect(HttpMethod.Head, "http://foo/nobody") - // We can't add HttpContent to a HEAD request, - // because HttpClient doesn't allow it and it will - // blow up at runtime - .With(r => r.Content == null) - .Respond("application/json", "Ok"); + var fixture = RestService.For("http://foo", settings); - var fixture = RestService.For("http://foo", settings); + await fixture.Head(); - await fixture.Head(); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task GetWithDecimal() + { + var mockHttp = new MockHttpMessageHandler(); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task GetWithDecimal() - { - var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + mockHttp + .Expect(HttpMethod.Get, "http://foo/withDecimal") + .WithExactQueryString(new[] { new KeyValuePair("value", "3.456") }) + .Respond("application/json", "Ok"); - mockHttp - .Expect(HttpMethod.Get, "http://foo/withDecimal") - .WithExactQueryString(new[] { new KeyValuePair("value", "3.456") }) - .Respond("application/json", "Ok"); + var fixture = RestService.For("http://foo", settings); - var fixture = RestService.For("http://foo", settings); + const decimal val = 3.456M; - const decimal val = 3.456M; + var result = await fixture.GetWithDecimal(val); - var result = await fixture.GetWithDecimal(val); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task HitTheGitHubUserApiAsApiResponse() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task HitTheGitHubUserApiAsApiResponse() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); - - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + var responseMessage = new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent( + "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }", + System.Text.Encoding.UTF8, + "application/json" + ), + }; + responseMessage.Headers.Add("Cookie", "Value"); + + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") + .Respond(req => responseMessage); + + var fixture = RestService.For("https://api.github.com", settings); + + var result = await fixture.GetUserWithMetadata("octocat"); + + Assert.True(result.Headers.Any()); + Assert.True(result.IsSuccessStatusCode); + Assert.NotNull(result.ReasonPhrase); + Assert.NotNull(result.RequestMessage); + Assert.False(result.StatusCode == default); + Assert.NotNull(result.Version); + Assert.Equal("octocat", result.Content.Login); + Assert.False(string.IsNullOrEmpty(result.Content.AvatarUrl)); + + mockHttp.VerifyNoOutstandingExpectation(); + } - var responseMessage = new HttpResponseMessage() - { - StatusCode = HttpStatusCode.OK, - Content = new StringContent( - "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }", - System.Text.Encoding.UTF8, - "application/json" - ), - }; - responseMessage.Headers.Add("Cookie", "Value"); - - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") - .Respond(req => responseMessage); - - var fixture = RestService.For("https://api.github.com", settings); - - var result = await fixture.GetUserWithMetadata("octocat"); - - Assert.True(result.Headers.Any()); - Assert.True(result.IsSuccessStatusCode); - Assert.NotNull(result.ReasonPhrase); - Assert.NotNull(result.RequestMessage); - Assert.False(result.StatusCode == default); - Assert.NotNull(result.Version); - Assert.Equal("octocat", result.Content.Login); - Assert.False(string.IsNullOrEmpty(result.Content.AvatarUrl)); - - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task HitTheNonExistentApiAsApiResponse() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task HitTheNonExistentApiAsApiResponse() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/give-me-some-404-action") + .Respond(HttpStatusCode.NotFound); - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/give-me-some-404-action") - .Respond(HttpStatusCode.NotFound); + var fixture = RestService.For("https://api.github.com", settings); - var fixture = RestService.For("https://api.github.com", settings); + using var result = await fixture.NothingToSeeHereWithMetadata(); + Assert.False(result.IsSuccessStatusCode); + Assert.NotNull(result.ReasonPhrase); + Assert.NotNull(result.RequestMessage); + Assert.True(result.StatusCode == HttpStatusCode.NotFound); + Assert.NotNull(result.Version); + Assert.Null(result.Content); - using var result = await fixture.NothingToSeeHereWithMetadata(); - Assert.False(result.IsSuccessStatusCode); - Assert.NotNull(result.ReasonPhrase); - Assert.NotNull(result.RequestMessage); - Assert.True(result.StatusCode == HttpStatusCode.NotFound); - Assert.NotNull(result.Version); - Assert.Null(result.Content); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task HitTheNonExistentApi() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task HitTheNonExistentApi() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); - - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; - - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/give-me-some-404-action") - .Respond(HttpStatusCode.NotFound); + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; - var fixture = RestService.For("https://api.github.com", settings); + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/give-me-some-404-action") + .Respond(HttpStatusCode.NotFound); - try - { - var result = await fixture.NothingToSeeHere(); - } - catch (Exception ex) - { - Assert.IsType(ex); - } + var fixture = RestService.For("https://api.github.com", settings); - mockHttp.VerifyNoOutstandingExpectation(); + try + { + var result = await fixture.NothingToSeeHere(); } - - [Fact] - public async Task HitTheGitHubUserApiAsObservableApiResponse() + catch (Exception ex) { - var mockHttp = new MockHttpMessageHandler(); + Assert.IsType(ex); + } - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + mockHttp.VerifyNoOutstandingExpectation(); + } - var responseMessage = new HttpResponseMessage() - { - StatusCode = HttpStatusCode.OK, - Content = new StringContent( - "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }", - System.Text.Encoding.UTF8, - "application/json" - ), - }; - responseMessage.Headers.Add("Cookie", "Value"); - - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") - .Respond(req => responseMessage); - - var fixture = RestService.For("https://api.github.com", settings); - - var result = await fixture - .GetUserObservableWithMetadata("octocat") - .Timeout(TimeSpan.FromSeconds(10)); - - Assert.True(result.Headers.Any()); - Assert.True(result.IsSuccessStatusCode); - Assert.NotNull(result.ReasonPhrase); - Assert.NotNull(result.RequestMessage); - Assert.False(result.StatusCode == default); - Assert.NotNull(result.Version); - Assert.Equal("octocat", result.Content.Login); - Assert.False(string.IsNullOrEmpty(result.Content.AvatarUrl)); - - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task HitTheGitHubUserApiAsObservableApiResponse() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task HitTheGitHubUserApi() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + var responseMessage = new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent( + "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }", + System.Text.Encoding.UTF8, + "application/json" + ), + }; + responseMessage.Headers.Add("Cookie", "Value"); + + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") + .Respond(req => responseMessage); + + var fixture = RestService.For("https://api.github.com", settings); + + var result = await fixture + .GetUserObservableWithMetadata("octocat") + .Timeout(TimeSpan.FromSeconds(10)); + + Assert.True(result.Headers.Any()); + Assert.True(result.IsSuccessStatusCode); + Assert.NotNull(result.ReasonPhrase); + Assert.NotNull(result.RequestMessage); + Assert.False(result.StatusCode == default); + Assert.NotNull(result.Version); + Assert.Equal("octocat", result.Content.Login); + Assert.False(string.IsNullOrEmpty(result.Content.AvatarUrl)); + + mockHttp.VerifyNoOutstandingExpectation(); + } - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + [Fact] + public async Task HitTheGitHubUserApi() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") - .Respond( - "application/json", - "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }" - ); + var settings = new RefitSettings + { + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") + .Respond( + "application/json", + "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }" + ); - var fixture = RestService.For("https://api.github.com", settings); + var fixture = RestService.For("https://api.github.com", settings); - var result = await fixture.GetUser("octocat"); + var result = await fixture.GetUser("octocat"); - Assert.Equal("octocat", result.Login); - Assert.False(string.IsNullOrEmpty(result.AvatarUrl)); + Assert.Equal("octocat", result.Login); + Assert.False(string.IsNullOrEmpty(result.AvatarUrl)); - mockHttp.VerifyNoOutstandingExpectation(); - } + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task HitWithCamelCaseParameter() - { - var mockHttp = new MockHttpMessageHandler(); + [Fact] + public async Task HitWithCamelCaseParameter() + { + var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + var settings = new RefitSettings + { + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") + .Respond( + "application/json", + "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }" + ); - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") - .Respond( - "application/json", - "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }" - ); + var fixture = RestService.For("https://api.github.com", settings); - var fixture = RestService.For("https://api.github.com", settings); + var result = await fixture.GetUserCamelCase("octocat"); - var result = await fixture.GetUserCamelCase("octocat"); + Assert.Equal("octocat", result.Login); + Assert.False(string.IsNullOrEmpty(result.AvatarUrl)); - Assert.Equal("octocat", result.Login); - Assert.False(string.IsNullOrEmpty(result.AvatarUrl)); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task HitTheGitHubOrgMembersApi() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task HitTheGitHubOrgMembersApi() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); - - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/orgs/github/members") + .Respond( + "application/json", + "[{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]" + ); - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/orgs/github/members") - .Respond( - "application/json", - "[{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]" - ); + var fixture = RestService.For("https://api.github.com", settings); - var fixture = RestService.For("https://api.github.com", settings); + var result = await fixture.GetOrgMembers("github"); - var result = await fixture.GetOrgMembers("github"); + Assert.True(result.Count > 0); + Assert.Contains(result, member => member.Type == "User"); - Assert.True(result.Count > 0); - Assert.Contains(result, member => member.Type == "User"); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task HitTheGitHubOrgMembersApiInParallel() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task HitTheGitHubOrgMembersApiInParallel() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); - - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/orgs/github/members") + .Respond( + "application/json", + "[{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]" + ); + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/orgs/github/members") + .Respond( + "application/json", + "[{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]" + ); - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/orgs/github/members") - .Respond( - "application/json", - "[{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]" - ); - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/orgs/github/members") - .Respond( - "application/json", - "[{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]" - ); + var fixture = RestService.For("https://api.github.com", settings); - var fixture = RestService.For("https://api.github.com", settings); + var task1 = fixture.GetOrgMembers("github"); + var task2 = fixture.GetOrgMembers("github"); - var task1 = fixture.GetOrgMembers("github"); - var task2 = fixture.GetOrgMembers("github"); + await Task.WhenAll(task1, task2); - await Task.WhenAll(task1, task2); + Assert.True(task1.Result.Count > 0); + Assert.Contains(task1.Result, member => member.Type == "User"); - Assert.True(task1.Result.Count > 0); - Assert.Contains(task1.Result, member => member.Type == "User"); + Assert.True(task2.Result.Count > 0); + Assert.Contains(task2.Result, member => member.Type == "User"); - Assert.True(task2.Result.Count > 0); - Assert.Contains(task2.Result, member => member.Type == "User"); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task RequestCanceledBeforeResponseRead() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task RequestCanceledBeforeResponseRead() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + var cts = new CancellationTokenSource(); - var cts = new CancellationTokenSource(); + mockHttp + .When(HttpMethod.Get, "https://api.github.com/orgs/github/members") + .Respond(req => + { + // Cancel the request + cts.Cancel(); - mockHttp - .When(HttpMethod.Get, "https://api.github.com/orgs/github/members") - .Respond(req => + return new HttpResponseMessage(HttpStatusCode.OK) { - // Cancel the request - cts.Cancel(); + Content = new StringContent( + "[{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]", + Encoding.UTF8, + "application/json" + ) + }; + }); + + var fixture = RestService.For("https://api.github.com", settings); + + var result = await Assert.ThrowsAsync( + async () => await fixture.GetOrgMembers("github", cts.Token) + ); - return new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent( - "[{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]", - Encoding.UTF8, - "application/json" - ) - }; - }); + AssertFirstLineContains(nameof(IGitHubApi.GetOrgMembers), result.StackTrace); + } - var fixture = RestService.For("https://api.github.com", settings); + [Fact] + public async Task HitTheGitHubUserSearchApi() + { + var mockHttp = new MockHttpMessageHandler(); - var result = await Assert.ThrowsAsync( - async () => await fixture.GetOrgMembers("github", cts.Token) + var settings = new RefitSettings + { + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/search/users") + .WithQueryString("q", "tom repos:>42 followers:>1000") + .Respond( + "application/json", + "{ 'total_count': 1, 'items': [{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]}" ); - AssertFirstLineContains(nameof(IGitHubApi.GetOrgMembers), result.StackTrace); - } + var fixture = RestService.For("https://api.github.com", settings); - [Fact] - public async Task HitTheGitHubUserSearchApi() - { - var mockHttp = new MockHttpMessageHandler(); + var result = await fixture.FindUsers("tom repos:>42 followers:>1000"); - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + Assert.True(result.TotalCount > 0); + Assert.Contains(result.Items, member => member.Type == "User"); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/search/users") - .WithQueryString("q", "tom repos:>42 followers:>1000") - .Respond( - "application/json", - "{ 'total_count': 1, 'items': [{ 'login':'octocat', 'avatar_url':'http://foo/bar', 'type':'User'}]}" - ); + [Fact] + public async Task HitTheGitHubUserApiAsObservable() + { + var mockHttp = new MockHttpMessageHandler(); - var fixture = RestService.For("https://api.github.com", settings); + var settings = new RefitSettings + { + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") + .Respond( + "application/json", + "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }" + ); - var result = await fixture.FindUsers("tom repos:>42 followers:>1000"); + var fixture = RestService.For("https://api.github.com", settings); - Assert.True(result.TotalCount > 0); - Assert.Contains(result.Items, member => member.Type == "User"); - mockHttp.VerifyNoOutstandingExpectation(); - } + var result = await fixture + .GetUserObservable("octocat") + .Timeout(TimeSpan.FromSeconds(10)); - [Fact] - public async Task HitTheGitHubUserApiAsObservable() - { - var mockHttp = new MockHttpMessageHandler(); + Assert.Equal("octocat", result.Login); + Assert.False(string.IsNullOrEmpty(result.AvatarUrl)); - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp - .Expect(HttpMethod.Get, "https://api.github.com/users/octocat") - .Respond( - "application/json", - "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }" - ); + [Fact] + public async Task HitTheGitHubUserApiAsObservableAndSubscribeAfterTheFact() + { + var mockHttp = new MockHttpMessageHandler(); - var fixture = RestService.For("https://api.github.com", settings); + var settings = new RefitSettings + { + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .When(HttpMethod.Get, "https://api.github.com/users/octocat") + .Respond( + "application/json", + "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }" + ); - var result = await fixture - .GetUserObservable("octocat") - .Timeout(TimeSpan.FromSeconds(10)); + var fixture = RestService.For("https://api.github.com", settings); - Assert.Equal("octocat", result.Login); - Assert.False(string.IsNullOrEmpty(result.AvatarUrl)); + var obs = fixture.GetUserObservable("octocat").Timeout(TimeSpan.FromSeconds(10)); - mockHttp.VerifyNoOutstandingExpectation(); - } + // NB: We're gonna await twice, so that the 2nd await is definitely + // after the result has completed. + await obs; + var result2 = await obs; + Assert.Equal("octocat", result2.Login); + Assert.False(string.IsNullOrEmpty(result2.AvatarUrl)); + } - [Fact] - public async Task HitTheGitHubUserApiAsObservableAndSubscribeAfterTheFact() + [Fact] + public async Task TwoSubscriptionsResultInTwoRequests() + { + var input = new TestHttpMessageHandler { - var mockHttp = new MockHttpMessageHandler(); - - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; - - mockHttp - .When(HttpMethod.Get, "https://api.github.com/users/octocat") - .Respond( - "application/json", - "{ 'login':'octocat', 'avatar_url':'http://foo/bar' }" - ); - - var fixture = RestService.For("https://api.github.com", settings); - - var obs = fixture.GetUserObservable("octocat").Timeout(TimeSpan.FromSeconds(10)); - - // NB: We're gonna await twice, so that the 2nd await is definitely - // after the result has completed. - await obs; - var result2 = await obs; - Assert.Equal("octocat", result2.Login); - Assert.False(string.IsNullOrEmpty(result2.AvatarUrl)); - } + // we need to use a factory here to ensure each request gets its own httpcontent instance + ContentFactory = () => new StringContent("test") + }; - [Fact] - public async Task TwoSubscriptionsResultInTwoRequests() - { - var input = new TestHttpMessageHandler - { - // we need to use a factory here to ensure each request gets its own httpcontent instance - ContentFactory = () => new StringContent("test") - }; + var client = new HttpClient(input) { BaseAddress = new Uri("http://foo") }; + var fixture = RestService.For(client); - var client = new HttpClient(input) { BaseAddress = new Uri("http://foo") }; - var fixture = RestService.For(client); + Assert.Equal(0, input.MessagesSent); - Assert.Equal(0, input.MessagesSent); + var obs = fixture.GetIndexObservable().Timeout(TimeSpan.FromSeconds(10)); - var obs = fixture.GetIndexObservable().Timeout(TimeSpan.FromSeconds(10)); + var result1 = await obs; + Assert.Equal(1, input.MessagesSent); - var result1 = await obs; - Assert.Equal(1, input.MessagesSent); + var result2 = await obs; + Assert.Equal(2, input.MessagesSent); - var result2 = await obs; - Assert.Equal(2, input.MessagesSent); + // NB: TestHttpMessageHandler returns what we tell it to ('test' by default) + Assert.Contains("test", result1); + Assert.Contains("test", result2); + } - // NB: TestHttpMessageHandler returns what we tell it to ('test' by default) - Assert.Contains("test", result1); - Assert.Contains("test", result2); - } + [Fact] + public async Task ShouldRetHttpResponseMessage() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task ShouldRetHttpResponseMessage() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + mockHttp.When(HttpMethod.Get, "https://api.github.com/").Respond(HttpStatusCode.OK); - mockHttp.When(HttpMethod.Get, "https://api.github.com/").Respond(HttpStatusCode.OK); + var fixture = RestService.For("https://api.github.com", settings); + var result = await fixture.GetIndex(); - var fixture = RestService.For("https://api.github.com", settings); - var result = await fixture.GetIndex(); + Assert.NotNull(result); + Assert.True(result.IsSuccessStatusCode); + } - Assert.NotNull(result); - Assert.True(result.IsSuccessStatusCode); - } + [Fact] + public async Task ShouldRetHttpResponseMessageWithNestedInterface() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task ShouldRetHttpResponseMessageWithNestedInterface() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + mockHttp.When(HttpMethod.Get, "https://api.github.com/").Respond(HttpStatusCode.OK); - mockHttp.When(HttpMethod.Get, "https://api.github.com/").Respond(HttpStatusCode.OK); + var fixture = RestService.For( + "https://api.github.com", + settings + ); + var result = await fixture.GetIndex(); - var fixture = RestService.For( - "https://api.github.com", - settings - ); - var result = await fixture.GetIndex(); + Assert.NotNull(result); + Assert.True(result.IsSuccessStatusCode); + } - Assert.NotNull(result); - Assert.True(result.IsSuccessStatusCode); - } + [Fact] + public async Task HitTheNpmJs() + { + var mockHttp = new MockHttpMessageHandler(); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task HitTheNpmJs() - { - var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Get, "https://registry.npmjs.org/congruence") + .Respond( + "application/json", + "{ \"_id\":\"congruence\", \"_rev\":\"rev\" , \"name\":\"name\"}" + ); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("https://registry.npmjs.org", settings); + var result = await fixture.GetCongruence(); - mockHttp - .Expect(HttpMethod.Get, "https://registry.npmjs.org/congruence") - .Respond( - "application/json", - "{ \"_id\":\"congruence\", \"_rev\":\"rev\" , \"name\":\"name\"}" - ); + Assert.Equal("congruence", result._id); - var fixture = RestService.For("https://registry.npmjs.org", settings); - var result = await fixture.GetCongruence(); + mockHttp.VerifyNoOutstandingExpectation(); + } - Assert.Equal("congruence", result._id); + [Fact] + public async Task PostToRequestBin() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp.VerifyNoOutstandingExpectation(); - } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task PostToRequestBin() - { - var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://httpbin.org/1h3a5jm1") + .Respond(HttpStatusCode.OK); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://httpbin.org/", settings); - mockHttp - .Expect(HttpMethod.Post, "http://httpbin.org/1h3a5jm1") - .Respond(HttpStatusCode.OK); + await fixture.Post(); - var fixture = RestService.For("http://httpbin.org/", settings); + mockHttp.VerifyNoOutstandingExpectation(); + } - await fixture.Post(); + [Fact] + public async Task PostStringDefaultToRequestBin() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp.VerifyNoOutstandingExpectation(); - } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task PostStringDefaultToRequestBin() - { - var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://httpbin.org/foo") + .WithContent("raw string") + .Respond(HttpStatusCode.OK); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://httpbin.org/", settings); - mockHttp - .Expect(HttpMethod.Post, "http://httpbin.org/foo") - .WithContent("raw string") - .Respond(HttpStatusCode.OK); + await fixture.PostRawStringDefault("raw string"); - var fixture = RestService.For("http://httpbin.org/", settings); + mockHttp.VerifyNoOutstandingExpectation(); + } - await fixture.PostRawStringDefault("raw string"); + [Fact] + public async Task PostStringJsonToRequestBin() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp.VerifyNoOutstandingExpectation(); - } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task PostStringJsonToRequestBin() - { - var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://httpbin.org/foo") + .WithContent("\"json string\"") + .WithHeaders("Content-Type", "application/json; charset=utf-8") + .Respond(HttpStatusCode.OK); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://httpbin.org/", settings); - mockHttp - .Expect(HttpMethod.Post, "http://httpbin.org/foo") - .WithContent("\"json string\"") - .WithHeaders("Content-Type", "application/json; charset=utf-8") - .Respond(HttpStatusCode.OK); + await fixture.PostRawStringJson("json string"); - var fixture = RestService.For("http://httpbin.org/", settings); + mockHttp.VerifyNoOutstandingExpectation(); + } - await fixture.PostRawStringJson("json string"); + [Fact] + public async Task PostStringUrlToRequestBin() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp.VerifyNoOutstandingExpectation(); - } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task PostStringUrlToRequestBin() - { - var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://httpbin.org/foo") + .WithContent("url%26string") + .WithHeaders("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") + .Respond(HttpStatusCode.OK); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://httpbin.org/", settings); - mockHttp - .Expect(HttpMethod.Post, "http://httpbin.org/foo") - .WithContent("url%26string") - .WithHeaders("Content-Type", "application/x-www-form-urlencoded; charset=utf-8") - .Respond(HttpStatusCode.OK); + await fixture.PostRawStringUrlEncoded("url&string"); - var fixture = RestService.For("http://httpbin.org/", settings); + mockHttp.VerifyNoOutstandingExpectation(); + } - await fixture.PostRawStringUrlEncoded("url&string"); + [Fact] + public async Task PostToRequestBinWithGenerics() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp.VerifyNoOutstandingExpectation(); - } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task PostToRequestBinWithGenerics() - { - var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect(HttpMethod.Post, "http://httpbin.org/1h3a5jm1") + .Respond(HttpStatusCode.OK); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://httpbin.org/", settings); - mockHttp - .Expect(HttpMethod.Post, "http://httpbin.org/1h3a5jm1") - .Respond(HttpStatusCode.OK); + await fixture.PostGeneric(5); - var fixture = RestService.For("http://httpbin.org/", settings); + mockHttp.VerifyNoOutstandingExpectation(); - await fixture.PostGeneric(5); + mockHttp.ResetExpectations(); - mockHttp.VerifyNoOutstandingExpectation(); + mockHttp + .Expect(HttpMethod.Post, "http://httpbin.org/1h3a5jm1") + .Respond(HttpStatusCode.OK); - mockHttp.ResetExpectations(); + await fixture.PostGeneric("4"); - mockHttp - .Expect(HttpMethod.Post, "http://httpbin.org/1h3a5jm1") - .Respond(HttpStatusCode.OK); + mockHttp.VerifyNoOutstandingExpectation(); + } - await fixture.PostGeneric("4"); + [Fact] + public async Task PostWithVoidReturnBufferedBodyExpectContentLengthHeader() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp.VerifyNoOutstandingExpectation(); - } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task PostWithVoidReturnBufferedBodyExpectContentLengthHeader() + var postBody = new Dictionary { - var mockHttp = new MockHttpMessageHandler(); + { "some", "body" }, + { "once", "told me" } + }; - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + mockHttp + .Expect(HttpMethod.Post, "http://httpbin.org/foo") + .With(request => request.Content?.Headers.ContentLength > 0) + .Respond(HttpStatusCode.OK); - var postBody = new Dictionary - { - { "some", "body" }, - { "once", "told me" } - }; + var fixture = RestService.For("http://httpbin.org/", settings); - mockHttp - .Expect(HttpMethod.Post, "http://httpbin.org/foo") - .With(request => request.Content?.Headers.ContentLength > 0) - .Respond(HttpStatusCode.OK); + await fixture.PostVoidReturnBodyBuffered(postBody); - var fixture = RestService.For("http://httpbin.org/", settings); + mockHttp.VerifyNoOutstandingExpectation(); + } - await fixture.PostVoidReturnBodyBuffered(postBody); + [Fact] + public async Task PostWithNonVoidReturnBufferedBodyExpectContentLengthHeader() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp.VerifyNoOutstandingExpectation(); - } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task PostWithNonVoidReturnBufferedBodyExpectContentLengthHeader() + var postBody = new Dictionary { - var mockHttp = new MockHttpMessageHandler(); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + { "some", "body" }, + { "once", "told me" } + }; + const string expectedResponse = "some response"; - var postBody = new Dictionary - { - { "some", "body" }, - { "once", "told me" } - }; - const string expectedResponse = "some response"; + mockHttp + .Expect(HttpMethod.Post, "http://httpbin.org/foo") + .With(request => request.Content?.Headers.ContentLength > 0) + .Respond("text/plain", expectedResponse); - mockHttp - .Expect(HttpMethod.Post, "http://httpbin.org/foo") - .With(request => request.Content?.Headers.ContentLength > 0) - .Respond("text/plain", expectedResponse); + var fixture = RestService.For("http://httpbin.org/", settings); - var fixture = RestService.For("http://httpbin.org/", settings); + var result = await fixture.PostNonVoidReturnBodyBuffered(postBody); - var result = await fixture.PostNonVoidReturnBodyBuffered(postBody); + mockHttp.VerifyNoOutstandingExpectation(); - mockHttp.VerifyNoOutstandingExpectation(); + Assert.Equal(expectedResponse, result); + } - Assert.Equal(expectedResponse, result); - } + [Fact] + public async Task UseMethodWithArgumentsParameter() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task UseMethodWithArgumentsParameter() - { - var mockHttp = new MockHttpMessageHandler(); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For("http://httpbin.org/", settings); - var fixture = RestService.For("http://httpbin.org/", settings); + mockHttp + .Expect(HttpMethod.Get, "http://httpbin.org/foo/something") + .Respond(HttpStatusCode.OK); - mockHttp - .Expect(HttpMethod.Get, "http://httpbin.org/foo/something") - .Respond(HttpStatusCode.OK); + await fixture.SomeApiThatUsesVariableNameFromCodeGen("something"); - await fixture.SomeApiThatUsesVariableNameFromCodeGen("something"); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task CanGetDataOutOfErrorResponses() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task CanGetDataOutOfErrorResponses() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .When(HttpMethod.Get, "https://api.github.com/give-me-some-404-action") + .Respond( + HttpStatusCode.NotFound, + "application/json", + "{'message': 'Not Found', 'documentation_url': 'http://foo/bar'}" + ); - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; - - mockHttp - .When(HttpMethod.Get, "https://api.github.com/give-me-some-404-action") - .Respond( - HttpStatusCode.NotFound, - "application/json", - "{'message': 'Not Found', 'documentation_url': 'http://foo/bar'}" - ); - - var fixture = RestService.For("https://api.github.com", settings); - try - { - await fixture.NothingToSeeHere(); - Assert.True(false); - } - catch (ApiException exception) - { - Assert.Equal(HttpStatusCode.NotFound, exception.StatusCode); - var content = await exception.GetContentAsAsync>(); + var fixture = RestService.For("https://api.github.com", settings); + try + { + await fixture.NothingToSeeHere(); + Assert.True(false); + } + catch (ApiException exception) + { + Assert.Equal(HttpStatusCode.NotFound, exception.StatusCode); + var content = await exception.GetContentAsAsync>(); - Assert.Equal("Not Found", content["message"]); - Assert.NotNull(content["documentation_url"]); - } + Assert.Equal("Not Found", content["message"]); + Assert.NotNull(content["documentation_url"]); } + } - [Fact] - public async Task CanSerializeBigData() + [Fact] + public async Task CanSerializeBigData() + { + var mockHttp = new MockHttpMessageHandler(); + + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new SystemTextJsonContentSerializer() + }; - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new SystemTextJsonContentSerializer() - }; + var bigObject = new BigObject + { + BigData = Enumerable.Range(0, 800000).Select(x => (byte)(x % 256)).ToArray() + }; - var bigObject = new BigObject + mockHttp + .Expect(HttpMethod.Post, "http://httpbin.org/big") + .With(m => { - BigData = Enumerable.Range(0, 800000).Select(x => (byte)(x % 256)).ToArray() - }; - - mockHttp - .Expect(HttpMethod.Post, "http://httpbin.org/big") - .With(m => + async Task T() { - async Task T() - { - using var s = await m.Content.ReadAsStreamAsync(); - var it = await System.Text.Json.JsonSerializer.DeserializeAsync( - s, - new System.Text.Json.JsonSerializerOptions - { - PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase - } - ); - return it.BigData.SequenceEqual(bigObject.BigData); - } + using var s = await m.Content.ReadAsStreamAsync(); + var it = await System.Text.Json.JsonSerializer.DeserializeAsync( + s, + new System.Text.Json.JsonSerializerOptions + { + PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase + } + ); + return it.BigData.SequenceEqual(bigObject.BigData); + } - return T().Result; - }) - .Respond(HttpStatusCode.OK); + return T().Result; + }) + .Respond(HttpStatusCode.OK); - var fixture = RestService.For("http://httpbin.org/", settings); + var fixture = RestService.For("http://httpbin.org/", settings); - await fixture.PostBig(bigObject); + await fixture.PostBig(bigObject); - mockHttp.VerifyNoOutstandingExpectation(); - } + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task ErrorsFromApiReturnErrorContent() - { - var mockHttp = new MockHttpMessageHandler(); + [Fact] + public async Task ErrorsFromApiReturnErrorContent() + { + var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + var settings = new RefitSettings + { + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .Expect(HttpMethod.Post, "https://api.github.com/users") + .Respond( + HttpStatusCode.BadRequest, + "application/json", + "{ 'errors': [ 'error1', 'message' ]}" + ); - mockHttp - .Expect(HttpMethod.Post, "https://api.github.com/users") - .Respond( - HttpStatusCode.BadRequest, - "application/json", - "{ 'errors': [ 'error1', 'message' ]}" - ); + var fixture = RestService.For("https://api.github.com", settings); - var fixture = RestService.For("https://api.github.com", settings); + var result = await Assert.ThrowsAsync( + async () => await fixture.CreateUser(new User { Name = "foo" }) + ); - var result = await Assert.ThrowsAsync( - async () => await fixture.CreateUser(new User { Name = "foo" }) - ); + AssertFirstLineContains(nameof(IGitHubApi.CreateUser), result.StackTrace); - AssertFirstLineContains(nameof(IGitHubApi.CreateUser), result.StackTrace); + var errors = await result.GetContentAsAsync(); - var errors = await result.GetContentAsAsync(); + Assert.Contains("error1", errors.Errors); + Assert.Contains("message", errors.Errors); - Assert.Contains("error1", errors.Errors); - Assert.Contains("message", errors.Errors); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task ErrorsFromApiReturnErrorContentWhenApiResponse() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task ErrorsFromApiReturnErrorContentWhenApiResponse() + var settings = new RefitSettings { - var mockHttp = new MockHttpMessageHandler(); - - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = new NewtonsoftJsonContentSerializer( - new JsonSerializerSettings() - { - ContractResolver = new SnakeCasePropertyNamesContractResolver() - } - ) - }; + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = new NewtonsoftJsonContentSerializer( + new JsonSerializerSettings() + { + ContractResolver = new SnakeCasePropertyNamesContractResolver() + } + ) + }; + + mockHttp + .Expect(HttpMethod.Post, "https://api.github.com/users") + .Respond( + HttpStatusCode.BadRequest, + "application/json", + "{ 'errors': [ 'error1', 'message' ]}" + ); - mockHttp - .Expect(HttpMethod.Post, "https://api.github.com/users") - .Respond( - HttpStatusCode.BadRequest, - "application/json", - "{ 'errors': [ 'error1', 'message' ]}" - ); + var fixture = RestService.For("https://api.github.com", settings); - var fixture = RestService.For("https://api.github.com", settings); + using var response = await fixture.CreateUserWithMetadata(new User { Name = "foo" }); + Assert.False(response.IsSuccessStatusCode); + Assert.NotNull(response.Error); - using var response = await fixture.CreateUserWithMetadata(new User { Name = "foo" }); - Assert.False(response.IsSuccessStatusCode); - Assert.NotNull(response.Error); + var errors = await response.Error.GetContentAsAsync(); - var errors = await response.Error.GetContentAsAsync(); + Assert.Contains("error1", errors.Errors); + Assert.Contains("message", errors.Errors); - Assert.Contains("error1", errors.Errors); - Assert.Contains("message", errors.Errors); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); + [Fact] + public void NonRefitInterfacesThrowMeaningfulExceptions() + { + try + { + RestService.For("http://example.com"); } - - [Fact] - public void NonRefitInterfacesThrowMeaningfulExceptions() + catch (InvalidOperationException exception) { - try - { - RestService.For("http://example.com"); - } - catch (InvalidOperationException exception) - { - Assert.StartsWith("INoRefitHereBuddy", exception.Message); - } + Assert.StartsWith("INoRefitHereBuddy", exception.Message); } + } - [Fact] - public async Task NonRefitMethodsThrowMeaningfulExceptions() + [Fact] + public async Task NonRefitMethodsThrowMeaningfulExceptions() + { + try { - try - { - var fixture = RestService.For("http://example.com"); - await fixture.Get(); - } - catch (NotImplementedException exception) - { - Assert.Contains("no Refit HTTP method attribute", exception.Message); - } + var fixture = RestService.For("http://example.com"); + await fixture.Get(); } - - [Fact] - public async Task GenericsWork() + catch (NotImplementedException exception) { - var mockHttp = new MockHttpMessageHandler(); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - - mockHttp - .Expect(HttpMethod.Get, "http://httpbin.org/get") - .WithHeaders("X-Refit", "99") - .WithQueryString("param", "foo") - .Respond( - "application/json", - "{\"url\": \"http://httpbin.org/get?param=foo\", \"args\": {\"param\": \"foo\"}, \"headers\":{\"X-Refit\":\"99\"}}" - ); - - var fixture = RestService.For>( - "http://httpbin.org/get", - settings - ); + Assert.Contains("no Refit HTTP method attribute", exception.Message); + } + } - var result = await fixture.Get("foo", 99); + [Fact] + public async Task GenericsWork() + { + var mockHttp = new MockHttpMessageHandler(); - Assert.Equal("http://httpbin.org/get?param=foo", result.Url); - Assert.Equal("foo", result.Args["param"]); - Assert.Equal("99", result.Headers["X-Refit"]); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - mockHttp.VerifyNoOutstandingExpectation(); - } + mockHttp + .Expect(HttpMethod.Get, "http://httpbin.org/get") + .WithHeaders("X-Refit", "99") + .WithQueryString("param", "foo") + .Respond( + "application/json", + "{\"url\": \"http://httpbin.org/get?param=foo\", \"args\": {\"param\": \"foo\"}, \"headers\":{\"X-Refit\":\"99\"}}" + ); - [Fact] - public async Task ValueTypesArentValidButTheyWorkAnyway() - { - var handler = new TestHttpMessageHandler("true"); + var fixture = RestService.For>( + "http://httpbin.org/get", + settings + ); - var fixture = RestService.For( - new HttpClient(handler) { BaseAddress = new Uri("http://nowhere.com") } - ); + var result = await fixture.Get("foo", 99); - var result = await fixture.PostAValue("Does this work?"); + Assert.Equal("http://httpbin.org/get?param=foo", result.Url); + Assert.Equal("foo", result.Args["param"]); + Assert.Equal("99", result.Headers["X-Refit"]); - Assert.True(result); - } + mockHttp.VerifyNoOutstandingExpectation(); + } - [Fact] - public async Task MissingBaseUrlThrowsArgumentException() - { - var client = new HttpClient(); // No BaseUrl specified + [Fact] + public async Task ValueTypesArentValidButTheyWorkAnyway() + { + var handler = new TestHttpMessageHandler("true"); - var fixture = RestService.For(client); + var fixture = RestService.For( + new HttpClient(handler) { BaseAddress = new Uri("http://nowhere.com") } + ); - // We should get an InvalidOperationException if we call a method without a base address set - var result = await Assert.ThrowsAsync( - async () => await fixture.GetUser(null) - ); + var result = await fixture.PostAValue("Does this work?"); - AssertFirstLineContains(nameof(IGitHubApi.GetUser), result.StackTrace); - } + Assert.True(result); + } - [Fact] - public async Task SimpleDynamicQueryparametersTest() - { - var mockHttp = new MockHttpMessageHandler(); + [Fact] + public async Task MissingBaseUrlThrowsArgumentException() + { + var client = new HttpClient(); // No BaseUrl specified - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For(client); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .WithHeaders("X-Refit", "99") - .Respond( - "application/json", - "{\"url\": \"https://httpbin.org/get?FirstName=John&LastName=Rambo\", \"args\": {\"FirstName\": \"John\", \"lName\": \"Rambo\"}}" - ); + // We should get an InvalidOperationException if we call a method without a base address set + var result = await Assert.ThrowsAsync( + async () => await fixture.GetUser(null) + ); - var myParams = new MySimpleQueryParams { FirstName = "John", LastName = "Rambo" }; + AssertFirstLineContains(nameof(IGitHubApi.GetUser), result.StackTrace); + } - var fixture = RestService.For>( - "https://httpbin.org/get", - settings - ); + [Fact] + public async Task SimpleDynamicQueryparametersTest() + { + var mockHttp = new MockHttpMessageHandler(); - var resp = await fixture.Get(myParams, 99); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - Assert.Equal("John", resp.Args["FirstName"]); - Assert.Equal("Rambo", resp.Args["lName"]); - } + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .WithHeaders("X-Refit", "99") + .Respond( + "application/json", + "{\"url\": \"https://httpbin.org/get?FirstName=John&LastName=Rambo\", \"args\": {\"FirstName\": \"John\", \"lName\": \"Rambo\"}}" + ); - [Fact] - public async Task ComplexDynamicQueryparametersTest() - { - var mockHttp = new MockHttpMessageHandler(); + var myParams = new MySimpleQueryParams { FirstName = "John", LastName = "Rambo" }; - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For>( + "https://httpbin.org/get", + settings + ); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond( - "application/json", - "{\"url\": \"https://httpbin.org/get?hardcoded=true&FirstName=John&LastName=Rambo&Addr_Zip=9999&Addr_Street=HomeStreet 99&MetaData_Age=99&MetaData_Initials=JR&MetaData_Birthday=10%2F31%2F1918 4%3A21%3A16 PM&Other=12345&Other=10%2F31%2F2017 4%3A21%3A17 PM&Other=696e8653-6671-4484-a65f-9485af95fd3a\", \"args\": { \"Addr_Street\": \"HomeStreet 99\", \"Addr_Zip\": \"9999\", \"FirstName\": \"John\", \"LastName\": \"Rambo\", \"MetaData_Age\": \"99\", \"MetaData_Birthday\": \"10/31/1981 4:32:59 PM\", \"MetaData_Initials\": \"JR\", \"Other\": [\"12345\",\"10/31/2017 4:32:59 PM\",\"60282dd2-f79a-4400-be01-bcb0e86e7bc6\"], \"hardcoded\": \"true\"}}" - ); + var resp = await fixture.Get(myParams, 99); - var myParams = new MyComplexQueryParams { FirstName = "John", LastName = "Rambo" }; - myParams.Address.Postcode = 9999; - myParams.Address.Street = "HomeStreet 99"; + Assert.Equal("John", resp.Args["FirstName"]); + Assert.Equal("Rambo", resp.Args["lName"]); + } - myParams.MetaData.Add("Age", 99); - myParams.MetaData.Add("Initials", "JR"); - myParams.MetaData.Add("Birthday", new DateTime(1981, 10, 31, 16, 24, 59)); + [Fact] + public async Task ComplexDynamicQueryparametersTest() + { + var mockHttp = new MockHttpMessageHandler(); - myParams.Other.Add(12345); - myParams.Other.Add(new DateTime(2017, 10, 31, 16, 24, 59)); - myParams.Other.Add(new Guid("60282dd2-f79a-4400-be01-bcb0e86e7bc6")); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For>( - "https://httpbin.org", - settings + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond( + "application/json", + "{\"url\": \"https://httpbin.org/get?hardcoded=true&FirstName=John&LastName=Rambo&Addr_Zip=9999&Addr_Street=HomeStreet 99&MetaData_Age=99&MetaData_Initials=JR&MetaData_Birthday=10%2F31%2F1918 4%3A21%3A16 PM&Other=12345&Other=10%2F31%2F2017 4%3A21%3A17 PM&Other=696e8653-6671-4484-a65f-9485af95fd3a\", \"args\": { \"Addr_Street\": \"HomeStreet 99\", \"Addr_Zip\": \"9999\", \"FirstName\": \"John\", \"LastName\": \"Rambo\", \"MetaData_Age\": \"99\", \"MetaData_Birthday\": \"10/31/1981 4:32:59 PM\", \"MetaData_Initials\": \"JR\", \"Other\": [\"12345\",\"10/31/2017 4:32:59 PM\",\"60282dd2-f79a-4400-be01-bcb0e86e7bc6\"], \"hardcoded\": \"true\"}}" ); - var resp = await fixture.GetQuery(myParams); + var myParams = new MyComplexQueryParams { FirstName = "John", LastName = "Rambo" }; + myParams.Address.Postcode = 9999; + myParams.Address.Street = "HomeStreet 99"; - Assert.Equal("John", resp.Args["FirstName"]); - Assert.Equal("Rambo", resp.Args["LastName"]); - Assert.Equal("9999", resp.Args["Addr_Zip"]); - } + myParams.MetaData.Add("Age", 99); + myParams.MetaData.Add("Initials", "JR"); + myParams.MetaData.Add("Birthday", new DateTime(1981, 10, 31, 16, 24, 59)); - [Fact] - public async Task ComplexPostDynamicQueryparametersTest() - { - var mockHttp = new MockHttpMessageHandler(); + myParams.Other.Add(12345); + myParams.Other.Add(new DateTime(2017, 10, 31, 16, 24, 59)); + myParams.Other.Add(new Guid("60282dd2-f79a-4400-be01-bcb0e86e7bc6")); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For>( + "https://httpbin.org", + settings + ); - mockHttp - .Expect(HttpMethod.Post, "https://httpbin.org/post") - .Respond( - "application/json", - "{\"url\": \"https://httpbin.org/post?hardcoded=true&FirstName=John&LastName=Rambo&Addr_Zip=9999&Addr_Street=HomeStreet 99&MetaData_Age=99&MetaData_Initials=JR&MetaData_Birthday=10%2F31%2F1918 4%3A21%3A16 PM&Other=12345&Other=10%2F31%2F2017 4%3A21%3A17 PM&Other=696e8653-6671-4484-a65f-9485af95fd3a\", \"args\": { \"Addr_Street\": \"HomeStreet 99\", \"Addr_Zip\": \"9999\", \"FirstName\": \"John\", \"LastName\": \"Rambo\", \"MetaData_Age\": \"99\", \"MetaData_Birthday\": \"10/31/1981 4:32:59 PM\", \"MetaData_Initials\": \"JR\", \"Other\": [\"12345\",\"10/31/2017 4:32:59 PM\",\"60282dd2-f79a-4400-be01-bcb0e86e7bc6\"], \"hardcoded\": \"true\"}}" - ); + var resp = await fixture.GetQuery(myParams); - var myParams = new MyComplexQueryParams { FirstName = "John", LastName = "Rambo" }; - myParams.Address.Postcode = 9999; - myParams.Address.Street = "HomeStreet 99"; + Assert.Equal("John", resp.Args["FirstName"]); + Assert.Equal("Rambo", resp.Args["LastName"]); + Assert.Equal("9999", resp.Args["Addr_Zip"]); + } - myParams.MetaData.Add("Age", 99); - myParams.MetaData.Add("Initials", "JR"); - myParams.MetaData.Add("Birthday", new DateTime(1981, 10, 31, 16, 24, 59)); + [Fact] + public async Task ComplexPostDynamicQueryparametersTest() + { + var mockHttp = new MockHttpMessageHandler(); - myParams.Other.Add(12345); - myParams.Other.Add(new DateTime(2017, 10, 31, 16, 24, 59)); - myParams.Other.Add(new Guid("60282dd2-f79a-4400-be01-bcb0e86e7bc6")); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For>( - "https://httpbin.org", - settings + mockHttp + .Expect(HttpMethod.Post, "https://httpbin.org/post") + .Respond( + "application/json", + "{\"url\": \"https://httpbin.org/post?hardcoded=true&FirstName=John&LastName=Rambo&Addr_Zip=9999&Addr_Street=HomeStreet 99&MetaData_Age=99&MetaData_Initials=JR&MetaData_Birthday=10%2F31%2F1918 4%3A21%3A16 PM&Other=12345&Other=10%2F31%2F2017 4%3A21%3A17 PM&Other=696e8653-6671-4484-a65f-9485af95fd3a\", \"args\": { \"Addr_Street\": \"HomeStreet 99\", \"Addr_Zip\": \"9999\", \"FirstName\": \"John\", \"LastName\": \"Rambo\", \"MetaData_Age\": \"99\", \"MetaData_Birthday\": \"10/31/1981 4:32:59 PM\", \"MetaData_Initials\": \"JR\", \"Other\": [\"12345\",\"10/31/2017 4:32:59 PM\",\"60282dd2-f79a-4400-be01-bcb0e86e7bc6\"], \"hardcoded\": \"true\"}}" ); - var resp = await fixture.PostQuery(myParams); + var myParams = new MyComplexQueryParams { FirstName = "John", LastName = "Rambo" }; + myParams.Address.Postcode = 9999; + myParams.Address.Street = "HomeStreet 99"; - Assert.Equal("John", resp.Args["FirstName"]); - Assert.Equal("Rambo", resp.Args["LastName"]); - Assert.Equal("9999", resp.Args["Addr_Zip"]); - } + myParams.MetaData.Add("Age", 99); + myParams.MetaData.Add("Initials", "JR"); + myParams.MetaData.Add("Birthday", new DateTime(1981, 10, 31, 16, 24, 59)); + + myParams.Other.Add(12345); + myParams.Other.Add(new DateTime(2017, 10, 31, 16, 24, 59)); + myParams.Other.Add(new Guid("60282dd2-f79a-4400-be01-bcb0e86e7bc6")); + + var fixture = RestService.For>( + "https://httpbin.org", + settings + ); + + var resp = await fixture.PostQuery(myParams); + + Assert.Equal("John", resp.Args["FirstName"]); + Assert.Equal("Rambo", resp.Args["LastName"]); + Assert.Equal("9999", resp.Args["Addr_Zip"]); + } + + [Fact] + public async Task GenericMethodTest() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task GenericMethodTest() + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + + const string response = "4"; + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond("application/json", response); + + var myParams = new Dictionary { - var mockHttp = new MockHttpMessageHandler(); + ["FirstName"] = "John", + ["LastName"] = "Rambo", + ["Address"] = new { Zip = 9999, Street = "HomeStreet 99" } + }; - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var fixture = RestService.For, int>>( + "https://httpbin.org", + settings + ); - const string response = "4"; - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond("application/json", response); + // Use the generic to get it as an ApiResponse of string + var resp = await fixture.GetQuery1>(myParams); + Assert.Equal(response, resp.Content); - var myParams = new Dictionary - { - ["FirstName"] = "John", - ["LastName"] = "Rambo", - ["Address"] = new { Zip = 9999, Street = "HomeStreet 99" } - }; - - var fixture = RestService.For, int>>( - "https://httpbin.org", - settings - ); + mockHttp.VerifyNoOutstandingExpectation(); - // Use the generic to get it as an ApiResponse of string - var resp = await fixture.GetQuery1>(myParams); - Assert.Equal(response, resp.Content); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond("application/json", response); - mockHttp.VerifyNoOutstandingExpectation(); + // Get as string + var resp1 = await fixture.GetQuery1(myParams); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond("application/json", response); + Assert.Equal(response, resp1); - // Get as string - var resp1 = await fixture.GetQuery1(myParams); + mockHttp.VerifyNoOutstandingExpectation(); - Assert.Equal(response, resp1); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond("application/json", response); - mockHttp.VerifyNoOutstandingExpectation(); + var resp2 = await fixture.GetQuery1(myParams); + Assert.Equal(4, resp2); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond("application/json", response); + mockHttp.VerifyNoOutstandingExpectation(); + } - var resp2 = await fixture.GetQuery1(myParams); - Assert.Equal(4, resp2); + [Fact] + public async Task InheritedMethodTest() + { + var mockHttp = new MockHttpMessageHandler(); + + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + + var fixture = RestService.For("https://httpbin.org", settings); + + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond("application/json", nameof(IAmInterfaceA.Ping)); + var resp = await fixture.Ping(); + Assert.Equal(nameof(IAmInterfaceA.Ping), resp); + mockHttp.VerifyNoOutstandingExpectation(); + + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond("application/json", nameof(IAmInterfaceB.Pong)); + resp = await fixture.Pong(); + Assert.Equal(nameof(IAmInterfaceB.Pong), resp); + mockHttp.VerifyNoOutstandingExpectation(); + + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond("application/json", nameof(IAmInterfaceC.Pang)); + resp = await fixture.Pang(); + Assert.Equal(nameof(IAmInterfaceC.Pang), resp); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.VerifyNoOutstandingExpectation(); - } + [Fact] + public async Task InheritedInterfaceWithOnlyBaseMethodsTest() + { + var mockHttp = new MockHttpMessageHandler(); - [Fact] - public async Task InheritedMethodTest() - { - var mockHttp = new MockHttpMessageHandler(); - - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - - var fixture = RestService.For("https://httpbin.org", settings); - - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond("application/json", nameof(IAmInterfaceA.Ping)); - var resp = await fixture.Ping(); - Assert.Equal(nameof(IAmInterfaceA.Ping), resp); - mockHttp.VerifyNoOutstandingExpectation(); - - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond("application/json", nameof(IAmInterfaceB.Pong)); - resp = await fixture.Pong(); - Assert.Equal(nameof(IAmInterfaceB.Pong), resp); - mockHttp.VerifyNoOutstandingExpectation(); - - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond("application/json", nameof(IAmInterfaceC.Pang)); - resp = await fixture.Pang(); - Assert.Equal(nameof(IAmInterfaceC.Pang), resp); - mockHttp.VerifyNoOutstandingExpectation(); - } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task InheritedInterfaceWithOnlyBaseMethodsTest() - { - var mockHttp = new MockHttpMessageHandler(); + var fixture = RestService.For("https://httpbin.org", settings); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond("application/json", nameof(IAmInterfaceA.Ping)); + var resp = await fixture.Ping(); + Assert.Equal(nameof(IAmInterfaceA.Ping), resp); + mockHttp.VerifyNoOutstandingExpectation(); - var fixture = RestService.For("https://httpbin.org", settings); + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond("application/json", nameof(IAmInterfaceB.Pong)); + resp = await fixture.Pong(); + Assert.Equal(nameof(IAmInterfaceB.Pong), resp); + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond("application/json", nameof(IAmInterfaceA.Ping)); - var resp = await fixture.Ping(); - Assert.Equal(nameof(IAmInterfaceA.Ping), resp); - mockHttp.VerifyNoOutstandingExpectation(); + [Fact] + public async Task InheritedInterfaceWithoutRefitInBaseMethodsTest() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond("application/json", nameof(IAmInterfaceB.Pong)); - resp = await fixture.Pong(); - Assert.Equal(nameof(IAmInterfaceB.Pong), resp); - mockHttp.VerifyNoOutstandingExpectation(); - } + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - [Fact] - public async Task InheritedInterfaceWithoutRefitInBaseMethodsTest() - { - var mockHttp = new MockHttpMessageHandler(); + var fixture = RestService.For( + "https://httpbin.org", + settings + ); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/doSomething") + .WithQueryString("parameter", "4") + .Respond("application/json", nameof(IImplementTheInterfaceAndUseRefit.DoSomething)); - var fixture = RestService.For( - "https://httpbin.org", - settings - ); + await fixture.DoSomething(4); + mockHttp.VerifyNoOutstandingExpectation(); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/doSomething") - .WithQueryString("parameter", "4") - .Respond("application/json", nameof(IImplementTheInterfaceAndUseRefit.DoSomething)); - - await fixture.DoSomething(4); - mockHttp.VerifyNoOutstandingExpectation(); - - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/DoSomethingElse") - .Respond( - "application/json", - nameof(IImplementTheInterfaceAndUseRefit.DoSomethingElse) - ); - await fixture.DoSomethingElse(); - mockHttp.VerifyNoOutstandingExpectation(); - - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/DoSomethingElse") - .Respond( - "application/json", - nameof(IImplementTheInterfaceAndUseRefit.DoSomethingElse) - ); - await ((IAmInterfaceEWithNoRefit)fixture).DoSomethingElse(); - mockHttp.VerifyNoOutstandingExpectation(); - - Assert.Throws( - () => RestService.For>("https://httpbin.org") + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/DoSomethingElse") + .Respond( + "application/json", + nameof(IImplementTheInterfaceAndUseRefit.DoSomethingElse) ); - } + await fixture.DoSomethingElse(); + mockHttp.VerifyNoOutstandingExpectation(); + + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/DoSomethingElse") + .Respond( + "application/json", + nameof(IImplementTheInterfaceAndUseRefit.DoSomethingElse) + ); + await ((IAmInterfaceEWithNoRefit)fixture).DoSomethingElse(); + mockHttp.VerifyNoOutstandingExpectation(); - [Fact] - public async Task DictionaryDynamicQueryparametersTest() - { - var mockHttp = new MockHttpMessageHandler(); + Assert.Throws( + () => RestService.For>("https://httpbin.org") + ); + } - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + [Fact] + public async Task DictionaryDynamicQueryparametersTest() + { + var mockHttp = new MockHttpMessageHandler(); - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond( - "application/json", - "{\"url\": \"https://httpbin.org/get?hardcoded=true&FirstName=John&LastName=Rambo&Address_Zip=9999&Address_Street=HomeStreet 99\", \"args\": {\"Address_Street\": \"HomeStreet 99\",\"Address_Zip\": \"9999\",\"FirstName\": \"John\",\"LastName\": \"Rambo\",\"hardcoded\": \"true\"}}" - ); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var myParams = new Dictionary - { - ["FirstName"] = "John", - ["LastName"] = "Rambo", - ["Address"] = new { Zip = 9999, Street = "HomeStreet 99" } - }; - - var fixture = RestService.For, int>>( - "https://httpbin.org", - settings + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond( + "application/json", + "{\"url\": \"https://httpbin.org/get?hardcoded=true&FirstName=John&LastName=Rambo&Address_Zip=9999&Address_Street=HomeStreet 99\", \"args\": {\"Address_Street\": \"HomeStreet 99\",\"Address_Zip\": \"9999\",\"FirstName\": \"John\",\"LastName\": \"Rambo\",\"hardcoded\": \"true\"}}" ); - var resp = await fixture.GetQuery(myParams); + var myParams = new Dictionary + { + ["FirstName"] = "John", + ["LastName"] = "Rambo", + ["Address"] = new { Zip = 9999, Street = "HomeStreet 99" } + }; - Assert.Equal("John", resp.Args["FirstName"]); - Assert.Equal("Rambo", resp.Args["LastName"]); - Assert.Equal("9999", resp.Args["Address_Zip"]); - } + var fixture = RestService.For, int>>( + "https://httpbin.org", + settings + ); - [Fact] - public async Task ComplexDynamicQueryparametersTestWithIncludeParameterName() - { - var mockHttp = new MockHttpMessageHandler(); + var resp = await fixture.GetQuery(myParams); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + Assert.Equal("John", resp.Args["FirstName"]); + Assert.Equal("Rambo", resp.Args["LastName"]); + Assert.Equal("9999", resp.Args["Address_Zip"]); + } - mockHttp - .Expect(HttpMethod.Get, "https://httpbin.org/get") - .Respond( - "application/json", - "{\"url\": \"https://httpbin.org/get?search.FirstName=John&search.LastName=Rambo&search.Addr.Zip=9999&search.Addr.Street=HomeStreet 99\", \"args\": {\"search.Addr.Street\": \"HomeStreet 99\",\"search.Addr.Zip\": \"9999\",\"search.FirstName\": \"John\",\"search.LastName\": \"Rambo\"}}" - ); + [Fact] + public async Task ComplexDynamicQueryparametersTestWithIncludeParameterName() + { + var mockHttp = new MockHttpMessageHandler(); - var myParams = new MyComplexQueryParams { FirstName = "John", LastName = "Rambo" }; - myParams.Address.Postcode = 9999; - myParams.Address.Street = "HomeStreet 99"; + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For>( - "https://httpbin.org/get", - settings + mockHttp + .Expect(HttpMethod.Get, "https://httpbin.org/get") + .Respond( + "application/json", + "{\"url\": \"https://httpbin.org/get?search.FirstName=John&search.LastName=Rambo&search.Addr.Zip=9999&search.Addr.Street=HomeStreet 99\", \"args\": {\"search.Addr.Street\": \"HomeStreet 99\",\"search.Addr.Zip\": \"9999\",\"search.FirstName\": \"John\",\"search.LastName\": \"Rambo\"}}" ); - var resp = await fixture.GetQueryWithIncludeParameterName(myParams); + var myParams = new MyComplexQueryParams { FirstName = "John", LastName = "Rambo" }; + myParams.Address.Postcode = 9999; + myParams.Address.Street = "HomeStreet 99"; - Assert.Equal("John", resp.Args["search.FirstName"]); - Assert.Equal("Rambo", resp.Args["search.LastName"]); - Assert.Equal("9999", resp.Args["search.Addr.Zip"]); - } + var fixture = RestService.For>( + "https://httpbin.org/get", + settings + ); - [Fact] - public async Task ServiceOutsideNamespaceGetRequest() - { - var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + var resp = await fixture.GetQueryWithIncludeParameterName(myParams); + + Assert.Equal("John", resp.Args["search.FirstName"]); + Assert.Equal("Rambo", resp.Args["search.LastName"]); + Assert.Equal("9999", resp.Args["search.Addr.Zip"]); + } - mockHttp - .Expect(HttpMethod.Get, "http://foo/") - // We can't add HttpContent to a GET request, - // because HttpClient doesn't allow it and it will - // blow up at runtime - .With(r => r.Content == null) - .Respond("application/json", "Ok"); + [Fact] + public async Task ServiceOutsideNamespaceGetRequest() + { + var mockHttp = new MockHttpMessageHandler(); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); + mockHttp + .Expect(HttpMethod.Get, "http://foo/") + // We can't add HttpContent to a GET request, + // because HttpClient doesn't allow it and it will + // blow up at runtime + .With(r => r.Content == null) + .Respond("application/json", "Ok"); - await fixture.GetRoot(); + var fixture = RestService.For("http://foo", settings); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.GetRoot(); - [Fact] - public async Task ServiceOutsideNamespacePostRequest() - { - var mockHttp = new MockHttpMessageHandler(); - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; + mockHttp.VerifyNoOutstandingExpectation(); + } - mockHttp.Expect(HttpMethod.Post, "http://foo/").Respond("application/json", "Ok"); + [Fact] + public async Task ServiceOutsideNamespacePostRequest() + { + var mockHttp = new MockHttpMessageHandler(); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp }; - var fixture = RestService.For("http://foo", settings); + mockHttp.Expect(HttpMethod.Post, "http://foo/").Respond("application/json", "Ok"); - await fixture.PostRoot(); + var fixture = RestService.For("http://foo", settings); - mockHttp.VerifyNoOutstandingExpectation(); - } + await fixture.PostRoot(); - [Fact] - public async Task CanSerializeContentAsXml() - { - var mockHttp = new MockHttpMessageHandler(); - var contentSerializer = new XmlContentSerializer(); - var settings = new RefitSettings - { - HttpMessageHandlerFactory = () => mockHttp, - ContentSerializer = contentSerializer - }; - - mockHttp - .Expect(HttpMethod.Post, "/users") - .WithHeaders("Content-Type:application/xml; charset=utf-8") - .Respond( - req => - new HttpResponseMessage(HttpStatusCode.OK) - { - Content = new StringContent( - "Created", - Encoding.UTF8, - "application/xml" - ) - } - ); + mockHttp.VerifyNoOutstandingExpectation(); + } - var fixture = RestService.For("https://api.github.com", settings); + [Fact] + public async Task CanSerializeContentAsXml() + { + var mockHttp = new MockHttpMessageHandler(); + var contentSerializer = new XmlContentSerializer(); + var settings = new RefitSettings + { + HttpMessageHandlerFactory = () => mockHttp, + ContentSerializer = contentSerializer + }; + + mockHttp + .Expect(HttpMethod.Post, "/users") + .WithHeaders("Content-Type:application/xml; charset=utf-8") + .Respond( + req => + new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent( + "Created", + Encoding.UTF8, + "application/xml" + ) + } + ); - var result = await fixture.CreateUser(new User()).ConfigureAwait(false); + var fixture = RestService.For("https://api.github.com", settings); - Assert.Equal("Created", result.Name); + var result = await fixture.CreateUser(new User()).ConfigureAwait(false); - mockHttp.VerifyNoOutstandingExpectation(); - } + Assert.Equal("Created", result.Name); - [Fact] - public void ShouldTrimTrailingForwardSlashFromBaseUrl() - { - var expectedBaseAddress = "http://example.com/api"; - var inputBaseAddress = "http://example.com/api/"; + mockHttp.VerifyNoOutstandingExpectation(); + } - var fixture = RestService.For(inputBaseAddress); + [Fact] + public void ShouldTrimTrailingForwardSlashFromBaseUrl() + { + var expectedBaseAddress = "http://example.com/api"; + var inputBaseAddress = "http://example.com/api/"; - Assert.Equal(fixture.Client.BaseAddress.AbsoluteUri, expectedBaseAddress); - } + var fixture = RestService.For(inputBaseAddress); - [Fact] - public void ShouldThrowArgumentExceptionIfHostUrlIsNull() - { - try - { - RestService.For(hostUrl: null); - } - catch (ArgumentException ex) - { - Assert.Equal("hostUrl", ex.ParamName); - return; - } + Assert.Equal(fixture.Client.BaseAddress.AbsoluteUri, expectedBaseAddress); + } - Assert.Fail("Exception not thrown."); + [Fact] + public void ShouldThrowArgumentExceptionIfHostUrlIsNull() + { + try + { + RestService.For(hostUrl: null); } - - [Fact] - public void ShouldThrowArgumentExceptionIfHostUrlIsEmpty() + catch (ArgumentException ex) { - try - { - RestService.For(hostUrl: ""); - } - catch (ArgumentException ex) - { - Assert.Equal("hostUrl", ex.ParamName); - return; - } - - Assert.Fail("Exception not thrown."); + Assert.Equal("hostUrl", ex.ParamName); + return; } - [Fact] - public void ShouldThrowArgumentExceptionIfHostUrlIsWhitespace() - { - try - { - RestService.For(hostUrl: " "); - } - catch (ArgumentException ex) - { - Assert.Equal("hostUrl", ex.ParamName); - return; - } + Assert.Fail("Exception not thrown."); + } - Assert.Fail("Exception not thrown."); + [Fact] + public void ShouldThrowArgumentExceptionIfHostUrlIsEmpty() + { + try + { + RestService.For(hostUrl: ""); } - - [Fact] - public void NonGenericCreate() + catch (ArgumentException ex) { - var expectedBaseAddress = "http://example.com/api"; - var inputBaseAddress = "http://example.com/api/"; + Assert.Equal("hostUrl", ex.ParamName); + return; + } - var fixture = - RestService.For(typeof(ITrimTrailingForwardSlashApi), inputBaseAddress) - as ITrimTrailingForwardSlashApi; + Assert.Fail("Exception not thrown."); + } - Assert.Equal(fixture.Client.BaseAddress.AbsoluteUri, expectedBaseAddress); + [Fact] + public void ShouldThrowArgumentExceptionIfHostUrlIsWhitespace() + { + try + { + RestService.For(hostUrl: " "); } - - [Fact] - public async Task TypeCollisionTest() + catch (ArgumentException ex) { - var mockHttp = new MockHttpMessageHandler(); + Assert.Equal("hostUrl", ex.ParamName); + return; + } - var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp, }; + Assert.Fail("Exception not thrown."); + } - const string Url = "https://httpbin.org/get"; + [Fact] + public void NonGenericCreate() + { + var expectedBaseAddress = "http://example.com/api"; + var inputBaseAddress = "http://example.com/api/"; - mockHttp.Expect(HttpMethod.Get, Url).Respond("application/json", "{ }"); + var fixture = + RestService.For(typeof(ITrimTrailingForwardSlashApi), inputBaseAddress) + as ITrimTrailingForwardSlashApi; - var fixtureA = RestService.For(Url); + Assert.Equal(fixture.Client.BaseAddress.AbsoluteUri, expectedBaseAddress); + } - var respA = await fixtureA.SomeARequest(); + [Fact] + public async Task TypeCollisionTest() + { + var mockHttp = new MockHttpMessageHandler(); - var fixtureB = RestService.For(Url); + var settings = new RefitSettings { HttpMessageHandlerFactory = () => mockHttp, }; - var respB = await fixtureB.SomeBRequest(); + const string Url = "https://httpbin.org/get"; - Assert.IsType(respA); - Assert.IsType(respB); - } + mockHttp.Expect(HttpMethod.Get, Url).Respond("application/json", "{ }"); - internal static Stream GetTestFileStream(string relativeFilePath) - { - const char namespaceSeparator = '.'; - - // get calling assembly - var assembly = Assembly.GetCallingAssembly(); - - // compute resource name suffix - var relativeName = - "." - + relativeFilePath - .Replace('\\', namespaceSeparator) - .Replace('/', namespaceSeparator) - .Replace(' ', '_'); - - // get resource stream - var fullName = assembly - .GetManifestResourceNames() - .FirstOrDefault( - name => name.EndsWith(relativeName, StringComparison.InvariantCulture) - ); - if (fullName == null) - { - throw new Exception( - $"Unable to find resource for path \"{relativeFilePath}\". Resource with name ending on \"{relativeName}\" was not found in assembly." - ); - } + var fixtureA = RestService.For(Url); - var stream = assembly.GetManifestResourceStream(fullName); - if (stream == null) - { - throw new Exception( - $"Unable to find resource for path \"{relativeFilePath}\". Resource named \"{fullName}\" was not found in assembly." - ); - } + var respA = await fixtureA.SomeARequest(); + + var fixtureB = RestService.For(Url); - return stream; + var respB = await fixtureB.SomeBRequest(); + + Assert.IsType(respA); + Assert.IsType(respB); + } + + internal static Stream GetTestFileStream(string relativeFilePath) + { + const char namespaceSeparator = '.'; + + // get calling assembly + var assembly = Assembly.GetCallingAssembly(); + + // compute resource name suffix + var relativeName = + "." + + relativeFilePath + .Replace('\\', namespaceSeparator) + .Replace('/', namespaceSeparator) + .Replace(' ', '_'); + + // get resource stream + var fullName = assembly + .GetManifestResourceNames() + .FirstOrDefault( + name => name.EndsWith(relativeName, StringComparison.InvariantCulture) + ); + if (fullName == null) + { + throw new Exception( + $"Unable to find resource for path \"{relativeFilePath}\". Resource with name ending on \"{relativeName}\" was not found in assembly." + ); } - public void AssertFirstLineContains(string expectedSubstring, string actualString) + var stream = assembly.GetManifestResourceStream(fullName); + if (stream == null) { - var eolIndex = actualString.IndexOf('\n'); - var firstLine = eolIndex < 0 ? actualString : actualString.Substring(0, eolIndex); - Assert.Contains(expectedSubstring, firstLine); + throw new Exception( + $"Unable to find resource for path \"{relativeFilePath}\". Resource named \"{fullName}\" was not found in assembly." + ); } + + return stream; + } + + public void AssertFirstLineContains(string expectedSubstring, string actualString) + { + var eolIndex = actualString.IndexOf('\n'); + var firstLine = eolIndex < 0 ? actualString : actualString.Substring(0, eolIndex); + Assert.Contains(expectedSubstring, firstLine); } } diff --git a/Refit.Tests/SerializedContentTests.cs b/Refit.Tests/SerializedContentTests.cs index 7dbc1c065..a4b190d70 100644 --- a/Refit.Tests/SerializedContentTests.cs +++ b/Refit.Tests/SerializedContentTests.cs @@ -5,186 +5,185 @@ using Xunit; using System.Threading; -namespace Refit.Tests +namespace Refit.Tests; + +public class SerializedContentTests { - public class SerializedContentTests + const string BaseAddress = "https://api/"; + + [Theory] + [InlineData(typeof(NewtonsoftJsonContentSerializer))] + [InlineData(typeof(SystemTextJsonContentSerializer))] + [InlineData(typeof(XmlContentSerializer))] + public async Task WhenARequestRequiresABodyThenItDoesNotDeadlock(Type contentSerializerType) { - const string BaseAddress = "https://api/"; + if ( + Activator.CreateInstance(contentSerializerType) + is not IHttpContentSerializer serializer + ) + { + throw new ArgumentException( + $"{contentSerializerType.FullName} does not implement {nameof(IHttpContentSerializer)}" + ); + } - [Theory] - [InlineData(typeof(NewtonsoftJsonContentSerializer))] - [InlineData(typeof(SystemTextJsonContentSerializer))] - [InlineData(typeof(XmlContentSerializer))] - public async Task WhenARequestRequiresABodyThenItDoesNotDeadlock(Type contentSerializerType) + var handler = new MockPushStreamContentHttpMessageHandler { - if ( - Activator.CreateInstance(contentSerializerType) - is not IHttpContentSerializer serializer - ) - { - throw new ArgumentException( - $"{contentSerializerType.FullName} does not implement {nameof(IHttpContentSerializer)}" - ); - } + Asserts = async content => + new StringContent(await content.ReadAsStringAsync().ConfigureAwait(false)) + }; - var handler = new MockPushStreamContentHttpMessageHandler - { - Asserts = async content => - new StringContent(await content.ReadAsStringAsync().ConfigureAwait(false)) - }; + var settings = new RefitSettings(serializer) + { + HttpMessageHandlerFactory = () => handler + }; - var settings = new RefitSettings(serializer) - { - HttpMessageHandlerFactory = () => handler - }; + var fixture = RestService.For(BaseAddress, settings); - var fixture = RestService.For(BaseAddress, settings); + var fixtureTask = await RunTaskWithATimeLimit(fixture.CreateUser(new User())) + .ConfigureAwait(false); + Assert.True(fixtureTask.IsCompleted); + Assert.Equal(TaskStatus.RanToCompletion, fixtureTask.Status); + } - var fixtureTask = await RunTaskWithATimeLimit(fixture.CreateUser(new User())) - .ConfigureAwait(false); - Assert.True(fixtureTask.IsCompleted); - Assert.Equal(TaskStatus.RanToCompletion, fixtureTask.Status); + [Theory] + [InlineData(typeof(NewtonsoftJsonContentSerializer))] + [InlineData(typeof(SystemTextJsonContentSerializer))] + [InlineData(typeof(XmlContentSerializer))] + public async Task WhenARequestRequiresABodyThenItIsSerialized(Type contentSerializerType) + { + if ( + Activator.CreateInstance(contentSerializerType) + is not IHttpContentSerializer serializer + ) + { + throw new ArgumentException( + $"{contentSerializerType.FullName} does not implement {nameof(IHttpContentSerializer)}" + ); } - [Theory] - [InlineData(typeof(NewtonsoftJsonContentSerializer))] - [InlineData(typeof(SystemTextJsonContentSerializer))] - [InlineData(typeof(XmlContentSerializer))] - public async Task WhenARequestRequiresABodyThenItIsSerialized(Type contentSerializerType) + var model = new User { - if ( - Activator.CreateInstance(contentSerializerType) - is not IHttpContentSerializer serializer - ) + Name = "Wile E. Coyote", + CreatedAt = new DateTime(1949, 9, 16).ToString(), + Company = "ACME", + }; + + var handler = new MockPushStreamContentHttpMessageHandler + { + Asserts = async content => { - throw new ArgumentException( - $"{contentSerializerType.FullName} does not implement {nameof(IHttpContentSerializer)}" + var stringContent = new StringContent( + await content.ReadAsStringAsync().ConfigureAwait(false) ); + var user = await serializer + .FromHttpContentAsync(content) + .ConfigureAwait(false); + Assert.NotSame(model, user); + Assert.Equal(model.Name, user.Name); + Assert.Equal(model.CreatedAt, user.CreatedAt); + Assert.Equal(model.Company, user.Company); + + // return some content so that the serializer doesn't complain + return stringContent; } + }; - var model = new User - { - Name = "Wile E. Coyote", - CreatedAt = new DateTime(1949, 9, 16).ToString(), - Company = "ACME", - }; + var settings = new RefitSettings(serializer) + { + HttpMessageHandlerFactory = () => handler + }; - var handler = new MockPushStreamContentHttpMessageHandler - { - Asserts = async content => - { - var stringContent = new StringContent( - await content.ReadAsStringAsync().ConfigureAwait(false) - ); - var user = await serializer - .FromHttpContentAsync(content) - .ConfigureAwait(false); - Assert.NotSame(model, user); - Assert.Equal(model.Name, user.Name); - Assert.Equal(model.CreatedAt, user.CreatedAt); - Assert.Equal(model.Company, user.Company); - - // return some content so that the serializer doesn't complain - return stringContent; - } - }; - - var settings = new RefitSettings(serializer) - { - HttpMessageHandlerFactory = () => handler - }; + var fixture = RestService.For(BaseAddress, settings); - var fixture = RestService.For(BaseAddress, settings); + var fixtureTask = await RunTaskWithATimeLimit(fixture.CreateUser(model)) + .ConfigureAwait(false); - var fixtureTask = await RunTaskWithATimeLimit(fixture.CreateUser(model)) - .ConfigureAwait(false); + Assert.True(fixtureTask.IsCompleted); + } - Assert.True(fixtureTask.IsCompleted); - } + [Fact] + public void VerityDefaultSerializer() + { + var settings = new RefitSettings(); - [Fact] - public void VerityDefaultSerializer() - { - var settings = new RefitSettings(); + Assert.NotNull(settings.ContentSerializer); + Assert.IsType(settings.ContentSerializer); - Assert.NotNull(settings.ContentSerializer); - Assert.IsType(settings.ContentSerializer); + settings = new RefitSettings(new NewtonsoftJsonContentSerializer()); - settings = new RefitSettings(new NewtonsoftJsonContentSerializer()); + Assert.NotNull(settings.ContentSerializer); + Assert.IsType(settings.ContentSerializer); + } - Assert.NotNull(settings.ContentSerializer); - Assert.IsType(settings.ContentSerializer); - } + /// + /// Runs the task to completion or until the timeout occurs + /// + static async Task> RunTaskWithATimeLimit(Task fixtureTask) + { + var circuitBreakerTask = Task.Delay(TimeSpan.FromSeconds(30)); + await Task.WhenAny(fixtureTask, circuitBreakerTask); + return fixtureTask; + } - /// - /// Runs the task to completion or until the timeout occurs - /// - static async Task> RunTaskWithATimeLimit(Task fixtureTask) - { - var circuitBreakerTask = Task.Delay(TimeSpan.FromSeconds(30)); - await Task.WhenAny(fixtureTask, circuitBreakerTask); - return fixtureTask; - } + class MockPushStreamContentHttpMessageHandler : HttpMessageHandler + { + public Func> Asserts { get; set; } - class MockPushStreamContentHttpMessageHandler : HttpMessageHandler + protected override async Task SendAsync( + HttpRequestMessage request, + CancellationToken cancellationToken + ) { - public Func> Asserts { get; set; } - - protected override async Task SendAsync( - HttpRequestMessage request, - CancellationToken cancellationToken - ) - { - var content = request.Content as PushStreamContent; - Assert.IsType(content); - Assert.NotNull(Asserts); + var content = request.Content as PushStreamContent; + Assert.IsType(content); + Assert.NotNull(Asserts); - var responseContent = await Asserts(content).ConfigureAwait(false); + var responseContent = await Asserts(content).ConfigureAwait(false); - return new HttpResponseMessage(HttpStatusCode.OK) { Content = responseContent }; - } + return new HttpResponseMessage(HttpStatusCode.OK) { Content = responseContent }; } + } - [Fact] - public async Task StreamDeserialization_UsingSystemTextJsonContentSerializer() + [Fact] + public async Task StreamDeserialization_UsingSystemTextJsonContentSerializer() + { + var model = new TestAliasObject { - var model = new TestAliasObject - { - ShortNameForAlias = nameof( - StreamDeserialization_UsingSystemTextJsonContentSerializer - ), - ShortNameForJsonProperty = nameof(TestAliasObject) - }; + ShortNameForAlias = nameof( + StreamDeserialization_UsingSystemTextJsonContentSerializer + ), + ShortNameForJsonProperty = nameof(TestAliasObject) + }; - var serializer = new SystemTextJsonContentSerializer(); + var serializer = new SystemTextJsonContentSerializer(); - var json = serializer.ToHttpContent(model); + var json = serializer.ToHttpContent(model); - var result = await serializer.FromHttpContentAsync(json); + var result = await serializer.FromHttpContentAsync(json); - Assert.NotNull(result); - Assert.Equal(model.ShortNameForAlias, result.ShortNameForAlias); - Assert.Equal(model.ShortNameForJsonProperty, result.ShortNameForJsonProperty); - } + Assert.NotNull(result); + Assert.Equal(model.ShortNameForAlias, result.ShortNameForAlias); + Assert.Equal(model.ShortNameForJsonProperty, result.ShortNameForJsonProperty); + } - [Fact] - public void StreamDeserialization_UsingSystemTextJsonContentSerializer_SetsCorrectHeaders() + [Fact] + public void StreamDeserialization_UsingSystemTextJsonContentSerializer_SetsCorrectHeaders() + { + var model = new TestAliasObject { - var model = new TestAliasObject - { - ShortNameForAlias = nameof( - StreamDeserialization_UsingSystemTextJsonContentSerializer - ), - ShortNameForJsonProperty = nameof(TestAliasObject) - }; + ShortNameForAlias = nameof( + StreamDeserialization_UsingSystemTextJsonContentSerializer + ), + ShortNameForJsonProperty = nameof(TestAliasObject) + }; - var serializer = new SystemTextJsonContentSerializer(); + var serializer = new SystemTextJsonContentSerializer(); - var json = serializer.ToHttpContent(model); + var json = serializer.ToHttpContent(model); - Assert.NotNull(json.Headers.ContentType); - Assert.Equal("utf-8", json.Headers.ContentType.CharSet); - Assert.Equal("application/json", json.Headers.ContentType.MediaType); - } + Assert.NotNull(json.Headers.ContentType); + Assert.Equal("utf-8", json.Headers.ContentType.CharSet); + Assert.Equal("application/json", json.Headers.ContentType.MediaType); } } diff --git a/Refit.Tests/TypeCollisionApiA.cs b/Refit.Tests/TypeCollisionApiA.cs index 157b7f0aa..119a8e9fd 100644 --- a/Refit.Tests/TypeCollisionApiA.cs +++ b/Refit.Tests/TypeCollisionApiA.cs @@ -4,19 +4,18 @@ using Refit; // InterfaceStubGenerator looks for this -namespace Refit.Tests +namespace Refit.Tests; + +public interface ITypeCollisionApiA { - public interface ITypeCollisionApiA - { - [Get("")] - Task SomeARequest(); - } + [Get("")] + Task SomeARequest(); +} - public static class TypeCollisionApiA +public static class TypeCollisionApiA +{ + public static ITypeCollisionApiA Create() { - public static ITypeCollisionApiA Create() - { - return RestService.For("http://somewhere.com"); - } + return RestService.For("http://somewhere.com"); } } diff --git a/Refit.Tests/TypeCollisionApiB.cs b/Refit.Tests/TypeCollisionApiB.cs index fbf70cac5..e7407d317 100644 --- a/Refit.Tests/TypeCollisionApiB.cs +++ b/Refit.Tests/TypeCollisionApiB.cs @@ -4,19 +4,18 @@ using Refit; // InterfaceStubGenerator looks for this -namespace Refit.Tests +namespace Refit.Tests; + +public interface ITypeCollisionApiB { - public interface ITypeCollisionApiB - { - [Get("")] - Task SomeBRequest(); - } + [Get("")] + Task SomeBRequest(); +} - public static class TypeCollisionApiB +public static class TypeCollisionApiB +{ + public static ITypeCollisionApiB Create() { - public static ITypeCollisionApiB Create() - { - return RestService.For("http://somewhere.com"); - } + return RestService.For("http://somewhere.com"); } } diff --git a/Refit.Tests/UseCultureAttribute.cs b/Refit.Tests/UseCultureAttribute.cs index d45fd0f31..11ab638ac 100644 --- a/Refit.Tests/UseCultureAttribute.cs +++ b/Refit.Tests/UseCultureAttribute.cs @@ -6,92 +6,91 @@ using System.Threading; using Xunit.Sdk; -namespace Refit.Tests +namespace Refit.Tests; + +/// +/// Apply this attribute to your test method to replace the +/// and +/// with another culture. +/// +[AttributeUsage( + AttributeTargets.Class | AttributeTargets.Method, + AllowMultiple = false, + Inherited = true +)] +public class UseCultureAttribute : BeforeAfterTestAttribute { - /// - /// Apply this attribute to your test method to replace the - /// and - /// with another culture. - /// - [AttributeUsage( - AttributeTargets.Class | AttributeTargets.Method, - AllowMultiple = false, - Inherited = true - )] - public class UseCultureAttribute : BeforeAfterTestAttribute - { - readonly Lazy culture; - readonly Lazy uiCulture; + readonly Lazy culture; + readonly Lazy uiCulture; - CultureInfo originalCulture; - CultureInfo originalUICulture; + CultureInfo originalCulture; + CultureInfo originalUICulture; - /// - /// Replaces the culture and UI culture of the current thread with - /// - /// - /// The name of the culture. - /// - /// - /// This constructor overload uses for both - /// and . - /// - /// - public UseCultureAttribute(string culture) - : this(culture, culture) { } + /// + /// Replaces the culture and UI culture of the current thread with + /// + /// + /// The name of the culture. + /// + /// + /// This constructor overload uses for both + /// and . + /// + /// + public UseCultureAttribute(string culture) + : this(culture, culture) { } - /// - /// Replaces the culture and UI culture of the current thread with - /// and - /// - /// The name of the culture. - /// The name of the UI culture. - public UseCultureAttribute(string culture, string uiCulture) - { - this.culture = new Lazy(() => new CultureInfo(culture)); - this.uiCulture = new Lazy(() => new CultureInfo(uiCulture)); - } + /// + /// Replaces the culture and UI culture of the current thread with + /// and + /// + /// The name of the culture. + /// The name of the UI culture. + public UseCultureAttribute(string culture, string uiCulture) + { + this.culture = new Lazy(() => new CultureInfo(culture)); + this.uiCulture = new Lazy(() => new CultureInfo(uiCulture)); + } - /// - /// Gets the culture. - /// - public CultureInfo Culture - { - get { return culture.Value; } - } + /// + /// Gets the culture. + /// + public CultureInfo Culture + { + get { return culture.Value; } + } - /// - /// Gets the UI culture. - /// - public CultureInfo UICulture - { - get { return uiCulture.Value; } - } + /// + /// Gets the UI culture. + /// + public CultureInfo UICulture + { + get { return uiCulture.Value; } + } - /// - /// Stores the current - /// and - /// and replaces them with the new cultures defined in the constructor. - /// - /// The method under test - public override void Before(MethodInfo methodUnderTest) - { - originalCulture = CultureInfo.CurrentCulture; - originalUICulture = CultureInfo.CurrentUICulture; + /// + /// Stores the current + /// and + /// and replaces them with the new cultures defined in the constructor. + /// + /// The method under test + public override void Before(MethodInfo methodUnderTest) + { + originalCulture = CultureInfo.CurrentCulture; + originalUICulture = CultureInfo.CurrentUICulture; - CultureInfo.CurrentCulture = Culture; - CultureInfo.CurrentUICulture = UICulture; - } + CultureInfo.CurrentCulture = Culture; + CultureInfo.CurrentUICulture = UICulture; + } - /// - /// Restores the original and - /// to - /// - /// The method under test - public override void After(MethodInfo methodUnderTest) - { - CultureInfo.CurrentCulture = originalCulture; - CultureInfo.CurrentUICulture = originalUICulture; - } + /// + /// Restores the original and + /// to + /// + /// The method under test + public override void After(MethodInfo methodUnderTest) + { + CultureInfo.CurrentCulture = originalCulture; + CultureInfo.CurrentUICulture = originalUICulture; } } diff --git a/Refit.Tests/Verifiers/CSharpIncrementalSourceGeneratorVerifier`1+Test.cs b/Refit.Tests/Verifiers/CSharpIncrementalSourceGeneratorVerifier`1+Test.cs index 2e490360f..4c35e0002 100644 --- a/Refit.Tests/Verifiers/CSharpIncrementalSourceGeneratorVerifier`1+Test.cs +++ b/Refit.Tests/Verifiers/CSharpIncrementalSourceGeneratorVerifier`1+Test.cs @@ -5,52 +5,51 @@ using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Testing; -namespace Refit.Tests +namespace Refit.Tests; + +public static partial class CSharpIncrementalSourceGeneratorVerifier + where TIncrementalGenerator : IIncrementalGenerator, new() { - public static partial class CSharpIncrementalSourceGeneratorVerifier - where TIncrementalGenerator : IIncrementalGenerator, new() + public class Test : CSharpSourceGeneratorTest { - public class Test : CSharpSourceGeneratorTest + public Test() { - public Test() - { - SolutionTransforms.Add( - (solution, projectId) => - { - var compilationOptions = solution.GetProject(projectId).CompilationOptions; - compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( - compilationOptions.SpecificDiagnosticOptions.SetItems( - CSharpVerifierHelper.NullableWarnings - ) - ); - solution = solution.WithProjectCompilationOptions( - projectId, - compilationOptions - ); + SolutionTransforms.Add( + (solution, projectId) => + { + var compilationOptions = solution.GetProject(projectId).CompilationOptions; + compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions.SetItems( + CSharpVerifierHelper.NullableWarnings + ) + ); + solution = solution.WithProjectCompilationOptions( + projectId, + compilationOptions + ); - return solution; - } - ); - } + return solution; + } + ); + } - /// - /// Gets the source generators. - /// - /// - protected override IEnumerable GetSourceGenerators() - { - yield return new TIncrementalGenerator().AsSourceGenerator().GetGeneratorType(); - } + /// + /// Gets the source generators. + /// + /// + protected override IEnumerable GetSourceGenerators() + { + yield return new TIncrementalGenerator().AsSourceGenerator().GetGeneratorType(); + } - /// - /// Creates the parse options. - /// - /// - protected override ParseOptions CreateParseOptions() - { - var parseOptions = (CSharpParseOptions)base.CreateParseOptions(); - return parseOptions.WithLanguageVersion(LanguageVersion.Preview); - } + /// + /// Creates the parse options. + /// + /// + protected override ParseOptions CreateParseOptions() + { + var parseOptions = (CSharpParseOptions)base.CreateParseOptions(); + return parseOptions.WithLanguageVersion(LanguageVersion.Preview); } } } diff --git a/Refit.Tests/Verifiers/CSharpIncrementalSourceGeneratorVerifier`1.cs b/Refit.Tests/Verifiers/CSharpIncrementalSourceGeneratorVerifier`1.cs index 068ecffde..ff0ba5a6f 100644 --- a/Refit.Tests/Verifiers/CSharpIncrementalSourceGeneratorVerifier`1.cs +++ b/Refit.Tests/Verifiers/CSharpIncrementalSourceGeneratorVerifier`1.cs @@ -1,7 +1,6 @@ using Microsoft.CodeAnalysis; -namespace Refit.Tests -{ - public static partial class CSharpIncrementalSourceGeneratorVerifier - where TIncrementalGenerator : IIncrementalGenerator, new() { } -} +namespace Refit.Tests; + +public static partial class CSharpIncrementalSourceGeneratorVerifier + where TIncrementalGenerator : IIncrementalGenerator, new(); diff --git a/Refit.Tests/Verifiers/CSharpSourceGeneratorVerifier`1+Test.cs b/Refit.Tests/Verifiers/CSharpSourceGeneratorVerifier`1+Test.cs index 3cc8ffe93..eefb94bcc 100644 --- a/Refit.Tests/Verifiers/CSharpSourceGeneratorVerifier`1+Test.cs +++ b/Refit.Tests/Verifiers/CSharpSourceGeneratorVerifier`1+Test.cs @@ -4,33 +4,32 @@ using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Testing; -namespace Refit.Tests +namespace Refit.Tests; + +public static partial class CSharpSourceGeneratorVerifier + where TSourceGenerator : ISourceGenerator, new() { - public static partial class CSharpSourceGeneratorVerifier - where TSourceGenerator : ISourceGenerator, new() + public class Test : CSharpSourceGeneratorTest { - public class Test : CSharpSourceGeneratorTest + public Test() { - public Test() - { - SolutionTransforms.Add( - (solution, projectId) => - { - var compilationOptions = solution.GetProject(projectId).CompilationOptions; - compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( - compilationOptions.SpecificDiagnosticOptions.SetItems( - CSharpVerifierHelper.NullableWarnings - ) - ); - solution = solution.WithProjectCompilationOptions( - projectId, - compilationOptions - ); + SolutionTransforms.Add( + (solution, projectId) => + { + var compilationOptions = solution.GetProject(projectId).CompilationOptions; + compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions.SetItems( + CSharpVerifierHelper.NullableWarnings + ) + ); + solution = solution.WithProjectCompilationOptions( + projectId, + compilationOptions + ); - return solution; - } - ); - } + return solution; + } + ); } } } diff --git a/Refit.Tests/Verifiers/CSharpSourceGeneratorVerifier`1.cs b/Refit.Tests/Verifiers/CSharpSourceGeneratorVerifier`1.cs index 3921a9722..4af99ba0d 100644 --- a/Refit.Tests/Verifiers/CSharpSourceGeneratorVerifier`1.cs +++ b/Refit.Tests/Verifiers/CSharpSourceGeneratorVerifier`1.cs @@ -1,7 +1,6 @@ using Microsoft.CodeAnalysis; -namespace Refit.Tests -{ - public static partial class CSharpSourceGeneratorVerifier - where TSourceGenerator : ISourceGenerator, new() { } -} +namespace Refit.Tests; + +public static partial class CSharpSourceGeneratorVerifier + where TSourceGenerator : ISourceGenerator, new(); diff --git a/Refit.Tests/Verifiers/CSharpVerifierHelper.cs b/Refit.Tests/Verifiers/CSharpVerifierHelper.cs index 5b0e3a1fa..f28f6cb67 100644 --- a/Refit.Tests/Verifiers/CSharpVerifierHelper.cs +++ b/Refit.Tests/Verifiers/CSharpVerifierHelper.cs @@ -4,29 +4,28 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; -namespace Refit.Tests +namespace Refit.Tests; + +static class CSharpVerifierHelper { - static class CSharpVerifierHelper - { - /// - /// By default, the compiler reports diagnostics for nullable reference types at - /// , and the analyzer test framework defaults to only validating - /// diagnostics at . This map contains all compiler diagnostic IDs - /// related to nullability mapped to , which is then used to enable all - /// of these warnings for default validation during analyzer and code fix tests. - /// - internal static ImmutableDictionary NullableWarnings { get; } = - GetNullableWarningsFromCompiler(); + /// + /// By default, the compiler reports diagnostics for nullable reference types at + /// , and the analyzer test framework defaults to only validating + /// diagnostics at . This map contains all compiler diagnostic IDs + /// related to nullability mapped to , which is then used to enable all + /// of these warnings for default validation during analyzer and code fix tests. + /// + internal static ImmutableDictionary NullableWarnings { get; } = + GetNullableWarningsFromCompiler(); - static ImmutableDictionary GetNullableWarningsFromCompiler() - { - string[] args = { "/warnaserror:nullable" }; - var commandLineArguments = CSharpCommandLineParser.Default.Parse( - args, - baseDirectory: Environment.CurrentDirectory, - sdkDirectory: Environment.CurrentDirectory - ); - return commandLineArguments.CompilationOptions.SpecificDiagnosticOptions; - } + static ImmutableDictionary GetNullableWarningsFromCompiler() + { + string[] args = { "/warnaserror:nullable" }; + var commandLineArguments = CSharpCommandLineParser.Default.Parse( + args, + baseDirectory: Environment.CurrentDirectory, + sdkDirectory: Environment.CurrentDirectory + ); + return commandLineArguments.CompilationOptions.SpecificDiagnosticOptions; } } diff --git a/Refit.Tests/XmlContentSerializerTests.cs b/Refit.Tests/XmlContentSerializerTests.cs index 6cc40a7c8..d9f257b7d 100644 --- a/Refit.Tests/XmlContentSerializerTests.cs +++ b/Refit.Tests/XmlContentSerializerTests.cs @@ -7,141 +7,140 @@ using System.Xml.Serialization; using Xunit; -namespace Refit.Tests +namespace Refit.Tests; + +public class XmlContentSerializerTests { - public class XmlContentSerializerTests + public class Dto { - public class Dto - { - public DateTime CreatedOn { get; set; } + public DateTime CreatedOn { get; set; } - public string Identifier { get; set; } + public string Identifier { get; set; } - [XmlElement(Namespace = "https://google.com")] - public string Name { get; set; } - } + [XmlElement(Namespace = "https://google.com")] + public string Name { get; set; } + } - [Fact] - public void MediaTypeShouldBeApplicationXmlAsync() - { - var dto = BuildDto(); - var sut = new XmlContentSerializer(); + [Fact] + public void MediaTypeShouldBeApplicationXmlAsync() + { + var dto = BuildDto(); + var sut = new XmlContentSerializer(); - var content = sut.ToHttpContent(dto); + var content = sut.ToHttpContent(dto); - Assert.Equal("application/xml", content.Headers.ContentType.MediaType); - } + Assert.Equal("application/xml", content.Headers.ContentType.MediaType); + } - [Fact] - public async Task ShouldSerializeToXml() - { - var dto = BuildDto(); - var sut = new XmlContentSerializer(); - - var content = sut.ToHttpContent(dto); - var document = new XmlDocument(); - document.LoadXml(await content.ReadAsStringAsync()); - - var root = - document[nameof(Dto)] - ?? throw new NullReferenceException("Root element was not found"); - Assert.Equal( - dto.CreatedOn, - XmlConvert.ToDateTime( - root[nameof(Dto.CreatedOn)].InnerText, - XmlDateTimeSerializationMode.Utc - ) - ); - Assert.Equal(dto.Identifier, root[nameof(Dto.Identifier)].InnerText); - Assert.Equal(dto.Name, root[nameof(Dto.Name)].InnerText); - } - - [Fact] - public async Task ShouldSerializeToXmlUsingAttributeOverrides() + [Fact] + public async Task ShouldSerializeToXml() + { + var dto = BuildDto(); + var sut = new XmlContentSerializer(); + + var content = sut.ToHttpContent(dto); + var document = new XmlDocument(); + document.LoadXml(await content.ReadAsStringAsync()); + + var root = + document[nameof(Dto)] + ?? throw new NullReferenceException("Root element was not found"); + Assert.Equal( + dto.CreatedOn, + XmlConvert.ToDateTime( + root[nameof(Dto.CreatedOn)].InnerText, + XmlDateTimeSerializationMode.Utc + ) + ); + Assert.Equal(dto.Identifier, root[nameof(Dto.Identifier)].InnerText); + Assert.Equal(dto.Name, root[nameof(Dto.Name)].InnerText); + } + + [Fact] + public async Task ShouldSerializeToXmlUsingAttributeOverrides() + { + const string overridenRootElementName = "dto-ex"; + + var dto = BuildDto(); + var serializerSettings = new XmlContentSerializerSettings(); + var attributes = new XmlAttributes { - const string overridenRootElementName = "dto-ex"; + XmlRoot = new XmlRootAttribute(overridenRootElementName) + }; + serializerSettings.XmlAttributeOverrides.Add(dto.GetType(), attributes); + var sut = new XmlContentSerializer(serializerSettings); - var dto = BuildDto(); - var serializerSettings = new XmlContentSerializerSettings(); - var attributes = new XmlAttributes - { - XmlRoot = new XmlRootAttribute(overridenRootElementName) - }; - serializerSettings.XmlAttributeOverrides.Add(dto.GetType(), attributes); - var sut = new XmlContentSerializer(serializerSettings); + var content = sut.ToHttpContent(dto); + var document = new XmlDocument(); + document.LoadXml(await content.ReadAsStringAsync()); - var content = sut.ToHttpContent(dto); - var document = new XmlDocument(); - document.LoadXml(await content.ReadAsStringAsync()); + Assert.Equal(overridenRootElementName, document.DocumentElement?.Name); + } - Assert.Equal(overridenRootElementName, document.DocumentElement?.Name); - } + [Fact] + public async Task ShouldSerializeToXmlUsingNamespaceOverrides() + { + const string prefix = "google"; - [Fact] - public async Task ShouldSerializeToXmlUsingNamespaceOverrides() + var dto = BuildDto(); + var serializerSettings = new XmlContentSerializerSettings { - const string prefix = "google"; - - var dto = BuildDto(); - var serializerSettings = new XmlContentSerializerSettings - { - XmlNamespaces = new XmlSerializerNamespaces() - }; - serializerSettings.XmlNamespaces.Add(prefix, "https://google.com"); - var sut = new XmlContentSerializer(serializerSettings); + XmlNamespaces = new XmlSerializerNamespaces() + }; + serializerSettings.XmlNamespaces.Add(prefix, "https://google.com"); + var sut = new XmlContentSerializer(serializerSettings); - var content = sut.ToHttpContent(dto); - var document = new XmlDocument(); - document.LoadXml(await content.ReadAsStringAsync()); + var content = sut.ToHttpContent(dto); + var document = new XmlDocument(); + document.LoadXml(await content.ReadAsStringAsync()); - Assert.Equal(prefix, document["Dto"]?["Name", "https://google.com"]?.Prefix); - } + Assert.Equal(prefix, document["Dto"]?["Name", "https://google.com"]?.Prefix); + } - [Fact] - public async Task ShouldDeserializeFromXmlAsync() + [Fact] + public async Task ShouldDeserializeFromXmlAsync() + { + var serializerSettings = new XmlContentSerializerSettings { - var serializerSettings = new XmlContentSerializerSettings - { - XmlNamespaces = new XmlSerializerNamespaces() - }; - var sut = new XmlContentSerializer(serializerSettings); + XmlNamespaces = new XmlSerializerNamespaces() + }; + var sut = new XmlContentSerializer(serializerSettings); - var dto = await sut.FromHttpContentAsync( - new StringContent("123") - ); + var dto = await sut.FromHttpContentAsync( + new StringContent("123") + ); - Assert.Equal("123", dto.Identifier); - } + Assert.Equal("123", dto.Identifier); + } - [Fact] - public async Task XmlEncodingShouldMatchWriterSettingAsync() + [Fact] + public async Task XmlEncodingShouldMatchWriterSettingAsync() + { + var encoding = Encoding.UTF32; + var serializerSettings = new XmlContentSerializerSettings { - var encoding = Encoding.UTF32; - var serializerSettings = new XmlContentSerializerSettings + XmlReaderWriterSettings = new XmlReaderWriterSettings() { - XmlReaderWriterSettings = new XmlReaderWriterSettings() - { - WriterSettings = new XmlWriterSettings() { Encoding = encoding } - } - }; - var sut = new XmlContentSerializer(serializerSettings); - - var dto = BuildDto(); - var content = sut.ToHttpContent(dto); - var xml = XDocument.Parse(await content.ReadAsStringAsync()); - var documentEncoding = xml.Declaration.Encoding; - Assert.Equal(encoding.WebName, documentEncoding); - } - - static Dto BuildDto() + WriterSettings = new XmlWriterSettings() { Encoding = encoding } + } + }; + var sut = new XmlContentSerializer(serializerSettings); + + var dto = BuildDto(); + var content = sut.ToHttpContent(dto); + var xml = XDocument.Parse(await content.ReadAsStringAsync()); + var documentEncoding = xml.Declaration.Encoding; + Assert.Equal(encoding.WebName, documentEncoding); + } + + static Dto BuildDto() + { + var dto = new Dto { - var dto = new Dto - { - CreatedOn = DateTime.UtcNow, - Identifier = Guid.NewGuid().ToString(), - Name = "Test Dto Object" - }; - return dto; - } + CreatedOn = DateTime.UtcNow, + Identifier = Guid.NewGuid().ToString(), + Name = "Test Dto Object" + }; + return dto; } } diff --git a/Refit.Xml/Refit.Xml.csproj b/Refit.Xml/Refit.Xml.csproj index 9a3c6647e..e2e4f14d6 100644 --- a/Refit.Xml/Refit.Xml.csproj +++ b/Refit.Xml/Refit.Xml.csproj @@ -3,7 +3,7 @@ Refit Xml Serializer ($(TargetFramework)) Refit Serializers for Xml - net462;netstandard2.0;netstandard2.1 + net462;netstandard2.0;net6.0;net8.0 true Refit enable diff --git a/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs b/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs index 90ace7c05..f18c3273e 100644 --- a/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs +++ b/Refit/Buffers/PooledBufferWriter.Stream.NETStandard21.cs @@ -1,4 +1,4 @@ -#if NETSTANDARD2_1 || NET6_0_OR_GREATER +#if NET6_0_OR_GREATER using System; using System.IO; diff --git a/Refit/Buffers/PooledBufferWriter.Stream.cs b/Refit/Buffers/PooledBufferWriter.Stream.cs index 78aa91d89..b86516289 100644 --- a/Refit/Buffers/PooledBufferWriter.Stream.cs +++ b/Refit/Buffers/PooledBufferWriter.Stream.cs @@ -90,7 +90,7 @@ CancellationToken cancellationToken try { -#if NETSTANDARD2_1 || NET6_0_OR_GREATER +#if NET6_0_OR_GREATER return CopyToInternalAsync(destination, cancellationToken); #else CopyTo(destination, bufferSize); diff --git a/Refit/Refit.csproj b/Refit/Refit.csproj index 675fbef69..595d96a32 100644 --- a/Refit/Refit.csproj +++ b/Refit/Refit.csproj @@ -2,7 +2,7 @@ Refit ($(TargetFramework)) - net462;netstandard2.0;netstandard2.1 + net462;netstandard2.0;net6.0;net8.0 true enable @@ -12,7 +12,7 @@ - + @@ -30,15 +30,9 @@ - + - + diff --git a/Refit/RestMethodInfo.cs b/Refit/RestMethodInfo.cs index dbd4c3294..63c0d9d69 100644 --- a/Refit/RestMethodInfo.cs +++ b/Refit/RestMethodInfo.cs @@ -4,7 +4,7 @@ using System.Text.RegularExpressions; // Enable support for C# 9 record types -#if NETSTANDARD2_1 || !NET6_0_OR_GREATER +#if !NET6_0_OR_GREATER namespace System.Runtime.CompilerServices { internal static class IsExternalInit { } @@ -309,7 +309,7 @@ List parameterInfo { Type = parameterType }; -#if NETSTANDARD2_1 || NET6_0_OR_GREATER +#if NET6_0_OR_GREATER ret.TryAdd( parameterInfo.IndexOf(restMethodParameterInfo.ParameterInfo), restMethodParameterInfo @@ -350,7 +350,7 @@ List parameterInfo restMethodParameterInfo.ParameterProperties.Add( new RestMethodParameterProperty(name, property.Item2) ); -#if NETSTANDARD2_1 || NET6_0_OR_GREATER +#if NET6_0_OR_GREATER ret.TryAdd( parameterInfo.IndexOf(restMethodParameterInfo.ParameterInfo), restMethodParameterInfo