import AppKit import Foundation import Testing @testable import Haven private final class ManagerURLProtocol: URLProtocol, @unchecked Sendable { override class func canInit(with request: URLRequest) -> Bool { true } override class func canonicalRequest(for request: URLRequest) -> URLRequest { request } override func startLoading() { let path = request.url!.path let statusCode = path.contains("fail-http") ? 500 : 200 let data: Data if path.contains("image.png") { data = onePixelPNG } else if path.contains("invalid.png") { data = Data("not an image".utf8) } else { data = Data("wallpaper".utf8) } let response = HTTPURLResponse( url: request.url!, statusCode: statusCode, httpVersion: nil, headerFields: nil)! client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed) client?.urlProtocol(self, didLoad: data) client?.urlProtocolDidFinishLoading(self) } override func stopLoading() {} } private func managerSession() -> URLSession { let configuration = URLSessionConfiguration.ephemeral configuration.protocolClasses = [ManagerURLProtocol.self] return URLSession(configuration: configuration) } private let onePixelPNG = Data( base64Encoded: "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=" )! @MainActor private final class DesktopImageStub: DesktopImageSetting { var receivedURLs: [URL] = [] func setDesktopImageURL( _ url: URL, for screen: NSScreen, options: [NSWorkspace.DesktopImageOptionKey: Any] ) throws { receivedURLs.append(url) } } @Suite("Favorites persistence", .serialized) struct FavoritesManagerTests { private let defaultsKey = "favoriteWallpapers" @Test("Toggling adds and removes a favorite") func toggleFavorite() { UserDefaults.standard.removeObject(forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } let manager = FavoritesManager() let wallpaper = makeWallpaper() manager.toggleFavorite(wallpaper) #expect(manager.favorites == [wallpaper]) #expect(manager.isFavorite(wallpaper)) manager.toggleFavorite(wallpaper) #expect(manager.favorites.isEmpty) #expect(!manager.isFavorite(wallpaper)) } @Test("Favorites survive manager recreation") func favoritesPersist() { UserDefaults.standard.removeObject(forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } let wallpaper = makeWallpaper() FavoritesManager().toggleFavorite(wallpaper) let reloaded = FavoritesManager() #expect(reloaded.favorites == [wallpaper]) } /// Encoder that always fails. Subclassing JSONEncoder lets us keep the /// real `UserDefaults` and validation paths and only flip the encode side. final class ThrowingEncoder: JSONEncoder, @unchecked Sendable { let testError = NSError( domain: "test", code: 7, userInfo: [NSLocalizedDescriptionKey: "encode boom"]) override func encode(_ value: T) throws -> Data where T: Encodable { throw testError } } @Test("Encode failure surfaces through persistenceError without losing in-memory state") func encodeFailureIsSurfaced() { UserDefaults.standard.removeObject(forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } let manager = FavoritesManager(encoder: ThrowingEncoder()) manager.toggleFavorite(makeWallpaper()) #expect(manager.favorites.count == 1) #expect(manager.persistenceError?.contains("encode boom") == true) } @Test("Corrupt stored data surfaces through persistenceError on load") func corruptDataIsSurfaced() { UserDefaults.standard.set(Data("not wallpaper json".utf8), forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } let manager = FavoritesManager() #expect(manager.favorites.isEmpty) #expect(manager.persistenceError?.contains("Failed to load favorites") == true) } } @Suite("History persistence", .serialized) struct HistoryManagerTests { private let defaultsKey = "wallpaperHistory" @Test("History keeps newest items first and promotes duplicates") func orderingAndPromotion() { UserDefaults.standard.removeObject(forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } let manager = HistoryManager() let first = makeWallpaper(id: "first") let second = makeWallpaper(id: "second") manager.addToHistory(first) manager.addToHistory(second) manager.addToHistory(first) #expect(manager.history.map(\.id) == ["first", "second"]) } @Test("History is capped at fifty entries") func historyLimit() { UserDefaults.standard.removeObject(forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } let manager = HistoryManager() for index in 0..<55 { manager.addToHistory(makeWallpaper(id: "item-\(index)")) } #expect(manager.history.count == 50) #expect(manager.history.first?.id == "item-54") #expect(manager.history.last?.id == "item-5") } @Test("History survives recreation and clear removes persisted data") func persistenceAndClear() { UserDefaults.standard.removeObject(forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } HistoryManager().addToHistory(makeWallpaper(id: "persisted")) let reloaded = HistoryManager() #expect(reloaded.history.map(\.id) == ["persisted"]) reloaded.clearHistory() #expect(HistoryManager().history.isEmpty) } final class ThrowingEncoder: JSONEncoder, @unchecked Sendable { let testError = NSError( domain: "test", code: 9, userInfo: [NSLocalizedDescriptionKey: "history encode boom"]) override func encode(_ value: T) throws -> Data where T: Encodable { throw testError } } @Test("Encode failure surfaces through persistenceError without losing in-memory state") func encodeFailureIsSurfaced() { UserDefaults.standard.removeObject(forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } let manager = HistoryManager(encoder: ThrowingEncoder()) manager.addToHistory(makeWallpaper(id: "one")) manager.addToHistory(makeWallpaper(id: "two")) #expect(manager.history.count == 2) #expect(manager.persistenceError?.contains("history encode boom") == true) } @Test("Corrupt stored data surfaces through persistenceError on load") func corruptDataIsSurfaced() { UserDefaults.standard.set(Data("not history json".utf8), forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } let manager = HistoryManager() #expect(manager.history.isEmpty) #expect(manager.persistenceError?.contains("Failed to load history") == true) } @Test("clearHistory surfaces persistenceError when the encoder fails") func clearHistoryEncoderFailureIsSurfaced() { UserDefaults.standard.removeObject(forKey: defaultsKey) defer { UserDefaults.standard.removeObject(forKey: defaultsKey) } // Seed history first via the regular encoder so we know there's an // entry to clear. HistoryManager().addToHistory(makeWallpaper(id: "seeded")) let manager = HistoryManager(encoder: ThrowingEncoder()) manager.clearHistory() #expect(manager.history.isEmpty) #expect(manager.persistenceError?.contains("history encode boom") == true) } } @Suite("Image cache") struct ImageCacheTests { @Test("Inserted images are returned for the same URL") func insertAndRetrieve() { let url = URL(string: "https://example.com/\(UUID().uuidString).png")! let image = NSImage(size: NSSize(width: 10, height: 20)) ImageCache.shared.insertImage(image, for: url) #expect(ImageCache.shared.image(for: url) === image) } @Test("Different URLs do not collide") func keysDoNotCollide() { let base = UUID().uuidString let firstURL = URL(string: "https://example.com/\(base)-first.png")! let secondURL = URL(string: "https://example.com/\(base)-second.png")! ImageCache.shared.insertImage(NSImage(size: NSSize(width: 1, height: 1)), for: firstURL) #expect(ImageCache.shared.image(for: secondURL) == nil) } @Test("Fetch decodes and caches successful image responses") func fetchAndCache() async throws { let cache = ImageCache(session: managerSession()) let url = URL(string: "https://example.com/image.png")! let first = try await cache.fetchImage(url: url) let second = try await cache.fetchImage(url: url) #expect(first === second) } @Test("Fetch rejects HTTP errors and invalid image bytes") func fetchFailures() async { let cache = ImageCache(session: managerSession()) let httpError = URL(string: "https://example.com/fail-http.png")! let invalid = URL(string: "https://example.com/invalid.png")! await #expect(throws: WallhavenError.self) { try await cache.fetchImage(url: httpError) } await #expect(throws: WallhavenError.self) { try await cache.fetchImage(url: invalid) } } } @Suite("Wallpaper file management", .serialized) @MainActor struct WallpaperManagerTests { @Test("Download validates HTTP status and writes response data") func download() async throws { let manager = WallpaperManager(session: managerSession()) let url = URL(string: "https://example.com/\(UUID().uuidString).jpg")! let downloaded = try await manager.download(from: url) defer { try? FileManager.default.removeItem(at: downloaded) } #expect(try Data(contentsOf: downloaded) == Data("wallpaper".utf8)) let errorURL = URL(string: "https://example.com/fail-http.jpg")! await #expect(throws: WallhavenError.self) { try await manager.download(from: errorURL) } } @Test("Desktop setter receives explicit and default screens") @MainActor func desktopSetter() throws { guard let screen = NSScreen.screens.first else { return } var received: [NSScreen] = [] let manager = WallpaperManager(desktopSetter: { _, target in received.append(target) }) let url = URL(fileURLWithPath: "/tmp/test-wallpaper.jpg") try manager.setDesktopImage(from: url, screen: screen) try manager.setDesktopImage(from: url) #expect(received.count == 2) #expect(received[0] === screen) } @Test("Default desktop adapter forwards the image to its workspace") func defaultDesktopAdapter() throws { guard let screen = NSScreen.screens.first else { return } let workspace = DesktopImageStub() let manager = WallpaperManager(workspace: workspace) let url = URL(fileURLWithPath: "/tmp/test-wallpaper.jpg") try manager.setDesktopImage(from: url, screen: screen) #expect(workspace.receivedURLs == [url]) } @Test("Set wallpaper composes download and desktop update") @MainActor func setWallpaper() async throws { guard let screen = NSScreen.screens.first else { return } var receivedURL: URL? let manager = WallpaperManager( session: managerSession(), desktopSetter: { url, _ in receivedURL = url }) let remote = URL(string: "https://example.com/\(UUID().uuidString).jpg")! try await manager.setWallpaper(from: remote, screen: screen) defer { if let receivedURL { try? FileManager.default.removeItem(at: receivedURL) } } // Temp file uses a UUID stem (to avoid collisions) but preserves the // original extension so downstream consumers can identify the format. #expect(receivedURL?.pathExtension == remote.pathExtension) #expect(receivedURL?.lastPathComponent.hasPrefix("haven-") == true) #expect(receivedURL?.lastPathComponent != remote.lastPathComponent) #expect(try Data(contentsOf: receivedURL!) == Data("wallpaper".utf8)) } @Test("Saving creates the destination folder and copies the file") func saveCreatesFolderAndCopies() throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } let source = root.appendingPathComponent("source/wallpaper.jpg") let destination = root.appendingPathComponent("nested/destination") try FileManager.default.createDirectory( at: source.deletingLastPathComponent(), withIntermediateDirectories: true) try Data("first".utf8).write(to: source) try WallpaperManager.shared.saveToFolder(from: source, to: destination) let copied = try Data(contentsOf: destination.appendingPathComponent("wallpaper.jpg")) #expect(copied == Data("first".utf8)) } @Test("Saving replaces an existing file with fresh data") func saveReplacesExistingFile() throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } let source = root.appendingPathComponent("source/wallpaper.jpg") let destination = root.appendingPathComponent("destination") try FileManager.default.createDirectory( at: source.deletingLastPathComponent(), withIntermediateDirectories: true) try FileManager.default.createDirectory(at: destination, withIntermediateDirectories: true) try Data("new".utf8).write(to: source) try Data("old".utf8).write(to: destination.appendingPathComponent("wallpaper.jpg")) try WallpaperManager.shared.saveToFolder(from: source, to: destination) let copied = try Data(contentsOf: destination.appendingPathComponent("wallpaper.jpg")) #expect(copied == Data("new".utf8)) } @Test("Saving the same logical wallpaper leaves the existing file untouched") func saveSameContentIsIdempotent() throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } let source = root.appendingPathComponent("source/wallpaper.jpg") let destination = root.appendingPathComponent("destination") try FileManager.default.createDirectory( at: source.deletingLastPathComponent(), withIntermediateDirectories: true) try FileManager.default.createDirectory(at: destination, withIntermediateDirectories: true) try Data("identical".utf8).write(to: source) let existingURL = destination.appendingPathComponent("wallpaper.jpg") try Data("identical".utf8).write(to: existingURL) let originalAttributes = try FileManager.default.attributesOfItem(atPath: existingURL.path) try WallpaperManager.shared.saveToFolder(from: source, to: destination) let updatedAttributes = try FileManager.default.attributesOfItem(atPath: existingURL.path) #expect(try Data(contentsOf: existingURL) == Data("identical".utf8)) #expect( (updatedAttributes[.modificationDate] as? Date) == (originalAttributes[.modificationDate] as? Date) ) } @Test("Saving into the same path as the source does not destroy data") func saveSamePathAsSource() throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) let source = root.appendingPathComponent("wallpaper.jpg") try Data("payload".utf8).write(to: source) try WallpaperManager.shared.saveToFolder(from: source, to: root) #expect(try Data(contentsOf: source) == Data("payload".utf8)) } @Test("Distinct URLs sharing a lastPathComponent produce distinct temp files") func distinctDownloadsDoNotCollide() async throws { let manager = WallpaperManager(session: managerSession()) let first = URL(string: "https://example.com/aaa/wallpaper.jpg")! let second = URL(string: "https://example.com/bbb/wallpaper.jpg")! let firstFile = try await manager.download(from: first) let secondFile = try await manager.download(from: second) defer { try? FileManager.default.removeItem(at: firstFile) try? FileManager.default.removeItem(at: secondFile) } #expect(firstFile.path != secondFile.path) #expect(firstFile.lastPathComponent != secondFile.lastPathComponent) #expect(try Data(contentsOf: firstFile) == Data("wallpaper".utf8)) #expect(try Data(contentsOf: secondFile) == Data("wallpaper".utf8)) } @Test("Repeated downloads of the same URL produce independent temp files") func repeatedDownloadsAreIndependent() async throws { let manager = WallpaperManager(session: managerSession()) let remote = URL(string: "https://example.com/\(UUID().uuidString).jpg")! let first = try await manager.download(from: remote) let second = try await manager.download(from: remote) defer { try? FileManager.default.removeItem(at: first) try? FileManager.default.removeItem(at: second) } #expect(first.path != second.path) #expect(try Data(contentsOf: first) == Data("wallpaper".utf8)) #expect(try Data(contentsOf: second) == Data("wallpaper".utf8)) } @Test("makeTempURL preserves the source extension when present") func makeTempURLPreservesExtension() { let withExtension = URL(string: "https://example.com/foo/wallpaper.png")! let withoutExtension = URL(string: "https://example.com/foo/wallpaper")! #expect(WallpaperManager.makeTempURL(for: withExtension).pathExtension == "png") #expect(WallpaperManager.makeTempURL(for: withoutExtension).pathExtension == "img") #expect( WallpaperManager.makeTempURL(for: withExtension).path != WallpaperManager.makeTempURL(for: withExtension).path) } } @Suite("Autostart persistence", .serialized) @MainActor struct AutostartManagerTests { @Test("Enable writes a launch agent and disable removes it") func enableAndDisable() throws { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } let manager = AutostartManager( libraryDirectory: root, executablePath: { "/Applications/Haven.app/Contents/MacOS/Haven" }) #expect(!manager.isEnabled) manager.isEnabled = true #expect(manager.isEnabled) manager.isEnabled = true let plist = root.appendingPathComponent("LaunchAgents/com.june.Haven.plist") let contents = try PropertyListSerialization.propertyList( from: Data(contentsOf: plist), format: nil) as? [String: Any] #expect(contents?["Label"] as? String == "com.june.Haven") #expect( contents?["ProgramArguments"] as? [String] == ["/Applications/Haven.app/Contents/MacOS/Haven"]) #expect(contents?["RunAtLoad"] as? Bool == true) manager.isEnabled = false #expect(!manager.isEnabled) manager.isEnabled = false } @Test("Missing executable leaves autostart disabled") func missingExecutable() { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } let manager = AutostartManager(libraryDirectory: root, executablePath: { nil }) manager.isEnabled = true #expect(!manager.isEnabled) } @Test("Default executable provider writes only inside the injected library") func defaultExecutableProvider() { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } let manager = AutostartManager(libraryDirectory: root) manager.isEnabled = true #expect(manager.isEnabled) manager.isEnabled = false } @Test("Unwritable launch-agent roots do not enable autostart") func writeFailure() throws { let file = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: file) } try Data("not a directory".utf8).write(to: file) let manager = AutostartManager(libraryDirectory: file, executablePath: { "/tmp/Haven" }) manager.isEnabled = true #expect(!manager.isEnabled) } @Test("Removal failures leave the launch agent enabled") func removalFailure() { let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } let manager = AutostartManager( libraryDirectory: root, executablePath: { "/tmp/Haven" }, removePlist: { _ in throw CocoaError(.fileWriteNoPermission) }) manager.isEnabled = true manager.isEnabled = false #expect(manager.isEnabled) } } @Suite("Local wallpaper library", .serialized) @MainActor struct LocalWallpapersManagerTests { private func waitForScan(_ manager: LocalWallpapersManager) async { for _ in 0..<100 where manager.isLoading { try? await Task.sleep(nanoseconds: 10_000_000) } } @Test("Scan filters files, reads metadata, and deletes wallpapers") func scanAndDelete() async throws { let defaults = UserDefaults.standard let oldPath = defaults.string(forKey: "saveFolderPath") defaults.removeObject(forKey: "saveFolderPath") defer { if let oldPath { defaults.set(oldPath, forKey: "saveFolderPath") } else { defaults.removeObject(forKey: "saveFolderPath") } } let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) try onePixelPNG.write(to: root.appendingPathComponent("wallpaper.png")) try Data("broken".utf8).write(to: root.appendingPathComponent("broken.png")) try Data("ignored".utf8).write(to: root.appendingPathComponent("notes.txt")) let manager = LocalWallpapersManager() manager.scanFolder(path: root.path) manager.scanFolder(path: root.path) await waitForScan(manager) let wallpaper = try #require(manager.wallpapers.first) #expect(manager.wallpapers.count == 1) #expect(wallpaper.thumbnailURL == wallpaper.url) #expect(wallpaper.filename == "wallpaper.png") #expect(wallpaper.resolution == "1x1") #expect(LocalWallpapersManager.wallpaper(at: root.appendingPathComponent("broken.png")) == nil) #expect(LocalWallpapersManager.wallpaper(at: root.appendingPathComponent("missing.png")) == nil) manager.deleteWallpaper(wallpaper) #expect(manager.wallpapers.isEmpty) manager.deleteWallpaper(wallpaper) #expect(manager.errorMessage?.hasPrefix("Failed to delete") == true) } @Test("Invalid scan roots surface an error") func scanError() async throws { let defaults = UserDefaults.standard defaults.removeObject(forKey: "saveFolderPath") let file = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: file) } try Data("file".utf8).write(to: file) let manager = LocalWallpapersManager() manager.scanFolder(path: file.path) await waitForScan(manager) #expect(manager.errorMessage?.hasPrefix("Failed to scan folder") == true) #expect(!manager.isLoading) } @Test("Concurrent scan requests are dispatched, not silently dropped") func concurrentScansAreDispatched() async throws { let defaults = UserDefaults.standard let oldPath = defaults.string(forKey: "saveFolderPath") defaults.removeObject(forKey: "saveFolderPath") defer { if let oldPath { defaults.set(oldPath, forKey: "saveFolderPath") } else { defaults.removeObject(forKey: "saveFolderPath") } } let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) let manager = LocalWallpapersManager() // First explicit scan baseline on an empty folder. manager.scanFolder(path: root.path) await waitForScan(manager) #expect(manager.wallpapers.isEmpty) // Drop two files in succession. Each scan after a write must observe the // new file rather than be silently dropped because the previous one is // still in flight. try onePixelPNG.write(to: root.appendingPathComponent("first.png")) try onePixelPNG.write(to: root.appendingPathComponent("second.png")) manager.scanFolder(path: root.path) manager.scanFolder(path: root.path) await waitForScan(manager) #expect(manager.wallpapers.contains(where: { $0.filename == "first.png" })) #expect(manager.wallpapers.contains(where: { $0.filename == "second.png" })) #expect(!manager.isLoading) #expect(manager.errorMessage == nil) } @Test("Reissuing a scan during an in-flight scan observes later state via generation") func scanDuringFlightWinsForLatestGeneration() async throws { let defaults = UserDefaults.standard let oldPath = defaults.string(forKey: "saveFolderPath") defaults.removeObject(forKey: "saveFolderPath") defer { if let oldPath { defaults.set(oldPath, forKey: "saveFolderPath") } else { defaults.removeObject(forKey: "saveFolderPath") } } let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) defer { try? FileManager.default.removeItem(at: root) } try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) let manager = LocalWallpapersManager() // Issue three scans in rapid succession against an empty folder. Under // the old guard !isLoading logic, two of these would be silently // dropped; under the generation strategy all three are dispatched and // only the latest commits. The manager must still end up stable. manager.scanFolder(path: root.path) manager.scanFolder(path: root.path) manager.scanFolder(path: root.path) await waitForScan(manager) #expect(!manager.isLoading) #expect(manager.wallpapers.isEmpty) #expect(manager.errorMessage == nil) // Now write a file and trigger a new scan; the new scan must observe it. try onePixelPNG.write(to: root.appendingPathComponent("added.png")) manager.scanFolder(path: root.path) await waitForScan(manager) #expect(manager.wallpapers.contains(where: { $0.filename == "added.png" })) } @Test("Monitoring configured folders observes filesystem changes and stops") func monitoring() async throws { let defaults = UserDefaults.standard let oldPath = defaults.string(forKey: "saveFolderPath") let root = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) try FileManager.default.createDirectory(at: root, withIntermediateDirectories: true) defaults.set(root.path, forKey: "saveFolderPath") defer { try? FileManager.default.removeItem(at: root) if let oldPath { defaults.set(oldPath, forKey: "saveFolderPath") } else { defaults.removeObject(forKey: "saveFolderPath") } } let manager = LocalWallpapersManager() await waitForScan(manager) try onePixelPNG.write(to: root.appendingPathComponent("observed.png")) try? await Task.sleep(nanoseconds: 100_000_000) await waitForScan(manager) #expect(manager.wallpapers.contains(where: { $0.filename == "observed.png" })) manager.stopMonitoring() try? await Task.sleep(nanoseconds: 500_000_000) let invalidMonitor = FolderMonitor(folderPath: root.appendingPathComponent("missing").path) {} invalidMonitor.start() invalidMonitor.closeFileDescriptor() let descriptor = open("/dev/null", O_RDONLY) let descriptorMonitor = FolderMonitor( folderPath: "/dev/null", fileDescriptor: descriptor, callback: {}) descriptorMonitor.closeFileDescriptor() #expect(fcntl(descriptor, F_GETFD) == -1) } }