DataLiteCore swift package
This commit is contained in:
28
Tests/DataLiteCoreTests/Classes/Connection+ErrorTests.swift
Normal file
28
Tests/DataLiteCoreTests/Classes/Connection+ErrorTests.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
import DataLiteC
|
||||
@testable import DataLiteCore
|
||||
|
||||
struct ConnectionErrorTests {
|
||||
@Test func testInitWithConnection() {
|
||||
var db: OpaquePointer? = nil
|
||||
defer { sqlite3_close(db) }
|
||||
sqlite3_open(":memory:", &db)
|
||||
sqlite3_exec(db, "INVALID SQL", nil, nil, nil)
|
||||
|
||||
let error = Connection.Error(db!)
|
||||
#expect(error.code == SQLITE_ERROR)
|
||||
#expect(error.message == "near \"INVALID\": syntax error")
|
||||
}
|
||||
|
||||
@Test func testInitWithCodeAndMessage() {
|
||||
let error = Connection.Error(code: 1, message: "Test Error Message")
|
||||
#expect(error.code == 1)
|
||||
#expect(error.message == "Test Error Message")
|
||||
}
|
||||
|
||||
@Test func testDescription() {
|
||||
let error = Connection.Error(code: 1, message: "Test Error Message")
|
||||
#expect(error.description == "Connection.Error code: 1 message: Test Error Message")
|
||||
}
|
||||
}
|
||||
25
Tests/DataLiteCoreTests/Classes/Connection+KeyTests.swift
Normal file
25
Tests/DataLiteCoreTests/Classes/Connection+KeyTests.swift
Normal file
@@ -0,0 +1,25 @@
|
||||
import Testing
|
||||
import Foundation
|
||||
import DataLiteCore
|
||||
|
||||
struct ConnectionKeyTests {
|
||||
@Test func testPassphrase() {
|
||||
let key = Connection.Key.passphrase("secret123")
|
||||
#expect(key.keyValue == "secret123")
|
||||
#expect(key.length == 9)
|
||||
}
|
||||
|
||||
@Test func testRawKey() {
|
||||
let keyData = Data([0x01, 0xAB, 0xCD, 0xEF])
|
||||
let key = Connection.Key.rawKey(keyData)
|
||||
#expect(key.keyValue == "X'01ABCDEF'")
|
||||
#expect(key.length == 11)
|
||||
}
|
||||
|
||||
@Test func testRawKeyLengthConsistency() {
|
||||
let rawBytes = Data(repeating: 0x00, count: 32)
|
||||
let key = Connection.Key.rawKey(rawBytes)
|
||||
let hexPart = key.keyValue.dropFirst(2).dropLast()
|
||||
#expect(hexPart.count == 64)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import Testing
|
||||
@testable import DataLiteCore
|
||||
|
||||
struct ConnectionLocationTests {
|
||||
@Test func testFileLocationPath() {
|
||||
let filePath = "/path/to/database.db"
|
||||
let location = Connection.Location.file(path: filePath)
|
||||
#expect(location.path == filePath)
|
||||
}
|
||||
|
||||
@Test func testInMemoryLocationPath() {
|
||||
let inMemoryLocation = Connection.Location.inMemory
|
||||
#expect(inMemoryLocation.path == ":memory:")
|
||||
}
|
||||
|
||||
@Test func testTemporaryLocationPath() {
|
||||
let temporaryLocation = Connection.Location.temporary
|
||||
#expect(temporaryLocation.path == "")
|
||||
}
|
||||
|
||||
@Test func testFileLocationInitialization() {
|
||||
let filePath = "/path/to/database.db"
|
||||
let location = Connection.Location.file(path: filePath)
|
||||
switch location {
|
||||
case .file(let path):
|
||||
#expect(path == filePath)
|
||||
default:
|
||||
Issue.record("Expected `.file` case but got \(location)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import Testing
|
||||
import DataLiteC
|
||||
import DataLiteCore
|
||||
|
||||
struct ConnectionOptionsTests {
|
||||
@Test func testReadOnlyOption() {
|
||||
let options: Connection.Options = [.readonly]
|
||||
#expect(options.contains(.readonly))
|
||||
}
|
||||
|
||||
@Test func testReadWriteOption() {
|
||||
let options: Connection.Options = [.readwrite]
|
||||
#expect(options.contains(.readwrite))
|
||||
}
|
||||
|
||||
@Test func testCreateOption() {
|
||||
let options: Connection.Options = [.create]
|
||||
#expect(options.contains(.create))
|
||||
}
|
||||
|
||||
@Test func testMultipleOptions() {
|
||||
let options: Connection.Options = [.readwrite, .create, .memory]
|
||||
#expect(options.contains(.readwrite))
|
||||
#expect(options.contains(.create))
|
||||
#expect(options.contains(.memory))
|
||||
}
|
||||
|
||||
@Test func testNoFollowOption() {
|
||||
let options: Connection.Options = [.nofollow]
|
||||
#expect(options.contains(.nofollow))
|
||||
}
|
||||
|
||||
@Test func testAllOptions() {
|
||||
let options: Connection.Options = [
|
||||
.readonly, .readwrite, .create, .uri, .memory,
|
||||
.nomutex, .fullmutex, .sharedcache,
|
||||
.privatecache, .exrescode, .nofollow
|
||||
]
|
||||
|
||||
#expect(options.contains(.readonly))
|
||||
#expect(options.contains(.readwrite))
|
||||
#expect(options.contains(.create))
|
||||
#expect(options.contains(.uri))
|
||||
#expect(options.contains(.memory))
|
||||
#expect(options.contains(.nomutex))
|
||||
#expect(options.contains(.fullmutex))
|
||||
#expect(options.contains(.sharedcache))
|
||||
#expect(options.contains(.privatecache))
|
||||
#expect(options.contains(.exrescode))
|
||||
#expect(options.contains(.nofollow))
|
||||
}
|
||||
|
||||
@Test func testOptionsRawValue() {
|
||||
let options: Connection.Options = [.readwrite, .create]
|
||||
let expectedRawValue = Int32(SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE)
|
||||
#expect(options.rawValue == expectedRawValue)
|
||||
|
||||
#expect(Connection.Options.readonly.rawValue == SQLITE_OPEN_READONLY)
|
||||
#expect(Connection.Options.readwrite.rawValue == SQLITE_OPEN_READWRITE)
|
||||
#expect(Connection.Options.create.rawValue == SQLITE_OPEN_CREATE)
|
||||
#expect(Connection.Options.memory.rawValue == SQLITE_OPEN_MEMORY)
|
||||
#expect(Connection.Options.nomutex.rawValue == SQLITE_OPEN_NOMUTEX)
|
||||
#expect(Connection.Options.fullmutex.rawValue == SQLITE_OPEN_FULLMUTEX)
|
||||
#expect(Connection.Options.sharedcache.rawValue == SQLITE_OPEN_SHAREDCACHE)
|
||||
#expect(Connection.Options.privatecache.rawValue == SQLITE_OPEN_PRIVATECACHE)
|
||||
#expect(Connection.Options.exrescode.rawValue == SQLITE_OPEN_EXRESCODE)
|
||||
#expect(Connection.Options.nofollow.rawValue == SQLITE_OPEN_NOFOLLOW)
|
||||
}
|
||||
}
|
||||
277
Tests/DataLiteCoreTests/Classes/ConnectionTests.swift
Normal file
277
Tests/DataLiteCoreTests/Classes/ConnectionTests.swift
Normal file
@@ -0,0 +1,277 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
import DataLiteC
|
||||
import DataLiteCore
|
||||
|
||||
struct ConnectionTests {
|
||||
@Test func testIsAutocommitInitially() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
#expect(connection.isAutocommit == true)
|
||||
}
|
||||
|
||||
@Test func testIsAutocommitDuringTransaction() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
try connection.beginTransaction()
|
||||
#expect(connection.isAutocommit == false)
|
||||
}
|
||||
|
||||
@Test func testIsAutocommitAfterCommit() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
try connection.beginTransaction()
|
||||
try connection.commitTransaction()
|
||||
#expect(connection.isAutocommit == true)
|
||||
}
|
||||
|
||||
@Test func testIsAutocommitAfterRollback() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
try connection.beginTransaction()
|
||||
try connection.rollbackTransaction()
|
||||
#expect(connection.isAutocommit == true)
|
||||
}
|
||||
|
||||
@Test(arguments: [
|
||||
(Connection.Options.readwrite, false),
|
||||
(Connection.Options.readonly, true)
|
||||
])
|
||||
func testIsReadonly(
|
||||
_ opt: Connection.Options,
|
||||
_ isReadonly: Bool
|
||||
) throws {
|
||||
let url = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent(UUID().uuidString)
|
||||
.appendingPathExtension("sqlite")
|
||||
defer { try? FileManager.default.removeItem(at: url) }
|
||||
let _ = try Connection(
|
||||
location: .file(path: url.path),
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
let connection = try Connection(
|
||||
location: .file(path: url.path),
|
||||
options: [opt]
|
||||
)
|
||||
#expect(connection.isReadonly == isReadonly)
|
||||
}
|
||||
|
||||
@Test func testBusyTimeout() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
connection.busyTimeout = 5000
|
||||
#expect(try connection.get(pragma: .busyTimeout) == 5000)
|
||||
|
||||
try connection.set(pragma: .busyTimeout, value: 1000)
|
||||
#expect(connection.busyTimeout == 1000)
|
||||
}
|
||||
|
||||
@Test func testBusyTimeoutSQLiteBusy() throws {
|
||||
let url = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent(UUID().uuidString)
|
||||
.appendingPathExtension("sqlite")
|
||||
defer { try? FileManager.default.removeItem(at: url) }
|
||||
|
||||
let oneConn = try Connection(
|
||||
location: .file(path: url.path),
|
||||
options: [.create, .readwrite, .fullmutex]
|
||||
)
|
||||
let twoConn = try Connection(
|
||||
location: .file(path: url.path),
|
||||
options: [.create, .readwrite, .fullmutex]
|
||||
)
|
||||
|
||||
try oneConn.execute(raw: """
|
||||
CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT);
|
||||
""")
|
||||
|
||||
try oneConn.beginTransaction()
|
||||
try oneConn.execute(raw: """
|
||||
INSERT INTO test (value) VALUES ('first');
|
||||
""")
|
||||
|
||||
#expect(
|
||||
throws: Connection.Error(
|
||||
code: SQLITE_BUSY,
|
||||
message: "database is locked"
|
||||
),
|
||||
performing: {
|
||||
twoConn.busyTimeout = 0
|
||||
try twoConn.execute(raw: """
|
||||
INSERT INTO test (value) VALUES ('second');
|
||||
""")
|
||||
}
|
||||
)
|
||||
|
||||
try oneConn.rollbackTransaction()
|
||||
}
|
||||
|
||||
@Test func testApplicationID() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
|
||||
#expect(connection.applicationID == 0)
|
||||
|
||||
connection.applicationID = 1024
|
||||
#expect(try connection.get(pragma: .applicationID) == 1024)
|
||||
|
||||
try connection.set(pragma: .applicationID, value: 123)
|
||||
#expect(connection.applicationID == 123)
|
||||
}
|
||||
|
||||
@Test func testForeignKeys() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
|
||||
#expect(connection.foreignKeys == false)
|
||||
|
||||
connection.foreignKeys = true
|
||||
#expect(try connection.get(pragma: .foreignKeys) == true)
|
||||
|
||||
try connection.set(pragma: .foreignKeys, value: false)
|
||||
#expect(connection.foreignKeys == false)
|
||||
}
|
||||
|
||||
@Test func testJournalMode() throws {
|
||||
let url = FileManager.default.temporaryDirectory
|
||||
.appendingPathComponent(UUID().uuidString)
|
||||
.appendingPathExtension("sqlite")
|
||||
defer { try? FileManager.default.removeItem(at: url) }
|
||||
|
||||
let connection = try Connection(
|
||||
location: .file(path: url.path),
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
|
||||
connection.journalMode = .delete
|
||||
#expect(try connection.get(pragma: .journalMode) == JournalMode.delete)
|
||||
|
||||
try connection.set(pragma: .journalMode, value: JournalMode.wal)
|
||||
#expect(connection.journalMode == .wal)
|
||||
}
|
||||
|
||||
@Test func testSynchronous() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
|
||||
connection.synchronous = .normal
|
||||
#expect(try connection.get(pragma: .synchronous) == Synchronous.normal)
|
||||
|
||||
try connection.set(pragma: .synchronous, value: Synchronous.full)
|
||||
#expect(connection.synchronous == .full)
|
||||
}
|
||||
|
||||
@Test func testUserVersion() throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
|
||||
connection.userVersion = 42
|
||||
#expect(try connection.get(pragma: .userVersion) == 42)
|
||||
|
||||
try connection.set(pragma: .userVersion, value: 13)
|
||||
#expect(connection.userVersion == 13)
|
||||
}
|
||||
|
||||
@Test(arguments: [
|
||||
(TestScalarFunc.self, TestScalarFunc.name),
|
||||
(TestAggregateFunc.self, TestAggregateFunc.name)
|
||||
] as [(Function.Type, String)])
|
||||
func testAddFunction(
|
||||
_ function: Function.Type,
|
||||
_ name: String
|
||||
) throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
try connection.execute(sql: """
|
||||
CREATE TABLE items (value INTEGER);
|
||||
INSERT INTO items (value) VALUES (1), (2), (NULL), (3);
|
||||
""")
|
||||
try connection.add(function: function)
|
||||
try connection.execute(raw: "SELECT \(name)(value) FROM items")
|
||||
}
|
||||
|
||||
@Test(arguments: [
|
||||
(TestScalarFunc.self, TestScalarFunc.name),
|
||||
(TestAggregateFunc.self, TestAggregateFunc.name)
|
||||
] as [(Function.Type, String)])
|
||||
func testRemoveFunction(
|
||||
_ function: Function.Type,
|
||||
_ name: String
|
||||
) throws {
|
||||
let connection = try Connection(
|
||||
location: .inMemory,
|
||||
options: [.create, .readwrite]
|
||||
)
|
||||
try connection.execute(sql: """
|
||||
CREATE TABLE items (value INTEGER);
|
||||
INSERT INTO items (value) VALUES (1), (2), (NULL), (3);
|
||||
""")
|
||||
try connection.add(function: function)
|
||||
try connection.remove(function: function)
|
||||
#expect(
|
||||
throws: Connection.Error(
|
||||
code: SQLITE_ERROR,
|
||||
message: "no such function: \(name)"
|
||||
),
|
||||
performing: {
|
||||
try connection.execute(raw: """
|
||||
SELECT \(name)(value) FROM items
|
||||
""")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private extension ConnectionTests {
|
||||
final class TestScalarFunc: Function.Scalar {
|
||||
override class var argc: Int32 { 1 }
|
||||
override class var name: String { "TO_STR" }
|
||||
override class var options: Options {
|
||||
[.deterministic, .innocuous]
|
||||
}
|
||||
|
||||
override class func invoke(args: Arguments) throws -> SQLiteRawRepresentable? {
|
||||
args[0].description
|
||||
}
|
||||
}
|
||||
|
||||
final class TestAggregateFunc: Function.Aggregate {
|
||||
override class var argc: Int32 { 1 }
|
||||
override class var name: String { "MY_COUNT" }
|
||||
override class var options: Options {
|
||||
[.deterministic, .innocuous]
|
||||
}
|
||||
|
||||
private var count: Int = 0
|
||||
|
||||
override func step(args: Arguments) throws {
|
||||
if args[0] != .null {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
|
||||
override func finalize() throws -> SQLiteRawRepresentable? {
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
58
Tests/DataLiteCoreTests/Classes/Function+OptionsTests.swift
Normal file
58
Tests/DataLiteCoreTests/Classes/Function+OptionsTests.swift
Normal file
@@ -0,0 +1,58 @@
|
||||
import Testing
|
||||
import DataLiteC
|
||||
import DataLiteCore
|
||||
|
||||
struct FunctionOptionsTests {
|
||||
@Test func testSingleOption() {
|
||||
#expect(Function.Options.deterministic.rawValue == SQLITE_DETERMINISTIC)
|
||||
#expect(Function.Options.directonly.rawValue == SQLITE_DIRECTONLY)
|
||||
#expect(Function.Options.innocuous.rawValue == SQLITE_INNOCUOUS)
|
||||
}
|
||||
|
||||
@Test func testMultipleOptions() {
|
||||
let options: Function.Options = [.deterministic, .directonly]
|
||||
#expect(options.contains(.deterministic))
|
||||
#expect(options.contains(.directonly))
|
||||
#expect(options.contains(.innocuous) == false)
|
||||
}
|
||||
|
||||
@Test func testEqualityAndHashability() {
|
||||
let options1: Function.Options = [.deterministic, .innocuous]
|
||||
let options2: Function.Options = [.deterministic, .innocuous]
|
||||
#expect(options1 == options2)
|
||||
|
||||
let hash1 = options1.hashValue
|
||||
let hash2 = options2.hashValue
|
||||
#expect(hash1 == hash2)
|
||||
}
|
||||
|
||||
@Test func testEmptyOptions() {
|
||||
let options = Function.Options(rawValue: 0)
|
||||
#expect(options.contains(.deterministic) == false)
|
||||
#expect(options.contains(.directonly) == false)
|
||||
#expect(options.contains(.innocuous) == false)
|
||||
}
|
||||
|
||||
@Test func testRawValueInitialization() {
|
||||
let rawValue: Int32 = SQLITE_DETERMINISTIC | SQLITE_INNOCUOUS
|
||||
let options = Function.Options(rawValue: rawValue)
|
||||
|
||||
#expect(options.contains(.deterministic))
|
||||
#expect(options.contains(.innocuous))
|
||||
#expect(options.contains(.directonly) == false)
|
||||
}
|
||||
|
||||
@Test func testAddingAndRemovingOptions() {
|
||||
var options: Function.Options = []
|
||||
|
||||
options.insert(.deterministic)
|
||||
#expect(options.contains(.deterministic))
|
||||
|
||||
options.insert(.directonly)
|
||||
#expect(options.contains(.directonly))
|
||||
|
||||
options.remove(.deterministic)
|
||||
#expect(options.contains(.deterministic) == false)
|
||||
}
|
||||
}
|
||||
|
||||
45
Tests/DataLiteCoreTests/Classes/Statement+OptionsTests.swift
Normal file
45
Tests/DataLiteCoreTests/Classes/Statement+OptionsTests.swift
Normal file
@@ -0,0 +1,45 @@
|
||||
import Testing
|
||||
import DataLiteCore
|
||||
import DataLiteC
|
||||
|
||||
struct StatementOptionsTests {
|
||||
@Test func testOptionsInitialization() {
|
||||
let options: Statement.Options = [.persistent]
|
||||
|
||||
#expect(options.contains(.persistent))
|
||||
#expect(options.contains(.noVtab) == false)
|
||||
}
|
||||
|
||||
@Test func testOptionsCombination() {
|
||||
var options: Statement.Options = [.persistent]
|
||||
|
||||
#expect(options.contains(.persistent))
|
||||
#expect(options.contains(.noVtab) == false)
|
||||
|
||||
options.insert(.noVtab)
|
||||
|
||||
#expect(options.contains(.persistent))
|
||||
#expect(options.contains(.noVtab))
|
||||
}
|
||||
|
||||
@Test func testOptionsRemoval() {
|
||||
var options: Statement.Options = [.persistent, .noVtab]
|
||||
|
||||
#expect(options.contains(.persistent))
|
||||
#expect(options.contains(.noVtab))
|
||||
|
||||
options.remove(.noVtab)
|
||||
|
||||
#expect(options.contains(.persistent))
|
||||
#expect(options.contains(.noVtab) == false)
|
||||
}
|
||||
|
||||
@Test func testOptionsRawValue() {
|
||||
let options: Statement.Options = [.persistent, .noVtab]
|
||||
let rawOpts = UInt32(SQLITE_PREPARE_PERSISTENT | SQLITE_PREPARE_NO_VTAB)
|
||||
|
||||
#expect(options.rawValue == rawOpts)
|
||||
#expect(Statement.Options.persistent.rawValue == UInt32(SQLITE_PREPARE_PERSISTENT))
|
||||
#expect(Statement.Options.noVtab.rawValue == UInt32(SQLITE_PREPARE_NO_VTAB))
|
||||
}
|
||||
}
|
||||
135
Tests/DataLiteCoreTests/Classes/StatementTests.swift
Normal file
135
Tests/DataLiteCoreTests/Classes/StatementTests.swift
Normal file
@@ -0,0 +1,135 @@
|
||||
import XCTest
|
||||
import DataLiteC
|
||||
@testable import DataLiteCore
|
||||
|
||||
final class StatementTests: XCTestCase {
|
||||
private let databasePath = FileManager.default.temporaryDirectory.appendingPathComponent("test.db").path
|
||||
private var connection: OpaquePointer!
|
||||
|
||||
override func setUpWithError() throws {
|
||||
try super.setUpWithError()
|
||||
|
||||
XCTAssertEqual(
|
||||
sqlite3_open(databasePath, &connection),
|
||||
SQLITE_OK,
|
||||
"Failed to open database"
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
sqlite3_exec(
|
||||
connection,
|
||||
"""
|
||||
CREATE TABLE users (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name TEXT,
|
||||
age INTEGER
|
||||
);
|
||||
""",
|
||||
nil, nil, nil
|
||||
),
|
||||
SQLITE_OK,
|
||||
"Failed to create table"
|
||||
)
|
||||
}
|
||||
|
||||
override func tearDownWithError() throws {
|
||||
sqlite3_close(connection)
|
||||
try FileManager.default.removeItem(atPath: databasePath)
|
||||
try super.tearDownWithError()
|
||||
}
|
||||
|
||||
func testMixBindings() throws {
|
||||
do {
|
||||
let sql = "INSERT INTO users (name, age) VALUES (?, ?)"
|
||||
let stmt = try Statement(db: connection, sql: sql, options: [])
|
||||
try stmt.bind("Alice", at: 1)
|
||||
try stmt.bind(88, at: 2)
|
||||
XCTAssertFalse(try stmt.step())
|
||||
}
|
||||
|
||||
do {
|
||||
let sql = "SELECT * FROM users WHERE age = ? AND name = $name"
|
||||
let stmt = try Statement(db: connection, sql: sql, options: [])
|
||||
try stmt.bind(88, at: 1)
|
||||
try stmt.bind("Alice", at: stmt.bind(parameterIndexBy: "$name"))
|
||||
XCTAssertTrue(try stmt.step())
|
||||
XCTAssertEqual(stmt.columnValue(at: 1), "Alice")
|
||||
XCTAssertEqual(stmt.columnValue(at: 2), 88)
|
||||
}
|
||||
}
|
||||
|
||||
func testStatementInitialization() throws {
|
||||
let sql = "INSERT INTO users (name, age) VALUES (?, ?)"
|
||||
let statement = try Statement(db: connection, sql: sql, options: [.persistent])
|
||||
XCTAssertNotNil(statement, "Statement should not be nil")
|
||||
}
|
||||
|
||||
func testBindAndExecute() throws {
|
||||
let sql = "INSERT INTO users (name, age) VALUES (?, ?)"
|
||||
let statement = try Statement(db: connection, sql: sql, options: [.persistent])
|
||||
try statement.bind("Alice", at: 1)
|
||||
try statement.bind(30, at: 2)
|
||||
XCTAssertEqual(statement.bindParameterCount(), 2)
|
||||
XCTAssertFalse(try statement.step())
|
||||
|
||||
let query = "SELECT * FROM users WHERE name = ?"
|
||||
let queryStatement = try Statement(db: connection, sql: query, options: [.persistent])
|
||||
try queryStatement.bind("Alice", at: 1)
|
||||
|
||||
XCTAssertTrue(try queryStatement.step(), "Failed to execute SELECT query")
|
||||
XCTAssertEqual(queryStatement.columnValue(at: 1), "Alice")
|
||||
XCTAssertEqual(queryStatement.columnValue(at: 2), 30)
|
||||
}
|
||||
|
||||
func testClearBindings() throws {
|
||||
let sql = "INSERT INTO users (name, age) VALUES (?, ?)"
|
||||
let statement = try Statement(db: connection, sql: sql, options: [.persistent])
|
||||
try statement.bind("Bob", at: 1)
|
||||
try statement.bind(25, at: 2)
|
||||
try statement.clearBindings()
|
||||
XCTAssertFalse(try statement.step())
|
||||
}
|
||||
|
||||
func testResetStatement() throws {
|
||||
let sql = "INSERT INTO users (name, age) VALUES (?, ?)"
|
||||
let statement = try Statement(db: connection, sql: sql, options: [.persistent])
|
||||
try statement.bind("Charlie", at: 1)
|
||||
try statement.bind(40, at: 2)
|
||||
try statement.step()
|
||||
|
||||
// Reset the statement and try executing it again with new values
|
||||
try statement.reset()
|
||||
try statement.bind("Dave", at: 1)
|
||||
try statement.bind(45, at: 2)
|
||||
XCTAssertEqual(statement.bindParameterCount(), 2)
|
||||
XCTAssertFalse(try statement.step())
|
||||
|
||||
// Check if the record was actually inserted
|
||||
let query = "SELECT * FROM users WHERE name = ?"
|
||||
let queryStatement = try Statement(db: connection, sql: query, options: [.persistent])
|
||||
try queryStatement.bind("Dave", at: 1)
|
||||
|
||||
XCTAssertTrue(try queryStatement.step(), "Failed to execute SELECT query")
|
||||
XCTAssertEqual(queryStatement.columnValue(at: 1), "Dave")
|
||||
XCTAssertEqual(queryStatement.columnValue(at: 2), 45)
|
||||
}
|
||||
|
||||
func testColumnValues() throws {
|
||||
let sql = "INSERT INTO users (name, age) VALUES (?, ?)"
|
||||
let statement = try Statement(db: connection, sql: sql, options: [.persistent])
|
||||
try statement.bind("Eve", at: 1)
|
||||
try statement.bind(28, at: 2)
|
||||
try statement.step()
|
||||
|
||||
// Perform a SELECT query and check column data types
|
||||
let query = "SELECT * FROM users WHERE name = ?"
|
||||
let queryStatement = try Statement(db: connection, sql: query, options: [.persistent])
|
||||
try queryStatement.bind("Eve", at: 1)
|
||||
|
||||
XCTAssertTrue(try queryStatement.step(), "Failed to execute SELECT query")
|
||||
XCTAssertEqual(queryStatement.columnType(at: 1), .text)
|
||||
XCTAssertEqual(queryStatement.columnType(at: 2), .int)
|
||||
XCTAssertEqual(queryStatement.columnValue(at: 1), "Eve")
|
||||
XCTAssertEqual(queryStatement.columnValue(at: 2), 28)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user