@@ -10,44 +10,90 @@ import Testing
1010
1111import KarrotCodableKit
1212
13+ @Suite ( " RFC3339Strategy " )
1314struct RFC3339StrategyTests {
1415
16+ private struct Fixture : Codable {
17+ @DateValue < RFC3339Strategy > var date : Date
18+ }
19+ }
20+
21+ // MARK: - Encoding a Date
22+
23+ extension RFC3339StrategyTests {
24+
1525 @Test
16- func encodesUTCDateWithStandardCompliantOffset ( ) {
26+ func encodesUTCDateWithZOffsetInsteadOfRFC822Offset ( ) {
1727 // given
1828 let date = Date ( timeIntervalSince1970: 1715082540 ) // 2024-05-07T11:49:00 UTC
1929
2030 // when
2131 let result = RFC3339Strategy . encode ( date)
2232
2333 // then
24- // RFC 3339 requires the UTC offset to be "Z" ( or "+00:00"), not the colon-less "+0000".
34+ // RFC 3339 allows only "Z" or "+00:00" for UTC, never the colon-less "+0000".
2535 #expect( result == " 2024-05-07T11:49:00Z " )
2636 }
2737
38+ @Test
39+ func serializesUTCDateWithZOffsetViaJSONEncoder( ) throws {
40+ // given
41+ let date = Date ( timeIntervalSince1970: 1715082540 ) // 2024-05-07T11:49:00 UTC
42+ let fixture = Fixture ( date: date)
43+
44+ // when
45+ let data = try JSONEncoder ( ) . encode ( fixture)
46+ let json = try #require( String ( bytes: data, encoding: . utf8) )
47+
48+ // then
49+ #expect( json. contains ( " \" 2024-05-07T11:49:00Z \" " ) )
50+ #expect( !json. contains ( " +0000 " ) )
51+ }
52+ }
53+
54+ // MARK: - Decoding an RFC 3339 string
55+
56+ extension RFC3339StrategyTests {
57+
2858 @Test ( arguments: [
2959 " 2024-05-07T11:49:00Z " ,
3060 " 2024-05-07T11:49:00+00:00 " ,
3161 " 2024-05-07T11:49:00+0000 "
3262 ] )
33- func decodesAllUTCOffsetForms ( input: String ) throws {
63+ func decodesEveryUTCOffsetFormToSameInstant ( input: String ) throws {
3464 // when
3565 let date = try RFC3339Strategy . decode ( input)
3666
3767 // then
38- // "ZZZZZ" still parses every offset form the old "Z" pattern accepted, including "+0000" .
68+ // "ZZZZZ" still parses every offset form the old "Z" pattern accepted.
3969 #expect( date == Date ( timeIntervalSince1970: 1715082540 ) )
4070 }
4171
4272 @Test ( arguments: [
4373 " 1996-12-19T16:39:57-08:00 " ,
4474 " 1996-12-19T16:39:57-0800 "
4575 ] )
46- func decodesNonUTCOffsetsRegardlessOfColon ( input: String ) throws {
76+ func decodesNonUTCOffsetsWithOrWithoutColon ( input: String ) throws {
4777 // when
4878 let date = try RFC3339Strategy . decode ( input)
4979
5080 // then
5181 #expect( date == Date ( timeIntervalSince1970: 851042397 ) )
5282 }
5383}
84+
85+ // MARK: - Decoding a malformed string
86+
87+ extension RFC3339StrategyTests {
88+
89+ @Test
90+ func throwsDataCorruptedErrorForMalformedString( ) {
91+ // when / then
92+ #expect {
93+ try RFC3339Strategy . decode ( " not-a-valid-date " )
94+ } throws: { error in
95+ guard case DecodingError . dataCorrupted = error else { return false }
96+ return true
97+ }
98+ }
99+ }
0 commit comments