Skip to content

Commit 686f56b

Browse files
committed
Add more ProtoData checks and tests
1 parent 431e794 commit 686f56b

File tree

2 files changed

+94
-8
lines changed

2 files changed

+94
-8
lines changed

FirebaseVertexAI/Sources/Types/Internal/ProtoDate.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import Foundation
2323
/// - A year on its own, with zero month and day values
2424
/// - A year and month value, with a zero day, such as a credit card expiration date
2525
///
26-
/// This represents a `google.type.Date`.
26+
/// This represents a
27+
/// [`google.type.Date`](https://cloud.google.com/vertex-ai/docs/reference/rest/Shared.Types/Date).
2728
struct ProtoDate {
2829
/// Year of the date.
2930
///
@@ -60,8 +61,8 @@ struct ProtoDate {
6061
guard day != nil else {
6162
throw DateConversionError(message: "Missing a day: \(self)")
6263
}
63-
guard let date = dateComponents.date else {
64-
throw DateConversionError(message: "Date conversion failed: \(self)")
64+
guard dateComponents.isValidDate, let date = dateComponents.date else {
65+
throw DateConversionError(message: "Invalid date: \(self)")
6566
}
6667
return date
6768
}
@@ -93,7 +94,7 @@ extension ProtoDate: Decodable {
9394
init(from decoder: any Decoder) throws {
9495
let container = try decoder.container(keyedBy: CodingKeys.self)
9596
if let year = try container.decodeIfPresent(Int.self, forKey: .year), year != 0 {
96-
guard year > 0 else {
97+
guard year >= 1 && year <= 9999 else {
9798
throw DecodingError.dataCorrupted(
9899
.init(codingPath: [CodingKeys.year], debugDescription: "Invalid year: \(year)")
99100
)
@@ -104,7 +105,7 @@ extension ProtoDate: Decodable {
104105
}
105106

106107
if let month = try container.decodeIfPresent(Int.self, forKey: .month), month != 0 {
107-
guard month > 0 else {
108+
guard month >= 1 && month <= 12 else {
108109
throw DecodingError.dataCorrupted(
109110
.init(codingPath: [CodingKeys.month], debugDescription: "Invalid month: \(month)")
110111
)
@@ -115,7 +116,7 @@ extension ProtoDate: Decodable {
115116
}
116117

117118
if let day = try container.decodeIfPresent(Int.self, forKey: .day), day != 0 {
118-
guard day > 0 else {
119+
guard day >= 1 && day <= 31 else {
119120
throw DecodingError.dataCorrupted(
120121
.init(codingPath: [CodingKeys.day], debugDescription: "Invalid day: \(day)")
121122
)

FirebaseVertexAI/Tests/Unit/Types/ProtoDateTests.swift

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,21 @@ final class ProtoDateTests: XCTestCase {
132132
XCTFail("Expected an error but none thrown.")
133133
}
134134

135+
func testProtoDate_invalidDate_asDate_throws() {
136+
// Reminder: Only 30 days in November
137+
let protoDate = ProtoDate(year: 2024, month: 11, day: 31)
138+
139+
do {
140+
_ = try protoDate.asDate()
141+
} catch let error as ProtoDate.DateConversionError {
142+
XCTAssertTrue(error.localizedDescription.contains("Invalid date"))
143+
return
144+
} catch {
145+
XCTFail("Expected \(ProtoDate.DateConversionError.self), got \(error).")
146+
}
147+
XCTFail("Expected an error but none thrown.")
148+
}
149+
135150
func testProtoDate_empty_asDate_throws() {
136151
let protoDate = ProtoDate(year: nil, month: nil, day: nil)
137152

@@ -275,7 +290,12 @@ final class ProtoDateTests: XCTestCase {
275290

276291
do {
277292
_ = try decoder.decode(ProtoDate.self, from: jsonData)
278-
} catch DecodingError.dataCorrupted {
293+
} catch let DecodingError.dataCorrupted(context) {
294+
XCTAssertEqual(
295+
context.codingPath as? [ProtoDate.CodingKeys],
296+
[ProtoDate.CodingKeys.year, ProtoDate.CodingKeys.month, ProtoDate.CodingKeys.day]
297+
)
298+
XCTAssertTrue(context.debugDescription.contains("Invalid date"))
279299
return
280300
}
281301
XCTFail("Expected a DecodingError.")
@@ -287,7 +307,72 @@ final class ProtoDateTests: XCTestCase {
287307

288308
do {
289309
_ = try decoder.decode(ProtoDate.self, from: jsonData)
290-
} catch DecodingError.dataCorrupted {
310+
} catch let DecodingError.dataCorrupted(context) {
311+
XCTAssertEqual(
312+
context.codingPath as? [ProtoDate.CodingKeys],
313+
[ProtoDate.CodingKeys.year, ProtoDate.CodingKeys.month, ProtoDate.CodingKeys.day]
314+
)
315+
XCTAssertTrue(context.debugDescription.contains("Invalid date"))
316+
return
317+
}
318+
XCTFail("Expected a DecodingError.")
319+
}
320+
321+
func testDecodeProtoDate_invalidYear_throws() throws {
322+
let json = """
323+
{
324+
"year" : -2024,
325+
"month" : 12,
326+
"day" : 31
327+
}
328+
"""
329+
let jsonData = try XCTUnwrap(json.data(using: .utf8))
330+
331+
do {
332+
_ = try decoder.decode(ProtoDate.self, from: jsonData)
333+
} catch let DecodingError.dataCorrupted(context) {
334+
XCTAssertEqual(context.codingPath as? [ProtoDate.CodingKeys], [ProtoDate.CodingKeys.year])
335+
XCTAssertTrue(context.debugDescription.contains("Invalid year"))
336+
return
337+
}
338+
XCTFail("Expected a DecodingError.")
339+
}
340+
341+
func testDecodeProtoDate_invalidMonth_throws() throws {
342+
let json = """
343+
{
344+
"year" : 2024,
345+
"month" : 13,
346+
"day" : 31
347+
}
348+
"""
349+
let jsonData = try XCTUnwrap(json.data(using: .utf8))
350+
351+
do {
352+
_ = try decoder.decode(ProtoDate.self, from: jsonData)
353+
} catch let DecodingError.dataCorrupted(context) {
354+
XCTAssertEqual(context.codingPath as? [ProtoDate.CodingKeys], [ProtoDate.CodingKeys.month])
355+
XCTAssertTrue(context.debugDescription.contains("Invalid month"))
356+
return
357+
}
358+
XCTFail("Expected a DecodingError.")
359+
}
360+
361+
func testDecodeProtoDate_invalidDay_throws() throws {
362+
let json = """
363+
{
364+
"year" : 2024,
365+
"month" : 12,
366+
"day" : 32
367+
}
368+
"""
369+
let jsonData = try XCTUnwrap(json.data(using: .utf8))
370+
371+
do {
372+
_ = try decoder.decode(ProtoDate.self, from: jsonData)
373+
} catch let DecodingError.dataCorrupted(context) {
374+
XCTAssertEqual(context.codingPath as? [ProtoDate.CodingKeys], [ProtoDate.CodingKeys.day])
375+
XCTAssertTrue(context.debugDescription.contains("Invalid day"))
291376
return
292377
}
293378
XCTFail("Expected a DecodingError.")

0 commit comments

Comments
 (0)