Files
llm-pii-poc/tests/PiiRedaction.Core.Tests/Redaction/PlaceholderPiiRedactorTests.cs

135 lines
4.0 KiB
C#
Raw Permalink Normal View History

using FluentAssertions;
using PiiRedaction.Core.Models;
using PiiRedaction.Core.Redaction;
namespace PiiRedaction.Core.Tests.Redaction;
[TestFixture]
public sealed class PlaceholderPiiRedactorTests
{
private readonly PlaceholderPiiRedactor _redactor = new();
[Test]
public void Redact_NoEntities_ReturnsOriginalTextAndEmptyMap()
{
const string text = "No PII here.";
var result = _redactor.Redact(text, []);
result.SanitizedText.Should().Be(text);
result.PlaceholderMap.Should().BeEmpty();
}
[Test]
public void Redact_SingleEntity_ReplacesWithTypedPlaceholder()
{
const string text = "Email ravi@test.com end.";
var entities = new[] { Entity(PiiEntityType.Email, "ravi@test.com", 6) };
var result = _redactor.Redact(text, entities);
result.SanitizedText.Should().Be("Email <EMAIL_1> end.");
result.PlaceholderMap["<EMAIL_1>"].Should().Be("ravi@test.com");
}
[Test]
public void Redact_DuplicateSameTypeAndValue_ReusesPlaceholder()
{
const string text = "a@b.co and a@b.co";
var entities = new[]
{
Entity(PiiEntityType.Email, "a@b.co", 0),
Entity(PiiEntityType.Email, "a@b.co", 11)
};
var result = _redactor.Redact(text, entities);
result.SanitizedText.Should().Be("<EMAIL_1> and <EMAIL_1>");
result.PlaceholderMap.Should().HaveCount(1);
}
[Test]
public void Redact_MultipleTypes_AssignsIndependentCounters()
{
const string text = "9876543210 ravi@test.com";
var entities = new[]
{
Entity(PiiEntityType.Phone, "9876543210", 0),
Entity(PiiEntityType.Email, "ravi@test.com", 11)
};
var result = _redactor.Redact(text, entities);
result.SanitizedText.Should().Be("<PHONE_1> <EMAIL_1>");
}
[Test]
public void Redact_MultipleSameTypeDifferentValues_IncrementsCounter()
{
const string text = "Customer Ravi Kumar and Customer Priya Nair";
var entities = new[]
{
Entity(PiiEntityType.Person, "Ravi Kumar", 9),
Entity(PiiEntityType.Person, "Priya Nair", 33)
};
var result = _redactor.Redact(text, entities);
result.SanitizedText.Should().Be("Customer <PERSON_2> and Customer <PERSON_1>");
result.PlaceholderMap.Should().HaveCount(2);
}
[Test]
public void Redact_EntityTypes_UseTypedPlaceholderPrefixes()
{
(PiiEntityType Type, string Prefix)[] cases =
[
(PiiEntityType.Person, "PERSON"),
(PiiEntityType.Email, "EMAIL"),
(PiiEntityType.LoanNumber, "LOAN_NUMBER")
];
foreach (var (type, prefix) in cases)
{
const string value = "VALUE";
var text = $"start {value} end";
var result = _redactor.Redact(text, [Entity(type, value, 6)]);
result.SanitizedText.Should().Contain($"<{prefix}_1>", because: type.ToString());
}
}
[Test]
public void Redact_RightToLeftReplacement_PreservesCorrectOutput()
{
const string text = "AA BB CC";
var entities = new[]
{
Entity(PiiEntityType.Phone, "AA", 0),
Entity(PiiEntityType.Email, "BB", 3),
Entity(PiiEntityType.Pan, "CC", 6)
};
var result = _redactor.Redact(text, entities);
result.SanitizedText.Should().Be("<PHONE_1> <EMAIL_1> <PAN_1>");
}
[TestCase(null)]
[TestCase("")]
[TestCase(" ")]
public void Redact_InvalidText_ThrowsArgumentException(string? text)
{
var action = () => _redactor.Redact(text!, []);
action.Should().Throw<ArgumentException>();
}
[Test]
public void Redact_NullEntities_ThrowsArgumentNullException()
{
var action = () => _redactor.Redact("text", null!);
action.Should().Throw<ArgumentNullException>();
}
private static PiiEntity Entity(PiiEntityType type, string value, int start) =>
new(type, value, start, value.Length, PiiDetectionSource.Regex);
}