Three bugs caused all integration tests to fail with -Dmacos_fsevents=true:
- FSEventStreamCreate was passed *CallbackContext directly as the context
parameter, which expects *FSEventStreamContext (a struct with version=0,
info=ptr, retain/release/copyDescription). The handler pointer landed in
the version field (must be 0) and info received by callbacks was garbage,
so the callback returned immediately on every event.
- FSEvents coalesces operations into a single delivery with multiple flags
set (e.g. ItemCreated|ItemModified, ItemRenamed|ItemModified). The
callback used an if/else chain that only emitted the first matching event
type, so a write coalesced with a create or rename produced no 'modified'
event. Fixed by checking each flag independently.
- FSEvents delivers spurious historical events for watched root directories
at stream start (even with kFSEventStreamEventIdSinceNow), causing
phantom dir_created events. Fixed by snapshotting the watched root paths
in CallbackContext at arm() time and skipping events whose path exactly
matches a root.
Also: arm() is now a no-op when no paths are watched yet (stream starts on
the first add_watch call), add_watch/remove_watch restart the stream so
paths added or removed take effect immediately, and makeTempDir resolves
/tmp to /private/tmp on macOS so test-constructed paths match FSEvents
canonical output.
Using realpath() in watch() caused events to be emitted under the resolved
path (e.g. /private/tmp/...) rather than the path the caller provided (e.g.
/tmp/..., where /tmp is a symlink on macOS). This broke all integration
tests on macOS since the test file paths didn't match the emitted event
paths.
For absolute paths, use them unchanged. For relative paths, join with the
current working directory without further symlink resolution. This
preserves the caller's view of the path while still satisfying the kqueue
backend's requirement for absolute paths.