Skip to content

Commit 049540a

Browse files
committed
Show user-friendly diagnostic for Info.plist decode error
1 parent f23c513 commit 049540a

File tree

3 files changed

+64
-8
lines changed

3 files changed

+64
-8
lines changed

Sources/SwiftDocC/Infrastructure/Workspace/DataProviderBundleDiscovery.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,13 @@ extension DocumentationWorkspaceDataProvider where Self: FileSystemProvider {
5252
/// a ``DocumentationBundle/PropertyListError`` error if the bundle's Info.plist file is invalid.
5353
/// - Returns: The new documentation bundle.
5454
private func createBundle(_ directory: FSNode.Directory, _ bundleChildren: [FSNode], options: BundleDiscoveryOptions) throws -> DocumentationBundle {
55-
let info: DocumentationBundle.Info
56-
57-
var infoPlistData: Data?
55+
let infoPlistData: Data?
5856
if let infoPlistRef = findInfoPlist(bundleChildren) {
5957
infoPlistData = try contentsOfURL(infoPlistRef.url)
58+
} else {
59+
infoPlistData = nil
6060
}
61-
info = try DocumentationBundle.Info(from: infoPlistData, bundleDiscoveryOptions: options)
61+
let info = try DocumentationBundle.Info(from: infoPlistData, bundleDiscoveryOptions: options)
6262

6363
let markupFiles = findMarkupFiles(bundleChildren, recursive: true).map { $0.url }
6464
let miscResources = findNonMarkupFiles(bundleChildren, recursive: true).map { $0.url }

Sources/SwiftDocC/Infrastructure/Workspace/DocumentationBundle+Info.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,16 @@ extension DocumentationBundle {
6464

6565
enum Error: DescribedError {
6666
case wrongType(expected: Any.Type, actual: Any.Type)
67+
case plistDecodingError(_ context: DecodingError.Context)
6768

6869
var errorDescription: String {
6970
switch self {
7071
case .wrongType(let expected, let actual):
7172
return "Expected '\(expected)', but found '\(actual)'."
73+
case .plistDecodingError(let context):
74+
let message = "Unable to decode Info.plist file. Verify that it is correctly formed."
75+
let verboseMessage = ((context.underlyingError as? NSError)?.userInfo["NSDebugDescription"] as? String) ?? context.debugDescription
76+
return [message, verboseMessage].joined(separator: " ")
7277
}
7378
}
7479
}
@@ -86,10 +91,15 @@ extension DocumentationBundle {
8691
propertyListDecoder.userInfo[.bundleDiscoveryOptions] = options
8792
}
8893

89-
self = try propertyListDecoder.decode(
90-
DocumentationBundle.Info.self,
91-
from: infoPlist
92-
)
94+
do {
95+
self = try propertyListDecoder.decode(
96+
DocumentationBundle.Info.self,
97+
from: infoPlist
98+
)
99+
} catch DecodingError.dataCorrupted(let context) {
100+
throw Error.plistDecodingError(context)
101+
}
102+
93103
} else {
94104
try self.init(with: nil, bundleDiscoveryOptions: options)
95105
}

Tests/SwiftDocCTests/Infrastructure/DocumentationBundleInfoTests.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,50 @@ class DocumentationBundleInfoTests: XCTestCase {
284284
try DocumentationBundle.Info(bundleDiscoveryOptions: bundleDiscoveryOptions)
285285
)
286286
}
287+
288+
func testDataCorruptedPlist() throws {
289+
let valueMissingInvaildPlist = """
290+
<plist version="1.0">
291+
<dict>
292+
<key>CDDefaultCodeListingLanguage</key>
293+
<string>swift</string>
294+
<key>CFBundleName</key>
295+
<string>Example</string>
296+
<key>CFBundleDisplayName</key>
297+
<string>Example</string>
298+
<key>CFBundleIdentifier</key>
299+
<string>org.swift.docc.example</string>
300+
<key>CFBundleDevelopmentRegion</key>
301+
<string>en</string>
302+
<key>CFBundleIconName</key>
303+
<string>DocumentationIcon</string>
304+
<key>CFBundleIconFile</key>
305+
<string>DocumentationIcon</string>
306+
<key>CFBundlePackageType</key>
307+
<string>DOCS</string>
308+
<key>CFBundleShortVersionString</key>
309+
<string>0.1.0</string>
310+
<key>CFBundleVersion</key>
311+
<string>0.1.0</string>
312+
<key>CDAppleDefaultAvailability</key>
313+
</dict>
314+
</plist>
315+
"""
316+
317+
let valueMissingInvaildPlistData = Data(valueMissingInvaildPlist.utf8)
318+
XCTAssertThrowsError(
319+
try DocumentationBundle.Info(from: valueMissingInvaildPlistData),
320+
"Info.plist decode didn't throw as expected"
321+
) { error in
322+
XCTAssertTrue(error is DocumentationBundle.Info.Error)
323+
let errorTypeChecking: Bool
324+
if case DocumentationBundle.Info.Error.plistDecodingError(_) = error {
325+
errorTypeChecking = true
326+
} else {
327+
errorTypeChecking = false
328+
}
329+
XCTAssertTrue(errorTypeChecking)
330+
XCTAssertEqual(error.localizedDescription, "Unable to decode Info.plist file. Verify that it is correctly formed. Value missing for key inside <dict> at line 24")
331+
}
332+
}
287333
}

0 commit comments

Comments
 (0)