@@ -352,42 +352,69 @@ public func verifySnapshot<Value, Format>(
352352 return " Couldn't snapshot value "
353353 }
354354
355- func recordSnapshot( ) throws {
356- try snapshotting. diffing. toData ( diffable) . write ( to: snapshotFileUrl)
355+ func recordSnapshot( writeToDisk: Bool ) throws {
356+ let snapshotData = snapshotting. diffing. toData ( diffable)
357+
358+ if writeToDisk {
359+ try snapshotData. write ( to: snapshotFileUrl)
360+ }
361+
357362 #if !os(Linux) && !os(Windows)
358363 if !isSwiftTesting,
359364 ProcessInfo . processInfo. environment. keys. contains ( " __XCODE_BUILT_PRODUCTS_DIR_PATHS " )
360365 {
361366 XCTContext . runActivity ( named: " Attached Recorded Snapshot " ) { activity in
362- let attachment = XCTAttachment ( contentsOfFile: snapshotFileUrl)
363- activity. add ( attachment)
367+ if writeToDisk {
368+ // Snapshot was written to disk. Create attachment from file
369+ let attachment = XCTAttachment ( contentsOfFile: snapshotFileUrl)
370+ activity. add ( attachment)
371+ } else {
372+ // Snapshot was not written to disk. Create attachment from data and path extension
373+ let typeIdentifier = snapshotting. pathExtension. flatMap ( uniformTypeIdentifier ( fromExtension: ) )
374+
375+ let attachment = XCTAttachment (
376+ uniformTypeIdentifier: typeIdentifier,
377+ name: snapshotFileUrl. lastPathComponent,
378+ payload: snapshotData
379+ )
380+
381+ activity. add ( attachment)
382+ }
364383 }
365384 }
366385 #endif
367386 }
368387
369- guard
370- record != . all,
371- ( record != . missing && record != . failed)
372- || fileManager. fileExists ( atPath: snapshotFileUrl. path)
373- else {
374- try recordSnapshot ( )
388+ if record == . all {
389+ try recordSnapshot ( writeToDisk: true )
375390
376- return SnapshotTestingConfiguration . current? . record == . all
377- ? """
391+ return """
378392 Record mode is on. Automatically recorded snapshot: …
379393
380394 open " \( snapshotFileUrl. absoluteString) "
381395
382396 Turn record mode off and re-run " \( testName) " to assert against the newly-recorded snapshot
383397 """
384- : """
398+ }
399+
400+ guard fileManager. fileExists ( atPath: snapshotFileUrl. path) else {
401+ if record == . never {
402+ try recordSnapshot ( writeToDisk: false )
403+
404+ return """
405+ No reference was found on disk. New snapshot was not recorded because recording is disabled
406+ """
407+ } else {
408+ try recordSnapshot ( writeToDisk: true )
409+
410+ return """
385411 No reference was found on disk. Automatically recorded snapshot: …
386412
387413 open " \( snapshotFileUrl. absoluteString) "
388414
389415 Re-run " \( testName) " to assert against the newly-recorded snapshot.
390416 """
417+ }
391418 }
392419
393420 let data = try Data ( contentsOf: snapshotFileUrl)
@@ -444,7 +471,7 @@ public func verifySnapshot<Value, Format>(
444471 }
445472
446473 if record == . failed {
447- try recordSnapshot ( )
474+ try recordSnapshot ( writeToDisk : true )
448475 failureMessage += " A new snapshot was automatically recorded. "
449476 }
450477
@@ -473,6 +500,19 @@ func sanitizePathComponent(_ string: String) -> String {
473500 . replacingOccurrences ( of: " ^-|-$ " , with: " " , options: . regularExpression)
474501}
475502
503+ #if !os(Linux) && !os(Windows)
504+ func uniformTypeIdentifier( fromExtension pathExtension: String ) -> String ? {
505+ // This can be much cleaner in macOS 11+ using UTType
506+ let unmanagedString = UTTypeCreatePreferredIdentifierForTag (
507+ kUTTagClassFilenameExtension as CFString ,
508+ pathExtension as CFString ,
509+ nil
510+ )
511+
512+ return unmanagedString? . takeRetainedValue ( ) as String ?
513+ }
514+ #endif
515+
476516// We need to clean counter between tests executions in order to support test-iterations.
477517private class CleanCounterBetweenTestCases : NSObject , XCTestObservation {
478518 private static var registered = false
0 commit comments