using System.Text.Json; using Inspectron.Epson.TemplateEngine.DataBinding; namespace Inspectron.Epson.TemplateEngine.Tests; public class ExpressionEvaluatorTests { private static DataContext CreateContext(string json) { var root = JsonDocument.Parse(json).RootElement; return new DataContext(root); } [Fact] public void Evaluate_SimpleProperty() { var ctx = CreateContext("""{"Name":"John"}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("Hello John", eval.Evaluate("Hello {{Name}}")); } [Fact] public void Evaluate_NestedProperty() { var ctx = CreateContext("""{"Person":{"Name":"Alice"}}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("Hi Alice", eval.Evaluate("Hi {{Person.Name}}")); } [Fact] public void Evaluate_MissingProperty_ReturnsEmpty() { var ctx = CreateContext("""{"Name":"John"}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("Hi ", eval.Evaluate("Hi {{Missing}}")); } [Fact] public void Evaluate_NumberProperty() { var ctx = CreateContext("""{"Count":42}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("Count: 42", eval.Evaluate("Count: {{Count}}")); } [Fact] public void Evaluate_FormatString_Decimal() { var ctx = CreateContext("""{"Price":9.5}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("9.50", eval.Evaluate("{{Price:F2}}")); } [Fact] public void Evaluate_FormatString_DateTime() { var ctx = CreateContext("""{"Date":"2024-03-15T14:30:00Z"}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("15-Mar-24 14:30", eval.Evaluate("{{Date:dd-MMM-yy HH:mm}}")); } [Fact] public void Evaluate_MultipleExpressions() { var ctx = CreateContext("""{"First":"John","Last":"Doe"}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("John Doe", eval.Evaluate("{{First}} {{Last}}")); } [Fact] public void Evaluate_CaseInsensitivePropertyLookup() { var ctx = CreateContext("""{"name":"Alice"}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("Alice", eval.Evaluate("{{Name}}")); } [Fact] public void Evaluate_EmptyTemplate() { var ctx = CreateContext("""{}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("", eval.Evaluate("")); } [Fact] public void Evaluate_NoExpressions() { var ctx = CreateContext("""{}"""); var eval = new ExpressionEvaluator(ctx); Assert.Equal("plain text", eval.Evaluate("plain text")); } [Fact] public void Evaluate_LoopVariable_Index() { var ctx = CreateContext("""{}"""); ctx.SetLoopVariable("$index", 3); var eval = new ExpressionEvaluator(ctx); Assert.Equal("Index: 3", eval.Evaluate("Index: {{$index}}")); } [Fact] public void EvaluateCondition_TruthyString() { var ctx = CreateContext("""{"Name":"John"}"""); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("Name")); } [Fact] public void EvaluateCondition_EmptyString_IsFalsy() { var ctx = CreateContext("""{"Name":""}"""); var eval = new ExpressionEvaluator(ctx); Assert.False(eval.EvaluateCondition("Name")); } [Fact] public void EvaluateCondition_MissingProperty_IsFalsy() { var ctx = CreateContext("""{}"""); var eval = new ExpressionEvaluator(ctx); Assert.False(eval.EvaluateCondition("Name")); } [Fact] public void EvaluateCondition_Negation() { var ctx = CreateContext("""{"Name":"John"}"""); var eval = new ExpressionEvaluator(ctx); Assert.False(eval.EvaluateCondition("!Name")); } [Fact] public void EvaluateCondition_Negation_Missing() { var ctx = CreateContext("""{}"""); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("!Name")); } [Fact] public void EvaluateCondition_NullValue_IsFalsy() { var ctx = CreateContext("""{"Name":null}"""); var eval = new ExpressionEvaluator(ctx); Assert.False(eval.EvaluateCondition("Name")); } [Fact] public void EvaluateCondition_Comparison_Equal() { var ctx = CreateContext("""{"Count":5}"""); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("Count==5")); } [Fact] public void EvaluateCondition_Comparison_NotEqual() { var ctx = CreateContext("""{"Count":5}"""); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("Count!=3")); } [Fact] public void EvaluateCondition_Comparison_GreaterThan() { var ctx = CreateContext("""{"Count":5}"""); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("Count>3")); } [Fact] public void EvaluateCondition_Comparison_StringEqual() { var ctx = CreateContext("""{"Status":"active"}"""); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("Status=='active'")); } [Fact] public void EvaluateCondition_LoopVariable_First() { var ctx = CreateContext("""{}"""); ctx.SetLoopVariable("$first", true); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("$first")); } [Fact] public void EvaluateCondition_LoopVariable_NotLast() { var ctx = CreateContext("""{}"""); ctx.SetLoopVariable("$last", false); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("!$last")); } [Fact] public void EvaluateCondition_NonEmptyArray_IsTruthy() { var ctx = CreateContext("""{"Items":[1,2,3]}"""); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("Items")); } [Fact] public void EvaluateCondition_EmptyArray_IsFalsy() { var ctx = CreateContext("""{"Items":[]}"""); var eval = new ExpressionEvaluator(ctx); Assert.False(eval.EvaluateCondition("Items")); } [Fact] public void EvaluateCondition_BooleanTrue_IsTruthy() { var ctx = CreateContext("""{"Active":true}"""); var eval = new ExpressionEvaluator(ctx); Assert.True(eval.EvaluateCondition("Active")); } [Fact] public void EvaluateCondition_BooleanFalse_IsFalsy() { var ctx = CreateContext("""{"Active":false}"""); var eval = new ExpressionEvaluator(ctx); Assert.False(eval.EvaluateCondition("Active")); } [Fact] public void DataContext_ChildScope_InheritsParentVariables() { var ctx = CreateContext("""{}"""); var item = JsonDocument.Parse("""{"Name":"Pizza"}""").RootElement; ctx.SetVariable("item", item); var child = ctx.CreateChildScope(); var childEval = new ExpressionEvaluator(child); Assert.Equal("Pizza", childEval.Evaluate("{{item.Name}}")); } [Fact] public void DataContext_ChildScope_OverridesParentVariable() { var ctx = CreateContext("""{}"""); var item1 = JsonDocument.Parse("""{"Name":"Pizza"}""").RootElement; ctx.SetVariable("item", item1); var child = ctx.CreateChildScope(); var item2 = JsonDocument.Parse("""{"Name":"Pasta"}""").RootElement; child.SetVariable("item", item2); var childEval = new ExpressionEvaluator(child); Assert.Equal("Pasta", childEval.Evaluate("{{item.Name}}")); var parentEval = new ExpressionEvaluator(ctx); Assert.Equal("Pizza", parentEval.Evaluate("{{item.Name}}")); } }