@@ -19,6 +19,8 @@ import XCTest
1919final class ProtoDateTests : XCTestCase {
2020 let decoder = JSONDecoder ( )
2121
22+ // MARK: - Date Components Tests
23+
2224 // A full date, with non-zero year, month, and day values.
2325 func testProtoDate_fullDate_dateComponents( ) {
2426 let year = 2024
@@ -64,7 +66,7 @@ final class ProtoDateTests: XCTestCase {
6466 // A year and month value, with a zero day, such as a credit card expiration date
6567 func testProtoDate_yearMonth_dateComponents( ) {
6668 let year = 2024
67- let month = 08
69+ let month = 8
6870 let protoDate = ProtoDate ( year: year, month: month, day: nil )
6971
7072 let dateComponents = protoDate. dateComponents
@@ -75,18 +77,78 @@ final class ProtoDateTests: XCTestCase {
7577 XCTAssertEqual ( protoDate. day, nil )
7678 }
7779
78- func testProtoDate_asDate( ) throws {
80+ // MARK: - Date Conversion Tests
81+
82+ func testProtoDate_fullDate_asDate( ) throws {
7983 let protoDate = ProtoDate ( year: 2024 , month: 12 , day: 31 )
8084 let dateFormatter = DateFormatter ( )
8185 dateFormatter. dateFormat = " yyyy-MM-dd "
8286 let expectedDate = try XCTUnwrap ( dateFormatter. date ( from: " 2024-12-31 " ) )
8387
84- let date = try XCTUnwrap ( protoDate. dateComponents . date )
88+ let date = try XCTUnwrap ( protoDate. asDate ( ) )
8589
8690 XCTAssertEqual ( date, expectedDate)
8791 }
8892
89- func testDecodeProtoDate( ) throws {
93+ func testProtoDate_monthDay_asDate_throws( ) {
94+ let protoDate = ProtoDate ( year: nil , month: 7 , day: 1 )
95+
96+ do {
97+ _ = try protoDate. asDate ( )
98+ } catch let error as ProtoDate . DateConversionError {
99+ XCTAssertTrue ( error. localizedDescription. contains ( " Missing a year " ) )
100+ return
101+ } catch {
102+ XCTFail ( " Expected \( ProtoDate . DateConversionError. self) , got \( error) . " )
103+ }
104+ XCTFail ( " Expected an error but none thrown. " )
105+ }
106+
107+ func testProtoDate_yearOnly_asDate_throws( ) {
108+ let protoDate = ProtoDate ( year: 2024 , month: nil , day: nil )
109+
110+ do {
111+ _ = try protoDate. asDate ( )
112+ } catch let error as ProtoDate . DateConversionError {
113+ XCTAssertTrue ( error. localizedDescription. contains ( " Missing a month " ) )
114+ return
115+ } catch {
116+ XCTFail ( " Expected \( ProtoDate . DateConversionError. self) , got \( error) . " )
117+ }
118+ XCTFail ( " Expected an error but none thrown. " )
119+ }
120+
121+ func testProtoDate_yearMonth_asDate_throws( ) {
122+ let protoDate = ProtoDate ( year: 2024 , month: 8 , day: nil )
123+
124+ do {
125+ _ = try protoDate. asDate ( )
126+ } catch let error as ProtoDate . DateConversionError {
127+ XCTAssertTrue ( error. localizedDescription. contains ( " Missing a day " ) )
128+ return
129+ } catch {
130+ XCTFail ( " Expected \( ProtoDate . DateConversionError. self) , got \( error) . " )
131+ }
132+ XCTFail ( " Expected an error but none thrown. " )
133+ }
134+
135+ func testProtoDate_empty_asDate_throws( ) {
136+ let protoDate = ProtoDate ( year: nil , month: nil , day: nil )
137+
138+ do {
139+ _ = try protoDate. asDate ( )
140+ } catch let error as ProtoDate . DateConversionError {
141+ XCTAssertTrue ( error. localizedDescription. contains ( " Missing a year " ) )
142+ return
143+ } catch {
144+ XCTFail ( " Expected \( ProtoDate . DateConversionError. self) , got \( error) . " )
145+ }
146+ XCTFail ( " Expected an error but none thrown. " )
147+ }
148+
149+ // MARK: - Decoding Tests
150+
151+ func testDecodeProtoDate_fullDate( ) throws {
90152 let json = """
91153 {
92154 " year " : 2024,
@@ -103,7 +165,123 @@ final class ProtoDateTests: XCTestCase {
103165 XCTAssertEqual ( protoDate. day, 31 )
104166 }
105167
168+ func testDecodeProtoDate_monthDay( ) throws {
169+ let json = """
170+ {
171+ " year " : 0,
172+ " month " : 12,
173+ " day " : 31
174+ }
175+ """
176+ let jsonData = try XCTUnwrap ( json. data ( using: . utf8) )
177+
178+ let protoDate = try decoder. decode ( ProtoDate . self, from: jsonData)
179+
180+ XCTAssertNil ( protoDate. year)
181+ XCTAssertEqual ( protoDate. month, 12 )
182+ XCTAssertEqual ( protoDate. day, 31 )
183+ }
184+
185+ func testDecodeProtoDate_monthDay_defaultsOmitted( ) throws {
186+ let json = """
187+ {
188+ " month " : 12,
189+ " day " : 31
190+ }
191+ """
192+ let jsonData = try XCTUnwrap ( json. data ( using: . utf8) )
193+
194+ let protoDate = try decoder. decode ( ProtoDate . self, from: jsonData)
195+
196+ XCTAssertNil ( protoDate. year)
197+ XCTAssertEqual ( protoDate. month, 12 )
198+ XCTAssertEqual ( protoDate. day, 31 )
199+ }
200+
201+ func testDecodeProtoDate_yearOnly( ) throws {
202+ let json = """
203+ {
204+ " year " : 2024,
205+ " month " : 0,
206+ " day " : 0
207+ }
208+ """
209+ let jsonData = try XCTUnwrap ( json. data ( using: . utf8) )
210+
211+ let protoDate = try decoder. decode ( ProtoDate . self, from: jsonData)
212+
213+ XCTAssertEqual ( protoDate. year, 2024 )
214+ XCTAssertNil ( protoDate. month)
215+ XCTAssertNil ( protoDate. day)
216+ }
217+
218+ func testDecodeProtoDate_yearOnly_defaultsOmitted( ) throws {
219+ let json = """
220+ {
221+ " year " : 2024
222+ }
223+ """
224+ let jsonData = try XCTUnwrap ( json. data ( using: . utf8) )
225+
226+ let protoDate = try decoder. decode ( ProtoDate . self, from: jsonData)
227+
228+ XCTAssertEqual ( protoDate. year, 2024 )
229+ XCTAssertNil ( protoDate. month)
230+ XCTAssertNil ( protoDate. day)
231+ }
232+
233+ func testDecodeProtoDate_yearMonth( ) throws {
234+ let json = """
235+ {
236+ " year " : 2024,
237+ " month " : 12,
238+ " day " : 0
239+ }
240+ """
241+ let jsonData = try XCTUnwrap ( json. data ( using: . utf8) )
242+
243+ let protoDate = try decoder. decode ( ProtoDate . self, from: jsonData)
244+
245+ XCTAssertEqual ( protoDate. year, 2024 )
246+ XCTAssertEqual ( protoDate. month, 12 )
247+ XCTAssertNil ( protoDate. day)
248+ }
249+
250+ func testDecodeProtoDate_yearMonth_defaultsOmitted( ) throws {
251+ let json = """
252+ {
253+ " year " : 2024,
254+ " month " : 12
255+ }
256+ """
257+ let jsonData = try XCTUnwrap ( json. data ( using: . utf8) )
258+
259+ let protoDate = try decoder. decode ( ProtoDate . self, from: jsonData)
260+
261+ XCTAssertEqual ( protoDate. year, 2024 )
262+ XCTAssertEqual ( protoDate. month, 12 )
263+ XCTAssertNil ( protoDate. day)
264+ }
265+
106266 func testDecodeProtoDate_emptyDate_throws( ) throws {
267+ let json = """
268+ {
269+ " year " : 0,
270+ " month " : 0,
271+ " day " : 0
272+ }
273+ """
274+ let jsonData = try XCTUnwrap ( json. data ( using: . utf8) )
275+
276+ do {
277+ _ = try decoder. decode ( ProtoDate . self, from: jsonData)
278+ } catch DecodingError . dataCorrupted {
279+ return
280+ }
281+ XCTFail ( " Expected a DecodingError. " )
282+ }
283+
284+ func testDecodeProtoDate_emptyDate_defaultsOmitted_throws( ) throws {
107285 let json = " {} "
108286 let jsonData = try XCTUnwrap ( json. data ( using: . utf8) )
109287
0 commit comments