- WordCounterService: pure domain service, 7-step algorithm (null/empty fast path → length check → emoji detection via Rune.EnumerateRunes → count specials before replace → replace specials+hyphens → collapse whitespace → tokenize) - WordCountResult: sealed record with TotalWords + IReadOnlyDictionary<string,int> SpecialCharCounts - 4 domain exceptions extending DomainException: EmojiDetectedException, WordCountValidationException, ChargeableCharConfigInvalidException, ChargeableCharConfigForwardOnlyException - ChargeableCharConfig: rich entity with Create factory (invariants), Rehydrate reconstructor, ScheduleNewPrice (forward-only, returns new entity), Deactivate (idempotent) - ChargeableCharCategories: enum-as-string constants (Currency, Percentage, Exclamation, Question, Other) - DomainTimeProviderExtensions: internal GetArgentinaToday helper (mirrors Application.Common without creating Domain→Application dependency) - 60 new tests: 25 golden cases all GREEN, 12 entity invariant tests, 12 exception tests, 5 WordCountResult tests, 6 ChargeableCharConfig entity tests
57 lines
1.8 KiB
C#
57 lines
1.8 KiB
C#
using FluentAssertions;
|
|
using SIGCM2.Domain.Pricing.WordCounter;
|
|
|
|
namespace SIGCM2.Application.Tests.Domain.Pricing.WordCounter;
|
|
|
|
/// <summary>
|
|
/// PRC-001 — T2.2 Domain unit tests for WordCountResult value object.
|
|
/// </summary>
|
|
public sealed class WordCountResultTests
|
|
{
|
|
[Fact]
|
|
public void WordCountResult_RecordEquality_SameValues_AreEqual()
|
|
{
|
|
var dictA = new Dictionary<string, int> { ["Currency"] = 1 };
|
|
var dictB = new Dictionary<string, int> { ["Currency"] = 1 };
|
|
|
|
var a = new WordCountResult(3, dictA);
|
|
var b = new WordCountResult(3, dictB);
|
|
|
|
// Records compare by value — TotalWords and SpecialCharCounts ref equality
|
|
// (not deep dict equality for records), but TotalWords equality is guaranteed.
|
|
a.TotalWords.Should().Be(b.TotalWords);
|
|
}
|
|
|
|
[Fact]
|
|
public void WordCountResult_SpecialCharCounts_IsIReadOnlyDictionary()
|
|
{
|
|
var result = new WordCountResult(0, new Dictionary<string, int>());
|
|
|
|
result.SpecialCharCounts.Should().BeAssignableTo<IReadOnlyDictionary<string, int>>();
|
|
}
|
|
|
|
[Fact]
|
|
public void WordCountResult_MissingKey_ReturnsZeroViaGetValueOrDefault()
|
|
{
|
|
var result = new WordCountResult(3, new Dictionary<string, int> { ["Currency"] = 1 });
|
|
|
|
result.SpecialCharCounts.GetValueOrDefault("Percentage").Should().Be(0);
|
|
}
|
|
|
|
[Fact]
|
|
public void WordCountResult_EmptySpecialCharCounts_ReturnsEmpty()
|
|
{
|
|
var result = new WordCountResult(0, new Dictionary<string, int>());
|
|
|
|
result.SpecialCharCounts.Should().BeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void WordCountResult_TotalWords_IsCorrect()
|
|
{
|
|
var result = new WordCountResult(5, new Dictionary<string, int>());
|
|
|
|
result.TotalWords.Should().Be(5);
|
|
}
|
|
}
|