Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public struct RFC3339Strategy: DateValueCodableStrategy {
let dateFormatter = DateFormatter()
dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZZZZZ"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
return dateFormatter
}()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
//
// RFC3339StrategyTests.swift
// KarrotCodableKit
//
// Created by Elon on 7/13/26.
//

import Foundation
import Testing

import KarrotCodableKit

@Suite("RFC3339Strategy")
struct RFC3339StrategyTests {

private struct Fixture: Codable {
@DateValue<RFC3339Strategy> var date: Date
}
}

// MARK: - Encoding a Date

extension RFC3339StrategyTests {

@Test
func encodesUTCDateWithZOffsetInsteadOfRFC822Offset() {
// given
let date = Date(timeIntervalSince1970: 1715082540) // 2024-05-07T11:49:00 UTC

// when
let result = RFC3339Strategy.encode(date)

// then
// RFC 3339 allows only "Z" or "+00:00" for UTC, never the colon-less "+0000".
#expect(result == "2024-05-07T11:49:00Z")
}

@Test
func serializesUTCDateWithZOffsetViaJSONEncoder() throws {
// given
let date = Date(timeIntervalSince1970: 1715082540) // 2024-05-07T11:49:00 UTC
let fixture = Fixture(date: date)

// when
let data = try JSONEncoder().encode(fixture)
let json = try #require(String(bytes: data, encoding: .utf8))

// then
#expect(json.contains("\"2024-05-07T11:49:00Z\""))
#expect(!json.contains("+0000"))
}
}

// MARK: - Decoding an RFC 3339 string

extension RFC3339StrategyTests {

@Test(arguments: [
"2024-05-07T11:49:00Z",
"2024-05-07T11:49:00+00:00",
"2024-05-07T11:49:00+0000"
])
func decodesEveryUTCOffsetFormToSameInstant(input: String) throws {
// when
let date = try RFC3339Strategy.decode(input)

// then
// "ZZZZZ" still parses every offset form the old "Z" pattern accepted.
#expect(date == Date(timeIntervalSince1970: 1715082540))
}

@Test(arguments: [
"1996-12-19T16:39:57-08:00",
"1996-12-19T16:39:57-0800"
])
func decodesNonUTCOffsetsWithOrWithoutColon(input: String) throws {
// when
let date = try RFC3339Strategy.decode(input)

// then
#expect(date == Date(timeIntervalSince1970: 851042397))
}
Comment thread
ElonPark marked this conversation as resolved.
}

// MARK: - Decoding a malformed string

extension RFC3339StrategyTests {

@Test
func throwsDataCorruptedErrorForMalformedString() {
// when / then
#expect {
try RFC3339Strategy.decode("not-a-valid-date")
} throws: { error in
guard case DecodingError.dataCorrupted = error else { return false }
return true
}
Comment thread
ElonPark marked this conversation as resolved.
}
}
Loading