Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;
using System.Text.RegularExpressions;

namespace Exceptionless.DateTimeExtensions.FormatParsers.PartParsers;

[Priority(1)]
public class WildcardPartParser : IPartParser
{
private static readonly Regex _wildCardRegex = new(@"\G\s*\*(?=\s|\]|\}|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);

public Regex Regex => _wildCardRegex;

public DateTimeOffset? Parse(Match match, DateTimeOffset relativeBaseTime, bool isUpperLimit)
{
if (!match.Success)
return null;

return isUpperLimit ? DateTimeOffset.MaxValue : DateTimeOffset.MinValue;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ namespace Exceptionless.DateTimeExtensions.FormatParsers;
[Priority(25)]
public class TwoPartFormatParser : IFormatParser
{
private static readonly Regex _beginRegex = new(@"^\s*");
private static readonly Regex _beginRegex = new(@"^\s*(?:[\[\{])?\s*");
private static readonly Regex _delimiterRegex = new(@"\G(?:\s*-\s*|\s+TO\s+)", RegexOptions.IgnoreCase);
private static readonly Regex _endRegex = new(@"\G\s*$");
private static readonly Regex _endRegex = new(@"\G\s*(?:[\]\}])?\s*$");

public TwoPartFormatParser()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Exceptionless.DateTimeExtensions.FormatParsers.PartParsers;
using Microsoft.Extensions.Logging;
using Xunit;
using Xunit.Abstractions;

namespace Exceptionless.DateTimeExtensions.Tests.FormatParsers.PartParsers;

public class WildcardPartParserTests : PartParserTestsBase
{
public WildcardPartParserTests(ITestOutputHelper output) : base(output) { }

[Theory]
[MemberData(nameof(ParseInputs))]
public void ParseInput(string input, bool isUpperLimit, DateTimeOffset? expected)
{
var parser = new WildcardPartParser();
_logger.LogInformation("Testing input: '{Input}', IsUpperLimit: {IsUpperLimit}, Expected: {Expected}", input, isUpperLimit, expected);

var match = parser.Regex.Match(input);
_logger.LogInformation("Regex match success: {Success}, Value: '{Value}', Index: {Index}, Length: {Length}", match.Success, match.Value, match.Index, match.Length);

var result = parser.Parse(match, _now, isUpperLimit);
_logger.LogInformation("Parse result: {Result}", result);

if (expected == null)
{
Assert.Null(result);
}
else
{
Assert.NotNull(result);
Assert.Equal(expected.Value.DateTime, result.Value.DateTime);
}
}

public static IEnumerable<object[]> ParseInputs
{
get
{
return new[]
{
// Valid wildcard inputs
new object[] { "*", false, DateTimeOffset.MinValue },
new object[] { "*", true, DateTimeOffset.MaxValue },
new object[] { " * ", false, DateTimeOffset.MinValue },
new object[] { " * ", true, DateTimeOffset.MaxValue },
new object[] { " * ", false, DateTimeOffset.MinValue },
new object[] { " * ", true, DateTimeOffset.MaxValue },

// Invalid inputs (patterns that should not match a complete wildcard)
new object[] { "blah", false, null },
new object[] { "blah", true, null },
new object[] { "2012", false, null },
new object[] { "2012", true, null },
new object[] { "**", false, null },

// This should match the first * in a two-part context like "* *"
new object[] { "* *", false, DateTimeOffset.MinValue },
};
}
}

[Fact]
public void RegexPatternTest()
{
var parser = new WildcardPartParser();
var regex = parser.Regex;

_logger.LogInformation("Regex pattern: {Pattern}", regex);

// Test various inputs
var testInputs = new[] { "*", " * ", " * ", "blah", "2012", "**", "* *", "" };

foreach (var input in testInputs)
{
var match = regex.Match(input);
_logger.LogInformation("Input: '{Input}' -> Success: {Success}, Value: '{Value}', Index: {Index}, Length: {Length}", input, match.Success, match.Value, match.Index, match.Length);
}
}

[Fact]
public void TestInTwoPartContext()
{
var parser = new WildcardPartParser();

// Test how it behaves in a two-part parsing context
var inputs = new[] { "* TO 2013", "2012 TO *", "[* TO 2013]", "{2012 TO *}" };

foreach (var input in inputs)
{
_logger.LogInformation("Testing two-part context for: '{Input}'", input);

// Test parsing at the beginning
var match = parser.Regex.Match(input, 0);
_logger.LogInformation(" At position 0: Success: {Success}, Value: '{Value}', Index: {Index}, Length: {Length}", match.Success, match.Value, match.Index, match.Length);

// Test parsing after bracket
if (input.StartsWith("[") || input.StartsWith("{"))
{
match = parser.Regex.Match(input, 1);
_logger.LogInformation(" At position 1: Success: {Success}, Value: '{Value}', Index: {Index}, Length: {Length}", match.Success, match.Value, match.Index, match.Length);
}

// Find TO and test parsing after it
var toIndex = input.IndexOf(" TO ", StringComparison.OrdinalIgnoreCase);
if (toIndex >= 0)
{
var afterTo = toIndex + 4;
match = parser.Regex.Match(input, afterTo);
_logger.LogInformation(" After TO at position {Position}: Success: {Success}, Value: '{Value}', Index: {Index}, Length: {Length}", afterTo, match.Success, match.Value, match.Index, match.Length);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,32 @@ public static IEnumerable<object[]> Inputs
get
{
return new[] {
// Original dash delimiter syntax
new object[] { "2012-2013", _now.ChangeYear(2012).StartOfYear(), _now.ChangeYear(2013).EndOfYear() },
new object[] { "5 days ago - now", _now.SubtractDays(5).StartOfDay(), _now },
new object[] { "jan-feb", _now.ChangeMonth(1).StartOfMonth(), _now.ChangeMonth(2).EndOfMonth() },
new object[] { "now-this feb", _now, _now.AddYears(1).ChangeMonth(2).EndOfMonth() },

// TO delimiter syntax (case-insensitive)
new object[] { "2012 TO 2013", _now.ChangeYear(2012).StartOfYear(), _now.ChangeYear(2013).EndOfYear() },
new object[] { "jan to feb", _now.ChangeMonth(1).StartOfMonth(), _now.ChangeMonth(2).EndOfMonth() },
new object[] { "5 days ago TO now", _now.SubtractDays(5).StartOfDay(), _now },

// Elasticsearch bracket syntax
new object[] { "[2012 TO 2013]", _now.ChangeYear(2012).StartOfYear(), _now.ChangeYear(2013).EndOfYear() },
new object[] { "{jan TO feb}", _now.ChangeMonth(1).StartOfMonth(), _now.ChangeMonth(2).EndOfMonth() },
new object[] { "[2012-2013]", _now.ChangeYear(2012).StartOfYear(), _now.ChangeYear(2013).EndOfYear() },

// Wildcard support
new object[] { "* TO 2013", DateTime.MinValue, _now.ChangeYear(2013).EndOfYear() },
new object[] { "2012 TO *", _now.ChangeYear(2012).StartOfYear(), DateTime.MaxValue},
new object[] { "[* TO 2013]", DateTime.MinValue, _now.ChangeYear(2013).EndOfYear() },
new object[] { "{2012 TO *}", _now.ChangeYear(2012).StartOfYear(), DateTime.MaxValue },

// Invalid inputs
new object[] { "blah", null, null },
new object[] { "blah blah", null, null }
new object[] { "[invalid", null, null },
new object[] { "invalid}", null, null }
};
}
}
Expand Down