Skip to content

Commit

Permalink
Use file-scoped namespaces.
Browse files Browse the repository at this point in the history
  • Loading branch information
ejball committed Aug 8, 2023
1 parent 9226b54 commit f2bfa57
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 110 deletions.
37 changes: 18 additions & 19 deletions src/Faithlife.DataAnnotations/ValidateObjectAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
using System.ComponentModel.DataAnnotations;

namespace Faithlife.DataAnnotations
namespace Faithlife.DataAnnotations;

/// <summary>
/// Used to validate a property whose type has its own properties with data annotations.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public sealed class ValidateObjectAttribute : ValidationAttribute
{
/// <summary>
/// Used to validate a property whose type has its own properties with data annotations.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public sealed class ValidateObjectAttribute : ValidationAttribute
/// <inheritdoc />
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
/// <inheritdoc />
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (value is null)
return null;
if (value is null)
return null;

var validationResults = ValidatorUtility.GetValidationResults(value);
if (validationResults.Count == 0)
return null;
var validationResults = ValidatorUtility.GetValidationResults(value);
if (validationResults.Count == 0)
return null;

var innerErrorMessage = string.Join(" ", validationResults.Select(x => x.ErrorMessage).Where(x => x is not null));
return new ValidationResult(
errorMessage: $"{FormatErrorMessage(validationContext.DisplayName)}{(innerErrorMessage.Length == 0 ? "" : $" ({innerErrorMessage})")}",
memberNames: validationContext.MemberName is string memberName ? new[] { memberName } : null);
}
var innerErrorMessage = string.Join(" ", validationResults.Select(x => x.ErrorMessage).Where(x => x is not null));
return new ValidationResult(
errorMessage: $"{FormatErrorMessage(validationContext.DisplayName)}{(innerErrorMessage.Length == 0 ? "" : $" ({innerErrorMessage})")}",
memberNames: validationContext.MemberName is string memberName ? new[] { memberName } : null);
}
}
65 changes: 32 additions & 33 deletions src/Faithlife.DataAnnotations/ValidatorUtility.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,42 @@
using System.ComponentModel.DataAnnotations;

namespace Faithlife.DataAnnotations
namespace Faithlife.DataAnnotations;

/// <summary>
/// Helper methods for using <see cref="Validator"/>.
/// </summary>
public static class ValidatorUtility
{
/// <summary>
/// Helper methods for using <see cref="Validator"/>.
/// Returns true if the specified object and its properties are valid.
/// </summary>
public static class ValidatorUtility
/// <exception cref="ArgumentNullException">The value is null.</exception>
public static bool IsValid(object value)
{
/// <summary>
/// Returns true if the specified object and its properties are valid.
/// </summary>
/// <exception cref="ArgumentNullException">The value is null.</exception>
public static bool IsValid(object value)
{
_ = value ?? throw new ArgumentNullException(nameof(value));
return Validator.TryValidateObject(value, new ValidationContext(value), validationResults: null, validateAllProperties: true);
}
_ = value ?? throw new ArgumentNullException(nameof(value));
return Validator.TryValidateObject(value, new ValidationContext(value), validationResults: null, validateAllProperties: true);
}

/// <summary>
/// Validates the specified object and its properties, throwing <see cref="ValidationException"/> if invalid.
/// </summary>
/// <exception cref="ArgumentNullException">The value is null.</exception>
/// <exception cref="ValidationException">The value is invalid.</exception>
public static void Validate(object value)
{
_ = value ?? throw new ArgumentNullException(nameof(value));
Validator.ValidateObject(value, new ValidationContext(value), validateAllProperties: true);
}
/// <summary>
/// Validates the specified object and its properties, throwing <see cref="ValidationException"/> if invalid.
/// </summary>
/// <exception cref="ArgumentNullException">The value is null.</exception>
/// <exception cref="ValidationException">The value is invalid.</exception>
public static void Validate(object value)
{
_ = value ?? throw new ArgumentNullException(nameof(value));
Validator.ValidateObject(value, new ValidationContext(value), validateAllProperties: true);
}

/// <summary>
/// Gets the validation results from validating the specified object and its properties.
/// </summary>
/// <exception cref="ArgumentNullException">The value is null.</exception>
public static IReadOnlyList<ValidationResult> GetValidationResults(object value)
{
_ = value ?? throw new ArgumentNullException(nameof(value));
var validationResults = new List<ValidationResult>();
Validator.TryValidateObject(value, new ValidationContext(value), validationResults, validateAllProperties: true);
return validationResults;
}
/// <summary>
/// Gets the validation results from validating the specified object and its properties.
/// </summary>
/// <exception cref="ArgumentNullException">The value is null.</exception>
public static IReadOnlyList<ValidationResult> GetValidationResults(object value)
{
_ = value ?? throw new ArgumentNullException(nameof(value));
var validationResults = new List<ValidationResult>();
Validator.TryValidateObject(value, new ValidationContext(value), validationResults, validateAllProperties: true);
return validationResults;
}
}
115 changes: 57 additions & 58 deletions tests/Faithlife.DataAnnotations.Tests/ValidatorTests.cs
Original file line number Diff line number Diff line change
@@ -1,77 +1,76 @@
using System.ComponentModel.DataAnnotations;
using NUnit.Framework;

