Files
data-lite-coder/Tests/DataLiteCoderTests/DateDecoderTests.swift

242 lines
8.4 KiB
Swift

import XCTest
import DataLiteCore
import DLCDecoder
@testable import DataLiteCoder
final class DateDecoderTests: XCTestCase {
func testDeferredToDate() {
let date = Date(timeIntervalSince1970: 123456789)
let dateDecoder = RowDecoder.DateDecoder(strategy: .deferredToDate)
let singleDecoder = SingleValueDecoder(
sqliteData: .real(date.timeIntervalSince1970)
)
XCTAssertEqual(try dateDecoder.decode(from: singleDecoder), date)
var row = SQLiteRow()
row[CodingKeys.key.stringValue] = .real(date.timeIntervalSince1970)
let keyedDecoder = KeyedDecoder(sqliteData: row)
XCTAssertEqual(try dateDecoder.decode(from: keyedDecoder, for: CodingKeys.key), date)
}
func testISO8601() throws {
let dateDecoder = RowDecoder.DateDecoder(strategy: .iso8601)
let formatter = ISO8601DateFormatter()
let string = "2024-04-18T13:45:00Z"
let date = formatter.date(from: string)!
let single = SingleValueDecoder(sqliteData: .text(string))
XCTAssertEqual(try dateDecoder.decode(from: single), date)
var row = SQLiteRow()
row[CodingKeys.key.stringValue] = .text(string)
let keyed = KeyedDecoder(sqliteData: row)
XCTAssertEqual(try dateDecoder.decode(from: keyed, for: CodingKeys.key), date)
}
func testFormatted() throws {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let string = "2023-10-15 16:30:00"
let date = formatter.date(from: string)!
let dateDecoder = RowDecoder.DateDecoder(strategy: .formatted(formatter))
let single = SingleValueDecoder(sqliteData: .text(string))
XCTAssertEqual(try dateDecoder.decode(from: single), date)
var row = SQLiteRow()
row[CodingKeys.key.stringValue] = .text(string)
let keyed = KeyedDecoder(sqliteData: row)
XCTAssertEqual(try dateDecoder.decode(from: keyed, for: CodingKeys.key), date)
}
func testFormattedInvalidDate() {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let invalidString = "not a date"
let dateDecoder = RowDecoder.DateDecoder(strategy: .formatted(formatter))
let single = SingleValueDecoder(sqliteData: .text(invalidString))
XCTAssertThrowsError(try dateDecoder.decode(from: single))
var row = SQLiteRow()
row[CodingKeys.key.stringValue] = .text(invalidString)
let keyed = KeyedDecoder(sqliteData: row)
XCTAssertThrowsError(try dateDecoder.decode(from: keyed, for: CodingKeys.key))
}
func testMillisecondsSince1970Int() throws {
let millis: Int64 = 1_600_000_000_000
let date = Date(timeIntervalSince1970: Double(millis) / 1000)
let dateDecoder = RowDecoder.DateDecoder(strategy: .millisecondsSince1970Int)
let single = SingleValueDecoder(sqliteData: .int(millis))
XCTAssertEqual(try dateDecoder.decode(from: single), date)
var row = SQLiteRow()
row[CodingKeys.key.stringValue] = .int(millis)
let keyed = KeyedDecoder(sqliteData: row)
XCTAssertEqual(try dateDecoder.decode(from: keyed, for: CodingKeys.key), date)
}
func testMillisecondsSince1970Double() throws {
let millis: Double = 1_600_000_000_000.0
let date = Date(timeIntervalSince1970: millis / 1000)
let dateDecoder = RowDecoder.DateDecoder(strategy: .millisecondsSince1970Double)
let single = SingleValueDecoder(sqliteData: .real(millis))
XCTAssertEqual(try dateDecoder.decode(from: single), date)
var row = SQLiteRow()
row[CodingKeys.key.stringValue] = .real(millis)
let keyed = KeyedDecoder(sqliteData: row)
XCTAssertEqual(try dateDecoder.decode(from: keyed, for: CodingKeys.key), date)
}
func testSecondsSince1970Int() throws {
let seconds: Int64 = 1_600_000_000
let date = Date(timeIntervalSince1970: Double(seconds))
let dateDecoder = RowDecoder.DateDecoder(strategy: .secondsSince1970Int)
let single = SingleValueDecoder(sqliteData: .int(seconds))
XCTAssertEqual(try dateDecoder.decode(from: single), date)
var row = SQLiteRow()
row[CodingKeys.key.stringValue] = .int(seconds)
let keyed = KeyedDecoder(sqliteData: row)
XCTAssertEqual(try dateDecoder.decode(from: keyed, for: CodingKeys.key), date)
}
func testSecondsSince1970Double() throws {
let seconds: Double = 1_600_000_000.789
let date = Date(timeIntervalSince1970: seconds)
let dateDecoder = RowDecoder.DateDecoder(strategy: .secondsSince1970Double)
let single = SingleValueDecoder(sqliteData: .real(seconds))
XCTAssertEqual(try dateDecoder.decode(from: single), date)
var row = SQLiteRow()
row[CodingKeys.key.stringValue] = .real(seconds)
let keyed = KeyedDecoder(sqliteData: row)
XCTAssertEqual(try dateDecoder.decode(from: keyed, for: CodingKeys.key), date)
}
}
private extension DateDecoderTests {
enum CodingKeys: CodingKey {
case key
}
final class SingleValueDecoder: DLCDecoder.ValueDecoder {
let sqliteData: SQLiteRawValue
let dateDecoder: DLCDecoder.DateDecoder
let codingPath: [any CodingKey]
let userInfo: [CodingUserInfoKey: Any]
init(
sqliteData: SQLiteRawValue,
dateDecoder: DLCDecoder.DateDecoder = RowDecoder.DateDecoder(strategy: .deferredToDate),
codingPath: [any CodingKey] = [],
userInfo: [CodingUserInfoKey: Any] = [:]
) {
self.sqliteData = sqliteData
self.dateDecoder = dateDecoder
self.codingPath = codingPath
self.userInfo = userInfo
}
func decodeNil() -> Bool {
fatalError()
}
func decodeDate() throws -> Date {
fatalError()
}
func decode<T: SQLiteRawRepresentable>(_ type: T.Type) throws -> T {
type.init(sqliteData)!
}
func container<Key: CodingKey>(
keyedBy type: Key.Type
) throws -> KeyedDecodingContainer<Key> {
fatalError()
}
func unkeyedContainer() throws -> any UnkeyedDecodingContainer {
fatalError()
}
func singleValueContainer() throws -> any SingleValueDecodingContainer {
fatalError()
}
}
final class KeyedDecoder: DLCDecoder.RowDecoder {
let sqliteData: SQLiteRow
let dateDecoder: DLCDecoder.DateDecoder
let codingPath: [any CodingKey]
let userInfo: [CodingUserInfoKey: Any]
var count: Int? { sqliteData.count }
init(
sqliteData: SQLiteRow,
dateDecoder: DLCDecoder.DateDecoder = RowDecoder.DateDecoder(strategy: .deferredToDate),
codingPath: [any CodingKey] = [],
userInfo: [CodingUserInfoKey: Any] = [:]
) {
self.sqliteData = sqliteData
self.dateDecoder = dateDecoder
self.codingPath = codingPath
self.userInfo = userInfo
}
func contains(_ key: any CodingKey) -> Bool {
fatalError()
}
func decodeNil(for key: any CodingKey) throws -> Bool {
fatalError()
}
func decodeDate(for key: any CodingKey) throws -> Date {
fatalError()
}
func decode<T: SQLiteRawRepresentable>(
_ type: T.Type,
for key: any CodingKey
) throws -> T {
type.init(sqliteData[key.stringValue]!)!
}
func decoder(for key: any CodingKey) -> any Decoder {
fatalError()
}
func container<Key: CodingKey>(
keyedBy type: Key.Type
) throws -> KeyedDecodingContainer<Key> {
fatalError()
}
func unkeyedContainer() throws -> any UnkeyedDecodingContainer {
fatalError()
}
func singleValueContainer() throws -> any SingleValueDecodingContainer {
fatalError()
}
}
}