diff --git a/tests/unit/Watchers/FSNotifierTest.swift b/tests/unit/Watchers/FSNotifierTest.swift index 26ca1ad2..fd59c3e5 100644 --- a/tests/unit/Watchers/FSNotifierTest.swift +++ b/tests/unit/Watchers/FSNotifierTest.swift @@ -11,37 +11,33 @@ import Foundation @Suite(.serialized) struct FSNotifierTest { - /** - This test verifies that FSNotifier fires the onChange callback when a file is modified. - */ - @Test func notifier_fires_when_file_is_modified_and_debounces_correctly() async throws { + + @Test func notifier_fires_when_file_is_modified() async throws { // Create a temporary file to monitor let tempDir = FileManager.default.temporaryDirectory let testFile = tempDir.appendingPathComponent("fs_notifier_test_\(UUID().uuidString).txt") FileManager.default.createFile(atPath: testFile.path, contents: nil) - defer { - try? FileManager.default.removeItem(at: testFile) - } - + // Our variable to keep track of let eventFired = Locked(0) + + // Our debouncer let debouncer = Debouncer() - // Create notifier - let notifier = FSNotifier( - for: testFile, - eventMask: .write, - onChange: { - Task { - // Debouncer is an actor so this is allowed - await debouncer.debounce(for: 1.0) { - eventFired.value += 1 - } - } - } - ) + // Set up the notifier + let notifier = FSNotifier(for: testFile, eventMask: .write, onChange: { + Task { await debouncer.debounce(for: 1.0) { + eventFired.value += 1 + }} + }) - // Modify the file, twice + // Cleanup for later + defer { + try? FileManager.default.removeItem(at: testFile) + notifier.terminate() + } + + // Modify the file, twice, debounce should work try "hello".write(to: testFile, atomically: false, encoding: .utf8) try "hello".write(to: testFile, atomically: false, encoding: .utf8) @@ -55,8 +51,52 @@ struct FSNotifierTest { // Verify after another second, our second write is actually noted await delay(seconds: 1.2) #expect(eventFired.value == 2) + } - // Clean up notifier - notifier.terminate() + @Test func notifier_suspends_and_resumes_correctly() async throws { + // Create a temporary file to monitor + let tempDir = FileManager.default.temporaryDirectory + let testFile = tempDir.appendingPathComponent("fs_notifier_test_\(UUID().uuidString).txt") + FileManager.default.createFile(atPath: testFile.path, contents: nil) + + // Our variable to keep track of + let eventFired = Locked(0) + + // Create notifier + let notifier = FSNotifier(for: testFile, eventMask: .write, onChange: { + Task { eventFired.value += 1 } + }) + + // Cleanup for later + defer { + try? FileManager.default.removeItem(at: testFile) + notifier.terminate() + } + + // Modify the file, twice + try "hello".write(to: testFile, atomically: false, encoding: .utf8) + await delay(seconds: 0.2) + #expect(eventFired.value == 1) + + // Try to write again (after debounce timing) + try "hello".write(to: testFile, atomically: false, encoding: .utf8) + await delay(seconds: 0.2) + #expect(eventFired.value == 2) + + // Now, we will suspend + await notifier.suspend() + + // Despite writing to the file, our event did not fire + try "hello".write(to: testFile, atomically: false, encoding: .utf8) + await delay(seconds: 0.2) + #expect(eventFired.value == 2) + + // Now, we will resume + await notifier.resume() + + // Our event should have fired again + try "hello".write(to: testFile, atomically: false, encoding: .utf8) + await delay(seconds: 0.2) + #expect(eventFired.value == 3) } }