From 4250e09a11b6e4210ae92f3a5264a89854420d7d Mon Sep 17 00:00:00 2001 From: Guillaume Faas Date: Fri, 8 Dec 2023 07:29:23 +0100 Subject: [PATCH] feat: implement request validation for CreateConversation --- .../CreateConversation/RequestBuilderTest.cs | 34 +++++++++++++++---- .../CreateConversationRequestBuilder.cs | 29 +++++++++++++++- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs b/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs index 96285240f..a2f147d3e 100644 --- a/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs +++ b/Vonage.Test.Unit/Conversations/CreateConversation/RequestBuilderTest.cs @@ -16,6 +16,15 @@ public void Build_ShouldReturnDefaultValues_GivenNoValuesHaveBeenSet() => .Should() .BeSuccess(); + [Fact] + public void Build_ShouldReturnFailure_GivenCallbackEventMaskLengthIsAbove200Characters() => + CreateConversationRequest.Build() + .WithCallback(new Callback(new Uri("https://example.com"), new string('a', 201), + new CallbackParameters("appId", new Uri("https://example.com")), HttpMethod.Get)) + .Create() + .Should() + .BeParsingFailure("Callback EventMask length cannot be higher than 200."); + [Theory] [InlineData("")] [InlineData(" ")] @@ -23,7 +32,6 @@ public void Build_ShouldReturnFailure_GivenDisplayNameIsProvidedButEmpty(string CreateConversationRequest.Build() .WithDisplayName(invalidDisplayName) .Create() - .Map(request => request.DisplayName) .Should() .BeParsingFailure("DisplayName cannot be null or whitespace."); @@ -32,7 +40,6 @@ public void Build_ShouldReturnFailure_GivenDisplayNameLengthIsAbove50Characters( CreateConversationRequest.Build() .WithDisplayName(new string('a', 51)) .Create() - .Map(request => request.DisplayName) .Should() .BeParsingFailure("DisplayName length cannot be higher than 50."); @@ -49,7 +56,6 @@ public void Build_ShouldReturnFailure_GivenHttpMethodIsNotGetOrPost(string metho .WithCallback(new Callback(new Uri("https://example.com"), "mask", new CallbackParameters("appId", new Uri("https://example.com")), new HttpMethod(method))) .Create() - .Map(request => request.Callback) .Should() .BeParsingFailure("Callback HttpMethod must be GET or POST."); @@ -60,7 +66,6 @@ public void Build_ShouldReturnFailure_GivenNameIsProvidedButEmpty(string invalid CreateConversationRequest.Build() .WithName(invalidName) .Create() - .Map(request => request.Name) .Should() .BeParsingFailure("Name cannot be null or whitespace."); @@ -69,10 +74,25 @@ public void Build_ShouldReturnFailure_GivenNameLengthIsAbove100Characters() => CreateConversationRequest.Build() .WithName(new string('a', 101)) .Create() - .Map(request => request.Name) .Should() .BeParsingFailure("Name length cannot be higher than 100."); + [Fact] + public void Build_ShouldReturnFailure_GivenPropertiesCustomSortKeyLengthIsAbove200Characters() => + CreateConversationRequest.Build() + .WithProperties(new Properties(10, "type", new string('a', 201), new Dictionary())) + .Create() + .Should() + .BeParsingFailure("Properties CustomSortKey length cannot be higher than 200."); + + [Fact] + public void Build_ShouldReturnFailure_GivenPropertiesTypeLengthIsAbove200Characters() => + CreateConversationRequest.Build() + .WithProperties(new Properties(10, new string('a', 201), "key", new Dictionary())) + .Create() + .Should() + .BeParsingFailure("Properties Type length cannot be higher than 200."); + [Fact] public void Build_ShouldSetCallback() => CreateConversationRequest.Build() @@ -114,13 +134,13 @@ public void Build_ShouldSetName() => [Fact] public void Build_ShouldSetProperties() => CreateConversationRequest.Build() - .WithProperties(new Properties(55, "Fake", "hello-there", + .WithProperties(new Properties(55, new string('a', 200), "hello-there", new Dictionary {{"temp1", "123"}, {"temp12", "456"}})) .Create() .Map(request => request.Properties) .Should() .BeSuccess(properties => - properties.Should().BeSome(new Properties(55, "Fake", "hello-there", + properties.Should().BeSome(new Properties(55, new string('a', 200), "hello-there", new Dictionary {{"temp1", "123"}, {"temp12", "456"}}))); } } \ No newline at end of file diff --git a/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs b/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs index a7aea2d96..90bc7c9d8 100644 --- a/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs +++ b/Vonage/Conversations/CreateConversation/CreateConversationRequestBuilder.cs @@ -11,8 +11,11 @@ namespace Vonage.Conversations.CreateConversation; internal class CreateConversationRequestBuilder : IBuilderForOptional { + private const int CallbackEventMask = 200; private const int DisplayNameMaxLength = 50; private const int NameMaxLength = 100; + private const int PropertiesCustomSortKeyMaxLength = 200; + private const int PropertiesTypeMaxLength = 200; private readonly IEnumerable allowedMethods = new[] {HttpMethod.Get, HttpMethod.Post}; private Maybe callback; @@ -35,7 +38,11 @@ public Result Create() => Result VerifyCallbackEventMaskLength(CreateConversationRequest request) => + request.Callback.Match( + some => InputValidation.VerifyLengthLowerOrEqualThan(request, some.EventMask, CallbackEventMask, + $"{nameof(request.Callback)} {nameof(some.EventMask)}"), + () => request); + private Result VerifyCallbackHttpMethod(CreateConversationRequest request) => request.Callback.Match( some => this.allowedMethods.Contains(some.Method) @@ -95,6 +108,20 @@ private static Result VerifyNameLength(CreateConversa request.Name.Match( some => InputValidation.VerifyLengthLowerOrEqualThan(request, some, NameMaxLength, nameof(request.Name)), () => request); + + private static Result VerifyPropertiesCustomSortKeyLength( + CreateConversationRequest request) => + request.Properties.Match( + some => InputValidation.VerifyLengthLowerOrEqualThan(request, some.CustomSortKey, + PropertiesCustomSortKeyMaxLength, + $"{nameof(request.Properties)} {nameof(some.CustomSortKey)}"), + () => request); + + private static Result VerifyPropertiesTypeLength(CreateConversationRequest request) => + request.Properties.Match( + some => InputValidation.VerifyLengthLowerOrEqualThan(request, some.Type, PropertiesTypeMaxLength, + $"{nameof(request.Properties)} {nameof(some.Type)}"), + () => request); } ///