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);
}
}