Skip to content

Commit df8d2f7

Browse files
authored
[Vertex AI] Add error handling for decoding ImagenInlineImage from b64 (#14458)
1 parent 1599cd3 commit df8d2f7

File tree

3 files changed

+50
-12
lines changed

3 files changed

+50
-12
lines changed

FirebaseVertexAI/Sources/Types/Public/Imagen/ImagenInlineImage.swift

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,8 @@ public struct ImagenInlineImage {
2626
/// The image data in PNG or JPEG format.
2727
public let data: Data
2828

29-
init(mimeType: String, bytesBase64Encoded: String) {
29+
init(mimeType: String, data: Data) {
3030
self.mimeType = mimeType
31-
guard let data = Data(base64Encoded: bytesBase64Encoded) else {
32-
// TODO(#14221): Add error handling for invalid base64 bytes.
33-
fatalError("Creating a `Data` from `bytesBase64Encoded` failed.")
34-
}
3531
self.data = data
3632
}
3733
}
@@ -65,6 +61,13 @@ extension ImagenInlineImage: Decodable {
6561
let container = try decoder.container(keyedBy: CodingKeys.self)
6662
let mimeType = try container.decode(String.self, forKey: .mimeType)
6763
let bytesBase64Encoded = try container.decode(String.self, forKey: .bytesBase64Encoded)
68-
self.init(mimeType: mimeType, bytesBase64Encoded: bytesBase64Encoded)
64+
guard let data = Data(base64Encoded: bytesBase64Encoded) else {
65+
throw DecodingError.dataCorruptedError(
66+
forKey: .bytesBase64Encoded,
67+
in: container,
68+
debugDescription: "Failed to decode data from base64-encoded string: \(bytesBase64Encoded)"
69+
)
70+
}
71+
self.init(mimeType: mimeType, data: data)
6972
}
7073
}

FirebaseVertexAI/Tests/Unit/Types/Imagen/ImagenGenerationResponseTests.swift

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ final class ImagenGenerationResponseTests: XCTestCase {
2323
func testDecodeResponse_oneBase64Image_noneFiltered() throws {
2424
let mimeType = "image/png"
2525
let bytesBase64Encoded = "dGVzdC1iYXNlNjQtZGF0YQ=="
26-
let image = ImagenInlineImage(mimeType: mimeType, bytesBase64Encoded: bytesBase64Encoded)
26+
let image = try ImagenInlineImage(
27+
mimeType: mimeType, data: XCTUnwrap(Data(base64Encoded: bytesBase64Encoded))
28+
)
2729
let json = """
2830
{
2931
"predictions": [
@@ -50,9 +52,15 @@ final class ImagenGenerationResponseTests: XCTestCase {
5052
let bytesBase64Encoded1 = "dGVzdC1iYXNlNjQtYnl0ZXMtMQ=="
5153
let bytesBase64Encoded2 = "dGVzdC1iYXNlNjQtYnl0ZXMtMg=="
5254
let bytesBase64Encoded3 = "dGVzdC1iYXNlNjQtYnl0ZXMtMw=="
53-
let image1 = ImagenInlineImage(mimeType: mimeType, bytesBase64Encoded: bytesBase64Encoded1)
54-
let image2 = ImagenInlineImage(mimeType: mimeType, bytesBase64Encoded: bytesBase64Encoded2)
55-
let image3 = ImagenInlineImage(mimeType: mimeType, bytesBase64Encoded: bytesBase64Encoded3)
55+
let image1 = try ImagenInlineImage(
56+
mimeType: mimeType, data: XCTUnwrap(Data(base64Encoded: bytesBase64Encoded1))
57+
)
58+
let image2 = try ImagenInlineImage(
59+
mimeType: mimeType, data: XCTUnwrap(Data(base64Encoded: bytesBase64Encoded2))
60+
)
61+
let image3 = try ImagenInlineImage(
62+
mimeType: mimeType, data: XCTUnwrap(Data(base64Encoded: bytesBase64Encoded3))
63+
)
5664
let json = """
5765
{
5866
"predictions": [
@@ -86,8 +94,12 @@ final class ImagenGenerationResponseTests: XCTestCase {
8694
let mimeType = "image/png"
8795
let bytesBase64Encoded1 = "dGVzdC1iYXNlNjQtYnl0ZXMtMQ=="
8896
let bytesBase64Encoded2 = "dGVzdC1iYXNlNjQtYnl0ZXMtMg=="
89-
let image1 = ImagenInlineImage(mimeType: mimeType, bytesBase64Encoded: bytesBase64Encoded1)
90-
let image2 = ImagenInlineImage(mimeType: mimeType, bytesBase64Encoded: bytesBase64Encoded2)
97+
let image1 = try ImagenInlineImage(
98+
mimeType: mimeType, data: XCTUnwrap(Data(base64Encoded: bytesBase64Encoded1))
99+
)
100+
let image2 = try ImagenInlineImage(
101+
mimeType: mimeType, data: XCTUnwrap(Data(base64Encoded: bytesBase64Encoded2))
102+
)
91103
let raiFilteredReason = """
92104
Your current safety filter threshold filtered out 2 generated images. You will not be charged \
93105
for blocked images. Try rephrasing the prompt. If you think this was an error, send feedback.

FirebaseVertexAI/Tests/Unit/Types/Imagen/ImagenInlineImageTests.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,27 @@ final class ImagenInlineImageTests: XCTestCase {
7777
XCTFail("Expected a DecodingError.keyNotFound error; got \(error).")
7878
}
7979
}
80+
81+
func testDecodeImage_invalidBase64Data_throws() throws {
82+
let bytesBase64Encoded = "not-a-base64-string"
83+
let json = """
84+
{
85+
"bytesBase64Encoded": "\(bytesBase64Encoded)",
86+
"mimeType": "image/png"
87+
}
88+
"""
89+
let jsonData = try XCTUnwrap(json.data(using: .utf8))
90+
91+
do {
92+
_ = try decoder.decode(ImagenInlineImage.self, from: jsonData)
93+
XCTFail("Expected an error; none thrown.")
94+
} catch let DecodingError.dataCorrupted(context) {
95+
XCTAssertEqual(
96+
context.debugDescription,
97+
"Failed to decode data from base64-encoded string: \(bytesBase64Encoded)"
98+
)
99+
} catch {
100+
XCTFail("Expected a DecodingError.dataCorrupted error; got \(error).")
101+
}
102+
}
80103
}

0 commit comments

Comments
 (0)