diff --git a/src/Core/Resources/ResponseMessages.Designer.cs b/src/Core/Resources/ResponseMessages.Designer.cs
index e300dc1..b8d79e4 100644
--- a/src/Core/Resources/ResponseMessages.Designer.cs
+++ b/src/Core/Resources/ResponseMessages.Designer.cs
@@ -168,6 +168,15 @@ internal static string ObtainedResources {
}
}
+ ///
+ /// Looks up a localized string similar to '{0}' property failed validation. Error was: {1}.
+ ///
+ internal static string PropertyFailedValidation {
+ get {
+ return ResourceManager.GetString("PropertyFailedValidation", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Operation successfully executed.
///
diff --git a/src/Core/Resources/ResponseMessages.es.resx b/src/Core/Resources/ResponseMessages.es.resx
index 362c513..1b1cf83 100644
--- a/src/Core/Resources/ResponseMessages.es.resx
+++ b/src/Core/Resources/ResponseMessages.es.resx
@@ -153,6 +153,9 @@
Recursos obtenidos con éxito
+
+ Propiedad '{0}' falló en la validación. El error fue: {1}
+
Operación ejecutada con éxito
diff --git a/src/Core/Resources/ResponseMessages.resx b/src/Core/Resources/ResponseMessages.resx
index c02d1dd..1eeb07a 100644
--- a/src/Core/Resources/ResponseMessages.resx
+++ b/src/Core/Resources/ResponseMessages.resx
@@ -153,6 +153,9 @@
Resources successfully obtained
+
+ '{0}' property failed validation. Error was: {1}
+
Operation successfully executed
diff --git a/src/Core/SimpleResults.csproj b/src/Core/SimpleResults.csproj
index b8acb05..8b99d11 100644
--- a/src/Core/SimpleResults.csproj
+++ b/src/Core/SimpleResults.csproj
@@ -40,6 +40,7 @@
+
diff --git a/src/FluentValidation/SRFluentValidationResultExtensions.cs b/src/FluentValidation/SRFluentValidationResultExtensions.cs
index 45f6f26..e811b35 100644
--- a/src/FluentValidation/SRFluentValidationResultExtensions.cs
+++ b/src/FluentValidation/SRFluentValidationResultExtensions.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using FluentValidation.Results;
+using SimpleResults.Resources;
namespace SimpleResults;
@@ -15,7 +16,7 @@ public static class SRFluentValidationResultExtensions
///
/// true if the validation result is failed; otherwise false.
///
- public static bool IsFailed(this ValidationResult result)
+ public static bool IsFailed(this ValidationResult result)
=> !result.IsValid;
///
@@ -24,7 +25,13 @@ public static bool IsFailed(this ValidationResult result)
/// The result of running a validator.
/// A collection that contains error messages.
public static IEnumerable AsErrors(this ValidationResult result)
- => result.Errors.Select(failure => failure.ErrorMessage);
+ => result.Errors.Select(GetErrorMessage);
+
+ private static string GetErrorMessage(ValidationFailure failure)
+ => string.Format(
+ ResponseMessages.PropertyFailedValidation,
+ failure.PropertyName,
+ failure.ErrorMessage);
///
/// Represents a validation error that prevents the underlying service from completing.
diff --git a/tests/FluentValidation/FailedValidationTestCases.cs b/tests/FluentValidation/FailedValidationTestCases.cs
new file mode 100644
index 0000000..3f54a07
--- /dev/null
+++ b/tests/FluentValidation/FailedValidationTestCases.cs
@@ -0,0 +1,69 @@
+namespace SimpleResults.Tests.FluentValidation;
+
+public class FailedValidationTestCases : IEnumerable
+{
+ public IEnumerator GetEnumerator()
+ {
+ yield return new object[]
+ {
+ new Order
+ {
+ Customer = string.Empty,
+ Description = string.Empty,
+ DeliveryAddress = default,
+ Details = default
+ },
+ new[]
+ {
+ "'Customer' property failed validation. Error was: 'Customer' must not be empty.",
+ "'Description' property failed validation. Error was: 'Description' must not be empty.",
+ "'DeliveryAddress' property failed validation. Error was: 'Delivery Address' must not be empty.",
+ "'Details' property failed validation. Error was: 'Details' must not be empty."
+ }
+ };
+
+ yield return new object[]
+ {
+ new Order
+ {
+ Customer = string.Empty,
+ Description = string.Empty,
+ DeliveryAddress = new Address
+ {
+ Description = string.Empty,
+ Postcode = string.Empty,
+ Country = string.Empty
+ },
+ Details = new List
+ {
+ new()
+ {
+ Product = string.Empty,
+ Price = 0,
+ Amount = 0
+ },
+ new()
+ {
+ Product = string.Empty,
+ Price = -1,
+ Amount = -1
+ }
+ }
+ },
+ new[]
+ {
+ "'Customer' property failed validation. Error was: 'Customer' must not be empty.",
+ "'Description' property failed validation. Error was: 'Description' must not be empty.",
+ "'DeliveryAddress.Description' property failed validation. Error was: 'Description' must not be empty.",
+ "'DeliveryAddress.Postcode' property failed validation. Error was: 'Postcode' must not be empty.",
+ "'DeliveryAddress.Country' property failed validation. Error was: 'Country' must not be empty.",
+ "'Details[0].Product' property failed validation. Error was: 'Product' must not be empty.",
+ "'Details[0].Price' property failed validation. Error was: 'Price' must be greater than '0'.",
+ "'Details[0].Amount' property failed validation. Error was: 'Amount' must be greater than '0'.",
+ "'Details[1].Product' property failed validation. Error was: 'Product' must not be empty.",
+ "'Details[1].Price' property failed validation. Error was: 'Price' must be greater than '0'.",
+ "'Details[1].Amount' property failed validation. Error was: 'Amount' must be greater than '0'."
+ }
+ };
+ }
+}
diff --git a/tests/FluentValidation/ValidationResultExtensionsTests.cs b/tests/FluentValidation/ValidationResultExtensionsTests.cs
index 47ba214..cd7f577 100644
--- a/tests/FluentValidation/ValidationResultExtensionsTests.cs
+++ b/tests/FluentValidation/ValidationResultExtensionsTests.cs
@@ -32,32 +32,43 @@ public void IsFailed_WhenValidationResultIsSuccess_ShouldReturnsFalse()
actual.Should().BeFalse();
}
- [Test]
- public void AsErrors_WhenValidationResultIsReceived_ShouldReturnsCollectionOfErrorMessages()
+ [TestCaseSource(typeof(FailedValidationTestCases))]
+ public void AsErrors_WhenValidationResultIsReceived_ShouldReturnsCollectionOfErrorMessages(
+ Order order,
+ string[] expectedErrors)
{
// Arrange
- var person = new Person { Name = string.Empty };
- var validator = new PersonValidator();
- ValidationResult result = validator.Validate(person);
- var expectedCollection = new[]
- {
- "'Name' must not be empty."
- };
+ var validator = new OrderValidator();
+ ValidationResult result = validator.Validate(order);
// Act
IEnumerable actual = result.AsErrors();
// Assert
- actual.Should().BeEquivalentTo(expectedCollection);
+ actual.Should().BeEquivalentTo(expectedErrors);
}
[Test]
public void AsErrors_WhenThereAreNoErrors_ShouldReturnsEmptyCollection()
{
// Arrange
- var person = new Person { Name = "Alice" };
- var validator = new PersonValidator();
- ValidationResult result = validator.Validate(person);
+ var order = new Order
+ {
+ Customer = "Bob",
+ Description = "Test",
+ DeliveryAddress = new Address { Description = "D", Postcode = "P", Country = "C" },
+ Details = new List
+ {
+ new()
+ {
+ Product = "P",
+ Price = 5000,
+ Amount = 2
+ }
+ }
+ };
+ var validator = new OrderValidator();
+ ValidationResult result = validator.Validate(order);
// Act
IEnumerable actual = result.AsErrors();
@@ -76,7 +87,7 @@ public void Invalid_WhenResultIsInvalidWithoutMessage_ShouldReturnsResultObject(
var expectedMessage = ResponseMessages.ValidationErrors;
var expectedErrors = new[]
{
- "'Name' must not be empty."
+ "'Name' property failed validation. Error was: 'Name' must not be empty."
};
// Act
@@ -100,7 +111,7 @@ public void Invalid_WhenResultIsInvalidWithMessage_ShouldReturnsResultObject()
var expectedMessage = "Error";
var expectedErrors = new[]
{
- "'Name' must not be empty."
+ "'Name' property failed validation. Error was: 'Name' must not be empty."
};
// Act
diff --git a/tests/FluentValidation/Validators/DeliveryAddressValidator.cs b/tests/FluentValidation/Validators/DeliveryAddressValidator.cs
new file mode 100644
index 0000000..db4940a
--- /dev/null
+++ b/tests/FluentValidation/Validators/DeliveryAddressValidator.cs
@@ -0,0 +1,18 @@
+namespace SimpleResults.Tests.FluentValidation.Validators;
+
+public class Address
+{
+ public string Description { get; init; }
+ public string Country { get; init; }
+ public string Postcode { get; init; }
+}
+
+public class DeliveryAddressValidator : AbstractValidator
+{
+ public DeliveryAddressValidator()
+ {
+ RuleFor(d => d.Description).NotEmpty();
+ RuleFor(d => d.Country).NotEmpty();
+ RuleFor(d => d.Postcode).NotEmpty();
+ }
+}
diff --git a/tests/FluentValidation/Validators/OrderDetailValidator.cs b/tests/FluentValidation/Validators/OrderDetailValidator.cs
new file mode 100644
index 0000000..2f0b7b4
--- /dev/null
+++ b/tests/FluentValidation/Validators/OrderDetailValidator.cs
@@ -0,0 +1,18 @@
+namespace SimpleResults.Tests.FluentValidation.Validators;
+
+public class OrderDetail
+{
+ public string Product { get; init; }
+ public int Amount { get; init; }
+ public double Price { get; init; }
+}
+
+public class OrderDetailValidator : AbstractValidator
+{
+ public OrderDetailValidator()
+ {
+ RuleFor(o => o.Product).NotEmpty();
+ RuleFor(o => o.Amount).GreaterThan(0);
+ RuleFor(o => o.Price).GreaterThan(0);
+ }
+}
diff --git a/tests/FluentValidation/Validators/OrderValidator.cs b/tests/FluentValidation/Validators/OrderValidator.cs
new file mode 100644
index 0000000..6ccb9ee
--- /dev/null
+++ b/tests/FluentValidation/Validators/OrderValidator.cs
@@ -0,0 +1,23 @@
+namespace SimpleResults.Tests.FluentValidation.Validators;
+
+public class Order
+{
+ public string Customer { get; init; }
+ public string Description { get; init; }
+ public Address DeliveryAddress { get; init; }
+ public IEnumerable Details { get; init; }
+}
+
+public class OrderValidator : AbstractValidator
+{
+ public OrderValidator()
+ {
+ RuleFor(o => o.Customer).NotEmpty();
+ RuleFor(o => o.Description).NotEmpty();
+ RuleFor(o => o.DeliveryAddress)
+ .NotEmpty()
+ .SetValidator(new DeliveryAddressValidator());
+ RuleFor(o => o.Details).NotEmpty();
+ RuleForEach(o => o.Details).SetValidator(new OrderDetailValidator());
+ }
+}
diff --git a/tests/FluentValidation/PersonValidator.cs b/tests/FluentValidation/Validators/PersonValidator.cs
similarity index 78%
rename from tests/FluentValidation/PersonValidator.cs
rename to tests/FluentValidation/Validators/PersonValidator.cs
index 0f05dbb..de80230 100644
--- a/tests/FluentValidation/PersonValidator.cs
+++ b/tests/FluentValidation/Validators/PersonValidator.cs
@@ -1,4 +1,4 @@
-namespace SimpleResults.Tests.FluentValidation;
+namespace SimpleResults.Tests.FluentValidation.Validators;
public class PersonValidator : AbstractValidator
{
diff --git a/tests/GlobalUsings.cs b/tests/GlobalUsings.cs
index b080ef2..14b6883 100644
--- a/tests/GlobalUsings.cs
+++ b/tests/GlobalUsings.cs
@@ -1,5 +1,6 @@
global using System.Globalization;
global using System.Text.Json;
+global using System.Collections;
global using NUnit.Framework;
global using FluentAssertions;
global using FluentValidation;
@@ -8,4 +9,5 @@
global using Microsoft.AspNetCore.Http;
global using Microsoft.AspNetCore.Http.HttpResults;
global using Microsoft.AspNetCore.Mvc.Filters;
-global using SimpleResults.Resources;
\ No newline at end of file
+global using SimpleResults.Resources;
+global using SimpleResults.Tests.FluentValidation.Validators;
\ No newline at end of file
diff --git a/tests/Utils/TestFixtureProjectSetup.cs b/tests/Utils/TestFixtureProjectSetup.cs
index 80dad29..f0057c8 100644
--- a/tests/Utils/TestFixtureProjectSetup.cs
+++ b/tests/Utils/TestFixtureProjectSetup.cs
@@ -7,6 +7,6 @@ public class TestFixtureProjectSetup
public void RunBeforeAllTestFixtures()
{
// Allows to load the default resource in English.
- Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
+ Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en");
}
}