mirror of
https://github.com/rmcrackan/Libation.git
synced 2026-03-30 12:53:45 -04:00
- Inspect exception on regexp timeout
- special tests for checks with whitespace - Escaping allows whitespace at the edges
This commit is contained in:
@@ -166,11 +166,11 @@ public partial class ConditionalTagCollection<TClass>(bool caseSensitive = true)
|
||||
|
||||
var match = CheckRegex().Match(checkString);
|
||||
|
||||
var valStr = match.Groups["val"].Value;
|
||||
var valStr = Unescape(match.Groups["val"]) ?? "";
|
||||
var iVal = -1;
|
||||
var isNumericalOperator = match.Groups["num_op"].Success && int.TryParse(valStr, out iVal);
|
||||
|
||||
var checkItem = match.Groups["op"].ValueSpan switch
|
||||
var checkItem = Unescape(match.Groups["op"]) switch
|
||||
{
|
||||
"=" or "" => (v, culture) => VComparedToStr(v, culture, valStr) == 0,
|
||||
"!=" or "!" => (v, culture) => VComparedToStr(v, culture, valStr) != 0,
|
||||
@@ -300,21 +300,24 @@ public partial class ConditionalTagCollection<TClass>(bool caseSensitive = true)
|
||||
var getBool = CreateConditionExpression(
|
||||
exactName,
|
||||
matchData.GetValueOrDefault("property")?.Value,
|
||||
Unescape(matchData.GetValueOrDefault("check")));
|
||||
matchData.GetValueOrDefault("check")?.Value);
|
||||
// Unescape(matchData.GetValueOrDefault("check")));
|
||||
return matchData["not"].Success ? Expression.Not(getBool) : getBool;
|
||||
}
|
||||
|
||||
[GeneratedRegex("""
|
||||
(?x) # option x: ignore all unescaped whitespace in pattern and allow comments starting with #
|
||||
^\s* # anchor at start of line trimming leading whitespace
|
||||
(?<op> # capture operator in <op> and <num_op>
|
||||
(?<num_op>\#=|\#!=|\#?>=|\#?>|\#?<=|\#?<) # - numerical operators start with a # and might be omitted if unique
|
||||
| ~|!=?|=? # - string comparison operators including ~ for regexp. No operator is like =
|
||||
) \s* # ignore space between operator and value
|
||||
(?<val>(?(num_op) # capture value in <val>
|
||||
\d+ # - numerical operators have to be followed by a number
|
||||
| .*? ) # - string for comparison. May be empty. Non-greedy capture resulting in no whitespace at the end
|
||||
)\s*$ # trimming up to the end
|
||||
(?x) # option x: ignore all unescaped whitespace in pattern and allow comments starting with #
|
||||
^\s* # anchor at start of line trimming leading whitespace
|
||||
(?<op>(?<num_op> # capture operator in <op> and <num_op> with every char escapable
|
||||
\\?\#(?:\\?!)?\\?= # - numerical operators: #= #!=
|
||||
| \\?\#\\?[<>](?:\\?=)? # - numerical operators: #>= #<= #> #<
|
||||
| \\?[<>](?:\\?=)? # - numerical operators: >= <= > <
|
||||
) | \\?~|\\?!(?:\\?=)?|(?:\\?=)? # - string comparison operators including ~ for regexp, = and !=. No operator is like =
|
||||
) \s* # ignore space between operator and value
|
||||
(?<val>(?(num_op) # capture value in <val>
|
||||
(?:\\?\d)+ # - numerical operators have to be followed by a number
|
||||
| (?:\\.|[^\\])* ) # - string for comparison. May be empty. Capturing also all whitespace up to the end as this must have been escaped.
|
||||
)$ # match to the end
|
||||
""")]
|
||||
private static partial Regex CheckRegex();
|
||||
}
|
||||
|
||||
@@ -53,9 +53,14 @@ public class ConditionalTagCollectionTests
|
||||
namingTemplate.Evaluate(testObj);
|
||||
Assert.Fail($"Expected InvalidOperationException for pattern: {pattern}");
|
||||
}
|
||||
catch (Exception ex) when (ex is InvalidOperationException or TargetInvocationException)
|
||||
catch (TargetInvocationException ex)
|
||||
{
|
||||
// Expected behavior - regex is invalid or caused timeout
|
||||
// if evaluation of the template started but the regex is running into a timeout an InvalidOperationException is thrown
|
||||
Assert.IsInstanceOfType<InvalidOperationException>(ex.InnerException);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// Expected behavior - regex is invalid and parsing should fail
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +71,7 @@ public class ConditionalTagCollectionTests
|
||||
public void ConditionalTag_ValidRegexPattern_ParsesSuccessfully()
|
||||
{
|
||||
// Arrange: Valid simple regex pattern with proper closing tag
|
||||
var template = "<testcond [~test.*]->content<-testcond>";
|
||||
var template = "<testcond foobar[~test.*]->content<-testcond>";
|
||||
|
||||
// Act: Parse should succeed without throwing exceptions
|
||||
var namingTemplate = NamingTemplate.NamingTemplate.Parse(template, [_conditionalTags]);
|
||||
@@ -86,7 +91,7 @@ public class ConditionalTagCollectionTests
|
||||
public void ConditionalTag_ValidComplexRegexPatterns_ParseSuccessfully(string pattern)
|
||||
{
|
||||
// Arrange: Valid complex regex patterns with proper closing tags
|
||||
var template = $"<testcond [~{pattern}]->c<-testcond>";
|
||||
var template = $"<testcond foobar[~{pattern}]->c<-testcond>";
|
||||
|
||||
// Act: Parse should succeed without throwing
|
||||
var namingTemplate = NamingTemplate.NamingTemplate.Parse(template, [_conditionalTags]);
|
||||
|
||||
@@ -556,6 +556,16 @@ namespace TemplatesTests
|
||||
[DataRow("<!is author[!=Sherlock]->false<-has>", "")]
|
||||
[DataRow("<is tag[=Tag1]->true<-has>", "true")]
|
||||
[DataRow("<is tag[separator(:)slice(-2..)][=Tag2:Tag3]->true<-has>", "true")]
|
||||
[DataRow("<is audible subtitle[3][=an]->false<-has>", "")]
|
||||
[DataRow("<is audible subtitle[3][=an ]->false<-has>", "")]
|
||||
[DataRow(@"<is audible subtitle[3][=an\ ]->true<-has>", "true")]
|
||||
[DataRow("<is audible subtitle[3][= an]->false<-has>", "")]
|
||||
[DataRow("<is audible subtitle[3][= an ]->false<-has>", "")]
|
||||
[DataRow(@"<is audible subtitle[3][= an\ ]->true<-has>", "true")]
|
||||
[DataRow(@"<is audible subtitle[3][=\ an\ ]->false<-has>", "")]
|
||||
[DataRow("<is audible subtitle[3][ =an]->false<-has>", "")]
|
||||
[DataRow("<is audible subtitle[3][ =an ]->false<-has>", "")]
|
||||
[DataRow(@"<is audible subtitle[3][ =an\ ]->true<-has>", "true")]
|
||||
public void HasValue_test(string template, string expected)
|
||||
{
|
||||
var bookDto = GetLibraryBook();
|
||||
|
||||
Reference in New Issue
Block a user