<commit_before>import XCTest
#if USING_SQLCIPHER
    import GRDBCipher
#elseif USING_CUSTOMSQLITE
    import GRDBCustomSQLite
#else
    import GRDB
#endif

class DatabaseCursorTests: GRDBTestCase {
    
    func testNextReturnsNilAfterExhaustion() {
        assertNoError {
            let dbQueue = try makeDatabaseQueue()
            try dbQueue.inDatabase { db in
                do {
                    let cursor = try Int.fetchCursor(db, "SELECT 1 WHERE 0")
                    XCTAssert(try cursor.next() == nil) // end
                    XCTAssert(try cursor.next() == nil) // past the end
                }
                do {
                    let cursor = try Int.fetchCursor(db, "SELECT 1")
                    XCTAssertEqual(try cursor.next()!,  1)
                    XCTAssert(try cursor.next() == nil) // end
                    XCTAssert(try cursor.next() == nil) // past the end
                }
                do {
                    let cursor = try Int.fetchCursor(db, "SELECT 1 UNION ALL SELECT 2")
                    XCTAssertEqual(try cursor.next()!, 1)
                    XCTAssertEqual(try cursor.next()!, 2)
                    XCTAssert(try cursor.next() == nil) // end
                    XCTAssert(try cursor.next() == nil) // past the end
                }
            }
        }
    }
    
    func testStepError() {
        assertNoError {
            let dbQueue = try makeDatabaseQueue()
            let customError = NSError(domain: "Custom", code: 0xDEAD)
            dbQueue.add(function: DatabaseFunction("throw", argumentCount: 0, pure: true) { _ in throw customError })
            try dbQueue.inDatabase { db in
                let cursor = try Int.fetchCursor(db, "SELECT 1 UNION ALL SELECT throw()")
                XCTAssertEqual(try cursor.next()!, 1)
                do {
                    _ = try cursor.next()
                    XCTFail()
                } catch let error as DatabaseError {
                    XCTAssertEqual(error.resultCode, .SQLITE_ERROR)
                    XCTAssertEqual(error.message, "\(customError)")
                    XCTAssertEqual(error.sql!, "SELECT 1 UNION ALL SELECT throw()")
                    XCTAssertEqual(error.description, "SQLite error 1 with statement `SELECT 1 UNION ALL SELECT throw()`: \(customError)")
                }
            }
        }
    }
}<commit_msg>DatabaseCursor: test preservation of custom error codes<commit_after>import XCTest
#if USING_SQLCIPHER
    import GRDBCipher
#elseif USING_CUSTOMSQLITE
    import GRDBCustomSQLite
#else
    import GRDB
#endif

class DatabaseCursorTests: GRDBTestCase {
    
    func testNextReturnsNilAfterExhaustion() {
        assertNoError {
            let dbQueue = try makeDatabaseQueue()
            try dbQueue.inDatabase { db in
                do {
                    let cursor = try Int.fetchCursor(db, "SELECT 1 WHERE 0")
                    XCTAssert(try cursor.next() == nil) // end
                    XCTAssert(try cursor.next() == nil) // past the end
                }
                do {
                    let cursor = try Int.fetchCursor(db, "SELECT 1")
                    XCTAssertEqual(try cursor.next()!,  1)
                    XCTAssert(try cursor.next() == nil) // end
                    XCTAssert(try cursor.next() == nil) // past the end
                }
                do {
                    let cursor = try Int.fetchCursor(db, "SELECT 1 UNION ALL SELECT 2")
                    XCTAssertEqual(try cursor.next()!, 1)
                    XCTAssertEqual(try cursor.next()!, 2)
                    XCTAssert(try cursor.next() == nil) // end
                    XCTAssert(try cursor.next() == nil) // past the end
                }
            }
        }
    }
    
    func testStepError() {
        assertNoError {
            let dbQueue = try makeDatabaseQueue()
            let customError = NSError(domain: "Custom", code: 0xDEAD)
            dbQueue.add(function: DatabaseFunction("throw", argumentCount: 0, pure: true) { _ in throw customError })
            try dbQueue.inDatabase { db in
                let cursor = try Int.fetchCursor(db, "SELECT throw()")
                do {
                    _ = try cursor.next()
                    XCTFail()
                } catch let error as DatabaseError {
                    XCTAssertEqual(error.resultCode, .SQLITE_ERROR)
                    XCTAssertEqual(error.message, "\(customError)")
                    XCTAssertEqual(error.sql!, "SELECT throw()")
                    XCTAssertEqual(error.description, "SQLite error 1 with statement `SELECT throw()`: \(customError)")
                }
            }
        }
    }
    
    func testStepDatabaseError() {
        assertNoError {
            let dbQueue = try makeDatabaseQueue()
            let customError = DatabaseError(resultCode: ResultCode(rawValue: 0xDEAD), message: "custom error")
            dbQueue.add(function: DatabaseFunction("throw", argumentCount: 0, pure: true) { _ in throw customError })
            try dbQueue.inDatabase { db in
                let cursor = try Int.fetchCursor(db, "SELECT throw()")
                do {
                    _ = try cursor.next()
                    XCTFail()
                } catch let error as DatabaseError {
                    XCTAssertEqual(error.extendedResultCode.rawValue, 0xDEAD)
                    XCTAssertEqual(error.message, "custom error")
                    XCTAssertEqual(error.sql!, "SELECT throw()")
                    XCTAssertEqual(error.description, "SQLite error 57005 with statement `SELECT throw()`: custom error")
                }
            }
        }
    }
}
{'fraction_non_alphanumeric': 0.09235387603743599, 'fraction_numerical': 0.006003884866678439, 'mean_word_length': 1.5240641711229947, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '371106', 'n_tokens_mistral': 1555, 'n_tokens_neox': 1435, 'n_words': 384}