Files
UUVPN/iOS-SwiftUI-Code/GRDB.swift-6.29.3/Tests/GRDBTests/DatabaseErrorTests.swift
T

234 lines
14 KiB
Swift

import XCTest
import GRDB
class DatabaseErrorTests: GRDBTestCase {
func testDatabaseErrorMessage() {
// We don't test for actual messages, since they may depend on SQLite version
XCTAssertEqual(DatabaseError().resultCode, .SQLITE_ERROR)
XCTAssertNotNil(DatabaseError().message)
XCTAssertNotNil(DatabaseError(resultCode: .SQLITE_BUSY).message)
XCTAssertNotEqual(DatabaseError().message, DatabaseError(resultCode: .SQLITE_BUSY).message)
}
func testDatabaseErrorInTransaction() throws {
let dbQueue = try makeDatabaseQueue()
do {
try dbQueue.inTransaction { db in
try db.execute(sql: "CREATE TABLE persons (id INTEGER PRIMARY KEY)")
try db.execute(sql: "CREATE TABLE pets (masterId INTEGER NOT NULL REFERENCES persons(id), name TEXT)")
sqlQueries.removeAll()
try db.execute(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)", arguments: [1, "Bobby"])
XCTFail()
return .commit
}
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
XCTAssertEqual(error.message!.lowercased(), "foreign key constraint failed") // lowercased: accept multiple SQLite version
XCTAssertEqual(error.sql!, "INSERT INTO pets (masterId, name) VALUES (?, ?)")
XCTAssertEqual(error.description.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)`")
XCTAssertEqual(error.expandedDescription.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
XCTAssertEqual(sqlQueries.count, 2)
XCTAssertEqual(sqlQueries[0], "INSERT INTO pets (masterId, name) VALUES (1, 'Bobby')")
XCTAssertEqual(sqlQueries[1], "ROLLBACK TRANSACTION")
}
}
func testDatabaseErrorInTopLevelSavepoint() throws {
let dbQueue = try makeDatabaseQueue()
do {
try dbQueue.writeWithoutTransaction { db in
do {
try db.inSavepoint {
XCTAssertTrue(db.isInsideTransaction)
try db.execute(sql: "CREATE TABLE persons (id INTEGER PRIMARY KEY)")
try db.execute(sql: "CREATE TABLE pets (masterId INTEGER NOT NULL REFERENCES persons(id), name TEXT)")
sqlQueries.removeAll()
try db.execute(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)", arguments: [1, "Bobby"])
XCTFail()
return .commit
}
XCTFail()
} catch {
XCTAssertFalse(db.isInsideTransaction)
throw error
}
}
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
XCTAssertEqual(error.message!.lowercased(), "foreign key constraint failed") // lowercased: accept multiple SQLite version
XCTAssertEqual(error.sql!, "INSERT INTO pets (masterId, name) VALUES (?, ?)")
XCTAssertEqual(error.description.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)`")
XCTAssertEqual(error.expandedDescription.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
}
}
func testDatabaseErrorThrownByUpdateStatementContainSQLAndNoPrivateArguments() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE persons (id INTEGER PRIMARY KEY)")
try db.execute(sql: "CREATE TABLE pets (masterId INTEGER NOT NULL REFERENCES persons(id), name TEXT)")
}
// db.execute(sql, arguments)
try dbQueue.inDatabase { db in
do {
try db.execute(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)", arguments: [1, "Bobby"])
XCTFail()
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
XCTAssertEqual(error.message!.lowercased(), "foreign key constraint failed") // lowercased: accept multiple SQLite version
XCTAssertEqual(error.sql!, "INSERT INTO pets (masterId, name) VALUES (?, ?)")
XCTAssertEqual(error.description.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)`")
XCTAssertEqual(error.expandedDescription.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
}
}
// statement.execute(arguments)
try dbQueue.inDatabase { db in
do {
let statement = try db.makeStatement(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)")
try statement.execute(arguments: [1, "Bobby"])
XCTFail()
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
XCTAssertEqual(error.message!.lowercased(), "foreign key constraint failed") // lowercased: accept multiple SQLite version
XCTAssertEqual(error.sql!, "INSERT INTO pets (masterId, name) VALUES (?, ?)")
XCTAssertEqual(error.description.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)`")
XCTAssertEqual(error.expandedDescription.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
}
}
// statement.execute()
try dbQueue.inDatabase { db in
do {
let statement = try db.makeStatement(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)")
statement.arguments = [1, "Bobby"]
try statement.execute()
XCTFail()
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
XCTAssertEqual(error.message!.lowercased(), "foreign key constraint failed") // lowercased: accept multiple SQLite version
XCTAssertEqual(error.sql!, "INSERT INTO pets (masterId, name) VALUES (?, ?)")
XCTAssertEqual(error.description.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)`")
XCTAssertEqual(error.expandedDescription.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
}
}
}
func testDatabaseErrorThrownByUpdateStatementContainSQLAndPublicArguments() throws {
// Opt in for public statement arguments
dbConfiguration.publicStatementArguments = true
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
try db.execute(sql: "CREATE TABLE persons (id INTEGER PRIMARY KEY)")
try db.execute(sql: "CREATE TABLE pets (masterId INTEGER NOT NULL REFERENCES persons(id), name TEXT)")
}
// db.execute(sql, arguments)
try dbQueue.inDatabase { db in
do {
try db.execute(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)", arguments: [1, "Bobby"])
XCTFail()
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
XCTAssertEqual(error.message!.lowercased(), "foreign key constraint failed") // lowercased: accept multiple SQLite version
XCTAssertEqual(error.sql!, "INSERT INTO pets (masterId, name) VALUES (?, ?)")
XCTAssertEqual(error.description.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
XCTAssertEqual(error.expandedDescription.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
}
}
// statement.execute(arguments)
try dbQueue.inDatabase { db in
do {
let statement = try db.makeStatement(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)")
try statement.execute(arguments: [1, "Bobby"])
XCTFail()
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
XCTAssertEqual(error.message!.lowercased(), "foreign key constraint failed") // lowercased: accept multiple SQLite version
XCTAssertEqual(error.sql!, "INSERT INTO pets (masterId, name) VALUES (?, ?)")
XCTAssertEqual(error.description.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
XCTAssertEqual(error.expandedDescription.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
}
}
// statement.execute()
try dbQueue.inDatabase { db in
do {
let statement = try db.makeStatement(sql: "INSERT INTO pets (masterId, name) VALUES (?, ?)")
statement.arguments = [1, "Bobby"]
try statement.execute()
XCTFail()
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
XCTAssertEqual(error.message!.lowercased(), "foreign key constraint failed") // lowercased: accept multiple SQLite version
XCTAssertEqual(error.sql!, "INSERT INTO pets (masterId, name) VALUES (?, ?)")
XCTAssertEqual(error.description.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
XCTAssertEqual(error.expandedDescription.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (?, ?)` with arguments [1, \"bobby\"]")
}
}
}
func testDatabaseErrorThrownByExecuteMultiStatementContainSQL() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
do {
try db.execute(sql: """
CREATE TABLE persons (id INTEGER PRIMARY KEY, name TEXT, age INT);
CREATE TABLE pets (masterId INTEGER NOT NULL REFERENCES persons(id), name TEXT);
INSERT INTO pets (masterId, name) VALUES (1, 'Bobby')
""")
XCTFail()
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode, .SQLITE_CONSTRAINT)
XCTAssertEqual(error.message!.lowercased(), "foreign key constraint failed") // lowercased: accept multiple SQLite version
XCTAssertEqual(error.sql!, "INSERT INTO pets (masterId, name) VALUES (1, 'Bobby')")
XCTAssertEqual(error.description.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (1, 'bobby')`")
XCTAssertEqual(error.expandedDescription.lowercased(), "sqlite error 19: foreign key constraint failed - while executing `insert into pets (masterid, name) values (1, 'bobby')`")
}
}
}
func testExtendedResultCodesAreActivated() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
try db.create(table: "parents") { $0.column("id", .integer).primaryKey() }
try db.create(table: "children") { $0.belongsTo("parent") }
do {
try db.execute(sql: "INSERT INTO children (parentId) VALUES (1)")
} catch let error as DatabaseError {
XCTAssert(error.extendedResultCode == .SQLITE_CONSTRAINT_FOREIGNKEY)
XCTAssertEqual(error.resultCode.rawValue, 19) // primary SQLITE_CONSTRAINT
}
}
}
func testNSErrorBridging() throws {
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
try db.create(table: "parents") { $0.column("id", .integer).primaryKey() }
try db.create(table: "children") { $0.belongsTo("parent") }
do {
try db.execute(sql: "INSERT INTO children (parentId) VALUES (1)")
} catch let error as NSError {
XCTAssertEqual(DatabaseError.errorDomain, "GRDB.DatabaseError")
XCTAssertEqual(error.domain, DatabaseError.errorDomain)
XCTAssertEqual(error.code, 787)
XCTAssertNotNil(error.localizedFailureReason)
}
}
}
}