Skip to content

Commit 43fb3fb

Browse files
authored
Add a cross-import overlay with UIKit to allow attaching UIImages. (#1216)
This PR adds on to the Core Graphics cross-import overlay added in #827 to allow attaching instances of `UIImage` to a test. > [!NOTE] > Image attachments remain an experimental feature. ### Checklist: - [x] Code and documentation should follow the style of the [Style Guide](https://github.com/apple/swift-testing/blob/main/Documentation/StyleGuide.md). - [x] If public symbols are renamed or modified, DocC references should be updated.
1 parent e245c54 commit 43fb3fb

File tree

5 files changed

+109
-0
lines changed

5 files changed

+109
-0
lines changed

Package.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ let package = Package(
9191
"_Testing_AppKit",
9292
"_Testing_CoreGraphics",
9393
"_Testing_CoreImage",
94+
"_Testing_UIKit",
9495
]
9596
)
9697
]
@@ -140,6 +141,7 @@ let package = Package(
140141
"_Testing_CoreGraphics",
141142
"_Testing_CoreImage",
142143
"_Testing_Foundation",
144+
"_Testing_UIKit",
143145
"MemorySafeTestingTests",
144146
],
145147
swiftSettings: .packageSettings
@@ -241,6 +243,16 @@ let package = Package(
241243
// it can only enable Library Evolution itself on those platforms.
242244
swiftSettings: .packageSettings + .enableLibraryEvolution(.whenApple())
243245
),
246+
.target(
247+
name: "_Testing_UIKit",
248+
dependencies: [
249+
"Testing",
250+
"_Testing_CoreGraphics",
251+
"_Testing_CoreImage",
252+
],
253+
path: "Sources/Overlays/_Testing_UIKit",
254+
swiftSettings: .packageSettings + .enableLibraryEvolution()
255+
),
244256

245257
// Utility targets: These are utilities intended for use when developing
246258
// this package, not for distribution.
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
// This source file is part of the Swift.org open source project
3+
//
4+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
5+
// Licensed under Apache License v2.0 with Runtime Library Exception
6+
//
7+
// See https://swift.org/LICENSE.txt for license information
8+
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
//
10+
11+
#if SWT_TARGET_OS_APPLE && canImport(UIKit)
12+
public import UIKit
13+
@_spi(Experimental) public import _Testing_CoreGraphics
14+
@_spi(Experimental) private import _Testing_CoreImage
15+
16+
private import ImageIO
17+
#if canImport(UIKitCore_Private)
18+
private import UIKitCore_Private
19+
#endif
20+
21+
@_spi(Experimental)
22+
extension UIImage: AttachableAsCGImage {
23+
public var attachableCGImage: CGImage {
24+
get throws {
25+
#if canImport(UIKitCore_Private)
26+
// _UIImageGetCGImageRepresentation() is an internal UIKit function that
27+
// flattens any (most) UIImage instances to a CGImage. BUG: rdar://155449485
28+
if let cgImage = _UIImageGetCGImageRepresentation(self)?.takeUnretainedValue() {
29+
return cgImage
30+
}
31+
#else
32+
// NOTE: This API is marked to-be-deprecated so we'll need to eventually
33+
// switch to UIGraphicsImageRenderer, but that type is not available on
34+
// watchOS. BUG: rdar://155452406
35+
UIGraphicsBeginImageContextWithOptions(size, true, scale)
36+
defer {
37+
UIGraphicsEndImageContext()
38+
}
39+
draw(at: .zero)
40+
if let cgImage = UIGraphicsGetImageFromCurrentImageContext()?.cgImage {
41+
return cgImage
42+
}
43+
#endif
44+
throw ImageAttachmentError.couldNotCreateCGImage
45+
}
46+
}
47+
48+
public var _attachmentOrientation: UInt32 {
49+
let result: CGImagePropertyOrientation = switch imageOrientation {
50+
case .up: .up
51+
case .down: .down
52+
case .left: .left
53+
case .right: .right
54+
case .upMirrored: .upMirrored
55+
case .downMirrored: .downMirrored
56+
case .leftMirrored: .leftMirrored
57+
case .rightMirrored: .rightMirrored
58+
@unknown default: .up
59+
}
60+
return result.rawValue
61+
}
62+
63+
public var _attachmentScaleFactor: CGFloat {
64+
scale
65+
}
66+
}
67+
#endif
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//
2+
// This source file is part of the Swift.org open source project
3+
//
4+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
5+
// Licensed under Apache License v2.0 with Runtime Library Exception
6+
//
7+
// See https://swift.org/LICENSE.txt for license information
8+
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
9+
//
10+
11+
@_exported @_spi(Experimental) @_spi(ForToolsIntegrationOnly) public import Testing
12+
@_exported @_spi(Experimental) @_spi(ForToolsIntegrationOnly) public import _Testing_CoreGraphics

Tests/TestingTests/AttachmentTests.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ import CoreGraphics
2626
import CoreImage
2727
@_spi(Experimental) import _Testing_CoreImage
2828
#endif
29+
#if canImport(UIKit)
30+
import UIKit
31+
@_spi(Experimental) import _Testing_UIKit
32+
#endif
2933
#if canImport(UniformTypeIdentifiers)
3034
import UniformTypeIdentifiers
3135
#endif
@@ -678,6 +682,18 @@ extension AttachmentTests {
678682
}
679683
}
680684
#endif
685+
686+
#if canImport(UIKit)
687+
@available(_uttypesAPI, *)
688+
@Test func attachUIImage() throws {
689+
let image = UIImage(cgImage: try Self.cgImage.get())
690+
let attachment = Attachment(image, named: "diamond.jpg")
691+
#expect(attachment.attachableValue === image)
692+
try attachment.attachableValue.withUnsafeBytes(for: attachment) { buffer in
693+
#expect(buffer.count > 32)
694+
}
695+
}
696+
#endif
681697
#endif
682698
}
683699
}

Tests/_MemorySafeTestingTests/MemorySafeTestDecls.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ struct ExampleSuite {
2424
@Test func example() {}
2525
}
2626

27+
#if !SWT_NO_EXIT_TESTS
2728
func exampleExitTest() async {
2829
await #expect(processExitsWith: .success) {}
2930
}
31+
#endif
3032

3133
#endif

0 commit comments

Comments
 (0)