-
Notifications
You must be signed in to change notification settings - Fork 120
Add support for attachments to the Foundation cross-import overlay. #819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
65e006e
Add support for attachments to the Foundation cross-import overlay.
grynspan 6e75bbe
URL inits need source location
grynspan 1421970
Rebase after type rename
grynspan d966c05
Merge branch 'main' into jgrynspan/foundation-attachment-overlay
grynspan 06cc43d
Update DocC references
grynspan 9b24b94
Fix test
grynspan f0b15bf
Don't use package access level, it won't work correctly when building…
grynspan 6f204f5
Use GitHub-style warning callouts
grynspan 939e578
Incorporate feedback
grynspan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
28 changes: 28 additions & 0 deletions
28
Sources/Overlays/_Testing_Foundation/Attachments/Attachable+Encodable+NSSecureCoding.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2024 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors | ||
// | ||
|
||
#if canImport(Foundation) | ||
@_spi(Experimental) public import Testing | ||
public import Foundation | ||
|
||
// This implementation is necessary to let the compiler disambiguate when a type | ||
// conforms to both Encodable and NSSecureCoding. It is hidden from the DocC | ||
// compiler because it appears redundant next to the other two implementations | ||
// (which explicitly document what happens when a type conforms to both | ||
// protocols.) | ||
|
||
@_spi(Experimental) | ||
extension Attachable where Self: Encodable & NSSecureCoding { | ||
@_documentation(visibility: private) | ||
public func withUnsafeBufferPointer<R>(for attachment: borrowing Attachment<Self>, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R { | ||
try _Testing_Foundation.withUnsafeBufferPointer(encoding: self, for: attachment, body) | ||
} | ||
} | ||
#endif |
98 changes: 98 additions & 0 deletions
98
Sources/Overlays/_Testing_Foundation/Attachments/Attachable+Encodable.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2024 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors | ||
// | ||
|
||
#if canImport(Foundation) | ||
@_spi(Experimental) public import Testing | ||
private import Foundation | ||
|
||
/// A common implementation of ``withUnsafeBufferPointer(for:_:)`` that is | ||
/// used when a type conforms to `Encodable`, whether or not it also conforms | ||
/// to `NSSecureCoding`. | ||
/// | ||
/// - Parameters: | ||
grynspan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// - attachableValue: The value to encode. | ||
/// - attachment: The attachment that is requesting a buffer (that is, the | ||
/// attachment containing this instance.) | ||
/// - body: A function to call. A temporary buffer containing a data | ||
/// representation of this instance is passed to it. | ||
/// | ||
/// - Returns: Whatever is returned by `body`. | ||
/// | ||
/// - Throws: Whatever is thrown by `body`, or any error that prevented the | ||
/// creation of the buffer. | ||
func withUnsafeBufferPointer<E, R>(encoding attachableValue: borrowing E, for attachment: borrowing Attachment<E>, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R where E: Attachable & Encodable { | ||
let format = try EncodingFormat(for: attachment) | ||
|
||
let data: Data | ||
switch format { | ||
case let .propertyListFormat(propertyListFormat): | ||
let plistEncoder = PropertyListEncoder() | ||
plistEncoder.outputFormat = propertyListFormat | ||
data = try plistEncoder.encode(attachableValue) | ||
case .default: | ||
// The default format is JSON. | ||
fallthrough | ||
case .json: | ||
// We cannot use our own JSON encoding wrapper here because that would | ||
// require it be exported with (at least) package visibility which would | ||
// create a visible external dependency on Foundation in the main testing | ||
// library target. | ||
data = try JSONEncoder().encode(attachableValue) | ||
grynspan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
return try data.withUnsafeBytes(body) | ||
} | ||
|
||
// Implement the protocol requirements generically for any encodable value by | ||
// encoding to JSON. This lets developers provide trivial conformance to the | ||
// protocol for types that already support Codable. | ||
@_spi(Experimental) | ||
extension Attachable where Self: Encodable { | ||
/// Encode this value into a buffer using either [`PropertyListEncoder`](https://developer.apple.com/documentation/foundation/propertylistencoder) | ||
/// or [`JSONEncoder`](https://developer.apple.com/documentation/foundation/jsonencoder), | ||
/// then call a function and pass that buffer to it. | ||
/// | ||
/// - Parameters: | ||
/// - attachment: The attachment that is requesting a buffer (that is, the | ||
/// attachment containing this instance.) | ||
/// - body: A function to call. A temporary buffer containing a data | ||
/// representation of this instance is passed to it. | ||
/// | ||
/// - Returns: Whatever is returned by `body`. | ||
/// | ||
/// - Throws: Whatever is thrown by `body`, or any error that prevented the | ||
/// creation of the buffer. | ||
/// | ||
/// The testing library uses this function when writing an attachment to a | ||
/// test report or to a file on disk. The encoding used depends on the path | ||
/// extension specified by the value of `attachment`'s ``Testing/Attachment/preferredName`` | ||
/// property: | ||
/// | ||
/// | Extension | Encoding Used | Encoder Used | | ||
/// |-|-|-| | ||
/// | `".xml"` | XML property list | [`PropertyListEncoder`](https://developer.apple.com/documentation/foundation/propertylistencoder) | | ||
/// | `".plist"` | Binary property list | [`PropertyListEncoder`](https://developer.apple.com/documentation/foundation/propertylistencoder) | | ||
/// | None, `".json"` | JSON | [`JSONEncoder`](https://developer.apple.com/documentation/foundation/jsonencoder) | | ||
/// | ||
/// OpenStep-style property lists are not supported. If a value conforms to | ||
/// _both_ [`Encodable`](https://developer.apple.com/documentation/swift/encodable) | ||
/// _and_ [`NSSecureCoding`](https://developer.apple.com/documentation/foundation/nssecurecoding), | ||
/// the default implementation of this function uses the value's conformance | ||
/// to `Encodable`. | ||
/// | ||
/// - Note: On Apple platforms, if the attachment's preferred name includes | ||
/// some other path extension, that path extension must represent a type | ||
/// that conforms to [`UTType.propertyList`](https://developer.apple.com/documentation/uniformtypeidentifiers/uttype-swift.struct/propertylist) | ||
/// or to [`UTType.json`](https://developer.apple.com/documentation/uniformtypeidentifiers/uttype-swift.struct/json). | ||
public func withUnsafeBufferPointer<R>(for attachment: borrowing Attachment<Self>, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R { | ||
try _Testing_Foundation.withUnsafeBufferPointer(encoding: self, for: attachment, body) | ||
} | ||
} | ||
#endif |
78 changes: 78 additions & 0 deletions
78
Sources/Overlays/_Testing_Foundation/Attachments/Attachable+NSSecureCoding.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2024 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See https://swift.org/LICENSE.txt for license information | ||
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors | ||
// | ||
|
||
#if canImport(Foundation) | ||
@_spi(Experimental) public import Testing | ||
public import Foundation | ||
|
||
// As with Encodable, implement the protocol requirements for | ||
// NSSecureCoding-conformant classes by default. The implementation uses | ||
// NSKeyedArchiver for encoding. | ||
@_spi(Experimental) | ||
extension Attachable where Self: NSSecureCoding { | ||
/// Encode this object using [`NSKeyedArchiver`](https://developer.apple.com/documentation/foundation/nskeyedarchiver) | ||
/// into a buffer, then call a function and pass that buffer to it. | ||
/// | ||
/// - Parameters: | ||
/// - attachment: The attachment that is requesting a buffer (that is, the | ||
/// attachment containing this instance.) | ||
/// - body: A function to call. A temporary buffer containing a data | ||
/// representation of this instance is passed to it. | ||
/// | ||
/// - Returns: Whatever is returned by `body`. | ||
/// | ||
/// - Throws: Whatever is thrown by `body`, or any error that prevented the | ||
/// creation of the buffer. | ||
/// | ||
/// The testing library uses this function when writing an attachment to a | ||
/// test report or to a file on disk. The encoding used depends on the path | ||
/// extension specified by the value of `attachment`'s ``Testing/Attachment/preferredName`` | ||
/// property: | ||
/// | ||
/// | Extension | Encoding Used | Encoder Used | | ||
/// |-|-|-| | ||
/// | `".xml"` | XML property list | [`NSKeyedArchiver`](https://developer.apple.com/documentation/foundation/nskeyedarchiver) | | ||
/// | None, `".plist"` | Binary property list | [`NSKeyedArchiver`](https://developer.apple.com/documentation/foundation/nskeyedarchiver) | | ||
grynspan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// | ||
/// OpenStep-style property lists are not supported. If a value conforms to | ||
/// _both_ [`Encodable`](https://developer.apple.com/documentation/swift/encodable) | ||
/// _and_ [`NSSecureCoding`](https://developer.apple.com/documentation/foundation/nssecurecoding), | ||
/// the default implementation of this function uses the value's conformance | ||
/// to `Encodable`. | ||
/// | ||
/// - Note: On Apple platforms, if the attachment's preferred name includes | ||
/// some other path extension, that path extension must represent a type | ||
/// that conforms to [`UTType.propertyList`](https://developer.apple.com/documentation/uniformtypeidentifiers/uttype-swift.struct/propertylist). | ||
public func withUnsafeBufferPointer<R>(for attachment: borrowing Attachment<Self>, _ body: (UnsafeRawBufferPointer) throws -> R) throws -> R { | ||
let format = try EncodingFormat(for: attachment) | ||
|
||
var data = try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: true) | ||
switch format { | ||
case .default: | ||
// The default format is just what NSKeyedArchiver produces. | ||
break | ||
case let .propertyListFormat(propertyListFormat): | ||
// BUG: Foundation does not offer a variant of | ||
// NSKeyedArchiver.archivedData(withRootObject:requiringSecureCoding:) | ||
// that is Swift-safe (throws errors instead of exceptions) and lets the | ||
// caller specify the output format. Work around this issue by decoding | ||
// the archive re-encoding it manually. | ||
if propertyListFormat != .binary { | ||
let plist = try PropertyListSerialization.propertyList(from: data, format: nil) | ||
data = try PropertyListSerialization.data(fromPropertyList: plist, format: propertyListFormat, options: 0) | ||
} | ||
case .json: | ||
throw CocoaError(.propertyListWriteInvalid, userInfo: [NSLocalizedDescriptionKey: "An instance of \(type(of: self)) cannot be encoded as JSON. Specify a property list format instead."]) | ||
grynspan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
return try data.withUnsafeBytes(body) | ||
} | ||
} | ||
#endif |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.