using Inspectron.Epson.PrintServer.Printers.Utils; using Inspectron.Epson.PrintServer.Printers.Utils.KitchenReceipt; using System.Text.Json; namespace Inspectron.Epson.TemplateEngine.Tests; public class KitchenReceiptTemplateTests { private const int LineWidth = 42; private const int BigLineWidth = 22; private readonly ReceiptTemplateEngine _engine = new(); private static string GetTemplatePath() { return Path.Combine(AppContext.BaseDirectory, "Templates", "KitchenReceipt.xml"); } [Fact] public void RenderKitchenReceipt_BasicStructure() { var template = File.ReadAllText(GetTemplatePath()); var json = """ { "Title": "Test Restaurant", "TransactionDateTime": "2024-03-15T14:30:00Z", "ReceiptNumber": "42", "WaiterName": "Max", "TableNumber": "5", "SpecialInstruction": null, "HasGangs": false, "HasDishes": false, "Gangs": [], "Dishes": [] } """; var commands = _engine.Render(template, json, LineWidth, BigLineWidth); Assert.True(commands.Count > 0); // First line: title centered in big font, red Assert.True(commands[0].IsBig); Assert.True(commands[0].IsTall); Assert.True(commands[0].IsRed); Assert.Contains("Test Restaurant", commands[0].Text); // Second line: separator Assert.Equal(new string('-', LineWidth), commands[1].Text); // Empty line Assert.Equal("", commands[2].Text); } [Fact] public void RenderKitchenReceipt_WithSpecialInstruction() { var template = File.ReadAllText(GetTemplatePath()); var json = """ { "Title": "Test Restaurant", "TransactionDateTime": "2024-03-15T14:30:00Z", "ReceiptNumber": "42", "WaiterName": "Max", "TableNumber": "5", "SpecialInstruction": "RUSH ORDER", "HasGangs": false, "HasDishes": false, "Gangs": [], "Dishes": [] } """; var commands = _engine.Render(template, json, LineWidth, BigLineWidth); // Should contain the special instruction var specialCommands = commands.Where(c => c.Text.Contains("RUSH ORDER")).ToList(); Assert.NotEmpty(specialCommands); Assert.True(specialCommands[0].IsBig); Assert.True(specialCommands[0].IsBold); } [Fact] public void RenderKitchenReceipt_WithGangs() { var template = File.ReadAllText(GetTemplatePath()); var json = """ { "Title": "Test Restaurant", "TransactionDateTime": "2024-03-15T14:30:00Z", "ReceiptNumber": "42", "WaiterName": "Max", "TableNumber": "5", "SpecialInstruction": null, "HasGangs": true, "HasDishes": false, "Gangs": [ { "Id": 1, "Name": "Vorspeise", "Dishes": [ { "Number": 2, "Name": "Caesar Salad", "GuestPrefix": "", "GuestId": null, "Modifications": { "Removed": [], "Added": [], "HasModifications": false }, "Comment": null } ] }, { "Id": 2, "Name": "Hauptgang", "Dishes": [ { "Number": 1, "Name": "Wiener Schnitzel", "GuestPrefix": "", "GuestId": null, "Modifications": { "Removed": ["Pommes"], "Added": ["Reis"], "HasModifications": true }, "Comment": "Well done" } ] } ], "Dishes": [] } """; var commands = _engine.Render(template, json, LineWidth, BigLineWidth); // Should contain gang names Assert.Contains(commands, c => c.Text.Contains("1. Vorspeise")); Assert.Contains(commands, c => c.Text.Contains("2. Hauptgang")); // Should contain dish names Assert.Contains(commands, c => c.Text.Contains("2x Caesar Salad")); Assert.Contains(commands, c => c.Text.Contains("1x Wiener Schnitzel")); // Should contain modifications Assert.Contains(commands, c => c.Text.Contains("- Pommes") && c.IsBold); Assert.Contains(commands, c => c.Text.Contains("+ Reis") && c.IsBold); // Should contain comment Assert.Contains(commands, c => c.Text.Contains("Comment: Well done") && c.IsBold); // Should have cut between gangs (not after last) var cutCommands = commands.Where(c => c.IsCut).ToList(); Assert.Single(cutCommands); // Gang headers should be red and big var gangHeaders = commands.Where(c => c.Text.Contains("Vorspeise") || c.Text.Contains("Hauptgang")).ToList(); Assert.All(gangHeaders, c => { Assert.True(c.IsRed); Assert.True(c.IsBig); Assert.True(c.IsTall); }); } [Fact] public void RenderKitchenReceipt_DishesAreTall() { var template = File.ReadAllText(GetTemplatePath()); var json = """ { "Title": "Test", "TransactionDateTime": "2024-01-01T00:00:00Z", "ReceiptNumber": "1", "WaiterName": "W", "TableNumber": "1", "SpecialInstruction": null, "HasGangs": true, "HasDishes": false, "Gangs": [ { "Id": 1, "Name": "Gang1", "Dishes": [ { "Number": 1, "Name": "Item", "GuestPrefix": "", "GuestId": null, "Modifications": { "Removed": [], "Added": [], "HasModifications": false }, "Comment": null } ] } ], "Dishes": [] } """; var commands = _engine.Render(template, json, LineWidth, BigLineWidth); // Dish line should be tall var dishCmd = commands.First(c => c.Text.Contains("1x Item")); Assert.True(dishCmd.IsTall); } [Fact] public void RenderKitchenReceipt_TableLineCenteredBigBold() { var template = File.ReadAllText(GetTemplatePath()); var json = """ { "Title": "Test", "TransactionDateTime": "2024-01-01T00:00:00Z", "ReceiptNumber": "1", "WaiterName": "W", "TableNumber": "12", "SpecialInstruction": null, "HasGangs": false, "HasDishes": false, "Gangs": [], "Dishes": [] } """; var commands = _engine.Render(template, json, LineWidth, BigLineWidth); var tableCmd = commands.First(c => c.Text.Contains("Tisch: 12")); Assert.True(tableCmd.IsBig); Assert.True(tableCmd.IsBold); // Should be centered in big font width Assert.True(tableCmd.Text.StartsWith(" ")); } [Fact] public void CompareWithExistingConverter_BasicReceipt() { // Create a KitchenReceipt via the existing converter var receipt = new KitchenReceipt { Title = "Test Restaurant", TransactionDateTime = new DateTime(2024, 3, 15, 14, 30, 0), ReceiptNumber = "42", WaiterName = "Max Mustermann", WaiterId = "W001", TableNumber = "5", SpecialInstruction = null, Gangs = new List(), Dishes = new List() }; var existingConverter = new KitchenReceiptConverter(LineWidth, BigLineWidth); var existingCommands = existingConverter.ConvertToPrintCommands(receipt); // Render with template engine var template = File.ReadAllText(GetTemplatePath()); var jsonData = JsonSerializer.Serialize(new { receipt.Title, TransactionDateTime = receipt.TransactionDateTime.ToString("o"), receipt.ReceiptNumber, receipt.WaiterName, receipt.TableNumber, receipt.SpecialInstruction, HasGangs = receipt.Gangs.Count > 0, HasDishes = receipt.Dishes != null && receipt.Dishes.Any(), receipt.Gangs, receipt.Dishes }); var templateCommands = _engine.Render(template, jsonData, LineWidth, BigLineWidth); // Compare key structural elements // Title should match Assert.Equal(existingCommands[0].Text, templateCommands[0].Text); Assert.Equal(existingCommands[0].IsRed, templateCommands[0].IsRed); Assert.Equal(existingCommands[0].IsBig, templateCommands[0].IsBig); Assert.Equal(existingCommands[0].IsTall, templateCommands[0].IsTall); // Separator should match Assert.Equal(existingCommands[1].Text, templateCommands[1].Text); // Empty line Assert.Equal(existingCommands[2].Text, templateCommands[2].Text); // Date/receipt number line should match formatting Assert.Equal(existingCommands[3].Text, templateCommands[3].Text); // Waiter name Assert.Equal(existingCommands[4].Text, templateCommands[4].Text); // Table number Assert.Equal(existingCommands[5].Text, templateCommands[5].Text); Assert.Equal(existingCommands[5].IsBig, templateCommands[5].IsBig); Assert.Equal(existingCommands[5].IsBold, templateCommands[5].IsBold); } }