using FluentValidation.TestHelper; using Microsoft.Extensions.Time.Testing; using SIGCM2.Application.Pricing.ChargeableChars.SchedulePrice; namespace SIGCM2.Application.Tests.Pricing.ChargeableChars; /// /// PRC-001 — Validator tests for SchedulePriceChangeCommand. /// Covers: PricePerUnit > 0, ValidFrom >= today_AR. /// Forward-only check (ValidFrom > existing.ValidFrom) is done in handler, not validator. /// public class SchedulePriceChangeCommandValidatorTests { private readonly FakeTimeProvider _time = new(new DateTimeOffset(2026, 4, 20, 12, 0, 0, TimeSpan.Zero)); private readonly SchedulePriceChangeCommandValidator _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 SchedulePriceChangeCommandValidatorTests() { _validator = new SchedulePriceChangeCommandValidator(_time); } private static SchedulePriceChangeCommand ValidCmd() => new( Id: 1L, PricePerUnit: 2.0m, ValidFrom: Tomorrow); // ── 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() { // today is valid — forward-only check vs existing row is done in handler 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); } // ── Id ─────────────────────────────────────────────────────────────────────── [Fact] public void Id_Zero_FailsValidation() { var cmd = ValidCmd() with { Id = 0L }; _validator.TestValidate(cmd).ShouldHaveValidationErrorFor(x => x.Id); } [Fact] public void Id_Positive_Passes() { var cmd = ValidCmd() with { Id = 1L }; _validator.TestValidate(cmd).ShouldNotHaveValidationErrorFor(x => x.Id); } // ── Happy path ──────────────────────────────────────────────────────────────── [Fact] public void ValidCommand_PassesAllRules() { _validator.TestValidate(ValidCmd()).ShouldNotHaveAnyValidationErrors(); } }