234 lines
14 KiB
Swift
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)
|
|
}
|
|
}
|
|
}
|
|
}
|