local helpers = require('test.functional.helpers')(after_each) local eq = helpers.eq local exec_lua = helpers.exec_lua local clear = helpers.clear local is_os = helpers.is_os local lfs = require('lfs') describe('vim._watch', function() before_each(function() clear() end) describe('watch', function() it('detects file changes', function() local root_dir = helpers.tmpname() os.remove(root_dir) lfs.mkdir(root_dir) local result = exec_lua( [[ local root_dir = ... local events = {} local expected_events = 0 local function wait_for_events() assert(vim.wait(100, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) end local stop = vim._watch.watch(root_dir, {}, function(path, change_type) table.insert(events, { path = path, change_type = change_type }) end) -- Only BSD seems to need some extra time for the watch to be ready to respond to events if vim.fn.has('bsd') then vim.wait(50) end local watched_path = root_dir .. '/file' local watched, err = io.open(watched_path, 'w') assert(not err, err) expected_events = expected_events + 1 wait_for_events() watched:close() os.remove(watched_path) expected_events = expected_events + 1 wait_for_events() stop() -- No events should come through anymore local watched_path = root_dir .. '/file' local watched, err = io.open(watched_path, 'w') assert(not err, err) vim.wait(50) watched:close() os.remove(watched_path) vim.wait(50) return events ]], root_dir ) local expected = { { change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), path = root_dir .. '/file', }, { change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), path = root_dir .. '/file', }, } -- kqueue only reports events on the watched path itself, so creating a file within a -- watched directory results in a "rename" libuv event on the directory. if is_os('bsd') then expected = { { change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), path = root_dir, }, { change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), path = root_dir, }, } end eq(expected, result) end) end) describe('poll', function() it('detects file changes', function() local root_dir = helpers.tmpname() os.remove(root_dir) lfs.mkdir(root_dir) local result = exec_lua( [[ local root_dir = ... local events = {} local poll_interval_ms = 1000 local poll_wait_ms = poll_interval_ms+200 local expected_events = 0 local function wait_for_events() assert(vim.wait(poll_wait_ms, function() return #events == expected_events end), 'Timed out waiting for expected number of events. Current events seen so far: ' .. vim.inspect(events)) end local stop = vim._watch.poll(root_dir, { interval = poll_interval_ms }, function(path, change_type) table.insert(events, { path = path, change_type = change_type }) end) -- polling generates Created events for the existing entries when it starts. expected_events = expected_events + 1 wait_for_events() local watched_path = root_dir .. '/file' local watched, err = io.open(watched_path, 'w') assert(not err, err) expected_events = expected_events + 2 wait_for_events() watched:close() os.remove(watched_path) expected_events = expected_events + 2 wait_for_events() stop() -- No events should come through anymore local watched_path = root_dir .. '/file' local watched, err = io.open(watched_path, 'w') assert(not err, err) vim.wait(poll_wait_ms) watched:close() os.remove(watched_path) return events ]], root_dir ) eq(5, #result) eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), path = root_dir, }, result[1]) eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Created]]), path = root_dir .. '/file', }, result[2]) eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), path = root_dir, }, result[3]) -- The file delete and corresponding directory change events do not happen in any -- particular order, so allow either if result[4].path == root_dir then eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), path = root_dir, }, result[4]) eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), path = root_dir .. '/file', }, result[5]) else eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Deleted]]), path = root_dir .. '/file', }, result[4]) eq({ change_type = exec_lua([[return vim._watch.FileChangeType.Changed]]), path = root_dir, }, result[5]) end end) end) end)