using System.Collections.Concurrent; using System.Text.RegularExpressions; using Common.Configuration.ContentBlocker; using Shouldly; namespace Infrastructure.Tests.Verticals.ContentBlocker; public class FilenameEvaluatorTests : IClassFixture { private readonly FilenameEvaluatorFixture _fixture; public FilenameEvaluatorTests(FilenameEvaluatorFixture fixture) { _fixture = fixture; } public class PatternTests : FilenameEvaluatorTests { public PatternTests(FilenameEvaluatorFixture fixture) : base(fixture) { } [Fact] public void WhenNoPatterns_ShouldReturnTrue() { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag(); var regexes = new ConcurrentBag(); // Act var result = sut.IsValid("test.txt", BlocklistType.Blacklist, patterns, regexes); // Assert result.ShouldBeTrue(); } [Theory] [InlineData("test.txt", "test.txt", true)] // Exact match [InlineData("test.txt", "*.txt", true)] // End wildcard [InlineData("test.txt", "test.*", true)] // Start wildcard [InlineData("test.txt", "*test*", true)] // Both wildcards [InlineData("test.txt", "other.txt", false)] // No match public void Blacklist_ShouldMatchPatterns(string filename, string pattern, bool shouldBeBlocked) { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag { pattern }; var regexes = new ConcurrentBag(); // Act var result = sut.IsValid(filename, BlocklistType.Blacklist, patterns, regexes); // Assert result.ShouldBe(!shouldBeBlocked); } [Theory] [InlineData("test.txt", "test.txt", true)] // Exact match [InlineData("test.txt", "*.txt", true)] // End wildcard [InlineData("test.txt", "test.*", true)] // Start wildcard [InlineData("test.txt", "*test*", true)] // Both wildcards [InlineData("test.txt", "other.txt", false)] // No match public void Whitelist_ShouldMatchPatterns(string filename, string pattern, bool shouldBeAllowed) { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag { pattern }; var regexes = new ConcurrentBag(); // Act var result = sut.IsValid(filename, BlocklistType.Whitelist, patterns, regexes); // Assert result.ShouldBe(shouldBeAllowed); } [Theory] [InlineData("TEST.TXT", "test.txt")] [InlineData("test.txt", "TEST.TXT")] public void ShouldBeCaseInsensitive(string filename, string pattern) { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag { pattern }; var regexes = new ConcurrentBag(); // Act var result = sut.IsValid(filename, BlocklistType.Blacklist, patterns, regexes); // Assert result.ShouldBeFalse(); } [Fact] public void MultiplePatterns_ShouldMatchAny() { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag { "other.txt", "*.pdf", "test.*" }; var regexes = new ConcurrentBag(); // Act var result = sut.IsValid("test.txt", BlocklistType.Blacklist, patterns, regexes); // Assert result.ShouldBeFalse(); } } public class RegexTests : FilenameEvaluatorTests { public RegexTests(FilenameEvaluatorFixture fixture) : base(fixture) { } [Fact] public void WhenNoRegexes_ShouldReturnTrue() { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag(); var regexes = new ConcurrentBag(); // Act var result = sut.IsValid("test.txt", BlocklistType.Blacklist, patterns, regexes); // Assert result.ShouldBeTrue(); } [Theory] [InlineData(@"test\d+\.txt", "test123.txt", true)] [InlineData(@"test\d+\.txt", "test.txt", false)] public void Blacklist_ShouldMatchRegexes(string pattern, string filename, bool shouldBeBlocked) { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag(); var regexes = new ConcurrentBag { new Regex(pattern, RegexOptions.IgnoreCase) }; // Act var result = sut.IsValid(filename, BlocklistType.Blacklist, patterns, regexes); // Assert result.ShouldBe(!shouldBeBlocked); } [Theory] [InlineData(@"test\d+\.txt", "test123.txt", true)] [InlineData(@"test\d+\.txt", "test.txt", false)] public void Whitelist_ShouldMatchRegexes(string pattern, string filename, bool shouldBeAllowed) { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag(); var regexes = new ConcurrentBag { new Regex(pattern, RegexOptions.IgnoreCase) }; // Act var result = sut.IsValid(filename, BlocklistType.Whitelist, patterns, regexes); // Assert result.ShouldBe(shouldBeAllowed); } [Theory] [InlineData(@"TEST\d+\.TXT", "test123.txt")] [InlineData(@"test\d+\.txt", "TEST123.TXT")] public void ShouldBeCaseInsensitive(string pattern, string filename) { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag(); var regexes = new ConcurrentBag { new Regex(pattern, RegexOptions.IgnoreCase) }; // Act var result = sut.IsValid(filename, BlocklistType.Blacklist, patterns, regexes); // Assert result.ShouldBeFalse(); } } public class CombinedTests : FilenameEvaluatorTests { public CombinedTests(FilenameEvaluatorFixture fixture) : base(fixture) { } [Fact] public void WhenBothPatternsAndRegexes_ShouldMatchBoth() { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag { "*.txt" }; var regexes = new ConcurrentBag { new Regex(@"test\d+", RegexOptions.IgnoreCase) }; // Act var result = sut.IsValid("test123.txt", BlocklistType.Blacklist, patterns, regexes); // Assert result.ShouldBeFalse(); } [Fact] public void WhenPatternMatchesButRegexDoesNot_ShouldReturnFalse() { // Arrange var sut = _fixture.CreateSut(); var patterns = new ConcurrentBag { "*.txt" }; var regexes = new ConcurrentBag { new Regex(@"test\d+", RegexOptions.IgnoreCase) }; // Act var result = sut.IsValid("other.txt", BlocklistType.Whitelist, patterns, regexes); // Assert result.ShouldBeFalse(); } } }