template engine
This commit is contained in:
445
Inspectron.Epson.TemplateEngine.Tests/TemplateRendererTests.cs
Normal file
445
Inspectron.Epson.TemplateEngine.Tests/TemplateRendererTests.cs
Normal file
@@ -0,0 +1,445 @@
|
||||
namespace Inspectron.Epson.TemplateEngine.Tests;
|
||||
|
||||
public class TemplateRendererTests
|
||||
{
|
||||
private readonly ReceiptTemplateEngine _engine = new();
|
||||
|
||||
[Fact]
|
||||
public void Render_EmptyReceipt()
|
||||
{
|
||||
var commands = _engine.Render("<receipt></receipt>", "{}", 42, 22);
|
||||
Assert.Empty(commands);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_SimpleLine()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"<receipt><line>Hello World</line></receipt>",
|
||||
"{}", 42, 22);
|
||||
|
||||
Assert.Single(commands);
|
||||
Assert.Equal("Hello World", commands[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_LineWithDataBinding()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"<receipt><line>Hello {{Name}}</line></receipt>",
|
||||
"""{"Name":"John"}""", 42, 22);
|
||||
|
||||
Assert.Single(commands);
|
||||
Assert.Equal("Hello John", commands[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_LineWithFormatting()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"""<receipt><line bold="true" big="true" tall="true" red="true">Text</line></receipt>""",
|
||||
"{}", 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(
|
||||
"""<receipt><line align="center">Test</line></receipt>""",
|
||||
"{}", 42, 22);
|
||||
|
||||
Assert.Equal(" Test", commands[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_LineWithCenterAlignment_BigFont()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"""<receipt><line align="center" big="true">Test</line></receipt>""",
|
||||
"{}", 42, 22);
|
||||
|
||||
Assert.Equal(" Test", commands[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_EmptyLine()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"<receipt><line /></receipt>",
|
||||
"{}", 42, 22);
|
||||
|
||||
Assert.Single(commands);
|
||||
Assert.Equal("", commands[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_Separator()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"<receipt><separator /></receipt>",
|
||||
"{}", 42, 22);
|
||||
|
||||
Assert.Single(commands);
|
||||
Assert.Equal(new string('-', 42), commands[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_Cut()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"<receipt><cut /></receipt>",
|
||||
"{}", 42, 22);
|
||||
|
||||
Assert.Single(commands);
|
||||
Assert.True(commands[0].IsCut);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_Feed()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"""<receipt><feed lines="3" /></receipt>""",
|
||||
"{}", 42, 22);
|
||||
|
||||
Assert.Equal(3, commands.Count);
|
||||
Assert.All(commands, c => Assert.Equal("", c.Text));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_Columns()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"""<receipt><columns left="Name" right="Price" /></receipt>""",
|
||||
"{}", 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(
|
||||
"""<receipt><columns left="{{Label}}" right="{{Value}}" /></receipt>""",
|
||||
"""{"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("""
|
||||
<receipt>
|
||||
<foreach items="Items" var="item">
|
||||
<line>{{item.Name}}</line>
|
||||
</foreach>
|
||||
</receipt>
|
||||
""",
|
||||
"""{"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("""
|
||||
<receipt>
|
||||
<foreach items="Items" var="item">
|
||||
<line>{{item.Name}}</line>
|
||||
</foreach>
|
||||
</receipt>
|
||||
""",
|
||||
"""{"Items":[]}""", 42, 22);
|
||||
|
||||
Assert.Empty(commands);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_Foreach_WithLoopVariables()
|
||||
{
|
||||
var commands = _engine.Render("""
|
||||
<receipt>
|
||||
<foreach items="Items" var="item">
|
||||
<line>{{$index}}: {{item.Name}}</line>
|
||||
</foreach>
|
||||
</receipt>
|
||||
""",
|
||||
"""{"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("""
|
||||
<receipt>
|
||||
<foreach items="Groups" var="group">
|
||||
<line>{{group.Name}}</line>
|
||||
<foreach items="group.Items" var="item">
|
||||
<line> {{item.Name}}</line>
|
||||
</foreach>
|
||||
</foreach>
|
||||
</receipt>
|
||||
""",
|
||||
"""{"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("""
|
||||
<receipt>
|
||||
<if test="Name">
|
||||
<line>Has name: {{Name}}</line>
|
||||
</if>
|
||||
</receipt>
|
||||
""",
|
||||
"""{"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("""
|
||||
<receipt>
|
||||
<if test="Name">
|
||||
<line>Has name</line>
|
||||
</if>
|
||||
</receipt>
|
||||
""",
|
||||
"""{}""", 42, 22);
|
||||
|
||||
Assert.Empty(commands);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_IfElse_True()
|
||||
{
|
||||
var commands = _engine.Render("""
|
||||
<receipt>
|
||||
<if test="Name">
|
||||
<line>Yes</line>
|
||||
</if>
|
||||
<else>
|
||||
<line>No</line>
|
||||
</else>
|
||||
</receipt>
|
||||
""",
|
||||
"""{"Name":"John"}""", 42, 22);
|
||||
|
||||
Assert.Single(commands);
|
||||
Assert.Equal("Yes", commands[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_IfElse_False()
|
||||
{
|
||||
var commands = _engine.Render("""
|
||||
<receipt>
|
||||
<if test="Name">
|
||||
<line>Yes</line>
|
||||
</if>
|
||||
<else>
|
||||
<line>No</line>
|
||||
</else>
|
||||
</receipt>
|
||||
""",
|
||||
"""{}""", 42, 22);
|
||||
|
||||
Assert.Single(commands);
|
||||
Assert.Equal("No", commands[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_If_NegatedCondition()
|
||||
{
|
||||
var commands = _engine.Render("""
|
||||
<receipt>
|
||||
<if test="!$last">
|
||||
<cut />
|
||||
</if>
|
||||
</receipt>
|
||||
""",
|
||||
"""{}""", 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("""
|
||||
<receipt>
|
||||
<foreach items="Items" var="item">
|
||||
<line>{{item.Name}}</line>
|
||||
<if test="!$last">
|
||||
<separator />
|
||||
</if>
|
||||
</foreach>
|
||||
</receipt>
|
||||
""",
|
||||
"""{"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(
|
||||
"""<receipt><line wrap="true">The quick brown fox jumps over the lazy dog and more text here</line></receipt>""",
|
||||
"{}", 30, 15);
|
||||
|
||||
Assert.True(commands.Count > 1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_LineSpacing()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"""<receipt><line lineSpacing="50">Text</line></receipt>""",
|
||||
"{}", 42, 22);
|
||||
|
||||
Assert.Equal(50, commands[0].SetLineSpacing);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_FormatString()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"<receipt><line>{{Price:F2}}</line></receipt>",
|
||||
"""{"Price":9.5}""", 42, 22);
|
||||
|
||||
Assert.Equal("9.50", commands[0].Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_DateTimeFormat()
|
||||
{
|
||||
var commands = _engine.Render(
|
||||
"<receipt><line>{{Date:dd.MM.yyyy}}</line></receipt>",
|
||||
"""{"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("""
|
||||
<receipt>
|
||||
<row>
|
||||
<col width="14">Left</col>
|
||||
<col width="14" align="center">Center</col>
|
||||
<col width="14" align="right">Right</col>
|
||||
</row>
|
||||
</receipt>
|
||||
""",
|
||||
"{}", 42, 22);
|
||||
|
||||
Assert.Single(commands);
|
||||
Assert.Equal(42, commands[0].Text.Length);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_InvalidXml_ThrowsParsingException()
|
||||
{
|
||||
Assert.Throws<TemplateParsingException>(() =>
|
||||
_engine.Render("not xml", "{}", 42, 22));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_InvalidJson_ThrowsRenderingException()
|
||||
{
|
||||
Assert.Throws<TemplateRenderingException>(() =>
|
||||
_engine.Render("<receipt></receipt>", "not json", 42, 22));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Render_ComplexTemplate()
|
||||
{
|
||||
var template = """
|
||||
<receipt>
|
||||
<line align="center" big="true" red="true">Restaurant</line>
|
||||
<separator />
|
||||
<line />
|
||||
<line align="center">{{DateTime:dd-MMM-yy HH:mm}} Nr.:{{Number}}</line>
|
||||
<line align="center" big="true" bold="true">Tisch: {{Table}}</line>
|
||||
<separator />
|
||||
<foreach items="Items" var="item">
|
||||
<line bold="true">{{item.Qty}}x {{item.Name}}</line>
|
||||
</foreach>
|
||||
<separator />
|
||||
<columns left="Total:" right="{{Total:F2}} CHF" bold="true" />
|
||||
<cut />
|
||||
</receipt>
|
||||
""";
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user