using FluentAssertions; using PiiRedaction.Core.Detection; using PiiRedaction.Core.Models; namespace PiiRedaction.Core.Tests.Detection; [TestFixture] public sealed class RegexPiiDetectorTests { private readonly RegexPiiDetector _detector = new(); [Test] public void Detect_PositiveEmail_ReturnsEntity() { const string text = "Contact ravi.kumar@gmail.com now."; var entities = _detector.Detect(text); entities.Should().ContainSingle(entity => entity.Type == PiiEntityType.Email && entity.Value == "ravi.kumar@gmail.com" && entity.Source == PiiDetectionSource.Regex); } [Test] public void Detect_PositivePhone_ReturnsTenDigitEntity() { var entities = _detector.Detect("Call 9876543210 today."); entities.Should().ContainSingle(entity => entity.Type == PiiEntityType.Phone && entity.Value == "9876543210" && entity.Source == PiiDetectionSource.Regex); } [TestCase("Aadhaar 1234 5678 9012 linked.", "1234 5678 9012")] [TestCase("Aadhaar 123456789012 linked.", "123456789012")] public void Detect_PositiveAadhaar_ReturnsEntity(string text, string expectedValue) { var entities = _detector.Detect(text); entities.Should().ContainSingle(entity => entity.Type == PiiEntityType.Aadhaar && entity.Value == expectedValue); } [Test] public void Detect_PositivePan_ReturnsUppercaseEntity() { var entities = _detector.Detect("PAN ABCDE1234F verified."); entities.Should().ContainSingle(entity => entity.Type == PiiEntityType.Pan); entities[0].Value.Should().MatchRegex("^[A-Z]{5}\\d{4}[A-Z]$"); } [Test] public void Detect_PositiveCreditCard_ReturnsEntity() { var entities = _detector.Detect("Card 4111-1111-1111-1111 used."); entities.Should().ContainSingle(entity => entity.Type == PiiEntityType.CreditCard); } [TestCase("not-an-email")] [TestCase("@missing.com")] [TestCase("pan abcde1234f")] [TestCase("Number 987654321")] public void Detect_NegativePatterns_ReturnsNoMatch(string text) { _detector.Detect(text).Should().BeEmpty(); } [Test] public void Detect_EmailSpan_HasCorrectIndices() { const string text = "Email ravi@test.com end."; var entities = _detector.Detect(text); var email = entities.Single(entity => entity.Type == PiiEntityType.Email); email.StartIndex.Should().Be(6); email.Length.Should().Be("ravi@test.com".Length); text[email.StartIndex..email.EndIndex].Should().Be("ravi@test.com"); } [TestCase(null)] [TestCase("")] [TestCase(" ")] public void Detect_InvalidInput_ThrowsArgumentException(string? text) { var action = () => _detector.Detect(text!); action.Should().Throw(); } }