Files
UUVPN/iOS-SwiftUI-Code/GRDB.swift-6.29.3/Tests/GRDBTests/DatabaseValueConvertibleDecodableTests.swift
T
2025-01-28 12:28:03 +08:00

383 lines
14 KiB
Swift

import XCTest
import GRDB
class DatabaseValueConvertibleDecodableTests: GRDBTestCase {
func testDatabaseValueConvertibleImplementationDerivedFromDecodable1() throws {
struct Value : Decodable, DatabaseValueConvertible {
let string: String
init(from decoder: Decoder) throws {
string = try decoder.singleValueContainer().decode(String.self)
}
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
// Inferred, tested
// static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? { ... }
}
do {
// Success from DatabaseValue
let value = Value.fromDatabaseValue("foo".databaseValue)!
XCTAssertEqual(value.string, "foo")
}
do {
// Success from database
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let value = try Value.fetchOne(db, sql: "SELECT 'foo'")!
XCTAssertEqual(value.string, "foo")
}
}
do {
// Failure from DatabaseValue
let value = Value.fromDatabaseValue(1.databaseValue)
XCTAssertNil(value)
}
}
func testDatabaseValueConvertibleImplementationDerivedFromDecodable2() throws {
struct Value : Decodable, DatabaseValueConvertible {
let string: String
init(from decoder: Decoder) throws {
string = try decoder.singleValueContainer().decode(String.self)
}
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
}
struct ValueWrapper : Decodable, DatabaseValueConvertible {
let value: Value
init(from decoder: Decoder) throws {
value = try decoder.singleValueContainer().decode(Value.self)
}
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
// Inferred, tested
// static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? { ... }
}
do {
// Success from DatabaseValue
let wrapper = ValueWrapper.fromDatabaseValue("foo".databaseValue)!
XCTAssertEqual(wrapper.value.string, "foo")
}
do {
// Success from database
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let wrapper = try ValueWrapper.fetchOne(db, sql: "SELECT 'foo'")!
XCTAssertEqual(wrapper.value.string, "foo")
}
}
do {
// Failure from DatabaseValue
let wrapper = ValueWrapper.fromDatabaseValue(1.databaseValue)
XCTAssertNil(wrapper)
}
}
func testDatabaseValueConvertibleImplementationDerivedFromDecodable3() throws {
struct ValueWrapper : Decodable, DatabaseValueConvertible {
struct Nested : Decodable {
let string: String
init(from decoder: Decoder) throws {
string = try decoder.singleValueContainer().decode(String.self)
}
}
let nested: Nested
init(from decoder: Decoder) throws {
nested = try decoder.singleValueContainer().decode(Nested.self)
}
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
// Inferred, tested
// static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? { ... }
}
do {
// Success from DatabaseValue
let wrapper = ValueWrapper.fromDatabaseValue("foo".databaseValue)!
XCTAssertEqual(wrapper.nested.string, "foo")
}
do {
// Success from database
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let wrapper = try ValueWrapper.fetchOne(db, sql: "SELECT 'foo'")!
XCTAssertEqual(wrapper.nested.string, "foo")
}
}
do {
// Failure from DatabaseValue
let wrapper = ValueWrapper.fromDatabaseValue(1.databaseValue)
XCTAssertNil(wrapper)
}
}
func testDatabaseValueConvertibleImplementationDerivedFromDecodable4() throws {
struct Value: Decodable, DatabaseValueConvertible {
let strings: [String]
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
}
do {
// Success from DatabaseValue
let value = Value.fromDatabaseValue(#"{ "strings": ["foo", "bar"] }"#.databaseValue)!
XCTAssertEqual(value.strings, ["foo", "bar"])
}
do {
// Success from database
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let value = try Value.fetchOne(db, sql: #"SELECT '{ "strings": ["foo", "bar"] }'"#)!
XCTAssertEqual(value.strings, ["foo", "bar"])
}
}
do {
// Failure from DatabaseValue
let value = Value.fromDatabaseValue(1.databaseValue)
XCTAssertNil(value)
}
}
func testDatabaseValueConvertibleImplementationDerivedFromDecodable5() throws {
struct Value: Decodable, DatabaseValueConvertible {
let dictionary: [String: Int]
init(from decoder: Decoder) throws {
dictionary = try .init(from: decoder)
}
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
}
do {
// Success from DatabaseValue
let value = Value.fromDatabaseValue(#"{"foo": 1}"#.databaseValue)!
XCTAssertEqual(value.dictionary, ["foo": 1])
}
do {
// Success from database
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let value = try Value.fetchOne(db, sql: #"SELECT '{"foo": 1}'"#)!
XCTAssertEqual(value.dictionary, ["foo": 1])
}
}
do {
// Failure from DatabaseValue
let value = Value.fromDatabaseValue(1.databaseValue)
XCTAssertNil(value)
}
}
func testDatabaseValueConvertibleImplementationDerivedFromDecodable6() throws {
struct Value: Decodable, DatabaseValueConvertible {
let strings: [String]
init(from decoder: Decoder) throws {
strings = try .init(from: decoder)
}
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
}
do {
// Success from DatabaseValue
let value = Value.fromDatabaseValue(#"["foo", "bar"]"#.databaseValue)!
XCTAssertEqual(value.strings, ["foo", "bar"])
}
do {
// Success from database
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let value = try Value.fetchOne(db, sql: #"SELECT '["foo", "bar"]'"#)!
XCTAssertEqual(value.strings, ["foo", "bar"])
}
}
do {
// Failure from DatabaseValue
let value = Value.fromDatabaseValue(1.databaseValue)
XCTAssertNil(value)
}
}
func testDatabaseValueConvertibleImplementationDerivedFromDecodable7() throws {
struct Value: Decodable, DatabaseValueConvertible {
let dictionary: [String: Int]
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
dictionary = try container.decode([String: Int].self)
}
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
}
do {
// Success from DatabaseValue
let value = Value.fromDatabaseValue(#"{"foo": 1}"#.databaseValue)!
XCTAssertEqual(value.dictionary, ["foo": 1])
}
do {
// Success from database
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let value = try Value.fetchOne(db, sql: #"SELECT '{"foo": 1}'"#)!
XCTAssertEqual(value.dictionary, ["foo": 1])
}
}
do {
// Failure from DatabaseValue
let value = Value.fromDatabaseValue(1.databaseValue)
XCTAssertNil(value)
}
}
func testDatabaseValueConvertibleImplementationDerivedFromDecodable8() throws {
struct Value: Decodable, DatabaseValueConvertible {
let strings: [String]
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
strings = try container.decode([String].self)
}
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
}
do {
// Success from DatabaseValue
let value = Value.fromDatabaseValue(#"["foo", "bar"]"#.databaseValue)!
XCTAssertEqual(value.strings, ["foo", "bar"])
}
do {
// Success from database
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let value = try Value.fetchOne(db, sql: #"SELECT '["foo", "bar"]'"#)!
XCTAssertEqual(value.strings, ["foo", "bar"])
}
}
do {
// Failure from DatabaseValue
let value = Value.fromDatabaseValue(1.databaseValue)
XCTAssertNil(value)
}
}
func testCustomDatabaseValueConvertible() throws {
struct Value : Decodable, DatabaseValueConvertible {
let string: String
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
if let string = String.fromDatabaseValue(databaseValue) {
return Value(string: string + " (DatabaseValueConvertible)")
} else {
return nil
}
}
}
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let value = try Value.fetchOne(db, sql: "SELECT 'foo'")!
XCTAssertEqual(value.string, "foo (DatabaseValueConvertible)")
}
}
func testDecodableRawRepresentableFetchingMethod() throws {
enum Value : String, Decodable, DatabaseValueConvertible {
case foo, bar
}
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let value = try Value.fetchOne(db, sql: "SELECT 'foo'")!
XCTAssertEqual(value, .foo)
}
}
func testDatabaseValueConvertibleImplementationDerivedFromDecodableWithCustomJsonDecoder() throws {
struct Value: Decodable, DatabaseValueConvertible {
let duration: Double
var databaseValue: DatabaseValue {
preconditionFailure("not tested")
}
public static func databaseJSONDecoder() -> JSONDecoder {
let decoder = JSONDecoder()
decoder.dataDecodingStrategy = .base64
decoder.dateDecodingStrategy = .millisecondsSince1970
decoder.nonConformingFloatDecodingStrategy = .convertFromString(
positiveInfinity: "+InF",
negativeInfinity: "-InF",
nan: "NaN"
)
return decoder
}
}
do {
// Success from DatabaseValue
let value = Value.fromDatabaseValue(#"{ "duration": "+InF" }"#.databaseValue)!
XCTAssertEqual(value.duration, Double.infinity)
let value2 = Value.fromDatabaseValue(#"{ "duration": "-InF" }"#.databaseValue)!
XCTAssertEqual(value2.duration, -Double.infinity)
let value3 = Value.fromDatabaseValue(#"{ "duration": "NaN" }"#.databaseValue)!
XCTAssertTrue(value3.duration.isNaN)
}
do {
// Success from database
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
let value = try Value.fetchOne(db, sql: #"SELECT '{ "duration": "+InF" }'"#)!
XCTAssertEqual(value.duration, Double.infinity)
let value2 = try Value.fetchOne(db, sql: #"SELECT '{ "duration": "-InF" }'"#)!
XCTAssertEqual(value2.duration, -Double.infinity)
let value3 = try Value.fetchOne(db, sql: #"SELECT '{ "duration": "NaN" }'"#)!
XCTAssertTrue(value3.duration.isNaN)
}
}
do {
// Failure from DatabaseValue
let value = Value.fromDatabaseValue("infinity".databaseValue)
XCTAssertNil(value)
}
}
}