From f10585aa3270a8d7ce38d94dfc748d72d8d949b9 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sun, 24 Nov 2024 23:50:02 -0500 Subject: [PATCH] Update PathMatch and add tests --- .../Paths/PathMatchTests.cs | 285 ++++++++++++++++++ SabreTools.Matching/Paths/PathMatch.cs | 35 ++- 2 files changed, 305 insertions(+), 15 deletions(-) create mode 100644 SabreTools.Matching.Test/Paths/PathMatchTests.cs diff --git a/SabreTools.Matching.Test/Paths/PathMatchTests.cs b/SabreTools.Matching.Test/Paths/PathMatchTests.cs new file mode 100644 index 0000000..333acb2 --- /dev/null +++ b/SabreTools.Matching.Test/Paths/PathMatchTests.cs @@ -0,0 +1,285 @@ +using System; +using System.Collections.Generic; +using System.IO; +using SabreTools.Matching.Paths; +using Xunit; + +namespace SabreTools.Matching.Test.Paths +{ + public class PathMatchTests + { + [Fact] + public void InvalidNeedleThrowsException() + { + Assert.Throws(() => new PathMatch(string.Empty)); + } + + #region Array + + [Fact] + public void NullArrayReturnsNoMatch() + { + var pm = new PathMatch("test"); + string? actual = pm.Match((string[]?)null); + Assert.Null(actual); + } + + [Fact] + public void EmptyArrayReturnsNoMatch() + { + var pm = new PathMatch("test"); + string? actual = pm.Match(Array.Empty()); + Assert.Null(actual); + } + + [Fact] + public void SingleItemArrayMatchingReturnsMatch() + { + string needle = "test"; + string[] stack = [needle]; + var pm = new PathMatch(needle); + + string? actual = pm.Match(stack); + Assert.Equal(needle, actual); + } + + [Fact] + public void SingleItemArrayMismatchedReturnsNoMatch() + { + string needle = "test"; + string[] stack = ["not"]; + var pm = new PathMatch(needle); + + string? actual = pm.Match(stack); + Assert.Null(actual); + } + + [Fact] + public void MultiItemArrayMatchingReturnsMatch() + { + string needle = "test"; + string[] stack = ["not", needle, "far"]; + var pm = new PathMatch(needle); + + string? actual = pm.Match(stack); + Assert.Equal(needle, actual); + } + + [Fact] + public void MultiItemArrayMismatchedReturnsNoMatch() + { + string needle = "test"; + string[] stack = ["not", "too", "far"]; + var pm = new PathMatch(needle); + + string? actual = pm.Match(stack); + Assert.Null(actual); + } + + #endregion + + #region List + + [Fact] + public void NullListReturnsNoMatch() + { + var pm = new PathMatch("test"); + string? actual = pm.Match((List?)null); + Assert.Null(actual); + } + + [Fact] + public void EmptyListReturnsNoMatch() + { + var pm = new PathMatch("test"); + string? actual = pm.Match(new List()); + Assert.Null(actual); + } + + [Fact] + public void SingleItemListMatchingReturnsMatch() + { + string needle = "test"; + List stack = [needle]; + var pm = new PathMatch(needle); + + string? actual = pm.Match(stack); + Assert.Equal(needle, actual); + } + + [Fact] + public void SingleItemListMismatchedReturnsNoMatch() + { + string needle = "test"; + List stack = ["not"]; + var pm = new PathMatch(needle); + + string? actual = pm.Match(stack); + Assert.Null(actual); + } + + [Fact] + public void MultiItemListMatchingReturnsMatch() + { + string needle = "test"; + List stack = ["not", needle, "far"]; + var pm = new PathMatch(needle); + + string? actual = pm.Match(stack); + Assert.Equal(needle, actual); + } + + [Fact] + public void MultiItemListMismatchedReturnsNoMatch() + { + string needle = "test"; + List stack = ["not", "too", "far"]; + var pm = new PathMatch(needle); + + string? actual = pm.Match(stack); + Assert.Null(actual); + } + + #endregion + + #region Match Case + + [Fact] + public void MatchCaseEqualReturnsMatch() + { + string needle = "test"; + List stack = [needle]; + var pm = new PathMatch(needle, matchCase: true); + + string? actual = pm.Match(stack); + Assert.Equal(needle, actual); + } + + [Fact] + public void NoMatchCaseEqualReturnsMatch() + { + string needle = "test"; + List stack = [needle]; + var pm = new PathMatch(needle, matchCase: false); + + string? actual = pm.Match(stack); + Assert.Equal(needle, actual); + } + + [Fact] + public void MatchCaseInequalReturnsNoMatch() + { + string needle = "test"; + List stack = [needle.ToUpperInvariant()]; + var pm = new PathMatch(needle, matchCase: true); + + string? actual = pm.Match(stack); + Assert.Null(actual); + } + + [Fact] + public void NoMatchCaseInequalReturnsMatch() + { + string needle = "test"; + List stack = [needle.ToUpperInvariant()]; + var pm = new PathMatch(needle, matchCase: false); + + string? actual = pm.Match(stack); + Assert.Equal(needle.ToUpperInvariant(), actual); + } + + [Fact] + public void MatchCaseContainsReturnsMatch() + { + string needle = "test"; + List stack = [$"prefix_{needle}_postfix"]; + var pm = new PathMatch(needle, matchCase: true); + + string? actual = pm.Match(stack); + Assert.Equal($"prefix_{needle}_postfix", actual); + } + + [Fact] + public void NoMatchCaseContainsReturnsMatch() + { + string needle = "test"; + List stack = [$"prefix_{needle}_postfix"]; + var pm = new PathMatch(needle, matchCase: false); + + string? actual = pm.Match(stack); + Assert.Equal($"prefix_{needle}_postfix", actual); + } + + #endregion + + #region Use Ends With + + [Fact] + public void EndsWithEqualReturnsMatch() + { + string needle = "test"; + List stack = [needle]; + var pm = new PathMatch(needle, useEndsWith: true); + + string? actual = pm.Match(stack); + Assert.Equal(needle, actual); + } + + [Fact] + public void NoEndsWithEqualReturnsMatch() + { + string needle = "test"; + List stack = [needle]; + var pm = new PathMatch(needle, useEndsWith: false); + + string? actual = pm.Match(stack); + Assert.Equal(needle, actual); + } + + [Fact] + public void EndsWithInequalReturnsMatch() + { + string needle = "test"; + List stack = [needle.ToUpperInvariant()]; + var pm = new PathMatch(needle, useEndsWith: true); + + string? actual = pm.Match(stack); + Assert.Equal(needle.ToUpperInvariant(), actual); + } + + [Fact] + public void NoEndsWithInequalReturnsMatch() + { + string needle = "test"; + List stack = [needle.ToUpperInvariant()]; + var pm = new PathMatch(needle, useEndsWith: false); + + string? actual = pm.Match(stack); + Assert.Equal(needle.ToUpperInvariant(), actual); + } + + [Fact] + public void EndsWithContainsReturnsNoMatch() + { + string needle = "test"; + List stack = [$"prefix_{needle}_postfix"]; + var pm = new PathMatch(needle, useEndsWith: true); + + string? actual = pm.Match(stack); + Assert.Null(actual); + } + + [Fact] + public void NoEndsWithContainsReturnsMatch() + { + string needle = "test"; + List stack = [$"prefix_{needle}_postfix"]; + var pm = new PathMatch(needle, useEndsWith: false); + + string? actual = pm.Match(stack); + Assert.Equal($"prefix_{needle}_postfix", actual); + } + + #endregion + } +} \ No newline at end of file diff --git a/SabreTools.Matching/Paths/PathMatch.cs b/SabreTools.Matching/Paths/PathMatch.cs index 8156f69..36703be 100644 --- a/SabreTools.Matching/Paths/PathMatch.cs +++ b/SabreTools.Matching/Paths/PathMatch.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.IO; namespace SabreTools.Matching.Paths { @@ -10,29 +11,33 @@ namespace SabreTools.Matching.Paths /// /// String to match /// - public string? Needle { get; } + public string Needle { get; } /// - /// Match exact casing instead of invariant + /// Match casing instead of invariant /// - public bool MatchExact { get; } + private readonly bool _matchCase; /// /// Match that values end with the needle and not just contains /// - public bool UseEndsWith { get; } + private readonly bool _useEndsWith; /// /// Constructor /// /// String representing the search - /// True to match exact casing, false otherwise - /// True to match the end only, false for all contents - public PathMatch(string? needle, bool matchExact = false, bool useEndsWith = false) + /// True to match exact casing, false otherwise + /// True to match the end only, false for contains + public PathMatch(string needle, bool matchCase = false, bool useEndsWith = false) { + // Validate the inputs + if (needle.Length == 0) + throw new InvalidDataException(nameof(needle)); + Needle = needle; - MatchExact = matchExact; - UseEndsWith = useEndsWith; + _matchCase = matchCase; + _useEndsWith = useEndsWith; } #region Matching @@ -40,7 +45,7 @@ namespace SabreTools.Matching.Paths /// /// Get if this match can be found in a stack /// - /// List of strings to search for the given content + /// Array of strings to search for the given content /// Matched item on success, null on error public string? Match(string[]? stack) => Match(stack == null ? null : new List(stack)); @@ -53,20 +58,20 @@ namespace SabreTools.Matching.Paths public string? Match(List? stack) { // If either array is null or empty, we can't do anything - if (stack == null || Needle == null || Needle.Length == 0) + if (stack == null || stack.Count == 0 || Needle.Length == 0) return null; // Preprocess the needle, if necessary - string procNeedle = MatchExact ? Needle : Needle.ToLowerInvariant(); + string procNeedle = _matchCase ? Needle : Needle.ToLowerInvariant(); foreach (string stackItem in stack) { // Preprocess the stack item, if necessary - string procStackItem = MatchExact ? stackItem : stackItem.ToLowerInvariant(); + string procStackItem = _matchCase ? stackItem : stackItem.ToLowerInvariant(); - if (UseEndsWith && procStackItem.EndsWith(procNeedle)) + if (_useEndsWith && procStackItem.EndsWith(procNeedle)) return stackItem; - else if (!UseEndsWith && procStackItem.Contains(procNeedle)) + else if (!_useEndsWith && procStackItem.Contains(procNeedle)) return stackItem; }