From b121fd4d22f00a63a676aba2ef93c900555685ca Mon Sep 17 00:00:00 2001 From: Rushikesh Vyas Date: Fri, 17 Nov 2023 14:16:05 -0500 Subject: [PATCH] Added string enumerable attribute (#39) * Added string enumerable attribute * Fixed unsealed class --- .../ContainsNonEmptyStringAttributeTests.cs | 77 +++++++++++++++++++ .../ContainsNonEmptyStringAttribute.cs | 23 ++++++ .../PublicAPI.Shipped.txt | 3 + 3 files changed, 103 insertions(+) create mode 100644 src/Workleap.ComponentModel.DataAnnotations.Tests/ContainsNonEmptyStringAttributeTests.cs create mode 100644 src/Workleap.ComponentModel.DataAnnotations/ContainsNonEmptyStringAttribute.cs diff --git a/src/Workleap.ComponentModel.DataAnnotations.Tests/ContainsNonEmptyStringAttributeTests.cs b/src/Workleap.ComponentModel.DataAnnotations.Tests/ContainsNonEmptyStringAttributeTests.cs new file mode 100644 index 0000000..679bd48 --- /dev/null +++ b/src/Workleap.ComponentModel.DataAnnotations.Tests/ContainsNonEmptyStringAttributeTests.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Globalization; + +namespace Workleap.ComponentModel.DataAnnotations.Tests; + +public sealed class ContainsNonEmptyStringAttributeTests +{ + [Theory] + [ClassData(typeof(ValidData))] + public void Given_ValidStrings_When_Validate_Then_Valid(object? inputs) + { + var attr = new ContainsNonEmptyStringAttribute(); + Assert.True(attr.IsValid(inputs)); + } + + [Theory] + [ClassData(typeof(InvalidData))] + public void Given_InvalidGuids_When_Validate_Then_Invalid(object? inputs) + { + var attr = new ContainsNonEmptyStringAttribute(); + var result = attr.IsValid(inputs); + Assert.False(result); + } + + [Fact] + public void Validator_TryValidateObject_Returns_The_Expected_Error_Message_When_Validation_Fails() + { + var something = new SomeClass(); + var expectedErrorMessage = string.Format(CultureInfo.InvariantCulture, ContainsNonEmptyStringAttribute.ErrorMessageFormat, nameof(SomeClass.Values)); + + var results = new List(); + var context = new ValidationContext(something, serviceProvider: null, items: null); + var isValid = Validator.TryValidateObject(something, context, results, validateAllProperties: true); + + Assert.False(isValid); + var result = Assert.Single(results); + Assert.NotNull(result.ErrorMessage); + Assert.Equal(expectedErrorMessage, result.ErrorMessage); + } + + private class ValidData : IEnumerable + { + public IEnumerator GetEnumerator() + { + yield return new object?[] { null }; + yield return new object[] { new string[] { "Lorem ipsum dolor sit amet" } }; + yield return new object[] { new string[] { "Lorem ipsum dolor sit amet", "Etiam porta velit non nisi feugiat pulvinar" } }; + yield return new object[] { new string[] { string.Empty, "Lorem ipsum dolor sit amet" } }; + yield return new object[] { new string?[] { default, "Lorem ipsum dolor sit amet" } }; + yield return new object[] { new string[] { "Lorem ipsum dolor sit amet", " " } }; + } + + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); + } + + private class InvalidData : IEnumerable + { + public IEnumerator GetEnumerator() + { + yield return new object[] { new string?[] { string.Empty, default } }; + yield return new object[] { new string?[] { string.Empty } }; + yield return new object[] { new string?[] { default } }; + yield return new object[] { new string[] { " " } }; + } + + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); + } + + private class SomeClass + { + [ContainsNonEmptyString] + public string?[] Values { get; set; } = Array.Empty(); + } +} \ No newline at end of file diff --git a/src/Workleap.ComponentModel.DataAnnotations/ContainsNonEmptyStringAttribute.cs b/src/Workleap.ComponentModel.DataAnnotations/ContainsNonEmptyStringAttribute.cs new file mode 100644 index 0000000..277b51c --- /dev/null +++ b/src/Workleap.ComponentModel.DataAnnotations/ContainsNonEmptyStringAttribute.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; + +namespace Workleap.ComponentModel.DataAnnotations; + +[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] +public sealed class ContainsNonEmptyStringAttribute : ValidationAttribute +{ + internal const string ErrorMessageFormat = "The field {0} must be a collection that contains at least one non-empty String"; + + public ContainsNonEmptyStringAttribute() : base(ErrorMessageFormat) + { + } + + public override bool IsValid(object? value) => value switch + { + null => true, + IEnumerable enumerable => enumerable.Any(x => !string.IsNullOrWhiteSpace(x)), + _ => false, + }; +} \ No newline at end of file diff --git a/src/Workleap.ComponentModel.DataAnnotations/PublicAPI.Shipped.txt b/src/Workleap.ComponentModel.DataAnnotations/PublicAPI.Shipped.txt index 4f4fb8a..93b3cde 100644 --- a/src/Workleap.ComponentModel.DataAnnotations/PublicAPI.Shipped.txt +++ b/src/Workleap.ComponentModel.DataAnnotations/PublicAPI.Shipped.txt @@ -4,6 +4,8 @@ Workleap.ComponentModel.DataAnnotations.ContainsAttribute Workleap.ComponentModel.DataAnnotations.ContainsAttribute.ContainsAttribute(string! text) -> void Workleap.ComponentModel.DataAnnotations.ContainsNonEmptyGuidAttribute Workleap.ComponentModel.DataAnnotations.ContainsNonEmptyGuidAttribute.ContainsNonEmptyGuidAttribute() -> void +Workleap.ComponentModel.DataAnnotations.ContainsNonEmptyStringAttribute +Workleap.ComponentModel.DataAnnotations.ContainsNonEmptyStringAttribute.ContainsNonEmptyStringAttribute() -> void Workleap.ComponentModel.DataAnnotations.EndsWithAttribute Workleap.ComponentModel.DataAnnotations.EndsWithAttribute.EndsWithAttribute(string! text) -> void Workleap.ComponentModel.DataAnnotations.GuidAttribute @@ -46,6 +48,7 @@ Workleap.ComponentModel.DataAnnotations.UrlOfKindAttribute.UrlOfKindAttribute(Sy Workleap.ComponentModel.DataAnnotations.ValidatePropertiesAttribute Workleap.ComponentModel.DataAnnotations.ValidatePropertiesAttribute.ValidatePropertiesAttribute() -> void override Workleap.ComponentModel.DataAnnotations.ContainsNonEmptyGuidAttribute.IsValid(object? value) -> bool +override Workleap.ComponentModel.DataAnnotations.ContainsNonEmptyStringAttribute.IsValid(object? value) -> bool override Workleap.ComponentModel.DataAnnotations.GuidAttribute.FormatErrorMessage(string! name) -> string! override Workleap.ComponentModel.DataAnnotations.GuidAttribute.IsValid(object? value) -> bool override Workleap.ComponentModel.DataAnnotations.NotEmptyAttribute.IsValid(object? value) -> bool