Add CI/CD configuration and API documentation
This commit is contained in:
+342
@@ -0,0 +1,342 @@
|
||||
import XCTest
|
||||
import Foundation
|
||||
import GRDB
|
||||
|
||||
class DatabaseValueConvertibleEncodableTests: GRDBTestCase {
|
||||
func testDatabaseValueConvertibleImplementationDerivedFromEncodable1() {
|
||||
struct Value : Encodable, DatabaseValueConvertible {
|
||||
let string: String
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(string)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
|
||||
// Inferred, tested
|
||||
// var databaseValue: DatabaseValue { ... }
|
||||
}
|
||||
|
||||
let dbValue = Value(string: "foo").databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, "foo")
|
||||
}
|
||||
|
||||
func testDatabaseValueConvertibleImplementationDerivedFromEncodable2() {
|
||||
struct Value : Encodable, DatabaseValueConvertible {
|
||||
let string: String
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(string)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
}
|
||||
|
||||
struct Wrapper : Encodable, DatabaseValueConvertible {
|
||||
let value: Value
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(value)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Wrapper? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
|
||||
// Inferred, tested
|
||||
// var databaseValue: DatabaseValue { ... }
|
||||
}
|
||||
|
||||
let dbValue = Wrapper(value: Value(string: "foo")).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, "foo")
|
||||
}
|
||||
|
||||
func testDatabaseValueConvertibleImplementationDerivedFromEncodable3() {
|
||||
struct Wrapper : Encodable, DatabaseValueConvertible {
|
||||
struct Nested : Encodable {
|
||||
let string: String
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(string)
|
||||
}
|
||||
}
|
||||
let nested: Nested
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(nested)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Wrapper? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
|
||||
// Inferred, tested
|
||||
// var databaseValue: DatabaseValue { ... }
|
||||
}
|
||||
|
||||
let dbValue = Wrapper(nested: Wrapper.Nested(string: "foo")).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, "foo")
|
||||
}
|
||||
|
||||
func testDatabaseValueConvertibleImplementationDerivedFromEncodable4() throws {
|
||||
struct Value: Encodable, DatabaseValueConvertible {
|
||||
let strings: [String]
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(strings: ["foo", "bar"]).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"{"strings":["foo","bar"]}"#)
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(strings: []).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"{"strings":[]}"#)
|
||||
}
|
||||
}
|
||||
|
||||
func testDatabaseValueConvertibleImplementationDerivedFromEncodable5() throws {
|
||||
struct Value: Encodable, DatabaseValueConvertible {
|
||||
let dictionary: [String: Int]
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
try dictionary.encode(to: encoder)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(dictionary: ["foo": 1]).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"{"foo":1}"#)
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(dictionary: [:]).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"{}"#)
|
||||
}
|
||||
}
|
||||
|
||||
func testDatabaseValueConvertibleImplementationDerivedFromEncodable6() throws {
|
||||
struct Value: Encodable, DatabaseValueConvertible {
|
||||
let strings: [String]
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
try strings.encode(to: encoder)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(strings: ["foo", "bar"]).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"["foo","bar"]"#)
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(strings: []).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"[]"#)
|
||||
}
|
||||
}
|
||||
|
||||
func testDatabaseValueConvertibleImplementationDerivedFromEncodable7() throws {
|
||||
struct Value: Encodable, DatabaseValueConvertible {
|
||||
let dictionary: [String: Int]
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(dictionary)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(dictionary: ["foo": 1]).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"{"foo":1}"#)
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(dictionary: [:]).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"{}"#)
|
||||
}
|
||||
}
|
||||
|
||||
func testDatabaseValueConvertibleImplementationDerivedFromEncodable8() throws {
|
||||
struct Value: Encodable, DatabaseValueConvertible {
|
||||
let strings: [String]
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(strings)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(strings: ["foo", "bar"]).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"["foo","bar"]"#)
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(strings: []).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"[]"#)
|
||||
}
|
||||
}
|
||||
|
||||
func testEncodableRawRepresentable() {
|
||||
// Test that the rawValue is encoded with DatabaseValueConvertible, not with Encodable
|
||||
struct Value : RawRepresentable, Encodable, DatabaseValueConvertible {
|
||||
let rawValue: Date
|
||||
}
|
||||
|
||||
let dbValue = Value(rawValue: Date()).databaseValue
|
||||
XCTAssertTrue(dbValue.storage.value is String)
|
||||
}
|
||||
|
||||
func testEncodableRawRepresentableEnum() {
|
||||
// Make sure this kind of declaration is possible
|
||||
enum Value : String, Encodable, DatabaseValueConvertible {
|
||||
case foo, bar
|
||||
}
|
||||
let dbValue = Value.foo.databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, "foo")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Foundation Codable Types
|
||||
|
||||
extension DatabaseValueConvertibleEncodableTests {
|
||||
func testDateProperty() {
|
||||
struct Value : Encodable, DatabaseValueConvertible {
|
||||
let date: Date
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(date)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
|
||||
// Inferred, tested
|
||||
// var databaseValue: DatabaseValue { ... }
|
||||
}
|
||||
|
||||
let value = Value(date: Date())
|
||||
let dbValue = value.databaseValue
|
||||
|
||||
// Date has a default Encodable implementation which encodes a Double.
|
||||
// We expect here a String, because DatabaseValueConvertible has
|
||||
// precedence over Encodable.
|
||||
XCTAssert(dbValue.storage.value is String)
|
||||
|
||||
let encodedDate = Date.fromDatabaseValue(dbValue)!
|
||||
XCTAssert(abs(encodedDate.timeIntervalSince(value.date)) < 0.001)
|
||||
}
|
||||
|
||||
func testURLProperty() {
|
||||
struct Value : Encodable, DatabaseValueConvertible {
|
||||
let url: URL
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(url)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
|
||||
// Inferred, tested
|
||||
// var databaseValue: DatabaseValue { ... }
|
||||
}
|
||||
|
||||
let value = Value(url: URL(string: "https://github.com")!)
|
||||
let dbValue = value.databaseValue
|
||||
XCTAssert(dbValue.storage.value is String)
|
||||
let encodedURL = URL.fromDatabaseValue(dbValue)!
|
||||
XCTAssertEqual(encodedURL, value.url)
|
||||
}
|
||||
|
||||
func testUUIDProperty() {
|
||||
struct Value : Encodable, DatabaseValueConvertible {
|
||||
let uuid: UUID
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.singleValueContainer()
|
||||
try container.encode(uuid)
|
||||
}
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
|
||||
// Inferred, tested
|
||||
// var databaseValue: DatabaseValue { ... }
|
||||
}
|
||||
|
||||
let value = Value(uuid: UUID())
|
||||
let dbValue = value.databaseValue
|
||||
XCTAssert(dbValue.storage.value is Data)
|
||||
let encodedUUID = UUID.fromDatabaseValue(dbValue)!
|
||||
XCTAssertEqual(encodedUUID, value.uuid)
|
||||
}
|
||||
|
||||
func testDatabaseValueConvertibleImplementationDerivedFromEncodableWithCustomJsonEncoder() throws {
|
||||
struct Value: Encodable, DatabaseValueConvertible {
|
||||
let duration: Double
|
||||
|
||||
static func fromDatabaseValue(_ databaseValue: DatabaseValue) -> Value? {
|
||||
preconditionFailure("not tested")
|
||||
}
|
||||
|
||||
public static func databaseJSONEncoder() -> JSONEncoder {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.dataEncodingStrategy = .base64
|
||||
encoder.dateEncodingStrategy = .millisecondsSince1970
|
||||
encoder.nonConformingFloatEncodingStrategy = .convertToString(
|
||||
positiveInfinity: "+InF",
|
||||
negativeInfinity: "-InF",
|
||||
nan: "NaN"
|
||||
)
|
||||
// guarantee some stability in order to ease value comparison
|
||||
encoder.outputFormatting = .sortedKeys
|
||||
return encoder
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let dbValue = Value(duration: .infinity).databaseValue
|
||||
XCTAssertEqual(dbValue.storage.value as! String, #"{"duration":"+InF"}"#)
|
||||
|
||||
let dbValue2 = Value(duration: -Double.infinity).databaseValue
|
||||
XCTAssertEqual(dbValue2.storage.value as! String, #"{"duration":"-InF"}"#)
|
||||
|
||||
let dbValue3 = Value(duration: .nan).databaseValue
|
||||
XCTAssertEqual(dbValue3.storage.value as! String, #"{"duration":"NaN"}"#)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user