diff --git a/Vonage.Common.Test/Client/VonageHttpClientTest.cs b/Vonage.Common.Test/Client/VonageHttpClientTest.cs index cac838267..7aa1378ce 100644 --- a/Vonage.Common.Test/Client/VonageHttpClientTest.cs +++ b/Vonage.Common.Test/Client/VonageHttpClientTest.cs @@ -9,295 +9,303 @@ using Vonage.Common.Test.Extensions; using Vonage.Common.Test.TestHelpers; -namespace Vonage.Common.Test.Client; - -public class VonageHttpClientTest +namespace Vonage.Common.Test.Client { - private readonly Fixture fixture; - - private readonly JsonSerializer serializer; - private readonly Result request; - - public VonageHttpClientTest() + public class VonageHttpClientTest { - this.serializer = new JsonSerializer(); - this.fixture = new Fixture(); - this.fixture.Customize(new SupportMutableValueTypesCustomization()); - this.request = BuildRequest(); - } + private readonly Fixture fixture; - [Fact] - public async Task SendAsync_ShouldThrowException_GivenOperationExceedsTimeout() => - await this.VerifyReturnsFailureGivenOperationExceedsTimeout(client => client.SendAsync(this.request)); - - [Property] - public Property SendAsync_VerifyReturnsFailureGivenApiResponseIsError() => - this.VerifyReturnsFailureGivenApiResponseIsError(BuildExpectedRequest(), - configuration => new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); - - [Property] - public Property SendAsync_VerifyReturnsFailureGivenErrorCannotBeParsed() => - this.VerifyReturnsFailureGivenErrorCannotBeParsed(BuildExpectedRequest(), - configuration => new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); - - [Fact] - public async Task SendAsync_VerifyReturnsFailureGivenRequestIsFailure() => - await this.VerifyReturnsFailureGivenRequestIsFailure((configuration, failureRequest) => - new VonageHttpClient(configuration, this.serializer).SendAsync(failureRequest)); - - [Fact] - public async Task SendAsync_VerifyReturnsFailureGivenTokenGenerationFails() => - await this.VerifyReturnsFailureGivenTokenGenerationFails(configuration => - new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); - - [Fact] - public async Task SendAsync_VerifyReturnsUnitGivenApiResponseIsSuccess() => - await this.VerifyReturnsExpectedValueGivenApiResponseIsSuccess(BuildExpectedRequest(), - configuration => new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); - - [Fact] - public async Task SendWithoutHeaderAsync_ShouldThrowException_GivenOperationExceedsTimeout() => - await this.VerifyReturnsFailureGivenOperationExceedsTimeout(client => - client.SendWithoutHeadersAsync(this.request)); - - [Property] - public Property SendWithoutHeaderAsync_VerifyReturnsFailureGivenApiResponseIsError() => - this.VerifyReturnsFailureGivenApiResponseIsError(BuildExpectedRequest(), - configuration => new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); - - [Property] - public Property SendWithoutHeaderAsync_VerifyReturnsFailureGivenErrorCannotBeParsed() => - this.VerifyReturnsFailureGivenErrorCannotBeParsed(BuildExpectedRequest(), - configuration => - new VonageHttpClient(configuration, this.serializer).SendWithoutHeadersAsync(this.request)); - - [Fact] - public async Task SendWithoutHeaderAsync_VerifyReturnsFailureGivenRequestIsFailure() => - await this.VerifyReturnsFailureGivenRequestIsFailure((configuration, failureRequest) => - new VonageHttpClient(configuration, this.serializer).SendWithoutHeadersAsync(failureRequest)); - - [Fact] - public async Task SendWithoutHeaderAsync_VerifyReturnsUnitGivenApiResponseIsSuccess() => - await this.VerifyReturnsExpectedValueGivenApiResponseIsSuccess(BuildExpectedRequest(), - configuration => - new VonageHttpClient(configuration, this.serializer).SendWithoutHeadersAsync(this.request)); - - [Fact] - public async Task SendWithRawResponseAsync_ShouldThrowException_GivenOperationExceedsTimeout() => - await this.VerifyReturnsFailureGivenOperationExceedsTimeout(client => - client.SendWithRawResponseAsync(this.request)); - - [Fact] - public async Task SendWithRawResponseAsync_VerifyReturnsExpectedValueGivenApiResponseIsSuccess() => - await this.VerifyReturnsRawContentGivenApiResponseIsSuccess(BuildExpectedRequest(), - configuration => - new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync(this.request)); - - [Property] - public Property SendWithRawResponseAsync_VerifyReturnsFailureGivenApiResponseIsError() => - this.VerifyReturnsFailureGivenApiResponseIsError(BuildExpectedRequest(), - configuration => - new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync(this.request)); - - [Property] - public Property SendWithRawResponseAsync_VerifyReturnsFailureGivenErrorCannotBeParsed() => - this.VerifyReturnsFailureGivenErrorCannotBeParsed(BuildExpectedRequest(), - configuration => - new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync(this.request)); - - [Fact] - public async Task SendWithRawResponseAsync_VerifyReturnsFailureGivenRequestIsFailure() => - await this.VerifyReturnsFailureGivenRequestIsFailure((configuration, failureRequest) => - new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync(failureRequest)); - - [Fact] - public async Task SendWithRawResponseAsync_VerifyReturnsFailureGivenTokenGenerationFails() => - await this.VerifyReturnsFailureGivenTokenGenerationFails(configuration => - new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync( - this.request)); - - [Fact] - public async Task SendWithResponseAsync_ShouldThrowException_GivenOperationExceedsTimeout() => - await this.VerifyReturnsFailureGivenOperationExceedsTimeout(client => - client.SendWithResponseAsync(this.request)); - - [Fact] - public async Task SendWithResponseAsync_VerifyReturnsExpectedValueGivenApiResponseIsSuccess() => - await this.VerifyReturnsExpectedValueGivenApiResponseIsSuccess(BuildExpectedRequest(), - configuration => - new VonageHttpClient(configuration, this.serializer).SendWithResponseAsync( - this.request)); + private readonly JsonSerializer serializer; + private readonly Result request; - [Fact] - public async Task SendWithResponseAsync_VerifyReturnsFailureGivenApiResponseCannotBeParsed() => - await this.VerifyReturnsFailureGivenApiResponseCannotBeParsed(BuildExpectedRequest(), - configuration => - new VonageHttpClient(configuration, this.serializer).SendWithResponseAsync( + public VonageHttpClientTest() + { + this.serializer = new JsonSerializer(); + this.fixture = new Fixture(); + this.fixture.Customize(new SupportMutableValueTypesCustomization()); + this.request = BuildRequest(); + } + + [Fact] + public async Task SendAsync_ShouldThrowException_GivenOperationExceedsTimeout() => + await this.VerifyReturnsFailureGivenOperationExceedsTimeout(client => client.SendAsync(this.request)); + + [Property] + public Property SendAsync_VerifyReturnsFailureGivenApiResponseIsError() => + this.VerifyReturnsFailureGivenApiResponseIsError(BuildExpectedRequest(), + configuration => new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); + + [Property] + public Property SendAsync_VerifyReturnsFailureGivenErrorCannotBeParsed() => + this.VerifyReturnsFailureGivenErrorCannotBeParsed(BuildExpectedRequest(), + configuration => new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); + + [Fact] + public async Task SendAsync_VerifyReturnsFailureGivenRequestIsFailure() => + await this.VerifyReturnsFailureGivenRequestIsFailure((configuration, failureRequest) => + new VonageHttpClient(configuration, this.serializer).SendAsync(failureRequest)); + + [Fact] + public async Task SendAsync_VerifyReturnsFailureGivenTokenGenerationFails() => + await this.VerifyReturnsFailureGivenTokenGenerationFails(configuration => + new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); + + [Fact] + public async Task SendAsync_VerifyReturnsUnitGivenApiResponseIsSuccess() => + await this.VerifyReturnsExpectedValueGivenApiResponseIsSuccess(BuildExpectedRequest(), + configuration => new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); + + [Fact] + public async Task SendWithoutHeaderAsync_ShouldThrowException_GivenOperationExceedsTimeout() => + await this.VerifyReturnsFailureGivenOperationExceedsTimeout(client => + client.SendWithoutHeadersAsync(this.request)); + + [Property] + public Property SendWithoutHeaderAsync_VerifyReturnsFailureGivenApiResponseIsError() => + this.VerifyReturnsFailureGivenApiResponseIsError(BuildExpectedRequest(), + configuration => new VonageHttpClient(configuration, this.serializer).SendAsync(this.request)); + + [Property] + public Property SendWithoutHeaderAsync_VerifyReturnsFailureGivenErrorCannotBeParsed() => + this.VerifyReturnsFailureGivenErrorCannotBeParsed(BuildExpectedRequest(), + configuration => + new VonageHttpClient(configuration, this.serializer).SendWithoutHeadersAsync(this.request)); + + [Fact] + public async Task SendWithoutHeaderAsync_VerifyReturnsFailureGivenRequestIsFailure() => + await this.VerifyReturnsFailureGivenRequestIsFailure((configuration, failureRequest) => + new VonageHttpClient(configuration, this.serializer).SendWithoutHeadersAsync(failureRequest)); + + [Fact] + public async Task SendWithoutHeaderAsync_VerifyReturnsUnitGivenApiResponseIsSuccess() => + await this.VerifyReturnsExpectedValueGivenApiResponseIsSuccess(BuildExpectedRequest(), + configuration => + new VonageHttpClient(configuration, this.serializer).SendWithoutHeadersAsync(this.request)); + + [Fact] + public async Task SendWithRawResponseAsync_ShouldThrowException_GivenOperationExceedsTimeout() => + await this.VerifyReturnsFailureGivenOperationExceedsTimeout(client => + client.SendWithRawResponseAsync(this.request)); + + [Fact] + public async Task SendWithRawResponseAsync_VerifyReturnsExpectedValueGivenApiResponseIsSuccess() => + await this.VerifyReturnsRawContentGivenApiResponseIsSuccess(BuildExpectedRequest(), + configuration => + new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync(this.request)); + + [Property] + public Property SendWithRawResponseAsync_VerifyReturnsFailureGivenApiResponseIsError() => + this.VerifyReturnsFailureGivenApiResponseIsError(BuildExpectedRequest(), + configuration => + new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync(this.request)); + + [Property] + public Property SendWithRawResponseAsync_VerifyReturnsFailureGivenErrorCannotBeParsed() => + this.VerifyReturnsFailureGivenErrorCannotBeParsed(BuildExpectedRequest(), + configuration => + new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync(this.request)); + + [Fact] + public async Task SendWithRawResponseAsync_VerifyReturnsFailureGivenRequestIsFailure() => + await this.VerifyReturnsFailureGivenRequestIsFailure((configuration, failureRequest) => + new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync(failureRequest)); + + [Fact] + public async Task SendWithRawResponseAsync_VerifyReturnsFailureGivenTokenGenerationFails() => + await this.VerifyReturnsFailureGivenTokenGenerationFails(configuration => + new VonageHttpClient(configuration, this.serializer).SendWithRawResponseAsync( this.request)); - [Property] - public Property SendWithResponseAsync_VerifyReturnsFailureGivenApiResponseIsError() => - this.VerifyReturnsFailureGivenApiResponseIsError(BuildExpectedRequest(), - configuration => + [Fact] + public async Task SendWithResponseAsync_ShouldThrowException_GivenOperationExceedsTimeout() => + await this.VerifyReturnsFailureGivenOperationExceedsTimeout(client => + client.SendWithResponseAsync(this.request)); + + [Fact] + public async Task SendWithResponseAsync_VerifyReturnsExpectedValueGivenApiResponseIsSuccess() => + await this.VerifyReturnsExpectedValueGivenApiResponseIsSuccess(BuildExpectedRequest(), + configuration => + new VonageHttpClient(configuration, this.serializer) + .SendWithResponseAsync( + this.request)); + + [Fact] + public async Task SendWithResponseAsync_VerifyReturnsFailureGivenApiResponseCannotBeParsed() => + await this.VerifyReturnsFailureGivenApiResponseCannotBeParsed(BuildExpectedRequest(), + configuration => + new VonageHttpClient(configuration, this.serializer) + .SendWithResponseAsync( + this.request)); + + [Property] + public Property SendWithResponseAsync_VerifyReturnsFailureGivenApiResponseIsError() => + this.VerifyReturnsFailureGivenApiResponseIsError(BuildExpectedRequest(), + configuration => + new VonageHttpClient(configuration, this.serializer) + .SendWithResponseAsync( + this.request)); + + [Property] + public Property SendWithResponseAsync_VerifyReturnsFailureGivenErrorCannotBeParsed() => + this.VerifyReturnsFailureGivenErrorCannotBeParsed(BuildExpectedRequest(), + configuration => + new VonageHttpClient(configuration, this.serializer) + .SendWithResponseAsync( + this.request)); + + [Fact] + public async Task SendWithResponseAsync_VerifyReturnsFailureGivenRequestIsFailure() => + await this.VerifyReturnsFailureGivenRequestIsFailure((configuration, failureRequest) => new VonageHttpClient(configuration, this.serializer).SendWithResponseAsync( - this.request)); + failureRequest)); - [Property] - public Property SendWithResponseAsync_VerifyReturnsFailureGivenErrorCannotBeParsed() => - this.VerifyReturnsFailureGivenErrorCannotBeParsed(BuildExpectedRequest(), - configuration => + [Fact] + public async Task SendWithResponseAsync_VerifyReturnsFailureGivenTokenGenerationFails() => + await this.VerifyReturnsFailureGivenTokenGenerationFails(configuration => new VonageHttpClient(configuration, this.serializer).SendWithResponseAsync( this.request)); - [Fact] - public async Task SendWithResponseAsync_VerifyReturnsFailureGivenRequestIsFailure() => - await this.VerifyReturnsFailureGivenRequestIsFailure((configuration, failureRequest) => - new VonageHttpClient(configuration, this.serializer).SendWithResponseAsync( - failureRequest)); - - [Fact] - public async Task SendWithResponseAsync_VerifyReturnsFailureGivenTokenGenerationFails() => - await this.VerifyReturnsFailureGivenTokenGenerationFails(configuration => - new VonageHttpClient(configuration, this.serializer).SendWithResponseAsync( - this.request)); - - private static ExpectedRequest BuildExpectedRequest() => - new() - { - Method = System.Net.Http.HttpMethod.Post, - RequestUri = new Uri("/my-fake-api/yolo", UriKind.Relative), - Content = "{\"id\":\"foo bar\",\"name\":\"My fake request\"}", - }; - - private static Result BuildRequest() => - new FakeRequest { Id = Guid.Parse("ceb2b201-2143-48f5-8890-c58369394eba"), Name = "My fake request" }; - - private VonageHttpClientConfiguration CreateConfiguration(FakeHttpRequestHandler handler) => - new(handler.ToHttpClient(), new AuthenticationHeaderValue("Anonymous"), this.fixture.Create()); - - private async Task VerifyReturnsExpectedValueGivenApiResponseIsSuccess(ExpectedRequest expected, - Func>> operation) - { - var expectedResponse = this.fixture.Create(); - var messageHandler = FakeHttpRequestHandler - .Build(HttpStatusCode.OK) - .WithExpectedRequest(expected) - .WithResponseContent(this.serializer.SerializeObject(expectedResponse)); - var result = await operation(this.CreateConfiguration(messageHandler)); - result.Should().BeSuccess(expectedResponse); - } - - private async Task VerifyReturnsFailureGivenApiResponseCannotBeParsed(ExpectedRequest expected, - Func>> operation) - { - var body = this.fixture.Create(); - var messageHandler = FakeHttpRequestHandler - .Build(HttpStatusCode.OK) - .WithExpectedRequest(expected) - .WithResponseContent(body); - var result = await operation(this.CreateConfiguration(messageHandler)); - result.Should().BeFailure(DeserializationFailure.From(typeof(TResponse), body)); - } - - private Property VerifyReturnsFailureGivenApiResponseIsError( - ExpectedRequest expected, - Func>> operation) => - Prop.ForAll( - FsCheckExtensions.GetErrorResponses(), - error => + private static ExpectedRequest BuildExpectedRequest() => + new() { - var expectedContent = string.Empty; - var messageHandler = FakeHttpRequestHandler - .Build(error.Code) - .WithExpectedRequest(expected); - if (error.Message != null) - { - expectedContent = this.serializer.SerializeObject(error); - messageHandler = messageHandler.WithResponseContent(expectedContent); - } - - operation(this.CreateConfiguration(messageHandler)).Result.Should() - .BeFailure(HttpFailure.From(error.Code, error.Message ?? string.Empty, expectedContent)); - }); - - private Property VerifyReturnsFailureGivenErrorCannotBeParsed( - ExpectedRequest expected, - Func>> operation) => - Prop.ForAll( - FsCheckExtensions.GetInvalidStatusCodes(), - FsCheckExtensions.GetNonDeserializableStrings(), - (statusCode, jsonError) => - { - var messageHandler = FakeHttpRequestHandler.Build(statusCode) - .WithExpectedRequest(expected) - .WithResponseContent(jsonError); - operation(this.CreateConfiguration(messageHandler)) - .Result - .Should() - .BeFailure(HttpFailure.From(statusCode, - DeserializationFailure.From(typeof(ErrorResponse), jsonError).GetFailureMessage(), - jsonError)); - }); - - private async Task VerifyReturnsFailureGivenOperationExceedsTimeout( - Func>> operation) - { - var httpClient = FakeHttpRequestHandler.Build(HttpStatusCode.OK).WithDelay(TimeSpan.FromSeconds(5)) - .ToHttpClient(); - httpClient.Timeout = TimeSpan.FromMilliseconds(100); - var client = - new VonageHttpClient( - new VonageHttpClientConfiguration(httpClient, new AuthenticationHeaderValue("Anonymous"), - this.fixture.Create()), this.serializer); - await operation(client).Should().BeFailureAsync(); - } + Method = HttpMethod.Post, + RequestUri = new Uri("/my-fake-api/yolo", UriKind.Relative), + Content = "{\"id\":\"foo bar\",\"name\":\"My fake request\"}", + }; - private async Task VerifyReturnsFailureGivenRequestIsFailure( - Func, Task>> operation) - { - var messageHandler = FakeHttpRequestHandler.Build(HttpStatusCode.OK); - var expectedFailure = ResultFailure.FromErrorMessage(this.fixture.Create()); - var result = await operation(this.CreateConfiguration(messageHandler), - Result.FromFailure(expectedFailure)); - result.Should().BeFailure(expectedFailure); - } + private static Result BuildRequest() => + new FakeRequest {Id = Guid.Parse("ceb2b201-2143-48f5-8890-c58369394eba"), Name = "My fake request"}; - private async Task VerifyReturnsFailureGivenTokenGenerationFails( - Func>> operation) - { - var configuration = new VonageHttpClientConfiguration( - FakeHttpRequestHandler.Build(HttpStatusCode.OK).ToHttpClient(), - new AuthenticationFailure().ToResult(), - this.fixture.Create()); - var result = await operation(configuration); - result.Should().BeFailure(new AuthenticationFailure()); - } + private VonageHttpClientConfiguration CreateConfiguration(FakeHttpRequestHandler handler) => + new(handler.ToHttpClient(), new AuthenticationHeaderValue("Anonymous"), this.fixture.Create()); - private async Task VerifyReturnsRawContentGivenApiResponseIsSuccess(ExpectedRequest expected, - Func>> operation) - { - var expectedResponse = this.fixture.Create(); - var messageHandler = FakeHttpRequestHandler - .Build(HttpStatusCode.OK) - .WithExpectedRequest(expected) - .WithResponseContent(expectedResponse); - var result = await operation(this.CreateConfiguration(messageHandler)); - result.Should().BeSuccess(expectedResponse); - } + private async Task VerifyReturnsExpectedValueGivenApiResponseIsSuccess(ExpectedRequest expected, + Func>> operation) + { + var expectedResponse = this.fixture.Create(); + var messageHandler = FakeHttpRequestHandler + .Build(HttpStatusCode.OK) + .WithExpectedRequest(expected) + .WithResponseContent(this.serializer.SerializeObject(expectedResponse)); + var result = await operation(this.CreateConfiguration(messageHandler)); + result.Should().BeSuccess(expectedResponse); + } + + private async Task VerifyReturnsFailureGivenApiResponseCannotBeParsed(ExpectedRequest expected, + Func>> operation) + { + var body = this.fixture.Create(); + var messageHandler = FakeHttpRequestHandler + .Build(HttpStatusCode.OK) + .WithExpectedRequest(expected) + .WithResponseContent(body); + var result = await operation(this.CreateConfiguration(messageHandler)); + result.Should().BeFailure(DeserializationFailure.From(typeof(TResponse), body)); + } + + private Property VerifyReturnsFailureGivenApiResponseIsError( + ExpectedRequest expected, + Func>> operation) => + Prop.ForAll( + FsCheckExtensions.GetErrorResponses(), + error => + { + var expectedContent = string.Empty; + var messageHandler = FakeHttpRequestHandler + .Build(error.Code) + .WithExpectedRequest(expected); + if (error.Message != null) + { + expectedContent = this.serializer.SerializeObject(error); + messageHandler = messageHandler.WithResponseContent(expectedContent); + } + + operation(this.CreateConfiguration(messageHandler)).Result.Should() + .BeFailure(HttpFailure.From(error.Code, error.Message ?? string.Empty, expectedContent)); + }); + + private Property VerifyReturnsFailureGivenErrorCannotBeParsed( + ExpectedRequest expected, + Func>> operation) => + Prop.ForAll( + FsCheckExtensions.GetInvalidStatusCodes(), + FsCheckExtensions.GetNonDeserializableStrings(), + (statusCode, jsonError) => + { + var messageHandler = FakeHttpRequestHandler.Build(statusCode) + .WithExpectedRequest(expected) + .WithResponseContent(jsonError); + operation(this.CreateConfiguration(messageHandler)) + .Result + .Should() + .BeFailure(HttpFailure.From(statusCode, + DeserializationFailure.From(typeof(ErrorResponse), jsonError).GetFailureMessage(), + jsonError)); + }); + + private async Task VerifyReturnsFailureGivenOperationExceedsTimeout( + Func>> operation) + { + var httpClient = FakeHttpRequestHandler.Build(HttpStatusCode.OK).WithDelay(TimeSpan.FromSeconds(5)) + .ToHttpClient(); + httpClient.Timeout = TimeSpan.FromMilliseconds(100); + var client = + new VonageHttpClient( + new VonageHttpClientConfiguration(httpClient, new AuthenticationHeaderValue("Anonymous"), + this.fixture.Create()), this.serializer); + await operation(client).Should().BeFailureAsync(); + } + + private async Task VerifyReturnsFailureGivenRequestIsFailure( + Func, Task>> operation) + { + var messageHandler = FakeHttpRequestHandler.Build(HttpStatusCode.OK); + var expectedFailure = ResultFailure.FromErrorMessage(this.fixture.Create()); + var result = await operation(this.CreateConfiguration(messageHandler), + Result.FromFailure(expectedFailure)); + result.Should().BeFailure(expectedFailure); + } + + private async Task VerifyReturnsFailureGivenTokenGenerationFails( + Func>> operation) + { + var configuration = new VonageHttpClientConfiguration( + FakeHttpRequestHandler.Build(HttpStatusCode.OK).ToHttpClient(), + new AuthenticationFailure().ToResult(), + this.fixture.Create()); + var result = await operation(configuration); + result.Should().BeFailure(new AuthenticationFailure()); + } + + private async Task VerifyReturnsRawContentGivenApiResponseIsSuccess(ExpectedRequest expected, + Func>> operation) + { + var expectedResponse = this.fixture.Create(); + var messageHandler = FakeHttpRequestHandler + .Build(HttpStatusCode.OK) + .WithExpectedRequest(expected) + .WithResponseContent(expectedResponse); + var result = await operation(this.CreateConfiguration(messageHandler)); + result.Should().BeSuccess(expectedResponse); + } + + private struct FakeRequest : IVonageRequest + { + public Guid Id { get; set; } - private struct FakeRequest : IVonageRequest - { - public Guid Id { get; set; } + public string Name { get; set; } - public string Name { get; set; } + public HttpRequestMessage BuildRequestMessage() => VonageRequestBuilder + .Initialize(HttpMethod.Post, this.GetEndpointPath()) + .WithContent(new StringContent("{\"id\":\"foo bar\",\"name\":\"My fake request\"}")) + .Build(); - public System.Net.Http.HttpRequestMessage BuildRequestMessage() => VonageRequestBuilder - .Initialize(System.Net.Http.HttpMethod.Post, this.GetEndpointPath()) - .WithContent(new System.Net.Http.StringContent("{\"id\":\"foo bar\",\"name\":\"My fake request\"}")) - .Build(); + public string GetEndpointPath() => "/my-fake-api/yolo"; + } - public string GetEndpointPath() => "/my-fake-api/yolo"; + private struct FakeResponse + { + public Guid Id { get; set; } + } } - - private record FakeResponse; } \ No newline at end of file diff --git a/Vonage.Common.Test/Extensions/MaybeAssertionExtensions.cs b/Vonage.Common.Test/Extensions/MaybeAssertionExtensions.cs index d59051091..d71a36756 100644 --- a/Vonage.Common.Test/Extensions/MaybeAssertionExtensions.cs +++ b/Vonage.Common.Test/Extensions/MaybeAssertionExtensions.cs @@ -21,21 +21,6 @@ public AndConstraint> Be(Maybe expected) return new AndConstraint>(this); } - public AndConstraint> BeEquivalentTo(Maybe expected) - { - Execute.Assertion - .WithExpectation($"Expected {this.Subject} to be equivalent to {expected}, ") - .Given(() => new {this.Subject, Expected = expected}) - .ForCondition(data => data.Subject.IsSome == data.Subject.IsSome) - .FailWith($"States differs between {this.Subject} and {expected}.") - .Then - .Given(data => data.Subject.Merge(data.Expected, (s, e) => new {Subject = s, Expected = e})) - .ForCondition( - data => data.Match(some => EvaluateValueEquality(some.Subject, some.Expected), () => true)) - .FailWith($"Value equality failed between {this.Subject} and {expected}."); - return new AndConstraint>(this); - } - public AndConstraint> BeNone() { Execute.Assertion @@ -60,13 +45,18 @@ public AndConstraint> BeSome(Action action) public AndConstraint> BeSome(T expected) { Execute.Assertion - .WithExpectation("Expected {context:option} to be Some {0}{reason}, ", expected) - .Given(() => this.Subject) - .ForCondition(subject => subject.IsSome) + .WithExpectation($"Expected {this.Subject} to be equivalent to {expected}, ") + .Given(() => new {this.Subject, Expected = expected}) + .ForCondition(data => data.Subject.IsSome) .FailWith("but found to be None.") .Then - .ForCondition(subject => subject.Equals(Maybe.Some(expected))) - .FailWith("but found Some {0}.", this.Subject); + .Given(data => new + { + Subject = data.Subject.GetUnsafe(), + data.Expected, + }) + .ForCondition(data => EvaluateValueEquality(data.Subject, data.Expected)) + .FailWith($"but value equality failed between {this.Subject} and {expected}."); return new AndConstraint>(this); } diff --git a/Vonage.Common.Test/Extensions/ResultAssertionExtensions.cs b/Vonage.Common.Test/Extensions/ResultAssertionExtensions.cs index ff33c7e46..20bdd236a 100644 --- a/Vonage.Common.Test/Extensions/ResultAssertionExtensions.cs +++ b/Vonage.Common.Test/Extensions/ResultAssertionExtensions.cs @@ -12,28 +12,6 @@ public ResultAssertionExtensions(Result subject) : base(subject) { } - public AndConstraint> BeEquivalentTo(Result expected) - { - Execute.Assertion - .WithExpectation($"Expected {this.Subject} to be equivalent to {expected}, ") - .Given(() => new {this.Subject, Expected = expected}) - .ForCondition(data => data.Subject.IsSuccess == data.Subject.IsSuccess) - .FailWith($"States differs between {this.Subject} and {expected}.") - .Then - .Given(data => new - { - IsSuccess = data.Subject.IsSuccess && data.Expected.IsSuccess, - data.Subject, - data.Expected, - }) - .ForCondition(data => - data.IsSuccess - ? EvaluateValueEquality(data.Subject.GetSuccessUnsafe(), data.Expected.GetSuccessUnsafe()) - : EvaluateValueEquality(data.Subject.GetFailureUnsafe(), data.Expected.GetFailureUnsafe())) - .FailWith($"Value equality failed between {this.Subject} and {expected}."); - return new AndConstraint>(this); - } - public AndConstraint> BeFailure(Action action) { this.BuildFailureExpectation(); @@ -92,10 +70,14 @@ public AndConstraint> BeSuccess(Action action) public AndConstraint> BeSuccess(T expected) { - this.BuildSuccessExpectation() + Execute.Assertion + .WithExpectation($"Expected {this.Subject} to be equivalent to {expected}, ") + .Given(() => new {this.Subject, Expected = expected}) + .ForCondition(data => data.Subject.IsSuccess) + .FailWith("but found to be Failure.") .Then - .ForCondition(subject => subject.Equals(Result.FromSuccess(expected))) - .FailWith(this.BuildResultSuccessMessage()); + .ForCondition(data => EvaluateValueEquality(data.Subject.GetSuccessUnsafe(), expected)) + .FailWith($"Value equality failed between {this.Subject} and {expected}."); return new AndConstraint>(this); } diff --git a/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs b/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs index 715647f01..69e1eb27b 100644 --- a/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs +++ b/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Vonage.Common.Test.Extensions; using Vonage.Conversations.CreateConversation; using Xunit; @@ -63,6 +64,15 @@ public void Build_ShouldSetDisplayName() => .Should() .BeSuccess(new string('a', 50)); + [Fact] + public void Build_ShouldSetImageUrl() => + CreateConversationRequest.Build() + .WithImageUrl(new Uri("https://example.com")) + .Create() + .Map(request => request.ImageUrl) + .Should() + .BeSuccess(new Uri("https://example.com")); + [Fact] public void Build_ShouldSetName() => CreateConversationRequest.Build() @@ -73,12 +83,15 @@ public void Build_ShouldSetName() => .BeSuccess(new string('a', 100)); [Fact] - public void Build_ShouldSetUri() => + public void Build_ShouldSetProperties() => CreateConversationRequest.Build() - .WithUri(new Uri("https://example.com")) + .WithProperties(new Properties(55, "Fake", "hello-there", + new Dictionary {{"temp1", "123"}, {"temp12", "456"}})) .Create() - .Map(request => request.Uri) + .Map(request => request.Properties) .Should() - .BeSuccess(new Uri("https://example.com")); + .BeSuccess(properties => + properties.Should().BeSome(new Properties(55, "Fake", "hello-there", + new Dictionary {{"temp1", "123"}, {"temp12", "456"}}))); } } \ No newline at end of file diff --git a/Vonage.Test.Unit/Conversations/CreateConversation/SerializationTest.cs b/Vonage.Test.Unit/Conversations/CreateConversation/SerializationTest.cs index e90cbad19..3615929ff 100644 --- a/Vonage.Test.Unit/Conversations/CreateConversation/SerializationTest.cs +++ b/Vonage.Test.Unit/Conversations/CreateConversation/SerializationTest.cs @@ -33,7 +33,7 @@ public void ShouldDeserialize200() => this.helper.Serializer DateTimeOffset.Parse("2019-09-03T18:40:24.324Z", CultureInfo.InvariantCulture), DateTimeOffset.Parse("2019-09-03T18:40:24.324Z", CultureInfo.InvariantCulture), DateTimeOffset.Parse("2019-09-03T18:40:24.324Z", CultureInfo.InvariantCulture))); - response.Properties.Should().BeEquivalentTo(new Properties(60, "string", + response.Properties.Should().BeSome(new Properties(60, "string", "string", new Dictionary { {"property1", "string"}, diff --git a/Vonage/Conversations/CreateConversation/CreateConversationRequest.cs b/Vonage/Conversations/CreateConversation/CreateConversationRequest.cs index 4a3402195..a10c6ef63 100644 --- a/Vonage/Conversations/CreateConversation/CreateConversationRequest.cs +++ b/Vonage/Conversations/CreateConversation/CreateConversationRequest.cs @@ -12,13 +12,17 @@ namespace Vonage.Conversations.CreateConversation; /// public Maybe DisplayName { get; internal init; } + /// + /// + public Maybe ImageUrl { get; internal init; } + /// /// public Maybe Name { get; internal init; } /// /// - public Maybe Uri { get; internal init; } + public Maybe Properties { get; internal init; } /// /// Initializes a builder for CreateConversationRequest. diff --git a/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs b/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs index 112fedce4..b1469e8d9 100644 --- a/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs +++ b/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs @@ -9,6 +9,7 @@ internal class CreateConversationRequestBuilder : IBuilderForOptional { private const int DisplayNameMaxLength = 50; private const int NameMaxLength = 100; + private Maybe properties; private Maybe name; private Maybe displayName; private Maybe uri; @@ -18,7 +19,8 @@ public Result Create() => Result.Evaluate) .Bind(evaluation => evaluation.WithRules( @@ -33,15 +35,21 @@ public IBuilderForOptional WithDisplayName(string value) return this; } + public IBuilderForOptional WithImageUrl(Uri value) + { + this.uri = value; + return this; + } + public IBuilderForOptional WithName(string value) { this.name = value; return this; } - public IBuilderForOptional WithUri(Uri value) + public IBuilderForOptional WithProperties(Properties value) { - this.uri = value; + this.properties = value; return this; } @@ -79,6 +87,13 @@ public interface IBuilderForOptional : IVonageRequestBuilderThe builder. IBuilderForOptional WithDisplayName(string value); + /// + /// Sets the Image Url. + /// + /// The Image Url. + /// The builder. + IBuilderForOptional WithImageUrl(Uri value); + /// /// Sets the Name /// @@ -87,9 +102,9 @@ public interface IBuilderForOptional : IVonageRequestBuilder - /// Sets the Uri + /// Sets the Properties. /// - /// The uri. + /// The properties. /// The builder. - IBuilderForOptional WithUri(Uri value); + IBuilderForOptional WithProperties(Properties value); } \ No newline at end of file