Files
data-lite-coder/Tests/DLCDecoderTests/MultiRowDecoderTests.swift

194 lines
7.0 KiB
Swift

import XCTest
import DataLiteCore
@testable import DLCDecoder
final class MultiRowDecoderTests: XCTestCase {
func testCount() {
let rows = [SQLiteRow](repeating: .init(), count: 5)
let decoder = decoder(sqliteData: rows)
XCTAssertEqual(decoder.count, rows.count)
}
func testDecodeNil() {
let path = [DummyKey(stringValue: "rootKey")]
let testKey = DummyKey(intValue: 0)
let decoder = decoder(sqliteData: [], codingPath: path)
XCTAssertThrowsError(
try decoder.decodeNil(for: testKey)
) { error in
guard case let DecodingError.dataCorrupted(context) = error else {
return XCTFail("Expected DecodingError.dataCorrupted, but got: \(error).")
}
XCTAssertEqual(context.codingPath as? [DummyKey], path + [testKey])
XCTAssertEqual(context.debugDescription, "Attempted to decode nil, but it's not supported for an array of rows.")
}
}
func testDecodeDate() {
let path = [DummyKey(stringValue: "root")]
let key = DummyKey(stringValue: "date")
let decoder = decoder(sqliteData: [], codingPath: path)
XCTAssertThrowsError(
try decoder.decodeDate(for: key)
) { error in
guard case let DecodingError.typeMismatch(type, context) = error else {
return XCTFail("Expected DecodingError.typeMismatch, but got: \(error)")
}
XCTAssert(type == Date.self)
XCTAssertEqual(context.codingPath as? [DummyKey], path + [key])
XCTAssertEqual(context.debugDescription, "Expected a type of \(Date.self), but found an array of rows.")
}
}
func testDecodeForKey() {
let path = [DummyKey(stringValue: "user")]
let key = DummyKey(stringValue: "id")
let decoder = decoder(sqliteData: [], codingPath: path)
XCTAssertThrowsError(
try decoder.decode(String.self, for: key)
) { error in
guard case let DecodingError.typeMismatch(type, context) = error else {
return XCTFail("Expected DecodingError.typeMismatch, but got: \(error)")
}
XCTAssertTrue(type == String.self)
XCTAssertEqual(context.codingPath as? [DummyKey], path + [key])
XCTAssertEqual(
context.debugDescription,
"Expected a type of \(String.self), but found an array of rows."
)
}
}
func testDecoderForKey() throws {
let path = [DummyKey(stringValue: "rootKey")]
let key = DummyKey(intValue: 0)
let rows = [SQLiteRow()]
let decoder = decoder(sqliteData: rows, codingPath: path)
let nestedDecoder = try decoder.decoder(for: key)
guard let rowDecoder = nestedDecoder as? SingleRowDecoder else {
return XCTFail("Expected SingleRowDecoder, but got: \(type(of: nestedDecoder)).")
}
XCTAssertTrue(rowDecoder.dateDecoder as? MockDateDecoder === decoder.dateDecoder as? MockDateDecoder)
XCTAssertEqual(rowDecoder.codingPath as? [DummyKey], path + [key])
}
func testDecoderWithInvalidKey() {
let path = [DummyKey(stringValue: "rootKey")]
let testKey = DummyKey(stringValue: "invalidKey")
let decoder = decoder(sqliteData: [], codingPath: path)
XCTAssertThrowsError(
try decoder.decoder(for: testKey)
) { error in
guard case let DecodingError.keyNotFound(key, context) = error else {
return XCTFail("Expected DecodingError.keyNotFound, but got: \(error).")
}
XCTAssertEqual(key as? DummyKey, testKey)
XCTAssertEqual(context.codingPath as? [DummyKey], path + [testKey])
XCTAssertEqual(context.debugDescription, "Expected an integer key, but found a non-integer key.")
}
}
func testKeyedContainer() {
let path: [DummyKey] = [DummyKey(stringValue: "root")]
let decoder = decoder(sqliteData: [], codingPath: path)
XCTAssertThrowsError(try decoder.container(keyedBy: DummyKey.self)) { error in
guard case let DecodingError.typeMismatch(expectedType, context) = error else {
return XCTFail("Expected DecodingError.typeMismatch")
}
XCTAssertTrue(expectedType == KeyedDecodingContainer<DummyKey>.self)
XCTAssertEqual(context.codingPath as? [DummyKey], path)
XCTAssertEqual(context.debugDescription, "Expected a keyed container, but found an array of rows.")
}
}
func testUnkeyedContainer() throws {
let path = [DummyKey(stringValue: "rootKey")]
let decoder = decoder(sqliteData: [SQLiteRow()], codingPath: path)
let container = try decoder.unkeyedContainer()
guard let unkeyed = container as? UnkeyedContainer<MultiRowDecoder> else {
return XCTFail("Expected UnkeyedContainer, got: \(type(of: container))")
}
XCTAssertTrue(unkeyed.decoder === decoder)
XCTAssertEqual(unkeyed.codingPath as? [DummyKey], path)
}
func testSingleValueContainer() {
let path = [DummyKey(stringValue: "rootKey")]
let decoder = decoder(sqliteData: [], codingPath: path)
XCTAssertThrowsError(
try decoder.singleValueContainer()
) { error in
guard case let DecodingError.typeMismatch(type, context) = error else {
return XCTFail("Expected DecodingError.typeMismatch, but got: \(error).")
}
XCTAssertTrue(type == SingleValueDecodingContainer.self)
XCTAssertEqual(context.codingPath as? [DummyKey], path)
XCTAssertEqual(context.debugDescription, "Expected a single value container, but found an array of rows.")
}
}
}
private extension MultiRowDecoderTests {
func decoder(
sqliteData: [SQLiteRow],
codingPath: [any CodingKey] = []
) -> MultiRowDecoder {
MultiRowDecoder(
dateDecoder: MockDateDecoder(),
sqliteData: sqliteData,
codingPath: codingPath,
userInfo: [:]
)
}
}
private extension MultiRowDecoderTests {
struct DummyKey: CodingKey, Equatable {
var stringValue: String
var intValue: Int?
init(stringValue: String) {
self.stringValue = stringValue
self.intValue = nil
}
init(intValue: Int) {
self.stringValue = "\(intValue)"
self.intValue = intValue
}
}
final class MockDateDecoder: DateDecoder {
func decode(
from decoder: any ValueDecoder
) throws -> Date {
fatalError()
}
func decode(
from decoder: any RowDecoder,
for key: any CodingKey
) throws -> Date {
fatalError()
}
}
}