From c86793e75a5b94e1d3d9b76650d86bce0c790f2d Mon Sep 17 00:00:00 2001 From: Ricky Witherspoon Date: Fri, 6 Feb 2026 09:30:27 -0500 Subject: [PATCH 1/7] Fix preview temp directory for CKAsset --- Sources/SQLiteData/CloudKit/Internal/DataManager.swift | 2 +- Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Sources/SQLiteData/CloudKit/Internal/DataManager.swift b/Sources/SQLiteData/CloudKit/Internal/DataManager.swift index 0bf280c4..683500cc 100644 --- a/Sources/SQLiteData/CloudKit/Internal/DataManager.swift +++ b/Sources/SQLiteData/CloudKit/Internal/DataManager.swift @@ -77,7 +77,7 @@ } package var temporaryDirectory: URL { - URL(fileURLWithPath: "/") + URL(fileURLWithPath: NSTemporaryDirectory()) } } diff --git a/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift b/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift index 3eabc637..0ee128a6 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift @@ -2,6 +2,7 @@ import DependenciesTestSupport import InlineSnapshotTesting import SnapshotTestingCustomDump + import Foundation import SQLiteData import Testing @@ -43,6 +44,14 @@ } } + @Test + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) + func inMemoryDataManagerUsesNSTemporaryDirectory() { + let expectedPath = URL(fileURLWithPath: NSTemporaryDirectory()).path + let actualPath = inMemoryDataManager.temporaryDirectory.path + #expect(actualPath == expectedPath) + } + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) @Test func delete() async throws { @FetchAll(RemindersList.all, database: userDatabase.database) var remindersLists From fba06e8ac59ccac8a0143bdfb4ea35aef5bc272b Mon Sep 17 00:00:00 2001 From: Ricky Witherspoon Date: Fri, 6 Feb 2026 10:01:49 -0500 Subject: [PATCH 2/7] reverted last commit --- Sources/SQLiteData/CloudKit/Internal/DataManager.swift | 2 +- Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Sources/SQLiteData/CloudKit/Internal/DataManager.swift b/Sources/SQLiteData/CloudKit/Internal/DataManager.swift index 683500cc..0bf280c4 100644 --- a/Sources/SQLiteData/CloudKit/Internal/DataManager.swift +++ b/Sources/SQLiteData/CloudKit/Internal/DataManager.swift @@ -77,7 +77,7 @@ } package var temporaryDirectory: URL { - URL(fileURLWithPath: NSTemporaryDirectory()) + URL(fileURLWithPath: "/") } } diff --git a/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift b/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift index 0ee128a6..c1fb2c37 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift @@ -44,14 +44,6 @@ } } - @Test - @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) - func inMemoryDataManagerUsesNSTemporaryDirectory() { - let expectedPath = URL(fileURLWithPath: NSTemporaryDirectory()).path - let actualPath = inMemoryDataManager.temporaryDirectory.path - #expect(actualPath == expectedPath) - } - @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) @Test func delete() async throws { @FetchAll(RemindersList.all, database: userDatabase.database) var remindersLists From af6295f74ca906c52a8f52f16cc97c7b07ac3f6d Mon Sep 17 00:00:00 2001 From: Ricky Witherspoon Date: Fri, 6 Feb 2026 10:02:40 -0500 Subject: [PATCH 3/7] forgot the foundation import from the revision --- Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift b/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift index c1fb2c37..3eabc637 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/PreviewTests.swift @@ -2,7 +2,6 @@ import DependenciesTestSupport import InlineSnapshotTesting import SnapshotTestingCustomDump - import Foundation import SQLiteData import Testing From 5d520444bc4184c48b15daf84a780d92123f4e9e Mon Sep 17 00:00:00 2001 From: Ricky Witherspoon Date: Fri, 6 Feb 2026 10:02:48 -0500 Subject: [PATCH 4/7] fix --- Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift b/Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift index ae093dd5..8b3223ec 100644 --- a/Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift +++ b/Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift @@ -60,7 +60,8 @@ for key in record.allKeys() { guard let assetData = state.assets[AssetID(recordID: record.recordID, key: key)] else { continue } - let url = URL(filePath: UUID().uuidString.lowercased()) + let randomPath = UUID().uuidString.lowercased() + let url = dataManager.wrappedValue.temporaryDirectory.appending(path: randomPath) try dataManager.wrappedValue.save(assetData, to: url) record[key] = CKAsset(fileURL: url) } From 74df7741225f8ce55d0d3b31a5fb1d6002299978 Mon Sep 17 00:00:00 2001 From: Ricky Witherspoon Date: Fri, 6 Feb 2026 10:11:25 -0500 Subject: [PATCH 5/7] added tests --- .../MockCloudDatabaseTests.swift | 29 ++++++++++++++++++ .../TemporaryDirectoryDataManager.swift | 30 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 Tests/SQLiteDataTests/Internal/TemporaryDirectoryDataManager.swift diff --git a/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift index ecd50cc2..f53f36a2 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift @@ -46,6 +46,35 @@ #expect(error == CKError(.unknownItem)) } + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) + @Test func assetsUseTemporaryDirectory() async throws { + let temporaryDirectory = URL(fileURLWithPath: NSTemporaryDirectory()) + .appending(path: "sqlite-data-test-assets") + let dataManager = TemporaryDirectoryDataManager(temporaryDirectory: temporaryDirectory) + + let recordID = CKRecord.ID(recordName: "asset-record") + let record = CKRecord(recordType: "AssetRecord", recordID: recordID) + let sourceURL = temporaryDirectory.appending(path: "source") + try dataManager.save(Data("image".utf8), to: sourceURL) + record["asset"] = CKAsset(fileURL: sourceURL) + + let database = syncEngine.private.database + try withDependencies { + $0.dataManager = dataManager + } operation: { + let (saveResults, _) = try database.modifyRecords( + saving: [record], + deleting: [] + ) + _ = try saveResults[recordID]?.get() + + let fetched = try database.record(for: recordID) + let asset = fetched["asset"] as? CKAsset + let assetDirectory = asset?.fileURL?.deletingLastPathComponent().path + #expect(assetDirectory == temporaryDirectory.path) + } + } + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) @Test func saveTransaction_ChildBeforeParent() async throws { let parent = CKRecord(recordType: "A", recordID: CKRecord.ID(recordName: "A")) diff --git a/Tests/SQLiteDataTests/Internal/TemporaryDirectoryDataManager.swift b/Tests/SQLiteDataTests/Internal/TemporaryDirectoryDataManager.swift new file mode 100644 index 00000000..92a8bc05 --- /dev/null +++ b/Tests/SQLiteDataTests/Internal/TemporaryDirectoryDataManager.swift @@ -0,0 +1,30 @@ +#if canImport(CloudKit) + import ConcurrencyExtras + import Foundation + import SQLiteData + + @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) + struct TemporaryDirectoryDataManager: DataManager { + let temporaryDirectory: URL + let storage = LockIsolated<[URL: Data]>([:]) + + func load(_ url: URL) throws -> Data { + try storage.withValue { storage in + guard let data = storage[url] + else { + struct FileNotFound: Error {} + throw FileNotFound() + } + return data + } + } + + func save(_ data: Data, to url: URL) throws { + storage.withValue { $0[url] = data } + } + + func sha256(of fileURL: URL) -> Data? { + nil + } + } +#endif From 0a72ea2a7f44ac50d7e25a0f399bd186bddbe0c1 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 6 Feb 2026 11:53:34 -0600 Subject: [PATCH 6/7] Use InMemoryDataManager for previews and fixed tests. --- .../CloudKit/Internal/DataManager.swift | 5 ++- .../CloudKit/Internal/MockCloudDatabase.swift | 3 +- .../MockCloudDatabaseTests.swift | 39 ++++++++----------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/Sources/SQLiteData/CloudKit/Internal/DataManager.swift b/Sources/SQLiteData/CloudKit/Internal/DataManager.swift index 0bf280c4..1b6a5442 100644 --- a/Sources/SQLiteData/CloudKit/Internal/DataManager.swift +++ b/Sources/SQLiteData/CloudKit/Internal/DataManager.swift @@ -77,7 +77,7 @@ } package var temporaryDirectory: URL { - URL(fileURLWithPath: "/") + URL(fileURLWithPath: "/tmp") } } @@ -86,6 +86,9 @@ static var liveValue: any DataManager { LiveDataManager() } + static var previewValue: any DataManager { + InMemoryDataManager() + } static var testValue: any DataManager { InMemoryDataManager() } diff --git a/Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift b/Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift index 8b3223ec..50f20237 100644 --- a/Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift +++ b/Sources/SQLiteData/CloudKit/Internal/MockCloudDatabase.swift @@ -60,8 +60,7 @@ for key in record.allKeys() { guard let assetData = state.assets[AssetID(recordID: record.recordID, key: key)] else { continue } - let randomPath = UUID().uuidString.lowercased() - let url = dataManager.wrappedValue.temporaryDirectory.appending(path: randomPath) + let url = dataManager.wrappedValue.temporaryDirectory.appending(path: UUID().uuidString) try dataManager.wrappedValue.save(assetData, to: url) record[key] = CKAsset(fileURL: url) } diff --git a/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift b/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift index f53f36a2..d019ae9e 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/MockCloudDatabaseTests.swift @@ -48,31 +48,26 @@ @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) @Test func assetsUseTemporaryDirectory() async throws { - let temporaryDirectory = URL(fileURLWithPath: NSTemporaryDirectory()) - .appending(path: "sqlite-data-test-assets") - let dataManager = TemporaryDirectoryDataManager(temporaryDirectory: temporaryDirectory) - - let recordID = CKRecord.ID(recordName: "asset-record") - let record = CKRecord(recordType: "AssetRecord", recordID: recordID) - let sourceURL = temporaryDirectory.appending(path: "source") - try dataManager.save(Data("image".utf8), to: sourceURL) + let recordID = CKRecord.ID(recordName: "record") + let record = CKRecord(recordType: "Record", recordID: recordID) + let sourceURL = URL(fileURLWithPath: "/sqlite-data-test-assets/asset.jpg") + try inMemoryDataManager.save(Data("image".utf8), to: sourceURL) record["asset"] = CKAsset(fileURL: sourceURL) let database = syncEngine.private.database - try withDependencies { - $0.dataManager = dataManager - } operation: { - let (saveResults, _) = try database.modifyRecords( - saving: [record], - deleting: [] - ) - _ = try saveResults[recordID]?.get() - - let fetched = try database.record(for: recordID) - let asset = fetched["asset"] as? CKAsset - let assetDirectory = asset?.fileURL?.deletingLastPathComponent().path - #expect(assetDirectory == temporaryDirectory.path) - } + let (saveResults, _) = try database.modifyRecords( + saving: [record], + deleting: [] + ) + _ = try saveResults[recordID]?.get() + + let fetched = try database.record(for: recordID) + let asset = fetched["asset"] as? CKAsset + let assetDirectory = try #require(asset?.fileURL?.path()) + #expect( + assetDirectory + .hasPrefix(inMemoryDataManager.temporaryDirectory.path()) + ) } @available(iOS 17, macOS 14, tvOS 17, watchOS 10, *) From b4765a75093b5f3ac553ab4da38ed4ba90536016 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Fri, 6 Feb 2026 11:57:38 -0600 Subject: [PATCH 7/7] Update inline snapshots. --- Package.resolved | 4 ++-- Tests/SQLiteDataTests/CloudKitTests/AssetsTests.swift | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Package.resolved b/Package.resolved index 0bc1cf5d..1657463c 100644 --- a/Package.resolved +++ b/Package.resolved @@ -123,8 +123,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-snapshot-testing", "state" : { - "revision" : "cc051f1c07a414cf36b3d45fc8d00f2a8086ca5e", - "version" : "1.18.8" + "revision" : "bf8d8c27f0f0c6d5e77bff0db76ab68f2050d15d", + "version" : "1.18.9" } }, { diff --git a/Tests/SQLiteDataTests/CloudKitTests/AssetsTests.swift b/Tests/SQLiteDataTests/CloudKitTests/AssetsTests.swift index 7744f34b..95d1204d 100644 --- a/Tests/SQLiteDataTests/CloudKitTests/AssetsTests.swift +++ b/Tests/SQLiteDataTests/CloudKitTests/AssetsTests.swift @@ -37,7 +37,7 @@ coverImage_hash: Data(32 bytes), remindersListID: 1, coverImage: CKAsset( - fileURL: URL(file:///6105d6cc76af400325e94d588ce511be5bfdbb73b437dc51eca43917d7a43e3d), + fileURL: URL(file:///tmp/6105d6cc76af400325e94d588ce511be5bfdbb73b437dc51eca43917d7a43e3d), dataString: "image" ) ), @@ -61,7 +61,7 @@ inMemoryDataManager.storage.withValue { storage in let url = URL( - string: "file:///6105d6cc76af400325e94d588ce511be5bfdbb73b437dc51eca43917d7a43e3d" + string: "file:///tmp/6105d6cc76af400325e94d588ce511be5bfdbb73b437dc51eca43917d7a43e3d" )! #expect(storage[url] == Data("image".utf8)) } @@ -93,7 +93,7 @@ coverImage_hash: Data(32 bytes), remindersListID: 1, coverImage: CKAsset( - fileURL: URL(file:///97e67a5645969953f1a4cfe2ea75649864ff99789189cdd3f6db03e59f8a8ebf), + fileURL: URL(file:///tmp/97e67a5645969953f1a4cfe2ea75649864ff99789189cdd3f6db03e59f8a8ebf), dataString: "new-image" ) ), @@ -117,7 +117,7 @@ inMemoryDataManager.storage.withValue { storage in let url = URL( - string: "file:///97e67a5645969953f1a4cfe2ea75649864ff99789189cdd3f6db03e59f8a8ebf" + string: "file:///tmp/97e67a5645969953f1a4cfe2ea75649864ff99789189cdd3f6db03e59f8a8ebf" )! #expect(storage[url] == Data("new-image".utf8)) }