157 lines
6.9 KiB
Swift
157 lines
6.9 KiB
Swift
import XCTest
|
|
@testable import GRDB
|
|
|
|
class DataMemoryTests: GRDBTestCase {
|
|
|
|
func testMemoryBehavior() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
// Make sure Data is on the heap (15 bytes is enough)
|
|
// For more context, see:
|
|
// https://forums.swift.org/t/swift-5-how-to-test-data-bytesnocopydeallocator/20299/2?u=gwendal.roue
|
|
let data = Data(repeating: 0xaa, count: 15)
|
|
|
|
do {
|
|
let rows = try Row.fetchCursor(db, sql: "SELECT ?", arguments: [data])
|
|
while let row = try rows.next() {
|
|
let blobPointer = sqlite3_column_blob(row.sqliteStatement, 0)
|
|
|
|
do {
|
|
// This data should be copied:
|
|
let copiedData: Data = row[0]
|
|
XCTAssertEqual(copiedData, data)
|
|
copiedData.withUnsafeBytes {
|
|
XCTAssertNotEqual($0.baseAddress, blobPointer)
|
|
}
|
|
}
|
|
|
|
do {
|
|
// This data should not be copied
|
|
try row.withUnsafeData(atIndex: 0) { nonCopiedData in
|
|
XCTAssertEqual(nonCopiedData, data)
|
|
nonCopiedData!.withUnsafeBytes {
|
|
XCTAssertEqual($0.baseAddress, blobPointer)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
do {
|
|
let adapter = ScopeAdapter(["nested": SuffixRowAdapter(fromIndex: 0)])
|
|
let rows = try Row.fetchCursor(db, sql: "SELECT ?", arguments: [data], adapter: adapter)
|
|
while let row = try rows.next() {
|
|
let blobPointer = sqlite3_column_blob(row.unadapted.sqliteStatement, 0)
|
|
let nestedRow = row.scopes["nested"]!
|
|
|
|
do {
|
|
// This data should be copied:
|
|
let copiedData: Data = nestedRow[0]
|
|
XCTAssertEqual(copiedData, data)
|
|
copiedData.withUnsafeBytes {
|
|
XCTAssertNotEqual($0.baseAddress, blobPointer)
|
|
}
|
|
}
|
|
|
|
do {
|
|
// This data should not be copied
|
|
try nestedRow.withUnsafeData(atIndex: 0) { nonCopiedData in
|
|
XCTAssertEqual(nonCopiedData, data)
|
|
nonCopiedData!.withUnsafeBytes {
|
|
XCTAssertEqual($0.baseAddress, blobPointer)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
do {
|
|
let row = try Row.fetchOne(db, sql: "SELECT ?", arguments: [data])!
|
|
let dbValue = row.first!.1 // TODO: think about exposing a (column:,databaseValue:) tuple
|
|
switch dbValue.storage {
|
|
case .blob(let data):
|
|
try data.withUnsafeBytes { buffer in
|
|
do {
|
|
// This data should not be copied:
|
|
let nonCopiedData: Data = row[0]
|
|
XCTAssertEqual(nonCopiedData, data)
|
|
nonCopiedData.withUnsafeBytes { nonCopiedBuffer in
|
|
XCTAssertEqual(nonCopiedBuffer.baseAddress, buffer.baseAddress)
|
|
}
|
|
}
|
|
|
|
do {
|
|
// This data should not be copied:
|
|
try row.withUnsafeData(atIndex: 0) { nonCopiedData in
|
|
XCTAssertEqual(nonCopiedData, data)
|
|
nonCopiedData!.withUnsafeBytes { nonCopiedBuffer in
|
|
XCTAssertEqual(nonCopiedBuffer.baseAddress, buffer.baseAddress)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
XCTFail("Not a blob")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@available(*, deprecated)
|
|
func testDeprecatedMemoryBehavior() throws {
|
|
let dbQueue = try makeDatabaseQueue()
|
|
try dbQueue.inDatabase { db in
|
|
// Make sure Data is on the heap (15 bytes is enough)
|
|
// For more context, see:
|
|
// https://forums.swift.org/t/swift-5-how-to-test-data-bytesnocopydeallocator/20299/2?u=gwendal.roue
|
|
let data = Data(repeating: 0xaa, count: 15)
|
|
|
|
do {
|
|
let rows = try Row.fetchCursor(db, sql: "SELECT ?", arguments: [data])
|
|
while let row = try rows.next() {
|
|
let blobPointer = sqlite3_column_blob(row.sqliteStatement, 0)
|
|
// This data should not be copied
|
|
let nonCopiedData = row.dataNoCopy(atIndex: 0)!
|
|
XCTAssertEqual(nonCopiedData, data)
|
|
nonCopiedData.withUnsafeBytes {
|
|
XCTAssertEqual($0.baseAddress, blobPointer)
|
|
}
|
|
}
|
|
}
|
|
|
|
do {
|
|
let adapter = ScopeAdapter(["nested": SuffixRowAdapter(fromIndex: 0)])
|
|
let rows = try Row.fetchCursor(db, sql: "SELECT ?", arguments: [data], adapter: adapter)
|
|
while let row = try rows.next() {
|
|
let blobPointer = sqlite3_column_blob(row.unadapted.sqliteStatement, 0)
|
|
let nestedRow = row.scopes["nested"]!
|
|
// This data should not be copied
|
|
let nonCopiedData = nestedRow.dataNoCopy(atIndex: 0)!
|
|
XCTAssertEqual(nonCopiedData, data)
|
|
nonCopiedData.withUnsafeBytes {
|
|
XCTAssertEqual($0.baseAddress, blobPointer)
|
|
}
|
|
}
|
|
}
|
|
|
|
do {
|
|
let row = try Row.fetchOne(db, sql: "SELECT ?", arguments: [data])!
|
|
let dbValue = row.first!.1 // TODO: think about exposing a (column:,databaseValue:) tuple
|
|
switch dbValue.storage {
|
|
case .blob(let data):
|
|
data.withUnsafeBytes { buffer in
|
|
// This data should not be copied:
|
|
let nonCopiedData = row.dataNoCopy(atIndex: 0)!
|
|
XCTAssertEqual(nonCopiedData, data)
|
|
nonCopiedData.withUnsafeBytes { nonCopiedBuffer in
|
|
XCTAssertEqual(nonCopiedBuffer.baseAddress, buffer.baseAddress)
|
|
}
|
|
}
|
|
default:
|
|
XCTFail("Not a blob")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|