From 563cf44c605286e47dde82f9701e02318f97c46b Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 1 Jun 2026 09:29:46 -0400 Subject: [PATCH] feat: OptionsValidatorBase --- .../OptionsValidatorBase.cs | 30 +++++++++++++++ .../OptionsValidatorBaseTests.cs | 37 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 ZB.MOM.WW.Configuration/src/ZB.MOM.WW.Configuration/OptionsValidatorBase.cs create mode 100644 ZB.MOM.WW.Configuration/tests/ZB.MOM.WW.Configuration.Tests/OptionsValidatorBaseTests.cs diff --git a/ZB.MOM.WW.Configuration/src/ZB.MOM.WW.Configuration/OptionsValidatorBase.cs b/ZB.MOM.WW.Configuration/src/ZB.MOM.WW.Configuration/OptionsValidatorBase.cs new file mode 100644 index 0000000..c2dc7eb --- /dev/null +++ b/ZB.MOM.WW.Configuration/src/ZB.MOM.WW.Configuration/OptionsValidatorBase.cs @@ -0,0 +1,30 @@ +using Microsoft.Extensions.Options; + +namespace ZB.MOM.WW.Configuration; + +/// +/// Base class for implementations that removes the +/// failure-accumulation plumbing. Override and +/// use the supplied ; the base aggregates ALL failures and returns +/// only when none were recorded. +/// +/// The options type being validated. +public abstract class OptionsValidatorBase : IValidateOptions + where TOptions : class +{ + /// + public ValidateOptionsResult Validate(string? name, TOptions options) + { + ArgumentNullException.ThrowIfNull(options); + var builder = new ValidationBuilder(); + Validate(builder, options); + return builder.IsValid + ? ValidateOptionsResult.Success + : ValidateOptionsResult.Fail(builder.Failures); + } + + /// Records validation failures for on . + /// The accumulator to record failures on. + /// The options instance to validate. + protected abstract void Validate(ValidationBuilder builder, TOptions options); +} diff --git a/ZB.MOM.WW.Configuration/tests/ZB.MOM.WW.Configuration.Tests/OptionsValidatorBaseTests.cs b/ZB.MOM.WW.Configuration/tests/ZB.MOM.WW.Configuration.Tests/OptionsValidatorBaseTests.cs new file mode 100644 index 0000000..1def4df --- /dev/null +++ b/ZB.MOM.WW.Configuration/tests/ZB.MOM.WW.Configuration.Tests/OptionsValidatorBaseTests.cs @@ -0,0 +1,37 @@ +using Microsoft.Extensions.Options; +using ZB.MOM.WW.Configuration; + +namespace ZB.MOM.WW.Configuration.Tests; + +public sealed class OptionsValidatorBaseTests +{ + private sealed class SampleOptions + { + public int Port { get; set; } + public string? Name { get; set; } + } + + private sealed class SampleValidator : OptionsValidatorBase + { + protected override void Validate(ValidationBuilder v, SampleOptions o) + { + v.Port(o.Port, "Sample:Port"); + v.Required(o.Name, "Sample:Name"); + } + } + + [Fact] + public void Success_when_clean() + { + var r = new SampleValidator().Validate(null, new SampleOptions { Port = 8080, Name = "ok" }); + Assert.True(r.Succeeded); + } + + [Fact] + public void Fails_and_reports_all_failures() + { + var r = new SampleValidator().Validate(null, new SampleOptions { Port = 0, Name = "" }); + Assert.True(r.Failed); + Assert.Equal(2, r.Failures!.Count()); + } +}