Files
UUVPN/iOS-SwiftUI-Code/GRDB.swift-6.29.3/Tests/GRDBTests/DataMemoryTests.swift
T
2025-01-28 12:28:03 +08:00

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")
}
}
}
}
}