namespace Faithlife.DataAnnotations.Tests
namespace Faithlife.DataAnnotations.Tests;

public class ValidatorTests
{
public class ValidatorTests
[Test]
public void ValidateNull()
{
[Test]
public void ValidateNull()
{
Assert.Throws<ArgumentNullException>(() => ValidatorUtility.GetValidationResults(null!));
}
Assert.Throws<ArgumentNullException>(() => ValidatorUtility.GetValidationResults(null!));
}

[TestCase(false)]
[TestCase(0)]
[TestCase("")]
public void ValidateNotValidatable(object value)
{
Assert.IsTrue(ValidatorUtility.IsValid(value));
Assert.IsEmpty(ValidatorUtility.GetValidationResults(value));
ValidatorUtility.Validate(value);
}
[TestCase(false)]
[TestCase(0)]
[TestCase("")]
public void ValidateNotValidatable(object value)
{
Assert.IsTrue(ValidatorUtility.IsValid(value));
Assert.IsEmpty(ValidatorUtility.GetValidationResults(value));
ValidatorUtility.Validate(value);
}

[Test]
public void ValidateRequired()
{
var validatable = new ValidatableDto();
[Test]
public void ValidateRequired()
{
var validatable = new ValidatableDto();

var results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Required), results.Single().MemberNames.Single());
var exception = Assert.Throws<ValidationException>(() => ValidatorUtility.Validate(validatable));
Assert.AreEqual(nameof(ValidatableDto.Required), exception!.ValidationResult.MemberNames.Single());
var results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Required), results.Single().MemberNames.Single());
var exception = Assert.Throws<ValidationException>(() => ValidatorUtility.Validate(validatable));
Assert.AreEqual(nameof(ValidatableDto.Required), exception!.ValidationResult.MemberNames.Single());

validatable.Required = "";
results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Required), results.Single().MemberNames.Single());
Assert.Throws<ValidationException>(() => ValidatorUtility.Validate(validatable));
validatable.Required = "";
results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Required), results.Single().MemberNames.Single());
Assert.Throws<ValidationException>(() => ValidatorUtility.Validate(validatable));

validatable.Required = " ";
results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Required), results.Single().MemberNames.Single());
Assert.Throws<ValidationException>(() => ValidatorUtility.Validate(validatable));
validatable.Required = " ";
results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Required), results.Single().MemberNames.Single());
Assert.Throws<ValidationException>(() => ValidatorUtility.Validate(validatable));

validatable.Required = "x";
results = ValidatorUtility.GetValidationResults(validatable);
Assert.IsEmpty(results);
ValidatorUtility.Validate(validatable);
}
validatable.Required = "x";
results = ValidatorUtility.GetValidationResults(validatable);
Assert.IsEmpty(results);
ValidatorUtility.Validate(validatable);
}

[Test]
public void ValidateRecursive()
{
var invalid = new ValidatableDto();
var validatable = new ValidatableDto { Required = "x", Validatable = invalid };
[Test]
public void ValidateRecursive()
{
var invalid = new ValidatableDto();
var validatable = new ValidatableDto { Required = "x", Validatable = invalid };

var results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Validatable), results.Single().MemberNames.Single());
var results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Validatable), results.Single().MemberNames.Single());

validatable.Validatable = new ValidatableDto { Required = "x", Validatable = invalid };
results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Validatable), results.Single().MemberNames.Single());
validatable.Validatable = new ValidatableDto { Required = "x", Validatable = invalid };
results = ValidatorUtility.GetValidationResults(validatable);
Assert.AreEqual(nameof(ValidatableDto.Validatable), results.Single().MemberNames.Single());

validatable.Validatable.Validatable = new ValidatableDto { Required = "x" };
results = ValidatorUtility.GetValidationResults(validatable);
Assert.IsEmpty(results);
}
validatable.Validatable.Validatable = new ValidatableDto { Required = "x" };
results = ValidatorUtility.GetValidationResults(validatable);
Assert.IsEmpty(results);
}

private sealed class ValidatableDto
{
[Required]
public string? Required { get; set; }
private sealed class ValidatableDto
{
[Required]
public string? Required { get; set; }

[ValidateObject]
public ValidatableDto? Validatable { get; set; }
}
[ValidateObject]
public ValidatableDto? Validatable { get; set; }
}
}

0 comments on commit f2bfa57

Please sign in to comment.