Skip to content

Commit

Permalink
Normalize color spaces before comparing images
Browse files Browse the repository at this point in the history
Use the sRGB converted snapshot when doing the perceptual comparison

This reduces the chances of failures when comparing snapshots in different color spaces
  • Loading branch information
ejensen committed Oct 22, 2022
1 parent a02ef9a commit aa9aacc
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 27 deletions.
6 changes: 3 additions & 3 deletions Sources/SnapshotTesting/Snapshotting/NSImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ private func compare(_ old: NSImage, _ new: NSImage, precision: Float, perceptua
}
if perceptualPrecision < 1, #available(macOS 10.13, *) {
return perceptuallyCompare(
CIImage(cgImage: oldCgImage),
CIImage(cgImage: newCgImage),
CIImage(cgImage: oldContext.makeImage() ?? oldCgImage),
CIImage(cgImage: newerContext.makeImage() ?? newerCgImage),
pixelPrecision: precision,
perceptualPrecision: perceptualPrecision
)
Expand All @@ -119,7 +119,7 @@ private func compare(_ old: NSImage, _ new: NSImage, precision: Float, perceptua

private func context(for cgImage: CGImage) -> CGContext? {
guard
let space = cgImage.colorSpace,
let space = CGColorSpace(name: CGColorSpace.sRGB) ?? cgImage.colorSpace,
let context = CGContext(
data: nil,
width: cgImage.width,
Expand Down
9 changes: 6 additions & 3 deletions Sources/SnapshotTesting/Snapshotting/UIImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ private func compare(_ old: UIImage, _ new: UIImage, precision: Float, perceptua
let pixelCount = oldCgImage.width * oldCgImage.height
let byteCount = imageContextBytesPerPixel * pixelCount
var oldBytes = [UInt8](repeating: 0, count: byteCount)
guard let oldData = context(for: oldCgImage, data: &oldBytes)?.data else {
guard
let oldContext = context(for: oldCgImage, data: &oldBytes),
let oldData = oldContext.data
else {
return "Reference image's data could not be loaded."
}
if let newContext = context(for: newCgImage), let newData = newContext.data {
Expand All @@ -115,8 +118,8 @@ private func compare(_ old: UIImage, _ new: UIImage, precision: Float, perceptua
}
if perceptualPrecision < 1, #available(iOS 11.0, tvOS 11.0, *) {
return perceptuallyCompare(
CIImage(cgImage: oldCgImage),
CIImage(cgImage: newCgImage),
CIImage(cgImage: oldContext.makeImage() ?? oldCgImage),
CIImage(cgImage: newerContext.makeImage() ?? newerCgImage),
pixelPrecision: precision,
perceptualPrecision: perceptualPrecision
)
Expand Down
57 changes: 36 additions & 21 deletions Tests/SnapshotTestingTests/SnapshotTestingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import XCTest
@testable import SnapshotTesting

final class SnapshotTestingTests: XCTestCase {
private let fixturesURL = URL(fileURLWithPath: #file, isDirectory: false)
.deletingLastPathComponent()
.appendingPathComponent("__Fixtures__", isDirectory: true)

override func setUp() {
super.setUp()
diffTool = "ksdiff"
Expand Down Expand Up @@ -291,19 +295,40 @@ final class SnapshotTestingTests: XCTestCase {

func testImagePrecision() throws {
#if os(iOS) || os(tvOS) || os(macOS)
let imageURL = URL(fileURLWithPath: String(#file), isDirectory: false)
.deletingLastPathComponent()
.appendingPathComponent("__Fixtures__/testImagePrecision.reference.png")
let imageURL = fixturesURL
.appendingPathComponent(sanitizePathComponent(#function), isDirectory: false)
.appendingPathExtension("reference.png")
#if os(iOS) || os(tvOS)
let image = try XCTUnwrap(UIImage(contentsOfFile: imageURL.path))
#elseif os(macOS)
let image = try XCTUnwrap(NSImage(byReferencing: imageURL))
#endif

assertSnapshot(matching: image, as: .image(precision: 0.995), named: "exact")
if #available(iOS 11.0, tvOS 11.0, macOS 10.13, *) {
assertSnapshot(matching: image, as: .image(perceptualPrecision: 0.98), named: "perceptual")
}
assertSnapshot(matching: image, as: .image(perceptualPrecision: 0.98), named: "perceptual")
#endif
}

func testImageColorSpaceConversion() throws {
#if os(iOS) || os(tvOS) || os(macOS)
let fileName = URL(fileURLWithPath: #file, isDirectory: false).deletingPathExtension().lastPathComponent
let baseImageURL = URL(fileURLWithPath: #file, isDirectory: false)
.deletingLastPathComponent()
.appendingPathComponent("__Snapshots__", isDirectory: true)
.appendingPathComponent(fileName, isDirectory: true)
.appendingPathComponent(sanitizePathComponent(#function), isDirectory: false)
let p3ImageURL = baseImageURL.appendingPathExtension("p3.png")
let sRGBImageURL = baseImageURL.appendingPathExtension("srgb.png")
#if os(iOS) || os(tvOS)
let p3Image = try XCTUnwrap(UIImage(contentsOfFile: p3ImageURL.path))
let sRGBImage = try XCTUnwrap(UIImage(contentsOfFile: sRGBImageURL.path))
#elseif os(macOS)
let p3Image = try XCTUnwrap(NSImage(byReferencing: p3ImageURL))
let sRGBImage = try XCTUnwrap(NSImage(byReferencing: sRGBImageURL))
#endif

assertSnapshot(matching: p3Image, as: .image(perceptualPrecision: 0.99), named: "srgb")
assertSnapshot(matching: sRGBImage, as: .image(perceptualPrecision: 0.99), named: "p3")
#endif
}

Expand All @@ -319,9 +344,7 @@ final class SnapshotTestingTests: XCTestCase {
// sphereNode.position = SCNVector3Zero
// scene.rootNode.addChildNode(sphereNode)
//
// sphereGeometry.firstMaterial?.diffuse.contents = URL(fileURLWithPath: String(#file), isDirectory: false)
// .deletingLastPathComponent()
// .appendingPathComponent("__Fixtures__/earth.png")
// sphereGeometry.firstMaterial?.diffuse.contents = fixturesURL.appendingPathComponent("earth.png", isDirectory: false)
//
// let cameraNode = SCNNode()
// cameraNode.camera = SCNCamera()
Expand Down Expand Up @@ -1029,9 +1052,7 @@ final class SnapshotTestingTests: XCTestCase {

func testWebView() throws {
#if os(iOS) || os(macOS)
let fixtureUrl = URL(fileURLWithPath: String(#file), isDirectory: false)
.deletingLastPathComponent()
.appendingPathComponent("__Fixtures__/pointfree.html")
let fixtureUrl = fixturesURL.appendingPathComponent("pointfree.html", isDirectory: false)
let html = try String(contentsOf: fixtureUrl)
let webView = WKWebView()
webView.loadHTMLString(html, baseURL: nil)
Expand Down Expand Up @@ -1080,9 +1101,7 @@ final class SnapshotTestingTests: XCTestCase {
let label = UILabel()
label.text = "Hello, Blob!"

let fixtureUrl = URL(fileURLWithPath: String(#file), isDirectory: false)
.deletingLastPathComponent()
.appendingPathComponent("__Fixtures__/pointfree.html")
let fixtureUrl = fixturesURL.appendingPathComponent("pointfree.html", isDirectory: false)
let html = try String(contentsOf: fixtureUrl)
let webView = WKWebView()
webView.loadHTMLString(html, baseURL: nil)
Expand Down Expand Up @@ -1112,9 +1131,7 @@ final class SnapshotTestingTests: XCTestCase {
let webView = WKWebView()
webView.navigationDelegate = manipulatingWKWebViewNavigationDelegate

let fixtureUrl = URL(fileURLWithPath: String(#file), isDirectory: false)
.deletingLastPathComponent()
.appendingPathComponent("__Fixtures__/pointfree.html")
let fixtureUrl = fixturesURL.appendingPathComponent("pointfree.html", isDirectory: false)
let html = try String(contentsOf: fixtureUrl)
webView.loadHTMLString(html, baseURL: nil)
if !ProcessInfo.processInfo.environment.keys.contains("GITHUB_WORKFLOW") {
Expand Down Expand Up @@ -1159,9 +1176,7 @@ final class SnapshotTestingTests: XCTestCase {
let webView = WKWebView()
webView.navigationDelegate = cancellingWKWebViewNavigationDelegate

let fixtureUrl = URL(fileURLWithPath: String(#file), isDirectory: false)
.deletingLastPathComponent()
.appendingPathComponent("__Fixtures__/pointfree.html")
let fixtureUrl = fixturesURL.appendingPathComponent("pointfree.html", isDirectory: false)
let html = try String(contentsOf: fixtureUrl)
webView.loadHTMLString(html, baseURL: nil)
if !ProcessInfo.processInfo.environment.keys.contains("GITHUB_WORKFLOW") {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit aa9aacc

Please sign in to comment.