DataLireCoder swift package
This commit is contained in:
337
Tests/DataLiteCoderTests/RowDecoderTests.swift
Normal file
337
Tests/DataLiteCoderTests/RowDecoderTests.swift
Normal file
@@ -0,0 +1,337 @@
|
||||
import XCTest
|
||||
import DataLiteCore
|
||||
import DataLiteCoder
|
||||
|
||||
final class RowDecoderTests: XCTestCase {
|
||||
// MARK: - Decode SQLiteRow
|
||||
|
||||
func testDecodeRowWithAllTypes() throws {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
let model = StandardModel(
|
||||
id: 123,
|
||||
type: .simple,
|
||||
name: "John Doe",
|
||||
age: 34,
|
||||
isActive: true,
|
||||
score: 3.1415,
|
||||
createdAt: Date(timeIntervalSince1970: 12345),
|
||||
payload: "payload".data(using: .utf8)!
|
||||
)
|
||||
|
||||
var row = SQLiteRow()
|
||||
row["id"] = model.id.sqliteRawValue
|
||||
row["type"] = model.type.rawValue.sqliteRawValue
|
||||
row["name"] = model.name.sqliteRawValue
|
||||
row["age"] = model.age.sqliteRawValue
|
||||
row["isActive"] = model.isActive.sqliteRawValue
|
||||
row["score"] = model.score.sqliteRawValue
|
||||
row["createdAt"] = model.createdAt.sqliteRawValue
|
||||
row["payload"] = model.payload.sqliteRawValue
|
||||
|
||||
let decoded = try decoder.decode(
|
||||
StandardModel.self,
|
||||
from: row
|
||||
)
|
||||
|
||||
XCTAssertEqual(decoded, model)
|
||||
}
|
||||
|
||||
func testDecodeRowWithOptionalValues() throws {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
let model = OptionalModel(
|
||||
id: 123,
|
||||
type: .multiple,
|
||||
name: "Jane Doe",
|
||||
createdAt: Date(timeIntervalSince1970: 11000),
|
||||
payload: "payload".data(using: .utf8)!
|
||||
)
|
||||
|
||||
var row = SQLiteRow()
|
||||
row["id"] = model.id!.sqliteRawValue
|
||||
row["type"] = model.type!.rawValue.sqliteRawValue
|
||||
row["name"] = model.name!.sqliteRawValue
|
||||
row["createdAt"] = model.createdAt!.sqliteRawValue
|
||||
row["payload"] = model.payload!.sqliteRawValue
|
||||
|
||||
let decoded = try decoder.decode(
|
||||
OptionalModel.self,
|
||||
from: row
|
||||
)
|
||||
|
||||
let empty = try decoder.decode(
|
||||
OptionalModel.self,
|
||||
from: SQLiteRow()
|
||||
)
|
||||
|
||||
XCTAssertEqual(decoded, model)
|
||||
XCTAssertEqual(empty, OptionalModel())
|
||||
}
|
||||
|
||||
func testDecodeRowAsArray() throws {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
let dates = [
|
||||
Date(timeIntervalSince1970: 1234),
|
||||
Date(timeIntervalSince1970: 31415),
|
||||
Date(timeIntervalSince1970: 123456789)
|
||||
]
|
||||
|
||||
var row = SQLiteRow()
|
||||
row["key0"] = dates[0].sqliteRawValue
|
||||
row["key1"] = dates[1].sqliteRawValue
|
||||
row["key2"] = dates[2].sqliteRawValue
|
||||
|
||||
let decoded = try decoder.decode([Date].self, from: row)
|
||||
|
||||
XCTAssertEqual(decoded, dates)
|
||||
}
|
||||
|
||||
func testDecodeRowMissingRequiredField() {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
var row = SQLiteRow()
|
||||
row["id"] = 1.sqliteRawValue
|
||||
|
||||
XCTAssertThrowsError(
|
||||
try decoder.decode(SimpleModel.self, from: row)
|
||||
) { error in
|
||||
guard case DecodingError.keyNotFound = error else {
|
||||
return XCTFail("Expected DecodingError.keyNotFound, but got: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testDecodeRowWrongType() {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
var row = SQLiteRow()
|
||||
row["id"] = "not an int".sqliteRawValue
|
||||
row["name"] = "test".sqliteRawValue
|
||||
|
||||
XCTAssertThrowsError(
|
||||
try decoder.decode(SimpleModel.self, from: row)
|
||||
) { error in
|
||||
guard case DecodingError.typeMismatch = error else {
|
||||
return XCTFail("Expected DecodingError.typeMismatch, but got: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Decode array of SQLiteRow
|
||||
|
||||
func testDecodeRowArrayWithAllTypes() throws {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
let models = [
|
||||
StandardModel(
|
||||
id: 123,
|
||||
type: .simple,
|
||||
name: "John Doe",
|
||||
age: 34,
|
||||
isActive: true,
|
||||
score: 3.1415,
|
||||
createdAt: Date(timeIntervalSince1970: 12345),
|
||||
payload: "payload".data(using: .utf8)!
|
||||
),
|
||||
StandardModel(
|
||||
id: 456,
|
||||
type: .multiple,
|
||||
name: "Jane Doe",
|
||||
age: 28,
|
||||
isActive: false,
|
||||
score: 2.7182,
|
||||
createdAt: Date(timeIntervalSince1970: 67890),
|
||||
payload: "another payload".data(using: .utf8)!
|
||||
)
|
||||
]
|
||||
|
||||
let rows: [SQLiteRow] = models.map { model in
|
||||
var row = SQLiteRow()
|
||||
row["id"] = model.id.sqliteRawValue
|
||||
row["type"] = model.type.rawValue.sqliteRawValue
|
||||
row["name"] = model.name.sqliteRawValue
|
||||
row["age"] = model.age.sqliteRawValue
|
||||
row["isActive"] = model.isActive.sqliteRawValue
|
||||
row["score"] = model.score.sqliteRawValue
|
||||
row["createdAt"] = model.createdAt.sqliteRawValue
|
||||
row["payload"] = model.payload.sqliteRawValue
|
||||
return row
|
||||
}
|
||||
|
||||
let decoded = try decoder.decode([StandardModel].self, from: rows)
|
||||
|
||||
XCTAssertEqual(decoded, models)
|
||||
}
|
||||
|
||||
func testDecodeRowArrayWithOptionalValues() throws {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
let models = [
|
||||
OptionalModel(
|
||||
id: 123,
|
||||
type: .multiple,
|
||||
name: "Jane Doe",
|
||||
createdAt: Date(timeIntervalSince1970: 11000),
|
||||
payload: "payload".data(using: .utf8)!
|
||||
),
|
||||
OptionalModel(
|
||||
id: nil,
|
||||
type: nil,
|
||||
name: "John Doe",
|
||||
createdAt: nil,
|
||||
payload: nil
|
||||
)
|
||||
]
|
||||
|
||||
let rows: [SQLiteRow] = models.map { model in
|
||||
var row = SQLiteRow()
|
||||
row["id"] = model.id?.sqliteRawValue
|
||||
row["type"] = model.type?.rawValue.sqliteRawValue
|
||||
row["name"] = model.name?.sqliteRawValue
|
||||
row["createdAt"] = model.createdAt?.sqliteRawValue
|
||||
row["payload"] = model.payload?.sqliteRawValue
|
||||
return row
|
||||
}
|
||||
|
||||
let decoded = try decoder.decode([OptionalModel].self, from: rows)
|
||||
|
||||
XCTAssertEqual(decoded, models)
|
||||
}
|
||||
|
||||
func testDecodeRowArrayAsDates() throws {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
let dates = [
|
||||
[
|
||||
Date(timeIntervalSince1970: 1234),
|
||||
Date(timeIntervalSince1970: 31415),
|
||||
Date(timeIntervalSince1970: 12345679)
|
||||
],
|
||||
[
|
||||
Date(timeIntervalSince1970: 1234),
|
||||
Date(timeIntervalSince1970: 31415),
|
||||
Date(timeIntervalSince1970: 12345679)
|
||||
]
|
||||
]
|
||||
|
||||
let rows: [SQLiteRow] = dates.map { dates in
|
||||
var row = SQLiteRow()
|
||||
row["key0"] = dates[0].sqliteRawValue
|
||||
row["key1"] = dates[1].sqliteRawValue
|
||||
row["key2"] = dates[2].sqliteRawValue
|
||||
return row
|
||||
}
|
||||
|
||||
let decoded = try decoder.decode([[Date]].self, from: rows)
|
||||
|
||||
XCTAssertEqual(decoded, dates)
|
||||
}
|
||||
|
||||
func testDecodeRowArrayMissingRequiredField() {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
var row = SQLiteRow()
|
||||
row["id"] = 1.sqliteRawValue
|
||||
|
||||
XCTAssertThrowsError(
|
||||
try decoder.decode([SimpleModel].self, from: [row])
|
||||
) { error in
|
||||
guard case DecodingError.keyNotFound = error else {
|
||||
return XCTFail("Expected DecodingError.keyNotFound, but got: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testDecodeRowArrayWrongType() {
|
||||
let decoder = RowDecoder(
|
||||
userInfo: [:],
|
||||
dateDecodingStrategy: .deferredToDate
|
||||
)
|
||||
|
||||
var row = SQLiteRow()
|
||||
row["id"] = "not an int".sqliteRawValue
|
||||
row["name"] = "test".sqliteRawValue
|
||||
|
||||
XCTAssertThrowsError(
|
||||
try decoder.decode([SimpleModel].self, from: [row])
|
||||
) { error in
|
||||
guard case DecodingError.typeMismatch = error else {
|
||||
return XCTFail("Expected DecodingError.typeMismatch, but got: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension RowDecoderTests {
|
||||
enum `Type`: String, Decodable, Equatable {
|
||||
case simple
|
||||
case multiple
|
||||
}
|
||||
|
||||
struct StandardModel: Decodable, Equatable {
|
||||
let id: Int
|
||||
let type: `Type`
|
||||
let name: String
|
||||
let age: Int
|
||||
let isActive: Bool
|
||||
let score: Double
|
||||
let createdAt: Date
|
||||
let payload: Data
|
||||
}
|
||||
|
||||
struct OptionalModel: Decodable, Equatable {
|
||||
let id: Int?
|
||||
let type: `Type`?
|
||||
let name: String?
|
||||
let createdAt: Date?
|
||||
let payload: Data?
|
||||
|
||||
init(
|
||||
id: Int? = nil,
|
||||
type: `Type`? = nil,
|
||||
name: String? = nil,
|
||||
createdAt: Date? = nil,
|
||||
payload: Data? = nil
|
||||
) {
|
||||
self.id = id
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.createdAt = createdAt
|
||||
self.payload = payload
|
||||
}
|
||||
}
|
||||
|
||||
struct SimpleModel: Decodable, Equatable {
|
||||
let id: Int
|
||||
let name: String
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user