From 020c17896aa8169dd3b42b6d2582f107cb4334c1 Mon Sep 17 00:00:00 2001 From: EugeneTes Date: Thu, 3 Sep 2026 12:13:41 +0200 Subject: [PATCH] register printer id 0x20 as POS895 across the three dispatch points Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref --- .../PrinterRegistrationTests.cs | 85 +++++++++++++++++++ Inspectron.Epson/DiscoveryService.cs | 1 + .../Printers/PrinterWrapperFactory.cs | 2 + .../Printers/Utils/ReceiptConverterFactory.cs | 1 + 4 files changed, 89 insertions(+) create mode 100644 Inspectron.Epson.Tests/PrinterRegistrationTests.cs diff --git a/Inspectron.Epson.Tests/PrinterRegistrationTests.cs b/Inspectron.Epson.Tests/PrinterRegistrationTests.cs new file mode 100644 index 0000000..6561dd3 --- /dev/null +++ b/Inspectron.Epson.Tests/PrinterRegistrationTests.cs @@ -0,0 +1,85 @@ +using Inspectron.Epson.PrintServer.Printers; +using Inspectron.Epson.PrintServer.Printers.Utils; + +namespace Inspectron.Epson.Tests; + +public class PrinterRegistrationTests +{ + [Fact] + public void WrapperFactory_returns_a_POS895_for_id_0x20() + { + var factory = new PrinterWrapperFactory(); + + var printer = factory.CreatePrinterFromId(0x20, new RecordingEpsonPrinter()); + + Assert.IsType(printer); + } + + [Fact] + public void WrapperFactory_still_returns_a_TM_T30III_for_id_0x01() + { + var factory = new PrinterWrapperFactory(); + + var printer = factory.CreatePrinterFromId(0x01, new RecordingEpsonPrinter()); + + Assert.IsType(printer); + } + + [Fact] + public void WorkareaTicket_uses_48_columns_for_the_POS895() + { + // The switch defaults to the 33-column TM-U220 layout. Without an + // explicit 0x20 case a POS895 prints kitchen tickets far too narrow - + // wrong, but not obviously broken. + // + // Both branches return the same converter type and only the constructor + // argument differs, so comparing types would pass even unfixed. Reading + // the private field is the only way to observe it. + var factory = new ReceiptConverterFactory(); + + var pos895 = factory.Create((int)ReceiptConverterFactory.EReceiptType.WorkareaTicket, 0x20); + + Assert.Equal(48, LineWidthOf(pos895)); + } + + [Fact] + public void WorkareaTicket_still_uses_33_columns_for_the_narrow_printer() + { + var factory = new ReceiptConverterFactory(); + + var u220 = factory.Create((int)ReceiptConverterFactory.EReceiptType.WorkareaTicket, 0x13); + + Assert.Equal(33, LineWidthOf(u220)); + } + + /// + /// Reads KitchenReceiptConverterAdapter._lineWidth. Brittle by design: if the + /// field is renamed this fails loudly rather than silently passing. + /// + private static int LineWidthOf(IReceiptConverter converter) + { + var field = converter.GetType().GetField("_lineWidth", + System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); + + Assert.NotNull(field); + return (int)field!.GetValue(converter)!; + } + + [Fact] + public void Receipt_types_resolve_for_the_POS895() + { + var factory = new ReceiptConverterFactory(); + + foreach (var type in new[] + { + ReceiptConverterFactory.EReceiptType.Receipt, + ReceiptConverterFactory.EReceiptType.WorkareaTicket, + ReceiptConverterFactory.EReceiptType.OrdersOverview, + ReceiptConverterFactory.EReceiptType.Invoice, + ReceiptConverterFactory.EReceiptType.MoneyReturn + }) + { + Assert.NotNull(factory.Create((int)type, 0x20)); + } + } +} diff --git a/Inspectron.Epson/DiscoveryService.cs b/Inspectron.Epson/DiscoveryService.cs index cbbd9ee..c900e62 100644 --- a/Inspectron.Epson/DiscoveryService.cs +++ b/Inspectron.Epson/DiscoveryService.cs @@ -144,6 +144,7 @@ public class DiscoveryService : IDiscoveryService 0x01 => "TM-T30III", 0x0D => "TM-U220II", 0x13 => "TM-U220II", + 0x20 => "POS895", _ => $"Unknown (0x{printerId:X2})" }; } diff --git a/Inspectron.Epson/PrintServer/Printers/PrinterWrapperFactory.cs b/Inspectron.Epson/PrintServer/Printers/PrinterWrapperFactory.cs index 62aa7a4..5835be3 100644 --- a/Inspectron.Epson/PrintServer/Printers/PrinterWrapperFactory.cs +++ b/Inspectron.Epson/PrintServer/Printers/PrinterWrapperFactory.cs @@ -14,6 +14,8 @@ public class PrinterWrapperFactory:IWrapperPrinterFactory return new TM_U220IITranslated(epsonPrinter); case 0x01: return new TM_T30IIITranslated(epsonPrinter); + case 0x20: + return new POS895(epsonPrinter); default: throw new NotSupportedException($"Printer with ID {printerId:X2} is not supported."); } diff --git a/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptConverterFactory.cs b/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptConverterFactory.cs index 8c65f0d..8ec217f 100644 --- a/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptConverterFactory.cs +++ b/Inspectron.Epson/PrintServer/Printers/Utils/ReceiptConverterFactory.cs @@ -15,6 +15,7 @@ public class ReceiptConverterFactory : IReceiptConverterFactory { //0x01=>new BarReceiptConverterAdapter(48, 24), 0x01 => new KitchenReceipt.KitchenReceiptConverterAdapter(48, 24), + 0x20 => new KitchenReceipt.KitchenReceiptConverterAdapter(48, 24), _ => new KitchenReceipt.KitchenReceiptConverterAdapter(33, 20), }, EReceiptType.NextCourse => new KitchenReceipt.KitchenReceiptConverterAdapter(33, 20),