diff --git a/Tests/ICCeryCoreTests/CupsOptionsFilterTests.swift b/Tests/ICCeryCoreTests/CupsOptionsFilterTests.swift index b4fe1ba..3acb4e2 100644 --- a/Tests/ICCeryCoreTests/CupsOptionsFilterTests.swift +++ b/Tests/ICCeryCoreTests/CupsOptionsFilterTests.swift @@ -24,6 +24,18 @@ final class CupsOptionsFilterTests: XCTestCase { XCTAssertEqual(CupsOptionsFilter.filter(raw), raw) } + /// #180 — a captured `EPIJ_Qual` (and the other canonical quality + /// keys) survives the filter so it wins over the Stage 2 explicit + /// quality in `LpArgs`. + func testKeepsQualityKeys() { + let raw = "EPIJ_Qual=304 CNIJPrintQuality=3 PrintQuality=2 " + + "cupsPrintQuality=High Quality=Best " + + "com.apple.print.JobTicket.PMTotalSidesImaged=0" + XCTAssertEqual(CupsOptionsFilter.filter(raw), + "EPIJ_Qual=304 CNIJPrintQuality=3 PrintQuality=2 " + + "cupsPrintQuality=High Quality=Best") + } + func testKeepsUnknown() { let raw = "VendorFooBar=baz MediaType=Plain" XCTAssertEqual(CupsOptionsFilter.filter(raw), raw) diff --git a/Tests/ICCeryCoreTests/CupsParserTests.swift b/Tests/ICCeryCoreTests/CupsParserTests.swift index 1ffe635..062c1f4 100644 --- a/Tests/ICCeryCoreTests/CupsParserTests.swift +++ b/Tests/ICCeryCoreTests/CupsParserTests.swift @@ -30,7 +30,7 @@ final class CupsParserTests: XCTestCase { MediaType/Media Type: *Stationery PhotographicHighGloss Photographic PhotographicMatte Envelope ColorModel/Output Mode: *RGB Gray Duplex/Duplex: *None DuplexNoTumble DuplexTumble - cupsPrintQuality/cupsPrintQuality: Draft *Normal High + EPIJ_Qual/Print Quality: 301 302 *303 308 304 305 307 """ func testDestinations() { @@ -124,6 +124,12 @@ final class CupsParserTests: XCTestCase { // last (they are colour-ish keys on some drivers — #183/#180). XCTAssertEqual(CupsParsers.detectQualityKey( optionKeys: ["EPIJ_Qual", "Quality", "OutputMode"]), "EPIJ_Qual") + // A full Epson key set — EPIJ_Qual wins over the colour-mode + // key, the generic keys, and Resolution (#180, R11). + XCTAssertEqual(CupsParsers.detectQualityKey( + optionKeys: ["EPIJ_Qual", "OutputMode", "Resolution", + "cupsPrintQuality", "PrintQuality", + "ColorModel"]), "EPIJ_Qual") XCTAssertEqual(CupsParsers.detectQualityKey( optionKeys: ["Quality", "OutputMode", "Resolution"]), "Quality") XCTAssertEqual(CupsParsers.detectQualityKey( @@ -141,32 +147,65 @@ final class CupsParserTests: XCTestCase { let listings = CupsParsers.lpoptionsList(lpoptionsL) let caps = service.capabilities(from: listings, ppd: nil) - // The fixture's only roster member is cupsPrintQuality. - XCTAssertEqual(caps.qualityKey, "cupsPrintQuality") - XCTAssertEqual(caps.qualities.map(\.id), ["Draft", "Normal", "High"]) - XCTAssertEqual(caps.qualityDefault, "Normal") + // EPIJ_Qual is the roster member — all seven Epson codes + // enumerate in the driver's own (non-sorted) order (#180). + XCTAssertEqual(caps.qualityKey, "EPIJ_Qual") + XCTAssertEqual(caps.qualities.map(\.id), + ["301", "302", "303", "308", "304", "305", "307"]) + XCTAssertEqual(caps.qualityDefault, "303") } func testCapabilitiesQualityPpdLabels() { + // Epson XP-55 PPD fragment — the seven `*EPIJ_Qual id/Label` + // lines in the driver's own order (#180). let ppd = """ - *EPIJ_Qual 301/Draft: "" + *OpenUI *EPIJ_Qual/Print Quality: PickOne + *DefaultEPIJ_Qual: 303 + *EPIJ_Qual 301/Fast Economy: "" + *EPIJ_Qual 302/Economy: "" *EPIJ_Qual 303/Normal: "" - *EPIJ_Qual 308/High Speed: "" + *EPIJ_Qual 308/Draft: "" + *EPIJ_Qual 304/Fine: "" + *EPIJ_Qual 305/Quality: "" + *EPIJ_Qual 307/Best Quality: "" + *CloseUI: *EPIJ_Qual """ let service = CupsService() let listings = CupsParsers.lpoptionsList( - "EPIJ_Qual/Print Quality: 301 *303 308\n") + "EPIJ_Qual/Print Quality: 301 302 *303 308 304 305 307\n") let caps = service.capabilities(from: listings, ppd: ppd) XCTAssertEqual(caps.qualityKey, "EPIJ_Qual") XCTAssertEqual(caps.qualities, [ - PrinterQuality(id: "301", name: "Draft"), + PrinterQuality(id: "301", name: "Fast Economy"), + PrinterQuality(id: "302", name: "Economy"), PrinterQuality(id: "303", name: "Normal"), - PrinterQuality(id: "308", name: "High Speed"), + PrinterQuality(id: "308", name: "Draft"), + PrinterQuality(id: "304", name: "Fine"), + PrinterQuality(id: "305", name: "Quality"), + PrinterQuality(id: "307", name: "Best Quality"), ]) XCTAssertEqual(caps.qualityDefault, "303") } + /// #180 — the Epson listing also carries `OutputMode` (a colour + /// mode) and `Resolution`; detection must still pick `EPIJ_Qual`. + func testCapabilitiesQualityEpsonDetection() { + let service = CupsService() + let listings = CupsParsers.lpoptionsList(""" + PageSize/Media Size: *A4 Letter + EPIJ_Qual/Print Quality: 301 302 *303 308 304 305 307 + OutputMode/Color Mode: *Color Mono + Resolution/Resolution: *360dpi 720dpi + """) + let caps = service.capabilities(from: listings, ppd: nil) + + XCTAssertEqual(caps.qualityKey, "EPIJ_Qual") + XCTAssertEqual(caps.qualities.count, 7) + XCTAssertEqual(caps.qualityDefault, "303") + XCTAssertFalse(caps.qualities.contains { $0.id == "Color" }) + } + func testExtractOption() { let options = "PageSize=A4 EPIJ_Qual=303 printer-info='EPSON XP-55'" XCTAssertEqual(CupsParsers.extractOption( diff --git a/Tests/ICCeryCoreTests/LpArgsTests.swift b/Tests/ICCeryCoreTests/LpArgsTests.swift index 7d80f4f..b8bddd5 100644 --- a/Tests/ICCeryCoreTests/LpArgsTests.swift +++ b/Tests/ICCeryCoreTests/LpArgsTests.swift @@ -106,12 +106,12 @@ final class LpArgsTests: XCTestCase { func testQualityDerived() throws { let argv = try build( options: PrintOptions( - orientation: "portrait", mediaType: "Photo", quality: "303"), + orientation: "portrait", mediaType: "Photo", quality: "305"), optionKeys: ["EPIJ_Qual", "MediaType"]) - XCTAssertTrue(argv.contains("EPIJ_Qual=303")) + XCTAssertTrue(argv.contains("EPIJ_Qual=305")) // Emit order: after the media option, before orientation. let media = argv.firstIndex(of: "MediaType=Photo")! - let quality = argv.firstIndex(of: "EPIJ_Qual=303")! + let quality = argv.firstIndex(of: "EPIJ_Qual=305")! let orient = argv.firstIndex(of: "orientation-requested=3")! XCTAssertTrue(media < quality && quality < orient) } diff --git a/Tests/ICCeryCoreTests/PrintSessionViewModelTests.swift b/Tests/ICCeryCoreTests/PrintSessionViewModelTests.swift index 349f391..7a98509 100644 --- a/Tests/ICCeryCoreTests/PrintSessionViewModelTests.swift +++ b/Tests/ICCeryCoreTests/PrintSessionViewModelTests.swift @@ -50,7 +50,7 @@ final class PrintSessionViewModelTests: XCTestCase { printf 'PageSize/Media Size: 4x6 5x7 *A4 Letter Legal Custom.WIDTHxHEIGHT\\n' printf 'InputSlot/Media Source: Auto *Main Rear\\n' printf 'MediaType/Media Type: *Stationery Glossy Matte\\n' - printf 'EPIJ_Qual/Print Quality: 301 302 *303 304\\n' + printf 'EPIJ_Qual/Print Quality: 301 302 *303 308 304 305 307\\n' exit 0 fi printf "printer-info='Mock %s' printer-type=42\\n" "$queue" @@ -106,6 +106,9 @@ final class PrintSessionViewModelTests: XCTestCase { XCTAssertEqual(workflow.print.selectedPaperSize, 3) // Quality seeds from the `*` default on caps load. XCTAssertEqual(workflow.print.selectedQuality, "303") + // All seven Epson codes enumerate in driver order (#180). + XCTAssertEqual(workflow.print.printerCaps.qualities.map(\.id), + ["301", "302", "303", "308", "304", "305", "307"]) } /// `.custom` → synthetic `id: 0` entry whose token is the diff --git a/Tests/ICCeryUITests/Fixtures/bin/lpoptions b/Tests/ICCeryUITests/Fixtures/bin/lpoptions index 35a5dd2..0110476 100755 --- a/Tests/ICCeryUITests/Fixtures/bin/lpoptions +++ b/Tests/ICCeryUITests/Fixtures/bin/lpoptions @@ -1,6 +1,8 @@ #!/bin/sh # Mock lpoptions for Milestone3UITests. `-p ` prints printer-info; -# `-p -l` prints Key/Label listings incl. Epson bypass keys. +# `-p -l` prints Key/Label listings incl. Epson bypass keys and the +# recorded XP-55 EPIJ_Qual line — the driver's own non-sorted order +# (308 sits between 303 and 304, #180). queue="" list=0 for arg in "$@"; do @@ -15,7 +17,7 @@ if [ "$list" = "1" ]; then printf 'PageSize/Media Size: 4x6 5x7 *A4 Letter Legal\n' printf 'InputSlot/Media Source: Auto *Main Rear\n' printf 'MediaType/Media Type: *Stationery PhotographicGlossy PhotographicMatte\n' - printf 'EPIJ_Qual/Print Quality: 301 302 *303 304 305 307 308\n' + printf 'EPIJ_Qual/Print Quality: 301 302 *303 308 304 305 307\n' printf 'EPIJ_CMat/Color Adjust: *0 1 2 3\n' printf 'ColorModel/Output Mode: *RGB Gray\n' exit 0 diff --git a/Tests/ICCeryUITests/Milestone11PrintSettingsUITests.swift b/Tests/ICCeryUITests/Milestone11PrintSettingsUITests.swift index 79df20d..d42052b 100644 --- a/Tests/ICCeryUITests/Milestone11PrintSettingsUITests.swift +++ b/Tests/ICCeryUITests/Milestone11PrintSettingsUITests.swift @@ -136,6 +136,32 @@ final class Milestone11PrintSettingsUITests: XCTestCase { XCTAssertEqual(selection(of: "printerQualitySelect"), "303") } + /// #180 — the quality picker lists all seven Epson `EPIJ_Qual` + /// codes in the driver's own order (308 between 303 and 304); no + /// PPD is injected under UI testing so items show raw tokens. + func testQualityPickerListsAllSevenDriverOptions() throws { + launchAppWithDefaults() + reachPrintPanel() + _ = waitFor("printerStatusBadge") + + let picker = app.popUpButtons["printerQualitySelect"] + XCTAssertTrue(picker.waitForExistence(timeout: 10)) + picker.click() + + let expected = ["301", "302", "303", "308", "304", "305", "307"] + for token in expected { + XCTAssertTrue( + app.menuItems[token].waitForExistence(timeout: 5), + "Missing quality menu item \(token)") + } + let titles = app.menuItems.allElementsBoundByIndex + .map(\.title) + .filter { expected.contains($0) } + XCTAssertEqual(titles, expected) + + app.typeKey(XCUIKeyboardKey.escape, modifierFlags: []) + } + /// The stubbed panel result's captured `PageSize=`/`EPIJ_Qual=` /// apply back into the Stage 2 pickers and reach the `lp` argv /// (R15 — the real modal is never driven).