mirror of
https://github.com/SabreTools/SabreTools.Matching.git
synced 2026-02-04 05:36:06 +00:00
Update Extensions and add tests
This commit is contained in:
344
SabreTools.Matching.Test/ExtensionsTests.cs
Normal file
344
SabreTools.Matching.Test/ExtensionsTests.cs
Normal file
@@ -0,0 +1,344 @@
|
||||
using System;
|
||||
using Xunit;
|
||||
|
||||
namespace SabreTools.Matching.Test
|
||||
{
|
||||
public class ExtensionsTests
|
||||
{
|
||||
#region Find All Positions
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
var positions = stack.FindAllPositions([0x01]);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
var positions = stack.FindAllPositions(Array.Empty<byte>());
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02]);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_InvalidStart_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02], start: -1);
|
||||
Assert.Empty(positions);
|
||||
|
||||
positions = stack.FindAllPositions([0x01, 0x02], start: 2);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_InvalidEnd_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02], end: -2);
|
||||
Assert.Empty(positions);
|
||||
|
||||
positions = stack.FindAllPositions([0x01, 0x02], end: 0);
|
||||
Assert.Empty(positions);
|
||||
|
||||
positions = stack.FindAllPositions([0x01, 0x02], end: 2);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02]);
|
||||
int position = Assert.Single(positions);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
var positions = stack.FindAllPositions([0x01, 0x02]);
|
||||
Assert.Empty(positions);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindAllPositions_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
var positions = stack.FindAllPositions([0x01]);
|
||||
Assert.Equal(2, positions.Count);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region First Position
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
int position = stack.FirstPosition([0x01]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.FirstPosition(Array.Empty<byte>());
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.FirstPosition([0x01, 0x02]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_InvalidStart_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.FirstPosition([0x01, 0x02], start: -1);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.FirstPosition([0x01, 0x02], start: 2);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_InvalidEnd_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.FirstPosition([0x01, 0x02], end: -2);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.FirstPosition([0x01, 0x02], end: 0);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.FirstPosition([0x01, 0x02], end: 2);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
int position = stack.FirstPosition([0x01, 0x02]);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
int position = stack.FirstPosition([0x01, 0x02]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FirstPosition_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
int position = stack.FirstPosition([0x01]);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Last Position
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
int position = stack.LastPosition([0x01]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.LastPosition(Array.Empty<byte>());
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.LastPosition([0x01, 0x02]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_InvalidStart_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.LastPosition([0x01, 0x02], start: -1);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.LastPosition([0x01, 0x02], start: 2);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_InvalidEnd_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
int position = stack.LastPosition([0x01, 0x02], end: -2);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.LastPosition([0x01, 0x02], end: 0);
|
||||
Assert.Equal(-1, position);
|
||||
|
||||
position = stack.LastPosition([0x01, 0x02], end: 2);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
int position = stack.LastPosition([0x01, 0x02]);
|
||||
Assert.Equal(0, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
int position = stack.LastPosition([0x01, 0x02]);
|
||||
Assert.Equal(-1, position);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LastPosition_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
int position = stack.LastPosition([0x01]);
|
||||
Assert.Equal(1, position);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Starts With
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
bool found = stack.StartsWith([0x01]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.StartsWith(Array.Empty<byte>());
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.StartsWith([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
bool found = stack.StartsWith([0x01, 0x02]);
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
bool found = stack.StartsWith([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartsWith_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
bool found = stack.StartsWith([0x01]);
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Ends With
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_EmptyStack_NoMatches()
|
||||
{
|
||||
byte[] stack = [];
|
||||
bool found = stack.EndsWith([0x01]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_EmptyNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.EndsWith(Array.Empty<byte>());
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_LongerNeedle_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01];
|
||||
bool found = stack.StartsWith([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_Matching_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x02];
|
||||
bool found = stack.EndsWith([0x01, 0x02]);
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_Mismatch_NoMatches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x03];
|
||||
bool found = stack.EndsWith([0x01, 0x02]);
|
||||
Assert.False(found);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EndsWith_Multiple_Matches()
|
||||
{
|
||||
byte[] stack = [0x01, 0x01];
|
||||
bool found = stack.EndsWith([0x01]);
|
||||
Assert.True(found);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -93,13 +93,21 @@ namespace SabreTools.Matching.Content
|
||||
if (stack == null || stack.Length == 0 || Needle.Length == 0)
|
||||
return -1;
|
||||
|
||||
// If the needle array is larger than the stack array, it can't be contained within
|
||||
if (Needle.Length > stack.Length)
|
||||
// Get the adjusted end value for comparison
|
||||
int end = _end < 0 ? stack.Length : _end;
|
||||
end = end > stack.Length ? stack.Length : end;
|
||||
|
||||
// If the stack window is invalid
|
||||
if (end < _start)
|
||||
return -1;
|
||||
|
||||
// If the needle and stack are identically sized, short-circuit
|
||||
if (Needle.Length == stack.Length)
|
||||
return EqualAt(stack, 0) ? 0 : -1;
|
||||
// If the needle is larger than the stack window, it can't be contained within
|
||||
if (Needle.Length > stack.Length - _start)
|
||||
return -1;
|
||||
|
||||
// If the needle and stack window are identically sized, short-circuit
|
||||
if (Needle.Length == stack.Length - _start)
|
||||
return EqualAt(stack, _start) ? _start : -1;
|
||||
|
||||
// Return based on the direction of search
|
||||
return reverse ? MatchReverse(stack) : MatchForward(stack);
|
||||
@@ -202,13 +210,21 @@ namespace SabreTools.Matching.Content
|
||||
if (stack == null || stack.Length == 0 || Needle.Length == 0)
|
||||
return -1;
|
||||
|
||||
// If the needle array is larger than the stack array, it can't be contained within
|
||||
if (Needle.Length > stack.Length)
|
||||
// Get the adjusted end value for comparison
|
||||
int end = _end < 0 ? (int)stack.Length : _end;
|
||||
end = end > (int)stack.Length ? (int)stack.Length : end;
|
||||
|
||||
// If the stack window is invalid
|
||||
if (end < _start)
|
||||
return -1;
|
||||
|
||||
// If the needle and stack are identically sized, short-circuit
|
||||
if (Needle.Length == stack.Length)
|
||||
return EqualAt(stack, 0) ? 0 : -1;
|
||||
// If the needle is larger than the stack window, it can't be contained within
|
||||
if (Needle.Length > stack.Length - _start)
|
||||
return -1;
|
||||
|
||||
// If the needle and stack window are identically sized, short-circuit
|
||||
if (Needle.Length == stack.Length - _start)
|
||||
return EqualAt(stack, _start) ? _start : -1;
|
||||
|
||||
// Return based on the direction of search
|
||||
return reverse ? MatchReverse(stack) : MatchForward(stack);
|
||||
|
||||
@@ -4,6 +4,7 @@ using SabreTools.Matching.Content;
|
||||
|
||||
namespace SabreTools.Matching
|
||||
{
|
||||
// TODO: Write SequenceEqual equivilent: EqualsExactly
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
@@ -31,16 +32,24 @@ namespace SabreTools.Matching
|
||||
// Get the outgoing list
|
||||
List<int> positions = [];
|
||||
|
||||
// Validate the start and end values
|
||||
if (start < 0 || start >= stack.Length)
|
||||
// If either set is null or empty
|
||||
if (stack.Length == 0 || needle.Length == 0)
|
||||
return positions;
|
||||
if (end < -1 || (end != -1 && end < start) || end > stack.Length)
|
||||
|
||||
// If the needle is longer than the stack
|
||||
if (needle.Length > stack.Length)
|
||||
return positions;
|
||||
|
||||
// Normalize the end value, if necessary
|
||||
if (end == -1)
|
||||
end = stack.Length;
|
||||
|
||||
// Validate the start and end values
|
||||
if (start < 0 || start >= stack.Length)
|
||||
return positions;
|
||||
if (end < -1 || end < start || end > stack.Length)
|
||||
return positions;
|
||||
|
||||
// Loop while there is data to check
|
||||
while (start < end)
|
||||
{
|
||||
@@ -54,7 +63,7 @@ namespace SabreTools.Matching
|
||||
|
||||
// Append the position and reset the start index
|
||||
positions.Add(position);
|
||||
start = position;
|
||||
start = position + 1;
|
||||
}
|
||||
|
||||
return positions;
|
||||
@@ -82,6 +91,14 @@ namespace SabreTools.Matching
|
||||
/// <param name="end">Optional ending position in the stack, defaults to -1 (length of stack)</param>
|
||||
public static int FirstPosition(this byte[] stack, byte?[] needle, int start = 0, int end = -1)
|
||||
{
|
||||
// If either set is null or empty
|
||||
if (stack.Length == 0 || needle.Length == 0)
|
||||
return -1;
|
||||
|
||||
// If the needle is longer than the stack
|
||||
if (needle.Length > stack.Length)
|
||||
return -1;
|
||||
|
||||
var matcher = new ContentMatch(needle, start, end);
|
||||
return matcher.Match(stack, reverse: false);
|
||||
}
|
||||
@@ -108,6 +125,14 @@ namespace SabreTools.Matching
|
||||
/// <param name="end">Optional ending position in the stack, defaults to -1 (length of stack)</param>
|
||||
public static int LastPosition(this byte[] stack, byte?[] needle, int start = 0, int end = -1)
|
||||
{
|
||||
// If either set is null or empty
|
||||
if (stack.Length == 0 || needle.Length == 0)
|
||||
return -1;
|
||||
|
||||
// If the needle is longer than the stack
|
||||
if (needle.Length > stack.Length)
|
||||
return -1;
|
||||
|
||||
var matcher = new ContentMatch(needle, start, end);
|
||||
return matcher.Match(stack, reverse: true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user