diff --git a/Sources/SnapshotTesting/AssertSnapshot.swift b/Sources/SnapshotTesting/AssertSnapshot.swift index 24868e082..ae298556d 100644 --- a/Sources/SnapshotTesting/AssertSnapshot.swift +++ b/Sources/SnapshotTesting/AssertSnapshot.swift @@ -403,7 +403,7 @@ public func verifySnapshot( } #endif - guard let (failure, attachments) = snapshotting.diffing.diff(reference, diffable) else { + guard let (failure, attachments, diffValue) = snapshotting.diffing.diff(reference, diffable) else { return nil } @@ -413,9 +413,24 @@ public func verifySnapshot( ) let artifactsSubUrl = artifactsUrl.appendingPathComponent(fileName) try fileManager.createDirectory(at: artifactsSubUrl, withIntermediateDirectories: true) - let failedSnapshotFileUrl = artifactsSubUrl.appendingPathComponent( - snapshotFileUrl.lastPathComponent) + + func artifactFileURL(for artifactType: ArtifactType) -> String { + let baseFileName = "\(testName).\(identifier)" + let artifactFileName = "\(baseFileName)\(artifactType.suffix)" + let result = URL(fileURLWithPath: artifactFileName, isDirectory: false) + return result.appendingPathExtension(snapshotting.pathExtension ?? "").path + } + + let failedSnapshotFileUrl = artifactsSubUrl.appendingPathComponent(artifactFileURL(for: .failure)) try snapshotting.diffing.toData(diffable).write(to: failedSnapshotFileUrl) + let referenceSnapshotFileURL = artifactsSubUrl.appendingPathComponent(artifactFileURL(for: .reference)) + try snapshotting.diffing.toData(reference).write(to: referenceSnapshotFileURL) + + if let diffValue { + let diffFileURL = artifactsSubUrl.appendingPathComponent(artifactFileURL(for: .diff)) + try snapshotting.diffing.toData(diffValue).write(to: diffFileURL) + } + if !attachments.isEmpty { #if !os(Linux) && !os(Windows) @@ -498,3 +513,20 @@ private class CleanCounterBetweenTestCases: NSObject, XCTestObservation { } } } + +private enum ArtifactType { + case failure + case reference + case diff + + var suffix: String { + switch self { + case .failure: + return "_failure" + case .reference: + return "_reference" + case .diff: + return "_diff" + } + } +} diff --git a/Sources/SnapshotTesting/Diffing.swift b/Sources/SnapshotTesting/Diffing.swift index c189578ec..0e8ab93f1 100644 --- a/Sources/SnapshotTesting/Diffing.swift +++ b/Sources/SnapshotTesting/Diffing.swift @@ -11,7 +11,8 @@ public struct Diffing { /// Compares two values. If the values do not match, returns a failure message and artifacts /// describing the failure. - public var diff: (Value, Value) -> (String, [XCTAttachment])? + public typealias DiffingResult = (String, [XCTAttachment], Value?) + public var diff: (Value, Value) -> DiffingResult? /// Creates a new `Diffing` on `Value`. /// @@ -22,7 +23,7 @@ public struct Diffing { public init( toData: @escaping (_ value: Value) -> Data, fromData: @escaping (_ data: Data) -> Value, - diff: @escaping (_ lhs: Value, _ rhs: Value) -> (String, [XCTAttachment])? + diff: @escaping (_ lhs: Value, _ rhs: Value) -> DiffingResult? ) { self.toData = toData self.fromData = fromData diff --git a/Sources/SnapshotTesting/Internal/Deprecations.swift b/Sources/SnapshotTesting/Internal/Deprecations.swift index ce93f2f7f..1c283b8a8 100644 --- a/Sources/SnapshotTesting/Internal/Deprecations.swift +++ b/Sources/SnapshotTesting/Internal/Deprecations.swift @@ -94,7 +94,7 @@ public func _verifyInlineSnapshot( let trimmedReference = reference.trimmingCharacters(in: .whitespacesAndNewlines) // Always perform diff, and return early on success! - guard let (failure, attachments) = snapshotting.diffing.diff(trimmedReference, diffable) else { + guard let (failure, attachments, diffValue) = snapshotting.diffing.diff(trimmedReference, diffable) else { return nil } diff --git a/Sources/SnapshotTesting/Snapshotting/Data.swift b/Sources/SnapshotTesting/Snapshotting/Data.swift index 9d2eb467a..7d651fff6 100644 --- a/Sources/SnapshotTesting/Snapshotting/Data.swift +++ b/Sources/SnapshotTesting/Snapshotting/Data.swift @@ -12,7 +12,7 @@ extension Snapshotting where Value == Data, Format == Data { old.count == new.count ? "Expected data to match" : "Expected \(new) to match \(old)" - return (message, []) + return (message, [], nil) } ) } diff --git a/Sources/SnapshotTesting/Snapshotting/NSImage.swift b/Sources/SnapshotTesting/Snapshotting/NSImage.swift index be4fd7cd4..a09e68340 100644 --- a/Sources/SnapshotTesting/Snapshotting/NSImage.swift +++ b/Sources/SnapshotTesting/Snapshotting/NSImage.swift @@ -33,7 +33,8 @@ differenceAttachment.name = "difference" return ( message, - [oldAttachment, newAttachment, differenceAttachment] + [oldAttachment, newAttachment, differenceAttachment], + difference ) } } diff --git a/Sources/SnapshotTesting/Snapshotting/String.swift b/Sources/SnapshotTesting/Snapshotting/String.swift index 44aeab0b4..0626fc074 100644 --- a/Sources/SnapshotTesting/Snapshotting/String.swift +++ b/Sources/SnapshotTesting/Snapshotting/String.swift @@ -10,20 +10,21 @@ extension Diffing where Value == String { /// A line-diffing strategy for UTF-8 text. public static let lines = Diffing( toData: { Data($0.utf8) }, - fromData: { String(decoding: $0, as: UTF8.self) } - ) { old, new in - guard old != new else { return nil } - let hunks = chunk( - diff: SnapshotTesting.diff( - old.split(separator: "\n", omittingEmptySubsequences: false).map(String.init), - new.split(separator: "\n", omittingEmptySubsequences: false).map(String.init) - )) - let failure = - hunks - .flatMap { [$0.patchMark] + $0.lines } - .joined(separator: "\n") - let attachment = XCTAttachment( - data: Data(failure.utf8), uniformTypeIdentifier: "public.patch-file") - return (failure, [attachment]) - } + fromData: { String(decoding: $0, as: UTF8.self) }, + diff: { old, new in + guard old != new else { return nil } + let hunks = chunk( + diff: SnapshotTesting.diff( + old.split(separator: "\n", omittingEmptySubsequences: false).map(String.init), + new.split(separator: "\n", omittingEmptySubsequences: false).map(String.init) + )) + let failure = + hunks + .flatMap { [$0.patchMark] + $0.lines } + .joined(separator: "\n") + let attachment = XCTAttachment( + data: Data(failure.utf8), uniformTypeIdentifier: "public.patch-file") + return (failure, [attachment], nil) + } + ) } diff --git a/Sources/SnapshotTesting/Snapshotting/UIImage.swift b/Sources/SnapshotTesting/Snapshotting/UIImage.swift index 3d1bb5319..4bf82f3a2 100644 --- a/Sources/SnapshotTesting/Snapshotting/UIImage.swift +++ b/Sources/SnapshotTesting/Snapshotting/UIImage.swift @@ -45,7 +45,8 @@ differenceAttachment.name = "difference" return ( message, - [oldAttachment, newAttachment, differenceAttachment] + [oldAttachment, newAttachment, differenceAttachment], + difference ) } }