Skip to content

Commit 5f820dd

Browse files
authored
Merge pull request #27 from cwakamo/fix-empty-views-and-images
[PlaygroundLogger] Better handle encoding of empty images and views.
2 parents 063a4b0 + 9177474 commit 5f820dd

File tree

4 files changed

+75
-3
lines changed

4 files changed

+75
-3
lines changed

PlaygroundLogger/PlaygroundLogger/OpaqueRepresentations/AppKit/NSImage+OpaqueImageRepresentable.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@
3434

3535
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) throws {
3636
guard let bitmapRep = self.bestBitmapRepresentation else {
37-
throw LoggingError.encodingFailure(reason: "Failed to get a bitmap representation of this NSImage")
37+
if size == .zero {
38+
// If we couldn't get a bitmap representation because the image was empty, encode empty PNG data.
39+
encoder.encode(number: 0)
40+
return
41+
}
42+
else {
43+
throw LoggingError.encodingFailure(reason: "Failed to get a bitmap representation of this NSImage")
44+
}
3845
}
3946

4047
try bitmapRep.encodeImage(into: encoder, withFormat: format)

PlaygroundLogger/PlaygroundLogger/OpaqueRepresentations/AppKit/NSView+OpaqueImageRepresentable.swift

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@
1616
extension NSView: OpaqueImageRepresentable {
1717
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) throws {
1818
guard let bitmapRep = self.bitmapImageRepForCachingDisplay(in: self.bounds) else {
19-
throw LoggingError.encodingFailure(reason: "Unable to create a bitmap representation of this NSView")
19+
if self.bounds == .zero {
20+
// If we couldn't get a bitmap representation because the view is zero-sized, encode empty PNG data.
21+
encoder.encode(number: 0)
22+
return
23+
}
24+
else {
25+
throw LoggingError.encodingFailure(reason: "Unable to create a bitmap representation of this NSView")
26+
}
2027
}
2128

2229
self.cacheDisplay(in: self.bounds, to: bitmapRep)

PlaygroundLogger/PlaygroundLogger/OpaqueRepresentations/UIKit/UIImage+OpaqueImageRepresentable.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,15 @@
1616
extension UIImage: OpaqueImageRepresentable {
1717
func encodeImage(into encoder: LogEncoder, withFormat format: LogEncoder.Format) throws {
1818
guard let pngData = UIImagePNGRepresentation(self) else {
19-
throw LoggingError.encodingFailure(reason: "Failed to convert UIImage to PNG")
19+
if size == .zero {
20+
// We tried encoding an empty image, so it understandably failed.
21+
// In this case, simply encode empty PNG data.
22+
encoder.encode(number: 0)
23+
return
24+
}
25+
else {
26+
throw LoggingError.encodingFailure(reason: "Failed to convert UIImage to PNG")
27+
}
2028
}
2129

2230
encoder.encode(number: UInt64(pngData.count))

PlaygroundLogger/PlaygroundLoggerTests/LogEntryTests.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ import XCTest
1515

1616
import Foundation
1717

18+
#if os(macOS)
19+
import AppKit
20+
#elseif os(iOS) || os(tvOS)
21+
import UIKit
22+
#endif
23+
1824
class LogEntryTests: XCTestCase {
1925
func testNilIUO() throws {
2026
let nilIUO: Int! = nil
@@ -30,4 +36,48 @@ class LogEntryTests: XCTestCase {
3036
XCTAssertEqual(totalChildrenCount, 0)
3137
XCTAssert(children.isEmpty)
3238
}
39+
40+
func testEmptyView() throws {
41+
#if os(macOS)
42+
let emptyView = NSView()
43+
#elseif os(iOS) || os(tvOS)
44+
let emptyView = UIView()
45+
#endif
46+
47+
let logEntry = try LogEntry(describing: emptyView, name: "emptyView", policy: .default)
48+
49+
guard case let .opaque(name, _, _, _, representation) = logEntry else {
50+
XCTFail("Expected an opaque log entry")
51+
return
52+
}
53+
54+
XCTAssertEqual(name, "emptyView")
55+
XCTAssert(representation is ImageOpaqueRepresentation)
56+
57+
// Try to encode the log entry. This operation shouldn't throw; if it does, it will fail the test.
58+
let encoder = LogEncoder()
59+
try logEntry.encode(with: encoder, format: .current)
60+
}
61+
62+
func testEmptyImage() throws {
63+
#if os(macOS)
64+
let emptyImage = NSImage()
65+
#elseif os(iOS) || os(tvOS)
66+
let emptyImage = UIImage()
67+
#endif
68+
69+
let logEntry = try LogEntry(describing: emptyImage, name: "emptyImage", policy: .default)
70+
71+
guard case let .opaque(name, _, _, _, representation) = logEntry else {
72+
XCTFail("Expected an opaque log entry")
73+
return
74+
}
75+
76+
XCTAssertEqual(name, "emptyImage")
77+
XCTAssert(representation is ImageOpaqueRepresentation)
78+
79+
// Try to encode the log entry. This operation shouldn't throw; if it does, it will fail the test.
80+
let encoder = LogEncoder()
81+
try logEntry.encode(with: encoder, format: .current)
82+
}
3383
}

0 commit comments

Comments
 (0)