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()); 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()); 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()); 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()); 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()); 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()); 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()); 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()); var prop = (Property)result; Assert.Multiple(() => { Assert.That(prop.PropertyName, Is.EqualTo("Age")); Assert.That(prop.Expression, Is.InstanceOf()); }); } [Test] public void Parse_LatexTextProperty_ReturnsProperty() { var result = Markdown.Parse("\\text{input.Department}"); Assert.That(result, Is.InstanceOf()); var prop = (Property)result; Assert.Multiple(() => { Assert.That(prop.PropertyName, Is.EqualTo("Department")); Assert.That(prop.Expression, Is.InstanceOf()); }); } [Test] public void Parse_LatexTextString_ReturnsStringLiteral() { var result = Markdown.Parse("\\text{some text}"); Assert.Multiple(() => { Assert.That(result, Is.InstanceOf()); 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()); var equal = (Equal)result; Assert.Multiple(() => { Assert.That(equal.Left, Is.InstanceOf()); Assert.That(equal.Right, Is.InstanceOf()); }); } [Test] public void Parse_NotEqual_ReturnsNotEqual() { var result = Markdown.Parse("x.Status != 'active'"); Assert.That(result, Is.InstanceOf()); var notEqual = (NotEqual)result; Assert.Multiple(() => { Assert.That(notEqual.Left, Is.InstanceOf()); Assert.That(notEqual.Right, Is.InstanceOf()); }); } [Test] public void Parse_LatexNotEqual_ReturnsNotEqual() { var result = Markdown.Parse("x.Value \\neq 100"); Assert.That(result, Is.InstanceOf()); var notEqual = (NotEqual)result; Assert.Multiple(() => { Assert.That(notEqual.Left, Is.InstanceOf()); Assert.That(notEqual.Right, Is.InstanceOf()); }); } [Test] public void Parse_GreaterThan_ReturnsGreaterThan() { var result = Markdown.Parse("x.Score > 100"); Assert.That(result, Is.InstanceOf()); var greaterThan = (GreaterThan)result; Assert.Multiple(() => { Assert.That(greaterThan.Left, Is.InstanceOf()); Assert.That(greaterThan.Right, Is.InstanceOf()); }); } [Test] public void Parse_LatexGreaterThan_ReturnsGreaterThan() { var result = Markdown.Parse("x.Total \\gt 500"); Assert.That(result, Is.InstanceOf()); var greaterThan = (GreaterThan)result; Assert.Multiple(() => { Assert.That(greaterThan.Left, Is.InstanceOf()); Assert.That(greaterThan.Right, Is.InstanceOf()); }); } #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()); var and = (And)result; Assert.Multiple(() => { Assert.That(and.Left, Is.InstanceOf()); Assert.That(and.Right, Is.InstanceOf()); }); } [Test] public void Parse_Or_ReturnsOr() { var result = Markdown.Parse("x.Status = 'pending' OR x.Status = 'active'"); Assert.That(result, Is.InstanceOf()); var or = (Or)result; Assert.Multiple(() => { Assert.That(or.Left, Is.InstanceOf()); Assert.That(or.Right, Is.InstanceOf()); }); } [Test] public void Parse_LatexLand_ReturnsAnd() { var result = Markdown.Parse("x.Valid = true \\land y.Count > 0"); Assert.That(result, Is.InstanceOf()); var and = (And)result; Assert.Multiple(() => { Assert.That(and.Left, Is.InstanceOf()); Assert.That(and.Right, Is.InstanceOf()); }); } [Test] public void Parse_LatexLor_ReturnsOr() { var result = Markdown.Parse("a.Type = 1 \\lor b.Type = 2"); Assert.That(result, Is.InstanceOf()); var or = (Or)result; Assert.Multiple(() => { Assert.That(or.Left, Is.InstanceOf()); Assert.That(or.Right, Is.InstanceOf()); }); } [Test] public void Parse_LatexWedge_ReturnsAnd() { var result = Markdown.Parse("x.Active = true \\wedge x.Verified = true"); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_LatexVee_ReturnsOr() { var result = Markdown.Parse("x.Status = 'A' \\vee x.Status = 'B'"); Assert.That(result, Is.InstanceOf()); } #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()); var or = (Or)result; Assert.Multiple(() => { Assert.That(or.Left, Is.InstanceOf()); Assert.That(or.Right, Is.InstanceOf()); }); } [Test] public void Parse_LatexParentheses_ReturnsCorrectStructure() { var result = Markdown.Parse("\\left(x.Value = 10\\right) \\land y.Value = 20"); Assert.That(result, Is.InstanceOf()); var and = (And)result; Assert.Multiple(() => { Assert.That(and.Left, Is.InstanceOf()); Assert.That(and.Right, Is.InstanceOf()); }); } [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()); var and = (And)result; Assert.Multiple(() => { Assert.That(and.Left, Is.InstanceOf()); Assert.That(and.Right, Is.InstanceOf()); }); var or = (Or)and.Right; Assert.Multiple(() => { Assert.That(or.Left, Is.InstanceOf()); Assert.That(or.Right, Is.InstanceOf()); }); } #endregion #region Markdown Delimiters [Test] public void Parse_InlineMath_RemovesDelimiters() { var result = Markdown.Parse("$x.Age = 25$"); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_BlockMath_RemovesDelimiters() { var result = Markdown.Parse("$$\nx.Age > 18\n$$"); Assert.That(result, Is.InstanceOf()); } [Test] public void Parse_MathCodeFence_RemovesDelimiters() { var result = Markdown.Parse("```math\nx.Active = true\n```"); Assert.That(result, Is.InstanceOf()); } #endregion #region Error Handling [Test] public void Parse_NullString_ThrowsArgumentException() { Assert.Throws(() => Markdown.Parse(null!)); } [Test] public void Parse_EmptyString_ThrowsArgumentException() { Assert.Throws(() => Markdown.Parse("")); } [Test] public void Parse_WhitespaceOnly_ThrowsArgumentException() { Assert.Throws(() => Markdown.Parse(" ")); } [Test] public void Parse_InvalidExpression_ThrowsArgumentException() { Assert.Throws(() => 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()); } [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()); var and = (And)result; // Left side: user.Age > 18 Assert.That(and.Left, Is.InstanceOf()); var greaterThan = (GreaterThan)and.Left; Assert.That(greaterThan.Left, Is.InstanceOf()); 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()); }); var equal = (Equal)and.Right; Assert.That(equal.Left, Is.InstanceOf()); 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()); var or = (Or)result; Assert.Multiple(() => { Assert.That(or.Left, Is.InstanceOf()); Assert.That(or.Right, Is.InstanceOf()); }); // Left AND: TotalCharges > 1000 AND Status = 'pending' var leftAnd = (And)or.Left; Assert.Multiple(() => { Assert.That(leftAnd.Left, Is.InstanceOf()); Assert.That(leftAnd.Right, Is.InstanceOf()); }); // Right AND: Priority = 'urgent' AND ApprovedBy != '' var rightAnd = (And)or.Right; Assert.Multiple(() => { Assert.That(rightAnd.Left, Is.InstanceOf()); Assert.That(rightAnd.Right, Is.InstanceOf()); }); } #endregion }