feat(application): commands/queries + IChargeableCharConfigService (PRC-001)
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
using FluentValidation.TestHelper;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using SIGCM2.Application.Pricing.ChargeableChars.SchedulePrice;
|
||||
|
||||
namespace SIGCM2.Application.Tests.Pricing.ChargeableChars;
|
||||
|
||||
/// <summary>
|
||||
/// PRC-001 — Validator tests for SchedulePriceChangeCommand.
|
||||
/// Covers: PricePerUnit > 0, ValidFrom >= today_AR.
|
||||
/// Forward-only check (ValidFrom > existing.ValidFrom) is done in handler, not validator.
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user