using FluentValidation.TestHelper; using Microsoft.Extensions.Time.Testing; using SIGCM2.Application.Pricing.ChargeableChars.Create; using SIGCM2.Domain.Pricing.ChargeableChars; namespace SIGCM2.Application.Tests.Pricing.ChargeableChars; /// /// PRC-001 — Validator tests for CreateChargeableCharConfigCommand. /// Covers: Symbol length, Category enum, PricePerUnit > 0, ValidFrom >= today_AR. /// public class CreateChargeableCharConfigCommandValidatorTests { private readonly FakeTimeProvider _time = new(new DateTimeOffset(2026, 4, 20, 12, 0, 0, TimeSpan.Zero)); private readonly CreateChargeableCharConfigCommandValidator _validator; private static readonly DateOnly Today = new(2026, 4, 20); private static readonly DateOnly Yesterday = new(2026, 4, 19); private static readonly DateOnly Tomorrow = new(2026, 4, 21); public CreateChargeableCharConfigCommandValidatorTests() { _validator = new CreateChargeableCharConfigCommandValidator(_time); } private static CreateChargeableCharConfigCommand ValidCmd() => new( ProductTypeId: null, Symbol: "$", Category: ChargeableCharCategories.Currency, PricePerUnit: 1.0m, ValidFrom: Today); // ── Symbol ─────────────────────────────────────────────────────────────────── [Fact] public void Symbol_Empty_FailsValidation() { var cmd = ValidCmd() with { Symbol = "" }; _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Symbol); } [Fact] public void Symbol_TooLong_FailsValidation() { // max 4 chars var cmd = ValidCmd() with { Symbol = "ABCDE" }; _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Symbol); } [Fact] public void Symbol_SingleChar_Passes() { var cmd = ValidCmd() with { Symbol = "$" }; _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.Symbol); } [Fact] public void Symbol_FourChars_Passes() { var cmd = ValidCmd() with { Symbol = "ABCD" }; _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.Symbol); } // ── Category ───────────────────────────────────────────────────────────────── [Fact] public void Category_Invalid_FailsValidation() { var cmd = ValidCmd() with { Category = "Unknown" }; _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Category); } [Fact] public void Category_Empty_FailsValidation() { var cmd = ValidCmd() with { Category = "" }; _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Category); } [Theory] [InlineData("Currency")] [InlineData("Percentage")] [InlineData("Exclamation")] [InlineData("Question")] [InlineData("Other")] public void Category_ValidValues_Pass(string category) { var cmd = ValidCmd() with { Category = category }; _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.Category); } // ── PricePerUnit ───────────────────────────────────────────────────────────── [Fact] public void PricePerUnit_Zero_FailsValidation() { var cmd = ValidCmd() with { PricePerUnit = 0m }; _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.PricePerUnit); } [Fact] public void PricePerUnit_Negative_FailsValidation() { var cmd = ValidCmd() with { PricePerUnit = -1m }; _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.PricePerUnit); } [Fact] public void PricePerUnit_Positive_Passes() { var cmd = ValidCmd() with { PricePerUnit = 0.01m }; _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.PricePerUnit); } // ── ValidFrom ──────────────────────────────────────────────────────────────── [Fact] public void ValidFrom_InPast_FailsValidation() { var cmd = ValidCmd() with { ValidFrom = Yesterday }; _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.ValidFrom); } [Fact] public void ValidFrom_Today_Passes() { var cmd = ValidCmd() with { ValidFrom = Today }; _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.ValidFrom); } [Fact] public void ValidFrom_Future_Passes() { var cmd = ValidCmd() with { ValidFrom = Tomorrow }; _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.ValidFrom); } // ── Happy path ──────────────────────────────────────────────────────────────── [Fact] public void ValidCommand_PassesAllRules() { _validator.TestValidate(ValidCmd()).ShouldNotHaveAnyValidationErrors(); } }