Files
iccery-v2-mac/Tests/ICCeryCoreTests/PrintTicketTests.swift
gronod fc1530ab2e
macOS CI / build-and-test (push) Skipped
feat(print): capture native print ticket on panel OK (#201 Phase 2)
Serialise PMPrintSettings/PMPageFormat to XML data plus a plist-safe
NSPrintInfo dictionary snapshot (PrintTicket), restore via
PM*CreateWithDataRepresentation -> PMCopy* -> PMSessionValidate* ->
updateFromPM*, and refuse cross-queue replay (R3).

PrintPanelService.showProperties now returns PanelCaptureResult; the
view model stores tickets in capturedTickets keyed by queue.

Also fixes a latent over-release: PMSessionGetCurrentPrinter hands back
the session's own printer (borrowed) — the extracted currentPrinterID
was PMRelease-ing it, which dangled the session and crashed AppKit's
_printerInPrintSession path and session teardown.
2026-09-17 13:43:43 +01:00

122 lines
4.5 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import AppKit
import Foundation
import XCTest
@testable import ICCery
/// Issue #201 Phase 2 — `PMTicketBridge.serialise`/`restore` byte
/// round-trip, cross-queue refusal (R3), plist fallback, and the
/// `takeRetainedValue` ownership canary.
@MainActor
final class PrintTicketTests: XCTestCase {
/// The queue a destination `NSPrintInfo` will report as bound —
/// the session's current printer, else the Cocoa printer name,
/// else a synthetic token for a queue-less environment.
private func boundQueue(of printInfo: NSPrintInfo) -> String {
PMTicketBridge.currentPrinterID(
session: PMTicketBridge.session(printInfo),
fallback: "UnboundQueue")
}
func testRoundTripRetainsVendorValue() throws {
let source = NSPrintInfo()
XCTAssertTrue(
PMTicketBridge.setValue(
"305", forKey: "EPIJ_Qual", locked: false,
in: PMTicketBridge.settings(source),
context: "PrintTicketTests"))
let target = NSPrintInfo()
let ticket = try PMTicketBridge.serialise(
source, queue: boundQueue(of: target))
try PMTicketBridge.restore(ticket, into: target)
XCTAssertEqual(
PMTicketBridge.stringValue(
forKey: "EPIJ_Qual",
in: PMTicketBridge.settings(target)),
"305")
}
func testPrintSettingsDataIsXmlPlist() throws {
let ticket = try PMTicketBridge.serialise(
NSPrintInfo(), queue: "AnyQueue")
XCTAssertFalse(ticket.printSettings.isEmpty)
XCTAssertFalse(ticket.pageFormat.isEmpty)
XCTAssertEqual(
String(decoding: ticket.printSettings.prefix(5),
as: UTF8.self),
"<?xml")
}
func testCrossQueueReplayIsRefused() throws {
let target = NSPrintInfo()
let bound = boundQueue(of: target)
let foreign = "DefinitelyNot_\(bound)"
try XCTSkipIf(
bound == foreign,
"destination resolved to the foreign queue")
// Sentinel on the destination — a refused restore must leave
// the target's settings untouched.
XCTAssertTrue(
PMTicketBridge.setValue(
"999", forKey: "EPIJ_Qual", locked: false,
in: PMTicketBridge.settings(target),
context: "PrintTicketTests"))
let source = NSPrintInfo()
XCTAssertTrue(
PMTicketBridge.setValue(
"305", forKey: "EPIJ_Qual", locked: false,
in: PMTicketBridge.settings(source),
context: "PrintTicketTests"))
let ticket = try PMTicketBridge.serialise(
source, queue: foreign)
try PMTicketBridge.restore(ticket, into: target)
XCTAssertEqual(
PMTicketBridge.stringValue(
forKey: "EPIJ_Qual",
in: PMTicketBridge.settings(target)),
"999")
}
func testPrintInfoPlistFallbackRoundTrips() throws {
let source = NSPrintInfo()
// The `com.apple.print.PrintSettings` entry only exists once
// something writes into the attribute dictionary — the
// ColorSync mirror does this on the real panel path.
source.dictionary()[
NSPrintInfo.AttributeKey("com.apple.print.PrintSettings")] =
["PMColorMatchingMode": "APCustomColorMatching"]
as NSDictionary
let ticket = try PMTicketBridge.serialise(
source, queue: "AnyQueue")
let data = try XCTUnwrap(ticket.printInfoPlist)
let object = try PropertyListSerialization.propertyList(
from: data, options: [], format: nil)
let dictionary = try XCTUnwrap(object as? [String: Any])
XCTAssertNotNil(
dictionary["com.apple.print.PrintSettings"])
}
/// 200× serialise loop — a `takeRetainedValue` over/under-release
/// canary. Byte counts must stay stable; ASan + Malloc Scribble
/// catches an actual imbalance.
func testSerialiseIsStableAcrossIterations() throws {
let source = NSPrintInfo()
var firstCount: Int?
for _ in 0..<200 {
let ticket = try PMTicketBridge.serialise(
source, queue: "AnyQueue")
if let first = firstCount {
XCTAssertEqual(ticket.printSettings.count, first)
} else {
firstCount = ticket.printSettings.count
}
}
XCTAssertNotNil(firstCount)
}
}