DataLireCoder swift package
This commit is contained in:
29
Tests/DLCEncoderTests/FailedEncoderTests.swift
Normal file
29
Tests/DLCEncoderTests/FailedEncoderTests.swift
Normal file
@@ -0,0 +1,29 @@
|
||||
import XCTest
|
||||
import DLCCommon
|
||||
|
||||
@testable import DLCEncoder
|
||||
|
||||
final class FailedEncoderTests: XCTestCase {
|
||||
func testKeyedContainer() {
|
||||
let path = [RowCodingKey(intValue: 1), RowCodingKey(intValue: 2)]
|
||||
let encoder = FailedEncoder(codingPath: path)
|
||||
let container = encoder.container(keyedBy: RowCodingKey.self)
|
||||
XCTAssertEqual(container.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testUnkeyedContainer() {
|
||||
let path = [RowCodingKey(intValue: 1), RowCodingKey(intValue: 2)]
|
||||
let encoder = FailedEncoder(codingPath: path)
|
||||
let container = encoder.unkeyedContainer()
|
||||
XCTAssertTrue(container is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(container.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testSingleValueContainer() {
|
||||
let path = [RowCodingKey(intValue: 1), RowCodingKey(intValue: 2)]
|
||||
let encoder = FailedEncoder(codingPath: path)
|
||||
let container = encoder.singleValueContainer()
|
||||
XCTAssertTrue(container is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(container.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
}
|
||||
153
Tests/DLCEncoderTests/FailedEncodingContainerTests.swift
Normal file
153
Tests/DLCEncoderTests/FailedEncodingContainerTests.swift
Normal file
@@ -0,0 +1,153 @@
|
||||
import XCTest
|
||||
import DLCCommon
|
||||
|
||||
@testable import DLCEncoder
|
||||
|
||||
final class FailedEncodingContainerTests: XCTestCase {
|
||||
func testEncodeNil() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
|
||||
XCTAssertThrowsError(
|
||||
try container.encodeNil()
|
||||
) { error in
|
||||
guard case let EncodingError.invalidValue(_, context) = error else {
|
||||
return XCTFail()
|
||||
}
|
||||
XCTAssertEqual(context.codingPath as? [RowCodingKey], path)
|
||||
XCTAssertEqual(
|
||||
context.debugDescription,
|
||||
"encodeNil() is not supported for this encoding path."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testEncodeNilForKey() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let key = RowCodingKey(intValue: 2)
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
|
||||
XCTAssertThrowsError(
|
||||
try container.encodeNil(forKey: key)
|
||||
) { error in
|
||||
guard case let EncodingError.invalidValue(_, context) = error else {
|
||||
return XCTFail()
|
||||
}
|
||||
XCTAssertEqual(context.codingPath as? [RowCodingKey], path + [key])
|
||||
XCTAssertEqual(
|
||||
context.debugDescription,
|
||||
"encodeNil(forKey:) is not supported for this encoding path."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testEncodeValue() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
|
||||
XCTAssertThrowsError(
|
||||
try container.encode(123)
|
||||
) { error in
|
||||
guard case let EncodingError.invalidValue(_, context) = error else {
|
||||
return XCTFail()
|
||||
}
|
||||
XCTAssertEqual(context.codingPath as? [RowCodingKey], path)
|
||||
XCTAssertEqual(
|
||||
context.debugDescription,
|
||||
"encode(_:) is not supported for this encoding path."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testEncodeValueForKey() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let key = RowCodingKey(intValue: 2)
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
|
||||
XCTAssertThrowsError(
|
||||
try container.encode(123, forKey: key)
|
||||
) { error in
|
||||
guard case let EncodingError.invalidValue(_, context) = error else {
|
||||
return XCTFail()
|
||||
}
|
||||
XCTAssertEqual(context.codingPath as? [RowCodingKey], path + [key])
|
||||
XCTAssertEqual(
|
||||
context.debugDescription,
|
||||
"encode(_:forKey:) is not supported for this encoding path."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testNestedKeyedContainer() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
let nestedContainer = container.nestedContainer(
|
||||
keyedBy: RowCodingKey.self
|
||||
)
|
||||
XCTAssertEqual(nestedContainer.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testNestedKeyedContainerForKey() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let key = RowCodingKey(intValue: 2)
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
let nestedContainer = container.nestedContainer(
|
||||
keyedBy: RowCodingKey.self, forKey: key
|
||||
)
|
||||
XCTAssertEqual(nestedContainer.codingPath as? [RowCodingKey], path + [key])
|
||||
}
|
||||
|
||||
func testNestedUnkeyedContainer() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
let nestedContainer = container.nestedUnkeyedContainer()
|
||||
XCTAssertTrue(nestedContainer is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(nestedContainer.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testNestedUnkeyedContainerForKey() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let key = RowCodingKey(intValue: 2)
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
let nestedContainer = container.nestedUnkeyedContainer(forKey: key)
|
||||
XCTAssertTrue(nestedContainer is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(nestedContainer.codingPath as? [RowCodingKey], path + [key])
|
||||
}
|
||||
|
||||
func testSuperEncoder() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
let encoder = container.superEncoder()
|
||||
XCTAssertTrue(encoder is FailedEncoder)
|
||||
XCTAssertEqual(encoder.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testSuperEncoderForKey() {
|
||||
let path = [RowCodingKey(intValue: 1)]
|
||||
let key = RowCodingKey(intValue: 2)
|
||||
let container = FailedEncodingContainer<RowCodingKey>(
|
||||
codingPath: path
|
||||
)
|
||||
let encoder = container.superEncoder(forKey: key)
|
||||
XCTAssertTrue(encoder is FailedEncoder)
|
||||
XCTAssertEqual(encoder.codingPath as? [RowCodingKey], path + [key])
|
||||
}
|
||||
}
|
||||
505
Tests/DLCEncoderTests/KeyedContainerTests.swift
Normal file
505
Tests/DLCEncoderTests/KeyedContainerTests.swift
Normal file
@@ -0,0 +1,505 @@
|
||||
import XCTest
|
||||
import DataLiteCore
|
||||
import DLCCommon
|
||||
|
||||
@testable import DLCEncoder
|
||||
|
||||
final class KeyedContainerTests: XCTestCase {
|
||||
func testEncodeNil() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeNil(forKey: .key1)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 1)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeBool() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(true, forKey: .key1)
|
||||
try container.encodeIfPresent(false, forKey: .key2)
|
||||
try container.encodeIfPresent(nil as Bool?, forKey: .key3)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 3)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(1))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .int(0))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key3.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeString() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent("test", forKey: .key1)
|
||||
try container.encodeIfPresent(nil as String?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .text("test"))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeDouble() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(Double(3.14), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as Double?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .real(3.14))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeFloat() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(Float(3.14), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as Float?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .real(Double(Float(3.14))))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeInt() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(Int(42), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as Int?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(42))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeInt8() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(Int8(8), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as Int8?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(Int64(8)))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeInt16() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(Int16(16), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as Int16?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(Int64(16)))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeInt32() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(Int32(32), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as Int32?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(Int64(32)))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeInt64() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(Int64(64), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as Int64?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(64))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeUInt() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(UInt(42), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as UInt?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(42))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeUInt8() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(UInt8(8), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as UInt8?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(8))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeUInt16() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(UInt16(16), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as UInt16?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(16))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeUInt32() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(UInt32(32), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as UInt32?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(32))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeUInt64() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(UInt64(64), forKey: .key1)
|
||||
try container.encodeIfPresent(nil as UInt64?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .int(64))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeDate() throws {
|
||||
let date = Date()
|
||||
let dateString = ISO8601DateFormatter().string(from: date)
|
||||
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(date, forKey: .key1)
|
||||
try container.encodeIfPresent(nil as Date?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .text(dateString))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeRawRepresentable() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(RawRepresentableModel.test, forKey: .key1)
|
||||
try container.encodeIfPresent(nil as RawRepresentableModel?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .text(RawRepresentableModel.test.rawValue))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testEncodeEncodable() throws {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: []
|
||||
)
|
||||
)
|
||||
|
||||
try container.encodeIfPresent(EncodableModel.test, forKey: .key1)
|
||||
try container.encodeIfPresent(nil as EncodableModel?, forKey: .key2)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1.stringValue], .text(EncodableModel.test.rawValue))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2.stringValue], .null)
|
||||
}
|
||||
|
||||
func testNestedKeyedContainer() {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: [CodingKeys.key1]
|
||||
)
|
||||
)
|
||||
let nestedContainer = container.nestedContainer(
|
||||
keyedBy: CodingKeys.self, forKey: .key3
|
||||
)
|
||||
XCTAssertEqual(nestedContainer.codingPath as? [CodingKeys], [.key1, .key3])
|
||||
}
|
||||
|
||||
func testNestedUnkeyedContainer() {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: [CodingKeys.key1]
|
||||
)
|
||||
)
|
||||
let nestedContainer = container.nestedUnkeyedContainer(forKey: .key3)
|
||||
XCTAssertTrue(nestedContainer is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(nestedContainer.codingPath as? [CodingKeys], [.key1, .key3])
|
||||
}
|
||||
|
||||
func testSuperEncoder() {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: [CodingKeys.key1]
|
||||
)
|
||||
)
|
||||
let superEncoder = container.superEncoder()
|
||||
XCTAssertTrue(superEncoder is FailedEncoder)
|
||||
XCTAssertEqual(superEncoder.codingPath as? [CodingKeys], [.key1])
|
||||
}
|
||||
|
||||
func testSuperEncoderForKey() {
|
||||
let encoder = MockSingleRowEncoder()
|
||||
var container = KeyedEncodingContainer(
|
||||
KeyedContainer<MockSingleRowEncoder, CodingKeys>(
|
||||
encoder: encoder, codingPath: [CodingKeys.key1]
|
||||
)
|
||||
)
|
||||
let superEncoder = container.superEncoder(forKey: .key3)
|
||||
XCTAssertTrue(superEncoder is FailedEncoder)
|
||||
XCTAssertEqual(superEncoder.codingPath as? [CodingKeys], [.key1, .key3])
|
||||
}
|
||||
}
|
||||
|
||||
private extension KeyedContainerTests {
|
||||
enum CodingKeys: CodingKey {
|
||||
case key1
|
||||
case key2
|
||||
case key3
|
||||
}
|
||||
|
||||
enum RawRepresentableModel: String, Encodable, SQLiteRawRepresentable {
|
||||
case test
|
||||
}
|
||||
|
||||
enum EncodableModel: String, Encodable {
|
||||
case test
|
||||
}
|
||||
|
||||
final class MockDateEncoder: DateEncoder {
|
||||
func encode(_ date: Date, to encoder: any ValueEncoder) throws {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func encode(_ date: Date, for key: any CodingKey, to encoder: any RowEncoder) throws {
|
||||
let formatter = ISO8601DateFormatter()
|
||||
let dateString = formatter.string(from: date)
|
||||
try encoder.encode(dateString, for: key)
|
||||
}
|
||||
}
|
||||
|
||||
final class MockSingleRowEncoder: RowEncoder {
|
||||
private(set) var sqliteData: SQLiteRow
|
||||
let dateEncoder: any DateEncoder
|
||||
let codingPath: [any CodingKey]
|
||||
let userInfo: [CodingUserInfoKey: Any]
|
||||
var count: Int { sqliteData.count }
|
||||
|
||||
init(
|
||||
sqliteData: SQLiteRow = SQLiteRow(),
|
||||
dateEncoder: any DateEncoder = MockDateEncoder(),
|
||||
codingPath: [any CodingKey] = [],
|
||||
userInfo: [CodingUserInfoKey: Any] = [:]
|
||||
) {
|
||||
self.sqliteData = sqliteData
|
||||
self.dateEncoder = dateEncoder
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
}
|
||||
|
||||
func set(_ value: Any, for key: any CodingKey) throws {
|
||||
guard let value = value as? SQLiteRawValue else {
|
||||
fatalError()
|
||||
}
|
||||
sqliteData[key.stringValue] = value
|
||||
}
|
||||
|
||||
func encodeNil(for key: any CodingKey) throws {
|
||||
sqliteData[key.stringValue] = .null
|
||||
}
|
||||
|
||||
func encodeDate(_ date: Date, for key: any CodingKey) throws {
|
||||
try dateEncoder.encode(date, for: key, to: self)
|
||||
}
|
||||
|
||||
func encode<T: SQLiteRawBindable>(_ value: T, for key: any CodingKey) throws {
|
||||
sqliteData[key.stringValue] = value.sqliteRawValue
|
||||
}
|
||||
|
||||
func encoder(for key: any CodingKey) throws -> any Encoder {
|
||||
MockSingleValueEncoder()
|
||||
}
|
||||
|
||||
func container<Key: CodingKey>(
|
||||
keyedBy type: Key.Type
|
||||
) -> KeyedEncodingContainer<Key> {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func unkeyedContainer() -> any UnkeyedEncodingContainer {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func singleValueContainer() -> any SingleValueEncodingContainer {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
final class MockSingleValueEncoder: ValueEncoder {
|
||||
private(set) var sqliteData: SQLiteRawValue?
|
||||
let dateEncoder: any DateEncoder
|
||||
let codingPath: [any CodingKey]
|
||||
let userInfo: [CodingUserInfoKey: Any]
|
||||
|
||||
init(
|
||||
sqliteData: SQLiteRawValue? = nil,
|
||||
dateEncoder: any DateEncoder = MockDateEncoder(),
|
||||
codingPath: [any CodingKey] = [],
|
||||
userInfo: [CodingUserInfoKey: Any] = [:]
|
||||
) {
|
||||
self.sqliteData = sqliteData
|
||||
self.dateEncoder = dateEncoder
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
}
|
||||
|
||||
func encodeNil() throws {
|
||||
sqliteData = .null
|
||||
}
|
||||
|
||||
func encodeDate(_ date: Date) throws {
|
||||
try dateEncoder.encode(date, to: self)
|
||||
}
|
||||
|
||||
func encode<T: SQLiteRawBindable>(_ value: T) throws {
|
||||
sqliteData = value.sqliteRawValue
|
||||
}
|
||||
|
||||
func container<Key: CodingKey>(
|
||||
keyedBy type: Key.Type
|
||||
) -> KeyedEncodingContainer<Key> {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func unkeyedContainer() -> any UnkeyedEncodingContainer {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func singleValueContainer() -> any SingleValueEncodingContainer {
|
||||
MockSingleValueContainer(encoder: self, codingPath: [])
|
||||
}
|
||||
}
|
||||
|
||||
final class MockSingleValueContainer<Encoder: ValueEncoder>: Container, SingleValueEncodingContainer {
|
||||
let encoder: Encoder
|
||||
let codingPath: [any CodingKey]
|
||||
|
||||
init(
|
||||
encoder: Encoder,
|
||||
codingPath: [any CodingKey]
|
||||
) {
|
||||
self.encoder = encoder
|
||||
self.codingPath = codingPath
|
||||
}
|
||||
|
||||
func encodeNil() throws {
|
||||
try encoder.encodeNil()
|
||||
}
|
||||
|
||||
func encode<T: Encodable>(_ value: T) throws {
|
||||
switch value {
|
||||
case let value as Date:
|
||||
try encoder.encodeDate(value)
|
||||
case let value as SQLiteRawRepresentable:
|
||||
try encoder.encode(value)
|
||||
default:
|
||||
try value.encode(to: encoder)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
174
Tests/DLCEncoderTests/MultiRowEncoderTests.swift
Normal file
174
Tests/DLCEncoderTests/MultiRowEncoderTests.swift
Normal file
@@ -0,0 +1,174 @@
|
||||
import XCTest
|
||||
import DataLiteCore
|
||||
import DLCCommon
|
||||
|
||||
@testable import DLCEncoder
|
||||
|
||||
final class MultiRowEncoderTests: XCTestCase {
|
||||
func testSetValueForKey() throws {
|
||||
let encoder = MultiRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: [],
|
||||
userInfo: [:]
|
||||
)
|
||||
try encoder.set(SQLiteRow(), for: RowCodingKey(intValue: 0))
|
||||
try encoder.set(SQLiteRow(), for: RowCodingKey(intValue: 1))
|
||||
XCTAssertEqual(encoder.sqliteData.count, 2)
|
||||
XCTAssertEqual(encoder.count, encoder.sqliteData.count)
|
||||
}
|
||||
|
||||
func testSetInvalidValueForKey() {
|
||||
let value = "Test Value"
|
||||
let path = [RowCodingKey(intValue: 0)]
|
||||
let key = RowCodingKey(intValue: 1)
|
||||
let encoder = MultiRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
XCTAssertThrowsError(
|
||||
try encoder.set(value, for: key)
|
||||
) { error in
|
||||
guard case let EncodingError.invalidValue(thrownValue, context) = error else {
|
||||
return XCTFail("Expected EncodingError.invalidValue, got \(error)")
|
||||
}
|
||||
XCTAssertEqual(thrownValue as? String, value)
|
||||
XCTAssertEqual(context.codingPath as? [RowCodingKey], path + [key])
|
||||
XCTAssertEqual(context.debugDescription, "Expected value of type SQLiteRow")
|
||||
}
|
||||
}
|
||||
|
||||
func testEncodeNilThrows() {
|
||||
let key = RowCodingKey(intValue: 1)
|
||||
let path = [RowCodingKey(intValue: 0)]
|
||||
let encoder = MultiRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
|
||||
XCTAssertThrowsError(try encoder.encodeNil(for: key)) { error in
|
||||
guard case let EncodingError.invalidValue(_, context) = error else {
|
||||
return XCTFail("Expected EncodingError.invalidValue, got \(error)")
|
||||
}
|
||||
XCTAssertEqual(context.codingPath as? [RowCodingKey], path + [key])
|
||||
XCTAssertEqual(context.debugDescription, "Attempted to encode nil, but it's not supported.")
|
||||
}
|
||||
}
|
||||
|
||||
func testEncodeDateThrows() {
|
||||
let key = RowCodingKey(intValue: 2)
|
||||
let path = [RowCodingKey(intValue: 0)]
|
||||
let encoder = MultiRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let date = Date()
|
||||
|
||||
XCTAssertThrowsError(try encoder.encodeDate(date, for: key)) { error in
|
||||
guard case let EncodingError.invalidValue(thrownValue, context) = error else {
|
||||
return XCTFail("Expected EncodingError.invalidValue, got \(error)")
|
||||
}
|
||||
XCTAssertEqual(thrownValue as? Date, date)
|
||||
XCTAssertEqual(context.codingPath as? [RowCodingKey], path + [key])
|
||||
XCTAssertEqual(context.debugDescription, "Attempted to encode Date, but it's not supported.")
|
||||
}
|
||||
}
|
||||
|
||||
func testEncodeRawBindableThrows() {
|
||||
let value = "Test Value"
|
||||
let path = [RowCodingKey(intValue: 0)]
|
||||
let key = RowCodingKey(intValue: 1)
|
||||
let encoder = MultiRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
|
||||
XCTAssertThrowsError(try encoder.encode(value, for: key)) { error in
|
||||
guard case let EncodingError.invalidValue(thrownValue, context) = error else {
|
||||
return XCTFail("Expected EncodingError.invalidValue, got \(error)")
|
||||
}
|
||||
XCTAssertEqual(thrownValue as? String, value)
|
||||
XCTAssertEqual(context.codingPath as? [RowCodingKey], path + [key])
|
||||
XCTAssertEqual(
|
||||
context.debugDescription,
|
||||
"Attempted to encode \(type(of: value)), but it's not supported."
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testEncoderForKey() throws {
|
||||
let path = [RowCodingKey(intValue: 0)]
|
||||
let key = RowCodingKey(intValue: 1)
|
||||
let encoder = MultiRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
|
||||
let nestedEncoder = try encoder.encoder(for: key)
|
||||
|
||||
XCTAssertTrue(nestedEncoder is SingleRowEncoder)
|
||||
XCTAssertEqual(nestedEncoder.codingPath as? [RowCodingKey], path + [key])
|
||||
}
|
||||
|
||||
func testKeyedContainer() {
|
||||
let path = [RowCodingKey(intValue: 0)]
|
||||
let encoder = MultiRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let container = encoder.container(keyedBy: RowCodingKey.self)
|
||||
XCTAssertEqual(container.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testUnkeyedContainer() {
|
||||
let path = [RowCodingKey(intValue: 0)]
|
||||
let encoder = MultiRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let container = encoder.unkeyedContainer()
|
||||
|
||||
XCTAssertTrue(container is UnkeyedContainer<MultiRowEncoder>)
|
||||
XCTAssertEqual(container.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testSingleValueContainer() {
|
||||
let path = [RowCodingKey(intValue: 0)]
|
||||
let encoder = MultiRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let container = encoder.singleValueContainer()
|
||||
|
||||
XCTAssertTrue(container is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(container.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
}
|
||||
|
||||
private extension MultiRowEncoderTests {
|
||||
final class MockDateEncoder: DateEncoder {
|
||||
private(set) var didCallEncode = false
|
||||
|
||||
func encode(
|
||||
_ date: Date,
|
||||
to encoder: any ValueEncoder
|
||||
) throws {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func encode(
|
||||
_ date: Date,
|
||||
for key: any CodingKey,
|
||||
to encoder: any RowEncoder
|
||||
) throws {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
164
Tests/DLCEncoderTests/SingleRowEncoderTests.swift
Normal file
164
Tests/DLCEncoderTests/SingleRowEncoderTests.swift
Normal file
@@ -0,0 +1,164 @@
|
||||
import XCTest
|
||||
import DataLiteCore
|
||||
import DLCCommon
|
||||
|
||||
@testable import DLCEncoder
|
||||
|
||||
final class SingleRowEncoderTests: XCTestCase {
|
||||
func testSetValueForKey() throws {
|
||||
let encoder = SingleRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: [],
|
||||
userInfo: [:]
|
||||
)
|
||||
try encoder.set(SQLiteRawValue.int(42), for: CodingKeys.key1)
|
||||
try encoder.set(SQLiteRawValue.real(3.14), for: CodingKeys.key2)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1], .int(42))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2], .real(3.14))
|
||||
XCTAssertEqual(encoder.count, encoder.sqliteData.count)
|
||||
}
|
||||
|
||||
func testSetInvalidValueForKey() {
|
||||
let value = "Test Value"
|
||||
let path = [CodingKeys.key1]
|
||||
let encoder = SingleRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
XCTAssertThrowsError(
|
||||
try encoder.set(value, for: CodingKeys.key2)
|
||||
) { error in
|
||||
guard case let EncodingError.invalidValue(thrownValue, context) = error else {
|
||||
return XCTFail("Expected EncodingError.invalidValue, got \(error)")
|
||||
}
|
||||
XCTAssertEqual(thrownValue as? String, value)
|
||||
XCTAssertEqual(context.codingPath as? [CodingKeys], path + [.key2])
|
||||
XCTAssertEqual(context.debugDescription, "The value does not match SQLiteRawValue")
|
||||
}
|
||||
}
|
||||
|
||||
func testEncodeNilForKey() throws {
|
||||
let encoder = SingleRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: [],
|
||||
userInfo: [:]
|
||||
)
|
||||
try encoder.encodeNil(for: CodingKeys.key1)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1], .null)
|
||||
XCTAssertEqual(encoder.count, encoder.sqliteData.count)
|
||||
}
|
||||
|
||||
func testEncodeDateForKey() throws {
|
||||
let date = Date()
|
||||
let mockDateEncoder = MockDateEncoder()
|
||||
let encoder = SingleRowEncoder(
|
||||
dateEncoder: mockDateEncoder,
|
||||
codingPath: [],
|
||||
userInfo: [:]
|
||||
)
|
||||
|
||||
try encoder.encodeDate(date, for: CodingKeys.key1)
|
||||
|
||||
XCTAssertTrue(mockDateEncoder.didCallEncode)
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1], date.sqliteRawValue)
|
||||
XCTAssertEqual(encoder.count, encoder.sqliteData.count)
|
||||
}
|
||||
|
||||
func testEncodeValueForKey() throws {
|
||||
let encoder = SingleRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: [],
|
||||
userInfo: [:]
|
||||
)
|
||||
|
||||
try encoder.encode(123, for: CodingKeys.key1)
|
||||
try encoder.encode(3.14, for: CodingKeys.key2)
|
||||
try encoder.encode("Hello", for: CodingKeys.key3)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key1], .int(123))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key2], .real(3.14))
|
||||
XCTAssertEqual(encoder.sqliteData[CodingKeys.key3], .text("Hello"))
|
||||
XCTAssertEqual(encoder.count, encoder.sqliteData.count)
|
||||
}
|
||||
|
||||
func testEncoderForKey() throws {
|
||||
let path = [CodingKeys.key1]
|
||||
let encoder = SingleRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
|
||||
let key = CodingKeys.key2
|
||||
let nestedEncoder = try encoder.encoder(for: key)
|
||||
|
||||
XCTAssertTrue(nestedEncoder is SingleValueEncoder)
|
||||
XCTAssertEqual(nestedEncoder.codingPath as? [CodingKeys], path + [key])
|
||||
}
|
||||
|
||||
func testKeyedContainer() {
|
||||
let path = [CodingKeys.key1]
|
||||
let encoder = SingleRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let container = encoder.container(keyedBy: CodingKeys.self)
|
||||
XCTAssertEqual(container.codingPath as? [CodingKeys], path)
|
||||
}
|
||||
|
||||
func testUnkeyedContainer() {
|
||||
let path = [CodingKeys.key1]
|
||||
let encoder = SingleRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let container = encoder.unkeyedContainer()
|
||||
|
||||
XCTAssertTrue(container is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(container.codingPath as? [CodingKeys], path)
|
||||
}
|
||||
|
||||
func testSingleValueContainer() {
|
||||
let path = [CodingKeys.key1]
|
||||
let encoder = SingleRowEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let container = encoder.singleValueContainer()
|
||||
|
||||
XCTAssertTrue(container is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(container.codingPath as? [CodingKeys], path)
|
||||
}
|
||||
}
|
||||
|
||||
private extension SingleRowEncoderTests {
|
||||
enum CodingKeys: CodingKey {
|
||||
case key1
|
||||
case key2
|
||||
case key3
|
||||
}
|
||||
|
||||
final class MockDateEncoder: DateEncoder {
|
||||
private(set) var didCallEncode = false
|
||||
|
||||
func encode(
|
||||
_ date: Date,
|
||||
to encoder: any ValueEncoder
|
||||
) throws {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func encode(
|
||||
_ date: Date,
|
||||
for key: any CodingKey,
|
||||
to encoder: any RowEncoder
|
||||
) throws {
|
||||
didCallEncode = true
|
||||
try encoder.encode(date, for: key)
|
||||
}
|
||||
}
|
||||
}
|
||||
205
Tests/DLCEncoderTests/SingleValueContainerTests.swift
Normal file
205
Tests/DLCEncoderTests/SingleValueContainerTests.swift
Normal file
@@ -0,0 +1,205 @@
|
||||
import XCTest
|
||||
import DataLiteCore
|
||||
|
||||
@testable import DLCEncoder
|
||||
|
||||
final class SingleValueContainerTests: XCTestCase {
|
||||
func testEncodeNil() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encodeNil()
|
||||
XCTAssertEqual(encoder.sqliteData, .null)
|
||||
}
|
||||
|
||||
func testEncodeBool() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
|
||||
try container.encode(true)
|
||||
XCTAssertEqual(encoder.sqliteData, .int(1))
|
||||
|
||||
try container.encode(false)
|
||||
XCTAssertEqual(encoder.sqliteData, .int(0))
|
||||
}
|
||||
|
||||
func testEncodeString() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode("test string")
|
||||
XCTAssertEqual(encoder.sqliteData, .text("test string"))
|
||||
}
|
||||
|
||||
func testEncodeDouble() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(Double(3.14))
|
||||
XCTAssertEqual(encoder.sqliteData, .real(3.14))
|
||||
}
|
||||
|
||||
func testEncodeFloat() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(Float(3.14))
|
||||
XCTAssertEqual(encoder.sqliteData, .real(Double(Float(3.14))))
|
||||
}
|
||||
|
||||
func testEncodeInt() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(Int(42))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(42))
|
||||
}
|
||||
|
||||
func testEncodeInt8() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(Int8(8))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(Int64(8)))
|
||||
}
|
||||
|
||||
func testEncodeInt16() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(Int16(16))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(Int64(16)))
|
||||
}
|
||||
|
||||
func testEncodeInt32() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(Int32(32))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(Int64(32)))
|
||||
}
|
||||
|
||||
func testEncodeInt64() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(Int64(64))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(64))
|
||||
}
|
||||
|
||||
func testEncodeUInt() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(UInt(42))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(42))
|
||||
}
|
||||
|
||||
func testEncodeUInt8() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(UInt8(8))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(8))
|
||||
}
|
||||
|
||||
func testEncodeUInt16() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(UInt16(16))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(16))
|
||||
}
|
||||
|
||||
func testEncodeUInt32() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(UInt32(32))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(32))
|
||||
}
|
||||
|
||||
func testEncodeUInt64() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(UInt64(64))
|
||||
XCTAssertEqual(encoder.sqliteData, .int(64))
|
||||
}
|
||||
|
||||
func testEncodeDate() throws {
|
||||
let date = Date()
|
||||
let dateString = ISO8601DateFormatter().string(from: date)
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(date)
|
||||
XCTAssertEqual(encoder.sqliteData, .text(dateString))
|
||||
}
|
||||
|
||||
func testEncodeRawRepresentable() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(RawRepresentableModel.test)
|
||||
XCTAssertEqual(encoder.sqliteData, .text(RawRepresentableModel.test.rawValue))
|
||||
}
|
||||
|
||||
func testEncodeEncodable() throws {
|
||||
let encoder = MockSingleValueEncoder()
|
||||
let container = SingleValueContainer(encoder: encoder, codingPath: [])
|
||||
try container.encode(EncodableModel.test)
|
||||
XCTAssertEqual(encoder.sqliteData, .text(EncodableModel.test.rawValue))
|
||||
}
|
||||
}
|
||||
|
||||
private extension SingleValueContainerTests {
|
||||
enum RawRepresentableModel: String, Encodable, SQLiteRawRepresentable {
|
||||
case test
|
||||
}
|
||||
|
||||
enum EncodableModel: String, Encodable {
|
||||
case test
|
||||
}
|
||||
|
||||
final class MockDateEncoder: DateEncoder {
|
||||
func encode(_ date: Date, to encoder: any ValueEncoder) throws {
|
||||
let formatter = ISO8601DateFormatter()
|
||||
let dateString = formatter.string(from: date)
|
||||
try encoder.encode(dateString)
|
||||
}
|
||||
|
||||
func encode(_ date: Date, for key: any CodingKey, to encoder: any RowEncoder) throws {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
final class MockSingleValueEncoder: ValueEncoder {
|
||||
private(set) var sqliteData: SQLiteRawValue?
|
||||
let dateEncoder: any DateEncoder
|
||||
let codingPath: [any CodingKey]
|
||||
let userInfo: [CodingUserInfoKey: Any]
|
||||
|
||||
init(
|
||||
sqliteData: SQLiteRawValue? = nil,
|
||||
dateEncoder: any DateEncoder = MockDateEncoder(),
|
||||
codingPath: [any CodingKey] = [],
|
||||
userInfo: [CodingUserInfoKey: Any] = [:]
|
||||
) {
|
||||
self.sqliteData = sqliteData
|
||||
self.dateEncoder = dateEncoder
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
}
|
||||
|
||||
func encodeNil() throws {
|
||||
sqliteData = .null
|
||||
}
|
||||
|
||||
func encodeDate(_ date: Date) throws {
|
||||
try dateEncoder.encode(date, to: self)
|
||||
}
|
||||
|
||||
func encode<T: SQLiteRawBindable>(_ value: T) throws {
|
||||
sqliteData = value.sqliteRawValue
|
||||
}
|
||||
|
||||
func container<Key: CodingKey>(
|
||||
keyedBy type: Key.Type
|
||||
) -> KeyedEncodingContainer<Key> {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func unkeyedContainer() -> any UnkeyedEncodingContainer {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func singleValueContainer() -> any SingleValueEncodingContainer {
|
||||
SingleValueContainer(encoder: self, codingPath: codingPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
108
Tests/DLCEncoderTests/SingleValueEncoderTests.swift
Normal file
108
Tests/DLCEncoderTests/SingleValueEncoderTests.swift
Normal file
@@ -0,0 +1,108 @@
|
||||
import XCTest
|
||||
import DataLiteCore
|
||||
import DLCCommon
|
||||
|
||||
@testable import DLCEncoder
|
||||
|
||||
final class SingleValueEncoderTests: XCTestCase {
|
||||
func testEncodeNil() throws {
|
||||
let encoder = SingleValueEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: [],
|
||||
userInfo: [:]
|
||||
)
|
||||
try encoder.encodeNil()
|
||||
XCTAssertEqual(encoder.sqliteData, .null)
|
||||
}
|
||||
|
||||
func testEncodeDate() throws {
|
||||
let date = Date()
|
||||
let dateEncoder = MockDateEncoder()
|
||||
let encoder = SingleValueEncoder(
|
||||
dateEncoder: dateEncoder,
|
||||
codingPath: [],
|
||||
userInfo: [:]
|
||||
)
|
||||
try encoder.encodeDate(date)
|
||||
XCTAssertEqual(encoder.sqliteData, date.sqliteRawValue)
|
||||
XCTAssertTrue(dateEncoder.didCallEncode)
|
||||
}
|
||||
|
||||
func testEncodeValue() throws {
|
||||
let encoder = SingleValueEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: [],
|
||||
userInfo: [:]
|
||||
)
|
||||
try encoder.encode("Test String")
|
||||
XCTAssertEqual(encoder.sqliteData, .text("Test String"))
|
||||
}
|
||||
|
||||
func testKeyedContainer() {
|
||||
let path = [
|
||||
RowCodingKey(intValue: 1),
|
||||
RowCodingKey(intValue: 2)
|
||||
]
|
||||
let encoder = SingleValueEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let container = encoder.container(
|
||||
keyedBy: RowCodingKey.self
|
||||
)
|
||||
XCTAssertEqual(container.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testUnkeyedContainer() {
|
||||
let path = [
|
||||
RowCodingKey(intValue: 1),
|
||||
RowCodingKey(intValue: 2)
|
||||
]
|
||||
let encoder = SingleValueEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let container = encoder.unkeyedContainer()
|
||||
XCTAssertTrue(container is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(container.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testSingleValueContainer() {
|
||||
let path = [
|
||||
RowCodingKey(intValue: 1),
|
||||
RowCodingKey(intValue: 2)
|
||||
]
|
||||
let encoder = SingleValueEncoder(
|
||||
dateEncoder: MockDateEncoder(),
|
||||
codingPath: path,
|
||||
userInfo: [:]
|
||||
)
|
||||
let container = encoder.singleValueContainer()
|
||||
XCTAssertTrue(container is SingleValueContainer<SingleValueEncoder>)
|
||||
XCTAssertEqual(container.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
}
|
||||
|
||||
private extension SingleValueEncoderTests {
|
||||
final class MockDateEncoder: DateEncoder {
|
||||
private(set) var didCallEncode = false
|
||||
|
||||
func encode(
|
||||
_ date: Date,
|
||||
to encoder: any ValueEncoder
|
||||
) throws {
|
||||
didCallEncode = true
|
||||
try encoder.encode(date)
|
||||
}
|
||||
|
||||
func encode(
|
||||
_ date: Date,
|
||||
for key: any CodingKey,
|
||||
to encoder: any RowEncoder
|
||||
) throws {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
296
Tests/DLCEncoderTests/UnkeyedContainerTests.swift
Normal file
296
Tests/DLCEncoderTests/UnkeyedContainerTests.swift
Normal file
@@ -0,0 +1,296 @@
|
||||
import XCTest
|
||||
import DataLiteCore
|
||||
import DLCCommon
|
||||
|
||||
@testable import DLCEncoder
|
||||
|
||||
final class UnkeyedContainerTests: XCTestCase {
|
||||
func testEncodeNil() throws {
|
||||
let encoder = MockMultiRowEncoder()
|
||||
let container = UnkeyedContainer<MockMultiRowEncoder>(
|
||||
encoder: encoder,
|
||||
codingPath: []
|
||||
)
|
||||
try container.encodeNil()
|
||||
XCTAssertTrue(encoder.sqliteData.isEmpty)
|
||||
}
|
||||
|
||||
func testEncodeModel() throws {
|
||||
let encoder = MockMultiRowEncoder()
|
||||
let container = UnkeyedContainer<MockMultiRowEncoder>(
|
||||
encoder: encoder,
|
||||
codingPath: []
|
||||
)
|
||||
|
||||
try container.encode(TestModel(id: 1, name: "John"))
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 1)
|
||||
XCTAssertEqual(encoder.sqliteData.first?.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData.first?["id"], .int(1))
|
||||
XCTAssertEqual(encoder.sqliteData.first?["name"], .text("John"))
|
||||
}
|
||||
|
||||
func testEncodeOptionalModel() throws {
|
||||
let encoder = MockMultiRowEncoder()
|
||||
let container = UnkeyedContainer<MockMultiRowEncoder>(
|
||||
encoder: encoder,
|
||||
codingPath: []
|
||||
)
|
||||
|
||||
try container.encode(TestModel(id: 1, name: "John") as TestModel?)
|
||||
|
||||
XCTAssertEqual(encoder.sqliteData.count, 1)
|
||||
XCTAssertEqual(encoder.sqliteData.first?.count, 2)
|
||||
XCTAssertEqual(encoder.sqliteData.first?["id"], .int(1))
|
||||
XCTAssertEqual(encoder.sqliteData.first?["name"], .text("John"))
|
||||
}
|
||||
|
||||
func testEncodeNilModel() throws {
|
||||
let encoder = MockMultiRowEncoder()
|
||||
let container = UnkeyedContainer<MockMultiRowEncoder>(
|
||||
encoder: encoder,
|
||||
codingPath: []
|
||||
)
|
||||
|
||||
try container.encode(nil as TestModel?)
|
||||
|
||||
XCTAssertTrue(encoder.sqliteData.isEmpty)
|
||||
}
|
||||
|
||||
func testNestedKeyedContainer() {
|
||||
let path = [RowCodingKey(intValue: 123)]
|
||||
let encoder = MockMultiRowEncoder()
|
||||
let container = UnkeyedContainer<MockMultiRowEncoder>(
|
||||
encoder: encoder,
|
||||
codingPath: path
|
||||
)
|
||||
let nestedContainer = container.nestedContainer(
|
||||
keyedBy: RowCodingKey.self
|
||||
)
|
||||
XCTAssertEqual(nestedContainer.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testNestedUnkeyedContainer() {
|
||||
let path = [RowCodingKey(intValue: 123)]
|
||||
let encoder = MockMultiRowEncoder()
|
||||
let container = UnkeyedContainer<MockMultiRowEncoder>(
|
||||
encoder: encoder,
|
||||
codingPath: path
|
||||
)
|
||||
let nestedContainer = container.nestedUnkeyedContainer()
|
||||
XCTAssertTrue(nestedContainer is FailedEncodingContainer<RowCodingKey>)
|
||||
XCTAssertEqual(nestedContainer.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
|
||||
func testSuperEncoder() {
|
||||
let path = [RowCodingKey(intValue: 123)]
|
||||
let encoder = MockMultiRowEncoder()
|
||||
let container = UnkeyedContainer<MockMultiRowEncoder>(
|
||||
encoder: encoder,
|
||||
codingPath: path
|
||||
)
|
||||
let superEncoder = container.superEncoder()
|
||||
XCTAssertTrue(superEncoder is FailedEncoder)
|
||||
XCTAssertEqual(superEncoder.codingPath as? [RowCodingKey], path)
|
||||
}
|
||||
}
|
||||
|
||||
private extension UnkeyedContainerTests {
|
||||
struct TestModel: Encodable {
|
||||
let id: Int
|
||||
let name: String
|
||||
}
|
||||
|
||||
final class MockDateEncoder: DateEncoder {
|
||||
func encode(_ date: Date, to encoder: any ValueEncoder) throws {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func encode(_ date: Date, for key: any CodingKey, to encoder: any RowEncoder) throws {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
final class MockMultiRowEncoder: RowEncoder {
|
||||
private(set) var sqliteData: [SQLiteRow]
|
||||
let dateEncoder: any DateEncoder
|
||||
let codingPath: [any CodingKey]
|
||||
let userInfo: [CodingUserInfoKey: Any]
|
||||
var count: Int { sqliteData.count }
|
||||
|
||||
init(
|
||||
sqliteData: [SQLiteRow] = [],
|
||||
dateEncoder: any DateEncoder = MockDateEncoder(),
|
||||
codingPath: [any CodingKey] = [],
|
||||
userInfo: [CodingUserInfoKey: Any] = [:]
|
||||
) {
|
||||
self.sqliteData = sqliteData
|
||||
self.dateEncoder = dateEncoder
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
}
|
||||
|
||||
func set(_ value: Any, for key: any CodingKey) throws {
|
||||
guard let value = value as? SQLiteRow else {
|
||||
fatalError()
|
||||
}
|
||||
sqliteData.append(value)
|
||||
}
|
||||
|
||||
func encodeNil(for key: any CodingKey) throws {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func encodeDate(_ date: Date, for key: any CodingKey) throws {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func encode<T: SQLiteRawBindable>(_ value: T, for key: any CodingKey) throws {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func encoder(for key: any CodingKey) throws -> any Encoder {
|
||||
MockSingleRowEncoder()
|
||||
}
|
||||
|
||||
func container<Key: CodingKey>(
|
||||
keyedBy type: Key.Type
|
||||
) -> KeyedEncodingContainer<Key> {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func unkeyedContainer() -> any UnkeyedEncodingContainer {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func singleValueContainer() -> any SingleValueEncodingContainer {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
final class MockSingleRowEncoder: RowEncoder {
|
||||
private(set) var sqliteData: SQLiteRow
|
||||
let dateEncoder: any DateEncoder
|
||||
let codingPath: [any CodingKey]
|
||||
let userInfo: [CodingUserInfoKey: Any]
|
||||
var count: Int { sqliteData.count }
|
||||
|
||||
init(
|
||||
sqliteData: SQLiteRow = SQLiteRow(),
|
||||
dateEncoder: any DateEncoder = MockDateEncoder(),
|
||||
codingPath: [any CodingKey] = [],
|
||||
userInfo: [CodingUserInfoKey: Any] = [:]
|
||||
) {
|
||||
self.sqliteData = sqliteData
|
||||
self.dateEncoder = dateEncoder
|
||||
self.codingPath = codingPath
|
||||
self.userInfo = userInfo
|
||||
}
|
||||
|
||||
func set(_ value: Any, for key: any CodingKey) throws {
|
||||
guard let value = value as? SQLiteRawValue else {
|
||||
fatalError()
|
||||
}
|
||||
sqliteData[key.stringValue] = value
|
||||
}
|
||||
|
||||
func encodeNil(for key: any CodingKey) throws {
|
||||
sqliteData[key.stringValue] = .null
|
||||
}
|
||||
|
||||
func encodeDate(_ date: Date, for key: any CodingKey) throws {
|
||||
try dateEncoder.encode(date, for: key, to: self)
|
||||
}
|
||||
|
||||
func encode<T: SQLiteRawBindable>(_ value: T, for key: any CodingKey) throws {
|
||||
sqliteData[key.stringValue] = value.sqliteRawValue
|
||||
}
|
||||
|
||||
func encoder(for key: any CodingKey) throws -> any Encoder {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func container<Key: CodingKey>(
|
||||
keyedBy type: Key.Type
|
||||
) -> KeyedEncodingContainer<Key> {
|
||||
let container = MockKeyedContainer<MockSingleRowEncoder, Key>(
|
||||
encoder: self, codingPath: []
|
||||
)
|
||||
return KeyedEncodingContainer(container)
|
||||
}
|
||||
|
||||
func unkeyedContainer() -> any UnkeyedEncodingContainer {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func singleValueContainer() -> any SingleValueEncodingContainer {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
|
||||
final class MockKeyedContainer<Encoder: RowEncoder, Key: CodingKey>: Container, KeyedEncodingContainerProtocol {
|
||||
// MARK: - Properties
|
||||
|
||||
let encoder: Encoder
|
||||
let codingPath: [any CodingKey]
|
||||
|
||||
// MARK: - Inits
|
||||
|
||||
init(
|
||||
encoder: Encoder,
|
||||
codingPath: [any CodingKey]
|
||||
) {
|
||||
self.encoder = encoder
|
||||
self.codingPath = codingPath
|
||||
}
|
||||
|
||||
// MARK: - Container Methods
|
||||
|
||||
func encodeNil(forKey key: Key) throws {
|
||||
try encoder.encodeNil(for: key)
|
||||
}
|
||||
|
||||
func encode<T: Encodable>(_ value: T, forKey key: Key) throws {
|
||||
switch value {
|
||||
case let value as Date:
|
||||
try encoder.encodeDate(value, for: key)
|
||||
case let value as SQLiteRawRepresentable:
|
||||
try encoder.encode(value, for: key)
|
||||
default:
|
||||
let valueEncoder = try encoder.encoder(for: key)
|
||||
try value.encode(to: valueEncoder)
|
||||
try encoder.set(valueEncoder.sqliteData, for: key)
|
||||
}
|
||||
}
|
||||
|
||||
func encodeIfPresent<T: Encodable>(_ value: T?, forKey key: Key) throws {
|
||||
switch value {
|
||||
case .some(let value):
|
||||
try encode(value, forKey: key)
|
||||
case .none:
|
||||
try encodeNil(forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
func nestedContainer<NestedKey: CodingKey>(
|
||||
keyedBy keyType: NestedKey.Type,
|
||||
forKey key: Key
|
||||
) -> KeyedEncodingContainer<NestedKey> {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func nestedUnkeyedContainer(
|
||||
forKey key: Key
|
||||
) -> any UnkeyedEncodingContainer {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func superEncoder() -> any Swift.Encoder {
|
||||
fatalError()
|
||||
}
|
||||
|
||||
func superEncoder(forKey key: Key) -> any Swift.Encoder {
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user