From bdbc7cdbfe62eaa9757d1a9f76b3d01985f1386b Mon Sep 17 00:00:00 2001 From: Tomoki Kobayashi Date: Tue, 22 Sep 2026 08:28:05 +0900 Subject: [PATCH] Restore perceptualPrecision on the canvas goldens (#49) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit swift-snapshot-testing 1.19.6 fixes the crash that forced byte-wise comparison in #48: the perceptual path passed a bare CGRect as CIAreaAverage's inputExtent, which Core Image on macOS 27 rejected with an uncaught -[NSConcreteValue CGRectValue] exception, killing the whole test process (pointfreeco/swift-snapshot-testing#1120). Floor the dependency at 1.19.6 rather than leaving it at 1.18.0. The perceptual path is only reached when bytes differ, so an older resolution would keep passing locally and crash wherever antialiasing drifts. Verified on macOS 27.0 (26A428) / Xcode 27.0 (27A266a) — the combination that crashed — by passing two deliberately different renders through Snapshotting.canvasGolden.diffing.diff, which now reports a difference instead of taking down the process. A green suite alone would not have shown this: the goldens match byte for byte on the machine that recorded them, so the perceptual path never runs. The goldens themselves are unchanged; perceptual comparison is strictly more permissive than the byte-wise one they were recorded against. --- CLAUDE.md | 2 +- Package.resolved | 6 +++--- Package.swift | 2 +- .../CanvasGoldenSnapshotting.swift | 18 ++++++++---------- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e04e660..e69d83d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,7 +91,7 @@ SVG tests avoid raw string literals (`#"..."#`) when the expected string contain **Drawing-scenario golden tests.** `Tests/TortoiseTestSupport/` (a non-product target) defines `DrawingScenario.all` — feature-grouped tortoise programs that together cover every `TortoiseCommand` case. Both renderers are verified against the same scenarios via pointfreeco/swift-snapshot-testing: - `TortoiseSVGTests/DrawingScenarioSVGTests` compares full SVG strings against goldens in `Tests/TortoiseSVGTests/__Snapshots__/`. -- `TortoiseUITests/DrawingScenarioCanvasTests` (macOS-only, `#if os(macOS)`) renders `TortoiseCanvas` via `ImageRenderer` (`scale = 2`, instant mode forced by prepending `speed = 0`) and compares PNGs in `Tests/TortoiseUITests/__Snapshots__/` with `.canvasGolden` (byte-wise `precision: 0.995`, defined in `CanvasGoldenSnapshotting.swift`) to absorb OS-level antialiasing drift. **Do not add `perceptualPrecision`**: swift-snapshot-testing's perceptual path passes a bare `CGRect` to `CIAreaAverage`, which Core Image on macOS 27 rejects with an uncaught exception that kills the whole test process. It only triggers when bytes differ, so it passes on the recording macOS and crashes on the CI runner's. Tracked in #49 (still reproduces on Xcode 27.0 GA; re-check once the runner image ships a GA macOS 27). +- `TortoiseUITests/DrawingScenarioCanvasTests` (macOS-only, `#if os(macOS)`) renders `TortoiseCanvas` via `ImageRenderer` (`scale = 2`, instant mode forced by prepending `speed = 0`) and compares PNGs in `Tests/TortoiseUITests/__Snapshots__/` with `.canvasGolden` (`precision: 0.995, perceptualPrecision: 0.98`, defined in `CanvasGoldenSnapshotting.swift`) to absorb OS-level antialiasing drift. `perceptualPrecision` requires **swift-snapshot-testing 1.19.6 or newer**, which is why `Package.swift` floors the dependency there rather than at the version SwiftPM would otherwise pick: through 1.19.5 the perceptual path passed a bare `CGRect` to `CIAreaAverage`, which Core Image on macOS 27 rejected with an uncaught exception that killed the whole test process (#49, fixed upstream in pointfreeco/swift-snapshot-testing#1120). That path is only reached when bytes differ, so a byte-identical run never exercises it — don't read a green local suite as proof the floor can be lowered. After intentionally changing scenario programs or renderer output, re-record **both** golden sets in the same commit and visually inspect them: diff --git a/Package.resolved b/Package.resolved index 7463ab3..5fbedb5 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "fecdfcddc1cd84994c47f489a833b228ebc5b8fe5f291fd6cceda440550ceb8a", + "originHash" : "a0706b87df21c4105ede5e0be61a46e8dab893ab49c1fb70251b67e04c8edee8", "pins" : [ { "identity" : "swift-custom-dump", @@ -33,8 +33,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-snapshot-testing", "state" : { - "revision" : "59a99c458de4d2dee580529b61b4f78dca7b7fa6", - "version" : "1.19.4" + "revision" : "28e5de025e3fd98991791bfbf83023ab3708da03", + "version" : "1.19.6" } }, { diff --git a/Package.swift b/Package.swift index 49e2fef..8d544d3 100644 --- a/Package.swift +++ b/Package.swift @@ -83,7 +83,7 @@ let package = Package( products: products, dependencies: [ .package(url: "https://github.com/swiftlang/swift-docc-plugin", from: "1.4.0"), - .package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.18.0"), + .package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.19.6"), ], targets: targets ) diff --git a/Tests/TortoiseUITests/CanvasGoldenSnapshotting.swift b/Tests/TortoiseUITests/CanvasGoldenSnapshotting.swift index c88c2dc..107c236 100644 --- a/Tests/TortoiseUITests/CanvasGoldenSnapshotting.swift +++ b/Tests/TortoiseUITests/CanvasGoldenSnapshotting.swift @@ -5,19 +5,17 @@ extension Snapshotting where Value == NSImage, Format == NSImage { /// The comparison every canvas PNG golden uses. /// - /// Byte-wise with a small tolerance, deliberately *without* - /// `perceptualPrecision`. swift-snapshot-testing's perceptual path passes a + /// `perceptualPrecision` absorbs the OS-level antialiasing drift that makes + /// byte-wise comparison of rendered text and curves brittle across machines. + /// + /// It was removed for a while: swift-snapshot-testing through 1.19.5 passed a /// bare `CGRect` as `CIAreaAverage`'s `inputExtent`, which Core Image on /// macOS 27 rejects with an uncaught `-[NSConcreteValue CGRectValue]` - /// exception — crashing the whole test process rather than failing one - /// test. An exact match never reaches that path, which is why the goldens - /// still pass on the macOS they were recorded on. - /// - /// Still reproduces on Xcode 27.0 GA (27A266a); the CI runner's macOS 27 is - /// itself still a beta build, so whether `perceptualPrecision` can ever come - /// back is tracked in #49. + /// exception — crashing the whole test process rather than failing one test. + /// Fixed upstream in 1.19.6 (pointfreeco/swift-snapshot-testing#1120), which + /// is why `Package.swift` floors the dependency there. See #49. static var canvasGolden: Snapshotting { - .image(precision: 0.995) + .image(precision: 0.995, perceptualPrecision: 0.98) } } #endif