Skip to content

Commit

Permalink
Implement TypedDate+Codable tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryu0118 committed Nov 11, 2023
1 parent a3d7476 commit f78d191
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 116 deletions.
118 changes: 118 additions & 0 deletions Sources/TypedDate/TypedDate+Codable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import Foundation

extension TypedDate: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let date = try container.decode(Date.self, forKey: .date)
let calendar = Calendar.current

switch Components.self {
case is (Year).Type:
let dc = calendar.dateComponents([.year], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = Year(year) as! Components

case is (Year, Month).Type:
let dc = calendar.dateComponents([.year, .month], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month)) as! Components

case is (Year, Month, Day).Type:
let dc = calendar.dateComponents([.year, .month, .day], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month), Day(day)) as! Components

case is (Year, Month, Day, Hour).Type:
let dc = calendar.dateComponents([.year, .month, .day, .hour], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day,
let hour = dc.hour
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month), Day(day), Hour(hour)) as! Components

case is (Year, Month, Day, Hour, Minute).Type:
let dc = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day,
let hour = dc.hour,
let minute = dc.minute
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month), Day(day), Hour(hour), Minute(minute)) as! Components

case is (Year, Month, Day, Hour, Minute, Second).Type:
let dc = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day,
let hour = dc.hour,
let minute = dc.minute,
let second = dc.second
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month), Day(day), Hour(hour), Minute(minute), Second(second)) as! Components

case is (Year, Month, Day, Hour, Minute, Second, Nanosecond).Type:
let dc = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day,
let hour = dc.hour,
let minute = dc.minute,
let second = dc.second
else {
throw TypedDateDecodingError.invalidDate
}
let nanosecond = dc.nanosecond ?? 0
self.date = date
self.components = (Year(year), Month(month), Day(day), Hour(hour), Minute(minute), Second(second), Nanosecond(nanosecond)) as! Components

default: throw TypedDateDecodingError.invalidComponents
}
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(date, forKey: .date)
}

public enum CodingKeys: CodingKey {
case date
}
}

public enum TypedDateDecodingError: Error {
case invalidDate
case invalidComponents
}
File renamed without changes.
116 changes: 0 additions & 116 deletions Sources/TypedDate/TypedDate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,119 +5,3 @@ public struct TypedDate<Components: Sendable>: Sendable {

let components: Components
}

extension TypedDate: Codable {
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let date = try container.decode(Date.self, forKey: .date)
let calendar = Calendar.current

switch Components.self {
case is (Year).Type:
let dc = calendar.dateComponents([.year], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = Year(year) as! Components

case is (Year, Month).Type:
let dc = calendar.dateComponents([.year, .month], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month)) as! Components

case is (Year, Month, Day).Type:
let dc = calendar.dateComponents([.year, .month, .day], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month), Day(day)) as! Components

case is (Year, Month, Day, Hour).Type:
let dc = calendar.dateComponents([.year, .month, .day, .hour], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day,
let hour = dc.hour
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month), Day(day), Hour(hour)) as! Components

case is (Year, Month, Day, Hour, Minute).Type:
let dc = calendar.dateComponents([.year, .month, .day, .hour, .minute], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day,
let hour = dc.hour,
let minute = dc.minute
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month), Day(day), Hour(hour), Minute(minute)) as! Components

case is (Year, Month, Day, Hour, Minute, Second).Type:
let dc = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day,
let hour = dc.hour,
let minute = dc.minute,
let second = dc.second
else {
throw TypedDateDecodingError.invalidDate
}
self.date = date
self.components = (Year(year), Month(month), Day(day), Hour(hour), Minute(minute), Second(second)) as! Components

case is (Year, Month, Day, Hour, Minute, Second, Nanosecond).Type:
let dc = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second, .nanosecond], from: date)
guard let date = calendar.date(from: dc),
let year = dc.year,
let month = dc.month,
let day = dc.day,
let hour = dc.hour,
let minute = dc.minute,
let second = dc.second
else {
throw TypedDateDecodingError.invalidDate
}
let nanosecond = dc.nanosecond ?? 0
self.date = date
self.components = (Year(year), Month(month), Day(day), Hour(hour), Minute(minute), Second(second), Nanosecond(nanosecond)) as! Components

default: throw TypedDateDecodingError.invalidDate
}
}

public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(date, forKey: .date)
}

public enum CodingKeys: CodingKey {
case date
}
}

public enum TypedDateDecodingError: Error {
case invalidDate
}
37 changes: 37 additions & 0 deletions Tests/TypedDateTests/TypedDateCodableTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation
import Testing
@testable import TypedDate

@Suite
struct TypedDateCodableTests {
let calendar: Calendar
let testSupport: TypedDateTestSupport

init() {
calendar = Calendar(identifier: .gregorian)
testSupport = TypedDateTestSupport.init(calendar: calendar)
}

@Test
func testCodable() throws {
let typedDate = testSupport.generateTypedNanosecondDate()
let jsonEncoder = JSONEncoder()
let data = try jsonEncoder.encode(typedDate)
let decoded1 = try JSONDecoder().decode(TypedDate<(Year, Month, Day, Hour, Minute, Second, Nanosecond)>.self, from: data)
testSupport.assertTypedDate(for: decoded1)
let decoded2 = try JSONDecoder().decode(TypedDate<(Year, Month, Day, Hour, Minute, Second)>.self, from: data)
testSupport.assertTypedDate(for: decoded2)
let decoded3 = try JSONDecoder().decode(TypedDate<(Year, Month, Day, Hour, Minute)>.self, from: data)
testSupport.assertTypedDate(for: decoded3)
let decoded4 = try JSONDecoder().decode(TypedDate<(Year, Month, Day, Hour)>.self, from: data)
testSupport.assertTypedDate(for: decoded4)
let decoded5 = try JSONDecoder().decode(TypedDate<(Year, Month, Day)>.self, from: data)
testSupport.assertTypedDate(for: decoded5)
let decoded6 = try JSONDecoder().decode(TypedDate<(Year, Month)>.self, from: data)
testSupport.assertTypedDate(for: decoded6)
let decoded7 = try JSONDecoder().decode(TypedDate<(Year, Month)>.self, from: data)
testSupport.assertTypedDate(for: decoded7)
let decoded8 = try JSONDecoder().decode(TypedDate<(Year)>.self, from: data)
testSupport.assertTypedDate(for: decoded8)
}
}

0 comments on commit f78d191

Please sign in to comment.