1. Strengthen POS895 IsCut test: add RecordingEpsonPrinter.CallOrder so the test can assert feeds happen BEFORE the cut, plus a LineFeedBytes count assertion. The prior test could not detect the FeedAsync call being deleted from the IsCut branch (verified: test now fails when that line is removed, passes when restored). 2. CompositeDiscoveryService: distinguish "some children failed" from "every child failed". Per-child failures are still absorbed, but if every discovery service throws, the composite now rethrows instead of silently returning an empty list. Previously a total discovery failure (e.g. a routeless interface) looked like "discovery succeeded, found nothing" to PrinterDiscoveryBackgroundTask, which would expire and unregister every known printer after the retention window, discarding their queued jobs. Also corrected a doc comment that overstated Task.WhenAll's timeout guarantee. 3. Update CLAUDE.md to describe the POS895/POS896 work as shipped rather than future work: added the Inspectron.Epson.Tests and Pos895Test projects, a dotnet test command, SprtDiscoveryService/ CompositeDiscoveryService/POS895 in the architecture sections, the 0x20 printer-ID note, and the established SPRT hardware facts. Claude-Session: https://claude.ai/code/session_01E6N3P4nSZLtp4BC2LXVref
114 lines
3.1 KiB
C#
114 lines
3.1 KiB
C#
using Inspectron.Epson.PrintServer.Printers;
|
|
using Inspectron.Epson.PrintServer.Printers.Utils;
|
|
|
|
namespace Inspectron.Epson.Tests;
|
|
|
|
public class POS895Tests
|
|
{
|
|
private static POS895 Make(out RecordingEpsonPrinter fake)
|
|
{
|
|
fake = new RecordingEpsonPrinter();
|
|
return new POS895(fake) { SkipDelays = true };
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PrintAsync_never_uses_ESC_d_to_feed()
|
|
{
|
|
// This firmware ignores ESC d. Feeding with it would cut the last line.
|
|
var printer = Make(out var fake);
|
|
|
|
await printer.PrintAsync(new List<PrintCommand>
|
|
{
|
|
new PrintCommand("hello")
|
|
});
|
|
|
|
Assert.Empty(fake.FeedLineCalls);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PrintAsync_feeds_with_literal_line_feeds_before_finishing()
|
|
{
|
|
var printer = Make(out var fake);
|
|
|
|
await printer.PrintAsync(new List<PrintCommand>
|
|
{
|
|
new PrintCommand("hello")
|
|
});
|
|
|
|
Assert.Equal(10, fake.LineFeedBytes);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PrintAsync_writes_the_command_text()
|
|
{
|
|
var printer = Make(out var fake);
|
|
|
|
await printer.PrintAsync(new List<PrintCommand>
|
|
{
|
|
new PrintCommand("hello")
|
|
});
|
|
|
|
Assert.Contains(fake.Text, t => t.Contains("hello"));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PrintAsync_handles_an_IsCut_command_with_line_feeds_then_a_cut()
|
|
{
|
|
var printer = Make(out var fake);
|
|
|
|
await printer.PrintAsync(new List<PrintCommand>
|
|
{
|
|
new PrintCommand("a"),
|
|
new PrintCommand("") { IsCut = true }
|
|
});
|
|
|
|
Assert.Empty(fake.FeedLineCalls);
|
|
Assert.Equal(1, fake.CutCount);
|
|
|
|
// 10 LF for the IsCut branch plus 10 for the trailing feed.
|
|
Assert.Equal(20, fake.LineFeedBytes);
|
|
|
|
// The cut must be preceded by a feed, or the receipt is cut through its
|
|
// last printed line - the exact failure ESC d would have caused.
|
|
int cutIndex = fake.CallOrder.IndexOf("cut");
|
|
Assert.True(cutIndex > 0, "expected a feed before the cut");
|
|
Assert.StartsWith("raw:", fake.CallOrder[cutIndex - 1]);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PrintImageAsync_uses_bit_image_mode_at_576_dots()
|
|
{
|
|
// GS ( L prints nothing on this firmware, so LoadImageAsync must not be used.
|
|
var printer = Make(out var fake);
|
|
|
|
await printer.PrintImageAsync("logo.png");
|
|
|
|
Assert.Empty(fake.RasterImages);
|
|
var image = Assert.Single(fake.BitModeImages);
|
|
Assert.Equal("logo.png", image.Path);
|
|
Assert.Equal(EpsonCommands.BitImageMode.DoubleDensity24Dot, image.Mode);
|
|
Assert.Equal(576, image.MaxWidth);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task PrintImageAsync_does_not_use_absolute_positioning()
|
|
{
|
|
// ESC $ is unverified on this firmware; the logo spans the full width.
|
|
var printer = Make(out var fake);
|
|
|
|
await printer.PrintImageAsync("logo.png");
|
|
|
|
Assert.Empty(fake.AbsolutePositions);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Cut_cuts_once()
|
|
{
|
|
var printer = Make(out var fake);
|
|
|
|
await printer.Cut();
|
|
|
|
Assert.Equal(1, fake.CutCount);
|
|
}
|
|
}
|