namespace Inspectron.Epson.TemplateEngine.Tests; public class TemplateRendererTests { private readonly ReceiptTemplateEngine _engine = new(); [Fact] public void Render_EmptyReceipt() { var commands = _engine.Render("", "{}", 42, 22); Assert.Empty(commands); } [Fact] public void Render_SimpleLine() { var commands = _engine.Render( "Hello World", "{}", 42, 22); Assert.Single(commands); Assert.Equal("Hello World", commands[0].Text); } [Fact] public void Render_LineWithDataBinding() { var commands = _engine.Render( "Hello {{Name}}", """{"Name":"John"}""", 42, 22); Assert.Single(commands); Assert.Equal("Hello John", commands[0].Text); } [Fact] public void Render_LineWithFormatting() { var commands = _engine.Render( """Text""", "{}", 42, 22); var cmd = commands[0]; Assert.True(cmd.IsBold); Assert.True(cmd.IsBig); Assert.True(cmd.IsTall); Assert.True(cmd.IsRed); } [Fact] public void Render_LineWithCenterAlignment() { var commands = _engine.Render( """Test""", "{}", 42, 22); Assert.Equal(" Test", commands[0].Text); } [Fact] public void Render_LineWithCenterAlignment_BigFont() { var commands = _engine.Render( """Test""", "{}", 42, 22); Assert.Equal(" Test", commands[0].Text); } [Fact] public void Render_EmptyLine() { var commands = _engine.Render( "", "{}", 42, 22); Assert.Single(commands); Assert.Equal("", commands[0].Text); } [Fact] public void Render_Separator() { var commands = _engine.Render( "", "{}", 42, 22); Assert.Single(commands); Assert.Equal(new string('-', 42), commands[0].Text); } [Fact] public void Render_Cut() { var commands = _engine.Render( "", "{}", 42, 22); Assert.Single(commands); Assert.True(commands[0].IsCut); } [Fact] public void Render_Feed() { var commands = _engine.Render( """""", "{}", 42, 22); Assert.Equal(3, commands.Count); Assert.All(commands, c => Assert.Equal("", c.Text)); } [Fact] public void Render_Columns() { var commands = _engine.Render( """""", "{}", 42, 22); Assert.Single(commands); Assert.Equal(42, commands[0].Text.Length); Assert.StartsWith("Name", commands[0].Text); Assert.EndsWith("Price", commands[0].Text); } [Fact] public void Render_ColumnsWithDataBinding() { var commands = _engine.Render( """""", """{"Label":"Total","Value":"100.00"}""", 42, 22); Assert.Single(commands); Assert.Contains("Total", commands[0].Text); Assert.Contains("100.00", commands[0].Text); } [Fact] public void Render_Foreach() { var commands = _engine.Render(""" {{item.Name}} """, """{"Items":[{"Name":"Pizza"},{"Name":"Pasta"},{"Name":"Salad"}]}""", 42, 22); Assert.Equal(3, commands.Count); Assert.Equal("Pizza", commands[0].Text); Assert.Equal("Pasta", commands[1].Text); Assert.Equal("Salad", commands[2].Text); } [Fact] public void Render_Foreach_EmptyArray() { var commands = _engine.Render(""" {{item.Name}} """, """{"Items":[]}""", 42, 22); Assert.Empty(commands); } [Fact] public void Render_Foreach_WithLoopVariables() { var commands = _engine.Render(""" {{$index}}: {{item.Name}} """, """{"Items":[{"Name":"A"},{"Name":"B"},{"Name":"C"}]}""", 42, 22); Assert.Equal(3, commands.Count); Assert.Equal("0: A", commands[0].Text); Assert.Equal("1: B", commands[1].Text); Assert.Equal("2: C", commands[2].Text); } [Fact] public void Render_NestedForeach() { var commands = _engine.Render(""" {{group.Name}} {{item.Name}} """, """{"Groups":[{"Name":"G1","Items":[{"Name":"A"},{"Name":"B"}]},{"Name":"G2","Items":[{"Name":"C"}]}]}""", 42, 22); Assert.Equal(5, commands.Count); Assert.Equal("G1", commands[0].Text); Assert.Equal(" A", commands[1].Text); Assert.Equal(" B", commands[2].Text); Assert.Equal("G2", commands[3].Text); Assert.Equal(" C", commands[4].Text); } [Fact] public void Render_If_True() { var commands = _engine.Render(""" Has name: {{Name}} """, """{"Name":"John"}""", 42, 22); Assert.Single(commands); Assert.Equal("Has name: John", commands[0].Text); } [Fact] public void Render_If_False() { var commands = _engine.Render(""" Has name """, """{}""", 42, 22); Assert.Empty(commands); } [Fact] public void Render_IfElse_True() { var commands = _engine.Render(""" Yes No """, """{"Name":"John"}""", 42, 22); Assert.Single(commands); Assert.Equal("Yes", commands[0].Text); } [Fact] public void Render_IfElse_False() { var commands = _engine.Render(""" Yes No """, """{}""", 42, 22); Assert.Single(commands); Assert.Equal("No", commands[0].Text); } [Fact] public void Render_If_NegatedCondition() { var commands = _engine.Render(""" """, """{}""", 42, 22); // $last is not set so not a boolean false, but the variable doesn't exist // When there's no foreach context, $last is null, so !null = true Assert.Single(commands); Assert.True(commands[0].IsCut); } [Fact] public void Render_Foreach_WithIfNotLast() { var commands = _engine.Render(""" {{item.Name}} """, """{"Items":[{"Name":"A"},{"Name":"B"},{"Name":"C"}]}""", 42, 22); // A, sep, B, sep, C = 5 Assert.Equal(5, commands.Count); Assert.Equal("A", commands[0].Text); Assert.Equal(new string('-', 42), commands[1].Text); Assert.Equal("B", commands[2].Text); Assert.Equal(new string('-', 42), commands[3].Text); Assert.Equal("C", commands[4].Text); } [Fact] public void Render_LineWithWrap() { var commands = _engine.Render( """The quick brown fox jumps over the lazy dog and more text here""", "{}", 30, 15); Assert.True(commands.Count > 1); } [Fact] public void Render_LineSpacing() { var commands = _engine.Render( """Text""", "{}", 42, 22); Assert.Equal(50, commands[0].SetLineSpacing); } [Fact] public void Render_FormatString() { var commands = _engine.Render( "{{Price:F2}}", """{"Price":9.5}""", 42, 22); Assert.Equal("9.50", commands[0].Text); } [Fact] public void Render_DateTimeFormat() { var commands = _engine.Render( "{{Date:dd.MM.yyyy}}", """{"Date":"2024-03-15T14:30:00Z"}""", 42, 22); Assert.Equal("15.03.2024", commands[0].Text); } [Fact] public void Render_Row() { var commands = _engine.Render(""" Left Center Right """, "{}", 42, 22); Assert.Single(commands); Assert.Equal(42, commands[0].Text.Length); } [Fact] public void Render_InvalidXml_ThrowsParsingException() { Assert.Throws(() => _engine.Render("not xml", "{}", 42, 22)); } [Fact] public void Render_InvalidJson_ThrowsRenderingException() { Assert.Throws(() => _engine.Render("", "not json", 42, 22)); } [Fact] public void Render_ComplexTemplate() { var template = """ Restaurant {{DateTime:dd-MMM-yy HH:mm}} Nr.:{{Number}} Tisch: {{Table}} {{item.Qty}}x {{item.Name}} """; var json = """ { "DateTime": "2024-03-15T14:30:00Z", "Number": "42", "Table": "5", "Items": [ {"Qty": 2, "Name": "Margherita"}, {"Qty": 1, "Name": "Tiramisu"} ], "Total": 45.50 } """; var commands = _engine.Render(template, json, 42, 22); Assert.True(commands.Count >= 10); // Header Assert.True(commands[0].IsRed); Assert.True(commands[0].IsBig); Assert.Contains("Restaurant", commands[0].Text); // Last command is cut Assert.True(commands[^1].IsCut); } }