add iOS
This commit is contained in:
+382
@@ -0,0 +1,382 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user