Files
sql-utilities/tests/Strata.SqlTools.Rules.Tests/MarkdownParserTests.cs
Thom LambandClaude Opus 4.7 67512d23e1 chore(sonar): wrap independent assertions in Assert.Multiple (NUnit2045)
Driven by `dotnet format analyzers --diagnostics NUnit2045`. The fixer
groups consecutive independent `Assert.That(...)` calls into
`Assert.Multiple(() => { ... })`, so a failing assertion no longer
short-circuits the block — every failure inside the group is reported,
which gives much better diagnostics on multi-property tests.

Audit confirmed no Assert.Throws / Assert.Fail / Assert.Catch / Assert.Pass
/ Assert.DoesNotThrow got pulled inside a Multiple block (those need to
short-circuit). All 1180 tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 11:59:47 -05:00

493 lines
13 KiB
C#

using Strata.SqlTools.Rules.Rule.Expression;
namespace Strata.SqlTools.Rules.Tests;
[TestFixture]
public class MarkdownParserTests
{
#region Basic Literals
[Test]
public void Parse_IntegerLiteral_ReturnsNumberLiteral()
{
var result = Markdown.Parse("42");
Assert.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<NumberLiteral>());
Assert.That(((NumberLiteral)result).Value, Is.EqualTo(42m));
});
}
[Test]
public void Parse_DecimalLiteral_ReturnsNumberLiteral()
{
var result = Markdown.Parse("3.14");
Assert.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<NumberLiteral>());
Assert.That(((NumberLiteral)result).Value, Is.EqualTo(3.14m));
});
}
[Test]
public void Parse_StringLiteral_DoubleQuotes_ReturnsStringLiteral()
{
var result = Markdown.Parse("\"hello world\"");
Assert.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<StringLiteral>());
Assert.That(((StringLiteral)result).Value, Is.EqualTo("hello world"));
});
}
[Test]
public void Parse_StringLiteral_SingleQuotes_ReturnsStringLiteral()
{
var result = Markdown.Parse("'test string'");
Assert.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<StringLiteral>());
Assert.That(((StringLiteral)result).Value, Is.EqualTo("test string"));
});
}
[Test]
public void Parse_BooleanLiteral_True_ReturnsLiteral()
{
var result = Markdown.Parse("true");
Assert.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<Literal>());
Assert.That(((Literal)result).Value, Is.EqualTo(true));
});
}
[Test]
public void Parse_BooleanLiteral_False_ReturnsLiteral()
{
var result = Markdown.Parse("false");
Assert.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<Literal>());
Assert.That(((Literal)result).Value, Is.EqualTo(false));
});
}
#endregion
#region Property Access
[Test]
public void Parse_SimpleProperty_ReturnsProperty()
{
var result = Markdown.Parse("PropertyName");
Assert.That(result, Is.InstanceOf<Property>());
var prop = (Property)result;
Assert.Multiple(() =>
{
Assert.That(prop.PropertyName, Is.EqualTo("PropertyName"));
Assert.That(prop.Expression, Is.Null);
});
}
[Test]
public void Parse_PropertyWithParameter_ReturnsProperty()
{
var result = Markdown.Parse("x.Age");
Assert.That(result, Is.InstanceOf<Property>());
var prop = (Property)result;
Assert.Multiple(() =>
{
Assert.That(prop.PropertyName, Is.EqualTo("Age"));
Assert.That(prop.Expression, Is.InstanceOf<Parameter>());
});
}
[Test]
public void Parse_LatexTextProperty_ReturnsProperty()
{
var result = Markdown.Parse("\\text{input.Department}");
Assert.That(result, Is.InstanceOf<Property>());
var prop = (Property)result;
Assert.Multiple(() =>
{
Assert.That(prop.PropertyName, Is.EqualTo("Department"));
Assert.That(prop.Expression, Is.InstanceOf<Parameter>());
});
}
[Test]
public void Parse_LatexTextString_ReturnsStringLiteral()
{
var result = Markdown.Parse("\\text{some text}");
Assert.Multiple(() =>
{
Assert.That(result, Is.InstanceOf<StringLiteral>());
Assert.That(((StringLiteral)result).Value, Is.EqualTo("some text"));
});
}
#endregion
#region Comparisons
[Test]
public void Parse_Equality_ReturnsEqual()
{
var result = Markdown.Parse("x.Age = 25");
Assert.That(result, Is.InstanceOf<Equal>());
var equal = (Equal)result;
Assert.Multiple(() =>
{
Assert.That(equal.Left, Is.InstanceOf<Property>());
Assert.That(equal.Right, Is.InstanceOf<NumberLiteral>());
});
}
[Test]
public void Parse_NotEqual_ReturnsNotEqual()
{
var result = Markdown.Parse("x.Status != 'active'");
Assert.That(result, Is.InstanceOf<NotEqual>());
var notEqual = (NotEqual)result;
Assert.Multiple(() =>
{
Assert.That(notEqual.Left, Is.InstanceOf<Property>());
Assert.That(notEqual.Right, Is.InstanceOf<StringLiteral>());
});
}
[Test]
public void Parse_LatexNotEqual_ReturnsNotEqual()
{
var result = Markdown.Parse("x.Value \\neq 100");
Assert.That(result, Is.InstanceOf<NotEqual>());
var notEqual = (NotEqual)result;
Assert.Multiple(() =>
{
Assert.That(notEqual.Left, Is.InstanceOf<Property>());
Assert.That(notEqual.Right, Is.InstanceOf<NumberLiteral>());
});
}
[Test]
public void Parse_GreaterThan_ReturnsGreaterThan()
{
var result = Markdown.Parse("x.Score > 100");
Assert.That(result, Is.InstanceOf<GreaterThan>());
var greaterThan = (GreaterThan)result;
Assert.Multiple(() =>
{
Assert.That(greaterThan.Left, Is.InstanceOf<Property>());
Assert.That(greaterThan.Right, Is.InstanceOf<NumberLiteral>());
});
}
[Test]
public void Parse_LatexGreaterThan_ReturnsGreaterThan()
{
var result = Markdown.Parse("x.Total \\gt 500");
Assert.That(result, Is.InstanceOf<GreaterThan>());
var greaterThan = (GreaterThan)result;
Assert.Multiple(() =>
{
Assert.That(greaterThan.Left, Is.InstanceOf<Property>());
Assert.That(greaterThan.Right, Is.InstanceOf<NumberLiteral>());
});
}
#endregion
#region Logical Operations
[Test]
public void Parse_And_ReturnsAnd()
{
var result = Markdown.Parse("x.Age > 18 AND y.Active = true");
Assert.That(result, Is.InstanceOf<And>());
var and = (And)result;
Assert.Multiple(() =>
{
Assert.That(and.Left, Is.InstanceOf<GreaterThan>());
Assert.That(and.Right, Is.InstanceOf<Equal>());
});
}
[Test]
public void Parse_Or_ReturnsOr()
{
var result = Markdown.Parse("x.Status = 'pending' OR x.Status = 'active'");
Assert.That(result, Is.InstanceOf<Or>());
var or = (Or)result;
Assert.Multiple(() =>
{
Assert.That(or.Left, Is.InstanceOf<Equal>());
Assert.That(or.Right, Is.InstanceOf<Equal>());
});
}
[Test]
public void Parse_LatexLand_ReturnsAnd()
{
var result = Markdown.Parse("x.Valid = true \\land y.Count > 0");
Assert.That(result, Is.InstanceOf<And>());
var and = (And)result;
Assert.Multiple(() =>
{
Assert.That(and.Left, Is.InstanceOf<Equal>());
Assert.That(and.Right, Is.InstanceOf<GreaterThan>());
});
}
[Test]
public void Parse_LatexLor_ReturnsOr()
{
var result = Markdown.Parse("a.Type = 1 \\lor b.Type = 2");
Assert.That(result, Is.InstanceOf<Or>());
var or = (Or)result;
Assert.Multiple(() =>
{
Assert.That(or.Left, Is.InstanceOf<Equal>());
Assert.That(or.Right, Is.InstanceOf<Equal>());
});
}
[Test]
public void Parse_LatexWedge_ReturnsAnd()
{
var result = Markdown.Parse("x.Active = true \\wedge x.Verified = true");
Assert.That(result, Is.InstanceOf<And>());
}
[Test]
public void Parse_LatexVee_ReturnsOr()
{
var result = Markdown.Parse("x.Status = 'A' \\vee x.Status = 'B'");
Assert.That(result, Is.InstanceOf<Or>());
}
#endregion
#region Complex Expressions
[Test]
public void Parse_NestedParentheses_ReturnsCorrectStructure()
{
var result = Markdown.Parse("(x.Age > 18 AND x.Active = true) OR y.Override = true");
Assert.That(result, Is.InstanceOf<Or>());
var or = (Or)result;
Assert.Multiple(() =>
{
Assert.That(or.Left, Is.InstanceOf<And>());
Assert.That(or.Right, Is.InstanceOf<Equal>());
});
}
[Test]
public void Parse_LatexParentheses_ReturnsCorrectStructure()
{
var result = Markdown.Parse("\\left(x.Value = 10\\right) \\land y.Value = 20");
Assert.That(result, Is.InstanceOf<And>());
var and = (And)result;
Assert.Multiple(() =>
{
Assert.That(and.Left, Is.InstanceOf<Equal>());
Assert.That(and.Right, Is.InstanceOf<Equal>());
});
}
[Test]
public void Parse_ComplexExpression_ReturnsCorrectStructure()
{
var result = Markdown.Parse("x.Age > 18 AND (y.Status = 'active' OR y.Status = 'pending')");
Assert.That(result, Is.InstanceOf<And>());
var and = (And)result;
Assert.Multiple(() =>
{
Assert.That(and.Left, Is.InstanceOf<GreaterThan>());
Assert.That(and.Right, Is.InstanceOf<Or>());
});
var or = (Or)and.Right;
Assert.Multiple(() =>
{
Assert.That(or.Left, Is.InstanceOf<Equal>());
Assert.That(or.Right, Is.InstanceOf<Equal>());
});
}
#endregion
#region Markdown Delimiters
[Test]
public void Parse_InlineMath_RemovesDelimiters()
{
var result = Markdown.Parse("$x.Age = 25$");
Assert.That(result, Is.InstanceOf<Equal>());
}
[Test]
public void Parse_BlockMath_RemovesDelimiters()
{
var result = Markdown.Parse("$$\nx.Age > 18\n$$");
Assert.That(result, Is.InstanceOf<GreaterThan>());
}
[Test]
public void Parse_MathCodeFence_RemovesDelimiters()
{
var result = Markdown.Parse("```math\nx.Active = true\n```");
Assert.That(result, Is.InstanceOf<Equal>());
}
#endregion
#region Error Handling
[Test]
public void Parse_NullString_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => Markdown.Parse(null!));
}
[Test]
public void Parse_EmptyString_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => Markdown.Parse(""));
}
[Test]
public void Parse_WhitespaceOnly_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => Markdown.Parse(" "));
}
[Test]
public void Parse_InvalidExpression_ThrowsArgumentException()
{
Assert.Throws<ArgumentException>(() => Markdown.Parse("@#$%"));
}
[Test]
public void TryParse_ValidExpression_ReturnsTrue()
{
var success = Markdown.TryParse("x.Age = 25", out var expression);
Assert.Multiple(() =>
{
Assert.That(success, Is.True);
Assert.That(expression, Is.Not.Null);
});
Assert.That(expression, Is.InstanceOf<Equal>());
}
[Test]
public void TryParse_InvalidExpression_ReturnsFalse()
{
var success = Markdown.TryParse("@#$%", out var expression);
Assert.Multiple(() =>
{
Assert.That(success, Is.False);
Assert.That(expression, Is.Null);
});
}
#endregion
#region Integration Tests
[Test]
public void Parse_RealWorldExample_UserAgeAndStatus()
{
var markdown = "$$\\text{user.Age} > 18 \\land \\text{user.Status} = \\text{active}$$";
var result = Markdown.Parse(markdown);
Assert.That(result, Is.InstanceOf<And>());
var and = (And)result;
// Left side: user.Age > 18
Assert.That(and.Left, Is.InstanceOf<GreaterThan>());
var greaterThan = (GreaterThan)and.Left;
Assert.That(greaterThan.Left, Is.InstanceOf<Property>());
var userAge = (Property)greaterThan.Left;
Assert.Multiple(() =>
{
Assert.That(userAge.PropertyName, Is.EqualTo("Age"));
// Right side: user.Status = "active"
Assert.That(and.Right, Is.InstanceOf<Equal>());
});
var equal = (Equal)and.Right;
Assert.That(equal.Left, Is.InstanceOf<Property>());
var userStatus = (Property)equal.Left;
Assert.That(userStatus.PropertyName, Is.EqualTo("Status"));
}
[Test]
public void Parse_RealWorldExample_ComplexBusinessRule()
{
var markdown = @"$
(invoice.TotalCharges > 1000 AND invoice.Status = 'pending')
OR
(invoice.Priority = 'urgent' AND invoice.ApprovedBy != '')
$";
var result = Markdown.Parse(markdown);
Assert.That(result, Is.InstanceOf<Or>());
var or = (Or)result;
Assert.Multiple(() =>
{
Assert.That(or.Left, Is.InstanceOf<And>());
Assert.That(or.Right, Is.InstanceOf<And>());
});
// Left AND: TotalCharges > 1000 AND Status = 'pending'
var leftAnd = (And)or.Left;
Assert.Multiple(() =>
{
Assert.That(leftAnd.Left, Is.InstanceOf<GreaterThan>());
Assert.That(leftAnd.Right, Is.InstanceOf<Equal>());
});
// Right AND: Priority = 'urgent' AND ApprovedBy != ''
var rightAnd = (And)or.Right;
Assert.Multiple(() =>
{
Assert.That(rightAnd.Left, Is.InstanceOf<Equal>());
Assert.That(rightAnd.Right, Is.InstanceOf<NotEqual>());
});
}
#endregion
}