diff --git a/.github/workflows/ubuntu-ci.yml b/.github/workflows/ubuntu-ci.yml
new file mode 100644
index 0000000000..a961c47bd6
--- /dev/null
+++ b/.github/workflows/ubuntu-ci.yml
@@ -0,0 +1,97 @@
+# https://github.com/actions/runner-images/blob/main/images/macos/macos-15-Readme.md
+
+name: "Linux CI"
+
+on:
+ push:
+ branches:
+ - master
+ - development
+ - grdb_linux_changes
+ paths:
+ - 'GRDB/**'
+ - 'Tests/**'
+ - '.github/workflows/**'
+ - 'Makefile'
+ - 'Package.swift'
+ - 'SQLiteCustom/src'
+ pull_request:
+ paths:
+ - 'GRDB/**'
+ - 'Tests/**'
+ - '.github/workflows/**'
+ - 'Makefile'
+ - 'Package.swift'
+ - 'SQLiteCustom/src'
+
+concurrency:
+ group: ${{ github.ref_name }}
+ cancel-in-progress: false
+permissions:
+ contents: read
+
+jobs:
+ build-and-test-on-linux:
+ runs-on: ${{ matrix.os }}
+ timeout-minutes: 60
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest]
+ swift: ["6.2", "6.1"]
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@v5
+
+ - name: Install Swift Dependencies
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y \
+ binutils \
+ git \
+ gnupg2 \
+ libc6-dev \
+ libcurl4-openssl-dev \
+ libedit2 \
+ libgcc-13-dev \
+ libpython3-dev \
+ libsqlite3-0 \
+ libstdc++-13-dev \
+ libxml2-dev \
+ libz3-dev \
+ pkg-config \
+ python3-lldb \
+ tzdata \
+ unzip \
+ zip \
+ zlib1g-dev \
+ wget \
+ curl \
+ ca-certificates \
+ util-linux
+
+ - name: Cache Swiftly toolchains
+ id: cache-swiftly
+ uses: actions/cache@v4
+ with:
+ path: ${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}
+ key: swiftly-${{ matrix.os }}-${{ matrix.swift }}
+
+ - name: Install Swift Using Swiftly
+ if: steps.cache-swiftly.outputs.cache-hit != 'true'
+ run: |
+ curl -O https://download.swift.org/swiftly/linux/swiftly-$(uname -m).tar.gz
+ tar zxf swiftly-$(uname -m).tar.gz
+ ./swiftly init --quiet-shell-followup -y --skip-install
+ . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh"
+ hash -r
+ swiftly install ${{ matrix.swift }} --assume-yes --use
+ . "${SWIFTLY_HOME_DIR:-$HOME/.local/share/swiftly}/env.sh"
+
+ - name: Build SPM Package
+ run: |
+ swift build -c release
+
+ - name: Run tests
+ run: |
+ swift test -c release
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..35164a22f8
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,7 @@
+{
+ "editor.formatOnSave": false,
+ "editor.insertSpaces": true,
+ "editor.tabSize": 4,
+ "editor.detectIndentation": false,
+ "editor.trimAutoWhitespace": false
+}
\ No newline at end of file
diff --git a/GRDB/Core/DispatchQueueActor.swift b/GRDB/Core/DispatchQueueActor.swift
index 3a51d8897f..93f054a30e 100644
--- a/GRDB/Core/DispatchQueueActor.swift
+++ b/GRDB/Core/DispatchQueueActor.swift
@@ -1,4 +1,8 @@
+#if os(Linux)
+@preconcurrency import Dispatch
+#else
import Dispatch
+#endif
/// An actor that runs in a DispatchQueue.
///
diff --git a/GRDB/Core/Support/CoreGraphics/CGFloat.swift b/GRDB/Core/Support/CoreGraphics/CGFloat.swift
index 6b0fb6053b..99d6153506 100644
--- a/GRDB/Core/Support/CoreGraphics/CGFloat.swift
+++ b/GRDB/Core/Support/CoreGraphics/CGFloat.swift
@@ -1,5 +1,8 @@
#if canImport(CoreGraphics)
import CoreGraphics
+#elseif !canImport(Darwin)
+import Foundation
+#endif
/// CGFloat adopts DatabaseValueConvertible
extension CGFloat: DatabaseValueConvertible {
@@ -15,4 +18,3 @@ extension CGFloat: DatabaseValueConvertible {
return CGFloat(double)
}
}
-#endif
diff --git a/GRDB/Core/Support/Foundation/Date.swift b/GRDB/Core/Support/Foundation/Date.swift
index dadc00fd65..379e3ff5b0 100644
--- a/GRDB/Core/Support/Foundation/Date.swift
+++ b/GRDB/Core/Support/Foundation/Date.swift
@@ -12,7 +12,6 @@ import GRDBSQLite
import Foundation
-#if !os(Linux)
/// NSDate is stored in the database using the format
/// "yyyy-MM-dd HH:mm:ss.SSS", in the UTC time zone.
extension NSDate: DatabaseValueConvertible {
@@ -41,7 +40,6 @@ extension NSDate: DatabaseValueConvertible {
return cast(date)
}
}
-#endif
/// Date is stored in the database using the format
/// "yyyy-MM-dd HH:mm:ss.SSS", in the UTC time zone.
diff --git a/GRDB/Core/Support/Foundation/Decimal.swift b/GRDB/Core/Support/Foundation/Decimal.swift
index 70d84f3ab7..d315fb6d45 100644
--- a/GRDB/Core/Support/Foundation/Decimal.swift
+++ b/GRDB/Core/Support/Foundation/Decimal.swift
@@ -1,4 +1,3 @@
-#if !os(Linux)
// Import C SQLite functions
#if GRDBCIPHER // CocoaPods (SQLCipher subspec)
import SQLCipher
@@ -68,4 +67,3 @@ extension Decimal: StatementColumnConvertible {
@usableFromInline
let _posixLocale = Locale(identifier: "en_US_POSIX")
-#endif
diff --git a/GRDB/Core/Support/Foundation/NSData.swift b/GRDB/Core/Support/Foundation/NSData.swift
index 72861ac02e..12cba1a3ce 100644
--- a/GRDB/Core/Support/Foundation/NSData.swift
+++ b/GRDB/Core/Support/Foundation/NSData.swift
@@ -1,4 +1,3 @@
-#if !os(Linux)
import Foundation
/// NSData is convertible to and from DatabaseValue.
@@ -24,4 +23,3 @@ extension NSData: DatabaseValueConvertible {
return cast(data)
}
}
-#endif
diff --git a/GRDB/Core/Support/Foundation/NSNumber.swift b/GRDB/Core/Support/Foundation/NSNumber.swift
index 1c5778c19e..3b5076fd34 100644
--- a/GRDB/Core/Support/Foundation/NSNumber.swift
+++ b/GRDB/Core/Support/Foundation/NSNumber.swift
@@ -1,4 +1,4 @@
-#if !os(Linux) && !os(Windows)
+#if !os(Windows)
import Foundation
private let integerRoundingBehavior = NSDecimalNumberHandler(
@@ -81,10 +81,18 @@ extension NSNumber: DatabaseValueConvertible {
/// Otherwise, returns nil.
public static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self? {
switch dbValue.storage {
+ case .int64(let int64) where self is NSDecimalNumber.Type:
+ let number = NSDecimalNumber(value: int64)
+ return number as? Self
case .int64(let int64):
- return self.init(value: int64)
+ let number = NSNumber(value: int64)
+ return number as? Self
+ case .double(let double) where self is NSDecimalNumber.Type:
+ let number = NSDecimalNumber(value: double)
+ return number as? Self
case .double(let double):
- return self.init(value: double)
+ let number = NSNumber(value: double)
+ return number as? Self
case let .string(string):
// Must match Decimal.fromDatabaseValue(_:)
guard let decimal = Decimal(string: string, locale: posixLocale) else { return nil }
diff --git a/GRDB/Core/Support/Foundation/NSString.swift b/GRDB/Core/Support/Foundation/NSString.swift
index acddddb35d..3f019ad403 100644
--- a/GRDB/Core/Support/Foundation/NSString.swift
+++ b/GRDB/Core/Support/Foundation/NSString.swift
@@ -1,4 +1,3 @@
-#if !os(Linux)
import Foundation
/// NSString adopts DatabaseValueConvertible
@@ -24,4 +23,3 @@ extension NSString: DatabaseValueConvertible {
return self.init(string: string)
}
}
-#endif
diff --git a/GRDB/Core/Support/Foundation/URL.swift b/GRDB/Core/Support/Foundation/URL.swift
index 6db66ec3b8..b3630b14a4 100644
--- a/GRDB/Core/Support/Foundation/URL.swift
+++ b/GRDB/Core/Support/Foundation/URL.swift
@@ -1,12 +1,16 @@
import Foundation
-#if !os(Linux) && !os(Windows)
+#if !os(Windows)
/// NSURL stores its absoluteString in the database.
extension NSURL: DatabaseValueConvertible {
/// Returns a TEXT database value containing the absolute URL.
public var databaseValue: DatabaseValue {
- absoluteString?.databaseValue ?? .null
+ #if !canImport(Darwin)
+ absoluteString.databaseValue
+ #else
+ absoluteString?.databaseValue ?? .null
+ #endif
}
public static func fromDatabaseValue(_ dbValue: DatabaseValue) -> Self? {
diff --git a/GRDB/Core/Support/Foundation/UUID.swift b/GRDB/Core/Support/Foundation/UUID.swift
index 54b18b2c80..92d4e1fcba 100644
--- a/GRDB/Core/Support/Foundation/UUID.swift
+++ b/GRDB/Core/Support/Foundation/UUID.swift
@@ -12,7 +12,7 @@ import GRDBSQLite
import Foundation
-#if !os(Linux) && !os(Windows)
+#if !os(Windows)
/// NSUUID adopts DatabaseValueConvertible
extension NSUUID: DatabaseValueConvertible {
/// Returns a BLOB database value containing the uuid bytes.
@@ -36,10 +36,17 @@ extension NSUUID: DatabaseValueConvertible {
switch dbValue.storage {
case .blob(let data) where data.count == 16:
return data.withUnsafeBytes {
- self.init(uuidBytes: $0.bindMemory(to: UInt8.self).baseAddress)
+ #if canImport(Darwin)
+ self.init(uuidBytes: $0.bindMemory(to: UInt8.self).baseAddress)
+ #else
+ guard let uuidBytes = $0.bindMemory(to: UInt8.self).baseAddress else {
+ return nil as Self?
+ }
+ return NSUUID(uuidBytes: uuidBytes) as? Self
+ #endif
}
case .string(let string):
- return self.init(uuidString: string)
+ return NSUUID(uuidString: string) as? Self
default:
return nil
}
@@ -91,8 +98,8 @@ extension UUID: StatementColumnConvertible {
self.init(uuid: uuid.uuid)
case SQLITE_BLOB:
guard sqlite3_column_bytes(sqliteStatement, index) == 16,
- let blob = sqlite3_column_blob(sqliteStatement, index) else
- {
+ let blob = sqlite3_column_blob(sqliteStatement, index)
+ else {
return nil
}
self.init(uuid: blob.assumingMemoryBound(to: uuid_t.self).pointee)
diff --git a/Package.swift b/Package.swift
index 26c61734a5..9a677d82c2 100644
--- a/Package.swift
+++ b/Package.swift
@@ -15,6 +15,8 @@ let darwinPlatforms: [Platform] = [
var swiftSettings: [SwiftSetting] = [
.define("SQLITE_ENABLE_FTS5"),
.define("SQLITE_ENABLE_SNAPSHOT"),
+ // Not all Linux distributions have support for WAL snapshots.
+ .define("SQLITE_DISABLE_SNAPSHOT", .when(platforms: [.linux])),
]
var cSettings: [CSetting] = []
var dependencies: [PackageDescription.Package.Dependency] = []
diff --git a/README.md b/README.md
index 4261c65e8f..1682f59ce8 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@
+
---
diff --git a/Tests/GRDBTests/CGFloatTests.swift b/Tests/GRDBTests/CGFloatTests.swift
index 1bcfaaa582..4c9ebd93b4 100644
--- a/Tests/GRDBTests/CGFloatTests.swift
+++ b/Tests/GRDBTests/CGFloatTests.swift
@@ -1,7 +1,12 @@
import XCTest
-import CoreGraphics
import GRDB
+#if canImport(CoreGraphics)
+import CoreGraphics
+#elseif !canImport(Darwin)
+import Foundation
+#endif
+
class CGFloatTests: GRDBTestCase {
func testCGFLoat() throws {
diff --git a/Tests/GRDBTests/DatabaseErrorTests.swift b/Tests/GRDBTests/DatabaseErrorTests.swift
index e968b44074..d0106ad64b 100644
--- a/Tests/GRDBTests/DatabaseErrorTests.swift
+++ b/Tests/GRDBTests/DatabaseErrorTests.swift
@@ -216,6 +216,9 @@ class DatabaseErrorTests: GRDBTestCase {
}
func testNSErrorBridging() throws {
+#if !canImport(Darwin)
+ throw XCTSkip("NSError bridging not available on non-Darwin platforms")
+#else
let dbQueue = try makeDatabaseQueue()
try dbQueue.inDatabase { db in
try db.create(table: "parents") { $0.column("id", .integer).primaryKey() }
@@ -229,5 +232,6 @@ class DatabaseErrorTests: GRDBTestCase {
XCTAssertNotNil(error.localizedFailureReason)
}
}
+#endif
}
}
diff --git a/Tests/GRDBTests/DatabaseMigratorTests.swift b/Tests/GRDBTests/DatabaseMigratorTests.swift
index da09225083..1b053e2583 100644
--- a/Tests/GRDBTests/DatabaseMigratorTests.swift
+++ b/Tests/GRDBTests/DatabaseMigratorTests.swift
@@ -10,6 +10,9 @@ class DatabaseMigratorTests : GRDBTestCase {
}
func testEmptyMigratorSync() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: some DatabaseWriter) throws {
let migrator = DatabaseMigrator()
try migrator.migrate(writer)
@@ -18,9 +21,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testEmptyMigratorAsync() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: some DatabaseWriter) throws {
let expectation = self.expectation(description: "")
let migrator = DatabaseMigrator()
@@ -38,9 +45,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testEmptyMigratorPublisher() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: some DatabaseWriter) throws {
let migrator = DatabaseMigrator()
let publisher = migrator.migratePublisher(writer)
@@ -51,9 +62,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testNonEmptyMigratorSync() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: some DatabaseWriter) throws {
var migrator = DatabaseMigrator()
migrator.registerMigration("createPersons") { db in
@@ -95,9 +110,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testNonEmptyMigratorAsync() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: some DatabaseWriter) throws {
var migrator = DatabaseMigrator()
migrator.registerMigration("createPersons") { db in
@@ -146,9 +165,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testNonEmptyMigratorPublisher() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: some DatabaseWriter) throws {
var migrator = DatabaseMigrator()
migrator.registerMigration("createPersons") { db in
@@ -198,9 +221,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testEmptyMigratorPublisherIsAsynchronous() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: some DatabaseWriter) throws {
let migrator = DatabaseMigrator()
let expectation = self.expectation(description: "")
@@ -220,9 +247,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testNonEmptyMigratorPublisherIsAsynchronous() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: some DatabaseWriter) throws {
var migrator = DatabaseMigrator()
migrator.registerMigration("first", migrate: { _ in })
@@ -243,9 +274,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testMigratorPublisherDefaultScheduler() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: Writer) {
var migrator = DatabaseMigrator()
migrator.registerMigration("first", migrate: { _ in })
@@ -268,9 +303,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testMigratorPublisherCustomScheduler() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: Writer) {
var migrator = DatabaseMigrator()
migrator.registerMigration("first", migrate: { _ in })
@@ -294,9 +333,13 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testMigrateUpTo() throws {
+#if !canImport(Combine)
+ throw XCTSkip("Combine not supported on this platform")
+#else
func test(writer: some DatabaseWriter) throws {
var migrator = DatabaseMigrator()
migrator.registerMigration("a") { db in
@@ -345,6 +388,7 @@ class DatabaseMigratorTests : GRDBTestCase {
try Test(test).run { try DatabaseQueue() }
try Test(test).runAtTemporaryDatabasePath { try DatabaseQueue(path: $0) }
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
+#endif
}
func testMigrationFailureTriggersRollback() throws {
diff --git a/Tests/GRDBTests/DatabasePoolConcurrencyTests.swift b/Tests/GRDBTests/DatabasePoolConcurrencyTests.swift
index 7d2478545b..bbdf523d44 100644
--- a/Tests/GRDBTests/DatabasePoolConcurrencyTests.swift
+++ b/Tests/GRDBTests/DatabasePoolConcurrencyTests.swift
@@ -877,10 +877,12 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, nil)
XCTAssertEqual(db.description, "GRDB.DatabasePool.writer")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "GRDB.DatabasePool.writer")
+#endif
}
let s1 = DispatchSemaphore(value: 0)
@@ -890,10 +892,12 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, nil)
XCTAssertEqual(db.description, "GRDB.DatabasePool.reader.1")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "GRDB.DatabasePool.reader.1")
+#endif
_ = s1.signal()
_ = s2.wait(timeout: .distantFuture)
@@ -906,10 +910,12 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, nil)
XCTAssertEqual(db.description, "GRDB.DatabasePool.reader.2")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "GRDB.DatabasePool.reader.2")
+#endif
}
}
let blocks = [block1, block2]
@@ -925,10 +931,12 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, "Toreador")
XCTAssertEqual(db.description, "Toreador.writer")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "Toreador.writer")
+#endif
}
let s1 = DispatchSemaphore(value: 0)
@@ -938,10 +946,12 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, "Toreador")
XCTAssertEqual(db.description, "Toreador.reader.1")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "Toreador.reader.1")
+#endif
_ = s1.signal()
_ = s2.wait(timeout: .distantFuture)
@@ -954,10 +964,12 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, "Toreador")
XCTAssertEqual(db.description, "Toreador.reader.2")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "Toreador.reader.2")
+#endif
}
}
let blocks = [block1, block2]
@@ -1037,6 +1049,9 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
}
func testQoS() throws {
+#if !canImport(Darwin)
+ throw XCTSkip("__dispatch_get_global_queue unavailable")
+#else
func test(qos: DispatchQoS) throws {
// https://forums.swift.org/t/what-is-the-default-target-queue-for-a-serial-queue/18094/5
//
@@ -1072,6 +1087,7 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
try test(qos: .background)
try test(qos: .userInitiated)
+#endif
}
// MARK: - AsyncConcurrentRead
@@ -1254,6 +1270,9 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
// MARK: - Concurrent opening
func testConcurrentOpening() throws {
+#if !canImport(Darwin)
+ throw XCTSkip("NSFileCoordinator unavailable")
+#else
for _ in 0..<50 {
let dbDirectoryName = "DatabasePoolConcurrencyTests-\(ProcessInfo.processInfo.globallyUniqueString)"
let directoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
@@ -1277,6 +1296,7 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
XCTAssert(poolError ?? coordinatorError == nil)
}
}
+#endif
}
// MARK: - NSFileCoordinator sample code tests
@@ -1284,6 +1304,9 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
// Test for sample code in Documentation.docc/DatabaseSharing.md.
// This test passes if this method compiles
private func openSharedDatabase(at databaseURL: URL) throws -> DatabasePool {
+#if !canImport(Darwin)
+ throw XCTSkip("NSFileCoordinator unavailable")
+#else
let coordinator = NSFileCoordinator(filePresenter: nil)
var coordinatorError: NSError?
var dbPool: DatabasePool?
@@ -1299,6 +1322,7 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
throw error
}
return dbPool!
+#endif
}
// Test for sample code in Documentation.docc/DatabaseSharing.md.
@@ -1313,6 +1337,9 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
// Test for sample code in Documentation.docc/DatabaseSharing.md.
// This test passes if this method compiles
private func openSharedReadOnlyDatabase(at databaseURL: URL) throws -> DatabasePool? {
+#if !canImport(Darwin)
+ throw XCTSkip("NSFileCoordinator unavailable")
+#else
let coordinator = NSFileCoordinator(filePresenter: nil)
var coordinatorError: NSError?
var dbPool: DatabasePool?
@@ -1328,6 +1355,7 @@ class DatabasePoolConcurrencyTests: GRDBTestCase {
throw error
}
return dbPool
+#endif
}
// Test for sample code in Documentation.docc/DatabaseSharing.md.
diff --git a/Tests/GRDBTests/DatabaseQueueTests.swift b/Tests/GRDBTests/DatabaseQueueTests.swift
index c22be83261..0372d97776 100644
--- a/Tests/GRDBTests/DatabaseQueueTests.swift
+++ b/Tests/GRDBTests/DatabaseQueueTests.swift
@@ -129,10 +129,12 @@ class DatabaseQueueTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, nil)
XCTAssertEqual(db.description, "GRDB.DatabaseQueue")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "GRDB.DatabaseQueue")
+#endif
}
}
@@ -144,10 +146,12 @@ class DatabaseQueueTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, "Toreador")
XCTAssertEqual(db.description, "Toreador")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "Toreador")
+#endif
}
}
@@ -221,6 +225,9 @@ class DatabaseQueueTests: GRDBTestCase {
}
func testQoS() throws {
+#if !canImport(Darwin)
+ throw XCTSkip("__dispatch_get_global_queue not available on non-Darwin platforms")
+#else
func test(qos: DispatchQoS) throws {
// https://forums.swift.org/t/what-is-the-default-target-queue-for-a-serial-queue/18094/5
//
@@ -256,6 +263,7 @@ class DatabaseQueueTests: GRDBTestCase {
try test(qos: .background)
try test(qos: .userInitiated)
+#endif
}
// MARK: - SQLITE_BUSY prevention
diff --git a/Tests/GRDBTests/DatabaseRegionObservationTests.swift b/Tests/GRDBTests/DatabaseRegionObservationTests.swift
index 3ffdfc39eb..6338a76057 100644
--- a/Tests/GRDBTests/DatabaseRegionObservationTests.swift
+++ b/Tests/GRDBTests/DatabaseRegionObservationTests.swift
@@ -4,12 +4,14 @@ import GRDB
class DatabaseRegionObservationTests: GRDBTestCase {
// Test passes if it compiles.
// See
+ #if canImport(Combine)
func testAnyDatabaseWriter(writer: any DatabaseWriter) throws {
let observation = DatabaseRegionObservation(tracking: .fullDatabase)
_ = observation.start(in: writer, onError: { _ in }, onChange: { _ in })
_ = observation.publisher(in: writer)
}
+ #endif
func testDatabaseRegionObservation_FullDatabase() throws {
let dbQueue = try makeDatabaseQueue()
diff --git a/Tests/GRDBTests/DatabaseSnapshotTests.swift b/Tests/GRDBTests/DatabaseSnapshotTests.swift
index 1cb422ecdd..b31ccea69d 100644
--- a/Tests/GRDBTests/DatabaseSnapshotTests.swift
+++ b/Tests/GRDBTests/DatabaseSnapshotTests.swift
@@ -230,10 +230,12 @@ class DatabaseSnapshotTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, nil)
XCTAssertEqual(db.description, "GRDB.DatabasePool.snapshot.1")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "GRDB.DatabasePool.snapshot.1")
+#endif
}
let snapshot2 = try dbPool.makeSnapshot()
@@ -241,10 +243,12 @@ class DatabaseSnapshotTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, nil)
XCTAssertEqual(db.description, "GRDB.DatabasePool.snapshot.2")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "GRDB.DatabasePool.snapshot.2")
+#endif
}
}
@@ -257,10 +261,12 @@ class DatabaseSnapshotTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, "Toreador")
XCTAssertEqual(db.description, "Toreador.snapshot.1")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "Toreador.snapshot.1")
+#endif
}
let snapshot2 = try dbPool.makeSnapshot()
@@ -268,10 +274,12 @@ class DatabaseSnapshotTests: GRDBTestCase {
XCTAssertEqual(db.configuration.label, "Toreador")
XCTAssertEqual(db.description, "Toreador.snapshot.2")
+#if canImport(Darwin)
// This test CAN break in future releases: the dispatch queue labels
// are documented to be a debug-only tool.
let label = String(utf8String: __dispatch_queue_get_label(nil))
XCTAssertEqual(label, "Toreador.snapshot.2")
+#endif
}
}
diff --git a/Tests/GRDBTests/FailureTestCase.swift b/Tests/GRDBTests/FailureTestCase.swift
index 9dfb9770ba..7b552aaa04 100644
--- a/Tests/GRDBTests/FailureTestCase.swift
+++ b/Tests/GRDBTests/FailureTestCase.swift
@@ -1,3 +1,4 @@
+#if canImport(Darwin)
// Inspired by https://github.com/groue/CombineExpectations
import XCTest
@@ -207,3 +208,4 @@ class FailureTestCaseTests: FailureTestCase {
}
}
}
+#endif
diff --git a/Tests/GRDBTests/ValueObservationRecorderTests.swift b/Tests/GRDBTests/ValueObservationRecorderTests.swift
index 4b8e8a2ae0..134543db4f 100644
--- a/Tests/GRDBTests/ValueObservationRecorderTests.swift
+++ b/Tests/GRDBTests/ValueObservationRecorderTests.swift
@@ -1,3 +1,4 @@
+#if canImport(Darwin)
import Dispatch
import XCTest
@@ -781,3 +782,4 @@ class ValueObservationRecorderTests: FailureTestCase {
}
}
}
+#endif
diff --git a/Tests/GRDBTests/ValueObservationTests.swift b/Tests/GRDBTests/ValueObservationTests.swift
index 6134d8453b..e884fc2a0e 100644
--- a/Tests/GRDBTests/ValueObservationTests.swift
+++ b/Tests/GRDBTests/ValueObservationTests.swift
@@ -926,6 +926,7 @@ class ValueObservationTests: GRDBTestCase {
}
// MARK: - Async Await
+#if canImport(Combine)
func testAsyncAwait_values_prefix() async throws {
func test(_ writer: some DatabaseWriter) async throws {
@@ -1238,6 +1239,7 @@ class ValueObservationTests: GRDBTestCase {
try Test(test).runAtTemporaryDatabasePath { try DatabasePool(path: $0) }
}
+#endif
// Regression test for
func testIssue1383() throws {