From 0abb4170363572277303ae9ba7389050d164e532 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 8 Sep 2026 10:27:35 +1000 Subject: [PATCH 001/154] test: neovim functional test integration and example test --- scripts/functionaltest.sh | 52 ++++++++++++++++++++++++++++++ test/func/api/open.lua | 67 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100755 scripts/functionaltest.sh create mode 100644 test/func/api/open.lua diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh new file mode 100755 index 00000000000..520b1e25ef7 --- /dev/null +++ b/scripts/functionaltest.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env sh + +set -e + +# neovim source +DIR_NVIM_SRC_DEF="/tmp/src/neovim-stable" + +cleanup() { + rm -fv "${DIR_NVT_PACK}" +} + +# TODO extract common functionality from vimdoc.sh +if [ ! -d "lua/nvim-tree" ]; then + echo "Must be run from nvim-tree root" 1>&2 + exit 1 +fi + +if [ -z "${DIR_NVIM_SRC}" ] && [ -d "${DIR_NVIM_SRC_DEF}" ]; then + export DIR_NVIM_SRC="${DIR_NVIM_SRC_DEF}" +fi + +if [ ! -d "${DIR_NVIM_SRC}" ]; then + cat << EOM + +Nvim stable source is required to run ${0} + +Unavailable: ${DIR_NVIM_SRC_DEF} or \$DIR_NVIM_SRC=${DIR_NVIM_SRC} + +Please: + mkdir -p ${DIR_NVIM_SRC_DEF} + curl -L 'https://github.com/neovim/neovim/archive/refs/tags/stable.tar.gz' | tar zx --directory $(dirname "${DIR_NVIM_SRC_DEF}") + or use your own e.g. + export DIR_NVIM_SRC="\${HOME}/src/neovim" + +EOM +exit 1 +fi + +# nvim-tree linked as a package for the tests to add before run +DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" + +cleanup + +ln -sv "${PWD}" "${DIR_NVT_PACK}" + +cd "${DIR_NVIM_SRC}" + +make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/api/open.lua" + +cd - + +cleanup diff --git a/test/func/api/open.lua b/test/func/api/open.lua new file mode 100644 index 00000000000..272a975ebf0 --- /dev/null +++ b/test/func/api/open.lua @@ -0,0 +1,67 @@ +-- TODO lsp defs for test utils + +local t = require('test.testutil') +local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') +local clear = n.clear +local command = n.command +local exec_lua = n.exec_lua + +describe('example', function() + --- @type test.functional.ui.screen + local screen + + setup(function() + clear({ args_rm = { '-u' } }) + + -- TODO add package from the real location, not the link runtime/pack/dist/opt/nvim-tree.lua + command('packadd nvim-tree.lua') + screen = Screen.new(40, 20) + end) + + before_each(function() + -- TODO think about copying contents of an actual directory into tmp rather than copying + local tmp = t.tmpname(false) + assert(t.mkdir(tmp)) + t.write_file(tmp .. '/file1', 'foo', true) + t.write_file(tmp .. '/file2', 'bar', true) + assert(t.mkdir(tmp .. '/dir1')) + + command(':cd ' .. tmp) + + -- TODO try and use a function, not a lua string, if we have luals issues + exec_lua([[ + require("nvim-tree").setup({ + renderer = { + root_folder_label = false, + }, + }) + ]]) + end) + + it('api_tree_open', function() + exec_lua([[ + local api = require("nvim-tree.api") + api.tree.open() + ]]) + + -- TODO use the complete set of nvim-tree HighlightGroup as test.functional.ui.screen.hl_groups + screen:add_extra_attr_ids({ + [100] = { background = Screen.colors.Grey90, foreground = tonumber('0x8094b4') }, + [101] = { background = Screen.colors.Grey90, foreground = Screen.colors.Blue }, + [102] = { foreground = tonumber('0x8094b4') }, + }) + + -- screen:snapshot_util() + + -- TODO use a grid + screen:expect([[ + {100:^ }{21: }{101:dir1}{21: }│ | + {102: } file1 │{1:~ }| + {102: } file2 │{1:~ }| + {1:~ }│{1:~ }|*15 + {3:NvimTree_1 [-] }{2: Date: Tue, 8 Sep 2026 10:34:06 +1000 Subject: [PATCH 002/154] test: add luals library for functionaltest framework --- .luarc.json | 4 +++- test/func/api/open.lua | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.luarc.json b/.luarc.json index 6a2d3d63eb2..0d37b497064 100644 --- a/.luarc.json +++ b/.luarc.json @@ -4,7 +4,9 @@ "workspace": { "library": [ "$VIMRUNTIME/lua/vim", - "${3rd}/luv/library" + "${3rd}/luv/library", + "${DIR_NVIM_SRC}/test", + "/tmp/src/neovim-stable/test" ] }, "format": { diff --git a/test/func/api/open.lua b/test/func/api/open.lua index 272a975ebf0..3fbbf01a440 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -1,5 +1,3 @@ --- TODO lsp defs for test utils - local t = require('test.testutil') local n = require('test.functional.testnvim')() local Screen = require('test.functional.ui.screen') From ada63370f6c7816bc05451de485ed5a210821827 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 8 Sep 2026 12:53:05 +1000 Subject: [PATCH 003/154] test: add NvimTree* hl group handling to functionaltest --- scripts/functionaltest.sh | 2 + test/func/api/open.lua | 80 ++++++++++++++++++++++++++------------- 2 files changed, 55 insertions(+), 27 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 520b1e25ef7..ade8a4ab187 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -1,5 +1,7 @@ #!/usr/bin/env sh +# TODO this will be shipped as part of the vim runtime https://github.com/neovim/neovim/issues/34592 + set -e # neovim source diff --git a/test/func/api/open.lua b/test/func/api/open.lua index 3fbbf01a440..96e92f2090d 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -1,19 +1,19 @@ -local t = require('test.testutil') -local n = require('test.functional.testnvim')() -local Screen = require('test.functional.ui.screen') +local t = require("test.testutil") +local n = require("test.functional.testnvim")() +local Screen = require("test.functional.ui.screen") local clear = n.clear local command = n.command local exec_lua = n.exec_lua -describe('example', function() +describe("api_open", function() --- @type test.functional.ui.screen local screen setup(function() - clear({ args_rm = { '-u' } }) + clear({ args_rm = { "-u" } }) + + command("packadd nvim-tree.lua") - -- TODO add package from the real location, not the link runtime/pack/dist/opt/nvim-tree.lua - command('packadd nvim-tree.lua') screen = Screen.new(40, 20) end) @@ -21,11 +21,12 @@ describe('example', function() -- TODO think about copying contents of an actual directory into tmp rather than copying local tmp = t.tmpname(false) assert(t.mkdir(tmp)) - t.write_file(tmp .. '/file1', 'foo', true) - t.write_file(tmp .. '/file2', 'bar', true) - assert(t.mkdir(tmp .. '/dir1')) + t.write_file(tmp .. "/file1", "foo", true) + t.write_file(tmp .. "/file2", "bar", true) + assert(t.mkdir(tmp .. "/dir1")) + assert(t.mkdir(tmp .. "/dir2")) - command(':cd ' .. tmp) + command(":cd " .. tmp) -- TODO try and use a function, not a lua string, if we have luals issues exec_lua([[ @@ -37,29 +38,54 @@ describe('example', function() ]]) end) - it('api_tree_open', function() + local function nvt_hl_attr_ids(hl_groups) + local attr_ids = {} + + -- build the cursor line first + local hl_cursor_line = n.api.nvim_get_hl(0, { name = "NvimTreeCursorLine", link = false }) + assert(hl_cursor_line) + local attr_cursor_line = { foreground = hl_cursor_line.fg, background = hl_cursor_line.bg } + attr_ids["NvimTreeCursorLine"] = attr_cursor_line + + for group in pairs(n.api.nvim_get_hl(0, {})) do + if vim.tbl_contains(hl_groups, group) and group ~= "NvimTreeCursorLine" then + -- add the group's concrete definition + local hl = n.api.nvim_get_hl(0, { name = group, link = false }) + local attr = { foreground = hl.fg, background = hl.bg } + attr_ids[group] = attr + + -- create a CL variant if background differs + if attr.background ~= attr_cursor_line.background then + attr_ids[group .. "CL"] = vim.tbl_extend("force", attr_ids[group], attr_ids["NvimTreeCursorLine"]) + end + end + end + + return attr_ids + end + + it("api_tree_open_populated", function() exec_lua([[ local api = require("nvim-tree.api") api.tree.open() ]]) - -- TODO use the complete set of nvim-tree HighlightGroup as test.functional.ui.screen.hl_groups - screen:add_extra_attr_ids({ - [100] = { background = Screen.colors.Grey90, foreground = tonumber('0x8094b4') }, - [101] = { background = Screen.colors.Grey90, foreground = Screen.colors.Blue }, - [102] = { foreground = tonumber('0x8094b4') }, - }) - - -- screen:snapshot_util() + screen:add_extra_attr_ids(nvt_hl_attr_ids({ + "NvimTreeFolderName", + "NvimTreeFolderIcon", + "NvimTreeCursorLine", + })) - -- TODO use a grid - screen:expect([[ - {100:^ }{21: }{101:dir1}{21: }│ | - {102: } file1 │{1:~ }| - {102: } file2 │{1:~ }| - {1:~ }│{1:~ }|*15 + screen:expect({ + grid = [[ + {NvimTreeFolderIconCL:^ }{NvimTreeCursorLine: }{NvimTreeFolderNameCL:dir1}{NvimTreeCursorLine: }│ | + {NvimTreeFolderIcon: } {NvimTreeFolderName:dir2} │{1:~ }| + {NvimTreeFolderIcon: } file1 │{1:~ }| + {NvimTreeFolderIcon: } file2 │{1:~ }| + {1:~ }│{1:~ }|*14 {3:NvimTree_1 [-] }{2: Date: Wed, 9 Sep 2026 12:25:40 +1000 Subject: [PATCH 004/154] test: add luals library for functionaltest framework --- .luarc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.luarc.json b/.luarc.json index 0d37b497064..6d0a620bce1 100644 --- a/.luarc.json +++ b/.luarc.json @@ -5,7 +5,7 @@ "library": [ "$VIMRUNTIME/lua/vim", "${3rd}/luv/library", - "${DIR_NVIM_SRC}/test", + "$DIR_NVIM_SRC/test", "/tmp/src/neovim-stable/test" ] }, From 12610d6ed6f2e33438cd0b9507136a3c1084a37e Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 10 Sep 2026 11:19:14 +1000 Subject: [PATCH 005/154] test: create unique NvimTree HL group definitions --- test/func/api/open.lua | 62 ++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/test/func/api/open.lua b/test/func/api/open.lua index 96e92f2090d..850080fccc9 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -10,6 +10,7 @@ describe("api_open", function() local screen setup(function() + -- TODO this can be done without -u and a direct vim.pack.add clear({ args_rm = { "-u" } }) command("packadd nvim-tree.lua") @@ -38,26 +39,43 @@ describe("api_open", function() ]]) end) - local function nvt_hl_attr_ids(hl_groups) + local function nvt_hl_attr_ids() local attr_ids = {} - -- build the cursor line first + -- build the cursor line first, background only local hl_cursor_line = n.api.nvim_get_hl(0, { name = "NvimTreeCursorLine", link = false }) assert(hl_cursor_line) - local attr_cursor_line = { foreground = hl_cursor_line.fg, background = hl_cursor_line.bg } + local attr_cursor_line = { background = hl_cursor_line.bg } attr_ids["NvimTreeCursorLine"] = attr_cursor_line - for group in pairs(n.api.nvim_get_hl(0, {})) do - if vim.tbl_contains(hl_groups, group) and group ~= "NvimTreeCursorLine" then - -- add the group's concrete definition - local hl = n.api.nvim_get_hl(0, { name = group, link = false }) - local attr = { foreground = hl.fg, background = hl.bg } - attr_ids[group] = attr + -- unique colour for each group, descending from #fefefe + local i = 1 + local r, g, b = 254, 254, 254 - -- create a CL variant if background differs - if attr.background ~= attr_cursor_line.background then - attr_ids[group .. "CL"] = vim.tbl_extend("force", attr_ids[group], attr_ids["NvimTreeCursorLine"]) + for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do + if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") then + local rgb = r * 256 * 256 + g * 256 + b + i = i + 1 + if (i % 256 == 0) then + b = 254 + g = 254 + r = r - 1 + elseif (i % 16 == 0) then + b = 254 + g = g - 1 + else + b = b - 1 end + -- print(string.format("#%x", rgb)) + + -- add the group's concrete definition with fg only + local attr = { foreground = rgb } + attr_ids[group] = attr + n.api.nvim_set_hl(0, group, { fg = string.format("#%x", rgb) }) + + -- create an NvimTreeCursorLine variant + attr_ids[group .. "CL"] = { foreground = rgb, background = hl_cursor_line.bg } + n.api.nvim_set_hl(0, group .. "CL", { fg = string.format("#%x", rgb), bg = string.format("#%x", hl_cursor_line.bg) }) end end @@ -70,20 +88,18 @@ describe("api_open", function() api.tree.open() ]]) - screen:add_extra_attr_ids(nvt_hl_attr_ids({ - "NvimTreeFolderName", - "NvimTreeFolderIcon", - "NvimTreeCursorLine", - })) + -- TODO this takes some time to execute + screen:add_extra_attr_ids(nvt_hl_attr_ids()) + -- TODO why does file have NvimTreeFolderArrowClosed ? screen:expect({ grid = [[ - {NvimTreeFolderIconCL:^ }{NvimTreeCursorLine: }{NvimTreeFolderNameCL:dir1}{NvimTreeCursorLine: }│ | - {NvimTreeFolderIcon: } {NvimTreeFolderName:dir2} │{1:~ }| - {NvimTreeFolderIcon: } file1 │{1:~ }| - {NvimTreeFolderIcon: } file2 │{1:~ }| - {1:~ }│{1:~ }|*14 - {3:NvimTree_1 [-] }{2: Date: Thu, 10 Sep 2026 12:11:37 +1000 Subject: [PATCH 006/154] test: create unique NvimTree HL group definitions --- test/func/api/open.lua | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/test/func/api/open.lua b/test/func/api/open.lua index 850080fccc9..3a4343580b1 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -42,19 +42,23 @@ describe("api_open", function() local function nvt_hl_attr_ids() local attr_ids = {} + -- math.random(tonumber('0x707070'),tonumber('0x909090')) + local bg_rgb, bg_hex = 8758352, "#85a450" + -- build the cursor line first, background only - local hl_cursor_line = n.api.nvim_get_hl(0, { name = "NvimTreeCursorLine", link = false }) - assert(hl_cursor_line) - local attr_cursor_line = { background = hl_cursor_line.bg } - attr_ids["NvimTreeCursorLine"] = attr_cursor_line + attr_ids["NvimTreeCursorLine"] = { background = bg_rgb } + n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = bg_hex }) -- unique colour for each group, descending from #fefefe - local i = 1 - local r, g, b = 254, 254, 254 + local i, r, g, b = 1, 254, 254, 254 + local rgb, hex for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") then - local rgb = r * 256 * 256 + g * 256 + b + + -- next unique fg colour + rgb = r * 256 * 256 + g * 256 + b + hex = string.format("#%x", rgb) i = i + 1 if (i % 256 == 0) then b = 254 @@ -66,16 +70,14 @@ describe("api_open", function() else b = b - 1 end - -- print(string.format("#%x", rgb)) -- add the group's concrete definition with fg only - local attr = { foreground = rgb } - attr_ids[group] = attr - n.api.nvim_set_hl(0, group, { fg = string.format("#%x", rgb) }) + attr_ids[group] = { foreground = rgb } + n.api.nvim_set_hl(0, group, { fg = hex }) -- create an NvimTreeCursorLine variant - attr_ids[group .. "CL"] = { foreground = rgb, background = hl_cursor_line.bg } - n.api.nvim_set_hl(0, group .. "CL", { fg = string.format("#%x", rgb), bg = string.format("#%x", hl_cursor_line.bg) }) + attr_ids[group .. "CL"] = { foreground = rgb, background = bg_rgb } + n.api.nvim_set_hl(0, group .. "CL", { fg = hex, bg = bg_hex }) end end @@ -88,10 +90,11 @@ describe("api_open", function() api.tree.open() ]]) - -- TODO this takes some time to execute - screen:add_extra_attr_ids(nvt_hl_attr_ids()) + -- TODO setting all hl groups causes expect to take much longer to execute + local attr_ids = nvt_hl_attr_ids() + screen:add_extra_attr_ids(attr_ids) - -- TODO why does file have NvimTreeFolderArrowClosed ? + -- TODO NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode screen:expect({ grid = [[ {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeEmptyFolderNameCL:dir1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | From db732e6c2b0003e57d9b8cdea504286377daddc4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 10 Sep 2026 12:58:13 +1000 Subject: [PATCH 007/154] test: refactor functional test lifecycle, add another test --- test/func/api/open.lua | 146 +++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 64 deletions(-) diff --git a/test/func/api/open.lua b/test/func/api/open.lua index 3a4343580b1..3d2c4d84c6a 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -2,9 +2,52 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear -local command = n.command local exec_lua = n.exec_lua +local function nvt_hl_attr_ids(screen) + local attr_ids = {} + + -- math.random(tonumber('0x707070'),tonumber('0x909090')) + local bg_rgb, bg_hex = 8758352, "#85a450" + + -- build the cursor line first, background only + attr_ids["NvimTreeCursorLine"] = { background = bg_rgb } + n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = bg_hex }) + + -- unique colour for each group, descending from #fefefe + local i, r, g, b = 1, 254, 254, 254 + local rgb, hex + + for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do + if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") then + -- next unique fg colour + rgb = r * 256 * 256 + g * 256 + b + hex = string.format("#%x", rgb) + i = i + 1 + if (i % 256 == 0) then + b = 254 + g = 254 + r = r - 1 + elseif (i % 16 == 0) then + b = 254 + g = g - 1 + else + b = b - 1 + end + + -- add the group's concrete definition with fg only + attr_ids[group] = { foreground = rgb } + n.api.nvim_set_hl(0, group, { fg = hex }) + + -- create an NvimTreeCursorLine variant + attr_ids[group .. "CL"] = { foreground = rgb, background = bg_rgb } + n.api.nvim_set_hl(0, group .. "CL", { fg = hex, bg = bg_hex }) + end + end + + screen:add_extra_attr_ids(attr_ids) +end + describe("api_open", function() --- @type test.functional.ui.screen local screen @@ -13,9 +56,20 @@ describe("api_open", function() -- TODO this can be done without -u and a direct vim.pack.add clear({ args_rm = { "-u" } }) - command("packadd nvim-tree.lua") + n.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) screen = Screen.new(40, 20) + + exec_lua(function() + require("nvim-tree").setup({ + renderer = { + root_folder_label = false, + }, + }) + end) + + -- TODO setting all hl groups causes expect to take much longer to execute + nvt_hl_attr_ids(screen) end) before_each(function() @@ -27,72 +81,14 @@ describe("api_open", function() assert(t.mkdir(tmp .. "/dir1")) assert(t.mkdir(tmp .. "/dir2")) - command(":cd " .. tmp) - - -- TODO try and use a function, not a lua string, if we have luals issues - exec_lua([[ - require("nvim-tree").setup({ - renderer = { - root_folder_label = false, - }, - }) - ]]) + n.api.nvim_cmd({ cmd = "cd", args = { tmp } }, {}) end) - local function nvt_hl_attr_ids() - local attr_ids = {} - - -- math.random(tonumber('0x707070'),tonumber('0x909090')) - local bg_rgb, bg_hex = 8758352, "#85a450" - - -- build the cursor line first, background only - attr_ids["NvimTreeCursorLine"] = { background = bg_rgb } - n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = bg_hex }) - - -- unique colour for each group, descending from #fefefe - local i, r, g, b = 1, 254, 254, 254 - local rgb, hex - - for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do - if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") then - - -- next unique fg colour - rgb = r * 256 * 256 + g * 256 + b - hex = string.format("#%x", rgb) - i = i + 1 - if (i % 256 == 0) then - b = 254 - g = 254 - r = r - 1 - elseif (i % 16 == 0) then - b = 254 - g = g - 1 - else - b = b - 1 - end - - -- add the group's concrete definition with fg only - attr_ids[group] = { foreground = rgb } - n.api.nvim_set_hl(0, group, { fg = hex }) - - -- create an NvimTreeCursorLine variant - attr_ids[group .. "CL"] = { foreground = rgb, background = bg_rgb } - n.api.nvim_set_hl(0, group .. "CL", { fg = hex, bg = bg_hex }) - end - end - - return attr_ids - end - - it("api_tree_open_populated", function() - exec_lua([[ + it("api_tree_open_populated_focussed", function() + exec_lua(function() local api = require("nvim-tree.api") api.tree.open() - ]]) - - -- TODO setting all hl groups causes expect to take much longer to execute - local attr_ids = nvt_hl_attr_ids() - screen:add_extra_attr_ids(attr_ids) + end) -- TODO NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode screen:expect({ @@ -107,4 +103,26 @@ describe("api_open", function() ]], }) end) + + it("api_tree_open_populated_unfocussed", function() + -- TODO consider resetting tree after each test, they are order dependent + -- exec_lua(function() + -- local api = require("nvim-tree.api") + -- api.tree.open() + -- end) + + n.feed("") + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeEmptyFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}^ | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*14 + {NvimTreeStatusLineNC:NvimTree_1 [-] }{3:[No Name] }| + | + ]], + }) + end) end) From 5a8deb11445b5a64dc360efb13277d3af65179ee Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 10 Sep 2026 13:11:19 +1000 Subject: [PATCH 008/154] test: simplify package loading --- test/func/api/open.lua | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test/func/api/open.lua b/test/func/api/open.lua index 3d2c4d84c6a..f06ef27b871 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -53,14 +53,11 @@ describe("api_open", function() local screen setup(function() - -- TODO this can be done without -u and a direct vim.pack.add - clear({ args_rm = { "-u" } }) - - n.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) - - screen = Screen.new(40, 20) + clear() exec_lua(function() + vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) + require("nvim-tree").setup({ renderer = { root_folder_label = false, @@ -68,7 +65,8 @@ describe("api_open", function() }) end) - -- TODO setting all hl groups causes expect to take much longer to execute + screen = Screen.new(40, 20) + nvt_hl_attr_ids(screen) end) From 9b7c91e26f3f1e6ec10421a28b64da6ecbd4e6ba Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 11 Sep 2026 10:55:50 +1000 Subject: [PATCH 009/154] test: add text-only functional test --- scripts/functionaltest.sh | 17 +++++++---- test/func/api/open.lua | 64 +++++++++++++++++++++++++++++++++------ 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index ade8a4ab187..7fb13902b29 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -4,15 +4,21 @@ set -e +# code under test +DIR_NVT="${PWD}" + # neovim source DIR_NVIM_SRC_DEF="/tmp/src/neovim-stable" +# nvim-tree linked as a package for the tests to add before run +DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" + cleanup() { rm -fv "${DIR_NVT_PACK}" } # TODO extract common functionality from vimdoc.sh -if [ ! -d "lua/nvim-tree" ]; then +if [ ! -d "${DIR_NVT}/lua/nvim-tree" ]; then echo "Must be run from nvim-tree root" 1>&2 exit 1 fi @@ -38,15 +44,14 @@ EOM exit 1 fi -# nvim-tree linked as a package for the tests to add before run -DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" - cleanup -ln -sv "${PWD}" "${DIR_NVT_PACK}" - cd "${DIR_NVIM_SRC}" +make + +ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" + make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/api/open.lua" cd - diff --git a/test/func/api/open.lua b/test/func/api/open.lua index f06ef27b871..9008bdbd91a 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -3,6 +3,7 @@ local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear local exec_lua = n.exec_lua +local command = n.command local function nvt_hl_attr_ids(screen) local attr_ids = {} @@ -57,7 +58,9 @@ describe("api_open", function() exec_lua(function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) + end) + exec_lua(function() require("nvim-tree").setup({ renderer = { root_folder_label = false, @@ -79,13 +82,55 @@ describe("api_open", function() assert(t.mkdir(tmp .. "/dir1")) assert(t.mkdir(tmp .. "/dir2")) - n.api.nvim_cmd({ cmd = "cd", args = { tmp } }, {}) + -- n.api.nvim_cmd({ cmd = "cd", args = { tmp } }, {}) + command("sil cd " .. tmp) + + exec_lua(function() + require("nvim-tree").setup({ + renderer = { + root_folder_label = false, + }, + }) + end) + end) + + it("api_tree_open_populated_unfocussed_text_only", function() + exec_lua(function() + require("nvim-tree.api").tree.open() + end) + + n.feed("") + + screen:expect({ + attr_ids = {}, + grid = [[ +   dir1 │^ | +   dir2 │~ | +  file1 │~ | +  file2 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +NvimTree_1 [-] [No Name] | + | + ]], + }) end) it("api_tree_open_populated_focussed", function() exec_lua(function() - local api = require("nvim-tree.api") - api.tree.open() + require("nvim-tree.api").tree.open() end) -- TODO NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode @@ -103,18 +148,17 @@ describe("api_open", function() end) it("api_tree_open_populated_unfocussed", function() - -- TODO consider resetting tree after each test, they are order dependent - -- exec_lua(function() - -- local api = require("nvim-tree.api") - -- api.tree.open() - -- end) + exec_lua(function() + require("nvim-tree.api").tree.open() + end) + n.feed("") n.feed("") screen:expect({ grid = [[ - {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeEmptyFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}^ | - {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeEmptyFolderName:dir1}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeEmptyFolderNameCL:dir2}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*14 From 6c235bdff4b6fea74e4884d2131f58847ae16017 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 11 Sep 2026 11:20:03 +1000 Subject: [PATCH 010/154] test: Screen 80 x 25 for more deterministic window sizes --- test/func/api/open.lua | 81 ++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/test/func/api/open.lua b/test/func/api/open.lua index 9008bdbd91a..3897e9a0139 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -3,7 +3,6 @@ local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear local exec_lua = n.exec_lua -local command = n.command local function nvt_hl_attr_ids(screen) local attr_ids = {} @@ -56,6 +55,8 @@ describe("api_open", function() setup(function() clear() + screen = Screen.new(80, 25) + exec_lua(function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) @@ -68,8 +69,6 @@ describe("api_open", function() }) end) - screen = Screen.new(40, 20) - nvt_hl_attr_ids(screen) end) @@ -82,8 +81,7 @@ describe("api_open", function() assert(t.mkdir(tmp .. "/dir1")) assert(t.mkdir(tmp .. "/dir2")) - -- n.api.nvim_cmd({ cmd = "cd", args = { tmp } }, {}) - command("sil cd " .. tmp) + n.api.nvim_set_current_dir(tmp) exec_lua(function() require("nvim-tree").setup({ @@ -104,26 +102,31 @@ describe("api_open", function() screen:expect({ attr_ids = {}, grid = [[ -   dir1 │^ | -   dir2 │~ | -  file1 │~ | -  file2 │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -NvimTree_1 [-] [No Name] | - | +   dir1 │^ | +   dir2 │~ | +  file1 │~ | +  file2 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +NvimTree_1 [-] [No Name] | + | ]], }) end) @@ -136,13 +139,13 @@ NvimTree_1 [-] [No Name] | -- TODO NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode screen:expect({ grid = [[ - {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeEmptyFolderNameCL:dir1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | - {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file1 }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file2 }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*14 - {NvimTreeStatusLine:NvimTree_1 [-] }{2: Date: Fri, 11 Sep 2026 11:28:51 +1000 Subject: [PATCH 011/154] test: Screen 80 x 25 for more deterministic window sizes --- test/func/api/open.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/test/func/api/open.lua b/test/func/api/open.lua index 3897e9a0139..fb88552bdc7 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -155,6 +155,7 @@ NvimTree_1 [-] [No Name] require("nvim-tree.api").tree.open() end) + -- TODO this cursor position will be set to view_state.Active.cursors even when tree is destroyed, n.feed("") n.feed("") From 3aaeb427ae092645f6aeda11e2ed03fb26ba7512 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 11 Sep 2026 11:54:22 +1000 Subject: [PATCH 012/154] test: somewhat idempotent nvt_hl_attr_ids called in before_each --- test/func/api/open.lua | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/test/func/api/open.lua b/test/func/api/open.lua index fb88552bdc7..75185a3f764 100644 --- a/test/func/api/open.lua +++ b/test/func/api/open.lua @@ -4,6 +4,10 @@ local Screen = require("test.functional.ui.screen") local clear = n.clear local exec_lua = n.exec_lua +--- Reset all NvimTree* highlight groups to just a unique foreground colour +--- Add a CL variant with the same background colour as NvimTreeCursorLine +--- May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order +--- @param screen test.functional.ui.screen local function nvt_hl_attr_ids(screen) local attr_ids = {} @@ -19,7 +23,7 @@ local function nvt_hl_attr_ids(screen) local rgb, hex for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do - if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") then + if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") and not group:match(".*CL$") then -- next unique fg colour rgb = r * 256 * 256 + g * 256 + b hex = string.format("#%x", rgb) @@ -60,16 +64,6 @@ describe("api_open", function() exec_lua(function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - - exec_lua(function() - require("nvim-tree").setup({ - renderer = { - root_folder_label = false, - }, - }) - end) - - nvt_hl_attr_ids(screen) end) before_each(function() @@ -90,6 +84,8 @@ describe("api_open", function() }, }) end) + + nvt_hl_attr_ids(screen) end) it("api_tree_open_populated_unfocussed_text_only", function() @@ -155,7 +151,7 @@ NvimTree_1 [-] [No Name] require("nvim-tree.api").tree.open() end) - -- TODO this cursor position will be set to view_state.Active.cursors even when tree is destroyed, + -- TODO this cursor position will be set to view_state.Active.cursors even when tree is destroyed n.feed("") n.feed("") From 5a35843feb41cdf755d1436da4eb2fca0f0e4c50 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 11 Sep 2026 12:18:09 +1000 Subject: [PATCH 013/154] test: add an interactive node open test --- scripts/functionaltest.sh | 3 +- test/func/api/{ => tree}/open.lua | 2 +- test/func/map/node_open.lua | 125 ++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 2 deletions(-) rename test/func/api/{ => tree}/open.lua (99%) create mode 100644 test/func/map/node_open.lua diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 7fb13902b29..580b62faced 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -52,7 +52,8 @@ make ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" -make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/api/open.lua" +# make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/api/tree/open.lua" +make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/map/node_open.lua" cd - diff --git a/test/func/api/open.lua b/test/func/api/tree/open.lua similarity index 99% rename from test/func/api/open.lua rename to test/func/api/tree/open.lua index 75185a3f764..f9bb602ce55 100644 --- a/test/func/api/open.lua +++ b/test/func/api/tree/open.lua @@ -52,7 +52,7 @@ local function nvt_hl_attr_ids(screen) screen:add_extra_attr_ids(attr_ids) end -describe("api_open", function() +describe("api_tree_open", function() --- @type test.functional.ui.screen local screen diff --git a/test/func/map/node_open.lua b/test/func/map/node_open.lua new file mode 100644 index 00000000000..be5047c8f1e --- /dev/null +++ b/test/func/map/node_open.lua @@ -0,0 +1,125 @@ +local t = require("test.testutil") +local n = require("test.functional.testnvim")() +local Screen = require("test.functional.ui.screen") +local clear = n.clear +local exec_lua = n.exec_lua + +describe("map_node_open", function() + --- @type test.functional.ui.screen + local screen + + setup(function() + clear() + + screen = Screen.new(80, 25) + + exec_lua(function() + vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) + end) + end) + + before_each(function() + -- TODO think about copying contents of an actual directory into tmp rather than copying + local tmp = t.tmpname(false) + assert(t.mkdir(tmp)) + + assert(t.mkdir(tmp .. "/d1")) + t.write_file(tmp .. "/d1/f1", "d1f1", true) + t.write_file(tmp .. "/d1/f2", "d1f2", true) + + assert(t.mkdir(tmp .. "/d2")) + + t.write_file(tmp .. "/f1", "f1", true) + t.write_file(tmp .. "/f2", "f2", true) + + n.api.nvim_set_current_dir(tmp) + + exec_lua(function() + require("nvim-tree").setup({ + renderer = { + root_folder_label = false, + }, + }) + end) + end) + + it("map_node_open_dir", function() + exec_lua(function() + require("nvim-tree.api").tree.open() + end) + + n.feed("gg") + n.feed("") + + screen:expect({ + attr_ids = {}, + grid = [[ + ^  d1 │ | +  f1 │~ | +  f2 │~ | +   d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +NvimTree_1 [-] [No Name] | + | + ]], + }) + end) + + it("map_node_open_file", function() + exec_lua(function() + require("nvim-tree.api").tree.open() + end) + + n.feed("") + n.feed("") + + screen:expect({ + attr_ids = {}, + grid = [[ +   d1 │^f1 | +   d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +NvimTree_1 [-] f1 | + | + ]], + }) + end) +end) From 05761a159313dc2794f087cd91dcb5a51daa0fa8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 11 Sep 2026 12:37:14 +1000 Subject: [PATCH 014/154] test: Screen 80 x 24 for more deterministic window sizes --- scripts/functionaltest.sh | 4 ++-- test/func/api/tree/open.lua | 7 +++---- test/func/map/node_open.lua | 7 ++++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 580b62faced..9b1ce9de3fc 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -52,8 +52,8 @@ make ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" -# make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/api/tree/open.lua" -make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/map/node_open.lua" +make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/api/tree/open.lua" +# make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/map/node_open.lua" cd - diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index f9bb602ce55..5a72f3ca0c4 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -59,7 +59,7 @@ describe("api_tree_open", function() setup(function() clear() - screen = Screen.new(80, 25) + screen = Screen.new(80, 24) exec_lua(function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) @@ -120,7 +120,6 @@ describe("api_tree_open", function() ~ │~ | ~ │~ | ~ │~ | -~ │~ | NvimTree_1 [-] [No Name] | | ]], @@ -139,7 +138,7 @@ NvimTree_1 [-] [No Name] {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*19 +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*18 {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| | ]], @@ -161,7 +160,7 @@ NvimTree_1 [-] [No Name] {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeEmptyFolderNameCL:dir2}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*19 +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*18 {NvimTreeStatusLineNC:NvimTree_1 [-] }{3:[No Name] }| | ]], diff --git a/test/func/map/node_open.lua b/test/func/map/node_open.lua index be5047c8f1e..d1e7463e3a6 100644 --- a/test/func/map/node_open.lua +++ b/test/func/map/node_open.lua @@ -4,6 +4,9 @@ local Screen = require("test.functional.ui.screen") local clear = n.clear local exec_lua = n.exec_lua +-- TODO create doc: +-- - to create expect grid start with nvim -nu nvt_min.lua --cmd ':set columns=80 lines=24' + describe("map_node_open", function() --- @type test.functional.ui.screen local screen @@ -11,7 +14,7 @@ describe("map_node_open", function() setup(function() clear() - screen = Screen.new(80, 25) + screen = Screen.new(80, 24) exec_lua(function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) @@ -76,7 +79,6 @@ describe("map_node_open", function() ~ │~ | ~ │~ | ~ │~ | -~ │~ | NvimTree_1 [-] [No Name] | | ]], @@ -116,7 +118,6 @@ NvimTree_1 [-] [No Name] ~ │~ | ~ │~ | ~ │~ | -~ │~ | NvimTree_1 [-] f1 | | ]], From 7e03da743da9d0c538d7234d04ccccdb27dce730 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 11 Sep 2026 13:11:16 +1000 Subject: [PATCH 015/154] test: purge state clears cursor positions --- lua/nvim-tree/core.lua | 3 +-- lua/nvim-tree/view.lua | 6 ++++++ test/func/api/tree/open.lua | 1 - 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lua/nvim-tree/core.lua b/lua/nvim-tree/core.lua index 8892dfd0dac..5ea6b688693 100644 --- a/lua/nvim-tree/core.lua +++ b/lua/nvim-tree/core.lua @@ -67,8 +67,7 @@ function M.get_nodes_starting_line() end function M.purge_all_state() - view.close_all_tabs() - view.abandon_all_windows() + view.purge_state() if TreeExplorer then git.purge_state() TreeExplorer:destroy() diff --git a/lua/nvim-tree/view.lua b/lua/nvim-tree/view.lua index 865a6eeeead..9b1dfea610e 100644 --- a/lua/nvim-tree/view.lua +++ b/lua/nvim-tree/view.lua @@ -354,6 +354,12 @@ function M.abandon_all_windows() end end +function M.purge_state() + M.close_all_tabs() + M.abandon_all_windows() + view_state.Active.cursors = {} +end + ---@param opts table|nil ---@return boolean function M.is_visible(opts) diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index 5a72f3ca0c4..03a181cc50b 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -150,7 +150,6 @@ NvimTree_1 [-] [No Name] require("nvim-tree.api").tree.open() end) - -- TODO this cursor position will be set to view_state.Active.cursors even when tree is destroyed n.feed("") n.feed("") From 6065099d1b08da2df66668b112ba66a23717b95c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 14 Sep 2026 11:03:22 +1000 Subject: [PATCH 016/154] test: functionaltest.sh driver allows test selection --- scripts/functionaltest.sh | 62 +++++++++++++++++++++++++++++++------ test/func/api/tree/open.lua | 6 ++-- test/func/map/node_open.lua | 4 +-- 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 9b1ce9de3fc..1b114861abe 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -13,10 +13,47 @@ DIR_NVIM_SRC_DEF="/tmp/src/neovim-stable" # nvim-tree linked as a package for the tests to add before run DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" -cleanup() { - rm -fv "${DIR_NVT_PACK}" +usage() { + echo "Usage: $0 [-h] [-t ] [-d ]" + echo + echo " OPTION:" + echo " -t Execute single test" + echo " -d Execute all tests in dir" + echo " -h Show this help" +} + +files_test_add_dir() { + find "${1}" -type f -iname '*lua' > /tmp/nvt_files_test + while IFS= read -r f; do + FILES_TEST="${FILES_TEST} ${f}" + done < /tmp/nvt_files_test + rm /tmp/nvt_files_test } +while getopts "ht:d:" o; do + case "$o" in + h) + usage + exit 0 + ;; + d) + files_test_add_dir "${OPTARG:-}" + ;; + t) + FILES_TEST="${FILES_TEST} ${OPTARG:-}" + ;; + \?) + usage >&2 + exit 1 + ;; + esac +done + +# run all tests if none specified +if [ -z "${FILES_TEST}" ]; then + files_test_add_dir "test/func" +fi + # TODO extract common functionality from vimdoc.sh if [ ! -d "${DIR_NVT}/lua/nvim-tree" ]; then echo "Must be run from nvim-tree root" 1>&2 @@ -44,17 +81,24 @@ EOM exit 1 fi -cleanup +cleanup() { + rm -fv "${DIR_NVT_PACK}" +} -cd "${DIR_NVIM_SRC}" +prepare() { + cd "${DIR_NVIM_SRC}" -make + make -ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" + ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" +} + +cleanup -make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/api/tree/open.lua" -# make functionaltest TEST_FILE="${DIR_NVT_PACK}/test/func/map/node_open.lua" +prepare -cd - +for f in ${FILES_TEST}; do + make functionaltest TEST_FILE="${DIR_NVT_PACK}/${f}" +done cleanup diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index 03a181cc50b..e3e235b7ebb 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -88,7 +88,7 @@ describe("api_tree_open", function() nvt_hl_attr_ids(screen) end) - it("api_tree_open_populated_unfocussed_text_only", function() + it("populated_unfocussed_text_only", function() exec_lua(function() require("nvim-tree.api").tree.open() end) @@ -126,7 +126,7 @@ NvimTree_1 [-] [No Name] }) end) - it("api_tree_open_populated_focussed", function() + it("populated_focussed", function() exec_lua(function() require("nvim-tree.api").tree.open() end) @@ -145,7 +145,7 @@ NvimTree_1 [-] [No Name] }) end) - it("api_tree_open_populated_unfocussed", function() + it("populated_unfocussed", function() exec_lua(function() require("nvim-tree.api").tree.open() end) diff --git a/test/func/map/node_open.lua b/test/func/map/node_open.lua index d1e7463e3a6..2b4330e34b0 100644 --- a/test/func/map/node_open.lua +++ b/test/func/map/node_open.lua @@ -46,7 +46,7 @@ describe("map_node_open", function() end) end) - it("map_node_open_dir", function() + it("dir", function() exec_lua(function() require("nvim-tree.api").tree.open() end) @@ -85,7 +85,7 @@ NvimTree_1 [-] [No Name] }) end) - it("map_node_open_file", function() + it("file", function() exec_lua(function() require("nvim-tree.api").tree.open() end) From 2b89e2d76d63502801ff2986cf198da8ba28a027 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 14 Sep 2026 12:16:43 +1000 Subject: [PATCH 017/154] test: func tests use fixed contents data directories --- scripts/functionaltest.sh | 27 ++++++++++++++++++- test/func/api/tree/data/file1 | 1 + test/func/api/tree/data/file2 | 1 + test/func/api/tree/open.lua | 16 +++++------ test/func/map/node/data/d1/f1 | 1 + test/func/map/node/data/d1/f2 | 1 + test/func/map/node/data/f1 | 1 + test/func/map/node/data/f2 | 1 + .../func/map/{node_open.lua => node/open.lua} | 21 +++++---------- 9 files changed, 44 insertions(+), 26 deletions(-) create mode 100644 test/func/api/tree/data/file1 create mode 100644 test/func/api/tree/data/file2 create mode 100644 test/func/map/node/data/d1/f1 create mode 100644 test/func/map/node/data/d1/f2 create mode 100644 test/func/map/node/data/f1 create mode 100644 test/func/map/node/data/f2 rename test/func/map/{node_open.lua => node/open.lua} (91%) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 1b114861abe..dbf91e65465 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -13,6 +13,9 @@ DIR_NVIM_SRC_DEF="/tmp/src/neovim-stable" # nvim-tree linked as a package for the tests to add before run DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" +# working copy of test data +DIR_DATA_WORKING="/tmp/nvt_test_func/data" + usage() { echo "Usage: $0 [-h] [-t ] [-d ]" echo @@ -83,9 +86,13 @@ fi cleanup() { rm -fv "${DIR_NVT_PACK}" + + rm -rf "$(dirname "${DIR_DATA_WORKING}")" } prepare() { + mkdir -p "$(dirname "${DIR_DATA_WORKING}")" + cd "${DIR_NVIM_SRC}" make @@ -93,12 +100,30 @@ prepare() { ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" } +execute() { + NVT_TEST_FILE="${DIR_NVT_PACK}/${1}" + + # copy the data directory to work + rm -rf "${DIR_DATA_WORKING}" + DIR_TEST="$(dirname "${NVT_TEST_FILE}")" + if [ -d "${DIR_TEST}/data" ]; then + cp -pr "${DIR_TEST}/data" "${DIR_DATA_WORKING}" + export NVT_TEST_DATA="${DIR_DATA_WORKING}" + else + export NVT_TEST_DATA= + fi + + make functionaltest TEST_FILE="${NVT_TEST_FILE}" + + rm -rf "${DIR_DATA_WORKING}" +} + cleanup prepare for f in ${FILES_TEST}; do - make functionaltest TEST_FILE="${DIR_NVT_PACK}/${f}" + execute "${f}" done cleanup diff --git a/test/func/api/tree/data/file1 b/test/func/api/tree/data/file1 new file mode 100644 index 00000000000..257cc5642cb --- /dev/null +++ b/test/func/api/tree/data/file1 @@ -0,0 +1 @@ +foo diff --git a/test/func/api/tree/data/file2 b/test/func/api/tree/data/file2 new file mode 100644 index 00000000000..5716ca5987c --- /dev/null +++ b/test/func/api/tree/data/file2 @@ -0,0 +1 @@ +bar diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index e3e235b7ebb..f7de3ec44f2 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -1,4 +1,3 @@ -local t = require("test.testutil") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear @@ -67,16 +66,13 @@ describe("api_tree_open", function() end) before_each(function() - -- TODO think about copying contents of an actual directory into tmp rather than copying - local tmp = t.tmpname(false) - assert(t.mkdir(tmp)) - t.write_file(tmp .. "/file1", "foo", true) - t.write_file(tmp .. "/file2", "bar", true) - assert(t.mkdir(tmp .. "/dir1")) - assert(t.mkdir(tmp .. "/dir2")) - - n.api.nvim_set_current_dir(tmp) + -- TODO maybe recursively copy contents + local nvt_test_data = os.getenv("NVT_TEST_DATA") + if nvt_test_data then + n.api.nvim_set_current_dir(nvt_test_data) + end + -- TODO helper to test root folder name exec_lua(function() require("nvim-tree").setup({ renderer = { diff --git a/test/func/map/node/data/d1/f1 b/test/func/map/node/data/d1/f1 new file mode 100644 index 00000000000..13d1560f267 --- /dev/null +++ b/test/func/map/node/data/d1/f1 @@ -0,0 +1 @@ +d1f1 diff --git a/test/func/map/node/data/d1/f2 b/test/func/map/node/data/d1/f2 new file mode 100644 index 00000000000..6ec000bf6df --- /dev/null +++ b/test/func/map/node/data/d1/f2 @@ -0,0 +1 @@ +d1f2 diff --git a/test/func/map/node/data/f1 b/test/func/map/node/data/f1 new file mode 100644 index 00000000000..8e1e71d5ce3 --- /dev/null +++ b/test/func/map/node/data/f1 @@ -0,0 +1 @@ +f1 diff --git a/test/func/map/node/data/f2 b/test/func/map/node/data/f2 new file mode 100644 index 00000000000..9de77c18733 --- /dev/null +++ b/test/func/map/node/data/f2 @@ -0,0 +1 @@ +f2 diff --git a/test/func/map/node_open.lua b/test/func/map/node/open.lua similarity index 91% rename from test/func/map/node_open.lua rename to test/func/map/node/open.lua index 2b4330e34b0..c8005ce2d5a 100644 --- a/test/func/map/node_open.lua +++ b/test/func/map/node/open.lua @@ -1,4 +1,3 @@ -local t = require("test.testutil") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear @@ -22,21 +21,13 @@ describe("map_node_open", function() end) before_each(function() - -- TODO think about copying contents of an actual directory into tmp rather than copying - local tmp = t.tmpname(false) - assert(t.mkdir(tmp)) - - assert(t.mkdir(tmp .. "/d1")) - t.write_file(tmp .. "/d1/f1", "d1f1", true) - t.write_file(tmp .. "/d1/f2", "d1f2", true) - - assert(t.mkdir(tmp .. "/d2")) - - t.write_file(tmp .. "/f1", "f1", true) - t.write_file(tmp .. "/f2", "f2", true) - - n.api.nvim_set_current_dir(tmp) + -- TODO maybe recursively copy contents + local nvt_test_data = os.getenv("NVT_TEST_DATA") + if nvt_test_data then + n.api.nvim_set_current_dir(nvt_test_data) + end + -- TODO helper to test root folder name exec_lua(function() require("nvim-tree").setup({ renderer = { From f46f5e577409078025b07fc5d7bfed8838e75459 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 14 Sep 2026 13:31:14 +1000 Subject: [PATCH 018/154] test: add functional test live for creating test data --- scripts/functionaltest.sh | 45 ++++++++++++++++++++++++++++--------- test/func/api/tree/open.lua | 4 ++++ test/func/map/node/open.lua | 5 ++--- 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index dbf91e65465..0c0391b719b 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -17,11 +17,12 @@ DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" DIR_DATA_WORKING="/tmp/nvt_test_func/data" usage() { - echo "Usage: $0 [-h] [-t ] [-d ]" + echo "Usage: $0 [-h] [-t ] [-d ] [-l]" echo echo " OPTION:" echo " -t Execute single test" echo " -d Execute all tests in dir" + echo " -l Live environment" echo " -h Show this help" } @@ -33,7 +34,7 @@ files_test_add_dir() { rm /tmp/nvt_files_test } -while getopts "ht:d:" o; do +while getopts "hlt:d:" o; do case "$o" in h) usage @@ -45,6 +46,9 @@ while getopts "ht:d:" o; do t) FILES_TEST="${FILES_TEST} ${OPTARG:-}" ;; + l) + LIVE=true + ;; \?) usage >&2 exit 1 @@ -52,11 +56,6 @@ while getopts "ht:d:" o; do esac done -# run all tests if none specified -if [ -z "${FILES_TEST}" ]; then - files_test_add_dir "test/func" -fi - # TODO extract common functionality from vimdoc.sh if [ ! -d "${DIR_NVT}/lua/nvim-tree" ]; then echo "Must be run from nvim-tree root" 1>&2 @@ -84,6 +83,11 @@ EOM exit 1 fi +# run all tests if none specified +if [ -z "${FILES_TEST}" ]; then + files_test_add_dir "test/func" +fi + cleanup() { rm -fv "${DIR_NVT_PACK}" @@ -100,6 +104,23 @@ prepare() { ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" } +live() { + # TODO add command line argument to cd to a data directory first, mandatory should be OK + + # extracted from testnvim.lua new_session + nvim \ + --clean \ + -u NONE \ + -i NONE \ + --cmd "set shortmess+=IS noswapfile noautoindent startofline laststatus=1 undodir=. directory=. viewdir=. backupdir=. belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}" \ + --cmd "set packpath^=${DIR_NVIM_SRC}/runtime/" \ + --cmd "set columns=80 lines=24" \ + --cmd "packadd nvim-tree.lua" \ + --cmd "lua require('nvim-tree').setup()" + + exit 0 +} + execute() { NVT_TEST_FILE="${DIR_NVT_PACK}/${1}" @@ -122,8 +143,12 @@ cleanup prepare -for f in ${FILES_TEST}; do - execute "${f}" -done +if [ -n "${LIVE}" ]; then + live +else + for f in ${FILES_TEST}; do + execute "${f}" + done +fi cleanup diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index f7de3ec44f2..a3692683fba 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -3,6 +3,8 @@ local Screen = require("test.functional.ui.screen") local clear = n.clear local exec_lua = n.exec_lua +-- TODO extract nvt test utils + --- Reset all NvimTree* highlight groups to just a unique foreground colour --- Add a CL variant with the same background colour as NvimTreeCursorLine --- May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order @@ -162,3 +164,5 @@ NvimTree_1 [-] [No Name] }) end) end) + +-- vim:colorcolumn=80 diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index c8005ce2d5a..a937ab9938f 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -3,9 +3,6 @@ local Screen = require("test.functional.ui.screen") local clear = n.clear local exec_lua = n.exec_lua --- TODO create doc: --- - to create expect grid start with nvim -nu nvt_min.lua --cmd ':set columns=80 lines=24' - describe("map_node_open", function() --- @type test.functional.ui.screen local screen @@ -115,3 +112,5 @@ NvimTree_1 [-] f1 }) end) end) + +-- vim:colorcolumn=80 From e4bd4e4e9dabafebbf41a5cb9974e02be0b126f4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 15 Sep 2026 11:53:44 +1000 Subject: [PATCH 019/154] test: add live test capture functionality --- scripts/functionaltest.sh | 10 +++----- test/func/init_live.lua | 51 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 test/func/init_live.lua diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 0c0391b719b..75c0def278f 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -107,17 +107,15 @@ prepare() { live() { # TODO add command line argument to cd to a data directory first, mandatory should be OK - # extracted from testnvim.lua new_session + # most options extracted from testnvim.lua new_session nvim \ --clean \ - -u NONE \ + -u "${DIR_NVT}/test/func/init_live.lua" \ + --noplugin \ -i NONE \ --cmd "set shortmess+=IS noswapfile noautoindent startofline laststatus=1 undodir=. directory=. viewdir=. backupdir=. belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}" \ --cmd "set packpath^=${DIR_NVIM_SRC}/runtime/" \ - --cmd "set columns=80 lines=24" \ - --cmd "packadd nvim-tree.lua" \ - --cmd "lua require('nvim-tree').setup()" - + --cmd "packadd nvim-tree.lua" exit 0 } diff --git a/test/func/init_live.lua b/test/func/init_live.lua new file mode 100644 index 00000000000..082e96bcdc9 --- /dev/null +++ b/test/func/init_live.lua @@ -0,0 +1,51 @@ +local dump_path = "/tmp/live_dump.txt" + +-- match the test screen size: r to reapply if the terminal is not cooperating +local function screen_resize() + vim.o.columns = 80 + vim.o.lines = 24 +end + +---dump the screen to dump_path: d +---pipe is appended to each line +---caret is inserted at the cursor position +---this is global so that we can call it without changing cursor position +---@diagnostic disable-next-line: missing-global-doc, global-element +function LIVE_DUMP() + screen_resize() + + -- absolute cursor position + local cursor = { col = vim.fn.screencol(), row = vim.fn.screenrow(), } + + -- clear the command line + vim.api.nvim_command("echo") + + -- capture all screen lines + local lines = {} + for row = 1, vim.o.lines do + local line = "" + for col = 1, vim.o.columns do + if row == cursor.row and col == cursor.col then + line = line .. "^" + end + line = line .. vim.fn.screenstring(row, col) + end + lines[row] = line .. "|" + end + + -- dump to file + vim.fn.writefile(lines, dump_path) + vim.api.nvim_command("echo 'dumped screen to " .. dump_path .. "'") + + -- try to open it + vim.ui.open(dump_path) +end + +vim.keymap.set("n", "r", screen_resize, { remap = false, }) +vim.keymap.set("n", "d", "lua LIVE_DUMP()", { remap = false, }) + +---set the screen size to match tests +screen_resize() + +---add the plugin under test +require("nvim-tree").setup({ renderer = { root_folder_label = false, }, }) From 3b64efe276bdaee0015f95c3fd5d3bdb4d4c0bb5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 15 Sep 2026 11:58:52 +1000 Subject: [PATCH 020/154] test: add live test capture functionality --- test/func/README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 test/func/README.md diff --git a/test/func/README.md b/test/func/README.md new file mode 100644 index 00000000000..3caa11536cd --- /dev/null +++ b/test/func/README.md @@ -0,0 +1,12 @@ +# Generating Test Data + +Execute `scripts/functionaltest.sh -l ` + +This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua` + +1. Perform the actions to be tested +2. Dump the screen `d` to `/tmp/live_dump.txt` +3. Add the dump to `screen:expect` `grid`, with `attr_ids = {}` + +The dump will have `|` appended to each line, with a caret `^` at the cursor position. + From 9595cf4ec0c3b48935d64c5267e7f78f8c6c94dd Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 15 Sep 2026 12:47:02 +1000 Subject: [PATCH 021/154] test: add live test capture functionality --- scripts/functionaltest.sh | 32 ++++++++++++++++---------------- test/func/README.md | 2 ++ test/func/init_live.lua | 6 +++++- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 75c0def278f..1a7baa14f81 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -17,12 +17,12 @@ DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" DIR_DATA_WORKING="/tmp/nvt_test_func/data" usage() { - echo "Usage: $0 [-h] [-t ] [-d ] [-l]" + echo "Usage: $0 [-h] [-t ] [-d ] [-l ]" echo echo " OPTION:" echo " -t Execute single test" echo " -d Execute all tests in dir" - echo " -l Live environment" + echo " -l Live environment in data" echo " -h Show this help" } @@ -34,7 +34,7 @@ files_test_add_dir() { rm /tmp/nvt_files_test } -while getopts "hlt:d:" o; do +while getopts "hl:t:d:" o; do case "$o" in h) usage @@ -47,7 +47,7 @@ while getopts "hlt:d:" o; do FILES_TEST="${FILES_TEST} ${OPTARG:-}" ;; l) - LIVE=true + DIR_LIVE="$(realpath "${OPTARG:-}")" ;; \?) usage >&2 @@ -90,33 +90,29 @@ fi cleanup() { rm -fv "${DIR_NVT_PACK}" - rm -rf "$(dirname "${DIR_DATA_WORKING}")" } prepare() { mkdir -p "$(dirname "${DIR_DATA_WORKING}")" - cd "${DIR_NVIM_SRC}" - make - ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" + cd "${DIR_NVT}" } live() { - # TODO add command line argument to cd to a data directory first, mandatory should be OK - - # most options extracted from testnvim.lua new_session + # options extracted from testnvim.lua nvim_argv, nvim_set nvim \ --clean \ - -u "${DIR_NVT}/test/func/init_live.lua" \ --noplugin \ + -u "${DIR_NVT}/test/func/init_live.lua" \ -i NONE \ - --cmd "set shortmess+=IS noswapfile noautoindent startofline laststatus=1 undodir=. directory=. viewdir=. backupdir=. belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}" \ + --cmd "set shortmess+=IS background=light noswapfile noautoindent startofline laststatus=1 undodir=. directory=. viewdir=. backupdir=. belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}" \ + --cmd "comclear | mapclear | mapclear!" \ --cmd "set packpath^=${DIR_NVIM_SRC}/runtime/" \ - --cmd "packadd nvim-tree.lua" - exit 0 + --cmd "lua dofile('${DIR_NVIM_SRC}/runtime/colors/vim.lua')" \ + --cmd "unlet g:colors_name" } execute() { @@ -141,9 +137,13 @@ cleanup prepare -if [ -n "${LIVE}" ]; then +if [ -n "${DIR_LIVE}" ]; then + cd "${DIR_LIVE}" + live else + cd "${DIR_NVIM_SRC}" + for f in ${FILES_TEST}; do execute "${f}" done diff --git a/test/func/README.md b/test/func/README.md index 3caa11536cd..7c239924137 100644 --- a/test/func/README.md +++ b/test/func/README.md @@ -10,3 +10,5 @@ This will open an interactive vim session that closely matches the test headless The dump will have `|` appended to each line, with a caret `^` at the cursor position. +The sessions should have screen size 80x24. Use `r` to reset the size if the terminal has changed it. + diff --git a/test/func/init_live.lua b/test/func/init_live.lua index 082e96bcdc9..e1ec48dd7b9 100644 --- a/test/func/init_live.lua +++ b/test/func/init_live.lua @@ -41,11 +41,15 @@ function LIVE_DUMP() vim.ui.open(dump_path) end -vim.keymap.set("n", "r", screen_resize, { remap = false, }) vim.keymap.set("n", "d", "lua LIVE_DUMP()", { remap = false, }) +vim.keymap.set("n", "r", screen_resize, { remap = false, }) ---set the screen size to match tests screen_resize() +-- use dark background for readability under dark and light +vim.o.background = "dark" + ---add the plugin under test +vim.api.nvim_command("packadd nvim-tree.lua") require("nvim-tree").setup({ renderer = { root_folder_label = false, }, }) From 4af24cf42e25438dc45b5f9ac64d55ca25c11d6d Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 15 Sep 2026 12:57:07 +1000 Subject: [PATCH 022/154] test: add live test capture functionality --- test/func/README.md | 2 +- test/func/api/tree/open.lua | 1 - test/func/init_live.lua | 4 ++-- test/func/map/node/open.lua | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/test/func/README.md b/test/func/README.md index 7c239924137..fa8bcf01a81 100644 --- a/test/func/README.md +++ b/test/func/README.md @@ -5,7 +5,7 @@ Execute `scripts/functionaltest.sh -l ` This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua` 1. Perform the actions to be tested -2. Dump the screen `d` to `/tmp/live_dump.txt` +2. Dump the screen `d` to `/tmp/nvt_test_func/dump.txt` 3. Add the dump to `screen:expect` `grid`, with `attr_ids = {}` The dump will have `|` appended to each line, with a caret `^` at the cursor position. diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index a3692683fba..48de62e0d6f 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -68,7 +68,6 @@ describe("api_tree_open", function() end) before_each(function() - -- TODO maybe recursively copy contents local nvt_test_data = os.getenv("NVT_TEST_DATA") if nvt_test_data then n.api.nvim_set_current_dir(nvt_test_data) diff --git a/test/func/init_live.lua b/test/func/init_live.lua index e1ec48dd7b9..d6a6a43667f 100644 --- a/test/func/init_live.lua +++ b/test/func/init_live.lua @@ -1,4 +1,4 @@ -local dump_path = "/tmp/live_dump.txt" +local dump_path = "/tmp/nvt_test_func/dump.txt" -- match the test screen size: r to reapply if the terminal is not cooperating local function screen_resize() @@ -9,7 +9,7 @@ end ---dump the screen to dump_path: d ---pipe is appended to each line ---caret is inserted at the cursor position ----this is global so that we can call it without changing cursor position +---this is global so that we can execute it as a command, without changing cursor position ---@diagnostic disable-next-line: missing-global-doc, global-element function LIVE_DUMP() screen_resize() diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index a937ab9938f..cfde9d11ed8 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -18,7 +18,6 @@ describe("map_node_open", function() end) before_each(function() - -- TODO maybe recursively copy contents local nvt_test_data = os.getenv("NVT_TEST_DATA") if nvt_test_data then n.api.nvim_set_current_dir(nvt_test_data) From d4aca2f5ccb637c68075fd597b68f29df25a8ef8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 16 Sep 2026 11:09:45 +1000 Subject: [PATCH 023/154] test: add live test capture functionality --- scripts/functionaltest.sh | 139 +++++++++++++++++++++--------------- test/func/api/tree/open.lua | 2 +- test/func/init_live.lua | 8 ++- test/func/map/node/open.lua | 2 +- 4 files changed, 92 insertions(+), 59 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 1a7baa14f81..0f716bd079c 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -1,6 +1,7 @@ #!/usr/bin/env sh -# TODO this will be shipped as part of the vim runtime https://github.com/neovim/neovim/issues/34592 +# neovim func test driver, see test/func/README.md +# this will be eventually be shipped as part of the vim runtime https://github.com/neovim/neovim/issues/34592 set -e @@ -10,44 +11,71 @@ DIR_NVT="${PWD}" # neovim source DIR_NVIM_SRC_DEF="/tmp/src/neovim-stable" -# nvim-tree linked as a package for the tests to add before run +# nvim-tree linked as a package under source DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" -# working copy of test data -DIR_DATA_WORKING="/tmp/nvt_test_func/data" +# working directory to copy test data into +DIR_WORK="/tmp/nvt_test_func" + +# absolute paths of test files under nvim source +FILES_TEST= + +# live directory, must contain data +DIR_LIVE= + +# optional test data directory exported for tests +NVT_DIR_TEST_DATA= usage() { - echo "Usage: $0 [-h] [-t ] [-d ] [-l ]" + echo "Usage: ${0} [-h] [-t ] [-l ]" echo echo " OPTION:" - echo " -t Execute single test" - echo " -d Execute all tests in dir" - echo " -l Live environment in data" + echo " -t Execute single test file or all in directory" + echo " -l Live environment in test data directory" echo " -h Show this help" } -files_test_add_dir() { - find "${1}" -type f -iname '*lua' > /tmp/nvt_files_test - while IFS= read -r f; do - FILES_TEST="${FILES_TEST} ${f}" - done < /tmp/nvt_files_test - rm /tmp/nvt_files_test +# add a file or directory $1 to FILES_TEST +files_test_add() { + if [ -f "${1}" ]; then + FILES_TEST="${FILES_TEST} ${DIR_NVT_PACK}/${1}" + elif [ -d "${1}" ]; then + find "${1}" -type f -iname '*lua' -not -iname 'init*.lua' > /tmp/nvt_files_test + while IFS= read -r f; do + FILES_TEST="${FILES_TEST} ${DIR_NVT_PACK}/${f}" + done < /tmp/nvt_files_test + rm /tmp/nvt_files_test + else + echo "${1} inexistent" + exit 1 + fi } -while getopts "hl:t:d:" o; do +# create DIR_LIVE if data dir present next to file $1 or in directory $1 +live_add() { + if [ -f "${1}" ]; then + DIR_LIVE="$(dirname "${1}")" + else + DIR_LIVE="${1}" + fi + + if [ ! -d "${DIR_LIVE}/data" ]; then + echo "${DIR_LIVE}/data inexistent" + exit 1 + fi +} + +while getopts "hl:t:" o; do case "$o" in - h) + h) usage exit 0 ;; - d) - files_test_add_dir "${OPTARG:-}" - ;; - t) - FILES_TEST="${FILES_TEST} ${OPTARG:-}" - ;; l) - DIR_LIVE="$(realpath "${OPTARG:-}")" + live_add "${OPTARG:-}" + ;; + t) + files_test_add "${OPTARG:-}" ;; \?) usage >&2 @@ -83,30 +111,38 @@ EOM exit 1 fi -# run all tests if none specified -if [ -z "${FILES_TEST}" ]; then - files_test_add_dir "test/func" -fi - -cleanup() { +# after all tests +teardown() { rm -fv "${DIR_NVT_PACK}" - rm -rf "$(dirname "${DIR_DATA_WORKING}")" + rm -rf "${DIR_WORK}" } -prepare() { - mkdir -p "$(dirname "${DIR_DATA_WORKING}")" +# before all tests: builds nvim and links nvim-tree as a package under nvim source +setup() { cd "${DIR_NVIM_SRC}" make ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" cd "${DIR_NVT}" } +# if present, copies data directory in $1 to $DIR_WORK/data and sets $NVT_DIR_TEST_DATA +before_each() { + rm -rf "${DIR_WORK}" + mkdir -p "${DIR_WORK}" + if [ -d "${1}/data" ]; then + cp -pr "${1}/data" "${DIR_WORK}" + export NVT_DIR_TEST_DATA="${DIR_WORK}/data" + else + export NVT_DIR_TEST_DATA= + fi +} + live() { # options extracted from testnvim.lua nvim_argv, nvim_set nvim \ --clean \ --noplugin \ - -u "${DIR_NVT}/test/func/init_live.lua" \ + -u "${DIR_NVT_PACK}/test/func/init_live.lua" \ -i NONE \ --cmd "set shortmess+=IS background=light noswapfile noautoindent startofline laststatus=1 undodir=. directory=. viewdir=. backupdir=. belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}" \ --cmd "comclear | mapclear | mapclear!" \ @@ -115,38 +151,29 @@ live() { --cmd "unlet g:colors_name" } -execute() { - NVT_TEST_FILE="${DIR_NVT_PACK}/${1}" - - # copy the data directory to work - rm -rf "${DIR_DATA_WORKING}" - DIR_TEST="$(dirname "${NVT_TEST_FILE}")" - if [ -d "${DIR_TEST}/data" ]; then - cp -pr "${DIR_TEST}/data" "${DIR_DATA_WORKING}" - export NVT_TEST_DATA="${DIR_DATA_WORKING}" - else - export NVT_TEST_DATA= - fi +teardown - make functionaltest TEST_FILE="${NVT_TEST_FILE}" - - rm -rf "${DIR_DATA_WORKING}" -} - -cleanup - -prepare +setup if [ -n "${DIR_LIVE}" ]; then - cd "${DIR_LIVE}" + before_each "${DIR_LIVE}" live else + # run all tests if none specified + if [ -z "${FILES_TEST}" ]; then + files_test_add "test/func" + fi + + # run from nvim source root cd "${DIR_NVIM_SRC}" + # execute all tests for f in ${FILES_TEST}; do - execute "${f}" + before_each "$(dirname "${f}")" + + make functionaltest TEST_FILE="${f}" done fi -cleanup +teardown diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index 48de62e0d6f..008b697d6aa 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -68,7 +68,7 @@ describe("api_tree_open", function() end) before_each(function() - local nvt_test_data = os.getenv("NVT_TEST_DATA") + local nvt_test_data = os.getenv("NVT_DIR_TEST_DATA") if nvt_test_data then n.api.nvim_set_current_dir(nvt_test_data) end diff --git a/test/func/init_live.lua b/test/func/init_live.lua index d6a6a43667f..c4c8de04aa7 100644 --- a/test/func/init_live.lua +++ b/test/func/init_live.lua @@ -50,6 +50,12 @@ screen_resize() -- use dark background for readability under dark and light vim.o.background = "dark" +-- move to the data directory +local nvt_test_data = os.getenv("NVT_DIR_TEST_DATA") +if nvt_test_data then + vim.api.nvim_set_current_dir(nvt_test_data) +end + ---add the plugin under test vim.api.nvim_command("packadd nvim-tree.lua") -require("nvim-tree").setup({ renderer = { root_folder_label = false, }, }) +require("nvim-tree").setup({}) diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index cfde9d11ed8..d23917c6f7a 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -18,7 +18,7 @@ describe("map_node_open", function() end) before_each(function() - local nvt_test_data = os.getenv("NVT_TEST_DATA") + local nvt_test_data = os.getenv("NVT_DIR_TEST_DATA") if nvt_test_data then n.api.nvim_set_current_dir(nvt_test_data) end From cdace03a8257e55bc6c1132d2aaf1d9fb57210fd Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 16 Sep 2026 11:25:45 +1000 Subject: [PATCH 024/154] test: add root dir to tests --- test/func/api/tree/open.lua | 27 ++++++++++++--------------- test/func/map/node/open.lua | 18 +++++++----------- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index 008b697d6aa..844547b8965 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -73,13 +73,8 @@ describe("api_tree_open", function() n.api.nvim_set_current_dir(nvt_test_data) end - -- TODO helper to test root folder name exec_lua(function() - require("nvim-tree").setup({ - renderer = { - root_folder_label = false, - }, - }) + require("nvim-tree").setup({}) end) nvt_hl_attr_ids(screen) @@ -95,7 +90,8 @@ describe("api_tree_open", function() screen:expect({ attr_ids = {}, grid = [[ -   dir1 │^ | + /tmp/nvt_test_func/data/.. │^ | +   dir1 │~ |   dir2 │~ |  file1 │~ |  file2 │~ | @@ -116,14 +112,13 @@ describe("api_tree_open", function() ~ │~ | ~ │~ | ~ │~ | -~ │~ | NvimTree_1 [-] [No Name] | | ]], }) end) - it("populated_focussed", function() + it("populated_unfocussed_hl_attrs", function() exec_lua(function() require("nvim-tree.api").tree.open() end) @@ -131,18 +126,19 @@ NvimTree_1 [-] [No Name] -- TODO NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode screen:expect({ grid = [[ -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeEmptyFolderNameCL:dir1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColumn: }{NvimTreeRootFolderCL:^/tmp/nvt_test_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:dir1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*18 +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| | ]], }) end) - it("populated_unfocussed", function() + it("populated_unfocussed_hl_attrs", function() exec_lua(function() require("nvim-tree.api").tree.open() end) @@ -152,11 +148,12 @@ NvimTree_1 [-] [No Name] screen:expect({ grid = [[ -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeEmptyFolderName:dir1}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeEmptyFolderNameCL:dir2}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_test_func/data/..}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeEmptyFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*18 +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 {NvimTreeStatusLineNC:NvimTree_1 [-] }{3:[No Name] }| | ]], diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index d23917c6f7a..4d39185566f 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -23,13 +23,8 @@ describe("map_node_open", function() n.api.nvim_set_current_dir(nvt_test_data) end - -- TODO helper to test root folder name exec_lua(function() - require("nvim-tree").setup({ - renderer = { - root_folder_label = false, - }, - }) + require("nvim-tree").setup({}) end) end) @@ -39,12 +34,14 @@ describe("map_node_open", function() end) n.feed("gg") + n.feed("") n.feed("") screen:expect({ attr_ids = {}, grid = [[ - ^  d1 │ | + /tmp/nvt_test_func/data/.. │ | + ^  d1 │~ |  f1 │~ |  f2 │~ |   d2 │~ | @@ -65,7 +62,6 @@ describe("map_node_open", function() ~ │~ | ~ │~ | ~ │~ | -~ │~ | NvimTree_1 [-] [No Name] | | ]], @@ -77,13 +73,14 @@ NvimTree_1 [-] [No Name] require("nvim-tree.api").tree.open() end) - n.feed("") + n.feed("") n.feed("") screen:expect({ attr_ids = {}, grid = [[ -   d1 │^f1 | + /tmp/nvt_test_func/data/.. │^f1 | +   d1 │~ |   d2 │~ |  f1 │~ |  f2 │~ | @@ -104,7 +101,6 @@ NvimTree_1 [-] [No Name] ~ │~ | ~ │~ | ~ │~ | -~ │~ | NvimTree_1 [-] f1 | | ]], From 25861759f8ce862a6923aa4fd6a8521e4986a0a9 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 16 Sep 2026 11:59:44 +1000 Subject: [PATCH 025/154] test: document highlight group testing --- test/func/README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/func/README.md b/test/func/README.md index fa8bcf01a81..f46cf7b8dcf 100644 --- a/test/func/README.md +++ b/test/func/README.md @@ -4,6 +4,8 @@ Execute `scripts/functionaltest.sh -l ` This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua` +## Text Only: `attr_ids = {}` + 1. Perform the actions to be tested 2. Dump the screen `d` to `/tmp/nvt_test_func/dump.txt` 3. Add the dump to `screen:expect` `grid`, with `attr_ids = {}` @@ -12,3 +14,11 @@ The dump will have `|` appended to each line, with a caret `^` at the cursor pos The sessions should have screen size 80x24. Use `r` to reset the size if the terminal has changed it. +## Text And Highlight + +Additional work is required to add highlight groups. + +Write the test as per Text Only and execute; it will fail. + +Use `Snapshot: screen:expect([[` contents from test log as the `grid`, visually validating that it matches the screen dump. + From f5da3bb43ec2ccfcfc09ebe325a5514d3c2b47f0 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 16 Sep 2026 13:01:04 +1000 Subject: [PATCH 026/154] test: add fs/create/dir --- scripts/functionaltest.sh | 2 +- test/func/api/tree/open.lua | 4 +- test/func/fs/create/data/d1/d1f1 | 0 test/func/fs/create/data/f1 | 0 test/func/fs/create/dir.lua | 202 +++++++++++++++++++++++++++++++ test/func/init_live.lua | 3 - 6 files changed, 204 insertions(+), 7 deletions(-) create mode 100644 test/func/fs/create/data/d1/d1f1 create mode 100644 test/func/fs/create/data/f1 create mode 100644 test/func/fs/create/dir.lua diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 0f716bd079c..2ac09dba979 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -40,7 +40,7 @@ files_test_add() { if [ -f "${1}" ]; then FILES_TEST="${FILES_TEST} ${DIR_NVT_PACK}/${1}" elif [ -d "${1}" ]; then - find "${1}" -type f -iname '*lua' -not -iname 'init*.lua' > /tmp/nvt_files_test + find "${1}" -type f -iname '*lua' -not -iname 'init_live.lua' > /tmp/nvt_files_test while IFS= read -r f; do FILES_TEST="${FILES_TEST} ${DIR_NVT_PACK}/${f}" done < /tmp/nvt_files_test diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index 844547b8965..6454b72ce0a 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -3,8 +3,6 @@ local Screen = require("test.functional.ui.screen") local clear = n.clear local exec_lua = n.exec_lua --- TODO extract nvt test utils - --- Reset all NvimTree* highlight groups to just a unique foreground colour --- Add a CL variant with the same background colour as NvimTreeCursorLine --- May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order @@ -123,7 +121,7 @@ NvimTree_1 [-] [No Name] require("nvim-tree.api").tree.open() end) - -- TODO NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode + -- TODO BUG NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode screen:expect({ grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolderCL:^/tmp/nvt_test_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | diff --git a/test/func/fs/create/data/d1/d1f1 b/test/func/fs/create/data/d1/d1f1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/func/fs/create/data/f1 b/test/func/fs/create/data/f1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/func/fs/create/dir.lua b/test/func/fs/create/dir.lua new file mode 100644 index 00000000000..dda62057e47 --- /dev/null +++ b/test/func/fs/create/dir.lua @@ -0,0 +1,202 @@ +local n = require("test.functional.testnvim")() +local t = require('test.testutil') +local Screen = require("test.functional.ui.screen") +local eq = t.eq +local clear = n.clear +local exec_lua = n.exec_lua + +-- TODO extract nvt test utils + +-- TODO file system state persists between tests; consider a mechanism to copy a fresh data directory before each or all + +--- @type test.functional.ui.screen +local screen + +setup(function() + clear() + + screen = Screen.new(80, 24) + + exec_lua(function() + vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) + end) +end) + +before_each(function() + local nvt_test_data = os.getenv("NVT_DIR_TEST_DATA") + if nvt_test_data then + n.api.nvim_set_current_dir(nvt_test_data) + end + + exec_lua(function() + require("nvim-tree").setup({}) + end) +end) + +describe("single", function() + it("direct", function() + n.feed( + ":NvimTreeOpen", + "a", + "direct/" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_test_func/data/.. │ | +   d1 │~ | + ^  direct │~ | +  f1 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_test_func/data/direct/ was properly created | + ]], + }) + + local stat, err = vim.uv.fs_stat("/tmp/nvt_test_func/data/direct") + eq(err, nil) + eq(stat and stat.type, "directory") + end) + + it("indirect", function() + n.feed( + ":NvimTreeOpen", + "gg", + "a", + "d1/indirect/" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_test_func/data/.. │ | +   d1 │~ | + ^   indirect │~ | +  d1f1 │~ | +   direct │~ | +  f1 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_test_func/data/d1/indirect/ was properly created | + ]], + }) + + local stat, err = vim.uv.fs_stat("/tmp/nvt_test_func/data/d1/indirect") + eq(err, nil) + eq(stat and stat.type, "directory") + end) + + it("dir_exists", function() + n.feed( + ":NvimTreeOpen", + "gg", + "a", + "d1/" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_test_func/data/.. │ | +   d1 │~ | +   direct │~ | +  f1 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +NvimTree_1 [-] [No Name] | +[NvimTree] Cannot create: file already exists | + ]], + }) + end) + + it("file_exists", function() + n.feed( + ":NvimTreeOpen", + "gg", + "a", + "d1/d1f1/" + ) + + -- TODO BUG this fails but shows message "/tmp/nvt_test_func/data/d1/d1f1/ was properly created" +-- screen:expect({ +-- attr_ids = {}, +-- grid = [[ +-- ^/tmp/nvt_test_func/data/.. │ | +--   d1 │~ | +--   direct │~ | +--  f1 │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- ~ │~ | +-- NvimTree_1 [-] [No Name] | +-- [NvimTree] Cannot create: file already exists | +-- ]], +-- }) + end) +end) + +-- vim:colorcolumn=80 diff --git a/test/func/init_live.lua b/test/func/init_live.lua index c4c8de04aa7..24145f1e8b0 100644 --- a/test/func/init_live.lua +++ b/test/func/init_live.lua @@ -17,9 +17,6 @@ function LIVE_DUMP() -- absolute cursor position local cursor = { col = vim.fn.screencol(), row = vim.fn.screenrow(), } - -- clear the command line - vim.api.nvim_command("echo") - -- capture all screen lines local lines = {} for row = 1, vim.o.lines do From 1669c2cf67740dd96f7814945a83220e7762e2dd Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 17 Sep 2026 11:13:07 +1000 Subject: [PATCH 027/154] test: clearer func temp directories --- scripts/functionaltest.sh | 30 ++++++------- test/func/README.md | 4 +- test/func/api/tree/open.lua | 11 ++--- test/func/fs/create/dir.lua | 85 ++++++++++++++++++------------------- test/func/init_live.lua | 11 ++--- test/func/map/node/open.lua | 9 ++-- 6 files changed, 69 insertions(+), 81 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 2ac09dba979..8bac1fcd2ba 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -14,24 +14,24 @@ DIR_NVIM_SRC_DEF="/tmp/src/neovim-stable" # nvim-tree linked as a package under source DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" -# working directory to copy test data into -DIR_WORK="/tmp/nvt_test_func" - # absolute paths of test files under nvim source FILES_TEST= # live directory, must contain data DIR_LIVE= -# optional test data directory exported for tests -NVT_DIR_TEST_DATA= +# working directory to copy test data into, cleared before each test +export NVT_TMP_FUNC="/tmp/nvt_func" + +# optional data directory under $NVT_TMP_FUNC +export NVT_TMP_FUNC_DATA= usage() { - echo "Usage: ${0} [-h] [-t ] [-l ]" + echo "Usage: ${0} [-h] [-t ] [-l ]" echo echo " OPTION:" echo " -t Execute single test file or all in directory" - echo " -l Live environment in test data directory" + echo " -l Live environment in test's data directory" echo " -h Show this help" } @@ -91,7 +91,7 @@ if [ ! -d "${DIR_NVT}/lua/nvim-tree" ]; then fi if [ -z "${DIR_NVIM_SRC}" ] && [ -d "${DIR_NVIM_SRC_DEF}" ]; then - export DIR_NVIM_SRC="${DIR_NVIM_SRC_DEF}" + DIR_NVIM_SRC="${DIR_NVIM_SRC_DEF}" fi if [ ! -d "${DIR_NVIM_SRC}" ]; then @@ -114,7 +114,7 @@ fi # after all tests teardown() { rm -fv "${DIR_NVT_PACK}" - rm -rf "${DIR_WORK}" + rm -rf "${NVT_TMP_FUNC}" } # before all tests: builds nvim and links nvim-tree as a package under nvim source @@ -125,15 +125,15 @@ setup() { cd "${DIR_NVT}" } -# if present, copies data directory in $1 to $DIR_WORK/data and sets $NVT_DIR_TEST_DATA +# if present, copies data directory in $1 to $NVT_TMP_FUNC/data and sets $NVT_TMP_FUNC_DATA before_each() { - rm -rf "${DIR_WORK}" - mkdir -p "${DIR_WORK}" + rm -rf "${NVT_TMP_FUNC}" + mkdir -p "${NVT_TMP_FUNC}" if [ -d "${1}/data" ]; then - cp -pr "${1}/data" "${DIR_WORK}" - export NVT_DIR_TEST_DATA="${DIR_WORK}/data" + cp -pr "${1}/data" "${NVT_TMP_FUNC}" + NVT_TMP_FUNC_DATA="${NVT_TMP_FUNC}/data" else - export NVT_DIR_TEST_DATA= + NVT_TMP_FUNC_DATA= fi } diff --git a/test/func/README.md b/test/func/README.md index f46cf7b8dcf..3111098d3c8 100644 --- a/test/func/README.md +++ b/test/func/README.md @@ -1,13 +1,13 @@ # Generating Test Data -Execute `scripts/functionaltest.sh -l ` +Execute `scripts/functionaltest.sh -l ` This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua` ## Text Only: `attr_ids = {}` 1. Perform the actions to be tested -2. Dump the screen `d` to `/tmp/nvt_test_func/dump.txt` +2. Dump the screen `d` to `/tmp/nvt_func/dump.txt` 3. Add the dump to `screen:expect` `grid`, with `attr_ids = {}` The dump will have `|` appended to each line, with a caret `^` at the cursor position. diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index 6454b72ce0a..3e1bd53ef73 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -66,10 +66,7 @@ describe("api_tree_open", function() end) before_each(function() - local nvt_test_data = os.getenv("NVT_DIR_TEST_DATA") - if nvt_test_data then - n.api.nvim_set_current_dir(nvt_test_data) - end + n.api.nvim_set_current_dir(os.getenv("NVT_TMP_FUNC_DATA") or "") exec_lua(function() require("nvim-tree").setup({}) @@ -88,7 +85,7 @@ describe("api_tree_open", function() screen:expect({ attr_ids = {}, grid = [[ - /tmp/nvt_test_func/data/.. │^ | + /tmp/nvt_func/data/.. │^ |   dir1 │~ |   dir2 │~ |  file1 │~ | @@ -124,7 +121,7 @@ NvimTree_1 [-] [No Name] -- TODO BUG NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode screen:expect({ grid = [[ -{NvimTreeSignColumn: }{NvimTreeRootFolderCL:^/tmp/nvt_test_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColumn: }{NvimTreeRootFolderCL:^/tmp/nvt_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:dir1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file1 }{NvimTreeWinSeparator:│}{1:~ }| @@ -146,7 +143,7 @@ NvimTree_1 [-] [No Name] screen:expect({ grid = [[ -{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_test_func/data/..}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | +{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeEmptyFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| diff --git a/test/func/fs/create/dir.lua b/test/func/fs/create/dir.lua index dda62057e47..fd6d932face 100644 --- a/test/func/fs/create/dir.lua +++ b/test/func/fs/create/dir.lua @@ -1,5 +1,5 @@ local n = require("test.functional.testnvim")() -local t = require('test.testutil') +local t = require("test.testutil") local Screen = require("test.functional.ui.screen") local eq = t.eq local clear = n.clear @@ -23,10 +23,7 @@ setup(function() end) before_each(function() - local nvt_test_data = os.getenv("NVT_DIR_TEST_DATA") - if nvt_test_data then - n.api.nvim_set_current_dir(nvt_test_data) - end + n.api.nvim_set_current_dir(os.getenv("NVT_TMP_FUNC_DATA") or "") exec_lua(function() require("nvim-tree").setup({}) @@ -44,7 +41,7 @@ describe("single", function() screen:expect({ attr_ids = {}, grid = [[ - /tmp/nvt_test_func/data/.. │ | + /tmp/nvt_func/data/.. │ |   d1 │~ | ^  direct │~ |  f1 │~ | @@ -67,12 +64,12 @@ describe("single", function() ~ │~ | ~ │~ | NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_test_func/data/direct/ was properly created | +[NvimTree] /tmp/nvt_func/data/direct/ was properly created | ]], }) - local stat, err = vim.uv.fs_stat("/tmp/nvt_test_func/data/direct") - eq(err, nil) + local stat, err = vim.uv.fs_stat("/tmp/nvt_func/data/direct") + eq(err, nil) eq(stat and stat.type, "directory") end) @@ -87,7 +84,7 @@ NvimTree_1 [-] [No Name] screen:expect({ attr_ids = {}, grid = [[ - /tmp/nvt_test_func/data/.. │ | + /tmp/nvt_func/data/.. │ |   d1 │~ | ^   indirect │~ |  d1f1 │~ | @@ -110,12 +107,12 @@ NvimTree_1 [-] [No Name] ~ │~ | ~ │~ | NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_test_func/data/d1/indirect/ was properly created | +[NvimTree] /tmp/nvt_func/data/d1/indirect/ was properly created | ]], }) - local stat, err = vim.uv.fs_stat("/tmp/nvt_test_func/data/d1/indirect") - eq(err, nil) + local stat, err = vim.uv.fs_stat("/tmp/nvt_func/data/d1/indirect") + eq(err, nil) eq(stat and stat.type, "directory") end) @@ -130,7 +127,7 @@ NvimTree_1 [-] [No Name] screen:expect({ attr_ids = {}, grid = [[ - ^/tmp/nvt_test_func/data/.. │ | + ^/tmp/nvt_func/data/.. │ |   d1 │~ |   direct │~ |  f1 │~ | @@ -166,36 +163,36 @@ NvimTree_1 [-] [No Name] "d1/d1f1/" ) - -- TODO BUG this fails but shows message "/tmp/nvt_test_func/data/d1/d1f1/ was properly created" --- screen:expect({ --- attr_ids = {}, --- grid = [[ --- ^/tmp/nvt_test_func/data/.. │ | ---   d1 │~ | ---   direct │~ | ---  f1 │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- ~ │~ | --- NvimTree_1 [-] [No Name] | --- [NvimTree] Cannot create: file already exists | --- ]], --- }) + -- TODO BUG this fails but shows message "/tmp/nvt_func/data/d1/d1f1/ was properly created" + -- screen:expect({ + -- attr_ids = {}, + -- grid = [[ + -- ^/tmp/nvt_func/data/.. │ | + --   d1 │~ | + --   direct │~ | + --  f1 │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- ~ │~ | + -- NvimTree_1 [-] [No Name] | + -- [NvimTree] Cannot create: file already exists | + -- ]], + -- }) end) end) diff --git a/test/func/init_live.lua b/test/func/init_live.lua index 24145f1e8b0..847fe41abfe 100644 --- a/test/func/init_live.lua +++ b/test/func/init_live.lua @@ -1,12 +1,10 @@ -local dump_path = "/tmp/nvt_test_func/dump.txt" - -- match the test screen size: r to reapply if the terminal is not cooperating local function screen_resize() vim.o.columns = 80 vim.o.lines = 24 end ----dump the screen to dump_path: d +---dump the screen to $NVT_TMP_FUNC/dump.txt: d ---pipe is appended to each line ---caret is inserted at the cursor position ---this is global so that we can execute it as a command, without changing cursor position @@ -30,6 +28,8 @@ function LIVE_DUMP() lines[row] = line .. "|" end + local dump_path = os.getenv("NVT_TMP_FUNC") .. "/dump.txt" + -- dump to file vim.fn.writefile(lines, dump_path) vim.api.nvim_command("echo 'dumped screen to " .. dump_path .. "'") @@ -48,10 +48,7 @@ screen_resize() vim.o.background = "dark" -- move to the data directory -local nvt_test_data = os.getenv("NVT_DIR_TEST_DATA") -if nvt_test_data then - vim.api.nvim_set_current_dir(nvt_test_data) -end +vim.api.nvim_set_current_dir(os.getenv("NVT_TMP_FUNC_DATA") or "") ---add the plugin under test vim.api.nvim_command("packadd nvim-tree.lua") diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index 4d39185566f..e7300d038f9 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -18,10 +18,7 @@ describe("map_node_open", function() end) before_each(function() - local nvt_test_data = os.getenv("NVT_DIR_TEST_DATA") - if nvt_test_data then - n.api.nvim_set_current_dir(nvt_test_data) - end + n.api.nvim_set_current_dir(os.getenv("NVT_TMP_FUNC_DATA") or "") exec_lua(function() require("nvim-tree").setup({}) @@ -40,7 +37,7 @@ describe("map_node_open", function() screen:expect({ attr_ids = {}, grid = [[ - /tmp/nvt_test_func/data/.. │ | + /tmp/nvt_func/data/.. │ | ^  d1 │~ |  f1 │~ |  f2 │~ | @@ -79,7 +76,7 @@ NvimTree_1 [-] [No Name] screen:expect({ attr_ids = {}, grid = [[ - /tmp/nvt_test_func/data/.. │^f1 | + /tmp/nvt_func/data/.. │^f1 |   d1 │~ |   d2 │~ |  f1 │~ | From 6ae3b961b360006360f434c0782ef0515b73525a Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 17 Sep 2026 11:57:23 +1000 Subject: [PATCH 028/154] test: live_dump no longer global --- test/func/init_live.lua | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test/func/init_live.lua b/test/func/init_live.lua index 847fe41abfe..9e4d6c1e54e 100644 --- a/test/func/init_live.lua +++ b/test/func/init_live.lua @@ -7,9 +7,7 @@ end ---dump the screen to $NVT_TMP_FUNC/dump.txt: d ---pipe is appended to each line ---caret is inserted at the cursor position ----this is global so that we can execute it as a command, without changing cursor position ----@diagnostic disable-next-line: missing-global-doc, global-element -function LIVE_DUMP() +local function live_dump() screen_resize() -- absolute cursor position @@ -38,8 +36,8 @@ function LIVE_DUMP() vim.ui.open(dump_path) end -vim.keymap.set("n", "d", "lua LIVE_DUMP()", { remap = false, }) -vim.keymap.set("n", "r", screen_resize, { remap = false, }) +vim.keymap.set("n", "d", live_dump, { remap = false, }) +vim.keymap.set("n", "r", screen_resize, { remap = false, }) ---set the screen size to match tests screen_resize() From fd0041f9308fcf0608c9897595999ae9a60b881a Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 17 Sep 2026 13:17:00 +1000 Subject: [PATCH 029/154] test: optionally collapse screen dumps --- test/func/README.md | 8 +++-- test/func/fs/create/dir.lua | 19 +---------- test/func/init_live.lua | 68 ++++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 40 deletions(-) diff --git a/test/func/README.md b/test/func/README.md index 3111098d3c8..7c5cb73aff1 100644 --- a/test/func/README.md +++ b/test/func/README.md @@ -4,16 +4,18 @@ Execute `scripts/functionaltest.sh -l ` This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua` +- `u` to dump the entire screen to `/tmp/nvt_func/dump.txt` and open it +- `c` to dump with identical lines collapsed +- `r` to resize the screen to 80 x 24, to match tests + ## Text Only: `attr_ids = {}` 1. Perform the actions to be tested -2. Dump the screen `d` to `/tmp/nvt_func/dump.txt` +2. Dump the screen `u` or `c>` to `/tmp/nvt_func/dump.txt` 3. Add the dump to `screen:expect` `grid`, with `attr_ids = {}` The dump will have `|` appended to each line, with a caret `^` at the cursor position. -The sessions should have screen size 80x24. Use `r` to reset the size if the terminal has changed it. - ## Text And Highlight Additional work is required to add highlight groups. diff --git a/test/func/fs/create/dir.lua b/test/func/fs/create/dir.lua index fd6d932face..d534dfdef16 100644 --- a/test/func/fs/create/dir.lua +++ b/test/func/fs/create/dir.lua @@ -45,24 +45,7 @@ describe("single", function()   d1 │~ | ^  direct │~ |  f1 │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | +~ │~ |*18 NvimTree_1 [-] [No Name] | [NvimTree] /tmp/nvt_func/data/direct/ was properly created | ]], diff --git a/test/func/init_live.lua b/test/func/init_live.lua index 9e4d6c1e54e..e535180cb04 100644 --- a/test/func/init_live.lua +++ b/test/func/init_live.lua @@ -4,29 +4,58 @@ local function screen_resize() vim.o.lines = 24 end ----dump the screen to $NVT_TMP_FUNC/dump.txt: d +---dump the screen to $NVT_TMP_FUNC/dump.txt: d for raw, c for collapsed ---pipe is appended to each line ---caret is inserted at the cursor position -local function live_dump() - screen_resize() - - -- absolute cursor position - local cursor = { col = vim.fn.screencol(), row = vim.fn.screenrow(), } - - -- capture all screen lines - local lines = {} - for row = 1, vim.o.lines do - local line = "" - for col = 1, vim.o.columns do - if row == cursor.row and col == cursor.col then - line = line .. "^" +---@param collapse boolean identical lines collapsed with "*n" appended +local function live_dump(collapse) + local dump_path = os.getenv("NVT_TMP_FUNC") .. "/dump.txt" + + local function cap_lines() + -- absolute cursor position + local cursor = { col = vim.fn.screencol(), row = vim.fn.screenrow(), } + + -- capture all screen lines + local lines = {} + for row = 1, vim.o.lines do + local line = "" + for col = 1, vim.o.columns do + if row == cursor.row and col == cursor.col then + line = line .. "^" + end + line = line .. vim.fn.screenstring(row, col) end - line = line .. vim.fn.screenstring(row, col) + lines[row] = line .. "|" end - lines[row] = line .. "|" + + return lines end - local dump_path = os.getenv("NVT_TMP_FUNC") .. "/dump.txt" + local function compress_lines(lines) + local ret = {} + local n = 0 + + for i = 1, #lines + 1 do + if lines[i - 1] == lines[i] then + n = n + 1 + else + if n > 0 then + table.insert(ret, lines[i - 1] .. "*" .. n + 1) + else + table.insert(ret, lines[i - 1]) + end + n = 0 + end + end + + return ret + end + + local lines = cap_lines() + + if collapse then + lines = compress_lines(lines) + end -- dump to file vim.fn.writefile(lines, dump_path) @@ -36,8 +65,9 @@ local function live_dump() vim.ui.open(dump_path) end -vim.keymap.set("n", "d", live_dump, { remap = false, }) -vim.keymap.set("n", "r", screen_resize, { remap = false, }) +vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) +vim.keymap.set("n", "c", function() live_dump(true) end, { remap = false, }) +vim.keymap.set("n", "r", screen_resize, { remap = false, }) ---set the screen size to match tests screen_resize() From 4ed7c2dd1daa58f30467298d8cafe76c19bd369e Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 10:32:39 +1000 Subject: [PATCH 030/154] test: add test/ to lint and style --- .luacheckrc | 13 +++++++++++-- Makefile | 1 + scripts/luals-check.sh | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.luacheckrc b/.luacheckrc index 267d0ce54ce..82be35053f8 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -4,12 +4,21 @@ local M = {} M.self = false M.ignore = { - "631", -- max_line_length + "631", -- max_line_length } --- Global objects defined by the C code M.globals = { + -- Global objects defined by the C code "vim", + -- Global neovim test functions + "it", + "describe", + "pending", + "setup", + "before_each", + "after_each", + "teardown", + "finally", } return M diff --git a/Makefile b/Makefile index bd65580b90b..59c7f86f22c 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ check: luals # luacheck: luacheck --codes --quiet lua --exclude-files "**/_meta/**" + luacheck --codes --quiet test style-check: scripts/luals-check.sh codestyle-check diff --git a/scripts/luals-check.sh b/scripts/luals-check.sh index a57b4546403..170f25f3f2a 100755 --- a/scripts/luals-check.sh +++ b/scripts/luals-check.sh @@ -50,7 +50,7 @@ case "${1}" in ;; esac -for SRC in lua scripts; do +for SRC in lua scripts test; do DIR_SRC="${DIR_NVT}/${SRC}" FILE_OUT="${DIR_OUT}/out.${SRC}.log" echo "Checking ${SRC}/" From 6bf2573e84efd65f86a00e6ee55e546def7f314d Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 11:53:30 +1000 Subject: [PATCH 031/154] test: extract common scripts/check-nvim-src.sh --- scripts/check-nvim-src.sh | 30 ++++++++++++++++++++++++++++++ scripts/functionaltest.sh | 38 ++++++++------------------------------ scripts/vimdoc.sh | 24 ++---------------------- 3 files changed, 40 insertions(+), 52 deletions(-) create mode 100755 scripts/check-nvim-src.sh diff --git a/scripts/check-nvim-src.sh b/scripts/check-nvim-src.sh new file mode 100755 index 00000000000..09030902db1 --- /dev/null +++ b/scripts/check-nvim-src.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env sh + +# common script to check the availability of neovim source +# - NOP if $DIR_NVIM_SRC is defined +# - sets $DIR_NVIM_SRC to /tmp/src/neovim-stable if present +# - otherwise prompts with instructions +# script must be sourced to receive the exported $DIR_NVIM_SRC + +DIR_NVIM_SRC_DEF="/tmp/src/neovim-stable" + +if [ -z "${DIR_NVIM_SRC}" ] && [ -d "${DIR_NVIM_SRC_DEF}" ]; then + export DIR_NVIM_SRC="${DIR_NVIM_SRC_DEF}" +fi + +if [ ! -d "${DIR_NVIM_SRC}" ]; then + cat << EOM + +Nvim stable source is required to run ${0} + +Unavailable: ${DIR_NVIM_SRC_DEF} or \$DIR_NVIM_SRC=${DIR_NVIM_SRC} + +Please: + mkdir -p ${DIR_NVIM_SRC_DEF} + curl -L 'https://github.com/neovim/neovim/archive/refs/tags/stable.tar.gz' | tar zx --directory $(dirname "${DIR_NVIM_SRC_DEF}") + or use your own e.g. + export DIR_NVIM_SRC="\${HOME}/src/neovim" + +EOM +exit 1 +fi diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 8bac1fcd2ba..566fab0ba23 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -5,12 +5,17 @@ set -e +if [ ! -d "test/func" ]; then + echo "Must be run from nvim-tree root" 1>&2 + exit 1 +fi + +# define $DIR_NVIM_SRC +. scripts/check-nvim-src.sh + # code under test DIR_NVT="${PWD}" -# neovim source -DIR_NVIM_SRC_DEF="/tmp/src/neovim-stable" - # nvim-tree linked as a package under source DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" @@ -84,33 +89,6 @@ while getopts "hl:t:" o; do esac done -# TODO extract common functionality from vimdoc.sh -if [ ! -d "${DIR_NVT}/lua/nvim-tree" ]; then - echo "Must be run from nvim-tree root" 1>&2 - exit 1 -fi - -if [ -z "${DIR_NVIM_SRC}" ] && [ -d "${DIR_NVIM_SRC_DEF}" ]; then - DIR_NVIM_SRC="${DIR_NVIM_SRC_DEF}" -fi - -if [ ! -d "${DIR_NVIM_SRC}" ]; then - cat << EOM - -Nvim stable source is required to run ${0} - -Unavailable: ${DIR_NVIM_SRC_DEF} or \$DIR_NVIM_SRC=${DIR_NVIM_SRC} - -Please: - mkdir -p ${DIR_NVIM_SRC_DEF} - curl -L 'https://github.com/neovim/neovim/archive/refs/tags/stable.tar.gz' | tar zx --directory $(dirname "${DIR_NVIM_SRC_DEF}") - or use your own e.g. - export DIR_NVIM_SRC="\${HOME}/src/neovim" - -EOM -exit 1 -fi - # after all tests teardown() { rm -fv "${DIR_NVT_PACK}" diff --git a/scripts/vimdoc.sh b/scripts/vimdoc.sh index cb8f8e6b27a..4c8751a9cbc 100755 --- a/scripts/vimdoc.sh +++ b/scripts/vimdoc.sh @@ -15,33 +15,13 @@ if [ $# -ne 1 ] || [ "${1}" != "doc" ]; then exit 1 fi -DIR_NVIM_SRC_DEF="/tmp/src/neovim-stable" - if [ ! -d "lua/nvim-tree" ]; then echo "Must be run from nvim-tree root" 1>&2 exit 1 fi -if [ -z "${DIR_NVIM_SRC}" ] && [ -d "${DIR_NVIM_SRC_DEF}" ]; then - export DIR_NVIM_SRC="${DIR_NVIM_SRC_DEF}" -fi - -if [ ! -d "${DIR_NVIM_SRC}" ]; then - cat << EOM - -Nvim stable source is required to run ${0} - -Unavailable: ${DIR_NVIM_SRC_DEF} or \$DIR_NVIM_SRC=${DIR_NVIM_SRC} - -Please: - mkdir -p ${DIR_NVIM_SRC_DEF} - curl -L 'https://github.com/neovim/neovim/archive/refs/tags/stable.tar.gz' | tar zx --directory $(dirname "${DIR_NVIM_SRC_DEF}") - or use your own e.g. - export DIR_NVIM_SRC="\${HOME}/src/neovim" - -EOM -exit 1 -fi +# define $DIR_NVIM_SRC +. scripts/check-nvim-src.sh cleanup() { # remove source link From 8d17bc59090298aaf95e459723ef032d9d82ba9d Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 12:00:38 +1000 Subject: [PATCH 032/154] test: add functionaltest ci job --- .github/workflows/ci.yml | 30 ++++++++++++++++++++++++++++++ Makefile | 5 +++++ 2 files changed, 35 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3740fb7e923..bd801a2e4a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,3 +98,33 @@ jobs: - run: make help-check if: ${{ matrix.nvim_version == 'stable' }} + + functionaltest: + runs-on: ubuntu-latest + + concurrency: + group: ${{ github.workflow }}-${{ matrix.nvim_version }}-${{ github.head_ref || github.ref_name }} + cancel-in-progress: true + + strategy: + matrix: + nvim_version: [ stable, nightly ] + + env: + VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime + DIR_NVIM_SRC: /home/runner/src/neovim-${{ matrix.nvim_version }} + + steps: + - name: checkout + uses: actions/checkout@v7 + + - name: build Nvim from source + if: ${{ matrix.nvim_version == 'stable' }} + run: | + mkdir -p "${DIR_NVIM_SRC}" + curl -L "https://github.com/neovim/neovim/archive/refs/tags/${{ matrix.nvim_version }}.tar.gz" | tar zx --directory "${DIR_NVIM_SRC}/.." + cd "${DIR_NVIM_SRC}" + make + + - run: make functionaltest + if: ${{ matrix.nvim_version == 'stable' }} diff --git a/Makefile b/Makefile index 59c7f86f22c..40d278b6142 100644 --- a/Makefile +++ b/Makefile @@ -48,6 +48,11 @@ help-update: help-check: help-update git diff --exit-code doc/nvim-tree-lua.txt +# +# tests +# +functionaltest: + scripts/functionaltest.sh .PHONY: all lint style check luacheck style-check style-doc luals format-fix format-check help-update help-check From 5938938a6e39af7838f56a9a5bdb716fba55cc82 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 12:16:48 +1000 Subject: [PATCH 033/154] test: ensure no empty directories in func test data --- test/func/api/tree/data/dir1/dir1file1 | 0 test/func/api/tree/data/dir2/dir2file1 | 0 test/func/api/tree/open.lua | 12 ++++++------ test/func/map/node/data/d2/f1 | 0 test/func/map/node/open.lua | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) create mode 100644 test/func/api/tree/data/dir1/dir1file1 create mode 100644 test/func/api/tree/data/dir2/dir2file1 create mode 100644 test/func/map/node/data/d2/f1 diff --git a/test/func/api/tree/data/dir1/dir1file1 b/test/func/api/tree/data/dir1/dir1file1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/func/api/tree/data/dir2/dir2file1 b/test/func/api/tree/data/dir2/dir2file1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index 3e1bd53ef73..75f7536195c 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -86,8 +86,8 @@ describe("api_tree_open", function() attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │^ | -   dir1 │~ | -   dir2 │~ | +   dir1 │~ | +   dir2 │~ |  file1 │~ |  file2 │~ | ~ │~ | @@ -122,8 +122,8 @@ NvimTree_1 [-] [No Name] screen:expect({ grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolderCL:^/tmp/nvt_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:dir1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:dir1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:dir2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file2 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 @@ -144,8 +144,8 @@ NvimTree_1 [-] [No Name] screen:expect({ grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeEmptyFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeEmptyFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 diff --git a/test/func/map/node/data/d2/f1 b/test/func/map/node/data/d2/f1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index e7300d038f9..f23a5963afc 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -41,7 +41,7 @@ describe("map_node_open", function() ^  d1 │~ |  f1 │~ |  f2 │~ | -   d2 │~ | +   d2 │~ |  f1 │~ |  f2 │~ | ~ │~ | @@ -78,7 +78,7 @@ NvimTree_1 [-] [No Name] grid = [[ /tmp/nvt_func/data/.. │^f1 |   d1 │~ | -   d2 │~ | +   d2 │~ |  f1 │~ |  f2 │~ | ~ │~ | From b02c09cd6738c09a08b839a2f60ac75e160273fa Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 12:18:44 +1000 Subject: [PATCH 034/154] test: run functest against nightly --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bd801a2e4a5..6a8ece7137f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,7 +119,6 @@ jobs: uses: actions/checkout@v7 - name: build Nvim from source - if: ${{ matrix.nvim_version == 'stable' }} run: | mkdir -p "${DIR_NVIM_SRC}" curl -L "https://github.com/neovim/neovim/archive/refs/tags/${{ matrix.nvim_version }}.tar.gz" | tar zx --directory "${DIR_NVIM_SRC}/.." @@ -127,4 +126,3 @@ jobs: make - run: make functionaltest - if: ${{ matrix.nvim_version == 'stable' }} From 59ee8cd868fefa1780377cd73bccb619df2f48e4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 12:33:14 +1000 Subject: [PATCH 035/154] test: stable and nightly test compatibility --- .github/workflows/ci.yml | 2 +- Makefile | 6 ------ scripts/functionaltest.sh | 1 + test/func/api/tree/open.lua | 7 +++++++ test/func/fs/create/dir.lua | 8 +++++++- test/func/map/node/open.lua | 7 +++++++ 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6a8ece7137f..d8eaa5ea8ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -125,4 +125,4 @@ jobs: cd "${DIR_NVIM_SRC}" make - - run: make functionaltest + - run: scripts/functionaltest.sh diff --git a/Makefile b/Makefile index 40d278b6142..4d6224dad31 100644 --- a/Makefile +++ b/Makefile @@ -48,11 +48,5 @@ help-update: help-check: help-update git diff --exit-code doc/nvim-tree-lua.txt -# -# tests -# -functionaltest: - scripts/functionaltest.sh - .PHONY: all lint style check luacheck style-check style-doc luals format-fix format-check help-update help-check diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 566fab0ba23..27f5ffa9675 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -70,6 +70,7 @@ live_add() { fi } +# TODO fail on scripts/functionaltest.sh foo while getopts "hl:t:" o; do case "$o" in h) diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index 75f7536195c..231540d5697 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -1,8 +1,15 @@ +local t = require("test.testutil") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear local exec_lua = n.exec_lua +-- 0.13 global compatibility +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +local setup = t.setup or setup + --- Reset all NvimTree* highlight groups to just a unique foreground colour --- Add a CL variant with the same background colour as NvimTreeCursorLine --- May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order diff --git a/test/func/fs/create/dir.lua b/test/func/fs/create/dir.lua index d534dfdef16..93dd4c8bfd0 100644 --- a/test/func/fs/create/dir.lua +++ b/test/func/fs/create/dir.lua @@ -1,10 +1,16 @@ -local n = require("test.functional.testnvim")() local t = require("test.testutil") +local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local eq = t.eq local clear = n.clear local exec_lua = n.exec_lua +-- 0.13 global compatibility +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +local setup = t.setup or setup + -- TODO extract nvt test utils -- TODO file system state persists between tests; consider a mechanism to copy a fresh data directory before each or all diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index f23a5963afc..cbd6004b1a4 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -1,8 +1,15 @@ +local t = require('test.testutil') local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear local exec_lua = n.exec_lua +-- 0.13 global compatibility +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +local setup = t.setup or setup + describe("map_node_open", function() --- @type test.functional.ui.screen local screen From cda1708984dd3aeea8caa7e8e3677f307e12ad58 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 12:58:43 +1000 Subject: [PATCH 036/154] test: luals-check for functests --- .github/workflows/ci.yml | 4 +++ Makefile | 6 ++-- scripts/luals-check.sh | 66 +++++++++++++++++++++++-------------- test/func/map/node/open.lua | 2 +- 4 files changed, 51 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8eaa5ea8ce..c06f71783a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -126,3 +126,7 @@ jobs: make - run: scripts/functionaltest.sh + + - run: scripts/luals-check.sh test + + - run: scripts/luals-check.sh codestyle-check test diff --git a/Makefile b/Makefile index 4d6224dad31..9db6f48e498 100644 --- a/Makefile +++ b/Makefile @@ -17,13 +17,15 @@ luacheck: luacheck --codes --quiet test style-check: - scripts/luals-check.sh codestyle-check + scripts/luals-check.sh codestyle-check lua + scripts/luals-check.sh codestyle-check scripts style-doc: scripts/doc-comments.sh luals: - scripts/luals-check.sh + scripts/luals-check.sh lua + scripts/luals-check.sh scripts # # format diff --git a/scripts/luals-check.sh b/scripts/luals-check.sh index 170f25f3f2a..4483a62ebeb 100755 --- a/scripts/luals-check.sh +++ b/scripts/luals-check.sh @@ -1,15 +1,39 @@ #!/usr/bin/env sh -# Performs a lua-language-server check on all lua files. +# Performs a lua-language-server check. # $VIMRUNTIME specifies neovim runtime path, defaults to "/usr/share/nvim/runtime" if unset. +# $DIR_NVIM_SRC will be checked and set for test files. # # Call with codestyle-check param to enable only codestyle-check # # lua-language-server is inconsisent about which parameters must be absolute paths therefore we pass every path as absolute -if [ $# -eq 1 ] && [ "${1}" != "codestyle-check" ] || [ $# -gt 1 ] ; then - echo "usage: ${0} [codestyle-check]" 1>&2 - exit 1 +usage() { + echo "usage: ${0} [codestyle-check] " 1>&2 +} + +if [ $# -eq 2 ]; then + if [ "${1}" != "codestyle-check" ]; then + usage + exit 1 + fi + STYLE=true + shift +fi + +case "${1}" in + lua|scripts|test) + TARGET="${1}" + ;; + *) + usage + exit 0 + ;; +esac + +# neovim source needed for tests +if [ "${TARGET}" = "test" ]; then + . scripts/check-nvim-src.sh fi DIR_NVT="${PWD}" @@ -38,28 +62,22 @@ rm -rf "${DIR_OUT}" mkdir "${DIR_OUT}" # create the luarc.json for the requested check -case "${1}" in - "codestyle-check") - jq \ - '.diagnostics.neededFileStatus[] = "None" | .diagnostics.neededFileStatus."codestyle-check" = "Any"' \ - "${DIR_NVT}/.luarc.json" > "${LUARC}" - - ;; - *) - cp "${DIR_NVT}/.luarc.json" "${LUARC}" - ;; -esac +if [ -n "${STYLE}" ]; then + jq \ + '.diagnostics.neededFileStatus[] = "None" | .diagnostics.neededFileStatus."codestyle-check" = "Any"' \ + "${DIR_NVT}/.luarc.json" > "${LUARC}" +else + cp "${DIR_NVT}/.luarc.json" "${LUARC}" +fi -for SRC in lua scripts test; do - DIR_SRC="${DIR_NVT}/${SRC}" - FILE_OUT="${DIR_OUT}/out.${SRC}.log" - echo "Checking ${SRC}/" +DIR_SRC="${DIR_NVT}/${TARGET}" +FILE_OUT="${DIR_OUT}/out.${TARGET}.log" +echo "Checking ${TARGET}/" - lua-language-server --check="${DIR_SRC}" --configpath="${LUARC}" --checklevel=Information --logpath="${DIR_OUT}" --loglevel=error 2>&1 | tee "${FILE_OUT}" +lua-language-server --check="${DIR_SRC}" --configpath="${LUARC}" --checklevel=Information --logpath="${DIR_OUT}" --loglevel=error 2>&1 | tee "${FILE_OUT}" - if ! grep --quiet "Diagnosis completed, no problems found" "${FILE_OUT}"; then - RC=1 - fi -done +if ! grep --quiet "Diagnosis completed, no problems found" "${FILE_OUT}"; then + RC=1 +fi exit "${RC}" diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index cbd6004b1a4..2d76be1fe0c 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -1,4 +1,4 @@ -local t = require('test.testutil') +local t = require("test.testutil") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear From cb2ded9b865b9e6f73186e1426db6739a303f5cb Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 13:05:31 +1000 Subject: [PATCH 037/154] test: luals-check uses neovim source runtime --- scripts/luals-check.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/luals-check.sh b/scripts/luals-check.sh index 4483a62ebeb..4c8e9dcbfae 100755 --- a/scripts/luals-check.sh +++ b/scripts/luals-check.sh @@ -34,6 +34,7 @@ esac # neovim source needed for tests if [ "${TARGET}" = "test" ]; then . scripts/check-nvim-src.sh + export VIMRUNTIME="${DIR_NVIM_SRC}/runtime" fi DIR_NVT="${PWD}" From 4652dccf13f7aff0686e784ec845a655cc1c9cbc Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 13:08:57 +1000 Subject: [PATCH 038/154] test: add luals for functest --- .github/workflows/ci.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c06f71783a8..87116fdd485 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,12 +103,13 @@ jobs: runs-on: ubuntu-latest concurrency: - group: ${{ github.workflow }}-${{ matrix.nvim_version }}-${{ github.head_ref || github.ref_name }} + group: ${{ github.workflow }}-${{ matrix.nvim_version }}-${{ matrix.luals_version }}-${{ github.head_ref || github.ref_name }} cancel-in-progress: true strategy: matrix: nvim_version: [ stable, nightly ] + luals_version: [ 3.15.0 ] env: VIMRUNTIME: /home/runner/nvim-${{ matrix.nvim_version }}/share/nvim/runtime @@ -118,6 +119,12 @@ jobs: - name: checkout uses: actions/checkout@v7 + - name: install lua-language-server ${{ matrix.luals_version }} + run: | + mkdir -p luals + curl -L "https://github.com/LuaLS/lua-language-server/releases/download/${{ matrix.luals_version }}/lua-language-server-${{ matrix.luals_version }}-linux-x64.tar.gz" | tar zx --directory luals + echo "luals/bin" >> "$GITHUB_PATH" + - name: build Nvim from source run: | mkdir -p "${DIR_NVIM_SRC}" From 3524a7b992aae7af49b0cc40e6b877753b95d803 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 18 Sep 2026 13:14:26 +1000 Subject: [PATCH 039/154] test: stable and nightly test compatibility --- scripts/luals-check.sh | 1 + test/func/api/tree/open.lua | 2 ++ test/func/fs/create/dir.lua | 2 ++ test/func/map/node/open.lua | 2 ++ 4 files changed, 7 insertions(+) diff --git a/scripts/luals-check.sh b/scripts/luals-check.sh index 4c8e9dcbfae..2ecc8671df7 100755 --- a/scripts/luals-check.sh +++ b/scripts/luals-check.sh @@ -8,6 +8,7 @@ # # lua-language-server is inconsisent about which parameters must be absolute paths therefore we pass every path as absolute +# TODO change to an optional -c argument usage() { echo "usage: ${0} [codestyle-check] " 1>&2 } diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index 231540d5697..c241e9a331c 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -5,10 +5,12 @@ local clear = n.clear local exec_lua = n.exec_lua -- 0.13 global compatibility +---@diagnostic disable: undefined-global local describe = t.describe or describe local before_each = t.before_each or before_each local it = t.it or it local setup = t.setup or setup +---@diagnostic enable: undefined-global --- Reset all NvimTree* highlight groups to just a unique foreground colour --- Add a CL variant with the same background colour as NvimTreeCursorLine diff --git a/test/func/fs/create/dir.lua b/test/func/fs/create/dir.lua index 93dd4c8bfd0..d8694d35076 100644 --- a/test/func/fs/create/dir.lua +++ b/test/func/fs/create/dir.lua @@ -6,10 +6,12 @@ local clear = n.clear local exec_lua = n.exec_lua -- 0.13 global compatibility +---@diagnostic disable: undefined-global local describe = t.describe or describe local before_each = t.before_each or before_each local it = t.it or it local setup = t.setup or setup +---@diagnostic enable: undefined-global -- TODO extract nvt test utils diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index 2d76be1fe0c..062e843dfd8 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -5,10 +5,12 @@ local clear = n.clear local exec_lua = n.exec_lua -- 0.13 global compatibility +---@diagnostic disable: undefined-global local describe = t.describe or describe local before_each = t.before_each or before_each local it = t.it or it local setup = t.setup or setup +---@diagnostic enable: undefined-global describe("map_node_open", function() --- @type test.functional.ui.screen From 76aa4db5e7029d68662ebcd960545de31386dd8e Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 21 Sep 2026 13:07:31 +1000 Subject: [PATCH 040/154] test: func tests are responsible for setting up and tearing down data --- scripts/functionaltest.sh | 52 ++++++++++++++----------------------- test/func/api/tree/open.lua | 29 +++++++++++++++++++-- test/func/fs/create/dir.lua | 52 +++++++++++++++++++++++++++---------- test/func/init_live.lua | 35 +++++++++++++++++++++---- test/func/map/node/open.lua | 29 +++++++++++++++++++-- 5 files changed, 141 insertions(+), 56 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 27f5ffa9675..0ba59dcb183 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -22,14 +22,14 @@ DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" # absolute paths of test files under nvim source FILES_TEST= -# live directory, must contain data +# live source directory DIR_LIVE= -# working directory to copy test data into, cleared before each test -export NVT_TMP_FUNC="/tmp/nvt_func" +# working directory for tests, which are responsible for creating and removing +export NVT_FUNC_TMP="/tmp/nvt_func" -# optional data directory under $NVT_TMP_FUNC -export NVT_TMP_FUNC_DATA= +# test source, which tests may copy data from +export NVT_FUNC_SRC= usage() { echo "Usage: ${0} [-h] [-t ] [-l ]" @@ -56,7 +56,7 @@ files_test_add() { fi } -# create DIR_LIVE if data dir present next to file $1 or in directory $1 +# set DIR_LIVE for directory or test file live_add() { if [ -f "${1}" ]; then DIR_LIVE="$(dirname "${1}")" @@ -64,8 +64,10 @@ live_add() { DIR_LIVE="${1}" fi - if [ ! -d "${DIR_LIVE}/data" ]; then - echo "${DIR_LIVE}/data inexistent" + DIR_LIVE="$(realpath "${DIR_LIVE}")" + + if [ ! -d "${DIR_LIVE}" ]; then + echo "${DIR_LIVE} inexistent" exit 1 fi } @@ -90,33 +92,20 @@ while getopts "hl:t:" o; do esac done -# after all tests -teardown() { - rm -fv "${DIR_NVT_PACK}" - rm -rf "${NVT_TMP_FUNC}" -} - -# before all tests: builds nvim and links nvim-tree as a package under nvim source +# before all tests: links nvim-tree as a package under nvim source setup() { - cd "${DIR_NVIM_SRC}" - make ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" - cd "${DIR_NVT}" } -# if present, copies data directory in $1 to $NVT_TMP_FUNC/data and sets $NVT_TMP_FUNC_DATA -before_each() { - rm -rf "${NVT_TMP_FUNC}" - mkdir -p "${NVT_TMP_FUNC}" - if [ -d "${1}/data" ]; then - cp -pr "${1}/data" "${NVT_TMP_FUNC}" - NVT_TMP_FUNC_DATA="${NVT_TMP_FUNC}/data" - else - NVT_TMP_FUNC_DATA= - fi +# after all tests: remove package link and temp +teardown() { + rm -fv "${DIR_NVT_PACK}" + rm -rf "${NVT_FUNC_TMP}" } live() { + NVT_FUNC_SRC="${DIR_LIVE}" + # options extracted from testnvim.lua nvim_argv, nvim_set nvim \ --clean \ @@ -135,8 +124,6 @@ teardown setup if [ -n "${DIR_LIVE}" ]; then - before_each "${DIR_LIVE}" - live else # run all tests if none specified @@ -144,13 +131,12 @@ else files_test_add "test/func" fi - # run from nvim source root + # must run from nvim source root cd "${DIR_NVIM_SRC}" # execute all tests for f in ${FILES_TEST}; do - before_each "$(dirname "${f}")" - + NVT_FUNC_SRC="$(dirname "${f}")" make functionaltest TEST_FILE="${f}" done fi diff --git a/test/func/api/tree/open.lua b/test/func/api/tree/open.lua index c241e9a331c..73a8ee835de 100644 --- a/test/func/api/tree/open.lua +++ b/test/func/api/tree/open.lua @@ -60,6 +60,31 @@ local function nvt_hl_attr_ids(screen) screen:add_extra_attr_ids(attr_ids) end +-- remove $NVT_FUNC_TMP +-- cd to $NVT_FUNC_TMP +-- if $NVT_FUNC_SRC/data exists:recursively copy it to $NVT_FUNC_TMP and cd +local function setup_dirs() + local tmp = os.getenv("NVT_FUNC_TMP") + if not tmp then + return + end + + -- blow away temp + print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) + print(n.fn.system({ "mkdir", "-p", "-v", tmp })) + + -- always cd to tmp + n.api.nvim_set_current_dir(tmp) + + -- maybe copy data and cd + local src = os.getenv("NVT_FUNC_SRC") + if src then + -- TODO handle data not present + print(n.fn.system({ "cp", "-p", "-r", "-v", src .. "/data", tmp .. "/data" })) + n.api.nvim_set_current_dir(tmp .. "/data") + end +end + describe("api_tree_open", function() --- @type test.functional.ui.screen local screen @@ -72,11 +97,11 @@ describe("api_tree_open", function() exec_lua(function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) + + setup_dirs() end) before_each(function() - n.api.nvim_set_current_dir(os.getenv("NVT_TMP_FUNC_DATA") or "") - exec_lua(function() require("nvim-tree").setup({}) end) diff --git a/test/func/fs/create/dir.lua b/test/func/fs/create/dir.lua index d8694d35076..b47ceee2147 100644 --- a/test/func/fs/create/dir.lua +++ b/test/func/fs/create/dir.lua @@ -14,31 +14,55 @@ local setup = t.setup or setup ---@diagnostic enable: undefined-global -- TODO extract nvt test utils - --- TODO file system state persists between tests; consider a mechanism to copy a fresh data directory before each or all +-- TODO use vim.system instead of vim.fn.system + +-- remove $NVT_FUNC_TMP +-- cd to $NVT_FUNC_TMP +-- if $NVT_FUNC_SRC/data exists:recursively copy it to $NVT_FUNC_TMP and cd +local function setup_dirs() + local tmp = os.getenv("NVT_FUNC_TMP") + if not tmp then + return + end + + -- blow away temp + print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) + print(n.fn.system({ "mkdir", "-p", "-v", tmp })) + + -- always cd to tmp + n.api.nvim_set_current_dir(tmp) + + -- maybe copy data and cd + local src = os.getenv("NVT_FUNC_SRC") + if src then + -- TODO handle data not present + print(n.fn.system({ "cp", "-p", "-r", "-v", src .. "/data", tmp .. "/data" })) + n.api.nvim_set_current_dir(tmp .. "/data") + end +end --- @type test.functional.ui.screen local screen -setup(function() - clear() - - screen = Screen.new(80, 24) - - exec_lua(function() - vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) - end) -end) - before_each(function() - n.api.nvim_set_current_dir(os.getenv("NVT_TMP_FUNC_DATA") or "") - exec_lua(function() require("nvim-tree").setup({}) end) end) describe("single", function() + setup(function() + clear() + + screen = Screen.new(80, 24) + + exec_lua(function() + vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) + end) + + setup_dirs() + end) + it("direct", function() n.feed( ":NvimTreeOpen", diff --git a/test/func/init_live.lua b/test/func/init_live.lua index e535180cb04..f8bffcbdb16 100644 --- a/test/func/init_live.lua +++ b/test/func/init_live.lua @@ -4,12 +4,12 @@ local function screen_resize() vim.o.lines = 24 end ----dump the screen to $NVT_TMP_FUNC/dump.txt: d for raw, c for collapsed +---dump the screen to $NVT_FUNC_TMP/dump.txt: d for raw, c for collapsed ---pipe is appended to each line ---caret is inserted at the cursor position ---@param collapse boolean identical lines collapsed with "*n" appended local function live_dump(collapse) - local dump_path = os.getenv("NVT_TMP_FUNC") .. "/dump.txt" + local dump_path = os.getenv("NVT_FUNC_TMP") .. "/dump.txt" local function cap_lines() -- absolute cursor position @@ -75,9 +75,34 @@ screen_resize() -- use dark background for readability under dark and light vim.o.background = "dark" --- move to the data directory -vim.api.nvim_set_current_dir(os.getenv("NVT_TMP_FUNC_DATA") or "") - ---add the plugin under test vim.api.nvim_command("packadd nvim-tree.lua") require("nvim-tree").setup({}) + +-- remove $NVT_FUNC_TMP +-- cd to $NVT_FUNC_TMP +-- if $NVT_FUNC_SRC/data exists:recursively copy it to $NVT_FUNC_TMP and cd +local function setup_dirs() + local n = vim + local tmp = os.getenv("NVT_FUNC_TMP") + if not tmp then + return + end + + -- blow away temp + print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) + print(n.fn.system({ "mkdir", "-p", "-v", tmp })) + + -- always cd to tmp + n.api.nvim_set_current_dir(tmp) + + -- maybe copy data and cd + local src = os.getenv("NVT_FUNC_SRC") + if src then + -- TODO handle data not present + print(n.fn.system({ "cp", "-p", "-r", "-v", src .. "/data", tmp .. "/data" })) + n.api.nvim_set_current_dir(tmp .. "/data") + end +end + +setup_dirs() diff --git a/test/func/map/node/open.lua b/test/func/map/node/open.lua index 062e843dfd8..e82ef164362 100644 --- a/test/func/map/node/open.lua +++ b/test/func/map/node/open.lua @@ -11,6 +11,31 @@ local before_each = t.before_each or before_each local it = t.it or it local setup = t.setup or setup ---@diagnostic enable: undefined-global +--- +-- remove $NVT_FUNC_TMP +-- cd to $NVT_FUNC_TMP +-- if $NVT_FUNC_SRC/data exists:recursively copy it to $NVT_FUNC_TMP and cd +local function setup_dirs() + local tmp = os.getenv("NVT_FUNC_TMP") + if not tmp then + return + end + + -- blow away temp + print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) + print(n.fn.system({ "mkdir", "-p", "-v", tmp })) + + -- always cd to tmp + n.api.nvim_set_current_dir(tmp) + + -- maybe copy data and cd + local src = os.getenv("NVT_FUNC_SRC") + if src then + -- TODO handle data not present + print(n.fn.system({ "cp", "-p", "-r", "-v", src .. "/data", tmp .. "/data" })) + n.api.nvim_set_current_dir(tmp .. "/data") + end +end describe("map_node_open", function() --- @type test.functional.ui.screen @@ -24,11 +49,11 @@ describe("map_node_open", function() exec_lua(function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) + + setup_dirs() end) before_each(function() - n.api.nvim_set_current_dir(os.getenv("NVT_TMP_FUNC_DATA") or "") - exec_lua(function() require("nvim-tree").setup({}) end) From 8e2de7324f6b02b45af4b8aa862a8047d7912c44 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 22 Sep 2026 12:40:31 +1000 Subject: [PATCH 041/154] test: link test and lua separately under nvim src --- scripts/functionaltest.sh | 71 +++++++++++-------- test/{func => functional/nvt}/README.md | 0 .../nvt}/api/tree/data/dir1/dir1file1 | 0 .../nvt}/api/tree/data/dir2/dir2file1 | 0 .../nvt}/api/tree/data/file1 | 0 .../nvt}/api/tree/data/file2 | 0 .../nvt/api/tree/open_spec.lua} | 10 ++- .../nvt}/fs/create/data/d1/d1f1 | 0 .../nvt}/fs/create/data/f1 | 0 .../nvt/fs/create/dir_spec.lua} | 26 ++++--- test/{func => functional/nvt}/init_live.lua | 13 ++-- .../nvt}/map/node/data/d1/f1 | 0 .../nvt}/map/node/data/d1/f2 | 0 .../nvt}/map/node/data/d2/f1 | 0 .../{func => functional/nvt}/map/node/data/f1 | 0 .../{func => functional/nvt}/map/node/data/f2 | 0 .../nvt/map/node/open_spec.lua} | 12 ++-- 17 files changed, 75 insertions(+), 57 deletions(-) rename test/{func => functional/nvt}/README.md (100%) rename test/{func => functional/nvt}/api/tree/data/dir1/dir1file1 (100%) rename test/{func => functional/nvt}/api/tree/data/dir2/dir2file1 (100%) rename test/{func => functional/nvt}/api/tree/data/file1 (100%) rename test/{func => functional/nvt}/api/tree/data/file2 (100%) rename test/{func/api/tree/open.lua => functional/nvt/api/tree/open_spec.lua} (96%) rename test/{func => functional/nvt}/fs/create/data/d1/d1f1 (100%) rename test/{func => functional/nvt}/fs/create/data/f1 (100%) rename test/{func/fs/create/dir.lua => functional/nvt/fs/create/dir_spec.lua} (94%) rename test/{func => functional/nvt}/init_live.lua (90%) rename test/{func => functional/nvt}/map/node/data/d1/f1 (100%) rename test/{func => functional/nvt}/map/node/data/d1/f2 (100%) rename test/{func => functional/nvt}/map/node/data/d2/f1 (100%) rename test/{func => functional/nvt}/map/node/data/f1 (100%) rename test/{func => functional/nvt}/map/node/data/f2 (100%) rename test/{func/map/node/open.lua => functional/nvt/map/node/open_spec.lua} (95%) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 0ba59dcb183..84c5ec59fa4 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -5,7 +5,7 @@ set -e -if [ ! -d "test/func" ]; then +if [ ! -d "test/functional/nvt" ]; then echo "Must be run from nvim-tree root" 1>&2 exit 1 fi @@ -19,35 +19,36 @@ DIR_NVT="${PWD}" # nvim-tree linked as a package under source DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" -# absolute paths of test files under nvim source +# test spec files to execute, relative to neovim source FILES_TEST= # live source directory DIR_LIVE= # working directory for tests, which are responsible for creating and removing -export NVT_FUNC_TMP="/tmp/nvt_func" +NVT_FUNC_TMP="/tmp/nvt_func" -# test source, which tests may copy data from -export NVT_FUNC_SRC= +# optional test data +NVT_FUNC_DATA= usage() { - echo "Usage: ${0} [-h] [-t ] [-l ]" + echo "Usage: ${0} [-h] [-t ] [-l []]" echo echo " OPTION:" echo " -t Execute single test file or all in directory" - echo " -l Live environment in test's data directory" + echo " -l Live environment, optionally using a test's data" echo " -h Show this help" } # add a file or directory $1 to FILES_TEST files_test_add() { + echo "files_test_add ${1}" if [ -f "${1}" ]; then - FILES_TEST="${FILES_TEST} ${DIR_NVT_PACK}/${1}" + FILES_TEST="${FILES_TEST} ${1}" elif [ -d "${1}" ]; then - find "${1}" -type f -iname '*lua' -not -iname 'init_live.lua' > /tmp/nvt_files_test + find "${1}" -type f -iname '*_spec.lua' > /tmp/nvt_files_test while IFS= read -r f; do - FILES_TEST="${FILES_TEST} ${DIR_NVT_PACK}/${f}" + FILES_TEST="${FILES_TEST} ${f}" done < /tmp/nvt_files_test rm /tmp/nvt_files_test else @@ -58,21 +59,13 @@ files_test_add() { # set DIR_LIVE for directory or test file live_add() { - if [ -f "${1}" ]; then - DIR_LIVE="$(dirname "${1}")" - else - DIR_LIVE="${1}" - fi - - DIR_LIVE="$(realpath "${DIR_LIVE}")" - + DIR_LIVE="${1}" if [ ! -d "${DIR_LIVE}" ]; then echo "${DIR_LIVE} inexistent" exit 1 fi } -# TODO fail on scripts/functionaltest.sh foo while getopts "hl:t:" o; do case "$o" in h) @@ -85,32 +78,52 @@ while getopts "hl:t:" o; do t) files_test_add "${OPTARG:-}" ;; - \?) + *) usage >&2 exit 1 ;; esac done -# before all tests: links nvim-tree as a package under nvim source +# before all tests: links nvim-tree lua and test under setup() { - ln -sv "${DIR_NVT}" "${DIR_NVT_PACK}" + mkdir -p "${DIR_NVT_PACK}" + ln -sv "${DIR_NVT}/lua" "${DIR_NVT_PACK}" + + ln -sv "${DIR_NVT}/test/functional/nvt" "${DIR_NVIM_SRC}/test/functional" } -# after all tests: remove package link and temp +# after all tests: remove lua/test links and temp teardown() { - rm -fv "${DIR_NVT_PACK}" + rm -fv "${DIR_NVIM_SRC}/test/functional/nvt" + + rm -fv "${DIR_NVT_PACK}/lua" + rm -rf "${DIR_NVT_PACK}" +} + +# export variables for individual test +before_each() { + # test will execute in this directory rm -rf "${NVT_FUNC_TMP}" + export NVT_FUNC_TMP + + # test will recursively copy data if it exists + NVT_FUNC_DATA="$(realpath "$(dirname "${1}")/data")" + if [ -d "${NVT_FUNC_DATA}" ]; then + export NVT_FUNC_DATA + else + unset NVT_FUNC_DATA + fi } live() { - NVT_FUNC_SRC="${DIR_LIVE}" + before_each "${DIR_LIVE}" # options extracted from testnvim.lua nvim_argv, nvim_set nvim \ --clean \ --noplugin \ - -u "${DIR_NVT_PACK}/test/func/init_live.lua" \ + -u "${DIR_NVIM_SRC}/test/functional/nvt/init_live.lua" \ -i NONE \ --cmd "set shortmess+=IS background=light noswapfile noautoindent startofline laststatus=1 undodir=. directory=. viewdir=. backupdir=. belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}" \ --cmd "comclear | mapclear | mapclear!" \ @@ -128,15 +141,15 @@ if [ -n "${DIR_LIVE}" ]; then else # run all tests if none specified if [ -z "${FILES_TEST}" ]; then - files_test_add "test/func" + files_test_add "test/functional/nvt" fi - # must run from nvim source root + # cmake must be run from nvim source root cd "${DIR_NVIM_SRC}" # execute all tests for f in ${FILES_TEST}; do - NVT_FUNC_SRC="$(dirname "${f}")" + before_each "${f}" make functionaltest TEST_FILE="${f}" done fi diff --git a/test/func/README.md b/test/functional/nvt/README.md similarity index 100% rename from test/func/README.md rename to test/functional/nvt/README.md diff --git a/test/func/api/tree/data/dir1/dir1file1 b/test/functional/nvt/api/tree/data/dir1/dir1file1 similarity index 100% rename from test/func/api/tree/data/dir1/dir1file1 rename to test/functional/nvt/api/tree/data/dir1/dir1file1 diff --git a/test/func/api/tree/data/dir2/dir2file1 b/test/functional/nvt/api/tree/data/dir2/dir2file1 similarity index 100% rename from test/func/api/tree/data/dir2/dir2file1 rename to test/functional/nvt/api/tree/data/dir2/dir2file1 diff --git a/test/func/api/tree/data/file1 b/test/functional/nvt/api/tree/data/file1 similarity index 100% rename from test/func/api/tree/data/file1 rename to test/functional/nvt/api/tree/data/file1 diff --git a/test/func/api/tree/data/file2 b/test/functional/nvt/api/tree/data/file2 similarity index 100% rename from test/func/api/tree/data/file2 rename to test/functional/nvt/api/tree/data/file2 diff --git a/test/func/api/tree/open.lua b/test/functional/nvt/api/tree/open_spec.lua similarity index 96% rename from test/func/api/tree/open.lua rename to test/functional/nvt/api/tree/open_spec.lua index 73a8ee835de..f4f1532482d 100644 --- a/test/func/api/tree/open.lua +++ b/test/functional/nvt/api/tree/open_spec.lua @@ -62,7 +62,7 @@ end -- remove $NVT_FUNC_TMP -- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_SRC/data exists:recursively copy it to $NVT_FUNC_TMP and cd +-- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd local function setup_dirs() local tmp = os.getenv("NVT_FUNC_TMP") if not tmp then @@ -76,11 +76,9 @@ local function setup_dirs() -- always cd to tmp n.api.nvim_set_current_dir(tmp) - -- maybe copy data and cd - local src = os.getenv("NVT_FUNC_SRC") - if src then - -- TODO handle data not present - print(n.fn.system({ "cp", "-p", "-r", "-v", src .. "/data", tmp .. "/data" })) + local data = os.getenv("NVT_FUNC_DATA") + if data and vim.uv.fs_stat(data) then + print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) n.api.nvim_set_current_dir(tmp .. "/data") end end diff --git a/test/func/fs/create/data/d1/d1f1 b/test/functional/nvt/fs/create/data/d1/d1f1 similarity index 100% rename from test/func/fs/create/data/d1/d1f1 rename to test/functional/nvt/fs/create/data/d1/d1f1 diff --git a/test/func/fs/create/data/f1 b/test/functional/nvt/fs/create/data/f1 similarity index 100% rename from test/func/fs/create/data/f1 rename to test/functional/nvt/fs/create/data/f1 diff --git a/test/func/fs/create/dir.lua b/test/functional/nvt/fs/create/dir_spec.lua similarity index 94% rename from test/func/fs/create/dir.lua rename to test/functional/nvt/fs/create/dir_spec.lua index b47ceee2147..3141a26ecc0 100644 --- a/test/func/fs/create/dir.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -18,7 +18,7 @@ local setup = t.setup or setup -- remove $NVT_FUNC_TMP -- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_SRC/data exists:recursively copy it to $NVT_FUNC_TMP and cd +-- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd local function setup_dirs() local tmp = os.getenv("NVT_FUNC_TMP") if not tmp then @@ -32,11 +32,9 @@ local function setup_dirs() -- always cd to tmp n.api.nvim_set_current_dir(tmp) - -- maybe copy data and cd - local src = os.getenv("NVT_FUNC_SRC") - if src then - -- TODO handle data not present - print(n.fn.system({ "cp", "-p", "-r", "-v", src .. "/data", tmp .. "/data" })) + local data = os.getenv("NVT_FUNC_DATA") + if data and vim.uv.fs_stat(data) then + print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) n.api.nvim_set_current_dir(tmp .. "/data") end end @@ -64,7 +62,11 @@ describe("single", function() end) it("direct", function() + exec_lua(function() + require("nvim-tree.api").tree.open() + end) n.feed( + -- TODO why does this command not work? timing? ":NvimTreeOpen", "a", "direct/" @@ -89,8 +91,10 @@ NvimTree_1 [-] [No Name] end) it("indirect", function() + exec_lua(function() + require("nvim-tree.api").tree.open() + end) n.feed( - ":NvimTreeOpen", "gg", "a", "d1/indirect/" @@ -132,8 +136,10 @@ NvimTree_1 [-] [No Name] end) it("dir_exists", function() + exec_lua(function() + require("nvim-tree.api").tree.open() + end) n.feed( - ":NvimTreeOpen", "gg", "a", "d1/" @@ -171,8 +177,10 @@ NvimTree_1 [-] [No Name] end) it("file_exists", function() + exec_lua(function() + require("nvim-tree.api").tree.open() + end) n.feed( - ":NvimTreeOpen", "gg", "a", "d1/d1f1/" diff --git a/test/func/init_live.lua b/test/functional/nvt/init_live.lua similarity index 90% rename from test/func/init_live.lua rename to test/functional/nvt/init_live.lua index f8bffcbdb16..710993a7cc4 100644 --- a/test/func/init_live.lua +++ b/test/functional/nvt/init_live.lua @@ -81,9 +81,10 @@ require("nvim-tree").setup({}) -- remove $NVT_FUNC_TMP -- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_SRC/data exists:recursively copy it to $NVT_FUNC_TMP and cd +-- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd local function setup_dirs() local n = vim + local tmp = os.getenv("NVT_FUNC_TMP") if not tmp then return @@ -96,13 +97,13 @@ local function setup_dirs() -- always cd to tmp n.api.nvim_set_current_dir(tmp) - -- maybe copy data and cd - local src = os.getenv("NVT_FUNC_SRC") - if src then - -- TODO handle data not present - print(n.fn.system({ "cp", "-p", "-r", "-v", src .. "/data", tmp .. "/data" })) + local data = os.getenv("NVT_FUNC_DATA") + if data and vim.uv.fs_stat(data) then + print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) n.api.nvim_set_current_dir(tmp .. "/data") end end setup_dirs() + +require("nvim-tree.api").tree.open() diff --git a/test/func/map/node/data/d1/f1 b/test/functional/nvt/map/node/data/d1/f1 similarity index 100% rename from test/func/map/node/data/d1/f1 rename to test/functional/nvt/map/node/data/d1/f1 diff --git a/test/func/map/node/data/d1/f2 b/test/functional/nvt/map/node/data/d1/f2 similarity index 100% rename from test/func/map/node/data/d1/f2 rename to test/functional/nvt/map/node/data/d1/f2 diff --git a/test/func/map/node/data/d2/f1 b/test/functional/nvt/map/node/data/d2/f1 similarity index 100% rename from test/func/map/node/data/d2/f1 rename to test/functional/nvt/map/node/data/d2/f1 diff --git a/test/func/map/node/data/f1 b/test/functional/nvt/map/node/data/f1 similarity index 100% rename from test/func/map/node/data/f1 rename to test/functional/nvt/map/node/data/f1 diff --git a/test/func/map/node/data/f2 b/test/functional/nvt/map/node/data/f2 similarity index 100% rename from test/func/map/node/data/f2 rename to test/functional/nvt/map/node/data/f2 diff --git a/test/func/map/node/open.lua b/test/functional/nvt/map/node/open_spec.lua similarity index 95% rename from test/func/map/node/open.lua rename to test/functional/nvt/map/node/open_spec.lua index e82ef164362..58966ce3d75 100644 --- a/test/func/map/node/open.lua +++ b/test/functional/nvt/map/node/open_spec.lua @@ -11,10 +11,10 @@ local before_each = t.before_each or before_each local it = t.it or it local setup = t.setup or setup ---@diagnostic enable: undefined-global ---- + -- remove $NVT_FUNC_TMP -- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_SRC/data exists:recursively copy it to $NVT_FUNC_TMP and cd +-- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd local function setup_dirs() local tmp = os.getenv("NVT_FUNC_TMP") if not tmp then @@ -28,11 +28,9 @@ local function setup_dirs() -- always cd to tmp n.api.nvim_set_current_dir(tmp) - -- maybe copy data and cd - local src = os.getenv("NVT_FUNC_SRC") - if src then - -- TODO handle data not present - print(n.fn.system({ "cp", "-p", "-r", "-v", src .. "/data", tmp .. "/data" })) + local data = os.getenv("NVT_FUNC_DATA") + if data and vim.uv.fs_stat(data) then + print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) n.api.nvim_set_current_dir(tmp .. "/data") end end From d3854eb7789abaf8fde466dbdbaa6da2a773d1b6 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 22 Sep 2026 12:51:13 +1000 Subject: [PATCH 042/154] test: link test and lua separately under nvim src --- scripts/functionaltest.sh | 14 +++++++++++--- test/functional/nvt/fs/create/dir_spec.lua | 19 +++---------------- test/functional/nvt/init_live.lua | 2 -- 3 files changed, 14 insertions(+), 21 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 84c5ec59fa4..cf9a4a8622f 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -85,20 +85,28 @@ while getopts "hl:t:" o; do esac done -# before all tests: links nvim-tree lua and test under +# before all tests: links plugin and tests in their appropriate places under neovim source setup() { + # plugin runtime package mkdir -p "${DIR_NVT_PACK}" + ln -sv "${DIR_NVT}/doc" "${DIR_NVT_PACK}" ln -sv "${DIR_NVT}/lua" "${DIR_NVT_PACK}" + ln -sv "${DIR_NVT}/plugin" "${DIR_NVT_PACK}" + # tests ln -sv "${DIR_NVT}/test/functional/nvt" "${DIR_NVIM_SRC}/test/functional" } # after all tests: remove lua/test links and temp teardown() { - rm -fv "${DIR_NVIM_SRC}/test/functional/nvt" - + # plugin runtime package + rm -fv "${DIR_NVT_PACK}/doc" rm -fv "${DIR_NVT_PACK}/lua" + rm -fv "${DIR_NVT_PACK}/plugin" rm -rf "${DIR_NVT_PACK}" + + # tests + rm -fv "${DIR_NVIM_SRC}/test/functional/nvt" } # export variables for individual test diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index 3141a26ecc0..f93a3da4082 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -13,9 +13,6 @@ local it = t.it or it local setup = t.setup or setup ---@diagnostic enable: undefined-global --- TODO extract nvt test utils --- TODO use vim.system instead of vim.fn.system - -- remove $NVT_FUNC_TMP -- cd to $NVT_FUNC_TMP -- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd @@ -62,11 +59,7 @@ describe("single", function() end) it("direct", function() - exec_lua(function() - require("nvim-tree.api").tree.open() - end) n.feed( - -- TODO why does this command not work? timing? ":NvimTreeOpen", "a", "direct/" @@ -91,10 +84,8 @@ NvimTree_1 [-] [No Name] end) it("indirect", function() - exec_lua(function() - require("nvim-tree.api").tree.open() - end) n.feed( + ":NvimTreeOpen", "gg", "a", "d1/indirect/" @@ -136,10 +127,8 @@ NvimTree_1 [-] [No Name] end) it("dir_exists", function() - exec_lua(function() - require("nvim-tree.api").tree.open() - end) n.feed( + ":NvimTreeOpen", "gg", "a", "d1/" @@ -177,10 +166,8 @@ NvimTree_1 [-] [No Name] end) it("file_exists", function() - exec_lua(function() - require("nvim-tree.api").tree.open() - end) n.feed( + ":NvimTreeOpen", "gg", "a", "d1/d1f1/" diff --git a/test/functional/nvt/init_live.lua b/test/functional/nvt/init_live.lua index 710993a7cc4..6328ffc48cc 100644 --- a/test/functional/nvt/init_live.lua +++ b/test/functional/nvt/init_live.lua @@ -105,5 +105,3 @@ local function setup_dirs() end setup_dirs() - -require("nvim-tree.api").tree.open() From d4d02283d3e2cd92b63d8c46913e2a6029eb79ce Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 22 Sep 2026 12:58:36 +1000 Subject: [PATCH 043/154] test: extract testutil.lua --- test/functional/nvt/api/tree/open_spec.lua | 76 +--------------------- test/functional/nvt/fs/create/dir_spec.lua | 26 +------- test/functional/nvt/map/node/open_spec.lua | 26 +------- test/functional/nvt/testutil.lua | 76 ++++++++++++++++++++++ 4 files changed, 83 insertions(+), 121 deletions(-) create mode 100644 test/functional/nvt/testutil.lua diff --git a/test/functional/nvt/api/tree/open_spec.lua b/test/functional/nvt/api/tree/open_spec.lua index f4f1532482d..7aa8036164c 100644 --- a/test/functional/nvt/api/tree/open_spec.lua +++ b/test/functional/nvt/api/tree/open_spec.lua @@ -1,4 +1,5 @@ local t = require("test.testutil") +local nt = require("test.functional.nvt.testutil") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear @@ -12,77 +13,6 @@ local it = t.it or it local setup = t.setup or setup ---@diagnostic enable: undefined-global ---- Reset all NvimTree* highlight groups to just a unique foreground colour ---- Add a CL variant with the same background colour as NvimTreeCursorLine ---- May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order ---- @param screen test.functional.ui.screen -local function nvt_hl_attr_ids(screen) - local attr_ids = {} - - -- math.random(tonumber('0x707070'),tonumber('0x909090')) - local bg_rgb, bg_hex = 8758352, "#85a450" - - -- build the cursor line first, background only - attr_ids["NvimTreeCursorLine"] = { background = bg_rgb } - n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = bg_hex }) - - -- unique colour for each group, descending from #fefefe - local i, r, g, b = 1, 254, 254, 254 - local rgb, hex - - for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do - if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") and not group:match(".*CL$") then - -- next unique fg colour - rgb = r * 256 * 256 + g * 256 + b - hex = string.format("#%x", rgb) - i = i + 1 - if (i % 256 == 0) then - b = 254 - g = 254 - r = r - 1 - elseif (i % 16 == 0) then - b = 254 - g = g - 1 - else - b = b - 1 - end - - -- add the group's concrete definition with fg only - attr_ids[group] = { foreground = rgb } - n.api.nvim_set_hl(0, group, { fg = hex }) - - -- create an NvimTreeCursorLine variant - attr_ids[group .. "CL"] = { foreground = rgb, background = bg_rgb } - n.api.nvim_set_hl(0, group .. "CL", { fg = hex, bg = bg_hex }) - end - end - - screen:add_extra_attr_ids(attr_ids) -end - --- remove $NVT_FUNC_TMP --- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd -local function setup_dirs() - local tmp = os.getenv("NVT_FUNC_TMP") - if not tmp then - return - end - - -- blow away temp - print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) - print(n.fn.system({ "mkdir", "-p", "-v", tmp })) - - -- always cd to tmp - n.api.nvim_set_current_dir(tmp) - - local data = os.getenv("NVT_FUNC_DATA") - if data and vim.uv.fs_stat(data) then - print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) - n.api.nvim_set_current_dir(tmp .. "/data") - end -end - describe("api_tree_open", function() --- @type test.functional.ui.screen local screen @@ -96,7 +26,7 @@ describe("api_tree_open", function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - setup_dirs() + nt.setup_dirs() end) before_each(function() @@ -104,7 +34,7 @@ describe("api_tree_open", function() require("nvim-tree").setup({}) end) - nvt_hl_attr_ids(screen) + screen:add_extra_attr_ids(nt.simple_attr_ids()) end) it("populated_unfocussed_text_only", function() diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index f93a3da4082..a1217194b21 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -1,4 +1,5 @@ local t = require("test.testutil") +local nt = require("test.functional.nvt.testutil") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local eq = t.eq @@ -13,29 +14,6 @@ local it = t.it or it local setup = t.setup or setup ---@diagnostic enable: undefined-global --- remove $NVT_FUNC_TMP --- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd -local function setup_dirs() - local tmp = os.getenv("NVT_FUNC_TMP") - if not tmp then - return - end - - -- blow away temp - print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) - print(n.fn.system({ "mkdir", "-p", "-v", tmp })) - - -- always cd to tmp - n.api.nvim_set_current_dir(tmp) - - local data = os.getenv("NVT_FUNC_DATA") - if data and vim.uv.fs_stat(data) then - print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) - n.api.nvim_set_current_dir(tmp .. "/data") - end -end - --- @type test.functional.ui.screen local screen @@ -55,7 +33,7 @@ describe("single", function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - setup_dirs() + nt.setup_dirs() end) it("direct", function() diff --git a/test/functional/nvt/map/node/open_spec.lua b/test/functional/nvt/map/node/open_spec.lua index 58966ce3d75..35d258b5d04 100644 --- a/test/functional/nvt/map/node/open_spec.lua +++ b/test/functional/nvt/map/node/open_spec.lua @@ -1,4 +1,5 @@ local t = require("test.testutil") +local nt = require("test.functional.nvt.testutil") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear @@ -12,29 +13,6 @@ local it = t.it or it local setup = t.setup or setup ---@diagnostic enable: undefined-global --- remove $NVT_FUNC_TMP --- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd -local function setup_dirs() - local tmp = os.getenv("NVT_FUNC_TMP") - if not tmp then - return - end - - -- blow away temp - print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) - print(n.fn.system({ "mkdir", "-p", "-v", tmp })) - - -- always cd to tmp - n.api.nvim_set_current_dir(tmp) - - local data = os.getenv("NVT_FUNC_DATA") - if data and vim.uv.fs_stat(data) then - print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) - n.api.nvim_set_current_dir(tmp .. "/data") - end -end - describe("map_node_open", function() --- @type test.functional.ui.screen local screen @@ -48,7 +26,7 @@ describe("map_node_open", function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - setup_dirs() + nt.setup_dirs() end) before_each(function() diff --git a/test/functional/nvt/testutil.lua b/test/functional/nvt/testutil.lua new file mode 100644 index 00000000000..9413008ce69 --- /dev/null +++ b/test/functional/nvt/testutil.lua @@ -0,0 +1,76 @@ +local n = require("test.functional.testnvim")() + +local M = {} + +-- remove $NVT_FUNC_TMP +-- cd to $NVT_FUNC_TMP +-- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd +function M.setup_dirs() + local tmp = os.getenv("NVT_FUNC_TMP") + if not tmp then + return + end + + -- blow away temp + print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) + print(n.fn.system({ "mkdir", "-p", "-v", tmp })) + + -- always cd to tmp + n.api.nvim_set_current_dir(tmp) + + local data = os.getenv("NVT_FUNC_DATA") + if data and vim.uv.fs_stat(data) then + print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) + n.api.nvim_set_current_dir(tmp .. "/data") + end +end + +--- Reset all NvimTree* highlight groups to just a unique foreground colour +--- Return attr_ids to match +--- Add a CL variant with the same background colour as NvimTreeCursorLine +--- May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order +function M.simple_attr_ids() + local attr_ids = {} + + -- math.random(tonumber('0x707070'),tonumber('0x909090')) + local bg_rgb, bg_hex = 8758352, "#85a450" + + -- build the cursor line first, background only + attr_ids["NvimTreeCursorLine"] = { background = bg_rgb } + n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = bg_hex }) + + -- unique colour for each group, descending from #fefefe + local i, r, g, b = 1, 254, 254, 254 + local rgb, hex + + for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do + if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") and not group:match(".*CL$") then + -- next unique fg colour + rgb = r * 256 * 256 + g * 256 + b + hex = string.format("#%x", rgb) + i = i + 1 + if (i % 256 == 0) then + b = 254 + g = 254 + r = r - 1 + elseif (i % 16 == 0) then + b = 254 + g = g - 1 + else + b = b - 1 + end + + -- add the group's concrete definition with fg only + attr_ids[group] = { foreground = rgb } + n.api.nvim_set_hl(0, group, { fg = hex }) + + -- create an NvimTreeCursorLine variant + attr_ids[group .. "CL"] = { foreground = rgb, background = bg_rgb } + n.api.nvim_set_hl(0, group .. "CL", { fg = hex, bg = bg_hex }) + end + end + + return attr_ids +end + +return M From 56fb23559d4adf773e1209c217da5b2b78f26ab4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 22 Sep 2026 13:06:45 +1000 Subject: [PATCH 044/154] test: extract fixtures.lua --- test/functional/nvt/api/tree/open_spec.lua | 5 +-- test/functional/nvt/fixtures.lua | 32 +++++++++++++++++++ test/functional/nvt/fs/create/dir_spec.lua | 4 +-- test/functional/nvt/map/node/open_spec.lua | 4 +-- .../nvt/{testutil.lua => utils.lua} | 23 ------------- 5 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 test/functional/nvt/fixtures.lua rename test/functional/nvt/{testutil.lua => utils.lua} (73%) diff --git a/test/functional/nvt/api/tree/open_spec.lua b/test/functional/nvt/api/tree/open_spec.lua index 7aa8036164c..0399be019a9 100644 --- a/test/functional/nvt/api/tree/open_spec.lua +++ b/test/functional/nvt/api/tree/open_spec.lua @@ -1,5 +1,6 @@ local t = require("test.testutil") -local nt = require("test.functional.nvt.testutil") +local nf = require("test.functional.nvt.fixtures") +local nt = require("test.functional.nvt.utils") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear @@ -26,7 +27,7 @@ describe("api_tree_open", function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - nt.setup_dirs() + nf.setup_dirs() end) before_each(function() diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua new file mode 100644 index 00000000000..c165ff35f26 --- /dev/null +++ b/test/functional/nvt/fixtures.lua @@ -0,0 +1,32 @@ +local n = vim +if not n.fn then + n = require("test.functional.testnvim")() +end + +local M = {} + +-- remove $NVT_FUNC_TMP +-- cd to $NVT_FUNC_TMP +-- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd +function M.setup_dirs() + local tmp = os.getenv("NVT_FUNC_TMP") + if not tmp then + return + end + + -- blow away temp + n.fn.system({ "rm", "-r", "-f", "-v", tmp }) + n.fn.system({ "mkdir", "-p", "-v", tmp }) + + -- always cd to tmp + n.api.nvim_set_current_dir(tmp) + + -- maybe copy entire data directory + local data = os.getenv("NVT_FUNC_DATA") + if data and vim.uv.fs_stat(data) then + n.fn.system({ "cp", "-p", "-r", "-v", data, tmp }) + n.api.nvim_set_current_dir(tmp .. "/data") + end +end + +return M diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index a1217194b21..8c51aaea2f0 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -1,5 +1,5 @@ local t = require("test.testutil") -local nt = require("test.functional.nvt.testutil") +local nf = require("test.functional.nvt.fixtures") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local eq = t.eq @@ -33,7 +33,7 @@ describe("single", function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - nt.setup_dirs() + nf.setup_dirs() end) it("direct", function() diff --git a/test/functional/nvt/map/node/open_spec.lua b/test/functional/nvt/map/node/open_spec.lua index 35d258b5d04..e0f6daab996 100644 --- a/test/functional/nvt/map/node/open_spec.lua +++ b/test/functional/nvt/map/node/open_spec.lua @@ -1,5 +1,5 @@ local t = require("test.testutil") -local nt = require("test.functional.nvt.testutil") +local nf = require("test.functional.nvt.fixtures") local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local clear = n.clear @@ -26,7 +26,7 @@ describe("map_node_open", function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - nt.setup_dirs() + nf.setup_dirs() end) before_each(function() diff --git a/test/functional/nvt/testutil.lua b/test/functional/nvt/utils.lua similarity index 73% rename from test/functional/nvt/testutil.lua rename to test/functional/nvt/utils.lua index 9413008ce69..a44e9c6b8e6 100644 --- a/test/functional/nvt/testutil.lua +++ b/test/functional/nvt/utils.lua @@ -2,29 +2,6 @@ local n = require("test.functional.testnvim")() local M = {} --- remove $NVT_FUNC_TMP --- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd -function M.setup_dirs() - local tmp = os.getenv("NVT_FUNC_TMP") - if not tmp then - return - end - - -- blow away temp - print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) - print(n.fn.system({ "mkdir", "-p", "-v", tmp })) - - -- always cd to tmp - n.api.nvim_set_current_dir(tmp) - - local data = os.getenv("NVT_FUNC_DATA") - if data and vim.uv.fs_stat(data) then - print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) - n.api.nvim_set_current_dir(tmp .. "/data") - end -end - --- Reset all NvimTree* highlight groups to just a unique foreground colour --- Return attr_ids to match --- Add a CL variant with the same background colour as NvimTreeCursorLine From 1c8a4ccec09fbbd23c660fa2353e262b9e7c5342 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 22 Sep 2026 13:11:17 +1000 Subject: [PATCH 045/154] test: extract fixtures.lua --- test/functional/nvt/fixtures.lua | 5 +---- test/functional/nvt/init_live.lua | 29 +++-------------------------- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index c165ff35f26..882debff68d 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -1,7 +1,4 @@ -local n = vim -if not n.fn then - n = require("test.functional.testnvim")() -end +local n = vim.fn and vim or require("test.functional.testnvim")() local M = {} diff --git a/test/functional/nvt/init_live.lua b/test/functional/nvt/init_live.lua index 6328ffc48cc..9c642e62190 100644 --- a/test/functional/nvt/init_live.lua +++ b/test/functional/nvt/init_live.lua @@ -1,3 +1,5 @@ +local nf = require("test.functional.nvt.fixtures") + -- match the test screen size: r to reapply if the terminal is not cooperating local function screen_resize() vim.o.columns = 80 @@ -79,29 +81,4 @@ vim.o.background = "dark" vim.api.nvim_command("packadd nvim-tree.lua") require("nvim-tree").setup({}) --- remove $NVT_FUNC_TMP --- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd -local function setup_dirs() - local n = vim - - local tmp = os.getenv("NVT_FUNC_TMP") - if not tmp then - return - end - - -- blow away temp - print(n.fn.system({ "rm", "-r", "-f", "-v", tmp })) - print(n.fn.system({ "mkdir", "-p", "-v", tmp })) - - -- always cd to tmp - n.api.nvim_set_current_dir(tmp) - - local data = os.getenv("NVT_FUNC_DATA") - if data and vim.uv.fs_stat(data) then - print(n.fn.system({ "cp", "-p", "-r", "-v", data, tmp })) - n.api.nvim_set_current_dir(tmp .. "/data") - end -end - -setup_dirs() +nf.setup_dirs() From 270f8c2d55e31fdf73699b02da8568d1ef1effb3 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 23 Sep 2026 12:39:05 +1000 Subject: [PATCH 046/154] test: shell script is responsible for creating test directory --- test/functional/nvt/api/tree/open_spec.lua | 2 +- test/functional/nvt/create_test_cwd.sh | 34 ++++++++++++++++++++++ test/functional/nvt/fixtures.lua | 30 +++++-------------- test/functional/nvt/fs/create/dir_spec.lua | 2 +- test/functional/nvt/init_live.lua | 5 ++-- test/functional/nvt/map/node/open_spec.lua | 2 +- 6 files changed, 47 insertions(+), 28 deletions(-) create mode 100755 test/functional/nvt/create_test_cwd.sh diff --git a/test/functional/nvt/api/tree/open_spec.lua b/test/functional/nvt/api/tree/open_spec.lua index 0399be019a9..ad2b0e5f13d 100644 --- a/test/functional/nvt/api/tree/open_spec.lua +++ b/test/functional/nvt/api/tree/open_spec.lua @@ -27,7 +27,7 @@ describe("api_tree_open", function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - nf.setup_dirs() + n.api.nvim_set_current_dir(nf.create_test_dir(n.fn.system)) end) before_each(function() diff --git a/test/functional/nvt/create_test_cwd.sh b/test/functional/nvt/create_test_cwd.sh new file mode 100755 index 00000000000..3cae6ad1851 --- /dev/null +++ b/test/functional/nvt/create_test_cwd.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env sh + +# delete, create and return the absolute path of the directory to execute tests in +# $NVT_FUNC_TMP is the base +# if data is present, recursively copy it into $NVT_FUNC_TMP/data and return it +# otherwise return empty $NVT_FUNC_TMP +# +# prints "PATH=/absolute/path" on success +# +# nvim 0.12 does not have access to vim.system, hence we must use vim.fn.system to execute this +# vim.fn.system cannot detect error codes in the test context, as vim.v is not available +# hence we must use the output to determine success + +set -e + +if [ -z "${NVT_FUNC_TMP}" ]; then + echo "\$NVT_FUNC_TMP not set" + exit 1 +fi + +# blow away temp +rm -r -f "${NVT_FUNC_TMP}" +mkdir -p "${NVT_FUNC_TMP}" + +# maybe copy entire data directory +if [ -n "${NVT_FUNC_DATA}" ]; then + if [ ! -d "${NVT_FUNC_DATA}" ]; then + echo "\$NVT_FUNC_DATA inexistent: ${NVT_FUNC_DATA}" + else + cp -p -r "${NVT_FUNC_DATA}" "${NVT_FUNC_TMP}" + fi +fi + +printf "PATH=${NVT_FUNC_TMP}/data" diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index 882debff68d..99bde99188a 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -1,29 +1,13 @@ -local n = vim.fn and vim or require("test.functional.testnvim")() - local M = {} --- remove $NVT_FUNC_TMP --- cd to $NVT_FUNC_TMP --- if $NVT_FUNC_DATA exists:recursively copy it to $NVT_FUNC_TMP and cd -function M.setup_dirs() - local tmp = os.getenv("NVT_FUNC_TMP") - if not tmp then - return - end - - -- blow away temp - n.fn.system({ "rm", "-r", "-f", "-v", tmp }) - n.fn.system({ "mkdir", "-p", "-v", tmp }) - - -- always cd to tmp - n.api.nvim_set_current_dir(tmp) +---create and return the absolute path of the directory to execute tests in +---recursively copies data if present +---@param system fun(cmd: string|string[], input?: string|string[]|integer): string vim.fn.system to use as it depends on the context +---@return string path +function M.create_test_dir(system) + local out = system({ "/home/alex/src/nvim-tree/test-neovim-functionaltest/test/functional/nvt/create_test_cwd.sh" }) - -- maybe copy entire data directory - local data = os.getenv("NVT_FUNC_DATA") - if data and vim.uv.fs_stat(data) then - n.fn.system({ "cp", "-p", "-r", "-v", data, tmp }) - n.api.nvim_set_current_dir(tmp .. "/data") - end + return out:match("^PATH=(.*)$") or error(out) end return M diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index 8c51aaea2f0..f7e9183af9f 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -33,7 +33,7 @@ describe("single", function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - nf.setup_dirs() + n.api.nvim_set_current_dir(nf.create_test_dir(n.fn.system)) end) it("direct", function() diff --git a/test/functional/nvt/init_live.lua b/test/functional/nvt/init_live.lua index 9c642e62190..f2d3ce7a252 100644 --- a/test/functional/nvt/init_live.lua +++ b/test/functional/nvt/init_live.lua @@ -77,8 +77,9 @@ screen_resize() -- use dark background for readability under dark and light vim.o.background = "dark" ----add the plugin under test +-- add the plugin under test vim.api.nvim_command("packadd nvim-tree.lua") require("nvim-tree").setup({}) -nf.setup_dirs() +-- create and change to the directory the test will execute from +vim.api.nvim_set_current_dir(nf.create_test_dir(vim.fn.system)) diff --git a/test/functional/nvt/map/node/open_spec.lua b/test/functional/nvt/map/node/open_spec.lua index e0f6daab996..3b47bd9a8e9 100644 --- a/test/functional/nvt/map/node/open_spec.lua +++ b/test/functional/nvt/map/node/open_spec.lua @@ -26,7 +26,7 @@ describe("map_node_open", function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) end) - nf.setup_dirs() + n.api.nvim_set_current_dir(nf.create_test_dir(n.fn.system)) end) before_each(function() From 3f955e575d90f54c50217c84fe4acd9755245766 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 23 Sep 2026 13:02:36 +1000 Subject: [PATCH 047/154] test: shell script is responsible for creating test directory --- scripts/functionaltest.sh | 28 ++++++------------------ test/functional/nvt/create_test_cwd.sh | 30 +++++++++++--------------- test/functional/nvt/fixtures.lua | 2 +- test/functional/nvt/init_live.lua | 4 ++-- 4 files changed, 22 insertions(+), 42 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index cf9a4a8622f..54db0d9bb3f 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -25,11 +25,8 @@ FILES_TEST= # live source directory DIR_LIVE= -# working directory for tests, which are responsible for creating and removing -NVT_FUNC_TMP="/tmp/nvt_func" - -# optional test data -NVT_FUNC_DATA= +# absolute path of the test, under DIR_NVT +export NVT_FUNC_TEST_SOURCE= usage() { echo "Usage: ${0} [-h] [-t ] [-l []]" @@ -109,23 +106,12 @@ teardown() { rm -fv "${DIR_NVIM_SRC}/test/functional/nvt" } -# export variables for individual test -before_each() { - # test will execute in this directory - rm -rf "${NVT_FUNC_TMP}" - export NVT_FUNC_TMP - - # test will recursively copy data if it exists - NVT_FUNC_DATA="$(realpath "$(dirname "${1}")/data")" - if [ -d "${NVT_FUNC_DATA}" ]; then - export NVT_FUNC_DATA +live() { + if [ "$(basename "${DIR_LIVE}")" = "data" ]; then + NVT_FUNC_TEST_SOURCE="$(realpath "$(dirname "${DIR_LIVE}")")" else - unset NVT_FUNC_DATA + NVT_FUNC_TEST_SOURCE="$(realpath "${DIR_LIVE}")" fi -} - -live() { - before_each "${DIR_LIVE}" # options extracted from testnvim.lua nvim_argv, nvim_set nvim \ @@ -157,7 +143,7 @@ else # execute all tests for f in ${FILES_TEST}; do - before_each "${f}" + NVT_FUNC_TEST_SOURCE="$(realpath "$(dirname "${f}")")" make functionaltest TEST_FILE="${f}" done fi diff --git a/test/functional/nvt/create_test_cwd.sh b/test/functional/nvt/create_test_cwd.sh index 3cae6ad1851..b12e0217c80 100755 --- a/test/functional/nvt/create_test_cwd.sh +++ b/test/functional/nvt/create_test_cwd.sh @@ -1,11 +1,11 @@ #!/usr/bin/env sh # delete, create and return the absolute path of the directory to execute tests in -# $NVT_FUNC_TMP is the base -# if data is present, recursively copy it into $NVT_FUNC_TMP/data and return it -# otherwise return empty $NVT_FUNC_TMP +# /tmp/nvt_func is the base +# if data is present, recursively copy it into /tmp/nvt_func/data and return it +# otherwise return empty /tmp/nvt_func # -# prints "PATH=/absolute/path" on success +# prints "DIR=/absolute/path" on success # # nvim 0.12 does not have access to vim.system, hence we must use vim.fn.system to execute this # vim.fn.system cannot detect error codes in the test context, as vim.v is not available @@ -13,22 +13,16 @@ set -e -if [ -z "${NVT_FUNC_TMP}" ]; then - echo "\$NVT_FUNC_TMP not set" - exit 1 -fi +DIR="/tmp/nvt_func" # blow away temp -rm -r -f "${NVT_FUNC_TMP}" -mkdir -p "${NVT_FUNC_TMP}" +rm -r -f "${DIR}" +mkdir -p "${DIR}" -# maybe copy entire data directory -if [ -n "${NVT_FUNC_DATA}" ]; then - if [ ! -d "${NVT_FUNC_DATA}" ]; then - echo "\$NVT_FUNC_DATA inexistent: ${NVT_FUNC_DATA}" - else - cp -p -r "${NVT_FUNC_DATA}" "${NVT_FUNC_TMP}" - fi +# maybe copy entire data directory and use it +if [ -d "${NVT_FUNC_TEST_SOURCE}/data" ]; then + cp -p -r "${NVT_FUNC_TEST_SOURCE}/data" "${DIR}" + DIR="${DIR}/data" fi -printf "PATH=${NVT_FUNC_TMP}/data" +printf "DIR=${DIR}" diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index 99bde99188a..d7fd40a2e35 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -7,7 +7,7 @@ local M = {} function M.create_test_dir(system) local out = system({ "/home/alex/src/nvim-tree/test-neovim-functionaltest/test/functional/nvt/create_test_cwd.sh" }) - return out:match("^PATH=(.*)$") or error(out) + return out:match("^DIR=(.*)$") or error(out) end return M diff --git a/test/functional/nvt/init_live.lua b/test/functional/nvt/init_live.lua index f2d3ce7a252..ca16dbb3636 100644 --- a/test/functional/nvt/init_live.lua +++ b/test/functional/nvt/init_live.lua @@ -6,12 +6,12 @@ local function screen_resize() vim.o.lines = 24 end ----dump the screen to $NVT_FUNC_TMP/dump.txt: d for raw, c for collapsed +---dump the screen to /tmp/nvt_live_dump.txt: d for raw, c for collapsed ---pipe is appended to each line ---caret is inserted at the cursor position ---@param collapse boolean identical lines collapsed with "*n" appended local function live_dump(collapse) - local dump_path = os.getenv("NVT_FUNC_TMP") .. "/dump.txt" + local dump_path = "/tmp/nvt_live_dump.txt" local function cap_lines() -- absolute cursor position From 8b74f72b9fc8ba3fb7323998a3e8a3aa186f23e2 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 23 Sep 2026 13:06:48 +1000 Subject: [PATCH 048/154] test: shell script is responsible for creating test directory --- scripts/functionaltest.sh | 3 +++ test/functional/nvt/fixtures.lua | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 54db0d9bb3f..c67c24ff835 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -25,6 +25,9 @@ FILES_TEST= # live source directory DIR_LIVE= +# absolute path of the source: DIR_NVT +export NVT_FUNC_NVT_ROOT="${DIR_NVT}" + # absolute path of the test, under DIR_NVT export NVT_FUNC_TEST_SOURCE= diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index d7fd40a2e35..c3108542eac 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -5,7 +5,7 @@ local M = {} ---@param system fun(cmd: string|string[], input?: string|string[]|integer): string vim.fn.system to use as it depends on the context ---@return string path function M.create_test_dir(system) - local out = system({ "/home/alex/src/nvim-tree/test-neovim-functionaltest/test/functional/nvt/create_test_cwd.sh" }) + local out = system({ os.getenv("NVT_FUNC_NVT_ROOT") .. "/test/functional/nvt/create_test_cwd.sh" }) return out:match("^DIR=(.*)$") or error(out) end From e9273e501ebea9f989fae4dfef273d35eef67e44 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 24 Sep 2026 10:36:53 +1000 Subject: [PATCH 049/154] test: complete functionaltest.sh script --- scripts/functionaltest.sh | 164 ++++++++++++++++--------- test/functional/nvt/create_test_cwd.sh | 4 +- test/functional/nvt/fixtures.lua | 2 +- 3 files changed, 109 insertions(+), 61 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index c67c24ff835..a665b5d4a46 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -13,70 +13,105 @@ fi # define $DIR_NVIM_SRC . scripts/check-nvim-src.sh -# code under test -DIR_NVT="${PWD}" +# root of code under test +dir_nvt="${PWD}" # nvim-tree linked as a package under source -DIR_NVT_PACK="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" +dir_nvt_pack="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" -# test spec files to execute, relative to neovim source -FILES_TEST= +# test spec files to execute, relative to neovim source $DIR_NVIM_SRC +files_test= -# live source directory -DIR_LIVE= +# live data directory or "none" +dir_live= -# absolute path of the source: DIR_NVT -export NVT_FUNC_NVT_ROOT="${DIR_NVT}" +# absolute path of the source: $dir_nvt +export NVT_FUNC_DIR_ROOT="${dir_nvt}" -# absolute path of the test, under DIR_NVT -export NVT_FUNC_TEST_SOURCE= +# absolute path of the test directory, under $dir_nvt +export NVT_FUNC_DIR_TEST= + +# a, t or l +mode= usage() { - echo "Usage: ${0} [-h] [-t ] [-l []]" + echo "Usage: ${0} [-a] [-h] [-t ] [-l []]" echo echo " OPTION:" - echo " -t Execute single test file or all in directory" - echo " -l Live environment, optionally using a test's data" + echo " -a Execute all tests" + echo " -t Execute single test file or all under directory" + echo " -l Live environment, optionally using a data directory" echo " -h Show this help" } -# add a file or directory $1 to FILES_TEST +# +# setup +# + +# set $mode to $1, fail if another $mode already set +mode_set() { + if [ -n "${mode}" ] && [ "${mode}" != "${1}" ]; then + echo "specify only one of -a, -t or -l" >&2 + exit 1 + fi + mode="${1}" +} + +# add a single file $1 or all _spec.lua files under directory $1 to $files_test files_test_add() { - echo "files_test_add ${1}" if [ -f "${1}" ]; then - FILES_TEST="${FILES_TEST} ${1}" + files_test="${files_test} ${1}" elif [ -d "${1}" ]; then find "${1}" -type f -iname '*_spec.lua' > /tmp/nvt_files_test while IFS= read -r f; do - FILES_TEST="${FILES_TEST} ${f}" + files_test="${files_test} ${f}" done < /tmp/nvt_files_test rm /tmp/nvt_files_test else - echo "${1} inexistent" + echo "${1} inexistent" >&2 + exit 1 + fi + if [ -z "${files_test}" ]; then + echo "no tests found in ${1}" >&2 exit 1 fi } -# set DIR_LIVE for directory or test file -live_add() { - DIR_LIVE="${1}" - if [ ! -d "${DIR_LIVE}" ]; then - echo "${DIR_LIVE} inexistent" - exit 1 +# set $dir_live to directory or "none" +dir_live_set() { + if [ -n "${1}" ]; then + dir_live="${1}" + if [ ! -d "${dir_live}" ]; then + echo "${dir_live} inexistent" >&2 + exit 1 + fi + if [ "$(basename "${dir_live}")" != "data" ]; then + echo "${dir_live} not a directory named data" >&2 + exit 1 + fi + else + dir_live="none" fi } -while getopts "hl:t:" o; do - case "$o" in +while getopts "ahlt:" o; do + case "${o}" in + a) + mode_set "${o}" + files_test_add "test/functional/nvt" + ;; h) usage exit 0 ;; l) - live_add "${OPTARG:-}" + shift + mode_set "${o}" + dir_live_set "${1}" ;; t) - files_test_add "${OPTARG:-}" + mode_set "${o}" + files_test_add "${OPTARG}" ;; *) usage >&2 @@ -84,36 +119,42 @@ while getopts "hl:t:" o; do ;; esac done +if [ -z "${mode}" ]; then + usage >&2 + exit 1 +fi + +# +# test harness +# # before all tests: links plugin and tests in their appropriate places under neovim source setup() { # plugin runtime package - mkdir -p "${DIR_NVT_PACK}" - ln -sv "${DIR_NVT}/doc" "${DIR_NVT_PACK}" - ln -sv "${DIR_NVT}/lua" "${DIR_NVT_PACK}" - ln -sv "${DIR_NVT}/plugin" "${DIR_NVT_PACK}" + mkdir -pv "${dir_nvt_pack}" + ln -sv "${dir_nvt}/doc" "${dir_nvt_pack}" + ln -sv "${dir_nvt}/lua" "${dir_nvt_pack}" + ln -sv "${dir_nvt}/plugin" "${dir_nvt_pack}" # tests - ln -sv "${DIR_NVT}/test/functional/nvt" "${DIR_NVIM_SRC}/test/functional" + ln -sv "${dir_nvt}/test/functional/nvt" "${DIR_NVIM_SRC}/test/functional" } -# after all tests: remove lua/test links and temp +# after all tests: remove plugin and test links from neovim source teardown() { # plugin runtime package - rm -fv "${DIR_NVT_PACK}/doc" - rm -fv "${DIR_NVT_PACK}/lua" - rm -fv "${DIR_NVT_PACK}/plugin" - rm -rf "${DIR_NVT_PACK}" + rm -fv "${dir_nvt_pack}/doc" + rm -fv "${dir_nvt_pack}/lua" + rm -fv "${dir_nvt_pack}/plugin" + rm -rf "${dir_nvt_pack}" # tests rm -fv "${DIR_NVIM_SRC}/test/functional/nvt" } live() { - if [ "$(basename "${DIR_LIVE}")" = "data" ]; then - NVT_FUNC_TEST_SOURCE="$(realpath "$(dirname "${DIR_LIVE}")")" - else - NVT_FUNC_TEST_SOURCE="$(realpath "${DIR_LIVE}")" + if [ "${dir_live}" != "none" ]; then + NVT_FUNC_DIR_TEST="$(realpath "$(dirname "${dir_live}")")" fi # options extracted from testnvim.lua nvim_argv, nvim_set @@ -129,26 +170,33 @@ live() { --cmd "unlet g:colors_name" } -teardown - -setup - -if [ -n "${DIR_LIVE}" ]; then - live -else - # run all tests if none specified - if [ -z "${FILES_TEST}" ]; then - files_test_add "test/functional/nvt" - fi - +files_test_execute() { # cmake must be run from nvim source root cd "${DIR_NVIM_SRC}" # execute all tests - for f in ${FILES_TEST}; do - NVT_FUNC_TEST_SOURCE="$(realpath "$(dirname "${f}")")" + for f in ${files_test}; do + NVT_FUNC_DIR_TEST="$(realpath "$(dirname "${f}")")" make functionaltest TEST_FILE="${f}" done -fi +} + +# +# act +# +teardown + +setup + +case "${mode}" in + l) + live + ;; + a|t) + files_test_execute + ;; + *) + ;; +esac teardown diff --git a/test/functional/nvt/create_test_cwd.sh b/test/functional/nvt/create_test_cwd.sh index b12e0217c80..ef3ee90b16f 100755 --- a/test/functional/nvt/create_test_cwd.sh +++ b/test/functional/nvt/create_test_cwd.sh @@ -20,8 +20,8 @@ rm -r -f "${DIR}" mkdir -p "${DIR}" # maybe copy entire data directory and use it -if [ -d "${NVT_FUNC_TEST_SOURCE}/data" ]; then - cp -p -r "${NVT_FUNC_TEST_SOURCE}/data" "${DIR}" +if [ -d "${NVT_FUNC_DIR_TEST}/data" ]; then + cp -p -r "${NVT_FUNC_DIR_TEST}/data" "${DIR}" DIR="${DIR}/data" fi diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index c3108542eac..2af0db32a2d 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -5,7 +5,7 @@ local M = {} ---@param system fun(cmd: string|string[], input?: string|string[]|integer): string vim.fn.system to use as it depends on the context ---@return string path function M.create_test_dir(system) - local out = system({ os.getenv("NVT_FUNC_NVT_ROOT") .. "/test/functional/nvt/create_test_cwd.sh" }) + local out = system({ os.getenv("NVT_FUNC_DIR_ROOT") .. "/test/functional/nvt/create_test_cwd.sh" }) return out:match("^DIR=(.*)$") or error(out) end From 0debfb9042a4bbaed400b2cd3d97ba4912cedc79 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 24 Sep 2026 10:38:29 +1000 Subject: [PATCH 050/154] test: complete functionaltest.sh script --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 87116fdd485..322672267d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -132,7 +132,7 @@ jobs: cd "${DIR_NVIM_SRC}" make - - run: scripts/functionaltest.sh + - run: scripts/functionaltest.sh -a - run: scripts/luals-check.sh test From 6ed1d4fb7db554de5b03761420e089a02a2c129d Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 24 Sep 2026 10:44:08 +1000 Subject: [PATCH 051/154] test: complete functionaltest.sh script --- test/functional/nvt/README.md | 5 ++++- test/functional/nvt/init_live.lua | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/test/functional/nvt/README.md b/test/functional/nvt/README.md index 7c5cb73aff1..9c35ef7e8b8 100644 --- a/test/functional/nvt/README.md +++ b/test/functional/nvt/README.md @@ -1,12 +1,15 @@ # Generating Test Data -Execute `scripts/functionaltest.sh -l ` +Execute `scripts/functionaltest.sh -l [ ]` This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua` +Test's `data` directory should be specified if present. + - `u` to dump the entire screen to `/tmp/nvt_func/dump.txt` and open it - `c` to dump with identical lines collapsed - `r` to resize the screen to 80 x 24, to match tests +- `o` to execute `api.tree.open()` ## Text Only: `attr_ids = {}` diff --git a/test/functional/nvt/init_live.lua b/test/functional/nvt/init_live.lua index ca16dbb3636..373a57ce844 100644 --- a/test/functional/nvt/init_live.lua +++ b/test/functional/nvt/init_live.lua @@ -67,10 +67,6 @@ local function live_dump(collapse) vim.ui.open(dump_path) end -vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) -vim.keymap.set("n", "c", function() live_dump(true) end, { remap = false, }) -vim.keymap.set("n", "r", screen_resize, { remap = false, }) - ---set the screen size to match tests screen_resize() @@ -83,3 +79,9 @@ require("nvim-tree").setup({}) -- create and change to the directory the test will execute from vim.api.nvim_set_current_dir(nf.create_test_dir(vim.fn.system)) + +-- mappings +vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) +vim.keymap.set("n", "c", function() live_dump(true) end, { remap = false, }) +vim.keymap.set("n", "r", screen_resize, { remap = false, }) +vim.keymap.set("n", "o", require("nvim-tree.api").tree.open, { remap = false, }) From 2fe87ab23f08b6fdaf9a1d6651b4a446cdae2d49 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 24 Sep 2026 11:48:16 +1000 Subject: [PATCH 052/154] test: extract utils --- test/functional/nvt/fs/create/dir_spec.lua | 125 ++++++--------------- test/functional/nvt/utils.lua | 21 ++++ 2 files changed, 56 insertions(+), 90 deletions(-) diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index f7e9183af9f..eab066a9d8f 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -1,45 +1,41 @@ local t = require("test.testutil") -local nf = require("test.functional.nvt.fixtures") +local nu = require("test.functional.nvt.utils") local n = require("test.functional.testnvim")() -local Screen = require("test.functional.ui.screen") local eq = t.eq -local clear = n.clear -local exec_lua = n.exec_lua -- 0.13 global compatibility ---@diagnostic disable: undefined-global local describe = t.describe or describe local before_each = t.before_each or before_each local it = t.it or it -local setup = t.setup or setup ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen before_each(function() - exec_lua(function() - require("nvim-tree").setup({}) - end) + screen = nu.create_session({ ext_cmdline = true }) end) -describe("single", function() - setup(function() - clear() - - screen = Screen.new(80, 24) - - exec_lua(function() - vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) +describe("single dir", function() + before_each(function() + n.exec_lua(function() + require("nvim-tree").setup({}) end) - - n.api.nvim_set_current_dir(nf.create_test_dir(n.fn.system)) end) - it("direct", function() + it("direct ok", function() n.feed( ":NvimTreeOpen", - "a", + "a" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, + }) + + n.feed( "direct/" ) @@ -61,7 +57,7 @@ NvimTree_1 [-] [No Name] eq(stat and stat.type, "directory") end) - it("indirect", function() + it("indirect ok", function() n.feed( ":NvimTreeOpen", "gg", @@ -76,24 +72,8 @@ NvimTree_1 [-] [No Name]   d1 │~ | ^   indirect │~ |  d1f1 │~ | -   direct │~ |  f1 │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | +~ │~ |*17 NvimTree_1 [-] [No Name] | [NvimTree] /tmp/nvt_func/data/d1/indirect/ was properly created | ]], @@ -104,7 +84,7 @@ NvimTree_1 [-] [No Name] eq(stat and stat.type, "directory") end) - it("dir_exists", function() + it("existing dir", function() n.feed( ":NvimTreeOpen", "gg", @@ -117,33 +97,15 @@ NvimTree_1 [-] [No Name] grid = [[ ^/tmp/nvt_func/data/.. │ |   d1 │~ | -   direct │~ |  f1 │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | +~ │~ |*19 NvimTree_1 [-] [No Name] | [NvimTree] Cannot create: file already exists | - ]], + ]], }) end) - it("file_exists", function() + it("existing file", function() n.feed( ":NvimTreeOpen", "gg", @@ -151,36 +113,19 @@ NvimTree_1 [-] [No Name] "d1/d1f1/" ) - -- TODO BUG this fails but shows message "/tmp/nvt_func/data/d1/d1f1/ was properly created" - -- screen:expect({ - -- attr_ids = {}, - -- grid = [[ - -- ^/tmp/nvt_func/data/.. │ | - --   d1 │~ | - --   direct │~ | - --  f1 │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- ~ │~ | - -- NvimTree_1 [-] [No Name] | - -- [NvimTree] Cannot create: file already exists | - -- ]], - -- }) + -- TODO BUG this fails but shows message "/tmp/nvt_func/data/d1/d1f1/ was properly created" and focuses the file + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d1f1 │~ | +  f1 │~ | +~ │~ |*18 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1/d1f1/ was properly created | + ]], + }) end) end) diff --git a/test/functional/nvt/utils.lua b/test/functional/nvt/utils.lua index a44e9c6b8e6..bda88a70710 100644 --- a/test/functional/nvt/utils.lua +++ b/test/functional/nvt/utils.lua @@ -1,7 +1,28 @@ local n = require("test.functional.testnvim")() +local nf = require("test.functional.nvt.fixtures") +local Screen = require("test.functional.ui.screen") local M = {} +---Create a new neovim session with +---- nvim-tree.lua package added +---- fresh test data directory created and cd'd into +---@param options? test.functional.ui.screen.Opts +---@return test.functional.ui.screen +function M.create_session(options) + n.clear() + + local screen = Screen.new(80, 24, options) + + n.exec_lua(function() + vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) + end) + + n.api.nvim_set_current_dir(nf.create_test_dir(n.fn.system)) + + return screen +end + --- Reset all NvimTree* highlight groups to just a unique foreground colour --- Return attr_ids to match --- Add a CL variant with the same background colour as NvimTreeCursorLine From 26256c44048524318182b8939ac5301bd0528e62 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 24 Sep 2026 12:05:20 +1000 Subject: [PATCH 053/154] test: more dir tests --- test/functional/nvt/fs/create/dir_spec.lua | 30 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index eab066a9d8f..083a87361f7 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -61,7 +61,15 @@ NvimTree_1 [-] [No Name] n.feed( ":NvimTreeOpen", "gg", - "a", + "a" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, + }) + + n.feed( "d1/indirect/" ) @@ -88,7 +96,15 @@ NvimTree_1 [-] [No Name] n.feed( ":NvimTreeOpen", "gg", - "a", + "a" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, + }) + + n.feed( "d1/" ) @@ -109,7 +125,15 @@ NvimTree_1 [-] [No Name] n.feed( ":NvimTreeOpen", "gg", - "a", + "a" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, + }) + + n.feed( "d1/d1f1/" ) From a80f70899a394ef49b9845b6a7a7a21437bc22f3 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 24 Sep 2026 12:13:05 +1000 Subject: [PATCH 054/154] test: extract fixtures, remove utils --- test/functional/nvt/api/tree/open_spec.lua | 15 +---- test/functional/nvt/fixtures.lua | 78 ++++++++++++++++++++-- test/functional/nvt/fs/create/dir_spec.lua | 4 +- test/functional/nvt/init_live.lua | 6 +- test/functional/nvt/map/node/open_spec.lua | 12 +--- test/functional/nvt/utils.lua | 74 -------------------- 6 files changed, 79 insertions(+), 110 deletions(-) delete mode 100644 test/functional/nvt/utils.lua diff --git a/test/functional/nvt/api/tree/open_spec.lua b/test/functional/nvt/api/tree/open_spec.lua index ad2b0e5f13d..9a68c5beaf0 100644 --- a/test/functional/nvt/api/tree/open_spec.lua +++ b/test/functional/nvt/api/tree/open_spec.lua @@ -1,9 +1,6 @@ local t = require("test.testutil") local nf = require("test.functional.nvt.fixtures") -local nt = require("test.functional.nvt.utils") local n = require("test.functional.testnvim")() -local Screen = require("test.functional.ui.screen") -local clear = n.clear local exec_lua = n.exec_lua -- 0.13 global compatibility @@ -19,15 +16,7 @@ describe("api_tree_open", function() local screen setup(function() - clear() - - screen = Screen.new(80, 24) - - exec_lua(function() - vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) - end) - - n.api.nvim_set_current_dir(nf.create_test_dir(n.fn.system)) + screen = nf.create_session() end) before_each(function() @@ -35,7 +24,7 @@ describe("api_tree_open", function() require("nvim-tree").setup({}) end) - screen:add_extra_attr_ids(nt.simple_attr_ids()) + screen:add_extra_attr_ids(nf.simple_attr_ids()) end) it("populated_unfocussed_text_only", function() diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index 2af0db32a2d..f842136e94e 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -1,13 +1,77 @@ +local n = require("test.functional.testnvim")() +local Screen = require("test.functional.ui.screen") + local M = {} ----create and return the absolute path of the directory to execute tests in ----recursively copies data if present ----@param system fun(cmd: string|string[], input?: string|string[]|integer): string vim.fn.system to use as it depends on the context ----@return string path -function M.create_test_dir(system) - local out = system({ os.getenv("NVT_FUNC_DIR_ROOT") .. "/test/functional/nvt/create_test_cwd.sh" }) +---Create a new neovim session with +---- nvim-tree.lua package added +---- fresh test data directory created and cd'd into +---@param options? test.functional.ui.screen.Opts +---@return test.functional.ui.screen +function M.create_session(options) + n.clear() + + local screen = Screen.new(80, 24, options) + + n.exec_lua(function() + vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) + end) + + -- TODO neovim 0.13: replace with vim.system calls; vim.system is not currenctly available in neovim 0.12 func tests + local out = n.fn.system({ os.getenv("NVT_FUNC_DIR_ROOT") .. "/test/functional/nvt/create_test_cwd.sh" }) + local dir = out:match("^DIR=(.*)$") or error(out) + + n.api.nvim_set_current_dir(dir) + + return screen +end + +--- Reset all NvimTree* highlight groups to just a unique foreground colour +--- Return attr_ids to match +--- Add a CL variant with the same background colour as NvimTreeCursorLine +--- May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order +function M.simple_attr_ids() + local attr_ids = {} + + -- math.random(tonumber('0x707070'),tonumber('0x909090')) + local bg_rgb, bg_hex = 8758352, "#85a450" + + -- build the cursor line first, background only + attr_ids["NvimTreeCursorLine"] = { background = bg_rgb } + n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = bg_hex }) + + -- unique colour for each group, descending from #fefefe + local i, r, g, b = 1, 254, 254, 254 + local rgb, hex + + for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do + if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") and not group:match(".*CL$") then + -- next unique fg colour + rgb = r * 256 * 256 + g * 256 + b + hex = string.format("#%x", rgb) + i = i + 1 + if (i % 256 == 0) then + b = 254 + g = 254 + r = r - 1 + elseif (i % 16 == 0) then + b = 254 + g = g - 1 + else + b = b - 1 + end + + -- add the group's concrete definition with fg only + attr_ids[group] = { foreground = rgb } + n.api.nvim_set_hl(0, group, { fg = hex }) + + -- create an NvimTreeCursorLine variant + attr_ids[group .. "CL"] = { foreground = rgb, background = bg_rgb } + n.api.nvim_set_hl(0, group .. "CL", { fg = hex, bg = bg_hex }) + end + end - return out:match("^DIR=(.*)$") or error(out) + return attr_ids end return M diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index 083a87361f7..1295447ba15 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -1,5 +1,5 @@ local t = require("test.testutil") -local nu = require("test.functional.nvt.utils") +local nf = require("test.functional.nvt.fixtures") local n = require("test.functional.testnvim")() local eq = t.eq @@ -14,7 +14,7 @@ local it = t.it or it local screen before_each(function() - screen = nu.create_session({ ext_cmdline = true }) + screen = nf.create_session({ ext_cmdline = true }) end) describe("single dir", function() diff --git a/test/functional/nvt/init_live.lua b/test/functional/nvt/init_live.lua index 373a57ce844..d5d10b1593a 100644 --- a/test/functional/nvt/init_live.lua +++ b/test/functional/nvt/init_live.lua @@ -1,5 +1,3 @@ -local nf = require("test.functional.nvt.fixtures") - -- match the test screen size: r to reapply if the terminal is not cooperating local function screen_resize() vim.o.columns = 80 @@ -78,7 +76,9 @@ vim.api.nvim_command("packadd nvim-tree.lua") require("nvim-tree").setup({}) -- create and change to the directory the test will execute from -vim.api.nvim_set_current_dir(nf.create_test_dir(vim.fn.system)) +local out = vim.fn.system({ os.getenv("NVT_FUNC_DIR_ROOT") .. "/test/functional/nvt/create_test_cwd.sh" }) +local dir = out:match("^DIR=(.*)$") or error(out) +vim.api.nvim_set_current_dir(dir) -- mappings vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) diff --git a/test/functional/nvt/map/node/open_spec.lua b/test/functional/nvt/map/node/open_spec.lua index 3b47bd9a8e9..9d13dcdbed0 100644 --- a/test/functional/nvt/map/node/open_spec.lua +++ b/test/functional/nvt/map/node/open_spec.lua @@ -1,8 +1,6 @@ local t = require("test.testutil") local nf = require("test.functional.nvt.fixtures") local n = require("test.functional.testnvim")() -local Screen = require("test.functional.ui.screen") -local clear = n.clear local exec_lua = n.exec_lua -- 0.13 global compatibility @@ -18,15 +16,7 @@ describe("map_node_open", function() local screen setup(function() - clear() - - screen = Screen.new(80, 24) - - exec_lua(function() - vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) - end) - - n.api.nvim_set_current_dir(nf.create_test_dir(n.fn.system)) + screen = nf.create_session() end) before_each(function() diff --git a/test/functional/nvt/utils.lua b/test/functional/nvt/utils.lua deleted file mode 100644 index bda88a70710..00000000000 --- a/test/functional/nvt/utils.lua +++ /dev/null @@ -1,74 +0,0 @@ -local n = require("test.functional.testnvim")() -local nf = require("test.functional.nvt.fixtures") -local Screen = require("test.functional.ui.screen") - -local M = {} - ----Create a new neovim session with ----- nvim-tree.lua package added ----- fresh test data directory created and cd'd into ----@param options? test.functional.ui.screen.Opts ----@return test.functional.ui.screen -function M.create_session(options) - n.clear() - - local screen = Screen.new(80, 24, options) - - n.exec_lua(function() - vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) - end) - - n.api.nvim_set_current_dir(nf.create_test_dir(n.fn.system)) - - return screen -end - ---- Reset all NvimTree* highlight groups to just a unique foreground colour ---- Return attr_ids to match ---- Add a CL variant with the same background colour as NvimTreeCursorLine ---- May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order -function M.simple_attr_ids() - local attr_ids = {} - - -- math.random(tonumber('0x707070'),tonumber('0x909090')) - local bg_rgb, bg_hex = 8758352, "#85a450" - - -- build the cursor line first, background only - attr_ids["NvimTreeCursorLine"] = { background = bg_rgb } - n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = bg_hex }) - - -- unique colour for each group, descending from #fefefe - local i, r, g, b = 1, 254, 254, 254 - local rgb, hex - - for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do - if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") and not group:match(".*CL$") then - -- next unique fg colour - rgb = r * 256 * 256 + g * 256 + b - hex = string.format("#%x", rgb) - i = i + 1 - if (i % 256 == 0) then - b = 254 - g = 254 - r = r - 1 - elseif (i % 16 == 0) then - b = 254 - g = g - 1 - else - b = b - 1 - end - - -- add the group's concrete definition with fg only - attr_ids[group] = { foreground = rgb } - n.api.nvim_set_hl(0, group, { fg = hex }) - - -- create an NvimTreeCursorLine variant - attr_ids[group .. "CL"] = { foreground = rgb, background = bg_rgb } - n.api.nvim_set_hl(0, group .. "CL", { fg = hex, bg = bg_hex }) - end - end - - return attr_ids -end - -return M From 81778d6ec5fae1a069784863d0c928a3d3f9595e Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 24 Sep 2026 13:01:04 +1000 Subject: [PATCH 055/154] test: more dir create tests, add file create tests --- test/functional/nvt/asserts.lua | 17 +++ test/functional/nvt/fs/create/dir_spec.lua | 130 ++++++++++++----- test/functional/nvt/fs/create/file_spec.lua | 151 ++++++++++++++++++++ 3 files changed, 262 insertions(+), 36 deletions(-) create mode 100644 test/functional/nvt/asserts.lua create mode 100644 test/functional/nvt/fs/create/file_spec.lua diff --git a/test/functional/nvt/asserts.lua b/test/functional/nvt/asserts.lua new file mode 100644 index 00000000000..f75cf31e134 --- /dev/null +++ b/test/functional/nvt/asserts.lua @@ -0,0 +1,17 @@ +local t = require("test.testutil") + +local M = {} + +function M.dir_exists(path) + local stat, err = vim.uv.fs_stat(path) + t.eq(nil, err, path) + t.eq("directory", stat and stat.type, path) +end + +function M.file_exists(path) + local stat, err = vim.uv.fs_stat(path) + t.eq(nil, err, path) + t.eq("file", stat and stat.type, path) +end + +return M diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index 1295447ba15..fc686eff771 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -1,7 +1,7 @@ local t = require("test.testutil") local nf = require("test.functional.nvt.fixtures") +local na = require("test.functional.nvt.asserts") local n = require("test.functional.testnvim")() -local eq = t.eq -- 0.13 global compatibility ---@diagnostic disable: undefined-global @@ -13,18 +13,25 @@ local it = t.it or it --- @type test.functional.ui.screen local screen + +-- TODO +-- test events +-- test creating in an illegal location e.g. /foo + + before_each(function() screen = nf.create_session({ ext_cmdline = true }) end) -describe("single dir", function() + +describe("prompt", function() before_each(function() n.exec_lua(function() require("nvim-tree").setup({}) end) end) - it("direct ok", function() + it("prompt", function() n.feed( ":NvimTreeOpen", "a" @@ -34,8 +41,22 @@ describe("single dir", function() mode = "cmdline_normal", cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, }) + end) +end) + + +describe("single dir", function() + before_each(function() + n.exec_lua(function() + require("nvim-tree").setup({}) + end) + end) + + it("direct ok", function() n.feed( + ":NvimTreeOpen", + "a", "direct/" ) @@ -52,24 +73,15 @@ NvimTree_1 [-] [No Name] ]], }) - local stat, err = vim.uv.fs_stat("/tmp/nvt_func/data/direct") - eq(err, nil) - eq(stat and stat.type, "directory") + na.dir_exists("/tmp/nvt_func/data/direct") end) + it("indirect ok", function() n.feed( ":NvimTreeOpen", "gg", - "a" - ) - - screen:expect({ - mode = "cmdline_normal", - cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, - }) - - n.feed( + "a", "d1/indirect/" ) @@ -87,24 +99,15 @@ NvimTree_1 [-] [No Name] ]], }) - local stat, err = vim.uv.fs_stat("/tmp/nvt_func/data/d1/indirect") - eq(err, nil) - eq(stat and stat.type, "directory") + na.dir_exists("/tmp/nvt_func/data/d1/indirect") end) + it("existing dir", function() n.feed( ":NvimTreeOpen", "gg", - "a" - ) - - screen:expect({ - mode = "cmdline_normal", - cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, - }) - - n.feed( + "a", "d1/" ) @@ -121,23 +124,17 @@ NvimTree_1 [-] [No Name] }) end) + it("existing file", function() n.feed( ":NvimTreeOpen", "gg", - "a" - ) - - screen:expect({ - mode = "cmdline_normal", - cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, - }) - - n.feed( + "a", "d1/d1f1/" ) -- TODO BUG this fails but shows message "/tmp/nvt_func/data/d1/d1f1/ was properly created" and focuses the file + -- TODO add similar test for multiple dirs when fixed screen:expect({ attr_ids = {}, grid = [[ @@ -153,4 +150,65 @@ NvimTree_1 [-] [No Name] end) end) + +describe("multiple dirs", function() + before_each(function() + n.exec_lua(function() + require("nvim-tree").setup({}) + end) + end) + + it("direct ok", function() + n.feed( + ":NvimTreeOpen", + "a", + "direct1/direct2/" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   direct1 │~ | + ^   direct2 │~ | +  f1 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/direct1/direct2/ was properly created | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/direct1") + na.dir_exists("/tmp/nvt_func/data/direct1/direct2") + end) + + + it("indirect ok", function() + n.feed( + ":NvimTreeOpen", + "a", + "d1/indirect1/indirect2/" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   indirect1 │~ | + ^   indirect2 │~ | +  d1f1 │~ | +  f1 │~ | +~ │~ |*16 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1/indirect1/indirect2/ was properly created | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d1/indirect1") + na.dir_exists("/tmp/nvt_func/data/d1/indirect1/indirect2") + end) +end) + -- vim:colorcolumn=80 diff --git a/test/functional/nvt/fs/create/file_spec.lua b/test/functional/nvt/fs/create/file_spec.lua new file mode 100644 index 00000000000..d6d1701296b --- /dev/null +++ b/test/functional/nvt/fs/create/file_spec.lua @@ -0,0 +1,151 @@ +local t = require("test.testutil") +local nf = require("test.functional.nvt.fixtures") +local na = require("test.functional.nvt.asserts") +local n = require("test.functional.testnvim")() + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + +--- @type test.functional.ui.screen +local screen + + +-- TODO +-- test events +-- test creating in an illegal location e.g. /foo + + +before_each(function() + screen = nf.create_session({ ext_cmdline = true }) +end) + + +describe("prompt", function() + before_each(function() + n.exec_lua(function() + require("nvim-tree").setup({}) + end) + end) + + it("prompt", function() + n.feed( + ":NvimTreeOpen", + "a" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, + }) + end) +end) + + +describe("single file", function() + before_each(function() + n.exec_lua(function() + require("nvim-tree").setup({}) + end) + end) + + + it("direct ok", function() + n.feed( + ":NvimTreeOpen", + "a", + "direct" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  direct │~ | +  f1 │~ | +~ │~ |*18 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/direct was properly created | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/direct") + end) + + + it("indirect ok", function() + n.feed( + ":NvimTreeOpen", + "a", + "d1/indirect" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | + ^  indirect │~ | +  f1 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1/indirect was properly created | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/d1/indirect") + end) + + + it("existing file", function() + n.feed( + ":NvimTreeOpen", + "a", + "f1" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  f1 │~ | +~ │~ |*19 +NvimTree_1 [-] [No Name] | +[NvimTree] Cannot create: file already exists | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/f1") + end) + + + it("existing dir", function() + n.feed( + ":NvimTreeOpen", + "a", + "d1" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  f1 │~ | +~ │~ |*19 +NvimTree_1 [-] [No Name] | +[NvimTree] Cannot create: file already exists | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d1") + end) +end) + +-- vim:colorcolumn=80 From a712128a96fe254dd3e684f508c366ffd1f3aee5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 25 Sep 2026 12:15:56 +1000 Subject: [PATCH 056/154] test: add event tests, implement for dirs --- test/functional/nvt/asserts.lua | 14 ++++ test/functional/nvt/fixtures.lua | 23 +++++++ test/functional/nvt/fs/create/dir_spec.lua | 80 ++++++++++++++++------ 3 files changed, 97 insertions(+), 20 deletions(-) diff --git a/test/functional/nvt/asserts.lua b/test/functional/nvt/asserts.lua index f75cf31e134..d638c9bc628 100644 --- a/test/functional/nvt/asserts.lua +++ b/test/functional/nvt/asserts.lua @@ -1,17 +1,31 @@ +local n = require("test.functional.testnvim")() local t = require("test.testutil") local M = {} +---Assert path exists and is a directory +---@param path string absolute function M.dir_exists(path) local stat, err = vim.uv.fs_stat(path) t.eq(nil, err, path) t.eq("directory", stat and stat.type, path) end +---Assert path exists and is a file +---@param path string absolute function M.file_exists(path) local stat, err = vim.uv.fs_stat(path) t.eq(nil, err, path) t.eq("file", stat and stat.type, path) end +---Assert events received during a functest, recorded in session global NVT_FUNCTEST_EVENTS +---Must be subscribed via event_subscribe +---@param events nvt.functest.event[] +function M.events_received(events) + t.eq(events, n.exec_lua(function() + return NVT_FUNCTEST_EVENTS + end)) +end + return M diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index f842136e94e..89977be06fa 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -3,6 +3,10 @@ local Screen = require("test.functional.ui.screen") local M = {} +---@class (exact) nvt.functest.event +---@field event_type nvim_tree.api.events.Event [nvim_tree_events_kind] +---@field payload table deep copy + ---Create a new neovim session with ---- nvim-tree.lua package added ---- fresh test data directory created and cd'd into @@ -15,6 +19,9 @@ function M.create_session(options) n.exec_lua(function() vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) + + ---@type nvt.functest.event[] + NVT_FUNCTEST_EVENTS = NVT_FUNCTEST_EVENTS or {} ---@diagnostic disable-line: global-element end) -- TODO neovim 0.13: replace with vim.system calls; vim.system is not currenctly available in neovim 0.12 func tests @@ -26,6 +33,22 @@ function M.create_session(options) return screen end +---Subscribe to an event, to be recorded in session global NVT_FUNCTEST_EVENTS nvt.functest.event[] +---Assert events via events_received +---@param event_type nvim_tree.api.events.Event [nvim_tree_events_kind] +function M.event_subscribe(event_type) + n.exec_lua(function() + local api = require("nvim-tree.api") + + api.events.subscribe(event_type, function(payload) + table.insert(NVT_FUNCTEST_EVENTS, { + event_type = event_type, + payload = vim.deepcopy(payload), + }) + end) + end) +end + --- Reset all NvimTree* highlight groups to just a unique foreground colour --- Return attr_ids to match --- Add a CL variant with the same background colour as NvimTreeCursorLine diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index fc686eff771..dd0d217f1ba 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -15,22 +15,21 @@ local screen -- TODO --- test events -- test creating in an illegal location e.g. /foo before_each(function() screen = nf.create_session({ ext_cmdline = true }) + + n.exec_lua(function() + require("nvim-tree").setup({}) + end) + + nf.event_subscribe("FolderCreated") end) describe("prompt", function() - before_each(function() - n.exec_lua(function() - require("nvim-tree").setup({}) - end) - end) - it("prompt", function() n.feed( ":NvimTreeOpen", @@ -46,13 +45,6 @@ end) describe("single dir", function() - before_each(function() - n.exec_lua(function() - require("nvim-tree").setup({}) - end) - end) - - it("direct ok", function() n.feed( ":NvimTreeOpen", @@ -74,6 +66,15 @@ NvimTree_1 [-] [No Name] }) na.dir_exists("/tmp/nvt_func/data/direct") + + na.events_received({ + { + event_type = "FolderCreated", + payload = { + folder_name = "/tmp/nvt_func/data/direct/", + }, + }, + }) end) @@ -100,6 +101,15 @@ NvimTree_1 [-] [No Name] }) na.dir_exists("/tmp/nvt_func/data/d1/indirect") + + na.events_received({ + { + event_type = "FolderCreated", + payload = { + folder_name = "/tmp/nvt_func/data/d1/indirect/", + }, + }, + }) end) @@ -122,6 +132,8 @@ NvimTree_1 [-] [No Name] [NvimTree] Cannot create: file already exists | ]], }) + + na.events_received({}) end) @@ -147,17 +159,13 @@ NvimTree_1 [-] [No Name] [NvimTree] /tmp/nvt_func/data/d1/d1f1/ was properly created | ]], }) + + na.events_received({}) end) end) describe("multiple dirs", function() - before_each(function() - n.exec_lua(function() - require("nvim-tree").setup({}) - end) - end) - it("direct ok", function() n.feed( ":NvimTreeOpen", @@ -181,6 +189,22 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/direct1") na.dir_exists("/tmp/nvt_func/data/direct1/direct2") + + na.events_received({ + { + event_type = "FolderCreated", + payload = { + -- TODO BUG this should be "/tmp/nvt_func/data/direct1/" + folder_name = "/tmp/nvt_func/data/direct1/direct2/", + }, + }, + { + event_type = "FolderCreated", + payload = { + folder_name = "/tmp/nvt_func/data/direct1/direct2/", + }, + }, + }) end) @@ -208,6 +232,22 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/d1/indirect1") na.dir_exists("/tmp/nvt_func/data/d1/indirect1/indirect2") + + na.events_received({ + { + event_type = "FolderCreated", + payload = { + -- TODO BUG this should be "/tmp/nvt_func/data/d1/indirect1/" + folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", + }, + }, + { + event_type = "FolderCreated", + payload = { + folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", + }, + }, + }) end) end) From e722e8a05c47deb23fbac839010fd0e69f6c56d8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 25 Sep 2026 12:27:22 +1000 Subject: [PATCH 057/154] test: file event tests --- test/functional/nvt/fs/create/dir_spec.lua | 48 +++----------- test/functional/nvt/fs/create/file_spec.lua | 70 ++++++++++++++++----- 2 files changed, 64 insertions(+), 54 deletions(-) diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index dd0d217f1ba..894d257cd99 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -30,7 +30,7 @@ end) describe("prompt", function() - it("prompt", function() + it("ok", function() n.feed( ":NvimTreeOpen", "a" @@ -68,12 +68,7 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/direct") na.events_received({ - { - event_type = "FolderCreated", - payload = { - folder_name = "/tmp/nvt_func/data/direct/", - }, - }, + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct/", }, }, }) end) @@ -103,12 +98,7 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/d1/indirect") na.events_received({ - { - event_type = "FolderCreated", - payload = { - folder_name = "/tmp/nvt_func/data/d1/indirect/", - }, - }, + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect/", }, }, }) end) @@ -191,19 +181,9 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/direct1/direct2") na.events_received({ - { - event_type = "FolderCreated", - payload = { - -- TODO BUG this should be "/tmp/nvt_func/data/direct1/" - folder_name = "/tmp/nvt_func/data/direct1/direct2/", - }, - }, - { - event_type = "FolderCreated", - payload = { - folder_name = "/tmp/nvt_func/data/direct1/direct2/", - }, - }, + -- TODO BUG this should be "/tmp/nvt_func/data/direct1/" + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct1/direct2/", }, }, + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct1/direct2/", }, }, }) end) @@ -234,19 +214,9 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/d1/indirect1/indirect2") na.events_received({ - { - event_type = "FolderCreated", - payload = { - -- TODO BUG this should be "/tmp/nvt_func/data/d1/indirect1/" - folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", - }, - }, - { - event_type = "FolderCreated", - payload = { - folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", - }, - }, + -- TODO BUG this should be "/tmp/nvt_func/data/d1/indirect1/" + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", }, }, + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", }, }, }) end) end) diff --git a/test/functional/nvt/fs/create/file_spec.lua b/test/functional/nvt/fs/create/file_spec.lua index d6d1701296b..b38604d8bd6 100644 --- a/test/functional/nvt/fs/create/file_spec.lua +++ b/test/functional/nvt/fs/create/file_spec.lua @@ -15,23 +15,24 @@ local screen -- TODO --- test events -- test creating in an illegal location e.g. /foo before_each(function() screen = nf.create_session({ ext_cmdline = true }) + + n.exec_lua(function() + require("nvim-tree").setup({}) + end) + + nf.event_subscribe("FileCreated") + nf.event_subscribe("WillCreateFile") + nf.event_subscribe("FolderCreated") end) describe("prompt", function() - before_each(function() - n.exec_lua(function() - require("nvim-tree").setup({}) - end) - end) - - it("prompt", function() + it("ok", function() n.feed( ":NvimTreeOpen", "a" @@ -46,13 +47,6 @@ end) describe("single file", function() - before_each(function() - n.exec_lua(function() - require("nvim-tree").setup({}) - end) - end) - - it("direct ok", function() n.feed( ":NvimTreeOpen", @@ -74,6 +68,11 @@ NvimTree_1 [-] [No Name] }) na.file_exists("/tmp/nvt_func/data/direct") + + na.events_received({ + { event_type = "WillCreateFile", payload = { fname = "/tmp/nvt_func/data/direct", }, }, + { event_type = "FileCreated", payload = { fname = "/tmp/nvt_func/data/direct", }, }, + }) end) @@ -99,6 +98,11 @@ NvimTree_1 [-] [No Name] }) na.file_exists("/tmp/nvt_func/data/d1/indirect") + + na.events_received({ + { event_type = "WillCreateFile", payload = { fname = "/tmp/nvt_func/data/d1/indirect", }, }, + { event_type = "FileCreated", payload = { fname = "/tmp/nvt_func/data/d1/indirect", }, }, + }) end) @@ -122,6 +126,8 @@ NvimTree_1 [-] [No Name] }) na.file_exists("/tmp/nvt_func/data/f1") + + na.events_received({}) end) @@ -145,6 +151,40 @@ NvimTree_1 [-] [No Name] }) na.dir_exists("/tmp/nvt_func/data/d1") + + na.events_received({}) + end) + + + it("nested dir", function() + n.feed( + ":NvimTreeOpen", + "a", + "newdir/newfile" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   newdir │~ | + ^  newfile │~ | +  f1 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/newdir/newfile was properly created | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d1") + + na.events_received({ + -- TODO BUG this should be "/tmp/nvt_func/data/newdir/" + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/newdir/newfile", }, }, + { event_type = "WillCreateFile", payload = { fname = "/tmp/nvt_func/data/newdir/newfile", }, }, + { event_type = "FileCreated", payload = { fname = "/tmp/nvt_func/data/newdir/newfile", }, }, + }) end) end) From 3da23d26927a82f69ece8c13fbaae049b3c44995 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 25 Sep 2026 12:52:52 +1000 Subject: [PATCH 058/154] test: illegal location create tests --- test/functional/nvt/fs/create/dir_spec.lua | 31 ++++++++++++++++----- test/functional/nvt/fs/create/file_spec.lua | 31 ++++++++++++++++++--- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index 894d257cd99..8466199056c 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -14,10 +14,6 @@ local it = t.it or it local screen --- TODO --- test creating in an illegal location e.g. /foo - - before_each(function() screen = nf.create_session({ ext_cmdline = true }) @@ -76,7 +72,6 @@ NvimTree_1 [-] [No Name] it("indirect ok", function() n.feed( ":NvimTreeOpen", - "gg", "a", "d1/indirect/" ) @@ -106,7 +101,6 @@ NvimTree_1 [-] [No Name] it("existing dir", function() n.feed( ":NvimTreeOpen", - "gg", "a", "d1/" ) @@ -130,7 +124,6 @@ NvimTree_1 [-] [No Name] it("existing file", function() n.feed( ":NvimTreeOpen", - "gg", "a", "d1/d1f1/" ) @@ -152,6 +145,30 @@ NvimTree_1 [-] [No Name] na.events_received({}) end) + + + it("invalid path", function() + n.feed( + ":NvimTreeOpen", + "a", + "", + "/foo/bar" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  f1 │~ | +~ │~ |*19 +NvimTree_1 [-] [No Name] | +[NvimTree] Could not create folder /foo | + ]], + }) + + na.events_received({}) + end) end) diff --git a/test/functional/nvt/fs/create/file_spec.lua b/test/functional/nvt/fs/create/file_spec.lua index b38604d8bd6..47e25eef7a1 100644 --- a/test/functional/nvt/fs/create/file_spec.lua +++ b/test/functional/nvt/fs/create/file_spec.lua @@ -14,10 +14,6 @@ local it = t.it or it local screen --- TODO --- test creating in an illegal location e.g. /foo - - before_each(function() screen = nf.create_session({ ext_cmdline = true }) @@ -186,6 +182,33 @@ NvimTree_1 [-] [No Name] { event_type = "FileCreated", payload = { fname = "/tmp/nvt_func/data/newdir/newfile", }, }, }) end) + + + it("invalid path", function() + n.feed( + ":NvimTreeOpen", + "a", + "", + "/foo" + ) + + -- TODO BUG this fails but shows message "/foo was properly created" +-- screen:expect({ +-- attr_ids = {}, +-- grid = [[ +-- ^/tmp/nvt_func/data/.. │ | +--   d1 │~ | +--  f1 │~ | +-- ~ │~ |*19 +-- NvimTree_1 [-] [No Name] | +-- [NvimTree] Could not create file /foo | +-- ]], +-- }) + + na.events_received({ + { event_type = "WillCreateFile", payload = { fname = "/foo", }, }, + }) + end) end) -- vim:colorcolumn=80 From 611591091c4adcca78627e60a92917480978037a Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 25 Sep 2026 12:57:51 +1000 Subject: [PATCH 059/154] test: lint/style --- .luacheckrc | 2 ++ test/functional/nvt/fixtures.lua | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.luacheckrc b/.luacheckrc index 82be35053f8..d3fd6056e26 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -19,6 +19,8 @@ M.globals = { "after_each", "teardown", "finally", + -- Global nvt functiontest data + "NVT_FUNCTEST_EVENTS", } return M diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index 89977be06fa..2a262936f4d 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -4,7 +4,7 @@ local Screen = require("test.functional.ui.screen") local M = {} ---@class (exact) nvt.functest.event ----@field event_type nvim_tree.api.events.Event [nvim_tree_events_kind] +---@field event_type string value of nvim_tree.api.events.Event ---@field payload table deep copy ---Create a new neovim session with @@ -35,7 +35,7 @@ end ---Subscribe to an event, to be recorded in session global NVT_FUNCTEST_EVENTS nvt.functest.event[] ---Assert events via events_received ----@param event_type nvim_tree.api.events.Event [nvim_tree_events_kind] +---@param event_type string value of nvim_tree.api.events.Event function M.event_subscribe(event_type) n.exec_lua(function() local api = require("nvim-tree.api") From ee7c259c51e69a41fc0e54000b452d2c3edd2fb6 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 25 Sep 2026 13:23:17 +1000 Subject: [PATCH 060/154] test: lint/style --- test/functional/nvt/fs/create/file_spec.lua | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/functional/nvt/fs/create/file_spec.lua b/test/functional/nvt/fs/create/file_spec.lua index 47e25eef7a1..ba927d543cf 100644 --- a/test/functional/nvt/fs/create/file_spec.lua +++ b/test/functional/nvt/fs/create/file_spec.lua @@ -193,17 +193,6 @@ NvimTree_1 [-] [No Name] ) -- TODO BUG this fails but shows message "/foo was properly created" --- screen:expect({ --- attr_ids = {}, --- grid = [[ --- ^/tmp/nvt_func/data/.. │ | ---   d1 │~ | ---  f1 │~ | --- ~ │~ |*19 --- NvimTree_1 [-] [No Name] | --- [NvimTree] Could not create file /foo | --- ]], --- }) na.events_received({ { event_type = "WillCreateFile", payload = { fname = "/foo", }, }, From f881f2771769c82b777d76d21a09a119565e95f2 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 25 Sep 2026 15:26:31 +1000 Subject: [PATCH 061/154] test: always teardown on functest failures to prevent luals picking up the linked test/src --- scripts/functionaltest.sh | 4 ++-- test/functional/nvt/fixtures.lua | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index a665b5d4a46..a069d76f969 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -190,10 +190,10 @@ setup case "${mode}" in l) - live + live || teardown ;; a|t) - files_test_execute + files_test_execute || teardown ;; *) ;; diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index 2a262936f4d..66a16227cfb 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -33,6 +33,8 @@ function M.create_session(options) return screen end +-- TODO consider always subscribing to all events + ---Subscribe to an event, to be recorded in session global NVT_FUNCTEST_EVENTS nvt.functest.event[] ---Assert events via events_received ---@param event_type string value of nvim_tree.api.events.Event From 3f63e58b85c7748f44c7256e06f92b48c24666db Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 28 Sep 2026 10:39:46 +1000 Subject: [PATCH 062/154] test: run all requested functests, exiting with number of failrues --- scripts/functionaltest.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index a069d76f969..11dac108f82 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -1,6 +1,7 @@ #!/usr/bin/env sh # neovim func test driver, see test/func/README.md +# exits with number of tests failed # this will be eventually be shipped as part of the vim runtime https://github.com/neovim/neovim/issues/34592 set -e @@ -25,6 +26,9 @@ files_test= # live data directory or "none" dir_live= +# number of test failures +failures=0 + # absolute path of the source: $dir_nvt export NVT_FUNC_DIR_ROOT="${dir_nvt}" @@ -167,7 +171,8 @@ live() { --cmd "comclear | mapclear | mapclear!" \ --cmd "set packpath^=${DIR_NVIM_SRC}/runtime/" \ --cmd "lua dofile('${DIR_NVIM_SRC}/runtime/colors/vim.lua')" \ - --cmd "unlet g:colors_name" + --cmd "unlet g:colors_name" \ + || failures=1 } files_test_execute() { @@ -177,7 +182,9 @@ files_test_execute() { # execute all tests for f in ${files_test}; do NVT_FUNC_DIR_TEST="$(realpath "$(dirname "${f}")")" - make functionaltest TEST_FILE="${f}" + + # don't exit on failure, just note it + make functionaltest TEST_FILE="${f}" || failures=$((failures + 1)) done } @@ -190,13 +197,15 @@ setup case "${mode}" in l) - live || teardown + live ;; a|t) - files_test_execute || teardown + files_test_execute ;; *) ;; esac teardown + +exit "${failures}" From d92b79bdafe7ae809848ed19e58515342bc926e5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 28 Sep 2026 10:41:52 +1000 Subject: [PATCH 063/154] test: inject test failures to test CI --- test/functional/nvt/api/tree/open_spec.lua | 2 +- test/functional/nvt/fs/create/file_spec.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/nvt/api/tree/open_spec.lua b/test/functional/nvt/api/tree/open_spec.lua index 9a68c5beaf0..5f598e852ed 100644 --- a/test/functional/nvt/api/tree/open_spec.lua +++ b/test/functional/nvt/api/tree/open_spec.lua @@ -73,7 +73,7 @@ NvimTree_1 [-] [No Name] -- TODO BUG NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode screen:expect({ grid = [[ -{NvimTreeSignColumn: }{NvimTreeRootFolderCL:^/tmp/nvt_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColun: }{NvimTreeRootFolderCL:^/tmp/nvt_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:dir1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:dir2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file1 }{NvimTreeWinSeparator:│}{1:~ }| diff --git a/test/functional/nvt/fs/create/file_spec.lua b/test/functional/nvt/fs/create/file_spec.lua index ba927d543cf..d845163b57e 100644 --- a/test/functional/nvt/fs/create/file_spec.lua +++ b/test/functional/nvt/fs/create/file_spec.lua @@ -137,7 +137,7 @@ NvimTree_1 [-] [No Name] screen:expect({ attr_ids = {}, grid = [[ - ^/tmp/nvt_func/data/.. │ | + ^/mp/nvt_func/data/.. │ |   d1 │~ |  f1 │~ | ~ │~ |*19 From 1e7cdc5d57dfc167b181b079e12ba25297119d6c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 28 Sep 2026 10:44:11 +1000 Subject: [PATCH 064/154] Revert "test: inject test failures to test CI" This reverts commit d92b79bdafe7ae809848ed19e58515342bc926e5. --- test/functional/nvt/api/tree/open_spec.lua | 2 +- test/functional/nvt/fs/create/file_spec.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/nvt/api/tree/open_spec.lua b/test/functional/nvt/api/tree/open_spec.lua index 5f598e852ed..9a68c5beaf0 100644 --- a/test/functional/nvt/api/tree/open_spec.lua +++ b/test/functional/nvt/api/tree/open_spec.lua @@ -73,7 +73,7 @@ NvimTree_1 [-] [No Name] -- TODO BUG NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode screen:expect({ grid = [[ -{NvimTreeSignColun: }{NvimTreeRootFolderCL:^/tmp/nvt_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColumn: }{NvimTreeRootFolderCL:^/tmp/nvt_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:dir1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:dir2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file1 }{NvimTreeWinSeparator:│}{1:~ }| diff --git a/test/functional/nvt/fs/create/file_spec.lua b/test/functional/nvt/fs/create/file_spec.lua index d845163b57e..ba927d543cf 100644 --- a/test/functional/nvt/fs/create/file_spec.lua +++ b/test/functional/nvt/fs/create/file_spec.lua @@ -137,7 +137,7 @@ NvimTree_1 [-] [No Name] screen:expect({ attr_ids = {}, grid = [[ - ^/mp/nvt_func/data/.. │ | + ^/tmp/nvt_func/data/.. │ |   d1 │~ |  f1 │~ | ~ │~ |*19 From ef2263bc29e949c85a9c2f18da7c74d88fbb0b83 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 28 Sep 2026 11:26:23 +1000 Subject: [PATCH 065/154] test: include nvim-tree source in test plumbing --- scripts/functionaltest.sh | 6 ++++++ scripts/luals-check.sh | 15 +++++++++------ test/functional/nvt/fixtures.lua | 4 +--- test/functional/nvt/fs/create/dir_spec.lua | 3 ++- test/functional/nvt/fs/create/file_spec.lua | 7 ++++--- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 11dac108f82..cbdd2b59845 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -140,6 +140,9 @@ setup() { ln -sv "${dir_nvt}/lua" "${dir_nvt_pack}" ln -sv "${dir_nvt}/plugin" "${dir_nvt_pack}" + # nvim-tree source, for use by tests + ln -sv "${dir_nvt}/lua/nvim-tree" "${DIR_NVIM_SRC}" + # tests ln -sv "${dir_nvt}/test/functional/nvt" "${DIR_NVIM_SRC}/test/functional" } @@ -152,6 +155,9 @@ teardown() { rm -fv "${dir_nvt_pack}/plugin" rm -rf "${dir_nvt_pack}" + # nvim-tree source, for use by tests + rm -fv "${DIR_NVIM_SRC}/nvim-tree" + # tests rm -fv "${DIR_NVIM_SRC}/test/functional/nvt" } diff --git a/scripts/luals-check.sh b/scripts/luals-check.sh index 2ecc8671df7..7ccd2b8b930 100755 --- a/scripts/luals-check.sh +++ b/scripts/luals-check.sh @@ -32,14 +32,18 @@ case "${1}" in ;; esac -# neovim source needed for tests +DIR_NVT="${PWD}" + if [ "${TARGET}" = "test" ]; then + # neovim and nvim-tree source needed for tests; check everything . scripts/check-nvim-src.sh export VIMRUNTIME="${DIR_NVIM_SRC}/runtime" + DIR_CHECK="${DIR_NVT}" +else + # otherwise just the source + DIR_CHECK="${DIR_NVT}/${TARGET}" fi -DIR_NVT="${PWD}" - if [ ! -f "${DIR_NVT}/scripts/luals-check.sh" ]; then echo "Must be run from nvim-tree root" 1>&2 exit 1 @@ -72,11 +76,10 @@ else cp "${DIR_NVT}/.luarc.json" "${LUARC}" fi -DIR_SRC="${DIR_NVT}/${TARGET}" FILE_OUT="${DIR_OUT}/out.${TARGET}.log" -echo "Checking ${TARGET}/" +echo "Checking ${TARGET}: ${DIR_CHECK} -> ${FILE_OUT}" -lua-language-server --check="${DIR_SRC}" --configpath="${LUARC}" --checklevel=Information --logpath="${DIR_OUT}" --loglevel=error 2>&1 | tee "${FILE_OUT}" +lua-language-server --check="${DIR_CHECK}" --configpath="${LUARC}" --checklevel=Information --logpath="${DIR_OUT}" --loglevel=error 2>&1 | tee "${FILE_OUT}" if ! grep --quiet "Diagnosis completed, no problems found" "${FILE_OUT}"; then RC=1 diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index 66a16227cfb..2f9951b2cd2 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -33,11 +33,9 @@ function M.create_session(options) return screen end --- TODO consider always subscribing to all events - ---Subscribe to an event, to be recorded in session global NVT_FUNCTEST_EVENTS nvt.functest.event[] ---Assert events via events_received ----@param event_type string value of nvim_tree.api.events.Event +---@param event_type nvim_tree.api.events.Event [nvim_tree_events_kind] function M.event_subscribe(event_type) n.exec_lua(function() local api = require("nvim-tree.api") diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/functional/nvt/fs/create/dir_spec.lua index 8466199056c..bc38c0b4046 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/functional/nvt/fs/create/dir_spec.lua @@ -21,7 +21,8 @@ before_each(function() require("nvim-tree").setup({}) end) - nf.event_subscribe("FolderCreated") + local Event = require("nvim-tree._meta.api.events").Event + nf.event_subscribe(Event.FolderCreated) end) diff --git a/test/functional/nvt/fs/create/file_spec.lua b/test/functional/nvt/fs/create/file_spec.lua index ba927d543cf..c87199b27e6 100644 --- a/test/functional/nvt/fs/create/file_spec.lua +++ b/test/functional/nvt/fs/create/file_spec.lua @@ -21,9 +21,10 @@ before_each(function() require("nvim-tree").setup({}) end) - nf.event_subscribe("FileCreated") - nf.event_subscribe("WillCreateFile") - nf.event_subscribe("FolderCreated") + local Event = require("nvim-tree._meta.api.events").Event + nf.event_subscribe(Event.FileCreated) + nf.event_subscribe(Event.WillCreateFile) + nf.event_subscribe(Event.FolderCreated) end) From 3c4d3feb2add4acd41973d1980615c3dc7ccfdb2 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 28 Sep 2026 12:17:34 +1000 Subject: [PATCH 066/154] test: use appearance source to simplify highlight groups --- test/functional/nvt/api/tree/open_spec.lua | 44 ++++++------ test/functional/nvt/fixtures.lua | 78 ++++++++++++---------- 2 files changed, 64 insertions(+), 58 deletions(-) diff --git a/test/functional/nvt/api/tree/open_spec.lua b/test/functional/nvt/api/tree/open_spec.lua index 9a68c5beaf0..2399ed393e2 100644 --- a/test/functional/nvt/api/tree/open_spec.lua +++ b/test/functional/nvt/api/tree/open_spec.lua @@ -24,7 +24,7 @@ describe("api_tree_open", function() require("nvim-tree").setup({}) end) - screen:add_extra_attr_ids(nf.simple_attr_ids()) + nf.unique_highlight_groups(screen) end) it("populated_unfocussed_text_only", function() @@ -85,27 +85,27 @@ NvimTree_1 [-] [No Name] }) end) - it("populated_unfocussed_hl_attrs", function() - exec_lua(function() - require("nvim-tree.api").tree.open() - end) - - n.feed("") - n.feed("") - - screen:expect({ - grid = [[ -{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 -{NvimTreeStatusLineNC:NvimTree_1 [-] }{3:[No Name] }| - | - ]], - }) - end) +-- it("populated_unfocussed_hl_attrs", function() +-- exec_lua(function() +-- require("nvim-tree.api").tree.open() +-- end) +-- +-- n.feed("") +-- n.feed("") +-- +-- screen:expect({ +-- grid = [[ +-- {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | +-- {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| +-- {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| +-- {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| +-- {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| +-- {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 +-- {NvimTreeStatusLineNC:NvimTree_1 [-] }{3:[No Name] }| +-- | +-- ]], +-- }) +-- end) end) -- vim:colorcolumn=80 diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index 2f9951b2cd2..00995aeba22 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -1,5 +1,6 @@ local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") +local appearance = require("nvim-tree.appearance") local M = {} @@ -49,52 +50,57 @@ function M.event_subscribe(event_type) end) end ---- Reset all NvimTree* highlight groups to just a unique foreground colour ---- Return attr_ids to match ---- Add a CL variant with the same background colour as NvimTreeCursorLine ---- May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order -function M.simple_attr_ids() - local attr_ids = {} +-- TODO events_clear - -- math.random(tonumber('0x707070'),tonumber('0x909090')) - local bg_rgb, bg_hex = 8758352, "#85a450" +---Reset all NvimTree* highlight groups to just a unique foreground colour +---Return attr_ids to match +---Add a CL variant with the same background colour as NvimTreeCursorLine +---May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order +---@param screen test.functional.ui.screen +function M.unique_highlight_groups(screen) + local attr_ids = {} - -- build the cursor line first, background only - attr_ids["NvimTreeCursorLine"] = { background = bg_rgb } - n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = bg_hex }) + -- arbitrary "unique" value: math.random(tonumber('0x707070'),tonumber('0x909090')) + local rgb_cl, hex_cl = 8758352, "#85a450" -- unique colour for each group, descending from #fefefe local i, r, g, b = 1, 254, 254, 254 local rgb, hex - for group, _ in pairs(n.api.nvim_get_hl(0, { create = false })) do - if group ~= "NvimTreeCursorLine" and group:match("^NvimTree.*") and not group:match(".*CL$") then - -- next unique fg colour - rgb = r * 256 * 256 + g * 256 + b - hex = string.format("#%x", rgb) - i = i + 1 - if (i % 256 == 0) then - b = 254 - g = 254 - r = r - 1 - elseif (i % 16 == 0) then - b = 254 - g = g - 1 - else - b = b - 1 - end - - -- add the group's concrete definition with fg only - attr_ids[group] = { foreground = rgb } - n.api.nvim_set_hl(0, group, { fg = hex }) - - -- create an NvimTreeCursorLine variant - attr_ids[group .. "CL"] = { foreground = rgb, background = bg_rgb } - n.api.nvim_set_hl(0, group .. "CL", { fg = hex, bg = bg_hex }) + -- build the cursor line first, background only + local hgs = vim.tbl_filter(function(hg) + if hg.group == "NvimTreeCursorLine" then + attr_ids["NvimTreeCursorLine"] = { background = rgb_cl } + n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = hex_cl }) + return false + else + return true end + end, appearance.HIGHLIGHT_GROUPS) + + for _, hg in ipairs(hgs) do + -- next unique fg colour + rgb = r * 256 * 256 + g * 256 + b + hex = string.format("#%x", rgb) + i = i + 1 + if (i % 256 == 0) then + b, g, r = 254, 254, r - 1 + elseif (i % 16 == 0) then + b, g = 254, g - 1 + else + b = b - 1 + end + + -- add the group's concrete definition with fg only + attr_ids[hg.group] = { foreground = rgb } + n.api.nvim_set_hl(0, hg.group, { fg = hex }) + + -- create an NvimTreeCursorLine variant + attr_ids[hg.group .. "CL"] = { foreground = rgb, background = rgb_cl } + n.api.nvim_set_hl(0, hg.group .. "CL", { fg = hex, bg = hex_cl }) end - return attr_ids + screen:add_extra_attr_ids(attr_ids) end return M From 9a94bb7eb3aece1333b3a1d50978d0f75daf30bd Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 28 Sep 2026 12:22:36 +1000 Subject: [PATCH 067/154] test: revert commented test --- test/functional/nvt/api/tree/open_spec.lua | 42 +++++++++++----------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/test/functional/nvt/api/tree/open_spec.lua b/test/functional/nvt/api/tree/open_spec.lua index 2399ed393e2..d1898ef1545 100644 --- a/test/functional/nvt/api/tree/open_spec.lua +++ b/test/functional/nvt/api/tree/open_spec.lua @@ -85,27 +85,27 @@ NvimTree_1 [-] [No Name] }) end) --- it("populated_unfocussed_hl_attrs", function() --- exec_lua(function() --- require("nvim-tree.api").tree.open() --- end) --- --- n.feed("") --- n.feed("") --- --- screen:expect({ --- grid = [[ --- {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | --- {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| --- {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| --- {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| --- {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| --- {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 --- {NvimTreeStatusLineNC:NvimTree_1 [-] }{3:[No Name] }| --- | --- ]], --- }) --- end) + it("populated_unfocussed_hl_attrs", function() + exec_lua(function() + require("nvim-tree.api").tree.open() + end) + + n.feed("") + n.feed("") + + screen:expect({ + grid = [[ +{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 +{NvimTreeStatusLineNC:NvimTree_1 [-] }{3:[No Name] }| + | + ]], + }) + end) end) -- vim:colorcolumn=80 From 464ab53d24de7a488657284b056e9c7e981e91c1 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 28 Sep 2026 12:52:37 +1000 Subject: [PATCH 068/154] test: add nvim-tree source to test lpath, remove links --- scripts/functionaltest.sh | 11 ++++------- test/functional/nvt/fixtures.lua | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index cbdd2b59845..6513c2f7435 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -29,6 +29,9 @@ dir_live= # number of test failures failures=0 +# add nvim-tree source to test environment so that tests themselves may access it +test_args="--lpath=${dir_nvt}/lua/?.lua --lpath=${dir_nvt}/lua/?/init.lua" + # absolute path of the source: $dir_nvt export NVT_FUNC_DIR_ROOT="${dir_nvt}" @@ -140,9 +143,6 @@ setup() { ln -sv "${dir_nvt}/lua" "${dir_nvt_pack}" ln -sv "${dir_nvt}/plugin" "${dir_nvt_pack}" - # nvim-tree source, for use by tests - ln -sv "${dir_nvt}/lua/nvim-tree" "${DIR_NVIM_SRC}" - # tests ln -sv "${dir_nvt}/test/functional/nvt" "${DIR_NVIM_SRC}/test/functional" } @@ -155,9 +155,6 @@ teardown() { rm -fv "${dir_nvt_pack}/plugin" rm -rf "${dir_nvt_pack}" - # nvim-tree source, for use by tests - rm -fv "${DIR_NVIM_SRC}/nvim-tree" - # tests rm -fv "${DIR_NVIM_SRC}/test/functional/nvt" } @@ -190,7 +187,7 @@ files_test_execute() { NVT_FUNC_DIR_TEST="$(realpath "$(dirname "${f}")")" # don't exit on failure, just note it - make functionaltest TEST_FILE="${f}" || failures=$((failures + 1)) + make functionaltest TEST_ARGS="${test_args}" TEST_FILE="${f}"|| failures=$((failures + 1)) done } diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index 00995aeba22..c2978a6638c 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -86,7 +86,7 @@ function M.unique_highlight_groups(screen) if (i % 256 == 0) then b, g, r = 254, 254, r - 1 elseif (i % 16 == 0) then - b, g = 254, g - 1 + b, g = 254, g - 1 else b = b - 1 end From c53ab9bde8eafb479682bdd41d48f7539550d5c8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 29 Sep 2026 10:50:13 +1000 Subject: [PATCH 069/154] test: func test runs from a single link under nvim src --- scripts/functionaltest.sh | 63 ++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 6513c2f7435..622f6b6a288 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -20,8 +20,12 @@ dir_nvt="${PWD}" # nvim-tree linked as a package under source dir_nvt_pack="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" -# test spec files to execute, relative to neovim source $DIR_NVIM_SRC -files_test= +# nvim-tree linked under the neovim source: under src (not test) to prevent luals from finding it +# this is necessary so that the test may be found relative to test startup directory build/Xtest_xdg, which contains only links to runtime, src and test +dir_nvt_linked="${DIR_NVIM_SRC}/src/nvt" + +# test spec files to execute, relative to $dir_nvt +files_test_lua= # live data directory or "none" dir_live= @@ -29,8 +33,8 @@ dir_live= # number of test failures failures=0 -# add nvim-tree source to test environment so that tests themselves may access it -test_args="--lpath=${dir_nvt}/lua/?.lua --lpath=${dir_nvt}/lua/?/init.lua" +# add absolute paths of linked nvim-tree source to test environment so that tests themselves may access it +test_args="--lpath=${dir_nvt_linked}/?.lua --lpath=${dir_nvt_linked}/lua/?.lua --lpath=${dir_nvt_linked}/lua/?/init.lua" # absolute path of the source: $dir_nvt export NVT_FUNC_DIR_ROOT="${dir_nvt}" @@ -64,21 +68,21 @@ mode_set() { mode="${1}" } -# add a single file $1 or all _spec.lua files under directory $1 to $files_test -files_test_add() { +# add a single file $1 or all _spec.lua files under directory $1 to $files_test_lua +files_test_lua_add() { if [ -f "${1}" ]; then - files_test="${files_test} ${1}" + files_test_lua="${files_test_lua} ${1}" elif [ -d "${1}" ]; then - find "${1}" -type f -iname '*_spec.lua' > /tmp/nvt_files_test + find "${1}" -type f -iname '*_spec.lua' > /tmp/nvt_files_test_lua while IFS= read -r f; do - files_test="${files_test} ${f}" - done < /tmp/nvt_files_test - rm /tmp/nvt_files_test + files_test_lua="${files_test_lua} ${f}" + done < /tmp/nvt_files_test_lua + rm /tmp/nvt_files_test_lua else echo "${1} inexistent" >&2 exit 1 fi - if [ -z "${files_test}" ]; then + if [ -z "${files_test_lua}" ]; then echo "no tests found in ${1}" >&2 exit 1 fi @@ -105,7 +109,7 @@ while getopts "ahlt:" o; do case "${o}" in a) mode_set "${o}" - files_test_add "test/functional/nvt" + files_test_lua_add "test/functional/nvt" ;; h) usage @@ -118,7 +122,7 @@ while getopts "ahlt:" o; do ;; t) mode_set "${o}" - files_test_add "${OPTARG}" + files_test_lua_add "${OPTARG}" ;; *) usage >&2 @@ -137,14 +141,17 @@ fi # before all tests: links plugin and tests in their appropriate places under neovim source setup() { + teardown + + # complete nvim-tree source + ln -sv "${dir_nvt}" "${dir_nvt_linked}" + + # TODO can we relocate this to a distinct packpath? # plugin runtime package mkdir -pv "${dir_nvt_pack}" ln -sv "${dir_nvt}/doc" "${dir_nvt_pack}" ln -sv "${dir_nvt}/lua" "${dir_nvt_pack}" ln -sv "${dir_nvt}/plugin" "${dir_nvt_pack}" - - # tests - ln -sv "${dir_nvt}/test/functional/nvt" "${DIR_NVIM_SRC}/test/functional" } # after all tests: remove plugin and test links from neovim source @@ -155,10 +162,11 @@ teardown() { rm -fv "${dir_nvt_pack}/plugin" rm -rf "${dir_nvt_pack}" - # tests - rm -fv "${DIR_NVIM_SRC}/test/functional/nvt" + # complete nvim-tree source + rm -fv "${dir_nvt_linked}" } +# TODO could this completely bypass setup? live() { if [ "${dir_live}" != "none" ]; then NVT_FUNC_DIR_TEST="$(realpath "$(dirname "${dir_live}")")" @@ -168,7 +176,7 @@ live() { nvim \ --clean \ --noplugin \ - -u "${DIR_NVIM_SRC}/test/functional/nvt/init_live.lua" \ + -u "test/functional/nvt/init_live.lua" \ -i NONE \ --cmd "set shortmess+=IS background=light noswapfile noautoindent startofline laststatus=1 undodir=. directory=. viewdir=. backupdir=. belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}" \ --cmd "comclear | mapclear | mapclear!" \ @@ -178,23 +186,24 @@ live() { || failures=1 } -files_test_execute() { +files_test_lua_execute() { # cmake must be run from nvim source root cd "${DIR_NVIM_SRC}" - # execute all tests - for f in ${files_test}; do - NVT_FUNC_DIR_TEST="$(realpath "$(dirname "${f}")")" + # execute all requested tests + for f in ${files_test_lua}; do + file_test_lua="${dir_nvt_linked}/${f}" + + NVT_FUNC_DIR_TEST="$(dirname "${file_test_lua}")" # don't exit on failure, just note it - make functionaltest TEST_ARGS="${test_args}" TEST_FILE="${f}"|| failures=$((failures + 1)) + make functionaltest TEST_ARGS="${test_args}" TEST_FILE="${file_test_lua}" || failures=$((failures + 1)) done } # # act # -teardown setup @@ -203,7 +212,7 @@ case "${mode}" in live ;; a|t) - files_test_execute + files_test_lua_execute ;; *) ;; From 8720dc41196d33f78ceba61d150fdea0a5c1ab02 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 29 Sep 2026 12:39:18 +1000 Subject: [PATCH 070/154] test: func test package is the nvim-tree source link itself --- scripts/functionaltest.sh | 85 ++++++++++++++------------------ test/functional/nvt/fixtures.lua | 8 ++- 2 files changed, 44 insertions(+), 49 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 622f6b6a288..7ec226ceb52 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -# neovim func test driver, see test/func/README.md +# Nvim func test driver, see test/func/README.md # exits with number of tests failed # this will be eventually be shipped as part of the vim runtime https://github.com/neovim/neovim/issues/34592 @@ -17,31 +17,30 @@ fi # root of code under test dir_nvt="${PWD}" -# nvim-tree linked as a package under source -dir_nvt_pack="${DIR_NVIM_SRC}/runtime/pack/dist/opt/nvim-tree.lua" +# parent directory under which nvim-tree is linked under Nvim source +# uses src (not test or runtime) to prevent luals from finding it +# src can be found in build/Xtest_xdg, which contains only links to runtime, src and test +# pack/dist/opt is added underneath to satisfy :packadd convention +export NVT_FUNC_PACKPATH="${DIR_NVIM_SRC}/src/nvt" -# nvim-tree linked under the neovim source: under src (not test) to prevent luals from finding it -# this is necessary so that the test may be found relative to test startup directory build/Xtest_xdg, which contains only links to runtime, src and test -dir_nvt_linked="${DIR_NVIM_SRC}/src/nvt" +# absolute link to nvim-tree source root under Nvim source +export NVT_FUNC_DIR_ROOT="${NVT_FUNC_PACKPATH}/pack/dist/opt/nvim-tree.lua" -# test spec files to execute, relative to $dir_nvt +# absolute path of the test directory under Nvim source +export NVT_FUNC_DIR_TEST= + +# absolute path of script to execute to setup the test execution directory +export NVT_FUNC_SCRIPT_CREATE_TEST_CWD="${NVT_FUNC_DIR_ROOT}/test/functional/nvt/create_test_cwd.sh" + +# absolute paths of test spec files to execute, under Nvim source files_test_lua= -# live data directory or "none" +# live data directory or "none", empty when -l not specified dir_live= # number of test failures failures=0 -# add absolute paths of linked nvim-tree source to test environment so that tests themselves may access it -test_args="--lpath=${dir_nvt_linked}/?.lua --lpath=${dir_nvt_linked}/lua/?.lua --lpath=${dir_nvt_linked}/lua/?/init.lua" - -# absolute path of the source: $dir_nvt -export NVT_FUNC_DIR_ROOT="${dir_nvt}" - -# absolute path of the test directory, under $dir_nvt -export NVT_FUNC_DIR_TEST= - # a, t or l mode= @@ -56,7 +55,7 @@ usage() { } # -# setup +# CLI args # # set $mode to $1, fail if another $mode already set @@ -71,11 +70,11 @@ mode_set() { # add a single file $1 or all _spec.lua files under directory $1 to $files_test_lua files_test_lua_add() { if [ -f "${1}" ]; then - files_test_lua="${files_test_lua} ${1}" + files_test_lua="${files_test_lua} ${NVT_FUNC_DIR_ROOT}/${1}" elif [ -d "${1}" ]; then find "${1}" -type f -iname '*_spec.lua' > /tmp/nvt_files_test_lua while IFS= read -r f; do - files_test_lua="${files_test_lua} ${f}" + files_test_lua="${files_test_lua} ${NVT_FUNC_DIR_ROOT}/${f}" done < /tmp/nvt_files_test_lua rm /tmp/nvt_files_test_lua else @@ -139,37 +138,25 @@ fi # test harness # -# before all tests: links plugin and tests in their appropriate places under neovim source +# before all tests: links plugin and tests in their appropriate places under Nvim source root setup() { teardown - # complete nvim-tree source - ln -sv "${dir_nvt}" "${dir_nvt_linked}" - - # TODO can we relocate this to a distinct packpath? - # plugin runtime package - mkdir -pv "${dir_nvt_pack}" - ln -sv "${dir_nvt}/doc" "${dir_nvt_pack}" - ln -sv "${dir_nvt}/lua" "${dir_nvt_pack}" - ln -sv "${dir_nvt}/plugin" "${dir_nvt_pack}" + # nvim-tree source link + mkdir -p "$(dirname "${NVT_FUNC_DIR_ROOT}")" + ln -sv "${dir_nvt}" "${NVT_FUNC_DIR_ROOT}" } -# after all tests: remove plugin and test links from neovim source +# after all tests: remove plugin and test links from Nvim source root teardown() { - # plugin runtime package - rm -fv "${dir_nvt_pack}/doc" - rm -fv "${dir_nvt_pack}/lua" - rm -fv "${dir_nvt_pack}/plugin" - rm -rf "${dir_nvt_pack}" - - # complete nvim-tree source - rm -fv "${dir_nvt_linked}" + # nvim-tree source link + rm -fv "${NVT_FUNC_DIR_ROOT}" } # TODO could this completely bypass setup? live() { if [ "${dir_live}" != "none" ]; then - NVT_FUNC_DIR_TEST="$(realpath "$(dirname "${dir_live}")")" + export NVT_FUNC_DIR_TEST="$(realpath "$(dirname "${dir_live}")")" fi # options extracted from testnvim.lua nvim_argv, nvim_set @@ -186,23 +173,25 @@ live() { || failures=1 } -files_test_lua_execute() { +run_tests() { # cmake must be run from nvim source root cd "${DIR_NVIM_SRC}" # execute all requested tests for f in ${files_test_lua}; do - file_test_lua="${dir_nvt_linked}/${f}" - - NVT_FUNC_DIR_TEST="$(dirname "${file_test_lua}")" + export NVT_FUNC_DIR_TEST="$(dirname "${f}")" + # append nvim-tree lua/test to package.path, so that tests themselves may access nvim-tree source # don't exit on failure, just note it - make functionaltest TEST_ARGS="${test_args}" TEST_FILE="${file_test_lua}" || failures=$((failures + 1)) - done + make functionaltest \ + TEST_FILE="${f}" \ + TEST_ARGS="--lpath=${NVT_FUNC_DIR_ROOT}/?.lua --lpath=${NVT_FUNC_DIR_ROOT}/lua/?.lua --lpath=${NVT_FUNC_DIR_ROOT}/lua/?/init.lua" \ + || failures=$((failures + 1)) + done } # -# act +# execute # setup @@ -212,7 +201,7 @@ case "${mode}" in live ;; a|t) - files_test_lua_execute + run_tests ;; *) ;; diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index c2978a6638c..20c5d84c695 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -19,6 +19,10 @@ function M.create_session(options) local screen = Screen.new(80, 24, options) n.exec_lua(function() + local packpath = os.getenv("NVT_FUNC_PACKPATH") + assert(packpath, "NVT_FUNC_PACKPATH not set") + vim.opt.packpath:append(packpath) + vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) ---@type nvt.functest.event[] @@ -26,7 +30,9 @@ function M.create_session(options) end) -- TODO neovim 0.13: replace with vim.system calls; vim.system is not currenctly available in neovim 0.12 func tests - local out = n.fn.system({ os.getenv("NVT_FUNC_DIR_ROOT") .. "/test/functional/nvt/create_test_cwd.sh" }) + local create_test_cwd = os.getenv("NVT_FUNC_SCRIPT_CREATE_TEST_CWD") + assert(create_test_cwd, "NVT_FUNC_SCRIPT_CREATE_TEST_CWD not set") + local out = n.fn.system({ create_test_cwd, }) local dir = out:match("^DIR=(.*)$") or error(out) n.api.nvim_set_current_dir(dir) From b1e088bcff550b86ecb29a1fbfde8e65d77cd7c9 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 29 Sep 2026 12:53:06 +1000 Subject: [PATCH 071/154] test: func test package is the nvim-tree source link itself --- scripts/functionaltest.sh | 15 ++++++--------- test/functional/nvt/fixtures.lua | 9 ++------- test/functional/nvt/init_live.lua | 9 ++++----- 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 7ec226ceb52..0a04f1625d3 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -14,9 +14,6 @@ fi # define $DIR_NVIM_SRC . scripts/check-nvim-src.sh -# root of code under test -dir_nvt="${PWD}" - # parent directory under which nvim-tree is linked under Nvim source # uses src (not test or runtime) to prevent luals from finding it # src can be found in build/Xtest_xdg, which contains only links to runtime, src and test @@ -26,7 +23,7 @@ export NVT_FUNC_PACKPATH="${DIR_NVIM_SRC}/src/nvt" # absolute link to nvim-tree source root under Nvim source export NVT_FUNC_DIR_ROOT="${NVT_FUNC_PACKPATH}/pack/dist/opt/nvim-tree.lua" -# absolute path of the test directory under Nvim source +# absolute path of the test's directory under Nvim source export NVT_FUNC_DIR_TEST= # absolute path of script to execute to setup the test execution directory @@ -144,7 +141,7 @@ setup() { # nvim-tree source link mkdir -p "$(dirname "${NVT_FUNC_DIR_ROOT}")" - ln -sv "${dir_nvt}" "${NVT_FUNC_DIR_ROOT}" + ln -sv "${PWD}" "${NVT_FUNC_DIR_ROOT}" } # after all tests: remove plugin and test links from Nvim source root @@ -153,10 +150,9 @@ teardown() { rm -fv "${NVT_FUNC_DIR_ROOT}" } -# TODO could this completely bypass setup? live() { if [ "${dir_live}" != "none" ]; then - export NVT_FUNC_DIR_TEST="$(realpath "$(dirname "${dir_live}")")" + NVT_FUNC_DIR_TEST="$(dirname "${dir_live}")" fi # options extracted from testnvim.lua nvim_argv, nvim_set @@ -167,9 +163,10 @@ live() { -i NONE \ --cmd "set shortmess+=IS background=light noswapfile noautoindent startofline laststatus=1 undodir=. directory=. viewdir=. backupdir=. belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}" \ --cmd "comclear | mapclear | mapclear!" \ - --cmd "set packpath^=${DIR_NVIM_SRC}/runtime/" \ + --cmd "set packpath^=${NVT_FUNC_PACKPATH}" \ --cmd "lua dofile('${DIR_NVIM_SRC}/runtime/colors/vim.lua')" \ --cmd "unlet g:colors_name" \ + --cmd "packadd nvim-tree.lua" \ || failures=1 } @@ -179,7 +176,7 @@ run_tests() { # execute all requested tests for f in ${files_test_lua}; do - export NVT_FUNC_DIR_TEST="$(dirname "${f}")" + NVT_FUNC_DIR_TEST="$(dirname "${f}")" # append nvim-tree lua/test to package.path, so that tests themselves may access nvim-tree source # don't exit on failure, just note it diff --git a/test/functional/nvt/fixtures.lua b/test/functional/nvt/fixtures.lua index 20c5d84c695..5948ccfc8cc 100644 --- a/test/functional/nvt/fixtures.lua +++ b/test/functional/nvt/fixtures.lua @@ -19,10 +19,7 @@ function M.create_session(options) local screen = Screen.new(80, 24, options) n.exec_lua(function() - local packpath = os.getenv("NVT_FUNC_PACKPATH") - assert(packpath, "NVT_FUNC_PACKPATH not set") - vim.opt.packpath:append(packpath) - + vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH")) vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) ---@type nvt.functest.event[] @@ -30,9 +27,7 @@ function M.create_session(options) end) -- TODO neovim 0.13: replace with vim.system calls; vim.system is not currenctly available in neovim 0.12 func tests - local create_test_cwd = os.getenv("NVT_FUNC_SCRIPT_CREATE_TEST_CWD") - assert(create_test_cwd, "NVT_FUNC_SCRIPT_CREATE_TEST_CWD not set") - local out = n.fn.system({ create_test_cwd, }) + local out = n.fn.system({ os.getenv("NVT_FUNC_SCRIPT_CREATE_TEST_CWD"), }) local dir = out:match("^DIR=(.*)$") or error(out) n.api.nvim_set_current_dir(dir) diff --git a/test/functional/nvt/init_live.lua b/test/functional/nvt/init_live.lua index d5d10b1593a..e0b5aa21e3b 100644 --- a/test/functional/nvt/init_live.lua +++ b/test/functional/nvt/init_live.lua @@ -71,15 +71,14 @@ screen_resize() -- use dark background for readability under dark and light vim.o.background = "dark" --- add the plugin under test -vim.api.nvim_command("packadd nvim-tree.lua") -require("nvim-tree").setup({}) - -- create and change to the directory the test will execute from -local out = vim.fn.system({ os.getenv("NVT_FUNC_DIR_ROOT") .. "/test/functional/nvt/create_test_cwd.sh" }) +local out = vim.fn.system({ os.getenv("NVT_FUNC_SCRIPT_CREATE_TEST_CWD") }) local dir = out:match("^DIR=(.*)$") or error(out) vim.api.nvim_set_current_dir(dir) +-- setup with defaults +require("nvim-tree").setup({}) + -- mappings vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) vim.keymap.set("n", "c", function() live_dump(true) end, { remap = false, }) From febbaf1be3704ec9f659e08a69f2bbfbcf526793 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 29 Sep 2026 13:00:46 +1000 Subject: [PATCH 072/154] test: proper namespace for nvt tests --- scripts/functionaltest.sh | 8 ++++---- test/{functional/nvt => nvt/func}/README.md | 0 .../nvt => nvt/func}/api/tree/data/dir1/dir1file1 | 0 .../nvt => nvt/func}/api/tree/data/dir2/dir2file1 | 0 test/{functional/nvt => nvt/func}/api/tree/data/file1 | 0 test/{functional/nvt => nvt/func}/api/tree/data/file2 | 0 test/{functional/nvt => nvt/func}/api/tree/open_spec.lua | 2 +- test/{functional/nvt => nvt/func}/asserts.lua | 0 test/{functional/nvt => nvt/func}/create_test_cwd.sh | 0 test/{functional/nvt => nvt/func}/fixtures.lua | 0 test/{functional/nvt => nvt/func}/fs/create/data/d1/d1f1 | 0 test/{functional/nvt => nvt/func}/fs/create/data/f1 | 0 test/{functional/nvt => nvt/func}/fs/create/dir_spec.lua | 4 ++-- test/{functional/nvt => nvt/func}/fs/create/file_spec.lua | 4 ++-- test/{functional/nvt => nvt/func}/init_live.lua | 0 test/{functional/nvt => nvt/func}/map/node/data/d1/f1 | 0 test/{functional/nvt => nvt/func}/map/node/data/d1/f2 | 0 test/{functional/nvt => nvt/func}/map/node/data/d2/f1 | 0 test/{functional/nvt => nvt/func}/map/node/data/f1 | 0 test/{functional/nvt => nvt/func}/map/node/data/f2 | 0 test/{functional/nvt => nvt/func}/map/node/open_spec.lua | 2 +- 21 files changed, 10 insertions(+), 10 deletions(-) rename test/{functional/nvt => nvt/func}/README.md (100%) rename test/{functional/nvt => nvt/func}/api/tree/data/dir1/dir1file1 (100%) rename test/{functional/nvt => nvt/func}/api/tree/data/dir2/dir2file1 (100%) rename test/{functional/nvt => nvt/func}/api/tree/data/file1 (100%) rename test/{functional/nvt => nvt/func}/api/tree/data/file2 (100%) rename test/{functional/nvt => nvt/func}/api/tree/open_spec.lua (99%) rename test/{functional/nvt => nvt/func}/asserts.lua (100%) rename test/{functional/nvt => nvt/func}/create_test_cwd.sh (100%) rename test/{functional/nvt => nvt/func}/fixtures.lua (100%) rename test/{functional/nvt => nvt/func}/fs/create/data/d1/d1f1 (100%) rename test/{functional/nvt => nvt/func}/fs/create/data/f1 (100%) rename test/{functional/nvt => nvt/func}/fs/create/dir_spec.lua (98%) rename test/{functional/nvt => nvt/func}/fs/create/file_spec.lua (98%) rename test/{functional/nvt => nvt/func}/init_live.lua (100%) rename test/{functional/nvt => nvt/func}/map/node/data/d1/f1 (100%) rename test/{functional/nvt => nvt/func}/map/node/data/d1/f2 (100%) rename test/{functional/nvt => nvt/func}/map/node/data/d2/f1 (100%) rename test/{functional/nvt => nvt/func}/map/node/data/f1 (100%) rename test/{functional/nvt => nvt/func}/map/node/data/f2 (100%) rename test/{functional/nvt => nvt/func}/map/node/open_spec.lua (99%) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 0a04f1625d3..5bdc424cd9f 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -6,7 +6,7 @@ set -e -if [ ! -d "test/functional/nvt" ]; then +if [ ! -d "test/nvt/func" ]; then echo "Must be run from nvim-tree root" 1>&2 exit 1 fi @@ -27,7 +27,7 @@ export NVT_FUNC_DIR_ROOT="${NVT_FUNC_PACKPATH}/pack/dist/opt/nvim-tree.lua" export NVT_FUNC_DIR_TEST= # absolute path of script to execute to setup the test execution directory -export NVT_FUNC_SCRIPT_CREATE_TEST_CWD="${NVT_FUNC_DIR_ROOT}/test/functional/nvt/create_test_cwd.sh" +export NVT_FUNC_SCRIPT_CREATE_TEST_CWD="${NVT_FUNC_DIR_ROOT}/test/nvt/func/create_test_cwd.sh" # absolute paths of test spec files to execute, under Nvim source files_test_lua= @@ -105,7 +105,7 @@ while getopts "ahlt:" o; do case "${o}" in a) mode_set "${o}" - files_test_lua_add "test/functional/nvt" + files_test_lua_add "test/nvt/func" ;; h) usage @@ -159,7 +159,7 @@ live() { nvim \ --clean \ --noplugin \ - -u "test/functional/nvt/init_live.lua" \ + -u "test/nvt/func/init_live.lua" \ -i NONE \ --cmd "set shortmess+=IS background=light noswapfile noautoindent startofline laststatus=1 undodir=. directory=. viewdir=. backupdir=. belloff= wildoptions-=pum joinspaces noshowcmd noruler nomore redrawdebug=invalid shada=!,'100,<50,s10,h statusline=%<%f\ %{%nvim_eval_statusline('%h%w%m%r',\ {'maxwidth':\ 30}).width\ >\ 0\ ?\ '%h%w%m%r\ '\ :\ ''%}%=%{%\ &showcmdloc\ ==\ 'statusline'\ ?\ '%-10.S\ '\ :\ ''\ %}%{%\ exists('b:keymap_name')\ ?\ '<'..b:keymap_name..'>\ '\ :\ ''\ %}%{%\ &ruler\ ?\ (\ &rulerformat\ ==\ ''\ ?\ '%-14.(%l,%c%V%)\ %P'\ :\ &rulerformat\ )\ :\ ''\ %}" \ --cmd "comclear | mapclear | mapclear!" \ diff --git a/test/functional/nvt/README.md b/test/nvt/func/README.md similarity index 100% rename from test/functional/nvt/README.md rename to test/nvt/func/README.md diff --git a/test/functional/nvt/api/tree/data/dir1/dir1file1 b/test/nvt/func/api/tree/data/dir1/dir1file1 similarity index 100% rename from test/functional/nvt/api/tree/data/dir1/dir1file1 rename to test/nvt/func/api/tree/data/dir1/dir1file1 diff --git a/test/functional/nvt/api/tree/data/dir2/dir2file1 b/test/nvt/func/api/tree/data/dir2/dir2file1 similarity index 100% rename from test/functional/nvt/api/tree/data/dir2/dir2file1 rename to test/nvt/func/api/tree/data/dir2/dir2file1 diff --git a/test/functional/nvt/api/tree/data/file1 b/test/nvt/func/api/tree/data/file1 similarity index 100% rename from test/functional/nvt/api/tree/data/file1 rename to test/nvt/func/api/tree/data/file1 diff --git a/test/functional/nvt/api/tree/data/file2 b/test/nvt/func/api/tree/data/file2 similarity index 100% rename from test/functional/nvt/api/tree/data/file2 rename to test/nvt/func/api/tree/data/file2 diff --git a/test/functional/nvt/api/tree/open_spec.lua b/test/nvt/func/api/tree/open_spec.lua similarity index 99% rename from test/functional/nvt/api/tree/open_spec.lua rename to test/nvt/func/api/tree/open_spec.lua index d1898ef1545..2a176c477c0 100644 --- a/test/functional/nvt/api/tree/open_spec.lua +++ b/test/nvt/func/api/tree/open_spec.lua @@ -1,5 +1,5 @@ local t = require("test.testutil") -local nf = require("test.functional.nvt.fixtures") +local nf = require("test.nvt.func.fixtures") local n = require("test.functional.testnvim")() local exec_lua = n.exec_lua diff --git a/test/functional/nvt/asserts.lua b/test/nvt/func/asserts.lua similarity index 100% rename from test/functional/nvt/asserts.lua rename to test/nvt/func/asserts.lua diff --git a/test/functional/nvt/create_test_cwd.sh b/test/nvt/func/create_test_cwd.sh similarity index 100% rename from test/functional/nvt/create_test_cwd.sh rename to test/nvt/func/create_test_cwd.sh diff --git a/test/functional/nvt/fixtures.lua b/test/nvt/func/fixtures.lua similarity index 100% rename from test/functional/nvt/fixtures.lua rename to test/nvt/func/fixtures.lua diff --git a/test/functional/nvt/fs/create/data/d1/d1f1 b/test/nvt/func/fs/create/data/d1/d1f1 similarity index 100% rename from test/functional/nvt/fs/create/data/d1/d1f1 rename to test/nvt/func/fs/create/data/d1/d1f1 diff --git a/test/functional/nvt/fs/create/data/f1 b/test/nvt/func/fs/create/data/f1 similarity index 100% rename from test/functional/nvt/fs/create/data/f1 rename to test/nvt/func/fs/create/data/f1 diff --git a/test/functional/nvt/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua similarity index 98% rename from test/functional/nvt/fs/create/dir_spec.lua rename to test/nvt/func/fs/create/dir_spec.lua index bc38c0b4046..30ac7448333 100644 --- a/test/functional/nvt/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -1,6 +1,6 @@ local t = require("test.testutil") -local nf = require("test.functional.nvt.fixtures") -local na = require("test.functional.nvt.asserts") +local nf = require("test.nvt.func.fixtures") +local na = require("test.nvt.func.asserts") local n = require("test.functional.testnvim")() -- 0.13 global compatibility diff --git a/test/functional/nvt/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua similarity index 98% rename from test/functional/nvt/fs/create/file_spec.lua rename to test/nvt/func/fs/create/file_spec.lua index c87199b27e6..bd080692557 100644 --- a/test/functional/nvt/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -1,6 +1,6 @@ local t = require("test.testutil") -local nf = require("test.functional.nvt.fixtures") -local na = require("test.functional.nvt.asserts") +local nf = require("test.nvt.func.fixtures") +local na = require("test.nvt.func.asserts") local n = require("test.functional.testnvim")() -- 0.13 global compatibility diff --git a/test/functional/nvt/init_live.lua b/test/nvt/func/init_live.lua similarity index 100% rename from test/functional/nvt/init_live.lua rename to test/nvt/func/init_live.lua diff --git a/test/functional/nvt/map/node/data/d1/f1 b/test/nvt/func/map/node/data/d1/f1 similarity index 100% rename from test/functional/nvt/map/node/data/d1/f1 rename to test/nvt/func/map/node/data/d1/f1 diff --git a/test/functional/nvt/map/node/data/d1/f2 b/test/nvt/func/map/node/data/d1/f2 similarity index 100% rename from test/functional/nvt/map/node/data/d1/f2 rename to test/nvt/func/map/node/data/d1/f2 diff --git a/test/functional/nvt/map/node/data/d2/f1 b/test/nvt/func/map/node/data/d2/f1 similarity index 100% rename from test/functional/nvt/map/node/data/d2/f1 rename to test/nvt/func/map/node/data/d2/f1 diff --git a/test/functional/nvt/map/node/data/f1 b/test/nvt/func/map/node/data/f1 similarity index 100% rename from test/functional/nvt/map/node/data/f1 rename to test/nvt/func/map/node/data/f1 diff --git a/test/functional/nvt/map/node/data/f2 b/test/nvt/func/map/node/data/f2 similarity index 100% rename from test/functional/nvt/map/node/data/f2 rename to test/nvt/func/map/node/data/f2 diff --git a/test/functional/nvt/map/node/open_spec.lua b/test/nvt/func/map/node/open_spec.lua similarity index 99% rename from test/functional/nvt/map/node/open_spec.lua rename to test/nvt/func/map/node/open_spec.lua index 9d13dcdbed0..9b92e1ace33 100644 --- a/test/functional/nvt/map/node/open_spec.lua +++ b/test/nvt/func/map/node/open_spec.lua @@ -1,5 +1,5 @@ local t = require("test.testutil") -local nf = require("test.functional.nvt.fixtures") +local nf = require("test.nvt.func.fixtures") local n = require("test.functional.testnvim")() local exec_lua = n.exec_lua From 600151846177fde283cf5f1e256898c0967ffcd6 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 29 Sep 2026 13:04:40 +1000 Subject: [PATCH 073/154] test: proper namespace for nvt tests --- test/nvt/func/fixtures.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index 5948ccfc8cc..49515b4e26c 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -19,7 +19,7 @@ function M.create_session(options) local screen = Screen.new(80, 24, options) n.exec_lua(function() - vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH")) + vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH") or "") vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) ---@type nvt.functest.event[] From a70586ec1de10a168e69654298b0f81b898f191e Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 29 Sep 2026 13:17:10 +1000 Subject: [PATCH 074/154] test: add events_clear --- test/nvt/func/fixtures.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index 49515b4e26c..4252c31a1b2 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -51,7 +51,12 @@ function M.event_subscribe(event_type) end) end --- TODO events_clear +---Clear all recorded events in NVT_FUNCTEST_EVENTS +function M.events_clear() + n.exec_lua(function() + NVT_FUNCTEST_EVENTS = {} ---@diagnostic disable-line: global-element + end) +end ---Reset all NvimTree* highlight groups to just a unique foreground colour ---Return attr_ids to match From 0e48695908a2e18bae9b7677fb808f000c5e0dc2 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 10:30:24 +1000 Subject: [PATCH 075/154] test: more fs.create.dir tests --- test/nvt/func/fs/create/dir_spec.lua | 68 ++++++++++++++++++++++++++- test/nvt/func/fs/create/file_spec.lua | 2 +- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 30ac7448333..4e196c90425 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -27,15 +27,79 @@ end) describe("prompt", function() - it("ok", function() + it("tree focused", function() n.feed( ":NvimTreeOpen", + "", "a" ) screen:expect({ mode = "cmdline_normal", - cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, + }) + end) + + + it("tree not focused", function() + n.feed( + ":NvimTreeOpen", + "", + "", + ":lua require('nvim-tree.api').fs.create()" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, + }) + end) +end) + + +describe("existing", function() + it("nop", function() + n.feed( + ":NvimTreeOpen", + "", + "a", + "" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | + ^  d1 │~ | +  f1 │~ | +~ │~ |*19 +NvimTree_1 [-] [No Name] | + | + ]], + }) + end) +end) + + +describe("cancelled", function() + it("nop", function() + n.feed( + ":NvimTreeOpen", + "a", + "foo", + "" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  f1 │~ | +~ │~ |*19 +NvimTree_1 [-] [No Name] | + | + ]], }) end) end) diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index bd080692557..aff6af6205d 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -29,7 +29,7 @@ end) describe("prompt", function() - it("ok", function() + it("tree focused", function() n.feed( ":NvimTreeOpen", "a" From c7b6e29e746babd189e83d3a826da6a75461ecaa Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 10:48:24 +1000 Subject: [PATCH 076/154] test: functionaltest.sh -l operates on any file or dir, finding data if present --- scripts/functionaltest.sh | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 5bdc424cd9f..944b51889f8 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -42,7 +42,7 @@ failures=0 mode= usage() { - echo "Usage: ${0} [-a] [-h] [-t ] [-l []]" + echo "Usage: ${0} [-a] [-h] [-t ] [-l []]" echo echo " OPTION:" echo " -a Execute all tests" @@ -84,20 +84,21 @@ files_test_lua_add() { fi } -# set $dir_live to directory or "none" +# set $dir_live to "none" when not passed, otherwise test directory dir_live_set() { - if [ -n "${1}" ]; then - dir_live="${1}" - if [ ! -d "${dir_live}" ]; then - echo "${dir_live} inexistent" >&2 - exit 1 - fi - if [ "$(basename "${dir_live}")" != "data" ]; then - echo "${dir_live} not a directory named data" >&2 - exit 1 + if [ -z "${1}" ]; then + dir_live="none" + elif [ -f "${1}" ]; then + dir_live="$(dirname "${1}")" + elif [ -d "${1}" ]; then + if [ "$(basename "${1}")" = "data" ]; then + dir_live="$(dirname "${1}")" + else + dir_live="${1}" fi else - dir_live="none" + echo "${1} inexistent" >&2 + exit 1 fi } @@ -152,7 +153,7 @@ teardown() { live() { if [ "${dir_live}" != "none" ]; then - NVT_FUNC_DIR_TEST="$(dirname "${dir_live}")" + NVT_FUNC_DIR_TEST="$(realpath "${dir_live}")" fi # options extracted from testnvim.lua nvim_argv, nvim_set From 559f07f98d516a0f5d525ab0d2b0f9190ac4132f Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 11:21:16 +1000 Subject: [PATCH 077/154] test: more fs.create.dir tests --- test/nvt/func/fs/create/dir_spec.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 4e196c90425..9aaa1fb7a3e 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -54,6 +54,21 @@ describe("prompt", function() cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, }) end) + + + it("file focused", function() + n.feed( + ":NvimTreeOpen", + "", + "", + "a" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, + }) + end) end) From 47fed8bf4256818b53b4258f049c8080cc588a98 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 11:45:49 +1000 Subject: [PATCH 078/154] doc: fix incorrect register doc for actions.use_system_clipboard --- lua/nvim-tree/_meta/config/actions.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/nvim-tree/_meta/config/actions.lua b/lua/nvim-tree/_meta/config/actions.lua index 012f4c364d9..5f39fbda3f1 100644 --- a/lua/nvim-tree/_meta/config/actions.lua +++ b/lua/nvim-tree/_meta/config/actions.lua @@ -5,7 +5,7 @@ error("Cannot require a meta file") ---@class nvim_tree.config.actions --- ----Use the system clipboard for copy/paste. Copied text will be stored in registers `+` (system), otherwise, it will be stored in `1` and `"` +---Use the system clipboard for copy/paste. Copied text will be stored in registers `+` (system), otherwise, it will be stored in `1` ---(default: `true`) ---@field use_system_clipboard? boolean --- From 178c640e1141b471bb330d5190adbb0b0cf6556b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 11:55:29 +1000 Subject: [PATCH 079/154] test: add func fs.copy.node --- test/nvt/func/fs/copy/node/data/d1/d1f1 | 1 + test/nvt/func/fs/copy/node/data/d1/d1f2 | 1 + test/nvt/func/fs/copy/node/data/d2/d2f1 | 1 + test/nvt/func/fs/copy/node/data/f1 | 1 + test/nvt/func/fs/copy/node/data/f2 | 1 + test/nvt/func/fs/copy/node/file_spec.lua | 79 ++++++++++++++++++++++++ 6 files changed, 84 insertions(+) create mode 100644 test/nvt/func/fs/copy/node/data/d1/d1f1 create mode 100644 test/nvt/func/fs/copy/node/data/d1/d1f2 create mode 100644 test/nvt/func/fs/copy/node/data/d2/d2f1 create mode 100644 test/nvt/func/fs/copy/node/data/f1 create mode 100644 test/nvt/func/fs/copy/node/data/f2 create mode 100644 test/nvt/func/fs/copy/node/file_spec.lua diff --git a/test/nvt/func/fs/copy/node/data/d1/d1f1 b/test/nvt/func/fs/copy/node/data/d1/d1f1 new file mode 100644 index 00000000000..13d1560f267 --- /dev/null +++ b/test/nvt/func/fs/copy/node/data/d1/d1f1 @@ -0,0 +1 @@ +d1f1 diff --git a/test/nvt/func/fs/copy/node/data/d1/d1f2 b/test/nvt/func/fs/copy/node/data/d1/d1f2 new file mode 100644 index 00000000000..6ec000bf6df --- /dev/null +++ b/test/nvt/func/fs/copy/node/data/d1/d1f2 @@ -0,0 +1 @@ +d1f2 diff --git a/test/nvt/func/fs/copy/node/data/d2/d2f1 b/test/nvt/func/fs/copy/node/data/d2/d2f1 new file mode 100644 index 00000000000..f901b65feae --- /dev/null +++ b/test/nvt/func/fs/copy/node/data/d2/d2f1 @@ -0,0 +1 @@ +d2f1 diff --git a/test/nvt/func/fs/copy/node/data/f1 b/test/nvt/func/fs/copy/node/data/f1 new file mode 100644 index 00000000000..8e1e71d5ce3 --- /dev/null +++ b/test/nvt/func/fs/copy/node/data/f1 @@ -0,0 +1 @@ +f1 diff --git a/test/nvt/func/fs/copy/node/data/f2 b/test/nvt/func/fs/copy/node/data/f2 new file mode 100644 index 00000000000..9de77c18733 --- /dev/null +++ b/test/nvt/func/fs/copy/node/data/f2 @@ -0,0 +1 @@ +f2 diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node/file_spec.lua new file mode 100644 index 00000000000..9e850805c5d --- /dev/null +++ b/test/nvt/func/fs/copy/node/file_spec.lua @@ -0,0 +1,79 @@ +local t = require("test.testutil") +local nf = require("test.nvt.func.fixtures") +local n = require("test.functional.testnvim")() + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + +--- @type test.functional.ui.screen +local screen + + +before_each(function() + screen = nf.create_session({ ext_cmdline = true }) + + n.exec_lua(function() + require("nvim-tree").setup({ + actions = { + -- don't use system clipboard for most tests as it is async + -- use_system_clipboard = false, + }, + }) + end) +end) + + +describe("single", function() + it("file", function() + nf.unique_highlight_groups(screen) + + n.fn.setreg("1", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "", + "c" + ) + + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("1")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d3 │~ | + ^  f1 │~ | +  f2 │~ | +~ │~ |*16 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + screen:expect({ + unchanged = true, + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:d3}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCopiedHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*16 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + end) +end) + +-- vim:colorcolumn=80 From 5287d4bb687158e88a6e417b2613ea1f2a333a46 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 11:55:45 +1000 Subject: [PATCH 080/154] test: add func fs.copy.node --- test/nvt/func/fs/copy/node/file_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node/file_spec.lua index 9e850805c5d..dd4530f0b4f 100644 --- a/test/nvt/func/fs/copy/node/file_spec.lua +++ b/test/nvt/func/fs/copy/node/file_spec.lua @@ -20,7 +20,7 @@ before_each(function() require("nvim-tree").setup({ actions = { -- don't use system clipboard for most tests as it is async - -- use_system_clipboard = false, + use_system_clipboard = false, }, }) end) From adb2185d5884130363996489296459c162cc6ec7 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 11:58:13 +1000 Subject: [PATCH 081/154] doc: fix incorrect register doc for actions.use_system_clipboard --- doc/nvim-tree-lua.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/nvim-tree-lua.txt b/doc/nvim-tree-lua.txt index 6fd01f18f1b..f468e6866b2 100644 --- a/doc/nvim-tree-lua.txt +++ b/doc/nvim-tree-lua.txt @@ -1708,7 +1708,7 @@ Config: actions *nvim-tree-config-actions* • {use_system_clipboard}? (`boolean`, default: `true`) Use the system clipboard for copy/paste. Copied text will be stored in registers `+` (system), otherwise, - it will be stored in `1` and `"` + it will be stored in `1` *nvim_tree.config.actions.change_dir* vim |current-directory| behaviour From 540cb4cc90a0858aa042a00c4e985f6b237ef375 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 11:58:58 +1000 Subject: [PATCH 082/154] test: add func fs.copy.node --- test/nvt/func/fs/copy/node/data/d3/d3f1 | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/nvt/func/fs/copy/node/data/d3/d3f1 diff --git a/test/nvt/func/fs/copy/node/data/d3/d3f1 b/test/nvt/func/fs/copy/node/data/d3/d3f1 new file mode 100644 index 00000000000..832bad2faee --- /dev/null +++ b/test/nvt/func/fs/copy/node/data/d3/d3f1 @@ -0,0 +1 @@ +d3f1 From df9f60e3c61292a4ef55618569f108776eb336ba Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 12:00:23 +1000 Subject: [PATCH 083/154] test: add func fs.copy.node --- test/nvt/func/fs/copy/node/data/d3/d3f1 | 1 - test/nvt/func/fs/copy/node/file_spec.lua | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) delete mode 100644 test/nvt/func/fs/copy/node/data/d3/d3f1 diff --git a/test/nvt/func/fs/copy/node/data/d3/d3f1 b/test/nvt/func/fs/copy/node/data/d3/d3f1 deleted file mode 100644 index 832bad2faee..00000000000 --- a/test/nvt/func/fs/copy/node/data/d3/d3f1 +++ /dev/null @@ -1 +0,0 @@ -d3f1 diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node/file_spec.lua index dd4530f0b4f..7d60d35a131 100644 --- a/test/nvt/func/fs/copy/node/file_spec.lua +++ b/test/nvt/func/fs/copy/node/file_spec.lua @@ -14,7 +14,7 @@ local screen before_each(function() - screen = nf.create_session({ ext_cmdline = true }) + screen = nf.create_session() n.exec_lua(function() require("nvim-tree").setup({ @@ -38,7 +38,6 @@ describe("single", function() "", "", "", - "", "c" ) @@ -50,10 +49,9 @@ describe("single", function() /tmp/nvt_func/data/.. │ |   d1 │~ |   d2 │~ | -   d3 │~ | ^  f1 │~ |  f2 │~ | -~ │~ |*16 +~ │~ |*17 NvimTree_1 [-] [No Name] | [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | ]], @@ -65,10 +63,9 @@ NvimTree_1 [-] [No Name] {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeEmptyFolderName:d3}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCopiedHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*16 + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | ]], From 2a3638b2d479a5f0d398cb56e1e0807e071ca3d8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 12:33:12 +1000 Subject: [PATCH 084/154] test: add func fs.copy.node --- test/nvt/func/fs/copy/node/file_spec.lua | 182 ++++++++++++++++++++++- 1 file changed, 181 insertions(+), 1 deletion(-) diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node/file_spec.lua index 7d60d35a131..3fe3b78cb5f 100644 --- a/test/nvt/func/fs/copy/node/file_spec.lua +++ b/test/nvt/func/fs/copy/node/file_spec.lua @@ -28,7 +28,7 @@ end) describe("single", function() - it("file", function() + it("file highlight", function() nf.unique_highlight_groups(screen) n.fn.setreg("1", "foo") @@ -71,6 +71,186 @@ NvimTree_1 [-] [No Name] ]], }) end) + + it("dir highlight", function() + nf.unique_highlight_groups(screen) + + n.fn.setreg("1", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "", + "c" + ) + + t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("1")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d2 added to clipboard. | + ]], + }) + + screen:expect({ + unchanged = true, + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeCopiedHLCL:d2}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/d2 added to clipboard. | + ]], + }) + end) + + it("toggle", function() + n.fn.setreg("1", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "c" + ) + + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("1")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | + ^  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + n.feed( + "c" + ) + + t.eq("", n.fn.getreg("1")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | + ^  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 removed from clipboard. | + ]], + }) + end) +end) + +describe("multiple", function() + it("dir overriding file", function() + n.fn.setreg("1", "foo") + + n.feed( + ":NvimTreeOpen", + "E", + "", + "", + "", + "", + "", + "", + "", + "c" + ) + + t.eq([[ +/tmp/nvt_func/data/d1/d1f2 +/tmp/nvt_func/data/d2/ +/tmp/nvt_func/data/f1]], n.fn.getreg("1")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +   d2 │~ | +  d2f1 │~ | + ^  f1 │~ | +  f2 │~ | +~ │~ |*14 +NvimTree_1 [-] [No Name] | +[NvimTree] 3 nodes added to clipboard. | + ]], + }) + end) + + it("toggle", function() + n.fn.setreg("1", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "c" + ) + + t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("1")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | + ^  d1 │~ | +   d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | + ]], + }) + + n.feed( + "", + "", + "c" + ) + + t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("1")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] 1 nodes added to clipboard. | + ]], + }) + end) end) -- vim:colorcolumn=80 From de1606c38ba46824d26cf1dba74d9dc33876c3ff Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 30 Sep 2026 13:30:40 +1000 Subject: [PATCH 085/154] test: add screen width/height params --- test/nvt/func/fixtures.lua | 6 ++++-- test/nvt/func/fs/copy/node/file_spec.lua | 24 ++++++++++++++++++++++-- test/nvt/func/fs/create/dir_spec.lua | 2 +- test/nvt/func/fs/create/file_spec.lua | 2 +- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index 4252c31a1b2..e536b6233c5 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -11,12 +11,14 @@ local M = {} ---Create a new neovim session with ---- nvim-tree.lua package added ---- fresh test data directory created and cd'd into +---@param width? integer +---@param height? integer ---@param options? test.functional.ui.screen.Opts ---@return test.functional.ui.screen -function M.create_session(options) +function M.create_session(width, height, options) n.clear() - local screen = Screen.new(80, 24, options) + local screen = Screen.new(width or 80, height or 24, options) n.exec_lua(function() vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH") or "") diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node/file_spec.lua index 3fe3b78cb5f..ef693d6f21e 100644 --- a/test/nvt/func/fs/copy/node/file_spec.lua +++ b/test/nvt/func/fs/copy/node/file_spec.lua @@ -19,7 +19,6 @@ before_each(function() n.exec_lua(function() require("nvim-tree").setup({ actions = { - -- don't use system clipboard for most tests as it is async use_system_clipboard = false, }, }) @@ -27,6 +26,8 @@ before_each(function() end) +-- TODO system clipboard + with dummy provider, see :help clipboard + describe("single", function() it("file highlight", function() nf.unique_highlight_groups(screen) @@ -165,7 +166,9 @@ NvimTree_1 [-] [No Name] end) describe("multiple", function() - it("dir overriding file", function() + it("dir overriding file highlight", function() + nf.unique_highlight_groups(screen) + n.fn.setreg("1", "foo") n.feed( @@ -202,6 +205,23 @@ NvimTree_1 [-] [No Name] [NvimTree] 3 nodes added to clipboard. | ]], }) + + screen:expect({ + unchanged = true, + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCopiedHL:d1f2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeCopiedHL:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d2f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCopiedHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*14 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] 3 nodes added to clipboard. | + ]], + }) end) it("toggle", function() diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 9aaa1fb7a3e..b14aa3c2a6b 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -15,7 +15,7 @@ local screen before_each(function() - screen = nf.create_session({ ext_cmdline = true }) + screen = nf.create_session(nil, nil, { ext_cmdline = true }) n.exec_lua(function() require("nvim-tree").setup({}) diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index aff6af6205d..9fb98188c8d 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -15,7 +15,7 @@ local screen before_each(function() - screen = nf.create_session({ ext_cmdline = true }) + screen = nf.create_session(nil, nil, { ext_cmdline = true }) n.exec_lua(function() require("nvim-tree").setup({}) From cc39375747f1fce1a7c642ed3b3f4c0063592f5a Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 1 Oct 2026 12:12:50 +1000 Subject: [PATCH 086/154] test: add dummy clipboard fixture --- test/nvt/func/fixtures.lua | 37 ++++++++++++- test/nvt/func/fs/copy/node/file_spec.lua | 70 ++++++++++++++++++------ 2 files changed, 87 insertions(+), 20 deletions(-) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index e536b6233c5..292e0a30308 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -2,6 +2,18 @@ local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") local appearance = require("nvim-tree.appearance") +---Globals used within test session context, noted in this test context only for type definition +---@diagnostic disable: global-element + +---@type nvt.functest.event[] +NVT_FUNCTEST_EVENTS = {} + +---@type string[] +NVT_DUMMY_CLIPBOARD_LINES = {} + +---@diagnostic enable: global-element + + local M = {} ---@class (exact) nvt.functest.event @@ -24,8 +36,8 @@ function M.create_session(width, height, options) vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH") or "") vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) - ---@type nvt.functest.event[] - NVT_FUNCTEST_EVENTS = NVT_FUNCTEST_EVENTS or {} ---@diagnostic disable-line: global-element + NVT_FUNCTEST_EVENTS = {} ---@diagnostic disable-line: global-element + NVT_DUMMY_CLIPBOARD_LINES = {} ---@diagnostic disable-line: global-element end) -- TODO neovim 0.13: replace with vim.system calls; vim.system is not currenctly available in neovim 0.12 func tests @@ -34,6 +46,8 @@ function M.create_session(width, height, options) n.api.nvim_set_current_dir(dir) + M.setup_dummy_clipboard() + return screen end @@ -60,6 +74,25 @@ function M.events_clear() end) end +---Setup a dummy clipboard using the global NVT_DUMMY_CLIPBOARD_LINES +function M.setup_dummy_clipboard() + n.exec_lua(function() + vim.g.clipboard = { + name = "NVT_DUMMY_CLIPBOARD", + copy = { + ["+"] = function(lines) + NVT_DUMMY_CLIPBOARD_LINES = lines ---@diagnostic disable-line: global-element + end + }, + paste = { + ["+"] = function() + return NVT_DUMMY_CLIPBOARD_LINES + end + }, + } + end) +end + ---Reset all NvimTree* highlight groups to just a unique foreground colour ---Return attr_ids to match ---Add a CL variant with the same background colour as NvimTreeCursorLine diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node/file_spec.lua index ef693d6f21e..7c2d8605e20 100644 --- a/test/nvt/func/fs/copy/node/file_spec.lua +++ b/test/nvt/func/fs/copy/node/file_spec.lua @@ -17,22 +17,17 @@ before_each(function() screen = nf.create_session() n.exec_lua(function() - require("nvim-tree").setup({ - actions = { - use_system_clipboard = false, - }, - }) + require("nvim-tree").setup({}) end) end) --- TODO system clipboard + with dummy provider, see :help clipboard - describe("single", function() it("file highlight", function() nf.unique_highlight_groups(screen) n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") n.feed( ":NvimTreeOpen", @@ -42,7 +37,8 @@ describe("single", function() "c" ) - t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("1")) + t.eq("foo", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) screen:expect({ attr_ids = {}, @@ -76,7 +72,7 @@ NvimTree_1 [-] [No Name] it("dir highlight", function() nf.unique_highlight_groups(screen) - n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") n.feed( ":NvimTreeOpen", @@ -85,7 +81,7 @@ NvimTree_1 [-] [No Name] "c" ) - t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) screen:expect({ attr_ids = {}, @@ -117,7 +113,7 @@ NvimTree_1 [-] [No Name] end) it("toggle", function() - n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") n.feed( ":NvimTreeOpen", @@ -127,7 +123,7 @@ NvimTree_1 [-] [No Name] "c" ) - t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) screen:expect({ attr_ids = {}, @@ -147,7 +143,7 @@ NvimTree_1 [-] [No Name] "c" ) - t.eq("", n.fn.getreg("1")) + t.eq("", n.fn.getreg("+")) screen:expect({ attr_ids = {}, @@ -163,13 +159,51 @@ NvimTree_1 [-] [No Name] ]], }) end) + + it("no system clipboard", function() + n.exec_lua(function() + require("nvim-tree").setup({ + actions = { + use_system_clipboard = false, + }, + }) + end) + + n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") + -- + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "c" + ) + + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("1")) + t.eq("foo", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | + ^  f1 │~ | +  f2 │~ | + ~ │~ |*17 + NvimTree_1 [-] [No Name] | + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + end) end) describe("multiple", function() it("dir overriding file highlight", function() nf.unique_highlight_groups(screen) - n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") n.feed( ":NvimTreeOpen", @@ -187,7 +221,7 @@ describe("multiple", function() t.eq([[ /tmp/nvt_func/data/d1/d1f2 /tmp/nvt_func/data/d2/ -/tmp/nvt_func/data/f1]], n.fn.getreg("1")) +/tmp/nvt_func/data/f1]], n.fn.getreg("+")) screen:expect({ attr_ids = {}, @@ -225,7 +259,7 @@ NvimTree_1 [-] [No Name] end) it("toggle", function() - n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") n.feed( ":NvimTreeOpen", @@ -233,7 +267,7 @@ NvimTree_1 [-] [No Name] "c" ) - t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("+")) screen:expect({ attr_ids = {}, @@ -255,7 +289,7 @@ NvimTree_1 [-] [No Name] "c" ) - t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) screen:expect({ attr_ids = {}, From 77486e710b93fdc77c2990b9c23ffb11bceb89b5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 1 Oct 2026 12:14:41 +1000 Subject: [PATCH 087/154] test: add dummy clipboard fixture --- .luacheckrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.luacheckrc b/.luacheckrc index d3fd6056e26..71df0e3dfd1 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -19,8 +19,9 @@ M.globals = { "after_each", "teardown", "finally", - -- Global nvt functiontest data + -- Global nvt functiontest fixtures "NVT_FUNCTEST_EVENTS", + "NVT_DUMMY_CLIPBOARD_LINES", } return M From dd56f8e81f429835916eb7591e5c33bc25c011b7 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 10:51:28 +1000 Subject: [PATCH 088/154] test: remove poc test --- test/nvt/func/map/node/data/d1/f1 | 1 - test/nvt/func/map/node/data/d1/f2 | 1 - test/nvt/func/map/node/data/d2/f1 | 0 test/nvt/func/map/node/data/f1 | 1 - test/nvt/func/map/node/data/f2 | 1 - test/nvt/func/map/node/open_spec.lua | 108 --------------------------- 6 files changed, 112 deletions(-) delete mode 100644 test/nvt/func/map/node/data/d1/f1 delete mode 100644 test/nvt/func/map/node/data/d1/f2 delete mode 100644 test/nvt/func/map/node/data/d2/f1 delete mode 100644 test/nvt/func/map/node/data/f1 delete mode 100644 test/nvt/func/map/node/data/f2 delete mode 100644 test/nvt/func/map/node/open_spec.lua diff --git a/test/nvt/func/map/node/data/d1/f1 b/test/nvt/func/map/node/data/d1/f1 deleted file mode 100644 index 13d1560f267..00000000000 --- a/test/nvt/func/map/node/data/d1/f1 +++ /dev/null @@ -1 +0,0 @@ -d1f1 diff --git a/test/nvt/func/map/node/data/d1/f2 b/test/nvt/func/map/node/data/d1/f2 deleted file mode 100644 index 6ec000bf6df..00000000000 --- a/test/nvt/func/map/node/data/d1/f2 +++ /dev/null @@ -1 +0,0 @@ -d1f2 diff --git a/test/nvt/func/map/node/data/d2/f1 b/test/nvt/func/map/node/data/d2/f1 deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/nvt/func/map/node/data/f1 b/test/nvt/func/map/node/data/f1 deleted file mode 100644 index 8e1e71d5ce3..00000000000 --- a/test/nvt/func/map/node/data/f1 +++ /dev/null @@ -1 +0,0 @@ -f1 diff --git a/test/nvt/func/map/node/data/f2 b/test/nvt/func/map/node/data/f2 deleted file mode 100644 index 9de77c18733..00000000000 --- a/test/nvt/func/map/node/data/f2 +++ /dev/null @@ -1 +0,0 @@ -f2 diff --git a/test/nvt/func/map/node/open_spec.lua b/test/nvt/func/map/node/open_spec.lua deleted file mode 100644 index 9b92e1ace33..00000000000 --- a/test/nvt/func/map/node/open_spec.lua +++ /dev/null @@ -1,108 +0,0 @@ -local t = require("test.testutil") -local nf = require("test.nvt.func.fixtures") -local n = require("test.functional.testnvim")() -local exec_lua = n.exec_lua - --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it -local setup = t.setup or setup ----@diagnostic enable: undefined-global - -describe("map_node_open", function() - --- @type test.functional.ui.screen - local screen - - setup(function() - screen = nf.create_session() - end) - - before_each(function() - exec_lua(function() - require("nvim-tree").setup({}) - end) - end) - - it("dir", function() - exec_lua(function() - require("nvim-tree.api").tree.open() - end) - - n.feed("gg") - n.feed("") - n.feed("") - - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | - ^  d1 │~ | -  f1 │~ | -  f2 │~ | -   d2 │~ | -  f1 │~ | -  f2 │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -NvimTree_1 [-] [No Name] | - | - ]], - }) - end) - - it("file", function() - exec_lua(function() - require("nvim-tree.api").tree.open() - end) - - n.feed("") - n.feed("") - - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │^f1 | -   d1 │~ | -   d2 │~ | -  f1 │~ | -  f2 │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -NvimTree_1 [-] f1 | - | - ]], - }) - end) -end) - --- vim:colorcolumn=80 From 0691a1d9ccd29966255ba11b4fb231673f2dfb2c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 10:52:20 +1000 Subject: [PATCH 089/154] test: don't use ext_linegrid when expecting HL groups for performance reasons, warn if so --- test/nvt/func/api/tree/open_spec.lua | 24 ++++++++++++------------ test/nvt/func/fixtures.lua | 10 ++++++++++ test/nvt/func/fs/copy/node/file_spec.lua | 2 +- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/test/nvt/func/api/tree/open_spec.lua b/test/nvt/func/api/tree/open_spec.lua index 2a176c477c0..ad1686a7ba0 100644 --- a/test/nvt/func/api/tree/open_spec.lua +++ b/test/nvt/func/api/tree/open_spec.lua @@ -8,25 +8,21 @@ local exec_lua = n.exec_lua local describe = t.describe or describe local before_each = t.before_each or before_each local it = t.it or it -local setup = t.setup or setup ---@diagnostic enable: undefined-global -describe("api_tree_open", function() - --- @type test.functional.ui.screen - local screen +--- @type test.functional.ui.screen +local screen - setup(function() - screen = nf.create_session() - end) - before_each(function() - exec_lua(function() - require("nvim-tree").setup({}) - end) +before_each(function() + screen = nf.create_session(nil, nil, { ext_linegrid = false }) - nf.unique_highlight_groups(screen) + n.exec_lua(function() + require("nvim-tree").setup({}) end) +end) +describe("api_tree_open", function() it("populated_unfocussed_text_only", function() exec_lua(function() require("nvim-tree.api").tree.open() @@ -66,6 +62,8 @@ NvimTree_1 [-] [No Name] end) it("populated_unfocussed_hl_attrs", function() + nf.unique_highlight_groups(screen) + exec_lua(function() require("nvim-tree.api").tree.open() end) @@ -86,6 +84,8 @@ NvimTree_1 [-] [No Name] end) it("populated_unfocussed_hl_attrs", function() + nf.unique_highlight_groups(screen) + exec_lua(function() require("nvim-tree.api").tree.open() end) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index 292e0a30308..e06137f899c 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -99,6 +99,16 @@ end ---May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order ---@param screen test.functional.ui.screen function M.unique_highlight_groups(screen) + if screen._options.ext_linegrid == nil or screen._options.ext_linegrid == true then + print([[ + +warning: test.functional.ui.screen.Opts.ext_linegrid is set +This can cause severe (x10) performance problems when all NvimTree attr_ids are set, due to the number of :help ui-event-hl_attr_define events +Recommended: disable test.functional.ui.screen.Opts.ext_linegrid when calling create_session +Exceptions: when testing extmarks based functionality e.g. right aligned icons, full name etc. +]]) + end + local attr_ids = {} -- arbitrary "unique" value: math.random(tonumber('0x707070'),tonumber('0x909090')) diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node/file_spec.lua index 7c2d8605e20..41e121ba41e 100644 --- a/test/nvt/func/fs/copy/node/file_spec.lua +++ b/test/nvt/func/fs/copy/node/file_spec.lua @@ -14,7 +14,7 @@ local screen before_each(function() - screen = nf.create_session() + screen = nf.create_session(nil, nil, { ext_linegrid = false }) n.exec_lua(function() require("nvim-tree").setup({}) From 2f2bde5df5db8326883811d6c6b19476db3eb9d1 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 10:55:29 +1000 Subject: [PATCH 090/154] test: remove poc test --- test/nvt/func/api/tree/data/dir1/dir1file1 | 0 test/nvt/func/api/tree/data/dir2/dir2file1 | 0 test/nvt/func/api/tree/data/file1 | 1 - test/nvt/func/api/tree/data/file2 | 1 - test/nvt/func/api/tree/open_spec.lua | 111 --------------------- 5 files changed, 113 deletions(-) delete mode 100644 test/nvt/func/api/tree/data/dir1/dir1file1 delete mode 100644 test/nvt/func/api/tree/data/dir2/dir2file1 delete mode 100644 test/nvt/func/api/tree/data/file1 delete mode 100644 test/nvt/func/api/tree/data/file2 delete mode 100644 test/nvt/func/api/tree/open_spec.lua diff --git a/test/nvt/func/api/tree/data/dir1/dir1file1 b/test/nvt/func/api/tree/data/dir1/dir1file1 deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/nvt/func/api/tree/data/dir2/dir2file1 b/test/nvt/func/api/tree/data/dir2/dir2file1 deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/test/nvt/func/api/tree/data/file1 b/test/nvt/func/api/tree/data/file1 deleted file mode 100644 index 257cc5642cb..00000000000 --- a/test/nvt/func/api/tree/data/file1 +++ /dev/null @@ -1 +0,0 @@ -foo diff --git a/test/nvt/func/api/tree/data/file2 b/test/nvt/func/api/tree/data/file2 deleted file mode 100644 index 5716ca5987c..00000000000 --- a/test/nvt/func/api/tree/data/file2 +++ /dev/null @@ -1 +0,0 @@ -bar diff --git a/test/nvt/func/api/tree/open_spec.lua b/test/nvt/func/api/tree/open_spec.lua deleted file mode 100644 index ad1686a7ba0..00000000000 --- a/test/nvt/func/api/tree/open_spec.lua +++ /dev/null @@ -1,111 +0,0 @@ -local t = require("test.testutil") -local nf = require("test.nvt.func.fixtures") -local n = require("test.functional.testnvim")() -local exec_lua = n.exec_lua - --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global - ---- @type test.functional.ui.screen -local screen - - -before_each(function() - screen = nf.create_session(nil, nil, { ext_linegrid = false }) - - n.exec_lua(function() - require("nvim-tree").setup({}) - end) -end) - -describe("api_tree_open", function() - it("populated_unfocussed_text_only", function() - exec_lua(function() - require("nvim-tree.api").tree.open() - end) - - n.feed("") - - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │^ | -   dir1 │~ | -   dir2 │~ | -  file1 │~ | -  file2 │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -NvimTree_1 [-] [No Name] | - | - ]], - }) - end) - - it("populated_unfocussed_hl_attrs", function() - nf.unique_highlight_groups(screen) - - exec_lua(function() - require("nvim-tree.api").tree.open() - end) - - -- TODO BUG NvimTreeFolderArrowClosed is always set by Padding:get_arrows, it should only be set for DirectoryNode - screen:expect({ - grid = [[ -{NvimTreeSignColumn: }{NvimTreeRootFolderCL:^/tmp/nvt_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:dir1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:dir2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file1 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: file2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 -{NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| - | - ]], - }) - end) - - it("populated_unfocussed_hl_attrs", function() - nf.unique_highlight_groups(screen) - - exec_lua(function() - require("nvim-tree.api").tree.open() - end) - - n.feed("") - n.feed("") - - screen:expect({ - grid = [[ -{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}^ | -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalNCCL: }{NvimTreeFolderNameCL:dir1}{NvimTreeNormalNCCL: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormalNC: }{NvimTreeFolderName:dir2}{NvimTreeNormalNC: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file1 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormalNC: file2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 -{NvimTreeStatusLineNC:NvimTree_1 [-] }{3:[No Name] }| - | - ]], - }) - end) -end) - --- vim:colorcolumn=80 From abb4655796ffe044bc1e4fd537e44127c8b8a05d Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 12:04:24 +1000 Subject: [PATCH 091/154] test: functest highlight groups are setup by main, not test, to avoid highlight event explosion --- lua/nvim-tree/appearance/init.lua | 58 +++++++++++++++- test/nvt/func/fixtures.lua | 86 +++++++----------------- test/nvt/func/fs/copy/node/file_spec.lua | 56 ++------------- 3 files changed, 84 insertions(+), 116 deletions(-) diff --git a/lua/nvim-tree/appearance/init.lua b/lua/nvim-tree/appearance/init.lua index 9918ca4dd0b..7dc9a3734a2 100644 --- a/lua/nvim-tree/appearance/init.lua +++ b/lua/nvim-tree/appearance/init.lua @@ -182,8 +182,7 @@ M.LEGACY_LINKS = { NvimTreeDiagnosticHintFolderHL = "NvimTreeLspDiagnosticsHintFolderText", } ----Create all highlight groups and links. Idempotent. -function M.highlight() +local function highlight_main() -- non-linked for _, g in ipairs(M.HIGHLIGHT_GROUPS) do if g.def then @@ -208,4 +207,59 @@ function M.highlight() end end +---Create all NvimTree* highlight groups with just a unique foreground colour +---NvimTreeCursorLine has just a background colour +---Add a CL variant for each group with the same background colour as NvimTreeCursorLine +---This is done here, as redefining groups in the test context is a performance issue, due to the number of :help ui-event-hl_attr_define events +local function highlight_functest() + + -- arbitrary cursor line "unique" value: math.random(tonumber('0x707070'),tonumber('0x909090')) + local hex_bg = "#85a450" + + -- unique colour for each group, descending from #fefefe + local i, r, g, b = 1, 254, 254, 254 + local rgb_fg, hex_fg + + -- build the cursor line first, background only + local hgs = vim.tbl_filter(function(hg) + if hg.group == "NvimTreeCursorLine" then + vim.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = hex_bg }) + return false + else + return true + end + end, M.HIGHLIGHT_GROUPS) + + -- define the remainder with unique foregrounds + for _, hg in ipairs(hgs) do + -- next unique fg colour + rgb_fg = r * 256 * 256 + g * 256 + b + hex_fg = string.format("#%x", rgb_fg) + i = i + 1 + if (i % 256 == 0) then + b, g, r = 254, 254, r - 1 + elseif (i % 16 == 0) then + b, g = 254, g - 1 + else + b = b - 1 + end + + -- add the group's concrete definition with fg only + vim.api.nvim_set_hl(0, hg.group, { fg = hex_fg }) + + -- create an NvimTreeCursorLine variant + vim.api.nvim_set_hl(0, hg.group .. "CL", { fg = hex_fg, bg = hex_bg }) + end +end + +---Create all highlight groups and links. Idempotent. +function M.highlight() + if NVT_FUNCTEST_CONTEXT then + highlight_functest() + else + highlight_main() + end + +end + return M diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index e06137f899c..88690d94141 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -1,25 +1,29 @@ local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") -local appearance = require("nvim-tree.appearance") + + +---@class (exact) nvt.functest.event +---@field event_type string value of nvim_tree.api.events.Event +---@field payload table deep copy + ---Globals used within test session context, noted in this test context only for type definition ---@diagnostic disable: global-element +---@type boolean +NVT_FUNCTEST_CONTEXT = true + ---@type nvt.functest.event[] NVT_FUNCTEST_EVENTS = {} ---@type string[] -NVT_DUMMY_CLIPBOARD_LINES = {} +NVT_FUNCTEST_CLIPBOARD_LINES = {} ---@diagnostic enable: global-element local M = {} ----@class (exact) nvt.functest.event ----@field event_type string value of nvim_tree.api.events.Event ----@field payload table deep copy - ---Create a new neovim session with ---- nvim-tree.lua package added ---- fresh test data directory created and cd'd into @@ -36,8 +40,11 @@ function M.create_session(width, height, options) vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH") or "") vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) - NVT_FUNCTEST_EVENTS = {} ---@diagnostic disable-line: global-element - NVT_DUMMY_CLIPBOARD_LINES = {} ---@diagnostic disable-line: global-element + ---@diagnostic disable: global-element + NVT_FUNCTEST_CONTEXT = true + NVT_FUNCTEST_EVENTS = {} + NVT_FUNCTEST_CLIPBOARD_LINES = {} + ---@diagnostic enable: global-element end) -- TODO neovim 0.13: replace with vim.system calls; vim.system is not currenctly available in neovim 0.12 func tests @@ -81,74 +88,29 @@ function M.setup_dummy_clipboard() name = "NVT_DUMMY_CLIPBOARD", copy = { ["+"] = function(lines) - NVT_DUMMY_CLIPBOARD_LINES = lines ---@diagnostic disable-line: global-element + NVT_FUNCTEST_CLIPBOARD_LINES = lines ---@diagnostic disable-line: global-element end }, paste = { ["+"] = function() - return NVT_DUMMY_CLIPBOARD_LINES + return NVT_FUNCTEST_CLIPBOARD_LINES end }, } end) end ----Reset all NvimTree* highlight groups to just a unique foreground colour ----Return attr_ids to match ----Add a CL variant with the same background colour as NvimTreeCursorLine ----May be executed repeatedly however results are not idempotent: foreground colours will be different, depending on vim.api.nvim_get_hl iteration order +---Set concrete attr_ids for all nvim-tree highlight groups +---Must be called after nvim-tree setup +---These groups are uniquely defined in the test context in TODO ---@param screen test.functional.ui.screen -function M.unique_highlight_groups(screen) - if screen._options.ext_linegrid == nil or screen._options.ext_linegrid == true then - print([[ - -warning: test.functional.ui.screen.Opts.ext_linegrid is set -This can cause severe (x10) performance problems when all NvimTree attr_ids are set, due to the number of :help ui-event-hl_attr_define events -Recommended: disable test.functional.ui.screen.Opts.ext_linegrid when calling create_session -Exceptions: when testing extmarks based functionality e.g. right aligned icons, full name etc. -]]) - end - +function M.add_nvt_attr_ids(screen) local attr_ids = {} - -- arbitrary "unique" value: math.random(tonumber('0x707070'),tonumber('0x909090')) - local rgb_cl, hex_cl = 8758352, "#85a450" - - -- unique colour for each group, descending from #fefefe - local i, r, g, b = 1, 254, 254, 254 - local rgb, hex - - -- build the cursor line first, background only - local hgs = vim.tbl_filter(function(hg) - if hg.group == "NvimTreeCursorLine" then - attr_ids["NvimTreeCursorLine"] = { background = rgb_cl } - n.api.nvim_set_hl(0, "NvimTreeCursorLine", { bg = hex_cl }) - return false - else - return true - end - end, appearance.HIGHLIGHT_GROUPS) - - for _, hg in ipairs(hgs) do - -- next unique fg colour - rgb = r * 256 * 256 + g * 256 + b - hex = string.format("#%x", rgb) - i = i + 1 - if (i % 256 == 0) then - b, g, r = 254, 254, r - 1 - elseif (i % 16 == 0) then - b, g = 254, g - 1 - else - b = b - 1 + for name, hl in pairs(n.api.nvim_get_hl(0, { create = false, link = true, })) do + if name:match("^NvimTree.*") then + attr_ids[name] = { foreground = hl.fg, background = hl.bg } end - - -- add the group's concrete definition with fg only - attr_ids[hg.group] = { foreground = rgb } - n.api.nvim_set_hl(0, hg.group, { fg = hex }) - - -- create an NvimTreeCursorLine variant - attr_ids[hg.group .. "CL"] = { foreground = rgb, background = rgb_cl } - n.api.nvim_set_hl(0, hg.group .. "CL", { fg = hex, bg = hex_cl }) end screen:add_extra_attr_ids(attr_ids) diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node/file_spec.lua index 41e121ba41e..21199a9fbd5 100644 --- a/test/nvt/func/fs/copy/node/file_spec.lua +++ b/test/nvt/func/fs/copy/node/file_spec.lua @@ -14,7 +14,7 @@ local screen before_each(function() - screen = nf.create_session(nil, nil, { ext_linegrid = false }) + screen = nf.create_session() n.exec_lua(function() require("nvim-tree").setup({}) @@ -24,8 +24,6 @@ end) describe("single", function() it("file highlight", function() - nf.unique_highlight_groups(screen) - n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -40,22 +38,9 @@ describe("single", function() t.eq("foo", n.fn.getreg("1")) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | -   d2 │~ | - ^  f1 │~ | -  f2 │~ | -~ │~ |*17 -NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | - ]], - }) + nf.add_nvt_attr_ids(screen) screen:expect({ - unchanged = true, grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| @@ -70,8 +55,6 @@ NvimTree_1 [-] [No Name] end) it("dir highlight", function() - nf.unique_highlight_groups(screen) - n.fn.setreg("+", "foo") n.feed( @@ -83,22 +66,9 @@ NvimTree_1 [-] [No Name] t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | - ^  d2 │~ | -  f1 │~ | -  f2 │~ | -~ │~ |*17 -NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/d2 added to clipboard. | - ]], - }) + nf.add_nvt_attr_ids(screen) screen:expect({ - unchanged = true, grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| @@ -201,8 +171,6 @@ end) describe("multiple", function() it("dir overriding file highlight", function() - nf.unique_highlight_groups(screen) - n.fn.setreg("+", "foo") n.feed( @@ -223,25 +191,9 @@ describe("multiple", function() /tmp/nvt_func/data/d2/ /tmp/nvt_func/data/f1]], n.fn.getreg("+")) - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | -  d1f1 │~ | -  d1f2 │~ | -   d2 │~ | -  d2f1 │~ | - ^  f1 │~ | -  f2 │~ | -~ │~ |*14 -NvimTree_1 [-] [No Name] | -[NvimTree] 3 nodes added to clipboard. | - ]], - }) + nf.add_nvt_attr_ids(screen) screen:expect({ - unchanged = true, grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| From 014a2eb5b2221643d3a3edbc62a4fb1183d6cf93 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 12:05:35 +1000 Subject: [PATCH 092/154] test: functest highlight groups are setup by main, not test, to avoid highlight event explosion --- .luacheckrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.luacheckrc b/.luacheckrc index 71df0e3dfd1..db7aa55a141 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -20,8 +20,9 @@ M.globals = { "teardown", "finally", -- Global nvt functiontest fixtures + "NVT_FUNCTEST_CONTEXT", "NVT_FUNCTEST_EVENTS", - "NVT_DUMMY_CLIPBOARD_LINES", + "NVT_FUNCTEST_CLIPBOARD_LINES", } return M From a9aaa82aa93f0e75e09a0de26de72ebd3bd09fec Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 12:07:54 +1000 Subject: [PATCH 093/154] test: functest highlight groups are setup by main, not test, to avoid highlight event explosion --- lua/nvim-tree/appearance/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lua/nvim-tree/appearance/init.lua b/lua/nvim-tree/appearance/init.lua index 7dc9a3734a2..d9cce4faf6a 100644 --- a/lua/nvim-tree/appearance/init.lua +++ b/lua/nvim-tree/appearance/init.lua @@ -254,7 +254,7 @@ end ---Create all highlight groups and links. Idempotent. function M.highlight() - if NVT_FUNCTEST_CONTEXT then + if NVT_FUNCTEST_CONTEXT then ---@diagnostic disable-line: undefined-global highlight_functest() else highlight_main() From 1b3a1ffad4a8337e7ac805384dfb88dd25e0e754 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 12:13:15 +1000 Subject: [PATCH 094/154] test: functest highlight groups are setup by main, not test, to avoid highlight event explosion --- Makefile | 2 ++ lua/nvim-tree/appearance/init.lua | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9db6f48e498..57d9e56e46c 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +# TODO functest move any checks from ci.yml into here, adding any missing e.g. codeformat + all: lint style check # diff --git a/lua/nvim-tree/appearance/init.lua b/lua/nvim-tree/appearance/init.lua index d9cce4faf6a..f90bbe659ce 100644 --- a/lua/nvim-tree/appearance/init.lua +++ b/lua/nvim-tree/appearance/init.lua @@ -212,7 +212,6 @@ end ---Add a CL variant for each group with the same background colour as NvimTreeCursorLine ---This is done here, as redefining groups in the test context is a performance issue, due to the number of :help ui-event-hl_attr_define events local function highlight_functest() - -- arbitrary cursor line "unique" value: math.random(tonumber('0x707070'),tonumber('0x909090')) local hex_bg = "#85a450" @@ -259,7 +258,6 @@ function M.highlight() else highlight_main() end - end return M From 197699cf1513699f913c2c2242f604839c774b8d Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 12:40:19 +1000 Subject: [PATCH 095/154] test: create_sessions now calls setup and adds attr_ids --- test/nvt/func/fixtures.lua | 24 +++++++++++++++++------- test/nvt/func/fs/copy/node/file_spec.lua | 10 ---------- test/nvt/func/fs/create/dir_spec.lua | 6 +----- test/nvt/func/fs/create/file_spec.lua | 6 +----- 4 files changed, 19 insertions(+), 27 deletions(-) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index 88690d94141..7635331e059 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -24,14 +24,18 @@ NVT_FUNCTEST_CLIPBOARD_LINES = {} local M = {} ----Create a new neovim session with +---Create a new neovim functest session with ---- nvim-tree.lua package added ---- fresh test data directory created and cd'd into ----@param width? integer ----@param height? integer +---- nvim-tree setup called +---- nvim-tree HL attr_ids added +---- dummy clipboard setup +---@param config? nvim_tree.config passed to nvim-tree.setup +---@param width? integer default 80 +---@param height? integer default 24 ---@param options? test.functional.ui.screen.Opts ---@return test.functional.ui.screen -function M.create_session(width, height, options) +function M.create_session(config, width, height, options) n.clear() local screen = Screen.new(width or 80, height or 24, options) @@ -47,13 +51,19 @@ function M.create_session(width, height, options) ---@diagnostic enable: global-element end) + -- Change to the temp test (data) directory -- TODO neovim 0.13: replace with vim.system calls; vim.system is not currenctly available in neovim 0.12 func tests local out = n.fn.system({ os.getenv("NVT_FUNC_SCRIPT_CREATE_TEST_CWD"), }) local dir = out:match("^DIR=(.*)$") or error(out) - n.api.nvim_set_current_dir(dir) - M.setup_dummy_clipboard() + n.exec_lua(function() + require("nvim-tree").setup(config) + end) + + M.add_nvt_attr_ids(screen) + + M.use_dummy_clipboard() return screen end @@ -82,7 +92,7 @@ function M.events_clear() end ---Setup a dummy clipboard using the global NVT_DUMMY_CLIPBOARD_LINES -function M.setup_dummy_clipboard() +function M.use_dummy_clipboard() n.exec_lua(function() vim.g.clipboard = { name = "NVT_DUMMY_CLIPBOARD", diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node/file_spec.lua index 21199a9fbd5..abd5a4ddeb0 100644 --- a/test/nvt/func/fs/copy/node/file_spec.lua +++ b/test/nvt/func/fs/copy/node/file_spec.lua @@ -15,10 +15,6 @@ local screen before_each(function() screen = nf.create_session() - - n.exec_lua(function() - require("nvim-tree").setup({}) - end) end) @@ -38,8 +34,6 @@ describe("single", function() t.eq("foo", n.fn.getreg("1")) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) - nf.add_nvt_attr_ids(screen) - screen:expect({ grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | @@ -66,8 +60,6 @@ describe("single", function() t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) - nf.add_nvt_attr_ids(screen) - screen:expect({ grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | @@ -191,8 +183,6 @@ describe("multiple", function() /tmp/nvt_func/data/d2/ /tmp/nvt_func/data/f1]], n.fn.getreg("+")) - nf.add_nvt_attr_ids(screen) - screen:expect({ grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index b14aa3c2a6b..3363513017d 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -15,11 +15,7 @@ local screen before_each(function() - screen = nf.create_session(nil, nil, { ext_cmdline = true }) - - n.exec_lua(function() - require("nvim-tree").setup({}) - end) + screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.FolderCreated) diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 9fb98188c8d..16086c491c0 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -15,11 +15,7 @@ local screen before_each(function() - screen = nf.create_session(nil, nil, { ext_cmdline = true }) - - n.exec_lua(function() - require("nvim-tree").setup({}) - end) + screen = nf.create_session({}, nil, nil, { ext_cmdline = true }) local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.FileCreated) From 30b5e07bbf5b858e4a15d12916faac6ba34f5e13 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 12:50:45 +1000 Subject: [PATCH 096/154] test: organise copy structure nicely --- test/nvt/func/fixtures.lua | 2 +- test/nvt/func/fs/copy/{node => }/data/d1/d1f1 | 0 test/nvt/func/fs/copy/{node => }/data/d1/d1f2 | 0 test/nvt/func/fs/copy/{node => }/data/d2/d2f1 | 0 test/nvt/func/fs/copy/{node => }/data/f1 | 0 test/nvt/func/fs/copy/{node => }/data/f2 | 0 test/nvt/func/fs/copy/{node/file_spec.lua => node_spec.lua} | 6 +++--- 7 files changed, 4 insertions(+), 4 deletions(-) rename test/nvt/func/fs/copy/{node => }/data/d1/d1f1 (100%) rename test/nvt/func/fs/copy/{node => }/data/d1/d1f2 (100%) rename test/nvt/func/fs/copy/{node => }/data/d2/d2f1 (100%) rename test/nvt/func/fs/copy/{node => }/data/f1 (100%) rename test/nvt/func/fs/copy/{node => }/data/f2 (100%) rename test/nvt/func/fs/copy/{node/file_spec.lua => node_spec.lua} (98%) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index 7635331e059..c711702d665 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -112,7 +112,7 @@ end ---Set concrete attr_ids for all nvim-tree highlight groups ---Must be called after nvim-tree setup ----These groups are uniquely defined in the test context in TODO +---These groups are uniquely defined in the test context by appearance/init.lua highlight_functest ---@param screen test.functional.ui.screen function M.add_nvt_attr_ids(screen) local attr_ids = {} diff --git a/test/nvt/func/fs/copy/node/data/d1/d1f1 b/test/nvt/func/fs/copy/data/d1/d1f1 similarity index 100% rename from test/nvt/func/fs/copy/node/data/d1/d1f1 rename to test/nvt/func/fs/copy/data/d1/d1f1 diff --git a/test/nvt/func/fs/copy/node/data/d1/d1f2 b/test/nvt/func/fs/copy/data/d1/d1f2 similarity index 100% rename from test/nvt/func/fs/copy/node/data/d1/d1f2 rename to test/nvt/func/fs/copy/data/d1/d1f2 diff --git a/test/nvt/func/fs/copy/node/data/d2/d2f1 b/test/nvt/func/fs/copy/data/d2/d2f1 similarity index 100% rename from test/nvt/func/fs/copy/node/data/d2/d2f1 rename to test/nvt/func/fs/copy/data/d2/d2f1 diff --git a/test/nvt/func/fs/copy/node/data/f1 b/test/nvt/func/fs/copy/data/f1 similarity index 100% rename from test/nvt/func/fs/copy/node/data/f1 rename to test/nvt/func/fs/copy/data/f1 diff --git a/test/nvt/func/fs/copy/node/data/f2 b/test/nvt/func/fs/copy/data/f2 similarity index 100% rename from test/nvt/func/fs/copy/node/data/f2 rename to test/nvt/func/fs/copy/data/f2 diff --git a/test/nvt/func/fs/copy/node/file_spec.lua b/test/nvt/func/fs/copy/node_spec.lua similarity index 98% rename from test/nvt/func/fs/copy/node/file_spec.lua rename to test/nvt/func/fs/copy/node_spec.lua index abd5a4ddeb0..0db172632a3 100644 --- a/test/nvt/func/fs/copy/node/file_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -19,7 +19,7 @@ end) describe("single", function() - it("file highlight", function() + it("file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -48,7 +48,7 @@ describe("single", function() }) end) - it("dir highlight", function() + it("dir", function() n.fn.setreg("+", "foo") n.feed( @@ -162,7 +162,7 @@ NvimTree_1 [-] [No Name] end) describe("multiple", function() - it("dir overriding file highlight", function() + it("dir overriding file", function() n.fn.setreg("+", "foo") n.feed( From a667003b5661d099590c5c30e7945e52a5a0dc19 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 2 Oct 2026 12:58:17 +1000 Subject: [PATCH 097/154] test: organise fs.create structure nicely --- test/nvt/func/fs/create/data/d1/d1f1 | 1 + test/nvt/func/fs/create/data/f1 | 1 + test/nvt/func/fs/create/dir_spec.lua | 70 -------------------- test/nvt/func/fs/create/file_spec.lua | 15 ----- test/nvt/func/fs/create/prompt_spec.lua | 88 +++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 85 deletions(-) create mode 100644 test/nvt/func/fs/create/prompt_spec.lua diff --git a/test/nvt/func/fs/create/data/d1/d1f1 b/test/nvt/func/fs/create/data/d1/d1f1 index e69de29bb2d..13d1560f267 100644 --- a/test/nvt/func/fs/create/data/d1/d1f1 +++ b/test/nvt/func/fs/create/data/d1/d1f1 @@ -0,0 +1 @@ +d1f1 diff --git a/test/nvt/func/fs/create/data/f1 b/test/nvt/func/fs/create/data/f1 index e69de29bb2d..8e1e71d5ce3 100644 --- a/test/nvt/func/fs/create/data/f1 +++ b/test/nvt/func/fs/create/data/f1 @@ -0,0 +1 @@ +f1 diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 3363513017d..fdda1bc2923 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -22,52 +22,6 @@ before_each(function() end) -describe("prompt", function() - it("tree focused", function() - n.feed( - ":NvimTreeOpen", - "", - "a" - ) - - screen:expect({ - mode = "cmdline_normal", - cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, - }) - end) - - - it("tree not focused", function() - n.feed( - ":NvimTreeOpen", - "", - "", - ":lua require('nvim-tree.api').fs.create()" - ) - - screen:expect({ - mode = "cmdline_normal", - cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, - }) - end) - - - it("file focused", function() - n.feed( - ":NvimTreeOpen", - "", - "", - "a" - ) - - screen:expect({ - mode = "cmdline_normal", - cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, - }) - end) -end) - - describe("existing", function() it("nop", function() n.feed( @@ -92,30 +46,6 @@ NvimTree_1 [-] [No Name] end) -describe("cancelled", function() - it("nop", function() - n.feed( - ":NvimTreeOpen", - "a", - "foo", - "" - ) - - screen:expect({ - attr_ids = {}, - grid = [[ - ^/tmp/nvt_func/data/.. │ | -   d1 │~ | -  f1 │~ | -~ │~ |*19 -NvimTree_1 [-] [No Name] | - | - ]], - }) - end) -end) - - describe("single dir", function() it("direct ok", function() n.feed( diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 16086c491c0..9a3546dfae7 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -24,21 +24,6 @@ before_each(function() end) -describe("prompt", function() - it("tree focused", function() - n.feed( - ":NvimTreeOpen", - "a" - ) - - screen:expect({ - mode = "cmdline_normal", - cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, - }) - end) -end) - - describe("single file", function() it("direct ok", function() n.feed( diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua new file mode 100644 index 00000000000..510b0e3536b --- /dev/null +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -0,0 +1,88 @@ +local t = require("test.testutil") +local nf = require("test.nvt.func.fixtures") +local n = require("test.functional.testnvim")() + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + +--- @type test.functional.ui.screen +local screen + + +before_each(function() + screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) +end) + + +describe("prompt", function() + it("tree focused", function() + n.feed( + ":NvimTreeOpen", + "", + "a" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, + }) + end) + + + it("tree not focused", function() + n.feed( + ":NvimTreeOpen", + "", + "", + ":lua require('nvim-tree.api').fs.create()" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, + }) + end) + + + it("file focused", function() + n.feed( + ":NvimTreeOpen", + "", + "", + "a" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, + }) + end) + + + it("cancelled", function() + n.feed( + ":NvimTreeOpen", + "a", + "foo", + "" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  f1 │~ | +~ │~ |*19 +NvimTree_1 [-] [No Name] | + | + ]], + }) + end) +end) + +-- vim:colorcolumn=80 From 90ee602cd8eac961dd08e68939581b8b053fb48c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 5 Oct 2026 12:32:31 +1100 Subject: [PATCH 098/154] test: add fs/cut --- test/nvt/func/fs/cut/data/d1/d1f1 | 1 + test/nvt/func/fs/cut/data/d1/d1f2 | 1 + test/nvt/func/fs/cut/data/d2/d2f1 | 1 + test/nvt/func/fs/cut/data/f1 | 1 + test/nvt/func/fs/cut/data/f2 | 1 + test/nvt/func/fs/cut/node_spec.lua | 256 +++++++++++++++++++++++++++++ 6 files changed, 261 insertions(+) create mode 100644 test/nvt/func/fs/cut/data/d1/d1f1 create mode 100644 test/nvt/func/fs/cut/data/d1/d1f2 create mode 100644 test/nvt/func/fs/cut/data/d2/d2f1 create mode 100644 test/nvt/func/fs/cut/data/f1 create mode 100644 test/nvt/func/fs/cut/data/f2 create mode 100644 test/nvt/func/fs/cut/node_spec.lua diff --git a/test/nvt/func/fs/cut/data/d1/d1f1 b/test/nvt/func/fs/cut/data/d1/d1f1 new file mode 100644 index 00000000000..13d1560f267 --- /dev/null +++ b/test/nvt/func/fs/cut/data/d1/d1f1 @@ -0,0 +1 @@ +d1f1 diff --git a/test/nvt/func/fs/cut/data/d1/d1f2 b/test/nvt/func/fs/cut/data/d1/d1f2 new file mode 100644 index 00000000000..6ec000bf6df --- /dev/null +++ b/test/nvt/func/fs/cut/data/d1/d1f2 @@ -0,0 +1 @@ +d1f2 diff --git a/test/nvt/func/fs/cut/data/d2/d2f1 b/test/nvt/func/fs/cut/data/d2/d2f1 new file mode 100644 index 00000000000..f901b65feae --- /dev/null +++ b/test/nvt/func/fs/cut/data/d2/d2f1 @@ -0,0 +1 @@ +d2f1 diff --git a/test/nvt/func/fs/cut/data/f1 b/test/nvt/func/fs/cut/data/f1 new file mode 100644 index 00000000000..8e1e71d5ce3 --- /dev/null +++ b/test/nvt/func/fs/cut/data/f1 @@ -0,0 +1 @@ +f1 diff --git a/test/nvt/func/fs/cut/data/f2 b/test/nvt/func/fs/cut/data/f2 new file mode 100644 index 00000000000..9de77c18733 --- /dev/null +++ b/test/nvt/func/fs/cut/data/f2 @@ -0,0 +1 @@ +f2 diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua new file mode 100644 index 00000000000..ad8cff203d2 --- /dev/null +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -0,0 +1,256 @@ +local t = require("test.testutil") +local nf = require("test.nvt.func.fixtures") +local n = require("test.functional.testnvim")() + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + + +-- TODO BUG singe operations report "added to clipboard", not "cut to clipboard" as per bulk operations + + +--- @type test.functional.ui.screen +local screen + + +before_each(function() + screen = nf.create_session() +end) + + +describe("single", function() + it("file", function() + n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "x" + ) + + t.eq("foo", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + end) + + it("dir", function() + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "", + "x" + ) + + t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:d2}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/d2 added to clipboard. | + ]], + }) + end) + + it("toggle", function() + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "x" + ) + + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | + ^  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + n.feed( + "x" + ) + + t.eq("", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | + ^  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 removed from clipboard. | + ]], + }) + end) + + it("no system clipboard", function() + n.exec_lua(function() + require("nvim-tree").setup({ + actions = { + use_system_clipboard = false, + }, + }) + end) + + n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") + -- + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "x" + ) + + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("1")) + t.eq("foo", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | + ^  f1 │~ | +  f2 │~ | + ~ │~ |*17 + NvimTree_1 [-] [No Name] | + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + end) +end) + +describe("multiple", function() + it("dir overriding file", function() + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "E", + "", + "", + "", + "", + "", + "", + "", + "x" + ) + + t.eq([[ +/tmp/nvt_func/data/d1/d1f2 +/tmp/nvt_func/data/d2/ +/tmp/nvt_func/data/f1]], n.fn.getreg("+")) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d1f2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d2f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*14 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] 3 nodes cut to clipboard. | + ]], + }) + end) + + it("toggle", function() + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "x" + ) + + t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | + ^  d1 │~ | +   d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | + ]], + }) + + n.feed( + "", + "", + "x" + ) + + t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] 1 nodes cut to clipboard. | + ]], + }) + end) +end) + +-- vim:colorcolumn=80 From 4c49ec979fa655a0b566776785954e48f6fa75be Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 5 Oct 2026 12:47:45 +1100 Subject: [PATCH 099/154] test: add fs cut override copy --- test/nvt/func/fs/cut/node_spec.lua | 116 +++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index ad8cff203d2..b8f132a2142 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -163,6 +163,52 @@ NvimTree_1 [-] [No Name] ]], }) end) + + it("overrides copy", function() + n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "c" + ) + + t.eq("foo", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCopiedHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + n.feed( + "x" + ) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + end) end) describe("multiple", function() @@ -251,6 +297,76 @@ NvimTree_1 [-] [No Name] ]], }) end) + + + it("overrides copy", function() + n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "", + "", + "c", + "", + "c" + ) + + t.eq("foo", n.fn.getreg("1")) + t.eq([[ +/tmp/nvt_func/data/d1/ +/tmp/nvt_func/data/d2/d2f1 +/tmp/nvt_func/data/f1]], n.fn.getreg("+")) + + screen:expect({ + grid = [[ +{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeCopiedHL:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCopiedHL:d2f1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCopiedHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*16 +{NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| +[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + n.feed( + "gg", + "", + "", + "", + "", + "", + "", + "x" + ) + + screen:expect({ + grid = [[ +{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCopiedHL:d2f1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCutHL:f1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:f2}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*16 +{NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| +[NvimTree] 4 nodes cut to clipboard. | + ]], + }) + + t.eq("foo", n.fn.getreg("1")) + t.eq([[ +/tmp/nvt_func/data/d1/ +/tmp/nvt_func/data/d2/ +/tmp/nvt_func/data/f1 +/tmp/nvt_func/data/f2]], n.fn.getreg("+")) + end) end) -- vim:colorcolumn=80 From 74849143065ec383931fa7a7d31158a70b6ca3b5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 5 Oct 2026 12:49:10 +1100 Subject: [PATCH 100/154] test: add fs copy override cut --- test/nvt/func/fs/copy/node_spec.lua | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index 0db172632a3..538a78eee93 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -159,6 +159,52 @@ NvimTree_1 [-] [No Name] ]], }) end) + + it("overrides cut", function() + n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "x" + ) + + t.eq("foo", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + n.feed( + "c" + ) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCopiedHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + end) end) describe("multiple", function() From 40e5cb38a38a719b62adae5e4ad67fc0cb3af47a Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 5 Oct 2026 13:31:05 +1100 Subject: [PATCH 101/154] test: add fs print_clipboard --- test/nvt/func/fs/print_clipboard/data/d1/d1f1 | 1 + test/nvt/func/fs/print_clipboard/data/d1/d1f2 | 1 + test/nvt/func/fs/print_clipboard/data/d2/d2f1 | 1 + test/nvt/func/fs/print_clipboard/data/d3/d3f1 | 1 + test/nvt/func/fs/print_clipboard/data/f1 | 1 + test/nvt/func/fs/print_clipboard/data/f2 | 1 + .../print_clipboard/print_clipboard_spec.lua | 78 +++++++++++++++++++ 7 files changed, 84 insertions(+) create mode 100644 test/nvt/func/fs/print_clipboard/data/d1/d1f1 create mode 100644 test/nvt/func/fs/print_clipboard/data/d1/d1f2 create mode 100644 test/nvt/func/fs/print_clipboard/data/d2/d2f1 create mode 100644 test/nvt/func/fs/print_clipboard/data/d3/d3f1 create mode 100644 test/nvt/func/fs/print_clipboard/data/f1 create mode 100644 test/nvt/func/fs/print_clipboard/data/f2 create mode 100644 test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua diff --git a/test/nvt/func/fs/print_clipboard/data/d1/d1f1 b/test/nvt/func/fs/print_clipboard/data/d1/d1f1 new file mode 100644 index 00000000000..13d1560f267 --- /dev/null +++ b/test/nvt/func/fs/print_clipboard/data/d1/d1f1 @@ -0,0 +1 @@ +d1f1 diff --git a/test/nvt/func/fs/print_clipboard/data/d1/d1f2 b/test/nvt/func/fs/print_clipboard/data/d1/d1f2 new file mode 100644 index 00000000000..6ec000bf6df --- /dev/null +++ b/test/nvt/func/fs/print_clipboard/data/d1/d1f2 @@ -0,0 +1 @@ +d1f2 diff --git a/test/nvt/func/fs/print_clipboard/data/d2/d2f1 b/test/nvt/func/fs/print_clipboard/data/d2/d2f1 new file mode 100644 index 00000000000..f901b65feae --- /dev/null +++ b/test/nvt/func/fs/print_clipboard/data/d2/d2f1 @@ -0,0 +1 @@ +d2f1 diff --git a/test/nvt/func/fs/print_clipboard/data/d3/d3f1 b/test/nvt/func/fs/print_clipboard/data/d3/d3f1 new file mode 100644 index 00000000000..832bad2faee --- /dev/null +++ b/test/nvt/func/fs/print_clipboard/data/d3/d3f1 @@ -0,0 +1 @@ +d3f1 diff --git a/test/nvt/func/fs/print_clipboard/data/f1 b/test/nvt/func/fs/print_clipboard/data/f1 new file mode 100644 index 00000000000..8e1e71d5ce3 --- /dev/null +++ b/test/nvt/func/fs/print_clipboard/data/f1 @@ -0,0 +1 @@ +f1 diff --git a/test/nvt/func/fs/print_clipboard/data/f2 b/test/nvt/func/fs/print_clipboard/data/f2 new file mode 100644 index 00000000000..9de77c18733 --- /dev/null +++ b/test/nvt/func/fs/print_clipboard/data/f2 @@ -0,0 +1 @@ +f2 diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua new file mode 100644 index 00000000000..c132f3b0ff2 --- /dev/null +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -0,0 +1,78 @@ +local t = require("test.testutil") +local nf = require("test.nvt.func.fixtures") +local n = require("test.functional.testnvim")() + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + + +--- @type test.functional.ui.screen +local screen + + +before_each(function() + screen = nf.create_session() +end) + + +describe("multiple", function() + it("initial", function() + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "c", + "", + "x", + "", + "c", + "", + "x" + ) + + n.exec_lua(function() + require("nvim-tree.api").fs.print_clipboard() + end) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +   d2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | + | +[NvimTree] | +Cut | + * /tmp/nvt_func/data/d1/d1f2 | + * /tmp/nvt_func/data/d3 | +Copy | + * /tmp/nvt_func/data/d1/d1f1 | + * /tmp/nvt_func/data/d2 | +Press ENTER or type command to continue^ | + ]], + }) + end) + + it("override", function() + -- TODO retain state from previous or just use one test + end) +end) + +-- vim:colorcolumn=80 From 20c92ca3b416dbf10ae303673b36cd52e3a7c447 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 6 Oct 2026 10:15:00 +1100 Subject: [PATCH 102/154] test: add fs print_clipboard --- .../print_clipboard/print_clipboard_spec.lua | 50 ++++++++++++++++--- 1 file changed, 44 insertions(+), 6 deletions(-) diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index c132f3b0ff2..3835770c166 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -19,8 +19,50 @@ before_each(function() end) -describe("multiple", function() - it("initial", function() +describe("fs.print_clipboard", function() + it("none", function() + n.feed( + ":NvimTreeOpen" + ) + + n.exec_lua(function() + require("nvim-tree.api").fs.print_clipboard() + end) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | + | +[NvimTree] | + | +Press ENTER or type command to continue^ | + ]], + }) + + end) + + + it("many", function() n.feed( ":NvimTreeOpen", "", @@ -69,10 +111,6 @@ Press ENTER or type command to continue^ ]], }) end) - - it("override", function() - -- TODO retain state from previous or just use one test - end) end) -- vim:colorcolumn=80 From d60f2a2b4f58997e71ff97a65f328cb99bd30cbe Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 6 Oct 2026 10:54:04 +1100 Subject: [PATCH 103/154] test: normalise names, use functional area as describe --- test/nvt/func/fs/copy/node_spec.lua | 114 +++++++------- test/nvt/func/fs/create/dir_spec.lua | 150 +++++++++---------- test/nvt/func/fs/create/file_spec.lua | 14 +- test/nvt/func/fs/create/prompt_spec.lua | 2 +- test/nvt/func/fs/cut/node_spec.lua | 191 ++++++++++++------------ 5 files changed, 237 insertions(+), 234 deletions(-) diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index 538a78eee93..723fcb78457 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -18,8 +18,8 @@ before_each(function() end) -describe("single", function() - it("file", function() +describe("fs.copy.node", function() + it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -48,7 +48,8 @@ describe("single", function() }) end) - it("dir", function() + + it("single dir", function() n.fn.setreg("+", "foo") n.feed( @@ -74,7 +75,8 @@ describe("single", function() }) end) - it("toggle", function() + + it("toggle one", function() n.fn.setreg("+", "foo") n.feed( @@ -122,6 +124,56 @@ NvimTree_1 [-] [No Name] }) end) + + it("toggle many", function() + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "c" + ) + + t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | + ^  d1 │~ | +   d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | + ]], + }) + + n.feed( + "", + "", + "c" + ) + + t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] 1 nodes added to clipboard. | + ]], + }) + end) + + it("no system clipboard", function() n.exec_lua(function() require("nvim-tree").setup({ @@ -160,6 +212,7 @@ NvimTree_1 [-] [No Name] }) end) + it("overrides cut", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -205,10 +258,9 @@ NvimTree_1 [-] [No Name] ]], }) end) -end) -describe("multiple", function() - it("dir overriding file", function() + + it("dir overrides file", function() n.fn.setreg("+", "foo") n.feed( @@ -245,54 +297,6 @@ describe("multiple", function() ]], }) end) - - it("toggle", function() - n.fn.setreg("+", "foo") - - n.feed( - ":NvimTreeOpen", - "", - "c" - ) - - t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("+")) - - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | - ^  d1 │~ | -   d2 │~ | -  f1 │~ | -  f2 │~ | -~ │~ |*17 -NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | - ]], - }) - - n.feed( - "", - "", - "c" - ) - - t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) - - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | - ^  d2 │~ | -  f1 │~ | -  f2 │~ | -~ │~ |*17 -NvimTree_1 [-] [No Name] | -[NvimTree] 1 nodes added to clipboard. | - ]], - }) - end) end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index fdda1bc2923..fc4b4ff910f 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -22,36 +22,69 @@ before_each(function() end) -describe("existing", function() - it("nop", function() +describe("fs.create dir", function() + it("single direct", function() n.feed( ":NvimTreeOpen", - "", "a", - "" + "direct/" ) screen:expect({ attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | - ^  d1 │~ | +   d1 │~ | + ^  direct │~ |  f1 │~ | -~ │~ |*19 +~ │~ |*18 NvimTree_1 [-] [No Name] | - | +[NvimTree] /tmp/nvt_func/data/direct/ was properly created | ]], }) + + na.dir_exists("/tmp/nvt_func/data/direct") + + na.events_received({ + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct/", }, }, + }) end) -end) -describe("single dir", function() - it("direct ok", function() + it("single indirect", function() n.feed( ":NvimTreeOpen", "a", - "direct/" + "d1/indirect/" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^   indirect │~ | +  d1f1 │~ | +  f1 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1/indirect/ was properly created | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d1/indirect") + + na.events_received({ + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect/", }, }, + }) + end) + + + it("multiple direct", function() + n.feed( + ":NvimTreeOpen", + "a", + "direct1/direct2/" ) screen:expect({ @@ -59,27 +92,31 @@ describe("single dir", function() grid = [[ /tmp/nvt_func/data/.. │ |   d1 │~ | - ^  direct │~ | +   direct1 │~ | + ^   direct2 │~ |  f1 │~ | -~ │~ |*18 +~ │~ |*17 NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/direct/ was properly created | +[NvimTree] /tmp/nvt_func/data/direct1/direct2/ was properly created | ]], }) - na.dir_exists("/tmp/nvt_func/data/direct") + na.dir_exists("/tmp/nvt_func/data/direct1") + na.dir_exists("/tmp/nvt_func/data/direct1/direct2") na.events_received({ - { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct/", }, }, + -- TODO BUG this should be "/tmp/nvt_func/data/direct1/" + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct1/direct2/", }, }, + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct1/direct2/", }, }, }) end) - it("indirect ok", function() + it("multiple indirect", function() n.feed( ":NvimTreeOpen", "a", - "d1/indirect/" + "d1/indirect1/indirect2/" ) screen:expect({ @@ -87,24 +124,28 @@ NvimTree_1 [-] [No Name] grid = [[ /tmp/nvt_func/data/.. │ |   d1 │~ | - ^   indirect │~ | +   indirect1 │~ | + ^   indirect2 │~ |  d1f1 │~ |  f1 │~ | -~ │~ |*17 +~ │~ |*16 NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/d1/indirect/ was properly created | +[NvimTree] /tmp/nvt_func/data/d1/indirect1/indirect2/ was properly created | ]], }) - na.dir_exists("/tmp/nvt_func/data/d1/indirect") + na.dir_exists("/tmp/nvt_func/data/d1/indirect1") + na.dir_exists("/tmp/nvt_func/data/d1/indirect1/indirect2") na.events_received({ - { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect/", }, }, + -- TODO BUG this should be "/tmp/nvt_func/data/d1/indirect1/" + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", }, }, + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", }, }, }) end) - it("existing dir", function() + it("fails when file exists", function() n.feed( ":NvimTreeOpen", "a", @@ -127,7 +168,7 @@ NvimTree_1 [-] [No Name] end) - it("existing file", function() + it("fails when file exists", function() n.feed( ":NvimTreeOpen", "a", @@ -153,7 +194,7 @@ NvimTree_1 [-] [No Name] end) - it("invalid path", function() + it("fails on invalid path", function() n.feed( ":NvimTreeOpen", "a", @@ -175,72 +216,27 @@ NvimTree_1 [-] [No Name] na.events_received({}) end) -end) -describe("multiple dirs", function() - it("direct ok", function() - n.feed( - ":NvimTreeOpen", - "a", - "direct1/direct2/" - ) - - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | -   direct1 │~ | - ^   direct2 │~ | -  f1 │~ | -~ │~ |*17 -NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/direct1/direct2/ was properly created | - ]], - }) - - na.dir_exists("/tmp/nvt_func/data/direct1") - na.dir_exists("/tmp/nvt_func/data/direct1/direct2") - - na.events_received({ - -- TODO BUG this should be "/tmp/nvt_func/data/direct1/" - { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct1/direct2/", }, }, - { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct1/direct2/", }, }, - }) - end) - - - it("indirect ok", function() + it("fails when dir exists", function() n.feed( ":NvimTreeOpen", + "", "a", - "d1/indirect1/indirect2/" + "" ) screen:expect({ attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | -   d1 │~ | -   indirect1 │~ | - ^   indirect2 │~ | -  d1f1 │~ | + ^  d1 │~ |  f1 │~ | -~ │~ |*16 +~ │~ |*19 NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/d1/indirect1/indirect2/ was properly created | + | ]], }) - - na.dir_exists("/tmp/nvt_func/data/d1/indirect1") - na.dir_exists("/tmp/nvt_func/data/d1/indirect1/indirect2") - - na.events_received({ - -- TODO BUG this should be "/tmp/nvt_func/data/d1/indirect1/" - { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", }, }, - { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", }, }, - }) end) end) diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 9a3546dfae7..c1f69d70450 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -24,8 +24,8 @@ before_each(function() end) -describe("single file", function() - it("direct ok", function() +describe("fs.create file", function() + it("direct", function() n.feed( ":NvimTreeOpen", "a", @@ -54,7 +54,7 @@ NvimTree_1 [-] [No Name] end) - it("indirect ok", function() + it("indirect", function() n.feed( ":NvimTreeOpen", "a", @@ -84,7 +84,7 @@ NvimTree_1 [-] [No Name] end) - it("existing file", function() + it("fails when file exists", function() n.feed( ":NvimTreeOpen", "a", @@ -109,7 +109,7 @@ NvimTree_1 [-] [No Name] end) - it("existing dir", function() + it("fails when dir exists", function() n.feed( ":NvimTreeOpen", "a", @@ -134,7 +134,7 @@ NvimTree_1 [-] [No Name] end) - it("nested dir", function() + it("indirect creates dirs", function() n.feed( ":NvimTreeOpen", "a", @@ -166,7 +166,7 @@ NvimTree_1 [-] [No Name] end) - it("invalid path", function() + it("fails on invalid path", function() n.feed( ":NvimTreeOpen", "a", diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index 510b0e3536b..da10aead289 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -18,7 +18,7 @@ before_each(function() end) -describe("prompt", function() +describe("fs.create prompt", function() it("tree focused", function() n.feed( ":NvimTreeOpen", diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index b8f132a2142..cffc264c422 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -22,8 +22,8 @@ before_each(function() end) -describe("single", function() - it("file", function() +describe("fs.cut.node", function() + it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -52,7 +52,8 @@ describe("single", function() }) end) - it("dir", function() + + it("single dir", function() n.fn.setreg("+", "foo") n.feed( @@ -78,7 +79,7 @@ describe("single", function() }) end) - it("toggle", function() + it("toggle one", function() n.fn.setreg("+", "foo") n.feed( @@ -126,6 +127,56 @@ NvimTree_1 [-] [No Name] }) end) + + it("toggle many", function() + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "", + "x" + ) + + t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | + ^  d1 │~ | +   d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | + ]], + }) + + n.feed( + "", + "", + "x" + ) + + t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] 1 nodes cut to clipboard. | + ]], + }) + end) + + it("no system clipboard", function() n.exec_lua(function() require("nvim-tree").setup({ @@ -164,7 +215,8 @@ NvimTree_1 [-] [No Name] }) end) - it("overrides copy", function() + + it("single overrides copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -209,97 +261,9 @@ NvimTree_1 [-] [No Name] ]], }) end) -end) - -describe("multiple", function() - it("dir overriding file", function() - n.fn.setreg("+", "foo") - - n.feed( - ":NvimTreeOpen", - "E", - "", - "", - "", - "", - "", - "", - "", - "x" - ) - - t.eq([[ -/tmp/nvt_func/data/d1/d1f2 -/tmp/nvt_func/data/d2/ -/tmp/nvt_func/data/f1]], n.fn.getreg("+")) - - screen:expect({ - grid = [[ - {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | - {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d1f2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d2f1 }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*14 - {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| - [NvimTree] 3 nodes cut to clipboard. | - ]], - }) - end) - - it("toggle", function() - n.fn.setreg("+", "foo") - - n.feed( - ":NvimTreeOpen", - "", - "x" - ) - - t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("+")) - - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | - ^  d1 │~ | -   d2 │~ | -  f1 │~ | -  f2 │~ | -~ │~ |*17 -NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | - ]], - }) - n.feed( - "", - "", - "x" - ) - - t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | - ^  d2 │~ | -  f1 │~ | -  f2 │~ | -~ │~ |*17 -NvimTree_1 [-] [No Name] | -[NvimTree] 1 nodes cut to clipboard. | - ]], - }) - end) - - - it("overrides copy", function() + it("multiple overrides copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -367,6 +331,45 @@ NvimTree_1 [-] [No Name] /tmp/nvt_func/data/f1 /tmp/nvt_func/data/f2]], n.fn.getreg("+")) end) + + + it("dir overrides file", function() + n.fn.setreg("+", "foo") + + n.feed( + ":NvimTreeOpen", + "E", + "", + "", + "", + "", + "", + "", + "", + "x" + ) + + t.eq([[ +/tmp/nvt_func/data/d1/d1f2 +/tmp/nvt_func/data/d2/ +/tmp/nvt_func/data/f1]], n.fn.getreg("+")) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d1f2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d2f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*14 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] 3 nodes cut to clipboard. | + ]], + }) + end) end) -- vim:colorcolumn=80 From 95118fca16c30714fb1d291fdf971156185033c2 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 6 Oct 2026 11:30:41 +1100 Subject: [PATCH 104/154] test: add fs.paste, wip --- test/nvt/func/asserts.lua | 7 ++ test/nvt/func/fs/paste/copy_spec.lua | 110 +++++++++++++++++++++++++++ test/nvt/func/fs/paste/cut_spec.lua | 93 ++++++++++++++++++++++ test/nvt/func/fs/paste/data/d1/d1f1 | 1 + test/nvt/func/fs/paste/data/d1/d1f2 | 1 + test/nvt/func/fs/paste/data/d2/d2f1 | 1 + test/nvt/func/fs/paste/data/d3/d3f1 | 0 test/nvt/func/fs/paste/data/f1 | 1 + test/nvt/func/fs/paste/data/f2 | 1 + 9 files changed, 215 insertions(+) create mode 100644 test/nvt/func/fs/paste/copy_spec.lua create mode 100644 test/nvt/func/fs/paste/cut_spec.lua create mode 100644 test/nvt/func/fs/paste/data/d1/d1f1 create mode 100644 test/nvt/func/fs/paste/data/d1/d1f2 create mode 100644 test/nvt/func/fs/paste/data/d2/d2f1 create mode 100644 test/nvt/func/fs/paste/data/d3/d3f1 create mode 100644 test/nvt/func/fs/paste/data/f1 create mode 100644 test/nvt/func/fs/paste/data/f2 diff --git a/test/nvt/func/asserts.lua b/test/nvt/func/asserts.lua index d638c9bc628..85e3b77acc4 100644 --- a/test/nvt/func/asserts.lua +++ b/test/nvt/func/asserts.lua @@ -19,6 +19,13 @@ function M.file_exists(path) t.eq("file", stat and stat.type, path) end +---Assert path does not exist +---@param path string absolute +function M.not_path_exists(path) + local stat = vim.uv.fs_stat(path) + t.eq(nil, stat, path) +end + ---Assert events received during a functest, recorded in session global NVT_FUNCTEST_EVENTS ---Must be subscribed via event_subscribe ---@param events nvt.functest.event[] diff --git a/test/nvt/func/fs/paste/copy_spec.lua b/test/nvt/func/fs/paste/copy_spec.lua new file mode 100644 index 00000000000..4795d82c8d9 --- /dev/null +++ b/test/nvt/func/fs/paste/copy_spec.lua @@ -0,0 +1,110 @@ +local t = require("test.testutil") +local nf = require("test.nvt.func.fixtures") +local na = require("test.nvt.func.asserts") +local n = require("test.functional.testnvim")() + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + +--- @type test.functional.ui.screen +local screen + + +before_each(function() + screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) +end) + + +describe("fs.paste.node copy", function() + it("single file", function() + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "", + "c", + "", + "p" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d3 │~ | +  d3f1 │~ | + ^  f1 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*14 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/f1") + na.file_exists("/tmp/nvt_func/data/d3/f1") + end) + + + it("single dir", function() + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p", + "E" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | + ^   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +  d2f1 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*12 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d2/d1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f2") + + na.dir_exists("/tmp/nvt_func/data/d1") + end) + + + it("single dir exists", function() + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, + }) + end) +end) + +-- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua new file mode 100644 index 00000000000..813a8d52081 --- /dev/null +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -0,0 +1,93 @@ +local t = require("test.testutil") +local nf = require("test.nvt.func.fixtures") +local na = require("test.nvt.func.asserts") +local n = require("test.functional.testnvim")() + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + +--- @type test.functional.ui.screen +local screen + + +before_each(function() + screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) +end) + + +describe("fs.paste.node cut", function() + it("cut single dir", function() + n.feed( + ":NvimTreeOpen", + "", + "x", + "", + "p", + "E" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d2 │~ | + ^   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +  d2f1 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*13 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d2/d1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f2") + + na.not_path_exists("/tmp/nvt_func/data/d1") + end) + + + it("cut single file", function() + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "", + "x", + "", + "p" + ) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d3 │~ | +  d3f1 │~ | + ^  f1 │~ | +  f2 │~ | +~ │~ |*15 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/d3/f1") + + na.not_path_exists("/tmp/nvt_func/data/f1") + end) +end) + +-- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/paste/data/d1/d1f1 b/test/nvt/func/fs/paste/data/d1/d1f1 new file mode 100644 index 00000000000..13d1560f267 --- /dev/null +++ b/test/nvt/func/fs/paste/data/d1/d1f1 @@ -0,0 +1 @@ +d1f1 diff --git a/test/nvt/func/fs/paste/data/d1/d1f2 b/test/nvt/func/fs/paste/data/d1/d1f2 new file mode 100644 index 00000000000..6ec000bf6df --- /dev/null +++ b/test/nvt/func/fs/paste/data/d1/d1f2 @@ -0,0 +1 @@ +d1f2 diff --git a/test/nvt/func/fs/paste/data/d2/d2f1 b/test/nvt/func/fs/paste/data/d2/d2f1 new file mode 100644 index 00000000000..f901b65feae --- /dev/null +++ b/test/nvt/func/fs/paste/data/d2/d2f1 @@ -0,0 +1 @@ +d2f1 diff --git a/test/nvt/func/fs/paste/data/d3/d3f1 b/test/nvt/func/fs/paste/data/d3/d3f1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/nvt/func/fs/paste/data/f1 b/test/nvt/func/fs/paste/data/f1 new file mode 100644 index 00000000000..8e1e71d5ce3 --- /dev/null +++ b/test/nvt/func/fs/paste/data/f1 @@ -0,0 +1 @@ +f1 diff --git a/test/nvt/func/fs/paste/data/f2 b/test/nvt/func/fs/paste/data/f2 new file mode 100644 index 00000000000..9de77c18733 --- /dev/null +++ b/test/nvt/func/fs/paste/data/f2 @@ -0,0 +1 @@ +f2 From 9ede3f8e7b94988cbdec4656ec338d7868e5f5c0 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 6 Oct 2026 12:28:43 +1100 Subject: [PATCH 105/154] test: fs.paste, wip --- test/nvt/func/fs/copy/node_spec.lua | 3 + test/nvt/func/fs/create/dir_spec.lua | 2 + test/nvt/func/fs/create/file_spec.lua | 2 + test/nvt/func/fs/create/prompt_spec.lua | 2 + test/nvt/func/fs/paste/copied_spec.lua | 380 ++++++++++++++++++++++++ test/nvt/func/fs/paste/copy_spec.lua | 110 ------- test/nvt/func/fs/paste/cut_spec.lua | 10 +- 7 files changed, 397 insertions(+), 112 deletions(-) create mode 100644 test/nvt/func/fs/paste/copied_spec.lua delete mode 100644 test/nvt/func/fs/paste/copy_spec.lua diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index 723fcb78457..645389b1fee 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -297,6 +297,9 @@ NvimTree_1 [-] [No Name] ]], }) end) + + + -- TODO test API end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index fc4b4ff910f..f4362bea58a 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -238,6 +238,8 @@ NvimTree_1 [-] [No Name] ]], }) end) + + -- TODO test API end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index c1f69d70450..083c576920e 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -180,6 +180,8 @@ NvimTree_1 [-] [No Name] { event_type = "WillCreateFile", payload = { fname = "/foo", }, }, }) end) + + -- TODO test API end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index da10aead289..3b554802684 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -83,6 +83,8 @@ NvimTree_1 [-] [No Name] ]], }) end) + + -- TODO test API end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua new file mode 100644 index 00000000000..5119f8f3c17 --- /dev/null +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -0,0 +1,380 @@ +local t = require("test.testutil") +local nf = require("test.nvt.func.fixtures") +local na = require("test.nvt.func.asserts") +local n = require("test.functional.testnvim")() + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + +--- @type test.functional.ui.screen +local screen + + +before_each(function() + screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) +end) + + +describe("fs.paste.node copied", function() + it("single file", function() + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "", + "c", + "", + "p" + ) + + screen:expect({ + cmdline = {}, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d3 │~ | +  d3f1 │~ | + ^  f1 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*14 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/f1") + na.file_exists("/tmp/nvt_func/data/d3/f1") + end) + + + it("single dir", function() + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p", + "gg", + "E" + ) + + screen:expect({ + cmdline = {}, + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +   d2 │~ | +   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +  d2f1 │~ | +   d3 │~ | +  d3f1 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*9 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d2/d1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f2") + + na.dir_exists("/tmp/nvt_func/data/d1") + end) + + + it("single dir conflict resolved", function() + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, + }) + + n.feed( + "_copy", + "gg", + "E" + ) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +   d1_copy │~ | +  d1f1 │~ | +  d1f2 │~ | +   d2 │~ | +  d2f1 │~ | +   d3 │~ | +  d3f1 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*9 +NvimTree_1 [-] [No Name] | + | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d1") + na.file_exists("/tmp/nvt_func/data/d1/d1f1") + na.file_exists("/tmp/nvt_func/data/d1/d1f2") + + na.dir_exists("/tmp/nvt_func/data/d1_copy") + na.file_exists("/tmp/nvt_func/data/d1_copy/d1f1") + na.file_exists("/tmp/nvt_func/data/d1_copy/d1f1") + end) + + + it("single dir conflict cancelled", function() + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, + }) + + n.feed( + "" + ) + + screen:expect({ + cmdline = { { abort = true } }, + }) + + n.feed( + "gg", + "E" + ) + + screen:expect({ + cmdline = {}, + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +   d2 │~ | +  d2f1 │~ | +   d3 │~ | +  d3f1 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*12 +NvimTree_1 [-] [No Name] | + | + ]], + }) + end) + + + -- TODO BUG this should prompt again when the file exists + it("single dir conflict second conflict overwrite", function() + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, + }) + + n.feed( + "2" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, + }) + + n.feed( + "y" + ) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | + | +[NvimTree] Could not copy /tmp/nvt_func/data/d1 - EEXIST: file already exists: /| +tmp/nvt_func/data/d2 | +Press ENTER or type command to continue^ | + ]], + }) + end) + + + it("single dir conflict second conflict cancel", function() + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, + }) + + n.feed( + "2" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, + }) + + n.feed( + "n", + "gg", + "E" + ) + + screen:expect({ + cmdline = { { abort = true } }, + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolderCL:^/tmp/nvt_func/data/..}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d2f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d3}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d3f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*12 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + | + ]], + }) + end) + + + it("single dir conflict second conflict resolved", function() + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, + }) + + n.feed( + "2" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, + }) + + n.feed( + "R" + ) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d2" } }, pos = 21, } }, + }) + + n.feed( + "1_copy", + "gg", + "E" + ) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +   d1_copy │~ | +  d1f1 │~ | +  d1f2 │~ | +   d2 │~ | +  d2f1 │~ | +   d3 │~ | +  d3f1 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*9 +NvimTree_1 [-] [No Name] | + | + ]], + }) + end) + + -- TODO multiple, needs same conflict checking as single, as the codepaths in Clipboard:resolve_conflicts are different + + -- TODO test API +end) + +-- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/paste/copy_spec.lua b/test/nvt/func/fs/paste/copy_spec.lua deleted file mode 100644 index 4795d82c8d9..00000000000 --- a/test/nvt/func/fs/paste/copy_spec.lua +++ /dev/null @@ -1,110 +0,0 @@ -local t = require("test.testutil") -local nf = require("test.nvt.func.fixtures") -local na = require("test.nvt.func.asserts") -local n = require("test.functional.testnvim")() - --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global - ---- @type test.functional.ui.screen -local screen - - -before_each(function() - screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) -end) - - -describe("fs.paste.node copy", function() - it("single file", function() - n.feed( - ":NvimTreeOpen", - "", - "", - "", - "", - "c", - "", - "p" - ) - - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | -   d2 │~ | -   d3 │~ | -  d3f1 │~ | - ^  f1 │~ | -  f1 │~ | -  f2 │~ | -~ │~ |*14 -NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | - ]], - }) - - na.file_exists("/tmp/nvt_func/data/f1") - na.file_exists("/tmp/nvt_func/data/d3/f1") - end) - - - it("single dir", function() - n.feed( - ":NvimTreeOpen", - "", - "c", - "", - "p", - "E" - ) - - screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | -   d2 │~ | - ^   d1 │~ | -  d1f1 │~ | -  d1f2 │~ | -  d2f1 │~ | -   d3 │~ | -  f1 │~ | -  f2 │~ | -~ │~ |*12 -NvimTree_1 [-] [No Name] | -[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | - ]], - }) - - na.dir_exists("/tmp/nvt_func/data/d2/d1") - na.file_exists("/tmp/nvt_func/data/d2/d1/d1f1") - na.file_exists("/tmp/nvt_func/data/d2/d1/d1f2") - - na.dir_exists("/tmp/nvt_func/data/d1") - end) - - - it("single dir exists", function() - n.feed( - ":NvimTreeOpen", - "", - "c", - "", - "p" - ) - - screen:expect({ - mode = "cmdline_normal", - cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, - }) - end) -end) - --- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index 813a8d52081..3c0efb9a70d 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -20,7 +20,7 @@ end) describe("fs.paste.node cut", function() - it("cut single dir", function() + it("single dir", function() n.feed( ":NvimTreeOpen", "", @@ -31,6 +31,7 @@ describe("fs.paste.node cut", function() ) screen:expect({ + cmdline = {}, attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | @@ -56,7 +57,7 @@ NvimTree_1 [-] [No Name] end) - it("cut single file", function() + it("single file", function() n.feed( ":NvimTreeOpen", "", @@ -69,6 +70,7 @@ NvimTree_1 [-] [No Name] ) screen:expect({ + cmdline = {}, attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | @@ -88,6 +90,10 @@ NvimTree_1 [-] [No Name] na.not_path_exists("/tmp/nvt_func/data/f1") end) + + -- TODO complete as per copied + + -- TODO test API end) -- vim:colorcolumn=80 From a5ba067050630e16f1dd52218b5b1a8245c719ab Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 7 Oct 2026 10:58:38 +1100 Subject: [PATCH 106/154] test: fs.paste cut tests buffer moved --- test/nvt/func/fs/paste/copied_spec.lua | 3 +- test/nvt/func/fs/paste/cut_spec.lua | 41 ++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 5119f8f3c17..8281df45d81 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -199,7 +199,6 @@ NvimTree_1 [-] [No Name] end) - -- TODO BUG this should prompt again when the file exists it("single dir conflict second conflict overwrite", function() n.feed( ":NvimTreeOpen", @@ -374,6 +373,8 @@ NvimTree_1 [-] [No Name] -- TODO multiple, needs same conflict checking as single, as the codepaths in Clipboard:resolve_conflicts are different + -- TODO partial partition + -- TODO test API end) diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index 3c0efb9a70d..1eca69d516c 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -14,8 +14,14 @@ local it = t.it or it local screen +-- common copy/paste codepaths are tested in copied_spec.lua + + before_each(function() - screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) + screen = nf.create_session(nil, nil, nil, { ext_cmdline = true, }) + + local Event = require("nvim-tree._meta.api.events").Event + nf.event_subscribe(Event.NodeRenamed) end) @@ -54,6 +60,14 @@ NvimTree_1 [-] [No Name] na.file_exists("/tmp/nvt_func/data/d2/d1/d1f2") na.not_path_exists("/tmp/nvt_func/data/d1") + + na.events_received({ { + event_type = "NodeRenamed", + payload = { + old_name = "/tmp/nvt_func/data/d1", + new_name = "/tmp/nvt_func/data/d2/d1", + }, + }, }) end) @@ -65,6 +79,8 @@ NvimTree_1 [-] [No Name] "", "", "x", + "", + "", "", "p" ) @@ -73,7 +89,7 @@ NvimTree_1 [-] [No Name] cmdline = {}, attr_ids = {}, grid = [[ - /tmp/nvt_func/data/.. │ | + /tmp/nvt_func/data/.. │f1 |   d1 │~ |   d2 │~ |   d3 │~ | @@ -81,7 +97,7 @@ NvimTree_1 [-] [No Name] ^  f1 │~ |  f2 │~ | ~ │~ |*15 -NvimTree_1 [-] [No Name] | +NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 | [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | ]], }) @@ -89,9 +105,24 @@ NvimTree_1 [-] [No Name] na.file_exists("/tmp/nvt_func/data/d3/f1") na.not_path_exists("/tmp/nvt_func/data/f1") - end) - -- TODO complete as per copied + na.events_received({ { + event_type = "NodeRenamed", + payload = { + old_name = "/tmp/nvt_func/data/f1", + new_name = "/tmp/nvt_func/data/d3/f1", + }, + }, }) + + t.eq(true, + vim.tbl_contains(n.api.nvim_list_bufs(), + function(buf) + return n.api.nvim_buf_get_name(buf) == "/tmp/nvt_func/data/d3/f1" and n.api.nvim_buf_is_loaded(buf) + end, { predicate = true } + ), + "buffer for /tmp/nvt_func/data/d3/f1 present and loaded" + ) + end) -- TODO test API end) From ccae550e1f63d2165e531dcedc9a25551270704b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 7 Oct 2026 12:00:44 +1100 Subject: [PATCH 107/154] test: fs.paste API tests --- test/nvt/func/fs/paste/copied_spec.lua | 12 ++--- test/nvt/func/fs/paste/cut_spec.lua | 75 +++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 8281df45d81..f68ef768820 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -18,6 +18,12 @@ before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) end) +-- common copy/paste codepaths are tested here except for API + +-- TODO multiple, needs same conflict checking as single, as the codepaths in Clipboard:resolve_conflicts are different + +-- TODO partial partition + describe("fs.paste.node copied", function() it("single file", function() @@ -370,12 +376,6 @@ NvimTree_1 [-] [No Name] ]], }) end) - - -- TODO multiple, needs same conflict checking as single, as the codepaths in Clipboard:resolve_conflicts are different - - -- TODO partial partition - - -- TODO test API end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index 1eca69d516c..d4ce6279f83 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -14,7 +14,7 @@ local it = t.it or it local screen --- common copy/paste codepaths are tested in copied_spec.lua +-- common copy/paste codepaths are tested in copied_spec.lua except for API before_each(function() @@ -124,7 +124,78 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 ) end) - -- TODO test API + + it("api clipboard", function() + n.feed( + ":NvimTreeOpen", + "", + "x", + "" + ) + + n.exec_lua(function() + require("nvim-tree.api").fs.paste() + end) + + na.dir_exists("/tmp/nvt_func/data/d2/d1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f2") + + na.not_path_exists("/tmp/nvt_func/data/d1") + + na.events_received({ { + event_type = "NodeRenamed", + payload = { + old_name = "/tmp/nvt_func/data/d1", + new_name = "/tmp/nvt_func/data/d2/d1", + }, + }, }) + end) + + + it("api node under cursor", function() + n.feed( + ":NvimTreeOpen", + "", + "x", + "" + ) + + n.exec_lua(function() + require("nvim-tree.api").fs.paste() + end) + + screen:expect({ + cmdline = {}, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d2 │~ | + ^   d1 │~ | +  d2f1 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*15 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d2/d1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f1") + na.file_exists("/tmp/nvt_func/data/d2/d1/d1f2") + + na.not_path_exists("/tmp/nvt_func/data/d1") + + na.events_received({ { + event_type = "NodeRenamed", + payload = { + old_name = "/tmp/nvt_func/data/d1", + new_name = "/tmp/nvt_func/data/d2/d1", + }, + }, }) + end) end) -- vim:colorcolumn=80 From 7ee7ae3c37f9cdff350ea2f22ac525f4bb0b50c8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 9 Oct 2026 10:12:31 +1100 Subject: [PATCH 108/154] test: remove TODO from BUGs --- test/nvt/func/fs/create/dir_spec.lua | 8 ++++---- test/nvt/func/fs/create/file_spec.lua | 4 ++-- test/nvt/func/fs/cut/node_spec.lua | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index f4362bea58a..f36293f0295 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -105,7 +105,7 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/direct1/direct2") na.events_received({ - -- TODO BUG this should be "/tmp/nvt_func/data/direct1/" + -- BUG this should be "/tmp/nvt_func/data/direct1/" { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct1/direct2/", }, }, { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/direct1/direct2/", }, }, }) @@ -138,7 +138,7 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/d1/indirect1/indirect2") na.events_received({ - -- TODO BUG this should be "/tmp/nvt_func/data/d1/indirect1/" + -- BUG this should be "/tmp/nvt_func/data/d1/indirect1/" { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", }, }, { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect1/indirect2/", }, }, }) @@ -175,8 +175,8 @@ NvimTree_1 [-] [No Name] "d1/d1f1/" ) - -- TODO BUG this fails but shows message "/tmp/nvt_func/data/d1/d1f1/ was properly created" and focuses the file - -- TODO add similar test for multiple dirs when fixed + -- BUG this fails but shows message "/tmp/nvt_func/data/d1/d1f1/ was properly created" and focuses the file + -- add similar test for multiple dirs when fixed screen:expect({ attr_ids = {}, grid = [[ diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 083c576920e..144ab6092bb 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -158,7 +158,7 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/d1") na.events_received({ - -- TODO BUG this should be "/tmp/nvt_func/data/newdir/" + -- BUG this should be "/tmp/nvt_func/data/newdir/" { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/newdir/newfile", }, }, { event_type = "WillCreateFile", payload = { fname = "/tmp/nvt_func/data/newdir/newfile", }, }, { event_type = "FileCreated", payload = { fname = "/tmp/nvt_func/data/newdir/newfile", }, }, @@ -174,7 +174,7 @@ NvimTree_1 [-] [No Name] "/foo" ) - -- TODO BUG this fails but shows message "/foo was properly created" + -- BUG this fails but shows message "/foo was properly created" na.events_received({ { event_type = "WillCreateFile", payload = { fname = "/foo", }, }, diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index cffc264c422..e2026b53890 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -10,7 +10,7 @@ local it = t.it or it ---@diagnostic enable: undefined-global --- TODO BUG singe operations report "added to clipboard", not "cut to clipboard" as per bulk operations +-- BUG singe operations report "added to clipboard", not "cut to clipboard" as per bulk operations --- @type test.functional.ui.screen From 46c3302c6fd6ca1b61e3484b197548bedfd4433c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 9 Oct 2026 10:33:29 +1100 Subject: [PATCH 109/154] test: cut_spec uses internal API pending resolution of #3362 --- test/nvt/func/fs/create/prompt_spec.lua | 4 +- test/nvt/func/fs/paste/cut_spec.lua | 50 +++++++++++++++++++------ 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index 3b554802684..e1ff9607c3e 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -33,7 +33,7 @@ describe("fs.create prompt", function() end) - it("tree not focused", function() + it("api tree not focused", function() n.feed( ":NvimTreeOpen", "", @@ -83,8 +83,6 @@ NvimTree_1 [-] [No Name] ]], }) end) - - -- TODO test API end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index d4ce6279f83..12628921456 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -125,7 +125,7 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 end) - it("api clipboard", function() + it("api node under cursor", function() n.feed( ":NvimTreeOpen", "", @@ -137,6 +137,23 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 require("nvim-tree.api").fs.paste() end) + screen:expect({ + cmdline = {}, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d2 │~ | + ^   d1 │~ | +  d2f1 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*15 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | + ]], + }) + na.dir_exists("/tmp/nvt_func/data/d2/d1") na.file_exists("/tmp/nvt_func/data/d2/d1/d1f1") na.file_exists("/tmp/nvt_func/data/d2/d1/d1f2") @@ -153,16 +170,25 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 end) - it("api node under cursor", function() + it("api node specified", function() n.feed( ":NvimTreeOpen", "", - "x", - "" + "x" ) n.exec_lua(function() - require("nvim-tree.api").fs.paste() + -- BUG #3362, replace with commented below when complete + local explorer = require("nvim-tree.core").get_explorer() + if explorer then + local node = explorer.nodes[3] -- d3 + explorer.clipboard:paste(node) + end + + -- local api = require("nvim-tree.api") + -- local explorer = api.tree.get_nodes() + -- local node = explorer.nodes[3] -- d3 + -- api.fs.paste(node) end) screen:expect({ @@ -170,10 +196,10 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | -   d2 │~ | +   d2 │~ | +   d3 │~ | ^   d1 │~ | -  d2f1 │~ | -   d3 │~ | +  d3f1 │~ |  f1 │~ |  f2 │~ | ~ │~ |*15 @@ -182,9 +208,9 @@ NvimTree_1 [-] [No Name] ]], }) - na.dir_exists("/tmp/nvt_func/data/d2/d1") - na.file_exists("/tmp/nvt_func/data/d2/d1/d1f1") - na.file_exists("/tmp/nvt_func/data/d2/d1/d1f2") + na.dir_exists("/tmp/nvt_func/data/d3/d1") + na.file_exists("/tmp/nvt_func/data/d3/d1/d1f1") + na.file_exists("/tmp/nvt_func/data/d3/d1/d1f2") na.not_path_exists("/tmp/nvt_func/data/d1") @@ -192,7 +218,7 @@ NvimTree_1 [-] [No Name] event_type = "NodeRenamed", payload = { old_name = "/tmp/nvt_func/data/d1", - new_name = "/tmp/nvt_func/data/d2/d1", + new_name = "/tmp/nvt_func/data/d3/d1", }, }, }) end) From 7220d22ab47acb7e94b80d1ae7a34b985e65c974 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 9 Oct 2026 12:01:45 +1100 Subject: [PATCH 110/154] test: paste multiple copied --- test/nvt/func/fs/paste/copied_spec.lua | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index f68ef768820..7aae5c722bc 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -61,6 +61,59 @@ NvimTree_1 [-] [No Name] end) + it("multiple files", function() + n.exec_lua(function() + require("nvim-tree.api").tree.open() + end) + + n.feed( + "", + "", + "", + "", + "", + "" + ) + + n.exec_lua(function() + require("nvim-tree.api").fs.copy.node() + end) + + n.feed( + "", + "" + ) + + n.exec_lua(function() + require("nvim-tree.api").fs.paste() + end) + + screen:expect({ + cmdline = {}, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d3 │~ | +  d3f1 │~ | +  f1 │~ | + ^  f2 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*13 +NvimTree_1 [-] [No Name] | +[NvimTree] 2 nodes added to clipboard. | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/f1") + na.file_exists("/tmp/nvt_func/data/f2") + na.file_exists("/tmp/nvt_func/data/d3/f1") + na.file_exists("/tmp/nvt_func/data/d3/f2") + end) + + it("single dir", function() n.feed( ":NvimTreeOpen", From e72af3e00fa8ca30ecd466283312eab370ef4447 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 9 Oct 2026 12:32:18 +1100 Subject: [PATCH 111/154] test: copied_spec uses synchronous tree calls --- test/nvt/func/fs/paste/copied_spec.lua | 120 +++++++++++++------------ 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 7aae5c722bc..a6b34936069 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -27,16 +27,21 @@ end) describe("fs.paste.node copied", function() it("single file", function() - n.feed( - ":NvimTreeOpen", - "", - "", - "", - "", - "c", - "", - "p" - ) + n.exec_lua(function() + require("nvim-tree.api").tree.open() + end) + + n.feed("") + + n.exec_lua(function() + require("nvim-tree.api").fs.copy.node() + end) + + n.feed("") + + n.exec_lua(function() + require("nvim-tree.api").fs.paste() + end) screen:expect({ cmdline = {}, @@ -67,10 +72,7 @@ NvimTree_1 [-] [No Name] end) n.feed( - "", - "", - "", - "", + "", "", "" ) @@ -79,10 +81,7 @@ NvimTree_1 [-] [No Name] require("nvim-tree.api").fs.copy.node() end) - n.feed( - "", - "" - ) + n.feed("") n.exec_lua(function() require("nvim-tree.api").fs.paste() @@ -115,34 +114,39 @@ NvimTree_1 [-] [No Name] it("single dir", function() - n.feed( - ":NvimTreeOpen", - "", - "c", - "", - "p", - "gg", - "E" - ) + n.exec_lua(function() + require("nvim-tree.api").tree.open() + end) + + n.feed("") + + n.exec_lua(function() + require("nvim-tree.api").fs.copy.node() + end) + + n.feed("") + + n.exec_lua(function() + require("nvim-tree.api").fs.paste() + end) + + n.feed("") screen:expect({ cmdline = {}, attr_ids = {}, grid = [[ - ^/tmp/nvt_func/data/.. │ | -   d1 │~ | -  d1f1 │~ | -  d1f2 │~ | + /tmp/nvt_func/data/.. │ | +   d1 │~ |   d2 │~ | -   d1 │~ | + ^   d1 │~ |  d1f1 │~ |  d1f2 │~ |  d2f1 │~ | -   d3 │~ | -  d3f1 │~ | +   d3 │~ |  f1 │~ |  f2 │~ | -~ │~ |*9 +~ │~ |*12 NvimTree_1 [-] [No Name] | [NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | ]], @@ -157,43 +161,40 @@ NvimTree_1 [-] [No Name] it("single dir conflict resolved", function() - n.feed( - ":NvimTreeOpen", - "", - "c", - "", - "p" - ) + n.exec_lua(function() + require("nvim-tree.api").tree.open() + end) + + n.feed("") + + n.exec_lua(function() + require("nvim-tree.api").fs.copy.node() + end) + + n.feed("") + + -- TODO need a mechanism to await feedback + n.feed("p") screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - n.feed( - "_copy", - "gg", - "E" - ) + n.feed("_copy") screen:expect({ cmdline = { { abort = true } }, attr_ids = {}, grid = [[ - ^/tmp/nvt_func/data/.. │ | -   d1 │~ | -  d1f1 │~ | -  d1f2 │~ | -   d1_copy │~ | -  d1f1 │~ | -  d1f2 │~ | -   d2 │~ | -  d2f1 │~ | -   d3 │~ | -  d3f1 │~ | + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d1_copy │~ | +   d2 │~ | +   d3 │~ |  f1 │~ |  f2 │~ | -~ │~ |*9 +~ │~ |*15 NvimTree_1 [-] [No Name] | | ]], @@ -208,6 +209,7 @@ NvimTree_1 [-] [No Name] na.file_exists("/tmp/nvt_func/data/d1_copy/d1f1") end) + -- TODO replace remainder of n.feed calls it("single dir conflict cancelled", function() n.feed( From da165eb5ae202c28c49595c534a28943b63fa1a9 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 12 Oct 2026 12:24:44 +1100 Subject: [PATCH 112/154] Revert "test: copied_spec uses synchronous tree calls" This reverts commit e72af3e00fa8ca30ecd466283312eab370ef4447. --- test/nvt/func/fs/paste/copied_spec.lua | 120 ++++++++++++------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index a6b34936069..7aae5c722bc 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -27,21 +27,16 @@ end) describe("fs.paste.node copied", function() it("single file", function() - n.exec_lua(function() - require("nvim-tree.api").tree.open() - end) - - n.feed("") - - n.exec_lua(function() - require("nvim-tree.api").fs.copy.node() - end) - - n.feed("") - - n.exec_lua(function() - require("nvim-tree.api").fs.paste() - end) + n.feed( + ":NvimTreeOpen", + "", + "", + "", + "", + "c", + "", + "p" + ) screen:expect({ cmdline = {}, @@ -72,7 +67,10 @@ NvimTree_1 [-] [No Name] end) n.feed( - "", + "", + "", + "", + "", "", "" ) @@ -81,7 +79,10 @@ NvimTree_1 [-] [No Name] require("nvim-tree.api").fs.copy.node() end) - n.feed("") + n.feed( + "", + "" + ) n.exec_lua(function() require("nvim-tree.api").fs.paste() @@ -114,39 +115,34 @@ NvimTree_1 [-] [No Name] it("single dir", function() - n.exec_lua(function() - require("nvim-tree.api").tree.open() - end) - - n.feed("") - - n.exec_lua(function() - require("nvim-tree.api").fs.copy.node() - end) - - n.feed("") - - n.exec_lua(function() - require("nvim-tree.api").fs.paste() - end) - - n.feed("") + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p", + "gg", + "E" + ) screen:expect({ cmdline = {}, attr_ids = {}, grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | +  d1f2 │~ |   d2 │~ | - ^   d1 │~ | +   d1 │~ |  d1f1 │~ |  d1f2 │~ |  d2f1 │~ | -   d3 │~ | +   d3 │~ | +  d3f1 │~ |  f1 │~ |  f2 │~ | -~ │~ |*12 +~ │~ |*9 NvimTree_1 [-] [No Name] | [NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | ]], @@ -161,40 +157,43 @@ NvimTree_1 [-] [No Name] it("single dir conflict resolved", function() - n.exec_lua(function() - require("nvim-tree.api").tree.open() - end) - - n.feed("") - - n.exec_lua(function() - require("nvim-tree.api").fs.copy.node() - end) - - n.feed("") - - -- TODO need a mechanism to await feedback - n.feed("p") + n.feed( + ":NvimTreeOpen", + "", + "c", + "", + "p" + ) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - n.feed("_copy") + n.feed( + "_copy", + "gg", + "E" + ) screen:expect({ cmdline = { { abort = true } }, attr_ids = {}, grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | - ^  d1_copy │~ | -   d2 │~ | -   d3 │~ | + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +   d1_copy │~ | +  d1f1 │~ | +  d1f2 │~ | +   d2 │~ | +  d2f1 │~ | +   d3 │~ | +  d3f1 │~ |  f1 │~ |  f2 │~ | -~ │~ |*15 +~ │~ |*9 NvimTree_1 [-] [No Name] | | ]], @@ -209,7 +208,6 @@ NvimTree_1 [-] [No Name] na.file_exists("/tmp/nvt_func/data/d1_copy/d1f1") end) - -- TODO replace remainder of n.feed calls it("single dir conflict cancelled", function() n.feed( From 5453abdf9d101011b2d4fdb637f5d29e5305a89c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 12 Oct 2026 13:46:26 +1100 Subject: [PATCH 113/154] test: use poke_eventloop to snc fs/paste tests, needs a better solution --- test/nvt/func/README.md | 19 +++++++++++++ test/nvt/func/fs/create/prompt_spec.lua | 1 + test/nvt/func/fs/paste/copied_spec.lua | 37 ++++++++++++++++--------- test/nvt/func/fs/paste/cut_spec.lua | 4 +++ 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/test/nvt/func/README.md b/test/nvt/func/README.md index 9c35ef7e8b8..b83e1bcc2e6 100644 --- a/test/nvt/func/README.md +++ b/test/nvt/func/README.md @@ -27,3 +27,22 @@ Write the test as per Text Only and execute; it will fail. Use `Snapshot: screen:expect([[` contents from test log as the `grid`, visually validating that it matches the screen dump. +# Test Inputs + +## Synchronisation + +TODO: this isn't great and results in a lot of test boilerplate; maybe write a `feed_sync` util, if there is not anything available +TODO: how to handle asynchronous operations e.g. fs/git update + +### `feed()` + +`test.functional.testnvim` `feed` is asynchronous and does not block the test thread: all inputs are all sent consecutively via `nvim_input()` and the function returns immediately. Nvim will effectively execute each input synchronously when the input blocks the main loop i.e. no threads or processes spawned. + +Before asserts, `screen:expect` etc., `poke_eventloop()` should be called, to ensure that all inputs have been processed by the main loop. + +_Exception:_ visual operations (e.g. select multiple for copy) do not appear to be executed synchronously. `poke_eventloop()` after those inputs to ensure synchronisation. + +### `exec_lua()` + +`test.functional.testnvim` `exec_lua` is synchronous: it will block the test thread until completion. + diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index e1ff9607c3e..ee5acb24189 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -38,6 +38,7 @@ describe("fs.create prompt", function() ":NvimTreeOpen", "", "", + -- TODO why can't we execute this from exec_lua ? ":lua require('nvim-tree.api').fs.create()" ) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 7aae5c722bc..76cde9e6161 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -37,6 +37,7 @@ describe("fs.paste.node copied", function() "", "p" ) + n.poke_eventloop() screen:expect({ cmdline = {}, @@ -62,11 +63,9 @@ NvimTree_1 [-] [No Name] it("multiple files", function() - n.exec_lua(function() - require("nvim-tree.api").tree.open() - end) - + -- visual selection is separate operation before copy to ensure synchronised state n.feed( + ":NvimTreeOpen", "", "", "", @@ -74,19 +73,15 @@ NvimTree_1 [-] [No Name] "", "" ) - - n.exec_lua(function() - require("nvim-tree.api").fs.copy.node() - end) + n.poke_eventloop() n.feed( + "c", "", - "" + "", + "p" ) - - n.exec_lua(function() - require("nvim-tree.api").fs.paste() - end) + n.poke_eventloop() screen:expect({ cmdline = {}, @@ -124,6 +119,7 @@ NvimTree_1 [-] [No Name] "gg", "E" ) + n.poke_eventloop() screen:expect({ cmdline = {}, @@ -164,6 +160,7 @@ NvimTree_1 [-] [No Name] "", "p" ) + n.poke_eventloop() screen:expect({ mode = "cmdline_normal", @@ -175,6 +172,7 @@ NvimTree_1 [-] [No Name] "gg", "E" ) + n.poke_eventloop() screen:expect({ cmdline = { { abort = true } }, @@ -217,6 +215,7 @@ NvimTree_1 [-] [No Name] "", "p" ) + n.poke_eventloop() screen:expect({ mode = "cmdline_normal", @@ -226,6 +225,7 @@ NvimTree_1 [-] [No Name] n.feed( "" ) + n.poke_eventloop() screen:expect({ cmdline = { { abort = true } }, @@ -235,6 +235,7 @@ NvimTree_1 [-] [No Name] "gg", "E" ) + n.poke_eventloop() screen:expect({ cmdline = {}, @@ -266,6 +267,7 @@ NvimTree_1 [-] [No Name] "", "p" ) + n.poke_eventloop() screen:expect({ mode = "cmdline_normal", @@ -275,6 +277,7 @@ NvimTree_1 [-] [No Name] n.feed( "2" ) + n.poke_eventloop() screen:expect({ mode = "cmdline_normal", @@ -284,6 +287,7 @@ NvimTree_1 [-] [No Name] n.feed( "y" ) + n.poke_eventloop() screen:expect({ cmdline = { { abort = true } }, @@ -326,6 +330,7 @@ Press ENTER or type command to continue^ "", "p" ) + n.poke_eventloop() screen:expect({ mode = "cmdline_normal", @@ -335,6 +340,7 @@ Press ENTER or type command to continue^ n.feed( "2" ) + n.poke_eventloop() screen:expect({ mode = "cmdline_normal", @@ -346,6 +352,7 @@ Press ENTER or type command to continue^ "gg", "E" ) + n.poke_eventloop() screen:expect({ cmdline = { { abort = true } }, @@ -376,6 +383,7 @@ Press ENTER or type command to continue^ "", "p" ) + n.poke_eventloop() screen:expect({ mode = "cmdline_normal", @@ -385,6 +393,7 @@ Press ENTER or type command to continue^ n.feed( "2" ) + n.poke_eventloop() screen:expect({ mode = "cmdline_normal", @@ -394,6 +403,7 @@ Press ENTER or type command to continue^ n.feed( "R" ) + n.poke_eventloop() screen:expect({ mode = "cmdline_normal", @@ -405,6 +415,7 @@ Press ENTER or type command to continue^ "gg", "E" ) + n.poke_eventloop() screen:expect({ cmdline = { { abort = true } }, diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index 12628921456..d2c8aea6bab 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -35,6 +35,7 @@ describe("fs.paste.node cut", function() "p", "E" ) + n.poke_eventloop() screen:expect({ cmdline = {}, @@ -84,6 +85,7 @@ NvimTree_1 [-] [No Name] "", "p" ) + n.poke_eventloop() screen:expect({ cmdline = {}, @@ -132,6 +134,7 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 "x", "" ) + n.poke_eventloop() n.exec_lua(function() require("nvim-tree.api").fs.paste() @@ -176,6 +179,7 @@ NvimTree_1 [-] [No Name] "", "x" ) + n.poke_eventloop() n.exec_lua(function() -- BUG #3362, replace with commented below when complete From f619d9941aa198aed15422b9c6314baa8170c8ff Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 13 Oct 2026 11:38:18 +1100 Subject: [PATCH 114/154] test: add utils with feed_sync, needs migration for all tests --- test/nvt/func/README.md | 15 +-- test/nvt/func/fs/paste/copied_spec.lua | 133 ++++++++++--------------- test/nvt/func/fs/paste/cut_spec.lua | 31 +++--- test/nvt/func/util.lua | 21 ++++ 4 files changed, 93 insertions(+), 107 deletions(-) create mode 100644 test/nvt/func/util.lua diff --git a/test/nvt/func/README.md b/test/nvt/func/README.md index b83e1bcc2e6..0da5d3fa65d 100644 --- a/test/nvt/func/README.md +++ b/test/nvt/func/README.md @@ -29,20 +29,11 @@ Use `Snapshot: screen:expect([[` contents from test log as the `grid`, visually # Test Inputs -## Synchronisation - -TODO: this isn't great and results in a lot of test boilerplate; maybe write a `feed_sync` util, if there is not anything available TODO: how to handle asynchronous operations e.g. fs/git update -### `feed()` - -`test.functional.testnvim` `feed` is asynchronous and does not block the test thread: all inputs are all sent consecutively via `nvim_input()` and the function returns immediately. Nvim will effectively execute each input synchronously when the input blocks the main loop i.e. no threads or processes spawned. - -Before asserts, `screen:expect` etc., `poke_eventloop()` should be called, to ensure that all inputs have been processed by the main loop. - -_Exception:_ visual operations (e.g. select multiple for copy) do not appear to be executed synchronously. `poke_eventloop()` after those inputs to ensure synchronisation. +## Synchronisation -### `exec_lua()` +The Nvim functional test framework's inputs are handled asynchronously via the commonly used `test.functional.testnvim` `feed` (non-deferred). It will execute all the inputs _immediately_ without waiting for them to complete, most notably lua callbacks such as nvim-tree mappings as well as some visual mode operations. See `:help api-fast` -`test.functional.testnvim` `exec_lua` is synchronous: it will block the test thread until completion. +Prefer `test.nvt.func.util` `feed_sync` to feed keys synchronously (deferred), blocking the test thread and instance until the instance's main loop is complete. diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 76cde9e6161..46d08fea29c 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -1,7 +1,7 @@ local t = require("test.testutil") local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local n = require("test.functional.testnvim")() +local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global @@ -27,7 +27,7 @@ end) describe("fs.paste.node copied", function() it("single file", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "", @@ -35,9 +35,8 @@ describe("fs.paste.node copied", function() "", "c", "", - "p" - ) - n.poke_eventloop() + "p", + }) screen:expect({ cmdline = {}, @@ -63,25 +62,19 @@ NvimTree_1 [-] [No Name] it("multiple files", function() - -- visual selection is separate operation before copy to ensure synchronised state - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "", "", "", "", - "" - ) - n.poke_eventloop() - - n.feed( + "", "c", "", "", - "p" - ) - n.poke_eventloop() + "p", + }) screen:expect({ cmdline = {}, @@ -110,16 +103,15 @@ NvimTree_1 [-] [No Name] it("single dir", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "c", "", "p", "gg", - "E" - ) - n.poke_eventloop() + "E", + }) screen:expect({ cmdline = {}, @@ -153,26 +145,24 @@ NvimTree_1 [-] [No Name] it("single dir conflict resolved", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "c", "", - "p" - ) - n.poke_eventloop() + "p", + }) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - n.feed( + nu.feed_sync({ "_copy", "gg", - "E" - ) - n.poke_eventloop() + "E", + }) screen:expect({ cmdline = { { abort = true } }, @@ -208,34 +198,31 @@ NvimTree_1 [-] [No Name] it("single dir conflict cancelled", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "c", "", - "p" - ) - n.poke_eventloop() + "p", + }) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - n.feed( - "" - ) - n.poke_eventloop() + nu.feed_sync({ + "", + }) screen:expect({ cmdline = { { abort = true } }, }) - n.feed( + nu.feed_sync({ "gg", - "E" - ) - n.poke_eventloop() + "E", + }) screen:expect({ cmdline = {}, @@ -260,34 +247,31 @@ NvimTree_1 [-] [No Name] it("single dir conflict second conflict overwrite", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "c", "", - "p" - ) - n.poke_eventloop() + "p", + }) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - n.feed( + nu.feed_sync({ "2" - ) - n.poke_eventloop() + }) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) - n.feed( - "y" - ) - n.poke_eventloop() + nu.feed_sync({ + "y", + }) screen:expect({ cmdline = { { abort = true } }, @@ -323,36 +307,33 @@ Press ENTER or type command to continue^ it("single dir conflict second conflict cancel", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "c", "", - "p" - ) - n.poke_eventloop() + "p", + }) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - n.feed( - "2" - ) - n.poke_eventloop() + nu.feed_sync({ + "2", + }) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) - n.feed( + nu.feed_sync({ "n", "gg", - "E" - ) - n.poke_eventloop() + "E", + }) screen:expect({ cmdline = { { abort = true } }, @@ -376,46 +357,42 @@ Press ENTER or type command to continue^ it("single dir conflict second conflict resolved", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "c", "", - "p" - ) - n.poke_eventloop() + "p", + }) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - n.feed( - "2" - ) - n.poke_eventloop() + nu.feed_sync({ + "2", + }) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) - n.feed( - "R" - ) - n.poke_eventloop() + nu.feed_sync({ + "R", + }) screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d2" } }, pos = 21, } }, }) - n.feed( + nu.feed_sync({ "1_copy", "gg", - "E" - ) - n.poke_eventloop() + "E", + }) screen:expect({ cmdline = { { abort = true } }, diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index d2c8aea6bab..404eddccdb1 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -1,7 +1,8 @@ local t = require("test.testutil") +local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local n = require("test.functional.testnvim")() +local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global @@ -27,15 +28,14 @@ end) describe("fs.paste.node cut", function() it("single dir", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "x", "", "p", - "E" - ) - n.poke_eventloop() + "E", + }) screen:expect({ cmdline = {}, @@ -73,7 +73,7 @@ NvimTree_1 [-] [No Name] it("single file", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "", @@ -83,9 +83,8 @@ NvimTree_1 [-] [No Name] "", "", "", - "p" - ) - n.poke_eventloop() + "p", + }) screen:expect({ cmdline = {}, @@ -128,13 +127,12 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 it("api node under cursor", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "x", - "" - ) - n.poke_eventloop() + "", + }) n.exec_lua(function() require("nvim-tree.api").fs.paste() @@ -174,12 +172,11 @@ NvimTree_1 [-] [No Name] it("api node specified", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", - "x" - ) - n.poke_eventloop() + "x", + }) n.exec_lua(function() -- BUG #3362, replace with commented below when complete diff --git a/test/nvt/func/util.lua b/test/nvt/func/util.lua new file mode 100644 index 00000000000..8031f8b08b1 --- /dev/null +++ b/test/nvt/func/util.lua @@ -0,0 +1,21 @@ +local n = require("test.functional.testnvim")() + +local M = {} + + +---Feed keys synchronously (deferred), blocking the test thread and instance until the instance's main loop is complete. +---This is needed as api-fast input will execute lua callbacks (such as nvim-tree mappings) then execute the next input without waiting for the callback to complete. +---Calls feedkeys() (non-deferred, api-fast) then poke_eventloop() for each input passed. +---See :help api-fast +---@param inputs string[] +function M.feed_sync(inputs) + for _, v in ipairs(inputs) do + -- api-fast, does not wait for callbacks or input to complete + n.feed(v) + + -- defer until complete + n.poke_eventloop() + end +end + +return M From d108dda29274b43830f2a8fab01b15f78bafdbb4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 13 Oct 2026 12:10:43 +1100 Subject: [PATCH 115/154] test: use feed_sync for all functests --- test/nvt/func/fs/copy/node_spec.lua | 90 +++++++-------- test/nvt/func/fs/create/dir_spec.lua | 50 ++++---- test/nvt/func/fs/create/file_spec.lua | 41 +++---- test/nvt/func/fs/create/prompt_spec.lua | 29 +++-- test/nvt/func/fs/cut/node_spec.lua | 107 ++++++++---------- .../print_clipboard/print_clipboard_spec.lua | 15 +-- 6 files changed, 154 insertions(+), 178 deletions(-) diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index 645389b1fee..24714eca7cf 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -1,6 +1,7 @@ local t = require("test.testutil") -local nf = require("test.nvt.func.fixtures") local n = require("test.functional.testnvim")() +local nf = require("test.nvt.func.fixtures") +local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global @@ -23,13 +24,11 @@ describe("fs.copy.node", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "c" - ) + "", + "c", + }) t.eq("foo", n.fn.getreg("1")) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) @@ -52,12 +51,11 @@ describe("fs.copy.node", function() it("single dir", function() n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "c" - ) + "", + "c", + }) t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) @@ -79,13 +77,11 @@ describe("fs.copy.node", function() it("toggle one", function() n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "c" - ) + "", + "c", + }) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) @@ -103,9 +99,9 @@ NvimTree_1 [-] [No Name] ]], }) - n.feed( - "c" - ) + nu.feed_sync({ + "c", + }) t.eq("", n.fn.getreg("+")) @@ -128,11 +124,11 @@ NvimTree_1 [-] [No Name] it("toggle many", function() n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", - "c" - ) + "c", + }) t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("+")) @@ -150,11 +146,11 @@ NvimTree_1 [-] [No Name] ]], }) - n.feed( + nu.feed_sync({ "", "", - "c" - ) + "c", + }) t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) @@ -186,13 +182,11 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") -- - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "c" - ) + "", + "c", + }) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("1")) t.eq("foo", n.fn.getreg("+")) @@ -217,13 +211,11 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "x" - ) + "", + "x", + }) t.eq("foo", n.fn.getreg("1")) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) @@ -241,9 +233,9 @@ NvimTree_1 [-] [No Name] ]], }) - n.feed( - "c" - ) + nu.feed_sync({ + "c", + }) screen:expect({ grid = [[ @@ -263,18 +255,14 @@ NvimTree_1 [-] [No Name] it("dir overrides file", function() n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "E", - "", - "", - "", + "", "", - "", - "", - "", - "c" - ) + "", + "c", + }) t.eq([[ /tmp/nvt_func/data/d1/d1f2 diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index f36293f0295..0dc2863300f 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -1,7 +1,7 @@ local t = require("test.testutil") local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local n = require("test.functional.testnvim")() +local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global @@ -24,11 +24,11 @@ end) describe("fs.create dir", function() it("single direct", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "direct/" - ) + "direct/", + }) screen:expect({ attr_ids = {}, @@ -52,11 +52,11 @@ NvimTree_1 [-] [No Name] it("single indirect", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "d1/indirect/" - ) + "d1/indirect/", + }) screen:expect({ attr_ids = {}, @@ -81,11 +81,11 @@ NvimTree_1 [-] [No Name] it("multiple direct", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "direct1/direct2/" - ) + "direct1/direct2/", + }) screen:expect({ attr_ids = {}, @@ -113,11 +113,11 @@ NvimTree_1 [-] [No Name] it("multiple indirect", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "d1/indirect1/indirect2/" - ) + "d1/indirect1/indirect2/", + }) screen:expect({ attr_ids = {}, @@ -146,11 +146,11 @@ NvimTree_1 [-] [No Name] it("fails when file exists", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "d1/" - ) + "d1/", + }) screen:expect({ attr_ids = {}, @@ -169,11 +169,11 @@ NvimTree_1 [-] [No Name] it("fails when file exists", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "d1/d1f1/" - ) + "d1/d1f1/", + }) -- BUG this fails but shows message "/tmp/nvt_func/data/d1/d1f1/ was properly created" and focuses the file -- add similar test for multiple dirs when fixed @@ -195,12 +195,12 @@ NvimTree_1 [-] [No Name] it("fails on invalid path", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", "", - "/foo/bar" - ) + "/foo/bar", + }) screen:expect({ attr_ids = {}, @@ -219,12 +219,12 @@ NvimTree_1 [-] [No Name] it("fails when dir exists", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "a", - "" - ) + "", + }) screen:expect({ attr_ids = {}, diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 144ab6092bb..642810714d5 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -1,7 +1,8 @@ local t = require("test.testutil") +local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local n = require("test.functional.testnvim")() +local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global @@ -26,11 +27,11 @@ end) describe("fs.create file", function() it("direct", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "direct" - ) + "direct", + }) screen:expect({ attr_ids = {}, @@ -55,11 +56,11 @@ NvimTree_1 [-] [No Name] it("indirect", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "d1/indirect" - ) + "d1/indirect", + }) screen:expect({ attr_ids = {}, @@ -85,11 +86,11 @@ NvimTree_1 [-] [No Name] it("fails when file exists", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "f1" - ) + "f1", + }) screen:expect({ attr_ids = {}, @@ -110,11 +111,11 @@ NvimTree_1 [-] [No Name] it("fails when dir exists", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "d1" - ) + "d1", + }) screen:expect({ attr_ids = {}, @@ -135,11 +136,11 @@ NvimTree_1 [-] [No Name] it("indirect creates dirs", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", - "newdir/newfile" - ) + "newdir/newfile", + }) screen:expect({ attr_ids = {}, @@ -167,14 +168,16 @@ NvimTree_1 [-] [No Name] it("fails on invalid path", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", "", - "/foo" - ) + }) -- BUG this fails but shows message "/foo was properly created" + n.feed( + "/foo" + ) na.events_received({ { event_type = "WillCreateFile", payload = { fname = "/foo", }, }, diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index ee5acb24189..21d716f30a9 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -1,6 +1,6 @@ local t = require("test.testutil") local nf = require("test.nvt.func.fixtures") -local n = require("test.functional.testnvim")() +local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global @@ -20,11 +20,11 @@ end) describe("fs.create prompt", function() it("tree focused", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", - "a" - ) + "a", + }) screen:expect({ mode = "cmdline_normal", @@ -34,13 +34,13 @@ describe("fs.create prompt", function() it("api tree not focused", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "", -- TODO why can't we execute this from exec_lua ? - ":lua require('nvim-tree.api').fs.create()" - ) + ":lua require('nvim-tree.api').fs.create()", + }) screen:expect({ mode = "cmdline_normal", @@ -50,12 +50,11 @@ describe("fs.create prompt", function() it("file focused", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "a" - ) + "", + "a", + }) screen:expect({ mode = "cmdline_normal", @@ -65,12 +64,12 @@ describe("fs.create prompt", function() it("cancelled", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "a", "foo", - "" - ) + "", + }) screen:expect({ attr_ids = {}, diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index e2026b53890..6b86440e026 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -1,6 +1,7 @@ local t = require("test.testutil") -local nf = require("test.nvt.func.fixtures") local n = require("test.functional.testnvim")() +local nf = require("test.nvt.func.fixtures") +local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global @@ -27,13 +28,11 @@ describe("fs.cut.node", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "x" - ) + "", + "x", + }) t.eq("foo", n.fn.getreg("1")) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) @@ -56,12 +55,11 @@ describe("fs.cut.node", function() it("single dir", function() n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "x" - ) + "", + "x", + }) t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) @@ -82,13 +80,11 @@ describe("fs.cut.node", function() it("toggle one", function() n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "x" - ) + "", + "x", + }) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) @@ -106,9 +102,9 @@ NvimTree_1 [-] [No Name] ]], }) - n.feed( - "x" - ) + nu.feed_sync({ + "x", + }) t.eq("", n.fn.getreg("+")) @@ -131,11 +127,11 @@ NvimTree_1 [-] [No Name] it("toggle many", function() n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", - "x" - ) + "x", + }) t.eq("/tmp/nvt_func/data/d1/", n.fn.getreg("+")) @@ -153,11 +149,11 @@ NvimTree_1 [-] [No Name] ]], }) - n.feed( + nu.feed_sync({ "", "", - "x" - ) + "x", + }) t.eq("/tmp/nvt_func/data/d2/", n.fn.getreg("+")) @@ -189,13 +185,11 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") -- - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "x" - ) + "", + "x", + }) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("1")) t.eq("foo", n.fn.getreg("+")) @@ -220,13 +214,11 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "c" - ) + "", + "c", + }) t.eq("foo", n.fn.getreg("1")) t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) @@ -244,9 +236,9 @@ NvimTree_1 [-] [No Name] ]], }) - n.feed( - "x" - ) + nu.feed_sync({ + "x", + }) screen:expect({ grid = [[ @@ -267,7 +259,7 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "c", @@ -276,8 +268,8 @@ NvimTree_1 [-] [No Name] "", "c", "", - "c" - ) + "c", + }) t.eq("foo", n.fn.getreg("1")) t.eq([[ @@ -299,16 +291,13 @@ NvimTree_1 [-] [No Name] ]], }) - n.feed( + nu.feed_sync({ "gg", "", "", - "", - "", - "", - "", - "x" - ) + "", + "x", + }) screen:expect({ grid = [[ @@ -336,18 +325,14 @@ NvimTree_1 [-] [No Name] it("dir overrides file", function() n.fn.setreg("+", "foo") - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "E", - "", - "", - "", + "", "", - "", - "", - "", - "x" - ) + "", + "x", + }) t.eq([[ /tmp/nvt_func/data/d1/d1f2 diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index 3835770c166..ddc428144a8 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -1,6 +1,7 @@ local t = require("test.testutil") -local nf = require("test.nvt.func.fixtures") local n = require("test.functional.testnvim")() +local nf = require("test.nvt.func.fixtures") +local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global @@ -21,9 +22,9 @@ end) describe("fs.print_clipboard", function() it("none", function() - n.feed( - ":NvimTreeOpen" - ) + nu.feed_sync({ + ":NvimTreeOpen", + }) n.exec_lua(function() require("nvim-tree.api").fs.print_clipboard() @@ -63,7 +64,7 @@ Press ENTER or type command to continue^ it("many", function() - n.feed( + nu.feed_sync({ ":NvimTreeOpen", "", "", @@ -74,8 +75,8 @@ Press ENTER or type command to continue^ "", "c", "", - "x" - ) + "x", + }) n.exec_lua(function() require("nvim-tree.api").fs.print_clipboard() From d2429885812756744fc42f9b23632ba0d5f9a226 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 13 Oct 2026 12:35:43 +1100 Subject: [PATCH 116/154] test: fs.create prompt timing fixes --- test/nvt/func/fs/create/prompt_spec.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index 21d716f30a9..0701db07188 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -1,4 +1,5 @@ local t = require("test.testutil") +local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") @@ -38,10 +39,16 @@ describe("fs.create prompt", function() ":NvimTreeOpen", "", "", - -- TODO why can't we execute this from exec_lua ? - ":lua require('nvim-tree.api').fs.create()", }) + -- schedule this as it blocks on vim.ui.input + n.exec_lua(function() + vim.schedule(require("nvim-tree.api").fs.create) + end) + + -- wait for the input + n.poke_eventloop() + screen:expect({ mode = "cmdline_normal", cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, From 276d20d616e8e7650615607c5019e2ab2a472317 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 13 Oct 2026 12:49:44 +1100 Subject: [PATCH 117/154] test: namespace functionaltest methods so that 0.12 global compatibility may be completely removed --- test/nvt/func/fs/copy/node_spec.lua | 22 ++++++++--------- test/nvt/func/fs/create/dir_spec.lua | 24 +++++++++---------- test/nvt/func/fs/create/file_spec.lua | 20 +++++++--------- test/nvt/func/fs/create/prompt_spec.lua | 16 ++++++------- test/nvt/func/fs/cut/node_spec.lua | 24 +++++++++---------- test/nvt/func/fs/paste/copied_spec.lua | 24 +++++++++---------- test/nvt/func/fs/paste/cut_spec.lua | 16 ++++++------- .../print_clipboard/print_clipboard_spec.lua | 12 ++++------ 8 files changed, 71 insertions(+), 87 deletions(-) diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index 24714eca7cf..f0885805888 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -5,22 +5,20 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session() end) -describe("fs.copy.node", function() - it("single file", function() +t.describe("fs.copy.node", function() + t.it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -48,7 +46,7 @@ describe("fs.copy.node", function() end) - it("single dir", function() + t.it("single dir", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -74,7 +72,7 @@ describe("fs.copy.node", function() end) - it("toggle one", function() + t.it("toggle one", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -121,7 +119,7 @@ NvimTree_1 [-] [No Name] end) - it("toggle many", function() + t.it("toggle many", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -170,7 +168,7 @@ NvimTree_1 [-] [No Name] end) - it("no system clipboard", function() + t.it("no system clipboard", function() n.exec_lua(function() require("nvim-tree").setup({ actions = { @@ -207,7 +205,7 @@ NvimTree_1 [-] [No Name] end) - it("overrides cut", function() + t.it("overrides cut", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -252,7 +250,7 @@ NvimTree_1 [-] [No Name] end) - it("dir overrides file", function() + t.it("dir overrides file", function() n.fn.setreg("+", "foo") nu.feed_sync({ diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 0dc2863300f..3959fc54814 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -5,16 +5,14 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) local Event = require("nvim-tree._meta.api.events").Event @@ -22,8 +20,8 @@ before_each(function() end) -describe("fs.create dir", function() - it("single direct", function() +t.describe("fs.create dir", function() + t.it("single direct", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -51,7 +49,7 @@ NvimTree_1 [-] [No Name] end) - it("single indirect", function() + t.it("single indirect", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -80,7 +78,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple direct", function() + t.it("multiple direct", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -112,7 +110,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple indirect", function() + t.it("multiple indirect", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -145,7 +143,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when file exists", function() + t.it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -168,7 +166,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when file exists", function() + t.it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -194,7 +192,7 @@ NvimTree_1 [-] [No Name] end) - it("fails on invalid path", function() + t.it("fails on invalid path", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -218,7 +216,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when dir exists", function() + t.it("fails when dir exists", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 642810714d5..14183942a6c 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -6,16 +6,14 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session({}, nil, nil, { ext_cmdline = true }) local Event = require("nvim-tree._meta.api.events").Event @@ -25,8 +23,8 @@ before_each(function() end) -describe("fs.create file", function() - it("direct", function() +t.describe("fs.create file", function() + t.it("direct", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -55,7 +53,7 @@ NvimTree_1 [-] [No Name] end) - it("indirect", function() + t.it("indirect", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -85,7 +83,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when file exists", function() + t.it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -110,7 +108,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when dir exists", function() + t.it("fails when dir exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -135,7 +133,7 @@ NvimTree_1 [-] [No Name] end) - it("indirect creates dirs", function() + t.it("indirect creates dirs", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -167,7 +165,7 @@ NvimTree_1 [-] [No Name] end) - it("fails on invalid path", function() + t.it("fails on invalid path", function() nu.feed_sync({ ":NvimTreeOpen", "a", diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index 0701db07188..c55eca79efc 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -5,22 +5,20 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) end) -describe("fs.create prompt", function() - it("tree focused", function() +t.describe("fs.create prompt", function() + t.it("tree focused", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -34,7 +32,7 @@ describe("fs.create prompt", function() end) - it("api tree not focused", function() + t.it("api tree not focused", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -56,7 +54,7 @@ describe("fs.create prompt", function() end) - it("file focused", function() + t.it("file focused", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -70,7 +68,7 @@ describe("fs.create prompt", function() end) - it("cancelled", function() + t.it("cancelled", function() nu.feed_sync({ ":NvimTreeOpen", "a", diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index 6b86440e026..28dc9deec04 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -5,9 +5,7 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global @@ -18,13 +16,13 @@ local it = t.it or it local screen -before_each(function() +t.before_each(function() screen = nf.create_session() end) -describe("fs.cut.node", function() - it("single file", function() +t.describe("fs.cut.node", function() + t.it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -52,7 +50,7 @@ describe("fs.cut.node", function() end) - it("single dir", function() + t.it("single dir", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -77,7 +75,7 @@ describe("fs.cut.node", function() }) end) - it("toggle one", function() + t.it("toggle one", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -124,7 +122,7 @@ NvimTree_1 [-] [No Name] end) - it("toggle many", function() + t.it("toggle many", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -173,7 +171,7 @@ NvimTree_1 [-] [No Name] end) - it("no system clipboard", function() + t.it("no system clipboard", function() n.exec_lua(function() require("nvim-tree").setup({ actions = { @@ -210,7 +208,7 @@ NvimTree_1 [-] [No Name] end) - it("single overrides copy", function() + t.it("single overrides copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -255,7 +253,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple overrides copy", function() + t.it("multiple overrides copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -322,7 +320,7 @@ NvimTree_1 [-] [No Name] end) - it("dir overrides file", function() + t.it("dir overrides file", function() n.fn.setreg("+", "foo") nu.feed_sync({ diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 46d08fea29c..b3bf7bc8f29 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -5,16 +5,14 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) end) @@ -25,8 +23,8 @@ end) -- TODO partial partition -describe("fs.paste.node copied", function() - it("single file", function() +t.describe("fs.paste.node copied", function() + t.it("single file", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -61,7 +59,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple files", function() + t.it("multiple files", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -102,7 +100,7 @@ NvimTree_1 [-] [No Name] end) - it("single dir", function() + t.it("single dir", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -144,7 +142,7 @@ NvimTree_1 [-] [No Name] end) - it("single dir conflict resolved", function() + t.it("single dir conflict resolved", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -197,7 +195,7 @@ NvimTree_1 [-] [No Name] end) - it("single dir conflict cancelled", function() + t.it("single dir conflict cancelled", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -246,7 +244,7 @@ NvimTree_1 [-] [No Name] end) - it("single dir conflict second conflict overwrite", function() + t.it("single dir conflict second conflict overwrite", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -306,7 +304,7 @@ Press ENTER or type command to continue^ end) - it("single dir conflict second conflict cancel", function() + t.it("single dir conflict second conflict cancel", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -356,7 +354,7 @@ Press ENTER or type command to continue^ end) - it("single dir conflict second conflict resolved", function() + t.it("single dir conflict second conflict resolved", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index 404eddccdb1..bd7bbebee41 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -6,9 +6,7 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen @@ -18,7 +16,7 @@ local screen -- common copy/paste codepaths are tested in copied_spec.lua except for API -before_each(function() +t.before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true, }) local Event = require("nvim-tree._meta.api.events").Event @@ -26,8 +24,8 @@ before_each(function() end) -describe("fs.paste.node cut", function() - it("single dir", function() +t.describe("fs.paste.node cut", function() + t.it("single dir", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -72,7 +70,7 @@ NvimTree_1 [-] [No Name] end) - it("single file", function() + t.it("single file", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -126,7 +124,7 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 end) - it("api node under cursor", function() + t.it("api node under cursor", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -171,7 +169,7 @@ NvimTree_1 [-] [No Name] end) - it("api node specified", function() + t.it("api node specified", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index ddc428144a8..0d7184dcc22 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -5,9 +5,7 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global @@ -15,13 +13,13 @@ local it = t.it or it local screen -before_each(function() +t.before_each(function() screen = nf.create_session() end) -describe("fs.print_clipboard", function() - it("none", function() +t.describe("fs.print_clipboard", function() + t.it("none", function() nu.feed_sync({ ":NvimTreeOpen", }) @@ -63,7 +61,7 @@ Press ENTER or type command to continue^ end) - it("many", function() + t.it("many", function() nu.feed_sync({ ":NvimTreeOpen", "", From 69a6a2aeeaf8397361a53b840e4a0355e0901139 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 13 Oct 2026 12:50:30 +1100 Subject: [PATCH 118/154] test: namespace functionaltest methods so that 0.12 global compatibility may be completely removed --- test/nvt/func/fs/copy/node_spec.lua | 2 +- test/nvt/func/fs/create/dir_spec.lua | 2 +- test/nvt/func/fs/create/file_spec.lua | 2 +- test/nvt/func/fs/create/prompt_spec.lua | 2 +- test/nvt/func/fs/cut/node_spec.lua | 2 +- test/nvt/func/fs/paste/copied_spec.lua | 2 +- test/nvt/func/fs/paste/cut_spec.lua | 2 +- test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index f0885805888..eed7ef201bd 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -3,7 +3,7 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.13 global compatibility +-- 0.12 global compatibility, remove when 0.13 is stable ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 3959fc54814..557924b8e5d 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -3,7 +3,7 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility +-- 0.12 global compatibility, remove when 0.13 is stable ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 14183942a6c..73bde0c4154 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -4,7 +4,7 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility +-- 0.12 global compatibility, remove when 0.13 is stable ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index c55eca79efc..f1c28708db8 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -3,7 +3,7 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.13 global compatibility +-- 0.12 global compatibility, remove when 0.13 is stable ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index 28dc9deec04..7ac3754556a 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -3,7 +3,7 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.13 global compatibility +-- 0.12 global compatibility, remove when 0.13 is stable ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index b3bf7bc8f29..8adacaad9b8 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -3,7 +3,7 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility +-- 0.12 global compatibility, remove when 0.13 is stable ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index bd7bbebee41..379dac1610d 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -4,7 +4,7 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility +-- 0.12 global compatibility, remove when 0.13 is stable ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index 0d7184dcc22..ff070ebefcd 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -3,7 +3,7 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.13 global compatibility +-- 0.12 global compatibility, remove when 0.13 is stable ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global From 1331b8dce32b8133dd68bf285bcf3a38bfce27cf Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Tue, 13 Oct 2026 13:11:51 +1100 Subject: [PATCH 119/154] test: add missing API test variants --- test/nvt/func/fs/copy/node_spec.lua | 34 ++++++++++++++++++++-- test/nvt/func/fs/create/dir_spec.lua | 42 +++++++++++++++++++++++++-- test/nvt/func/fs/create/file_spec.lua | 42 +++++++++++++++++++++++++-- test/nvt/func/fs/cut/node_spec.lua | 33 ++++++++++++++++++++- 4 files changed, 143 insertions(+), 8 deletions(-) diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index eed7ef201bd..04d1eb61215 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -46,6 +46,37 @@ t.describe("fs.copy.node", function() end) + t.it("api single file", function() + n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") + + nu.feed_sync({ + ":NvimTreeOpen", + "", + }) + + n.exec_lua(function() + require("nvim-tree.api").fs.copy.node() + end) + + t.eq("foo", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCopiedHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + end) + + t.it("single dir", function() n.fn.setreg("+", "foo") @@ -283,9 +314,6 @@ NvimTree_1 [-] [No Name] ]], }) end) - - - -- TODO test API end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 557924b8e5d..865aaa42f8b 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -1,4 +1,5 @@ local t = require("test.testutil") +local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") @@ -78,6 +79,45 @@ NvimTree_1 [-] [No Name] end) + t.it("api single indirect", function() + nu.feed_sync({ + ":NvimTreeOpen", + }) + + -- schedule this as it blocks on vim.ui.input + n.exec_lua(function() + vim.schedule(require("nvim-tree.api").fs.create) + end) + + -- wait for the input + n.poke_eventloop() + + nu.feed_sync({ + "d1/indirect/", + }) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^   indirect │~ | +  d1f1 │~ | +  f1 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1/indirect/ was properly created | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d1/indirect") + + na.events_received({ + { event_type = "FolderCreated", payload = { folder_name = "/tmp/nvt_func/data/d1/indirect/", }, }, + }) + end) + + t.it("multiple direct", function() nu.feed_sync({ ":NvimTreeOpen", @@ -236,8 +276,6 @@ NvimTree_1 [-] [No Name] ]], }) end) - - -- TODO test API end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 73bde0c4154..baa347f5cf6 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -83,6 +83,46 @@ NvimTree_1 [-] [No Name] end) + t.it("api indirect", function() + nu.feed_sync({ + ":NvimTreeOpen", + }) + + -- schedule this as it blocks on vim.ui.input + n.exec_lua(function() + vim.schedule(require("nvim-tree.api").fs.create) + end) + + -- wait for the input + n.poke_eventloop() + + nu.feed_sync({ + "d1/indirect", + }) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +  d1f1 │~ | + ^  indirect │~ | +  f1 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/d1/indirect was properly created | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/d1/indirect") + + na.events_received({ + { event_type = "WillCreateFile", payload = { fname = "/tmp/nvt_func/data/d1/indirect", }, }, + { event_type = "FileCreated", payload = { fname = "/tmp/nvt_func/data/d1/indirect", }, }, + }) + end) + + t.it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", @@ -181,8 +221,6 @@ NvimTree_1 [-] [No Name] { event_type = "WillCreateFile", payload = { fname = "/foo", }, }, }) end) - - -- TODO test API end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index 7ac3754556a..3d736b88593 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -21,7 +21,7 @@ t.before_each(function() end) -t.describe("fs.cut.node", function() +t.describe("fs.cut", function() t.it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -50,6 +50,37 @@ t.describe("fs.cut.node", function() end) + t.it("api single file", function() + n.fn.setreg("1", "foo") + n.fn.setreg("+", "foo") + + nu.feed_sync({ + ":NvimTreeOpen", + "", + }) + + n.exec_lua(function() + require("nvim-tree.api").fs.cut() + end) + + t.eq("foo", n.fn.getreg("1")) + t.eq("/tmp/nvt_func/data/f1", n.fn.getreg("+")) + + screen:expect({ + grid = [[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + end) + + t.it("single dir", function() n.fn.setreg("+", "foo") From f797b014871440d466163003f9813f66c6a19f6a Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 14 Oct 2026 08:51:39 +1100 Subject: [PATCH 120/154] Revert "test: namespace functionaltest methods so that 0.12 global compatibility may be completely removed" This reverts commit 69a6a2aeeaf8397361a53b840e4a0355e0901139. --- test/nvt/func/fs/copy/node_spec.lua | 2 +- test/nvt/func/fs/create/dir_spec.lua | 2 +- test/nvt/func/fs/create/file_spec.lua | 2 +- test/nvt/func/fs/create/prompt_spec.lua | 2 +- test/nvt/func/fs/cut/node_spec.lua | 2 +- test/nvt/func/fs/paste/copied_spec.lua | 2 +- test/nvt/func/fs/paste/cut_spec.lua | 2 +- test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index 04d1eb61215..0e9f3e82b2c 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -3,7 +3,7 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.12 global compatibility, remove when 0.13 is stable +-- 0.13 global compatibility ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 865aaa42f8b..4e67e454c54 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -4,7 +4,7 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.12 global compatibility, remove when 0.13 is stable +-- 0.13 global compatibility ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index baa347f5cf6..d69c42d096a 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -4,7 +4,7 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.12 global compatibility, remove when 0.13 is stable +-- 0.13 global compatibility ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index f1c28708db8..c55eca79efc 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -3,7 +3,7 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.12 global compatibility, remove when 0.13 is stable +-- 0.13 global compatibility ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index 3d736b88593..7dad809537e 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -3,7 +3,7 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.12 global compatibility, remove when 0.13 is stable +-- 0.13 global compatibility ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 8adacaad9b8..b3bf7bc8f29 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -3,7 +3,7 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.12 global compatibility, remove when 0.13 is stable +-- 0.13 global compatibility ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index 379dac1610d..bd7bbebee41 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -4,7 +4,7 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.12 global compatibility, remove when 0.13 is stable +-- 0.13 global compatibility ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index ff070ebefcd..0d7184dcc22 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -3,7 +3,7 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.12 global compatibility, remove when 0.13 is stable +-- 0.13 global compatibility ---@diagnostic disable: undefined-global t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic enable: undefined-global From 97920d73fe5c93c2a6d70352572b991a03f9a74c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 14 Oct 2026 08:54:11 +1100 Subject: [PATCH 121/154] Revert "test: namespace functionaltest methods so that 0.12 global compatibility may be completely removed" This reverts commit 276d20d616e8e7650615607c5019e2ab2a472317. --- test/nvt/func/fs/copy/node_spec.lua | 25 +++++++++--------- test/nvt/func/fs/create/dir_spec.lua | 26 ++++++++++--------- test/nvt/func/fs/create/file_spec.lua | 22 +++++++++------- test/nvt/func/fs/create/prompt_spec.lua | 16 +++++++----- test/nvt/func/fs/cut/node_spec.lua | 26 ++++++++++--------- test/nvt/func/fs/paste/copied_spec.lua | 24 +++++++++-------- test/nvt/func/fs/paste/cut_spec.lua | 16 +++++++----- .../print_clipboard/print_clipboard_spec.lua | 12 +++++---- 8 files changed, 91 insertions(+), 76 deletions(-) diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index 0e9f3e82b2c..6c0ddc01164 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -5,20 +5,22 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -t.before_each(function() +before_each(function() screen = nf.create_session() end) -t.describe("fs.copy.node", function() - t.it("single file", function() +describe("fs.copy.node", function() + it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -46,7 +48,7 @@ t.describe("fs.copy.node", function() end) - t.it("api single file", function() + it("api single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -76,8 +78,7 @@ t.describe("fs.copy.node", function() }) end) - - t.it("single dir", function() + it("single dir", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -103,7 +104,7 @@ t.describe("fs.copy.node", function() end) - t.it("toggle one", function() + it("toggle one", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -150,7 +151,7 @@ NvimTree_1 [-] [No Name] end) - t.it("toggle many", function() + it("toggle many", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -199,7 +200,7 @@ NvimTree_1 [-] [No Name] end) - t.it("no system clipboard", function() + it("no system clipboard", function() n.exec_lua(function() require("nvim-tree").setup({ actions = { @@ -236,7 +237,7 @@ NvimTree_1 [-] [No Name] end) - t.it("overrides cut", function() + it("overrides cut", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -281,7 +282,7 @@ NvimTree_1 [-] [No Name] end) - t.it("dir overrides file", function() + it("dir overrides file", function() n.fn.setreg("+", "foo") nu.feed_sync({ diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 4e67e454c54..d4a68e20e9f 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -6,14 +6,16 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -t.before_each(function() +before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) local Event = require("nvim-tree._meta.api.events").Event @@ -21,8 +23,8 @@ t.before_each(function() end) -t.describe("fs.create dir", function() - t.it("single direct", function() +describe("fs.create dir", function() + it("single direct", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -50,7 +52,7 @@ NvimTree_1 [-] [No Name] end) - t.it("single indirect", function() + it("single indirect", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -79,7 +81,7 @@ NvimTree_1 [-] [No Name] end) - t.it("api single indirect", function() + it("api single indirect", function() nu.feed_sync({ ":NvimTreeOpen", }) @@ -118,7 +120,7 @@ NvimTree_1 [-] [No Name] end) - t.it("multiple direct", function() + it("multiple direct", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -150,7 +152,7 @@ NvimTree_1 [-] [No Name] end) - t.it("multiple indirect", function() + it("multiple indirect", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -183,7 +185,7 @@ NvimTree_1 [-] [No Name] end) - t.it("fails when file exists", function() + it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -206,7 +208,7 @@ NvimTree_1 [-] [No Name] end) - t.it("fails when file exists", function() + it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -232,7 +234,7 @@ NvimTree_1 [-] [No Name] end) - t.it("fails on invalid path", function() + it("fails on invalid path", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -256,7 +258,7 @@ NvimTree_1 [-] [No Name] end) - t.it("fails when dir exists", function() + it("fails when dir exists", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index d69c42d096a..7de5901833d 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -6,14 +6,16 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -t.before_each(function() +before_each(function() screen = nf.create_session({}, nil, nil, { ext_cmdline = true }) local Event = require("nvim-tree._meta.api.events").Event @@ -23,8 +25,8 @@ t.before_each(function() end) -t.describe("fs.create file", function() - t.it("direct", function() +describe("fs.create file", function() + it("direct", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -53,7 +55,7 @@ NvimTree_1 [-] [No Name] end) - t.it("indirect", function() + it("indirect", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -83,7 +85,7 @@ NvimTree_1 [-] [No Name] end) - t.it("api indirect", function() + it("api indirect", function() nu.feed_sync({ ":NvimTreeOpen", }) @@ -123,7 +125,7 @@ NvimTree_1 [-] [No Name] end) - t.it("fails when file exists", function() + it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -148,7 +150,7 @@ NvimTree_1 [-] [No Name] end) - t.it("fails when dir exists", function() + it("fails when dir exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -173,7 +175,7 @@ NvimTree_1 [-] [No Name] end) - t.it("indirect creates dirs", function() + it("indirect creates dirs", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -205,7 +207,7 @@ NvimTree_1 [-] [No Name] end) - t.it("fails on invalid path", function() + it("fails on invalid path", function() nu.feed_sync({ ":NvimTreeOpen", "a", diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index c55eca79efc..0701db07188 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -5,20 +5,22 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -t.before_each(function() +before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) end) -t.describe("fs.create prompt", function() - t.it("tree focused", function() +describe("fs.create prompt", function() + it("tree focused", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -32,7 +34,7 @@ t.describe("fs.create prompt", function() end) - t.it("api tree not focused", function() + it("api tree not focused", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -54,7 +56,7 @@ t.describe("fs.create prompt", function() end) - t.it("file focused", function() + it("file focused", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -68,7 +70,7 @@ t.describe("fs.create prompt", function() end) - t.it("cancelled", function() + it("cancelled", function() nu.feed_sync({ ":NvimTreeOpen", "a", diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index 7dad809537e..ac6baee96bc 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -5,7 +5,9 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it ---@diagnostic enable: undefined-global @@ -16,13 +18,13 @@ t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_e local screen -t.before_each(function() +before_each(function() screen = nf.create_session() end) -t.describe("fs.cut", function() - t.it("single file", function() +describe("fs.cut.node", function() + it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -50,7 +52,7 @@ t.describe("fs.cut", function() end) - t.it("api single file", function() + it("api single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -81,7 +83,7 @@ t.describe("fs.cut", function() end) - t.it("single dir", function() + it("single dir", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -106,7 +108,7 @@ t.describe("fs.cut", function() }) end) - t.it("toggle one", function() + it("toggle one", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -153,7 +155,7 @@ NvimTree_1 [-] [No Name] end) - t.it("toggle many", function() + it("toggle many", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -202,7 +204,7 @@ NvimTree_1 [-] [No Name] end) - t.it("no system clipboard", function() + it("no system clipboard", function() n.exec_lua(function() require("nvim-tree").setup({ actions = { @@ -239,7 +241,7 @@ NvimTree_1 [-] [No Name] end) - t.it("single overrides copy", function() + it("single overrides copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -284,7 +286,7 @@ NvimTree_1 [-] [No Name] end) - t.it("multiple overrides copy", function() + it("multiple overrides copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -351,7 +353,7 @@ NvimTree_1 [-] [No Name] end) - t.it("dir overrides file", function() + it("dir overrides file", function() n.fn.setreg("+", "foo") nu.feed_sync({ diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index b3bf7bc8f29..46d08fea29c 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -5,14 +5,16 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen local screen -t.before_each(function() +before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) end) @@ -23,8 +25,8 @@ end) -- TODO partial partition -t.describe("fs.paste.node copied", function() - t.it("single file", function() +describe("fs.paste.node copied", function() + it("single file", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -59,7 +61,7 @@ NvimTree_1 [-] [No Name] end) - t.it("multiple files", function() + it("multiple files", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -100,7 +102,7 @@ NvimTree_1 [-] [No Name] end) - t.it("single dir", function() + it("single dir", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -142,7 +144,7 @@ NvimTree_1 [-] [No Name] end) - t.it("single dir conflict resolved", function() + it("single dir conflict resolved", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -195,7 +197,7 @@ NvimTree_1 [-] [No Name] end) - t.it("single dir conflict cancelled", function() + it("single dir conflict cancelled", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -244,7 +246,7 @@ NvimTree_1 [-] [No Name] end) - t.it("single dir conflict second conflict overwrite", function() + it("single dir conflict second conflict overwrite", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -304,7 +306,7 @@ Press ENTER or type command to continue^ end) - t.it("single dir conflict second conflict cancel", function() + it("single dir conflict second conflict cancel", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -354,7 +356,7 @@ Press ENTER or type command to continue^ end) - t.it("single dir conflict second conflict resolved", function() + it("single dir conflict second conflict resolved", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index bd7bbebee41..404eddccdb1 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -6,7 +6,9 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it ---@diagnostic enable: undefined-global --- @type test.functional.ui.screen @@ -16,7 +18,7 @@ local screen -- common copy/paste codepaths are tested in copied_spec.lua except for API -t.before_each(function() +before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true, }) local Event = require("nvim-tree._meta.api.events").Event @@ -24,8 +26,8 @@ t.before_each(function() end) -t.describe("fs.paste.node cut", function() - t.it("single dir", function() +describe("fs.paste.node cut", function() + it("single dir", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -70,7 +72,7 @@ NvimTree_1 [-] [No Name] end) - t.it("single file", function() + it("single file", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -124,7 +126,7 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 end) - t.it("api node under cursor", function() + it("api node under cursor", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -169,7 +171,7 @@ NvimTree_1 [-] [No Name] end) - t.it("api node specified", function() + it("api node specified", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index 0d7184dcc22..ddc428144a8 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -5,7 +5,9 @@ local nu = require("test.nvt.func.util") -- 0.13 global compatibility ---@diagnostic disable: undefined-global -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it ---@diagnostic enable: undefined-global @@ -13,13 +15,13 @@ t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_e local screen -t.before_each(function() +before_each(function() screen = nf.create_session() end) -t.describe("fs.print_clipboard", function() - t.it("none", function() +describe("fs.print_clipboard", function() + it("none", function() nu.feed_sync({ ":NvimTreeOpen", }) @@ -61,7 +63,7 @@ Press ENTER or type command to continue^ end) - t.it("many", function() + it("many", function() nu.feed_sync({ ":NvimTreeOpen", "", From 24102fbdf919d9d9294c22acccd0d0620c926657 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 14 Oct 2026 10:16:22 +1100 Subject: [PATCH 122/154] test: add multiple paste tests --- test/nvt/func/README.md | 6 +- test/nvt/func/fs/paste/copied_spec.lua | 289 +++++++++++++++++++++---- test/nvt/func/fs/paste/cut_spec.lua | 17 +- test/nvt/func/fs/paste/data/d1/d1f1 | 1 - test/nvt/func/fs/paste/data/d1/d1f2 | 1 - test/nvt/func/fs/paste/data/d2/d2f1 | 1 - test/nvt/func/fs/paste/data/d2/d3/d3f1 | 0 test/nvt/func/fs/paste/data/d2/f2 | 1 + 8 files changed, 256 insertions(+), 60 deletions(-) delete mode 100644 test/nvt/func/fs/paste/data/d2/d2f1 create mode 100644 test/nvt/func/fs/paste/data/d2/d3/d3f1 create mode 100644 test/nvt/func/fs/paste/data/d2/f2 diff --git a/test/nvt/func/README.md b/test/nvt/func/README.md index 0da5d3fa65d..7934e1cf1bd 100644 --- a/test/nvt/func/README.md +++ b/test/nvt/func/README.md @@ -1,10 +1,12 @@ # Generating Test Data -Execute `scripts/functionaltest.sh -l [ ]` +Execute `scripts/functionaltest.sh -l [ ]` This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua` -Test's `data` directory should be specified if present. +If a `data` directory is present, it will be copied and the session will execute in `/tmp/nvt_func/data` otherwise `/tmp/nvt_func`. + +Test's `data` directory will be used if present. - `u` to dump the entire screen to `/tmp/nvt_func/dump.txt` and open it - `c` to dump with identical lines collapsed diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 46d08fea29c..865f6c8c6e5 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -29,10 +29,7 @@ describe("fs.paste.node copied", function() it("single file", function() nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "", + "", "c", "", "p", @@ -64,10 +61,7 @@ NvimTree_1 [-] [No Name] it("multiple files", function() nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "", + "", "", "", "c", @@ -109,28 +103,25 @@ NvimTree_1 [-] [No Name] "c", "", "p", - "gg", - "E", + "", }) screen:expect({ cmdline = {}, attr_ids = {}, grid = [[ - ^/tmp/nvt_func/data/.. │ | -   d1 │~ | -  d1f1 │~ | -  d1f2 │~ | + /tmp/nvt_func/data/.. │ | +   d1 │~ |   d2 │~ | -   d1 │~ | + ^   d1 │~ |  d1f1 │~ |  d1f2 │~ | -  d2f1 │~ | -   d3 │~ | -  d3f1 │~ | +   d3 │~ | +  f2 │~ | +   d3 │~ |  f1 │~ |  f2 │~ | -~ │~ |*9 +~ │~ |*11 NvimTree_1 [-] [No Name] | [NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | ]], @@ -160,28 +151,23 @@ NvimTree_1 [-] [No Name] nu.feed_sync({ "_copy", - "gg", - "E", + "", }) screen:expect({ cmdline = { { abort = true } }, attr_ids = {}, grid = [[ - ^/tmp/nvt_func/data/.. │ | -   d1 │~ | -  d1f1 │~ | -  d1f2 │~ | -   d1_copy │~ | + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d1_copy │~ |  d1f1 │~ |  d1f2 │~ | -   d2 │~ | -  d2f1 │~ | -   d3 │~ | -  d3f1 │~ | +   d2 │~ | +   d3 │~ |  f1 │~ |  f2 │~ | -~ │~ |*9 +~ │~ |*13 NvimTree_1 [-] [No Name] | | ]], @@ -233,12 +219,14 @@ NvimTree_1 [-] [No Name]  d1f1 │~ |  d1f2 │~ |   d2 │~ | -  d2f1 │~ | +   d3 │~ | +  d3f1 │~ | +  f2 │~ |   d3 │~ |  d3f1 │~ |  f1 │~ |  f2 │~ | -~ │~ |*12 +~ │~ |*10 NvimTree_1 [-] [No Name] | | ]], @@ -343,12 +331,14 @@ Press ENTER or type command to continue^ {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f2 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d2f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d3}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d3f1 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d3}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d3f1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| - {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*12 + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*10 {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| | ]], @@ -390,32 +380,239 @@ Press ENTER or type command to continue^ nu.feed_sync({ "1_copy", - "gg", - "E", + "", }) screen:expect({ cmdline = { { abort = true } }, attr_ids = {}, grid = [[ - ^/tmp/nvt_func/data/.. │ | -   d1 │~ | -  d1f1 │~ | -  d1f2 │~ | -   d1_copy │~ | + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d1_copy │~ |  d1f1 │~ |  d1f2 │~ | +   d2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*13 +NvimTree_1 [-] [No Name] | + | + ]], + }) + end) + + + it("multiple", function() + nu.feed_sync({ + ":NvimTreeOpen", + "", + "c", + "", + "c", + "", + "p", + "", + "", + }) + + screen:expect({ + cmdline = {}, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ |   d2 │~ | -  d2f1 │~ | -   d3 │~ | -  d3f1 │~ | + ^   d1 │~ | +  d1f1 │~ | +  d1f2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*10 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/d2/f1") + na.dir_exists("/tmp/nvt_func/data/d2/d3") + na.file_exists("/tmp/nvt_func/data/d2/d3/d3f1") + end) + + + it("multiple conflict no rename", function() + nu.feed_sync({ + ":NvimTreeOpen", + "", + "", + "G", + "c", + "", + "c", + "p", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "n", + }) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d1 │~ | +   d3 │~ | + ^  f1 │~ | +  f2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*12 +NvimTree_1 [-] [No Name] | + | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/d2/f1") + na.file_exists("/tmp/nvt_func/data/d2/f2") + na.dir_exists("/tmp/nvt_func/data/d2/d3") + na.file_exists("/tmp/nvt_func/data/d2/d3/d3f1") + end) + + + it("multiple conflict rename all", function() + nu.feed_sync({ + ":NvimTreeOpen", + "", + "", + "G", + "c", + "", + "c", + "p", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "r", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Suffix: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + ".renamed", + }) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d1 │~ | +   d3 │~ | +   d3.renamed │~ | +  f1 │~ | +  f2 │~ | + ^  f2.renamed │~ | +   d3 │~ |  f1 │~ |  f2 │~ | -~ │~ |*9 +~ │~ |*10 NvimTree_1 [-] [No Name] | | ]], }) + + na.dir_exists("/tmp/nvt_func/data/d2/d1") + na.dir_exists("/tmp/nvt_func/data/d2/d3") + na.file_exists("/tmp/nvt_func/data/d2/f1") + na.file_exists("/tmp/nvt_func/data/d2/f2") + + na.file_exists("/tmp/nvt_func/data/d2/f2.renamed") + na.dir_exists("/tmp/nvt_func/data/d2/d3.renamed") + na.file_exists("/tmp/nvt_func/data/d2/d3.renamed/d3f1") + end) + + + it("multiple conflict overwrite", function() + nu.feed_sync({ + ":NvimTreeOpen", + "", + "", + "G", + "c", + "", + "c", + "p", + }) + + -- BUG: this should read as per single prompt: "2 file(s) already exist. R(ename suffix)/y/n: " + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "y", + }) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d1 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | + | +[NvimTree] Could not copy /tmp/nvt_func/data/d3 - EEXIST: file already exists: /| +tmp/nvt_func/data/d2/d3 | +Press ENTER or type command to continue^ | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d2/d1") + na.dir_exists("/tmp/nvt_func/data/d2/d3") + na.file_exists("/tmp/nvt_func/data/d2/f1") + na.file_exists("/tmp/nvt_func/data/d2/f2") end) end) diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index 404eddccdb1..c5e0df7e8fa 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -34,7 +34,7 @@ describe("fs.paste.node cut", function() "x", "", "p", - "E", + "", }) screen:expect({ @@ -46,11 +46,12 @@ describe("fs.paste.node cut", function() ^   d1 │~ |  d1f1 │~ |  d1f2 │~ | -  d2f1 │~ | +   d3 │~ | +  f2 │~ |   d3 │~ |  f1 │~ |  f2 │~ | -~ │~ |*13 +~ │~ |*12 NvimTree_1 [-] [No Name] | [NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | ]], @@ -75,10 +76,7 @@ NvimTree_1 [-] [No Name] it("single file", function() nu.feed_sync({ ":NvimTreeOpen", - "", - "", - "", - "", + "", "x", "", "", @@ -145,11 +143,12 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 /tmp/nvt_func/data/.. │ |   d2 │~ | ^   d1 │~ | -  d2f1 │~ | +   d3 │~ | +  f2 │~ |   d3 │~ |  f1 │~ |  f2 │~ | -~ │~ |*15 +~ │~ |*14 NvimTree_1 [-] [No Name] | [NvimTree] /tmp/nvt_func/data/d1 added to clipboard. | ]], diff --git a/test/nvt/func/fs/paste/data/d1/d1f1 b/test/nvt/func/fs/paste/data/d1/d1f1 index 13d1560f267..e69de29bb2d 100644 --- a/test/nvt/func/fs/paste/data/d1/d1f1 +++ b/test/nvt/func/fs/paste/data/d1/d1f1 @@ -1 +0,0 @@ -d1f1 diff --git a/test/nvt/func/fs/paste/data/d1/d1f2 b/test/nvt/func/fs/paste/data/d1/d1f2 index 6ec000bf6df..e69de29bb2d 100644 --- a/test/nvt/func/fs/paste/data/d1/d1f2 +++ b/test/nvt/func/fs/paste/data/d1/d1f2 @@ -1 +0,0 @@ -d1f2 diff --git a/test/nvt/func/fs/paste/data/d2/d2f1 b/test/nvt/func/fs/paste/data/d2/d2f1 deleted file mode 100644 index f901b65feae..00000000000 --- a/test/nvt/func/fs/paste/data/d2/d2f1 +++ /dev/null @@ -1 +0,0 @@ -d2f1 diff --git a/test/nvt/func/fs/paste/data/d2/d3/d3f1 b/test/nvt/func/fs/paste/data/d2/d3/d3f1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/nvt/func/fs/paste/data/d2/f2 b/test/nvt/func/fs/paste/data/d2/f2 new file mode 100644 index 00000000000..8e1e71d5ce3 --- /dev/null +++ b/test/nvt/func/fs/paste/data/d2/f2 @@ -0,0 +1 @@ +f1 From 383077601a6161183e289ad560cd565520a58b99 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 14 Oct 2026 10:48:01 +1100 Subject: [PATCH 123/154] test: add multiple paste tests --- test/nvt/func/fs/paste/copied_spec.lua | 139 +++++++++++++++++++++++-- test/nvt/func/fs/paste/data/d2/d3/d3f1 | 1 + test/nvt/func/fs/paste/data/d2/f2 | 2 +- 3 files changed, 134 insertions(+), 8 deletions(-) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 865f6c8c6e5..6b16fffd3bc 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -14,15 +14,12 @@ local it = t.it or it local screen -before_each(function() - screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) -end) - -- common copy/paste codepaths are tested here except for API --- TODO multiple, needs same conflict checking as single, as the codepaths in Clipboard:resolve_conflicts are different --- TODO partial partition +before_each(function() + screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) +end) describe("fs.paste.node copied", function() @@ -493,7 +490,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple conflict rename all", function() + it("multiple conflict rename suffix", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -556,6 +553,134 @@ NvimTree_1 [-] [No Name] end) + it("multiple conflict rename cancel", function() + nu.feed_sync({ + ":NvimTreeOpen", + "", + "", + "G", + "c", + "", + "c", + "p", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "", + "", + }) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d1 │~ | +   d3 │~ | + ^  f1 │~ | +  f2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*12 +NvimTree_1 [-] [No Name] | + | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d2/d1") + na.dir_exists("/tmp/nvt_func/data/d2/d3") + na.file_exists("/tmp/nvt_func/data/d2/d3/d3f1") + na.file_exists("/tmp/nvt_func/data/d2/f1") + na.file_exists("/tmp/nvt_func/data/d2/f2") + end) + + + it("multiple conflict rename second conflict", function() + nu.feed_sync({ + ":NvimTreeOpen", + "", + "a", + "f2.renamed", + }) + + na.file_exists("/tmp/nvt_func/data/d2/f2.renamed") + + nu.feed_sync({ + "W", + "gg", + "", + "", + "G", + "c", + "", + "c", + "p", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "", + ".renamed", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2/f2.renamed ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "", + ".again", + }) + + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d1 │~ | +   d3 │~ | +   d3.renamed │~ | +  f1 │~ | +  f2 │~ | +  f2.renamed │~ | + ^  f2.renamed.again │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*9 +NvimTree_1 [-] [No Name] | + | + ]], + }) +-- + na.dir_exists("/tmp/nvt_func/data/d2/d1") + na.dir_exists("/tmp/nvt_func/data/d2/d3") + na.file_exists("/tmp/nvt_func/data/d2/f1") + na.file_exists("/tmp/nvt_func/data/d2/f2") + + na.file_exists("/tmp/nvt_func/data/d2/f2.renamed") + na.file_exists("/tmp/nvt_func/data/d2/f2.renamed.again") + na.dir_exists("/tmp/nvt_func/data/d2/d3.renamed") + na.file_exists("/tmp/nvt_func/data/d2/d3.renamed/d3f1") + end) + + it("multiple conflict overwrite", function() nu.feed_sync({ ":NvimTreeOpen", diff --git a/test/nvt/func/fs/paste/data/d2/d3/d3f1 b/test/nvt/func/fs/paste/data/d2/d3/d3f1 index e69de29bb2d..832bad2faee 100644 --- a/test/nvt/func/fs/paste/data/d2/d3/d3f1 +++ b/test/nvt/func/fs/paste/data/d2/d3/d3f1 @@ -0,0 +1 @@ +d3f1 diff --git a/test/nvt/func/fs/paste/data/d2/f2 b/test/nvt/func/fs/paste/data/d2/f2 index 8e1e71d5ce3..9de77c18733 100644 --- a/test/nvt/func/fs/paste/data/d2/f2 +++ b/test/nvt/func/fs/paste/data/d2/f2 @@ -1 +1 @@ -f1 +f2 From 2e3e69cee47a5cad49934521c528e603d95cbe31 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 14 Oct 2026 11:04:06 +1100 Subject: [PATCH 124/154] test: add fs.clear_clipboard tests --- .../clear_clipboard/clear_clipboard_spec.lua | 140 ++++++++++++++++++ test/nvt/func/fs/clear_clipboard/data/d1/d1f1 | 1 + test/nvt/func/fs/clear_clipboard/data/d1/d1f2 | 1 + test/nvt/func/fs/clear_clipboard/data/d2/d2f1 | 1 + test/nvt/func/fs/clear_clipboard/data/d3/d3f1 | 1 + test/nvt/func/fs/clear_clipboard/data/f1 | 1 + test/nvt/func/fs/clear_clipboard/data/f2 | 1 + 7 files changed, 146 insertions(+) create mode 100644 test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua create mode 100644 test/nvt/func/fs/clear_clipboard/data/d1/d1f1 create mode 100644 test/nvt/func/fs/clear_clipboard/data/d1/d1f2 create mode 100644 test/nvt/func/fs/clear_clipboard/data/d2/d2f1 create mode 100644 test/nvt/func/fs/clear_clipboard/data/d3/d3f1 create mode 100644 test/nvt/func/fs/clear_clipboard/data/f1 create mode 100644 test/nvt/func/fs/clear_clipboard/data/f2 diff --git a/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua new file mode 100644 index 00000000000..6257caf1381 --- /dev/null +++ b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua @@ -0,0 +1,140 @@ +local t = require("test.testutil") +local n = require("test.functional.testnvim")() +local nf = require("test.nvt.func.fixtures") +local nu = require("test.nvt.func.util") + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + + +--- @type test.functional.ui.screen +local screen + + +before_each(function() + screen = nf.create_session() +end) + + +describe("fs.clear_clipboard", function() + it("empty", function() + nu.feed_sync({ + ":NvimTreeOpen", + }) + + n.exec_lua(function() + require("nvim-tree.api").fs.clear_clipboard() + end) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +   d3 │~ | +  f1 │~ | +  f2 │~ | +~ │~ |*16 +NvimTree_1 [-] [No Name] | +[NvimTree] Clipboard has been emptied. | + ]], + }) + end) + + + it("many", function() + nu.feed_sync({ + ":NvimTreeOpen", + "", + "", + "", + "c", + "", + "x", + "", + "c", + "", + "x", + }) + + n.exec_lua(function() + require("nvim-tree.api").fs.print_clipboard() + end) + + screen:expect({ + grid = [[ +{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCopiedHL:d1f1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d1f2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeCopiedHL:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:d3}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*7 +{3: }| +[NvimTree] | +Cut | + * /tmp/nvt_func/data/d1/d1f2 | + * /tmp/nvt_func/data/d3 | +Copy | + * /tmp/nvt_func/data/d1/d1f1 | + * /tmp/nvt_func/data/d2 | +{6:Press ENTER or type command to continue}^ | + ]], + }) + + nu.feed_sync({ + "", + }) + + n.exec_lua(function() + require("nvim-tree.api").fs.clear_clipboard() + end) + + screen:expect({ + grid = [[ +{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f2 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeFolderNameCL:d3}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*14 +{NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| +[NvimTree] Clipboard has been emptied. | + ]], + }) + + n.exec_lua(function() + require("nvim-tree.api").fs.print_clipboard() + end) + + screen:expect({ + grid = [[ +{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | +{NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f2 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeFolderNameCL:d3}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*12 +{3: }| +[NvimTree] | + | +{6:Press ENTER or type command to continue}^ | + ]], + }) + end) +end) + +-- vim:colorcolumn=80 diff --git a/test/nvt/func/fs/clear_clipboard/data/d1/d1f1 b/test/nvt/func/fs/clear_clipboard/data/d1/d1f1 new file mode 100644 index 00000000000..13d1560f267 --- /dev/null +++ b/test/nvt/func/fs/clear_clipboard/data/d1/d1f1 @@ -0,0 +1 @@ +d1f1 diff --git a/test/nvt/func/fs/clear_clipboard/data/d1/d1f2 b/test/nvt/func/fs/clear_clipboard/data/d1/d1f2 new file mode 100644 index 00000000000..6ec000bf6df --- /dev/null +++ b/test/nvt/func/fs/clear_clipboard/data/d1/d1f2 @@ -0,0 +1 @@ +d1f2 diff --git a/test/nvt/func/fs/clear_clipboard/data/d2/d2f1 b/test/nvt/func/fs/clear_clipboard/data/d2/d2f1 new file mode 100644 index 00000000000..f901b65feae --- /dev/null +++ b/test/nvt/func/fs/clear_clipboard/data/d2/d2f1 @@ -0,0 +1 @@ +d2f1 diff --git a/test/nvt/func/fs/clear_clipboard/data/d3/d3f1 b/test/nvt/func/fs/clear_clipboard/data/d3/d3f1 new file mode 100644 index 00000000000..832bad2faee --- /dev/null +++ b/test/nvt/func/fs/clear_clipboard/data/d3/d3f1 @@ -0,0 +1 @@ +d3f1 diff --git a/test/nvt/func/fs/clear_clipboard/data/f1 b/test/nvt/func/fs/clear_clipboard/data/f1 new file mode 100644 index 00000000000..8e1e71d5ce3 --- /dev/null +++ b/test/nvt/func/fs/clear_clipboard/data/f1 @@ -0,0 +1 @@ +f1 diff --git a/test/nvt/func/fs/clear_clipboard/data/f2 b/test/nvt/func/fs/clear_clipboard/data/f2 new file mode 100644 index 00000000000..9de77c18733 --- /dev/null +++ b/test/nvt/func/fs/clear_clipboard/data/f2 @@ -0,0 +1 @@ +f2 From cc5ce95fdc2f43d24e86ef723d3d175eada2f370 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 14 Oct 2026 11:05:41 +1100 Subject: [PATCH 125/154] test: formatting --- test/nvt/func/fs/paste/copied_spec.lua | 2 +- test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index 6b16fffd3bc..dc8c63c844e 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -668,7 +668,7 @@ NvimTree_1 [-] [No Name] | ]], }) --- + -- na.dir_exists("/tmp/nvt_func/data/d2/d1") na.dir_exists("/tmp/nvt_func/data/d2/d3") na.file_exists("/tmp/nvt_func/data/d2/f1") diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index ddc428144a8..48902644592 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -59,7 +59,6 @@ describe("fs.print_clipboard", function() Press ENTER or type command to continue^ | ]], }) - end) From 0c40e11155457c6add2d03ba2757cd29b05c0df5 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 14 Oct 2026 11:46:45 +1100 Subject: [PATCH 126/154] test: add fs.move tests --- test/nvt/func/fs/move/data/dst/f2 | 0 test/nvt/func/fs/move/data/src/f1 | 1 + test/nvt/func/fs/move/node_spec.lua | 106 ++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 test/nvt/func/fs/move/data/dst/f2 create mode 100644 test/nvt/func/fs/move/data/src/f1 create mode 100644 test/nvt/func/fs/move/node_spec.lua diff --git a/test/nvt/func/fs/move/data/dst/f2 b/test/nvt/func/fs/move/data/dst/f2 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/nvt/func/fs/move/data/src/f1 b/test/nvt/func/fs/move/data/src/f1 new file mode 100644 index 00000000000..8e1e71d5ce3 --- /dev/null +++ b/test/nvt/func/fs/move/data/src/f1 @@ -0,0 +1 @@ +f1 diff --git a/test/nvt/func/fs/move/node_spec.lua b/test/nvt/func/fs/move/node_spec.lua new file mode 100644 index 00000000000..d476de212b3 --- /dev/null +++ b/test/nvt/func/fs/move/node_spec.lua @@ -0,0 +1,106 @@ +local t = require("test.testutil") +local n = require("test.functional.testnvim")() +local nf = require("test.nvt.func.fixtures") +local na = require("test.nvt.func.asserts") +local nu = require("test.nvt.func.util") + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local before_each = t.before_each or before_each +local it = t.it or it +---@diagnostic enable: undefined-global + + +--- @type test.functional.ui.screen +local screen + + +before_each(function() + screen = nf.create_session() +end) + + +describe("fs.move", function() + it("nothing", function() + n.fn.setreg("+", "") + + nu.feed_sync({ + ":NvimTreeOpen", + "gp", + "E", + }) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   dst │~ | +  f2 │~ | +   src │~ | +  f1 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +:NvimTreeOpen | + ]], + }) + end) + + + it("inexistent", function() + n.fn.setreg("+", "/tmp/nvt_func/data/inexistent") + + nu.feed_sync({ + ":NvimTreeOpen", + "gp", + "E", + }) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   dst │~ | +  f2 │~ | +   src │~ | +  f1 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +:NvimTreeOpen | + ]], + }) + end) + + + it("present", function() + n.fn.setreg("+", "/tmp/nvt_func/data/src/f1") + + nu.feed_sync({ + ":NvimTreeOpen", + "E", + "", + "gp", + }) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   dst │~ | + ^  f1 │~ | +  f2 │~ | +   src │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +:NvimTreeOpen | + ]], + }) + + -- TODO remove hardcoding + na.dir_exists("/tmp/nvt_func/data/dst") + na.file_exists("/tmp/nvt_func/data/dst/f1") + na.not_path_exists("/tmp/nvt_func/data/src/f1") + end) +end) + +-- vim:colorcolumn=80 From 57ca2e085ac7ed19c5a3a5f9bd4b6011ab838dd4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 14 Oct 2026 11:49:15 +1100 Subject: [PATCH 127/154] test: formatting --- test/nvt/func/fs/cut/node_spec.lua | 2 +- test/nvt/func/fs/move/node_spec.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index ac6baee96bc..170d7c7435e 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -11,7 +11,7 @@ local it = t.it or it ---@diagnostic enable: undefined-global --- BUG singe operations report "added to clipboard", not "cut to clipboard" as per bulk operations +-- BUG single operations report "added to clipboard", not "cut to clipboard" as per bulk operations --- @type test.functional.ui.screen diff --git a/test/nvt/func/fs/move/node_spec.lua b/test/nvt/func/fs/move/node_spec.lua index d476de212b3..c65b9f93a74 100644 --- a/test/nvt/func/fs/move/node_spec.lua +++ b/test/nvt/func/fs/move/node_spec.lua @@ -19,7 +19,7 @@ local screen before_each(function() screen = nf.create_session() end) - + describe("fs.move", function() it("nothing", function() From b563d907fbd47a46b8414699c716e1cac2da67d4 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Wed, 14 Oct 2026 12:47:53 +1100 Subject: [PATCH 128/154] test: add fs.trash tests, wip --- test/nvt/func/fs/copy/node_spec.lua | 2 +- test/nvt/func/fs/cut/node_spec.lua | 2 +- test/nvt/func/fs/paste/copied_spec.lua | 2 +- test/nvt/func/fs/paste/cut_spec.lua | 2 +- test/nvt/func/fs/trash/data/d1/d1f1 | 1 + test/nvt/func/fs/trash/data/d2/d2f1 | 1 + test/nvt/func/fs/trash/data/f1 | 1 + test/nvt/func/fs/trash/node_spec.lua | 185 +++++++++++++++++++++++++ test/nvt/func/init_live.lua | 6 +- 9 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 test/nvt/func/fs/trash/data/d1/d1f1 create mode 100644 test/nvt/func/fs/trash/data/d2/d2f1 create mode 100644 test/nvt/func/fs/trash/data/f1 create mode 100644 test/nvt/func/fs/trash/node_spec.lua diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index 6c0ddc01164..312e7a32143 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -19,7 +19,7 @@ before_each(function() end) -describe("fs.copy.node", function() +describe("fs.copy", function() it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index 170d7c7435e..56895ba88d4 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -23,7 +23,7 @@ before_each(function() end) -describe("fs.cut.node", function() +describe("fs.cut", function() it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index dc8c63c844e..a7026f84ba6 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -22,7 +22,7 @@ before_each(function() end) -describe("fs.paste.node copied", function() +describe("fs.paste copied", function() it("single file", function() nu.feed_sync({ ":NvimTreeOpen", diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index c5e0df7e8fa..fff5aea6959 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -26,7 +26,7 @@ before_each(function() end) -describe("fs.paste.node cut", function() +describe("fs.paste cut", function() it("single dir", function() nu.feed_sync({ ":NvimTreeOpen", diff --git a/test/nvt/func/fs/trash/data/d1/d1f1 b/test/nvt/func/fs/trash/data/d1/d1f1 new file mode 100644 index 00000000000..13d1560f267 --- /dev/null +++ b/test/nvt/func/fs/trash/data/d1/d1f1 @@ -0,0 +1 @@ +d1f1 diff --git a/test/nvt/func/fs/trash/data/d2/d2f1 b/test/nvt/func/fs/trash/data/d2/d2f1 new file mode 100644 index 00000000000..f901b65feae --- /dev/null +++ b/test/nvt/func/fs/trash/data/d2/d2f1 @@ -0,0 +1 @@ +d2f1 diff --git a/test/nvt/func/fs/trash/data/f1 b/test/nvt/func/fs/trash/data/f1 new file mode 100644 index 00000000000..8e1e71d5ce3 --- /dev/null +++ b/test/nvt/func/fs/trash/data/f1 @@ -0,0 +1 @@ +f1 diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua new file mode 100644 index 00000000000..7b7d4829358 --- /dev/null +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -0,0 +1,185 @@ +local t = require("test.testutil") +local nf = require("test.nvt.func.fixtures") +local na = require("test.nvt.func.asserts") +local nu = require("test.nvt.func.util") + +-- 0.13 global compatibility +---@diagnostic disable: undefined-global +local describe = t.describe or describe +local it = t.it or it +---@diagnostic enable: undefined-global + + +--- @type test.functional.ui.screen +local screen + + +-- TODO test: +-- clear buffer +-- many +-- events +-- failed file and dir + + +describe("fs.trash", function() + it("single file", function() + screen = nf.create_session({ + trash = { + -- TODO this executes async, need to wait for completion and tree to update, maybe disable watchers + -- cmd = "sleep 1; rm ", + cmd = "rm ", + } + }, nil, nil, { ext_cmdline = true, }) + + nu.feed_sync({ + ":NvimTreeOpen", + "", + "", + "", + "D", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Trash d1f1? y/N: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "y", + }) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d2 │~ | +  f1 │~ | +~ │~ |*18 +NvimTree_1 [-] [No Name] | + | + ]], + }) + + na.not_path_exists("/tmp/nvt_func/data/d1/d1f1") + end) + + + it("single dir", function() + screen = nf.create_session({ + trash = { + -- TODO this executes async, need to wait for completion and tree to update, maybe disable watchers + -- cmd = "sleep 1; rm -rf ", + cmd = "rm -rf ", + } + }, nil, nil, { ext_cmdline = true, }) + + nu.feed_sync({ + ":NvimTreeOpen", + "", + "D", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Trash d1? y/N: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "y", + "gg", + "E", + }) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d2 │~ | +  d2f1 │~ | +  f1 │~ | +~ │~ |*18 +NvimTree_1 [-] [No Name] | + | + ]], + }) + + na.not_path_exists("/tmp/nvt_func/data/d1") + end) + + + it("invalid trash.cmd", function() + screen = nf.create_session({ + trash = { + cmd = "foobarbaz", + } + }, nil, nil, { ext_cmdline = true, }) + + nu.feed_sync({ + ":NvimTreeOpen", + "", + "", + "", + "D", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Trash d1f1? y/N: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "y", + }) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | + ^  d1f1 │~ | +   d2 │~ | +  f1 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] trash.cmd 'foobarbaz' is not an executable. | + ]], + }) + + na.file_exists("/tmp/nvt_func/data/d1/d1f1") + end) + + + it("ignore root", function() + screen = nf.create_session({}, nil, nil, nil) + + nu.feed_sync({ + ":NvimTreeOpen", + "D", + }) + + screen:expect({ + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | +  f1 │~ | +~ │~ |*18 +NvimTree_1 [-] [No Name] | +:NvimTreeOpen | + ]], + }) + + na.dir_exists("/tmp/nvt_func/data/d1") + na.file_exists("/tmp/nvt_func/data/d1/d1f1") + na.dir_exists("/tmp/nvt_func/data/d2") + na.file_exists("/tmp/nvt_func/data/d2/d2f1") + na.file_exists("/tmp/nvt_func/data/f1") + end) +end) + +-- vim:colorcolumn=80 diff --git a/test/nvt/func/init_live.lua b/test/nvt/func/init_live.lua index e0b5aa21e3b..80f055f9140 100644 --- a/test/nvt/func/init_live.lua +++ b/test/nvt/func/init_live.lua @@ -77,7 +77,11 @@ local dir = out:match("^DIR=(.*)$") or error(out) vim.api.nvim_set_current_dir(dir) -- setup with defaults -require("nvim-tree").setup({}) +require("nvim-tree").setup({ + trash = { + cmd = "rm -rf ", + } +}) -- mappings vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) From 53aa6441c3c1e4b97e62b690a31c465384b085b9 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 09:14:47 +1100 Subject: [PATCH 129/154] test: add buf_exists asserts, fs.trash tests, wip --- test/nvt/func/asserts.lua | 23 +++++++++++ test/nvt/func/fs/move/node_spec.lua | 1 - test/nvt/func/fs/paste/cut_spec.lua | 9 +--- test/nvt/func/fs/trash/node_spec.lua | 61 ++++++++++++++++++++-------- 4 files changed, 68 insertions(+), 26 deletions(-) diff --git a/test/nvt/func/asserts.lua b/test/nvt/func/asserts.lua index 85e3b77acc4..126c43188eb 100644 --- a/test/nvt/func/asserts.lua +++ b/test/nvt/func/asserts.lua @@ -35,4 +35,27 @@ function M.events_received(events) end)) end +---buffer with name exists and is loaded +---@param name string buffer name +---@return boolean +local function buf_loaded(name) + return vim.tbl_contains(n.api.nvim_list_bufs(), + function(buf) + return n.api.nvim_buf_get_name(buf) == name and n.api.nvim_buf_is_loaded(buf) + end, { predicate = true } + ) +end + +---Assert buffer with name exists and is loaded +---@param name string buffer name +function M.buf_exists(name) + t.eq(true, buf_loaded(name), "buffer '" .. name .. "' should be present and loaded") +end + +---Assert buffer with name does not exist +---@param name string buffer name +function M.not_buf_exists(name) + t.eq(false, buf_loaded(name), "buffer '" .. name .. "' should not be present") +end + return M diff --git a/test/nvt/func/fs/move/node_spec.lua b/test/nvt/func/fs/move/node_spec.lua index c65b9f93a74..81d9ad3d50d 100644 --- a/test/nvt/func/fs/move/node_spec.lua +++ b/test/nvt/func/fs/move/node_spec.lua @@ -96,7 +96,6 @@ NvimTree_1 [-] [No Name] ]], }) - -- TODO remove hardcoding na.dir_exists("/tmp/nvt_func/data/dst") na.file_exists("/tmp/nvt_func/data/dst/f1") na.not_path_exists("/tmp/nvt_func/data/src/f1") diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index fff5aea6959..b7e4a03b4f9 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -113,14 +113,7 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 }, }, }) - t.eq(true, - vim.tbl_contains(n.api.nvim_list_bufs(), - function(buf) - return n.api.nvim_buf_get_name(buf) == "/tmp/nvt_func/data/d3/f1" and n.api.nvim_buf_is_loaded(buf) - end, { predicate = true } - ), - "buffer for /tmp/nvt_func/data/d3/f1 present and loaded" - ) + na.buf_exists("/tmp/nvt_func/data/d3/f1") end) diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index 7b7d4829358..c17ed134825 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -15,27 +15,40 @@ local screen -- TODO test: --- clear buffer -- many --- events -- failed file and dir +---@param config nvim_tree.config +---@return test.functional.ui.screen +local function create_trash_session(config) + screen = nf.create_session(config, nil, nil, { ext_cmdline = true, }) + + local Event = require("nvim-tree._meta.api.events").Event + nf.event_subscribe(Event.FileRemoved) + nf.event_subscribe(Event.WillRemoveFile) + nf.event_subscribe(Event.FolderRemoved) + + return screen +end + describe("fs.trash", function() - it("single file", function() - screen = nf.create_session({ + it("single file buffer deleted", function() + screen = create_trash_session({ trash = { -- TODO this executes async, need to wait for completion and tree to update, maybe disable watchers -- cmd = "sleep 1; rm ", cmd = "rm ", } - }, nil, nil, { ext_cmdline = true, }) + }) nu.feed_sync({ ":NvimTreeOpen", "", "", "", + "", + ":NvimTreeFocus", "D", }) @@ -52,28 +65,33 @@ describe("fs.trash", function() cmdline = { { abort = true } }, attr_ids = {}, grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | - ^  d2 │~ | -  f1 │~ | -~ │~ |*18 -NvimTree_1 [-] [No Name] | + /tmp/nvt_func/data/.. | +   d1 | + ^  d2 | +  f1 | +~ |*19 | ]], }) na.not_path_exists("/tmp/nvt_func/data/d1/d1f1") + na.not_buf_exists("/tmp/nvt_func/data/d1/d1f1") + + na.events_received({ + { event_type = "WillRemoveFile", payload = { fname = "/tmp/nvt_func/data/d1/d1f1", }, }, + { event_type = "FileRemoved", payload = { fname = "/tmp/nvt_func/data/d1/d1f1", }, }, + }) end) it("single dir", function() - screen = nf.create_session({ + screen = create_trash_session({ trash = { -- TODO this executes async, need to wait for completion and tree to update, maybe disable watchers -- cmd = "sleep 1; rm -rf ", cmd = "rm -rf ", } - }, nil, nil, { ext_cmdline = true, }) + }) nu.feed_sync({ ":NvimTreeOpen", @@ -107,15 +125,19 @@ NvimTree_1 [-] [No Name] }) na.not_path_exists("/tmp/nvt_func/data/d1") + + na.events_received({ + { event_type = "FolderRemoved", payload = { folder_name = "/tmp/nvt_func/data/d1", }, }, + }) end) it("invalid trash.cmd", function() - screen = nf.create_session({ + screen = create_trash_session({ trash = { cmd = "foobarbaz", } - }, nil, nil, { ext_cmdline = true, }) + }) nu.feed_sync({ ":NvimTreeOpen", @@ -150,11 +172,13 @@ NvimTree_1 [-] [No Name] }) na.file_exists("/tmp/nvt_func/data/d1/d1f1") + + na.events_received({}) end) it("ignore root", function() - screen = nf.create_session({}, nil, nil, nil) + screen = create_trash_session({}) nu.feed_sync({ ":NvimTreeOpen", @@ -162,6 +186,7 @@ NvimTree_1 [-] [No Name] }) screen:expect({ + cmdline = {}, attr_ids = {}, grid = [[ ^/tmp/nvt_func/data/.. │ | @@ -170,7 +195,7 @@ NvimTree_1 [-] [No Name]  f1 │~ | ~ │~ |*18 NvimTree_1 [-] [No Name] | -:NvimTreeOpen | + | ]], }) @@ -179,6 +204,8 @@ NvimTree_1 [-] [No Name] na.dir_exists("/tmp/nvt_func/data/d2") na.file_exists("/tmp/nvt_func/data/d2/d2f1") na.file_exists("/tmp/nvt_func/data/f1") + + na.events_received({}) end) end) From 72c61f645bf7ffc4724e63e8364e517f394b89ce Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 09:47:53 +1100 Subject: [PATCH 130/154] test: fs.trash tests, wip --- test/nvt/func/fs/trash/data/d 1/d 1 f 1 | 1 + test/nvt/func/fs/trash/data/d 2/d 2 f 1 | 1 + test/nvt/func/fs/trash/data/d1/d1f1 | 1 - test/nvt/func/fs/trash/data/d2/d2f1 | 1 - test/nvt/func/fs/trash/data/f 1 | 1 + test/nvt/func/fs/trash/data/f1 | 1 - test/nvt/func/fs/trash/node_spec.lua | 113 ++++++++++++++++++------ 7 files changed, 87 insertions(+), 32 deletions(-) create mode 100644 test/nvt/func/fs/trash/data/d 1/d 1 f 1 create mode 100644 test/nvt/func/fs/trash/data/d 2/d 2 f 1 delete mode 100644 test/nvt/func/fs/trash/data/d1/d1f1 delete mode 100644 test/nvt/func/fs/trash/data/d2/d2f1 create mode 100644 test/nvt/func/fs/trash/data/f 1 delete mode 100644 test/nvt/func/fs/trash/data/f1 diff --git a/test/nvt/func/fs/trash/data/d 1/d 1 f 1 b/test/nvt/func/fs/trash/data/d 1/d 1 f 1 new file mode 100644 index 00000000000..5515d8cd4d4 --- /dev/null +++ b/test/nvt/func/fs/trash/data/d 1/d 1 f 1 @@ -0,0 +1 @@ +d 1 f 1 diff --git a/test/nvt/func/fs/trash/data/d 2/d 2 f 1 b/test/nvt/func/fs/trash/data/d 2/d 2 f 1 new file mode 100644 index 00000000000..622cb1eb8e7 --- /dev/null +++ b/test/nvt/func/fs/trash/data/d 2/d 2 f 1 @@ -0,0 +1 @@ +d 2 f 1 diff --git a/test/nvt/func/fs/trash/data/d1/d1f1 b/test/nvt/func/fs/trash/data/d1/d1f1 deleted file mode 100644 index 13d1560f267..00000000000 --- a/test/nvt/func/fs/trash/data/d1/d1f1 +++ /dev/null @@ -1 +0,0 @@ -d1f1 diff --git a/test/nvt/func/fs/trash/data/d2/d2f1 b/test/nvt/func/fs/trash/data/d2/d2f1 deleted file mode 100644 index f901b65feae..00000000000 --- a/test/nvt/func/fs/trash/data/d2/d2f1 +++ /dev/null @@ -1 +0,0 @@ -d2f1 diff --git a/test/nvt/func/fs/trash/data/f 1 b/test/nvt/func/fs/trash/data/f 1 new file mode 100644 index 00000000000..95635f9f126 --- /dev/null +++ b/test/nvt/func/fs/trash/data/f 1 @@ -0,0 +1 @@ +f 1 diff --git a/test/nvt/func/fs/trash/data/f1 b/test/nvt/func/fs/trash/data/f1 deleted file mode 100644 index 8e1e71d5ce3..00000000000 --- a/test/nvt/func/fs/trash/data/f1 +++ /dev/null @@ -1 +0,0 @@ -f1 diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index c17ed134825..fec39b1e567 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -15,7 +15,6 @@ local screen -- TODO test: --- many -- failed file and dir ---@param config nvim_tree.config @@ -54,7 +53,7 @@ describe("fs.trash", function() screen:expect({ mode = "cmdline_normal", - cmdline = { { prompt = "Trash d1f1? y/N: ", content = { { "" } }, pos = 0, } }, + cmdline = { { prompt = "Trash d 1 f 1? y/N: ", content = { { "" } }, pos = 0, } }, }) nu.feed_sync({ @@ -66,20 +65,20 @@ describe("fs.trash", function() attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. | -   d1 | - ^  d2 | -  f1 | +   d 1 | + ^  d 2 | +  f 1 | ~ |*19 | ]], }) - na.not_path_exists("/tmp/nvt_func/data/d1/d1f1") - na.not_buf_exists("/tmp/nvt_func/data/d1/d1f1") + na.not_path_exists("/tmp/nvt_func/data/d 1/d 1 f 1") + na.not_buf_exists("/tmp/nvt_func/data/d 1/d 1 f 1") na.events_received({ - { event_type = "WillRemoveFile", payload = { fname = "/tmp/nvt_func/data/d1/d1f1", }, }, - { event_type = "FileRemoved", payload = { fname = "/tmp/nvt_func/data/d1/d1f1", }, }, + { event_type = "WillRemoveFile", payload = { fname = "/tmp/nvt_func/data/d 1/d 1 f 1", }, }, + { event_type = "FileRemoved", payload = { fname = "/tmp/nvt_func/data/d 1/d 1 f 1", }, }, }) end) @@ -101,7 +100,7 @@ describe("fs.trash", function() screen:expect({ mode = "cmdline_normal", - cmdline = { { prompt = "Trash d1? y/N: ", content = { { "" } }, pos = 0, } }, + cmdline = { { prompt = "Trash d 1? y/N: ", content = { { "" } }, pos = 0, } }, }) nu.feed_sync({ @@ -115,23 +114,79 @@ describe("fs.trash", function() attr_ids = {}, grid = [[ ^/tmp/nvt_func/data/.. │ | -   d2 │~ | -  d2f1 │~ | -  f1 │~ | +   d 2 │~ | +  d 2 f 1 │~ | +  f 1 │~ | ~ │~ |*18 NvimTree_1 [-] [No Name] | | ]], }) - na.not_path_exists("/tmp/nvt_func/data/d1") + na.not_path_exists("/tmp/nvt_func/data/d 1") na.events_received({ - { event_type = "FolderRemoved", payload = { folder_name = "/tmp/nvt_func/data/d1", }, }, + { event_type = "FolderRemoved", payload = { folder_name = "/tmp/nvt_func/data/d 1", }, }, }) end) + it("many", function() + screen = create_trash_session({ + trash = { + -- TODO this executes async, need to wait for completion and tree to update, maybe disable watchers + -- cmd = "sleep 1; rm -rf ", + cmd = "rm -rf ", + } + }) + + nu.feed_sync({ + ":NvimTreeOpen", + "", + "", + "", + "", + "", + "D", + }) + + screen:expect({ + mode = "cmdline_normal", + cmdline = { { prompt = "Trash 3 selected? y/N: ", content = { { "" } }, pos = 0, } }, + }) + + nu.feed_sync({ + "y", + "gg", + "E", + }) + + screen:expect({ + cmdline = { { abort = true } }, + attr_ids = {}, + grid = [[ + ^/tmp/nvt_func/data/.. │ | +   d 1 │~ | +~ │~ |*20 +NvimTree_1 [-] [No Name] | + | + ]], + }) + + na.events_received({ + { event_type = "WillRemoveFile", payload = { fname = "/tmp/nvt_func/data/d 1/d 1 f 1", }, }, + { event_type = "WillRemoveFile", payload = { fname = "/tmp/nvt_func/data/f 1", }, }, + { event_type = "FileRemoved", payload = { fname = "/tmp/nvt_func/data/d 1/d 1 f 1", }, }, + { event_type = "FolderRemoved", payload = { folder_name = "/tmp/nvt_func/data/d 2", }, }, + { event_type = "FileRemoved", payload = { fname = "/tmp/nvt_func/data/f 1", }, }, + }) + + na.not_path_exists("/tmp/nvt_func/data/d 1/d 1 f 1") + na.not_path_exists("/tmp/nvt_func/data/d 2") + na.not_path_exists("/tmp/nvt_func/data/f 1") + end) + + it("invalid trash.cmd", function() screen = create_trash_session({ trash = { @@ -149,7 +204,7 @@ NvimTree_1 [-] [No Name] screen:expect({ mode = "cmdline_normal", - cmdline = { { prompt = "Trash d1f1? y/N: ", content = { { "" } }, pos = 0, } }, + cmdline = { { prompt = "Trash d 1 f 1? y/N: ", content = { { "" } }, pos = 0, } }, }) nu.feed_sync({ @@ -161,17 +216,17 @@ NvimTree_1 [-] [No Name] attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | -   d1 │~ | - ^  d1f1 │~ | -   d2 │~ | -  f1 │~ | +   d 1 │~ | + ^  d 1 f 1 │~ | +   d 2 │~ | +  f 1 │~ | ~ │~ |*17 NvimTree_1 [-] [No Name] | [NvimTree] trash.cmd 'foobarbaz' is not an executable. | ]], }) - na.file_exists("/tmp/nvt_func/data/d1/d1f1") + na.file_exists("/tmp/nvt_func/data/d 1/d 1 f 1") na.events_received({}) end) @@ -190,20 +245,20 @@ NvimTree_1 [-] [No Name] attr_ids = {}, grid = [[ ^/tmp/nvt_func/data/.. │ | -   d1 │~ | -   d2 │~ | -  f1 │~ | +   d 1 │~ | +   d 2 │~ | +  f 1 │~ | ~ │~ |*18 NvimTree_1 [-] [No Name] | | ]], }) - na.dir_exists("/tmp/nvt_func/data/d1") - na.file_exists("/tmp/nvt_func/data/d1/d1f1") - na.dir_exists("/tmp/nvt_func/data/d2") - na.file_exists("/tmp/nvt_func/data/d2/d2f1") - na.file_exists("/tmp/nvt_func/data/f1") + na.dir_exists("/tmp/nvt_func/data/d 1") + na.file_exists("/tmp/nvt_func/data/d 1/d 1 f 1") + na.dir_exists("/tmp/nvt_func/data/d 2") + na.file_exists("/tmp/nvt_func/data/d 2/d 2 f 1") + na.file_exists("/tmp/nvt_func/data/f 1") na.events_received({}) end) From 586343944f00cb0acf6c420b5e470d863b835847 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 11:26:32 +1100 Subject: [PATCH 131/154] test: fs.trash tests, wip --- test/nvt/func/README.md | 2 +- test/nvt/func/fs/trash/data/trash_fail.sh | 9 +++ test/nvt/func/fs/trash/node_spec.lua | 94 +++++++++++++++++------ test/nvt/func/init_live.lua | 17 ++-- 4 files changed, 86 insertions(+), 36 deletions(-) create mode 100755 test/nvt/func/fs/trash/data/trash_fail.sh diff --git a/test/nvt/func/README.md b/test/nvt/func/README.md index 7934e1cf1bd..69f084727a3 100644 --- a/test/nvt/func/README.md +++ b/test/nvt/func/README.md @@ -2,7 +2,7 @@ Execute `scripts/functionaltest.sh -l [ ]` -This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua` +This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua`. Add any test specific config to `require("nvim-tree").setup` when needed. If a `data` directory is present, it will be copied and the session will execute in `/tmp/nvt_func/data` otherwise `/tmp/nvt_func`. diff --git a/test/nvt/func/fs/trash/data/trash_fail.sh b/test/nvt/func/fs/trash/data/trash_fail.sh new file mode 100755 index 00000000000..f74fb732638 --- /dev/null +++ b/test/nvt/func/fs/trash/data/trash_fail.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env sh + +if [ "${1}" == "/tmp/nvt_func/data/f 1" ]; then + rm "${1}" + exit 0 +else + printf "synthetic trash failure" >&2 + exit 1 +fi diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index fec39b1e567..b8ada9dca2b 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -14,13 +14,14 @@ local it = t.it or it local screen --- TODO test: --- failed file and dir +-- TODO the command executes async, need to wait for completion and tree to update, maybe disable watchers or wait for TreeRendered event +-- cmd = "sleep 5; rm -rf ", + ---@param config nvim_tree.config ---@return test.functional.ui.screen local function create_trash_session(config) - screen = nf.create_session(config, nil, nil, { ext_cmdline = true, }) + screen = nf.create_session(config, nil, nil, { ext_messages = true, }) local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.FileRemoved) @@ -35,9 +36,7 @@ describe("fs.trash", function() it("single file buffer deleted", function() screen = create_trash_session({ trash = { - -- TODO this executes async, need to wait for completion and tree to update, maybe disable watchers - -- cmd = "sleep 1; rm ", - cmd = "rm ", + cmd = "rm -rf ", } }) @@ -52,7 +51,6 @@ describe("fs.trash", function() }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Trash d 1 f 1? y/N: ", content = { { "" } }, pos = 0, } }, }) @@ -61,16 +59,15 @@ describe("fs.trash", function() }) screen:expect({ - cmdline = { { abort = true } }, attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. |   d 1 | ^  d 2 |  f 1 | +  trash_fail.sh | ~ |*19 - | - ]], + ]], }) na.not_path_exists("/tmp/nvt_func/data/d 1/d 1 f 1") @@ -86,8 +83,6 @@ describe("fs.trash", function() it("single dir", function() screen = create_trash_session({ trash = { - -- TODO this executes async, need to wait for completion and tree to update, maybe disable watchers - -- cmd = "sleep 1; rm -rf ", cmd = "rm -rf ", } }) @@ -99,7 +94,6 @@ describe("fs.trash", function() }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Trash d 1? y/N: ", content = { { "" } }, pos = 0, } }, }) @@ -110,16 +104,15 @@ describe("fs.trash", function() }) screen:expect({ - cmdline = { { abort = true } }, attr_ids = {}, grid = [[ ^/tmp/nvt_func/data/.. │ |   d 2 │~ |  d 2 f 1 │~ |  f 1 │~ | +  trash_fail.sh │~ | ~ │~ |*18 NvimTree_1 [-] [No Name] | - | ]], }) @@ -134,8 +127,6 @@ NvimTree_1 [-] [No Name] it("many", function() screen = create_trash_session({ trash = { - -- TODO this executes async, need to wait for completion and tree to update, maybe disable watchers - -- cmd = "sleep 1; rm -rf ", cmd = "rm -rf ", } }) @@ -151,8 +142,8 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Trash 3 selected? y/N: ", content = { { "" } }, pos = 0, } }, + showmode = { { "-- VISUAL LINE --", 5, "ModeMsg" } }, }) nu.feed_sync({ @@ -162,14 +153,13 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - cmdline = { { abort = true } }, attr_ids = {}, grid = [[ ^/tmp/nvt_func/data/.. │ |   d 1 │~ | +  trash_fail.sh │~ | ~ │~ |*20 NvimTree_1 [-] [No Name] | - | ]], }) @@ -203,7 +193,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Trash d 1 f 1? y/N: ", content = { { "" } }, pos = 0, } }, }) @@ -212,7 +201,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - cmdline = { { abort = true } }, attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | @@ -220,10 +208,11 @@ NvimTree_1 [-] [No Name] ^  d 1 f 1 │~ |   d 2 │~ |  f 1 │~ | +  trash_fail.sh │~ | ~ │~ |*17 NvimTree_1 [-] [No Name] | -[NvimTree] trash.cmd 'foobarbaz' is not an executable. | ]], + messages = { { content = { { "[NvimTree] trash.cmd 'foobarbaz' is not an executable.", "WarningMsg" } }, history = true, kind = "echomsg" }, } }) na.file_exists("/tmp/nvt_func/data/d 1/d 1 f 1") @@ -241,16 +230,15 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - cmdline = {}, attr_ids = {}, grid = [[ ^/tmp/nvt_func/data/.. │ |   d 1 │~ |   d 2 │~ |  f 1 │~ | +  trash_fail.sh │~ | ~ │~ |*18 NvimTree_1 [-] [No Name] | - | ]], }) @@ -262,6 +250,62 @@ NvimTree_1 [-] [No Name] na.events_received({}) end) + + + it("many multiple failures", function() + screen = create_trash_session({ + trash = { + -- fails unless "/tmp/nvt_func/data/f 1", prints same error message as execution completion is nondeterministic + cmd = "./trash_fail.sh", + } + }) + + nu.feed_sync({ + ":NvimTreeOpen", + "", + "", + "", + "", + "", + "D", + }) + + screen:expect({ + cmdline = { { prompt = "Trash 3 selected? y/N: ", content = { { "" } }, pos = 0, } }, + showmode = { { "-- VISUAL LINE --", 5, "ModeMsg" } } + }) + + nu.feed_sync({ + "y", + }) + + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d 1 │~ | +  d 1 f 1 │~ | +   d 2 │~ | + ^  trash_fail.sh │~ | +~ │~ |*18 +NvimTree_1 [-] [No Name] | + ]], + messages = { + { content = { { "[NvimTree] trash failed: synthetic trash failure; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" }, + { content = { { "[NvimTree] trash failed: synthetic trash failure; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" } + }, + }) + + na.events_received({ + { event_type = "WillRemoveFile", payload = { fname = "/tmp/nvt_func/data/d 1/d 1 f 1", }, }, + { event_type = "WillRemoveFile", payload = { fname = "/tmp/nvt_func/data/f 1", }, }, + { event_type = "FileRemoved", payload = { fname = "/tmp/nvt_func/data/f 1", }, }, + }) + + na.file_exists("/tmp/nvt_func/data/d 1/d 1 f 1") + na.dir_exists("/tmp/nvt_func/data/d 2") + na.not_path_exists("/tmp/nvt_func/data/f 1") + end) end) -- vim:colorcolumn=80 diff --git a/test/nvt/func/init_live.lua b/test/nvt/func/init_live.lua index 80f055f9140..6a4f9f888e0 100644 --- a/test/nvt/func/init_live.lua +++ b/test/nvt/func/init_live.lua @@ -76,15 +76,12 @@ local out = vim.fn.system({ os.getenv("NVT_FUNC_SCRIPT_CREATE_TEST_CWD") }) local dir = out:match("^DIR=(.*)$") or error(out) vim.api.nvim_set_current_dir(dir) --- setup with defaults +-- mappings +vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) +vim.keymap.set("n", "c", function() live_dump(true) end, { remap = false, }) +vim.keymap.set("n", "r", screen_resize, { remap = false, }) +vim.keymap.set("n", "o", function() require("nvim-tree.api").tree.open() end, { remap = false, }) + +-- add test specific setup here require("nvim-tree").setup({ - trash = { - cmd = "rm -rf ", - } }) - --- mappings -vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) -vim.keymap.set("n", "c", function() live_dump(true) end, { remap = false, }) -vim.keymap.set("n", "r", screen_resize, { remap = false, }) -vim.keymap.set("n", "o", require("nvim-tree.api").tree.open, { remap = false, }) From b188f99190f69bf9a96b57353f9a486b1449a164 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 11:32:09 +1100 Subject: [PATCH 132/154] test: fs.trash tests, wip --- test/nvt/func/fs/trash/data/trash_fail.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nvt/func/fs/trash/data/trash_fail.sh b/test/nvt/func/fs/trash/data/trash_fail.sh index f74fb732638..bab84cfd864 100755 --- a/test/nvt/func/fs/trash/data/trash_fail.sh +++ b/test/nvt/func/fs/trash/data/trash_fail.sh @@ -4,6 +4,6 @@ if [ "${1}" == "/tmp/nvt_func/data/f 1" ]; then rm "${1}" exit 0 else - printf "synthetic trash failure" >&2 + echo -n "synthetic trash failure" >&2 exit 1 fi From 5ddb6f6cb37ec5dda04b4731d16e9939e826d28b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 11:40:14 +1100 Subject: [PATCH 133/154] test: tidy any unnecessary ext_cmdline --- test/nvt/func/fs/create/dir_spec.lua | 2 +- test/nvt/func/fs/create/file_spec.lua | 2 +- test/nvt/func/fs/create/prompt_spec.lua | 3 --- test/nvt/func/fs/paste/copied_spec.lua | 16 ---------------- test/nvt/func/fs/paste/cut_spec.lua | 6 +----- test/nvt/func/fs/trash/node_spec.lua | 2 +- 6 files changed, 4 insertions(+), 27 deletions(-) diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index d4a68e20e9f..8fce02d3244 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -16,7 +16,7 @@ local screen before_each(function() - screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) + screen = nf.create_session() local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.FolderCreated) diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 7de5901833d..46db8bbdd12 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -16,7 +16,7 @@ local screen before_each(function() - screen = nf.create_session({}, nil, nil, { ext_cmdline = true }) + screen = nf.create_session() local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.FileCreated) diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index 0701db07188..d6332e12ce4 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -28,7 +28,6 @@ describe("fs.create prompt", function() }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, }) end) @@ -50,7 +49,6 @@ describe("fs.create prompt", function() n.poke_eventloop() screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/d1/" } }, pos = 22, } }, }) end) @@ -64,7 +62,6 @@ describe("fs.create prompt", function() }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, }) end) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index a7026f84ba6..f7d10d143e6 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -142,7 +142,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) @@ -190,7 +189,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) @@ -241,7 +239,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) @@ -250,7 +247,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) @@ -301,7 +297,6 @@ Press ENTER or type command to continue^ }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) @@ -310,7 +305,6 @@ Press ENTER or type command to continue^ }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) @@ -353,7 +347,6 @@ Press ENTER or type command to continue^ }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) @@ -362,7 +355,6 @@ Press ENTER or type command to continue^ }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) @@ -371,7 +363,6 @@ Press ENTER or type command to continue^ }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d2" } }, pos = 21, } }, }) @@ -455,7 +446,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) @@ -503,7 +493,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) @@ -512,7 +501,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Suffix: ", content = { { "" } }, pos = 0, } }, }) @@ -566,7 +554,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) @@ -626,7 +613,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) @@ -636,7 +622,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2/f2.renamed ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) @@ -695,7 +680,6 @@ NvimTree_1 [-] [No Name] -- BUG: this should read as per single prompt: "2 file(s) already exist. R(ename suffix)/y/n: " screen:expect({ - mode = "cmdline_normal", cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index b7e4a03b4f9..d8290ed1ab5 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -19,7 +19,7 @@ local screen before_each(function() - screen = nf.create_session(nil, nil, nil, { ext_cmdline = true, }) + screen = nf.create_session() local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.NodeRenamed) @@ -38,7 +38,6 @@ describe("fs.paste cut", function() }) screen:expect({ - cmdline = {}, attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | @@ -85,7 +84,6 @@ NvimTree_1 [-] [No Name] }) screen:expect({ - cmdline = {}, attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │f1 | @@ -130,7 +128,6 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 end) screen:expect({ - cmdline = {}, attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | @@ -185,7 +182,6 @@ NvimTree_1 [-] [No Name] end) screen:expect({ - cmdline = {}, attr_ids = {}, grid = [[ /tmp/nvt_func/data/.. │ | diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index b8ada9dca2b..26e5b7b218e 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -272,7 +272,7 @@ NvimTree_1 [-] [No Name] screen:expect({ cmdline = { { prompt = "Trash 3 selected? y/N: ", content = { { "" } }, pos = 0, } }, - showmode = { { "-- VISUAL LINE --", 5, "ModeMsg" } } + showmode = { { "-- VISUAL LINE --", 5, "ModeMsg" } }, }) nu.feed_sync({ From e103c52b55ac0abf2c75366bccd7ce312173d699 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 11:50:59 +1100 Subject: [PATCH 134/154] test: fs.trash tests, wip --- test/nvt/func/fs/trash/data/trash_fail.sh | 1 - test/nvt/func/fs/trash/node_spec.lua | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/nvt/func/fs/trash/data/trash_fail.sh b/test/nvt/func/fs/trash/data/trash_fail.sh index bab84cfd864..7788e48cf56 100755 --- a/test/nvt/func/fs/trash/data/trash_fail.sh +++ b/test/nvt/func/fs/trash/data/trash_fail.sh @@ -4,6 +4,5 @@ if [ "${1}" == "/tmp/nvt_func/data/f 1" ]; then rm "${1}" exit 0 else - echo -n "synthetic trash failure" >&2 exit 1 fi diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index 26e5b7b218e..deaf00925df 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -255,7 +255,6 @@ NvimTree_1 [-] [No Name] it("many multiple failures", function() screen = create_trash_session({ trash = { - -- fails unless "/tmp/nvt_func/data/f 1", prints same error message as execution completion is nondeterministic cmd = "./trash_fail.sh", } }) @@ -291,8 +290,8 @@ NvimTree_1 [-] [No Name] NvimTree_1 [-] [No Name] | ]], messages = { - { content = { { "[NvimTree] trash failed: synthetic trash failure; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" }, - { content = { { "[NvimTree] trash failed: synthetic trash failure; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" } + { content = { { "[NvimTree] trash failed: ; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" }, + { content = { { "[NvimTree] trash failed: ; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" } }, }) From 71df0542cf6721c6326589c7d6b7abc99ee3670d Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 11:53:50 +1100 Subject: [PATCH 135/154] Revert "test: fs.trash tests, wip" This reverts commit e103c52b55ac0abf2c75366bccd7ce312173d699. --- test/nvt/func/fs/trash/data/trash_fail.sh | 1 + test/nvt/func/fs/trash/node_spec.lua | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/nvt/func/fs/trash/data/trash_fail.sh b/test/nvt/func/fs/trash/data/trash_fail.sh index 7788e48cf56..bab84cfd864 100755 --- a/test/nvt/func/fs/trash/data/trash_fail.sh +++ b/test/nvt/func/fs/trash/data/trash_fail.sh @@ -4,5 +4,6 @@ if [ "${1}" == "/tmp/nvt_func/data/f 1" ]; then rm "${1}" exit 0 else + echo -n "synthetic trash failure" >&2 exit 1 fi diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index deaf00925df..26e5b7b218e 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -255,6 +255,7 @@ NvimTree_1 [-] [No Name] it("many multiple failures", function() screen = create_trash_session({ trash = { + -- fails unless "/tmp/nvt_func/data/f 1", prints same error message as execution completion is nondeterministic cmd = "./trash_fail.sh", } }) @@ -290,8 +291,8 @@ NvimTree_1 [-] [No Name] NvimTree_1 [-] [No Name] | ]], messages = { - { content = { { "[NvimTree] trash failed: ; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" }, - { content = { { "[NvimTree] trash failed: ; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" } + { content = { { "[NvimTree] trash failed: synthetic trash failure; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" }, + { content = { { "[NvimTree] trash failed: synthetic trash failure; please see :help nvim-tree.trash", "WarningMsg" } }, history = true, kind = "echomsg" } }, }) From 8e9041bc057f5a6103cc9ed5a7eecc22c481718b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 11:54:22 +1100 Subject: [PATCH 136/154] test: fs.trash tests, wip --- test/nvt/func/fs/trash/data/trash_fail.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nvt/func/fs/trash/data/trash_fail.sh b/test/nvt/func/fs/trash/data/trash_fail.sh index bab84cfd864..4534a4f3e60 100755 --- a/test/nvt/func/fs/trash/data/trash_fail.sh +++ b/test/nvt/func/fs/trash/data/trash_fail.sh @@ -1,6 +1,6 @@ #!/usr/bin/env sh -if [ "${1}" == "/tmp/nvt_func/data/f 1" ]; then +if [ "${1}" = "/tmp/nvt_func/data/f 1" ]; then rm "${1}" exit 0 else From 78aaae7b9eb0780a54abbbd4f6880e1af0c2fde8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 12:14:14 +1100 Subject: [PATCH 137/154] test: notes on func test ext_cmdline and ext_messages --- test/nvt/func/README.md | 32 ++++++++++++++++++++++++++++ test/nvt/func/fs/trash/node_spec.lua | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/test/nvt/func/README.md b/test/nvt/func/README.md index 69f084727a3..8fe3f9c7405 100644 --- a/test/nvt/func/README.md +++ b/test/nvt/func/README.md @@ -39,3 +39,35 @@ The Nvim functional test framework's inputs are handled asynchronously via the c Prefer `test.nvt.func.util` `feed_sync` to feed keys synchronously (deferred), blocking the test thread and instance until the instance's main loop is complete. +# Test Mechanisms + +## Command Line + +`Screen:expect` `cmdline` may be used to assert command line state. `test.functional.ui.screen.Opts` `ext_cmdline` must be enabled, e.g. + +```lua +screen = nf.create_session({}, nil, nil, { ext_cmdline = true }) +--- +screen:expect({ + cmdline = { { prompt = "Create ", content = { { "/tmp/nvt_func/data/" } }, pos = 19, } }, +}) +``` + +## Messages + +Messages may be usually be asserted simply via `Screen:expect` `grid` + +In the case of complex or multiline messages, `test.functional.ui.screen.Opts` `ext_messages` may be used to capture messages for finer grained assertion. This will: + +- implicitly set `ext_cmdline` +- remove the command line from the screen `grid`; which you may need to adjust to match + +e.g. +```lua +screen = nf.create_session({}, nil, nil, { ext_messages = true, }) +--- +screen:expect({ + messages = { { content = { { "[NvimTree] trash.cmd 'foobarbaz' is not an executable.", "WarningMsg" } }, history = true, kind = "echomsg" }, } +}) +``` + diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index 26e5b7b218e..64d7dcbdbec 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -21,7 +21,7 @@ local screen ---@param config nvim_tree.config ---@return test.functional.ui.screen local function create_trash_session(config) - screen = nf.create_session(config, nil, nil, { ext_messages = true, }) + screen = nf.create_session(config, nil, nil, { ext_messages = true, ext_cmdline = true, }) local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.FileRemoved) From ead37d808129745cad6372f8555fb7ac8fb5d699 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 12:36:15 +1100 Subject: [PATCH 138/154] test: print/clear clipboard use ext_messages --- .../clear_clipboard/clear_clipboard_spec.lua | 86 ++++++++----------- .../print_clipboard/print_clipboard_spec.lua | 78 +++++------------ 2 files changed, 58 insertions(+), 106 deletions(-) diff --git a/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua index 6257caf1381..52784e71efc 100644 --- a/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua +++ b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua @@ -16,7 +16,7 @@ local screen before_each(function() - screen = nf.create_session() + screen = nf.create_session({}, nil, nil, { ext_messages = true, }) end) @@ -31,18 +31,7 @@ describe("fs.clear_clipboard", function() end) screen:expect({ - attr_ids = {}, - grid = [[ - ^/tmp/nvt_func/data/.. │ | -   d1 │~ | -   d2 │~ | -   d3 │~ | -  f1 │~ | -  f2 │~ | -~ │~ |*16 -NvimTree_1 [-] [No Name] | -[NvimTree] Clipboard has been emptied. | - ]], + messages = { { content = { { "[NvimTree] Clipboard has been emptied." } }, history = true, kind = "echomsg" }, } }) end) @@ -62,35 +51,44 @@ NvimTree_1 [-] [No Name] "x", }) - n.exec_lua(function() - require("nvim-tree.api").fs.print_clipboard() - end) - screen:expect({ + messages = { + { content = { { "[NvimTree] /tmp/nvt_func/data/d1/d1f1 added to clipboard." } }, history = true, kind = "echomsg" }, + { content = { { "[NvimTree] /tmp/nvt_func/data/d1/d1f2 added to clipboard." } }, history = true, kind = "echomsg" }, + { content = { { "[NvimTree] /tmp/nvt_func/data/d2 added to clipboard." } }, history = true, kind = "echomsg" }, + { content = { { "[NvimTree] /tmp/nvt_func/data/d3 added to clipboard." } }, history = true, kind = "echomsg" }, + }, grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCopiedHL:d1f1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: }{NvimTreeCutHL:d1f2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeCopiedHL:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:d3}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeCutHLCL:d3}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*7 -{3: }| -[NvimTree] | -Cut | - * /tmp/nvt_func/data/d1/d1f2 | - * /tmp/nvt_func/data/d3 | -Copy | - * /tmp/nvt_func/data/d1/d1f1 | - * /tmp/nvt_func/data/d2 | -{6:Press ENTER or type command to continue}^ | - ]], +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*15 +{NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| +]], }) - nu.feed_sync({ - "", + n.exec_lua(function() + require("nvim-tree.api").fs.print_clipboard() + end) + + screen:expect({ + messages = { { + history = true, + kind = "echomsg", + content = { { [[[NvimTree] +Cut + * /tmp/nvt_func/data/d1/d1f2 + * /tmp/nvt_func/data/d3 +Copy + * /tmp/nvt_func/data/d1/d1f1 + * /tmp/nvt_func/data/d2 +]], } }, + } }, }) n.exec_lua(function() @@ -98,19 +96,7 @@ Copy end) screen:expect({ - grid = [[ -{NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | -{NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeFolderNameCL:d3}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*14 -{NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| -[NvimTree] Clipboard has been emptied. | - ]], + messages = { { content = { { "[NvimTree] Clipboard has been emptied.", } }, history = true, kind = "echomsg", } }, }) n.exec_lua(function() @@ -118,21 +104,19 @@ Copy end) screen:expect({ + messages = { { content = { { "[NvimTree]\n\n", } }, history = true, kind = "echomsg", } }, grid = [[ {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | {NvimTreeSignColumn: }{NvimTreeFolderArrowOpen: }{NvimTreeOpenedFolderIcon:}{NvimTreeNormal: }{NvimTreeOpenedFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeIndentMarker: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: d1f2 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL: }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeFolderNameCL:d3}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| +{NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeClosedFolderIconCL:}{NvimTreeNormalCL: }{NvimTreeFolderNameCL:d3}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f1 }{NvimTreeWinSeparator:│}{1:~ }| {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| -{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*12 -{3: }| -[NvimTree] | - | -{6:Press ENTER or type command to continue}^ | - ]], +{NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*15 +{NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + ]], }) end) end) diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index 48902644592..43b0391399d 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -16,7 +16,7 @@ local screen before_each(function() - screen = nf.create_session() + screen = nf.create_session({}, nil, nil, { ext_messages = true, }) end) @@ -31,33 +31,7 @@ describe("fs.print_clipboard", function() end) screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | -   d2 │~ | -   d3 │~ | -  f1 │~ | -  f2 │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | - | -[NvimTree] | - | -Press ENTER or type command to continue^ | - ]], + messages = { { content = { { "[NvimTree]\n\n", } }, history = true, kind = "echomsg", } }, }) end) @@ -77,38 +51,32 @@ Press ENTER or type command to continue^ "x", }) + screen:expect({ + messages = { + { content = { { "[NvimTree] /tmp/nvt_func/data/d1/d1f1 added to clipboard." } }, history = true, kind = "echomsg" }, + { content = { { "[NvimTree] /tmp/nvt_func/data/d1/d1f2 added to clipboard." } }, history = true, kind = "echomsg" }, + { content = { { "[NvimTree] /tmp/nvt_func/data/d2 added to clipboard." } }, history = true, kind = "echomsg" }, + { content = { { "[NvimTree] /tmp/nvt_func/data/d3 added to clipboard." } }, history = true, kind = "echomsg" }, + }, + }) + n.exec_lua(function() require("nvim-tree.api").fs.print_clipboard() end) screen:expect({ - attr_ids = {}, - grid = [[ - /tmp/nvt_func/data/.. │ | -   d1 │~ | -  d1f1 │~ | -  d1f2 │~ | -   d2 │~ | -   d3 │~ | -  f1 │~ | -  f2 │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | -~ │~ | - | -[NvimTree] | -Cut | - * /tmp/nvt_func/data/d1/d1f2 | - * /tmp/nvt_func/data/d3 | -Copy | - * /tmp/nvt_func/data/d1/d1f1 | - * /tmp/nvt_func/data/d2 | -Press ENTER or type command to continue^ | - ]], + messages = { { + history = true, + kind = "echomsg", + content = { { [[[NvimTree] +Cut + * /tmp/nvt_func/data/d1/d1f2 + * /tmp/nvt_func/data/d3 +Copy + * /tmp/nvt_func/data/d1/d1f1 + * /tmp/nvt_func/data/d2 +]], } }, + } }, }) end) end) From c4f662a52911c6eaeeac9d83bda77e720bb6e90c Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 13:29:02 +1100 Subject: [PATCH 139/154] test: add missing file create message assertions, add functest globals to luals ignore --- .luarc.json | 6 ++++- test/nvt/func/asserts.lua | 5 +++- test/nvt/func/fixtures.lua | 16 +++--------- test/nvt/func/fs/create/file_spec.lua | 36 ++++++++++++++++++++++++++- 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/.luarc.json b/.luarc.json index 6d0a620bce1..6f3ba03d697 100644 --- a/.luarc.json +++ b/.luarc.json @@ -23,7 +23,11 @@ }, "diagnostics": { "libraryFiles": "Disable", - "globals": [], + "globals": [ + "NVT_FUNCTEST_CONTEXT", + "NVT_FUNCTEST_EVENTS", + "NVT_FUNCTEST_CLIPBOARD_LINES" + ], "neededFileStatus": { "ambiguity-1": "Any", "assign-type-mismatch": "Any", diff --git a/test/nvt/func/asserts.lua b/test/nvt/func/asserts.lua index 126c43188eb..0d7aaa58138 100644 --- a/test/nvt/func/asserts.lua +++ b/test/nvt/func/asserts.lua @@ -28,10 +28,13 @@ end ---Assert events received during a functest, recorded in session global NVT_FUNCTEST_EVENTS ---Must be subscribed via event_subscribe +---Clears events as per ext_messages ---@param events nvt.functest.event[] function M.events_received(events) t.eq(events, n.exec_lua(function() - return NVT_FUNCTEST_EVENTS + local ev = vim.deepcopy(NVT_FUNCTEST_EVENTS) + NVT_FUNCTEST_EVENTS = {} + return ev end)) end diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index c711702d665..e4c5d5c738d 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -8,19 +8,13 @@ local Screen = require("test.functional.ui.screen") ---Globals used within test session context, noted in this test context only for type definition ----@diagnostic disable: global-element - ---@type boolean NVT_FUNCTEST_CONTEXT = true - ---@type nvt.functest.event[] NVT_FUNCTEST_EVENTS = {} - ---@type string[] NVT_FUNCTEST_CLIPBOARD_LINES = {} ----@diagnostic enable: global-element - local M = {} @@ -44,11 +38,9 @@ function M.create_session(config, width, height, options) vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH") or "") vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) - ---@diagnostic disable: global-element NVT_FUNCTEST_CONTEXT = true NVT_FUNCTEST_EVENTS = {} NVT_FUNCTEST_CLIPBOARD_LINES = {} - ---@diagnostic enable: global-element end) -- Change to the temp test (data) directory @@ -87,18 +79,18 @@ end ---Clear all recorded events in NVT_FUNCTEST_EVENTS function M.events_clear() n.exec_lua(function() - NVT_FUNCTEST_EVENTS = {} ---@diagnostic disable-line: global-element + NVT_FUNCTEST_EVENTS = {} end) end ----Setup a dummy clipboard using the global NVT_DUMMY_CLIPBOARD_LINES +---Setup a dummy clipboard named NVT_FUNCTEST_CLIPBOARD containing the global NVT_FUNCTEST_CLIPBOARD_LINES function M.use_dummy_clipboard() n.exec_lua(function() vim.g.clipboard = { - name = "NVT_DUMMY_CLIPBOARD", + name = "NVT_FUNCTEST_CLIPBOARD", copy = { ["+"] = function(lines) - NVT_FUNCTEST_CLIPBOARD_LINES = lines ---@diagnostic disable-line: global-element + NVT_FUNCTEST_CLIPBOARD_LINES = lines end }, paste = { diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 46db8bbdd12..ff560df1e5a 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -214,11 +214,45 @@ NvimTree_1 [-] [No Name] "", }) - -- BUG this fails but shows message "/foo was properly created" n.feed( "/foo" ) + -- BUG this fails but shows message "/foo was properly created" + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +  f1 │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | +~ │~ | + | +[NvimTree] Couldn't create file /foo | +[NvimTree] /foo was properly created | +Press ENTER or type command to continue^ | + ]], + }) + + n.feed( + "" + ) + na.events_received({ { event_type = "WillCreateFile", payload = { fname = "/foo", }, }, }) From a80291197d391a0e31cfbbe2dc963c7a01765eaa Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 13:37:17 +1100 Subject: [PATCH 140/154] test: namespace functionaltest methods so that 0.12 global compatibility may be completely removed --- .../clear_clipboard/clear_clipboard_spec.lua | 16 +++----- test/nvt/func/fs/copy/node_spec.lua | 28 ++++++------- test/nvt/func/fs/create/dir_spec.lua | 30 ++++++-------- test/nvt/func/fs/create/file_spec.lua | 26 +++++------- test/nvt/func/fs/create/prompt_spec.lua | 20 ++++------ test/nvt/func/fs/cut/node_spec.lua | 30 ++++++-------- test/nvt/func/fs/move/node_spec.lua | 18 ++++----- test/nvt/func/fs/paste/copied_spec.lua | 40 +++++++++---------- test/nvt/func/fs/paste/cut_spec.lua | 20 ++++------ .../print_clipboard/print_clipboard_spec.lua | 16 +++----- test/nvt/func/fs/trash/node_spec.lua | 21 +++++----- 11 files changed, 111 insertions(+), 154 deletions(-) diff --git a/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua index 52784e71efc..6d467febd6c 100644 --- a/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua +++ b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua @@ -3,25 +3,21 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session({}, nil, nil, { ext_messages = true, }) end) -describe("fs.clear_clipboard", function() - it("empty", function() +t.describe("fs.clear_clipboard", function() + t.it("empty", function() nu.feed_sync({ ":NvimTreeOpen", }) @@ -36,7 +32,7 @@ describe("fs.clear_clipboard", function() end) - it("many", function() + t.it("many", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index 312e7a32143..abaa1f5fefc 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -3,24 +3,20 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session() end) -describe("fs.copy", function() - it("single file", function() +t.describe("fs.copy", function() + t.it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -48,7 +44,7 @@ describe("fs.copy", function() end) - it("api single file", function() + t.it("api single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -78,7 +74,7 @@ describe("fs.copy", function() }) end) - it("single dir", function() + t.it("single dir", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -104,7 +100,7 @@ describe("fs.copy", function() end) - it("toggle one", function() + t.it("toggle one", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -151,7 +147,7 @@ NvimTree_1 [-] [No Name] end) - it("toggle many", function() + t.it("toggle many", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -200,7 +196,7 @@ NvimTree_1 [-] [No Name] end) - it("no system clipboard", function() + t.it("no system clipboard", function() n.exec_lua(function() require("nvim-tree").setup({ actions = { @@ -237,7 +233,7 @@ NvimTree_1 [-] [No Name] end) - it("overrides cut", function() + t.it("overrides cut", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -282,7 +278,7 @@ NvimTree_1 [-] [No Name] end) - it("dir overrides file", function() + t.it("dir overrides file", function() n.fn.setreg("+", "foo") nu.feed_sync({ diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 8fce02d3244..5ef59c629a6 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -4,18 +4,14 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session() local Event = require("nvim-tree._meta.api.events").Event @@ -23,8 +19,8 @@ before_each(function() end) -describe("fs.create dir", function() - it("single direct", function() +t.describe("fs.create dir", function() + t.it("single direct", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -52,7 +48,7 @@ NvimTree_1 [-] [No Name] end) - it("single indirect", function() + t.it("single indirect", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -81,7 +77,7 @@ NvimTree_1 [-] [No Name] end) - it("api single indirect", function() + t.it("api single indirect", function() nu.feed_sync({ ":NvimTreeOpen", }) @@ -120,7 +116,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple direct", function() + t.it("multiple direct", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -152,7 +148,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple indirect", function() + t.it("multiple indirect", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -185,7 +181,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when file exists", function() + t.it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -208,7 +204,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when file exists", function() + t.it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -234,7 +230,7 @@ NvimTree_1 [-] [No Name] end) - it("fails on invalid path", function() + t.it("fails on invalid path", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -258,7 +254,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when dir exists", function() + t.it("fails when dir exists", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index ff560df1e5a..5acedf8fe90 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -4,18 +4,14 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session() local Event = require("nvim-tree._meta.api.events").Event @@ -25,8 +21,8 @@ before_each(function() end) -describe("fs.create file", function() - it("direct", function() +t.describe("fs.create file", function() + t.it("direct", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -55,7 +51,7 @@ NvimTree_1 [-] [No Name] end) - it("indirect", function() + t.it("indirect", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -85,7 +81,7 @@ NvimTree_1 [-] [No Name] end) - it("api indirect", function() + t.it("api indirect", function() nu.feed_sync({ ":NvimTreeOpen", }) @@ -125,7 +121,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when file exists", function() + t.it("fails when file exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -150,7 +146,7 @@ NvimTree_1 [-] [No Name] end) - it("fails when dir exists", function() + t.it("fails when dir exists", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -175,7 +171,7 @@ NvimTree_1 [-] [No Name] end) - it("indirect creates dirs", function() + t.it("indirect creates dirs", function() nu.feed_sync({ ":NvimTreeOpen", "a", @@ -207,7 +203,7 @@ NvimTree_1 [-] [No Name] end) - it("fails on invalid path", function() + t.it("fails on invalid path", function() nu.feed_sync({ ":NvimTreeOpen", "a", diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index d6332e12ce4..71219c3114d 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -3,24 +3,20 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) end) -describe("fs.create prompt", function() - it("tree focused", function() +t.describe("fs.create prompt", function() + t.it("tree focused", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -33,7 +29,7 @@ describe("fs.create prompt", function() end) - it("api tree not focused", function() + t.it("api tree not focused", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -54,7 +50,7 @@ describe("fs.create prompt", function() end) - it("file focused", function() + t.it("file focused", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -67,7 +63,7 @@ describe("fs.create prompt", function() end) - it("cancelled", function() + t.it("cancelled", function() nu.feed_sync({ ":NvimTreeOpen", "a", diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index 56895ba88d4..2e0dd2b47be 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -3,12 +3,8 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global -- BUG single operations report "added to clipboard", not "cut to clipboard" as per bulk operations @@ -18,13 +14,13 @@ local it = t.it or it local screen -before_each(function() +t.before_each(function() screen = nf.create_session() end) -describe("fs.cut", function() - it("single file", function() +t.describe("fs.cut", function() + t.it("single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -52,7 +48,7 @@ describe("fs.cut", function() end) - it("api single file", function() + t.it("api single file", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -83,7 +79,7 @@ describe("fs.cut", function() end) - it("single dir", function() + t.it("single dir", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -108,7 +104,7 @@ describe("fs.cut", function() }) end) - it("toggle one", function() + t.it("toggle one", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -155,7 +151,7 @@ NvimTree_1 [-] [No Name] end) - it("toggle many", function() + t.it("toggle many", function() n.fn.setreg("+", "foo") nu.feed_sync({ @@ -204,7 +200,7 @@ NvimTree_1 [-] [No Name] end) - it("no system clipboard", function() + t.it("no system clipboard", function() n.exec_lua(function() require("nvim-tree").setup({ actions = { @@ -241,7 +237,7 @@ NvimTree_1 [-] [No Name] end) - it("single overrides copy", function() + t.it("single overrides copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -286,7 +282,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple overrides copy", function() + t.it("multiple overrides copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") @@ -353,7 +349,7 @@ NvimTree_1 [-] [No Name] end) - it("dir overrides file", function() + t.it("dir overrides file", function() n.fn.setreg("+", "foo") nu.feed_sync({ diff --git a/test/nvt/func/fs/move/node_spec.lua b/test/nvt/func/fs/move/node_spec.lua index 81d9ad3d50d..64e9c3b4326 100644 --- a/test/nvt/func/fs/move/node_spec.lua +++ b/test/nvt/func/fs/move/node_spec.lua @@ -4,25 +4,21 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session() end) -describe("fs.move", function() - it("nothing", function() +t.describe("fs.move", function() + t.it("nothing", function() n.fn.setreg("+", "") nu.feed_sync({ @@ -47,7 +43,7 @@ NvimTree_1 [-] [No Name] end) - it("inexistent", function() + t.it("inexistent", function() n.fn.setreg("+", "/tmp/nvt_func/data/inexistent") nu.feed_sync({ @@ -72,7 +68,7 @@ NvimTree_1 [-] [No Name] end) - it("present", function() + t.it("present", function() n.fn.setreg("+", "/tmp/nvt_func/data/src/f1") nu.feed_sync({ diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index f7d10d143e6..a2850d72789 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -3,12 +3,8 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen local screen @@ -17,13 +13,13 @@ local screen -- common copy/paste codepaths are tested here except for API -before_each(function() +t.before_each(function() screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) end) -describe("fs.paste copied", function() - it("single file", function() +t.describe("fs.paste copied", function() + t.it("single file", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -55,7 +51,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple files", function() + t.it("multiple files", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -93,7 +89,7 @@ NvimTree_1 [-] [No Name] end) - it("single dir", function() + t.it("single dir", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -132,7 +128,7 @@ NvimTree_1 [-] [No Name] end) - it("single dir conflict resolved", function() + t.it("single dir conflict resolved", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -179,7 +175,7 @@ NvimTree_1 [-] [No Name] end) - it("single dir conflict cancelled", function() + t.it("single dir conflict cancelled", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -229,7 +225,7 @@ NvimTree_1 [-] [No Name] end) - it("single dir conflict second conflict overwrite", function() + t.it("single dir conflict second conflict overwrite", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -287,7 +283,7 @@ Press ENTER or type command to continue^ end) - it("single dir conflict second conflict cancel", function() + t.it("single dir conflict second conflict cancel", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -337,7 +333,7 @@ Press ENTER or type command to continue^ end) - it("single dir conflict second conflict resolved", function() + t.it("single dir conflict second conflict resolved", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -392,7 +388,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple", function() + t.it("multiple", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -433,7 +429,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple conflict no rename", function() + t.it("multiple conflict no rename", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -480,7 +476,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple conflict rename suffix", function() + t.it("multiple conflict rename suffix", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -541,7 +537,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple conflict rename cancel", function() + t.it("multiple conflict rename cancel", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -590,7 +586,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple conflict rename second conflict", function() + t.it("multiple conflict rename second conflict", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -666,7 +662,7 @@ NvimTree_1 [-] [No Name] end) - it("multiple conflict overwrite", function() + t.it("multiple conflict overwrite", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index d8290ed1ab5..6462cf61f8f 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -4,12 +4,8 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen local screen @@ -18,7 +14,7 @@ local screen -- common copy/paste codepaths are tested in copied_spec.lua except for API -before_each(function() +t.before_each(function() screen = nf.create_session() local Event = require("nvim-tree._meta.api.events").Event @@ -26,8 +22,8 @@ before_each(function() end) -describe("fs.paste cut", function() - it("single dir", function() +t.describe("fs.paste cut", function() + t.it("single dir", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -72,7 +68,7 @@ NvimTree_1 [-] [No Name] end) - it("single file", function() + t.it("single file", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -115,7 +111,7 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 end) - it("api node under cursor", function() + t.it("api node under cursor", function() nu.feed_sync({ ":NvimTreeOpen", "", @@ -160,7 +156,7 @@ NvimTree_1 [-] [No Name] end) - it("api node specified", function() + t.it("api node specified", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index 43b0391399d..34835011de0 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -3,25 +3,21 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local before_each = t.before_each or before_each -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen local screen -before_each(function() +t.before_each(function() screen = nf.create_session({}, nil, nil, { ext_messages = true, }) end) -describe("fs.print_clipboard", function() - it("none", function() +t.describe("fs.print_clipboard", function() + t.it("none", function() nu.feed_sync({ ":NvimTreeOpen", }) @@ -36,7 +32,7 @@ describe("fs.print_clipboard", function() end) - it("many", function() + t.it("many", function() nu.feed_sync({ ":NvimTreeOpen", "", diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index 64d7dcbdbec..646d9e2fc94 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -3,11 +3,8 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") local nu = require("test.nvt.func.util") --- 0.13 global compatibility ----@diagnostic disable: undefined-global -local describe = t.describe or describe -local it = t.it or it ----@diagnostic enable: undefined-global +-- 0.12 global compatibility +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global --- @type test.functional.ui.screen @@ -32,8 +29,8 @@ local function create_trash_session(config) end -describe("fs.trash", function() - it("single file buffer deleted", function() +t.describe("fs.trash", function() + t.it("single file buffer deleted", function() screen = create_trash_session({ trash = { cmd = "rm -rf ", @@ -80,7 +77,7 @@ describe("fs.trash", function() end) - it("single dir", function() + t.it("single dir", function() screen = create_trash_session({ trash = { cmd = "rm -rf ", @@ -124,7 +121,7 @@ NvimTree_1 [-] [No Name] end) - it("many", function() + t.it("many", function() screen = create_trash_session({ trash = { cmd = "rm -rf ", @@ -177,7 +174,7 @@ NvimTree_1 [-] [No Name] end) - it("invalid trash.cmd", function() + t.it("invalid trash.cmd", function() screen = create_trash_session({ trash = { cmd = "foobarbaz", @@ -221,7 +218,7 @@ NvimTree_1 [-] [No Name] end) - it("ignore root", function() + t.it("ignore root", function() screen = create_trash_session({}) nu.feed_sync({ @@ -252,7 +249,7 @@ NvimTree_1 [-] [No Name] end) - it("many multiple failures", function() + t.it("many multiple failures", function() screen = create_trash_session({ trash = { -- fails unless "/tmp/nvt_func/data/f 1", prints same error message as execution completion is nondeterministic From 2611540bae3efeb3fad013cb9a6de9b9d3bb1c1d Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Thu, 15 Oct 2026 13:45:46 +1100 Subject: [PATCH 141/154] test: notes on test mechanisms --- test/nvt/func/README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test/nvt/func/README.md b/test/nvt/func/README.md index 8fe3f9c7405..8f735da9b7e 100644 --- a/test/nvt/func/README.md +++ b/test/nvt/func/README.md @@ -41,6 +41,10 @@ Prefer `test.nvt.func.util` `feed_sync` to feed keys synchronously (deferred), b # Test Mechanisms +## Screen Grid + +TODO + ## Command Line `Screen:expect` `cmdline` may be used to assert command line state. `test.functional.ui.screen.Opts` `ext_cmdline` must be enabled, e.g. @@ -71,3 +75,20 @@ screen:expect({ }) ``` +## nvim-tree Events + +Specific nvim-tree events may be subscribed to via `test.nvt.func.fixtures` `event_subscribe`, recorded as `nvt.functest.event[]` and the entire collection asserted in order via `test.nvt.func.asserts` `events_received` + +After assertion, the collected events are cleared. + +e.g. +```lua +local Event = require("nvim-tree._meta.api.events").Event +nf.event_subscribe(Event.FileRemoved) +nf.event_subscribe(Event.WillRemoveFile) +--- +na.events_received({ + { event_type = "WillRemoveFile", payload = { fname = "/tmp/nvt_func/data/d 1/d 1 f 1", }, }, + { event_type = "FileRemoved", payload = { fname = "/tmp/nvt_func/data/d 1/d 1 f 1", }, }, +}) +``` From ea3ea209fcd0ad59506dc76724b3c99b1af8eac3 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 09:01:57 +1100 Subject: [PATCH 142/154] test: notes on test assertions --- test/nvt/func/README.md | 56 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/test/nvt/func/README.md b/test/nvt/func/README.md index 8f735da9b7e..b833198c05b 100644 --- a/test/nvt/func/README.md +++ b/test/nvt/func/README.md @@ -39,11 +39,63 @@ The Nvim functional test framework's inputs are handled asynchronously via the c Prefer `test.nvt.func.util` `feed_sync` to feed keys synchronously (deferred), blocking the test thread and instance until the instance's main loop is complete. -# Test Mechanisms +# Test Assertions ## Screen Grid -TODO +`Screen:expect` `grid` is the main assertion mechanism, validating the contents of the entire screen, optionally including highlights and extmarks, referred to as `attr_ids`. + +Nvim tests almost always asserts highlights and extmarks however they can be difficult to prepare and read. nvim-tree usually asserts only text, asserting highlights only when necessary for the test e.g. copy, git status. + +Unique nvim-tree highlight groups `attr_ids` are defined during `test.nvt.func.fixtures` `create_session`. An addition variant for each group when in the cursor line suffixed with `CL` e.g. `NvimTreeFileIconCL` for file icons within the cursor line. + +### Text Only + +Set `attr_ids = {}` when calling `expect` to direct a text only assertion. + +See [Generating Test Data](TODO link) to dump the screen contents to a file. + +Contents are inserted directly into a text block `grid` e.g. + +```lua + screen:expect({ + attr_ids = {}, + grid = [[ + /tmp/nvt_func/data/.. │ | +   d1 │~ | +   d2 │~ | + ^  f1 │~ | +  f2 │~ | +~ │~ |*17 +NvimTree_1 [-] [No Name] | +[NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | + ]], + }) +``` + +Note the 17 repeated lines suffixed with `*17` which is optional; the entire screen may be inserted. + +### Complete + +It is impractical to generate the `grid` manually, due to the number of `attr_ids` that must be specified, combined and turned on and off. + +- Create a passing `screen:expect` with text only +- Remove `attr_ids = {}` and re-run the test +- On failure, the test will print the expected `grid` to use e.g. + +```lua +Snapshot: +screen:expect([[ + {NvimTreeSignColumn: }{NvimTreeRootFolder:/tmp/nvt_func/data/..}{NvimTreeNormal: }{NvimTreeWinSeparator:│} | + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d1}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeClosedFolderIcon:}{NvimTreeNormal: }{NvimTreeFolderName:d2}{NvimTreeNormal: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosedCL:^ }{NvimTreeFileIconCL:}{NvimTreeNormalCL: }{NvimTreeCopiedHLCL:f1}{NvimTreeNormalCL: }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeSignColumn: }{NvimTreeFolderArrowClosed: }{NvimTreeFileIcon:}{NvimTreeNormal: f2 }{NvimTreeWinSeparator:│}{1:~ }| + {NvimTreeEndOfBuffer:~ }{NvimTreeWinSeparator:│}{1:~ }|*17 + {NvimTreeStatusLine:NvimTree_1 [-] }{2:[No Name] }| + [NvimTree] /tmp/nvt_func/data/f1 added to clipboard. | +]]) +``` ## Command Line From 0c6e959ddcf427616f604cf5656c723c240e4310 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 09:35:27 +1100 Subject: [PATCH 143/154] test: notes on test timeouts --- test/nvt/func/README.md | 4 ++-- test/nvt/func/fs/trash/node_spec.lua | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/test/nvt/func/README.md b/test/nvt/func/README.md index b833198c05b..3db6635809d 100644 --- a/test/nvt/func/README.md +++ b/test/nvt/func/README.md @@ -31,8 +31,6 @@ Use `Snapshot: screen:expect([[` contents from test log as the `grid`, visually # Test Inputs -TODO: how to handle asynchronous operations e.g. fs/git update - ## Synchronisation The Nvim functional test framework's inputs are handled asynchronously via the commonly used `test.functional.testnvim` `feed` (non-deferred). It will execute all the inputs _immediately_ without waiting for them to complete, most notably lua callbacks such as nvim-tree mappings as well as some visual mode operations. See `:help api-fast` @@ -49,6 +47,8 @@ Nvim tests almost always asserts highlights and extmarks however they can be dif Unique nvim-tree highlight groups `attr_ids` are defined during `test.nvt.func.fixtures` `create_session`. An addition variant for each group when in the cursor line suffixed with `CL` e.g. `NvimTreeFileIconCL` for file icons within the cursor line. +`expect` will continually validate the contents of the screen after each update until it matches the expected. This allows for for asynchronous updates such as git/filesystem changes, however it will timeout and fail if the expected state is not reached after `timeout` ms, default 3500. + ### Text Only Set `attr_ids = {}` when calling `expect` to direct a text only assertion. diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index 646d9e2fc94..fb4a593b12b 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -11,10 +11,6 @@ t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_e local screen --- TODO the command executes async, need to wait for completion and tree to update, maybe disable watchers or wait for TreeRendered event --- cmd = "sleep 5; rm -rf ", - - ---@param config nvim_tree.config ---@return test.functional.ui.screen local function create_trash_session(config) From b5ea788fb05ceb96911f54bde8180bfe2005a5f8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 09:47:10 +1100 Subject: [PATCH 144/154] test: notes on test timeouts --- test/nvt/func/fs/trash/node_spec.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index fb4a593b12b..85b3ceeae5b 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -248,7 +248,7 @@ NvimTree_1 [-] [No Name] t.it("many multiple failures", function() screen = create_trash_session({ trash = { - -- fails unless "/tmp/nvt_func/data/f 1", prints same error message as execution completion is nondeterministic + -- fails unless "/tmp/nvt_func/data/f 1", prints identical error message as vim.fn.jobstart completion time is nondeterministic cmd = "./trash_fail.sh", } }) From 4e8e0d356a1c846c7dd79df22017610e41de41c7 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 09:48:02 +1100 Subject: [PATCH 145/154] test: experiment, disable feed_sync poke to see CI test output --- test/nvt/func/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nvt/func/util.lua b/test/nvt/func/util.lua index 8031f8b08b1..0c98fc8fac5 100644 --- a/test/nvt/func/util.lua +++ b/test/nvt/func/util.lua @@ -14,7 +14,7 @@ function M.feed_sync(inputs) n.feed(v) -- defer until complete - n.poke_eventloop() + -- n.poke_eventloop() end end From ed7ea49c8e319d4691f220839379f9cdfa29ae08 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 10:00:18 +1100 Subject: [PATCH 146/154] Revert "test: experiment, disable feed_sync poke to see CI test output" This reverts commit 4e8e0d356a1c846c7dd79df22017610e41de41c7. --- test/nvt/func/util.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/nvt/func/util.lua b/test/nvt/func/util.lua index 0c98fc8fac5..8031f8b08b1 100644 --- a/test/nvt/func/util.lua +++ b/test/nvt/func/util.lua @@ -14,7 +14,7 @@ function M.feed_sync(inputs) n.feed(v) -- defer until complete - -- n.poke_eventloop() + n.poke_eventloop() end end From d8f5ee98564a41d4b20def4262e35964694095b6 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 12:10:54 +1100 Subject: [PATCH 147/154] test: replace create_test_cwd.sh with lua --- scripts/functionaltest.sh | 4 +-- test/nvt/func/create_test_cwd.sh | 28 --------------- test/nvt/func/fixtures.lua | 60 ++++++++++++++++++++++++++------ 3 files changed, 52 insertions(+), 40 deletions(-) delete mode 100755 test/nvt/func/create_test_cwd.sh diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 944b51889f8..666f7d9e4b9 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -26,8 +26,8 @@ export NVT_FUNC_DIR_ROOT="${NVT_FUNC_PACKPATH}/pack/dist/opt/nvim-tree.lua" # absolute path of the test's directory under Nvim source export NVT_FUNC_DIR_TEST= -# absolute path of script to execute to setup the test execution directory -export NVT_FUNC_SCRIPT_CREATE_TEST_CWD="${NVT_FUNC_DIR_ROOT}/test/nvt/func/create_test_cwd.sh" +# absolute path of the test instance cwd +export NVT_FUNC_DIR_CWD="/tmp/nvt_func" # absolute paths of test spec files to execute, under Nvim source files_test_lua= diff --git a/test/nvt/func/create_test_cwd.sh b/test/nvt/func/create_test_cwd.sh deleted file mode 100755 index ef3ee90b16f..00000000000 --- a/test/nvt/func/create_test_cwd.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env sh - -# delete, create and return the absolute path of the directory to execute tests in -# /tmp/nvt_func is the base -# if data is present, recursively copy it into /tmp/nvt_func/data and return it -# otherwise return empty /tmp/nvt_func -# -# prints "DIR=/absolute/path" on success -# -# nvim 0.12 does not have access to vim.system, hence we must use vim.fn.system to execute this -# vim.fn.system cannot detect error codes in the test context, as vim.v is not available -# hence we must use the output to determine success - -set -e - -DIR="/tmp/nvt_func" - -# blow away temp -rm -r -f "${DIR}" -mkdir -p "${DIR}" - -# maybe copy entire data directory and use it -if [ -d "${NVT_FUNC_DIR_TEST}/data" ]; then - cp -p -r "${NVT_FUNC_DIR_TEST}/data" "${DIR}" - DIR="${DIR}/data" -fi - -printf "DIR=${DIR}" diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index e4c5d5c738d..6b1f46ececb 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -2,11 +2,6 @@ local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") ----@class (exact) nvt.functest.event ----@field event_type string value of nvim_tree.api.events.Event ----@field payload table deep copy - - ---Globals used within test session context, noted in this test context only for type definition ---@type boolean NVT_FUNCTEST_CONTEXT = true @@ -18,6 +13,48 @@ NVT_FUNCTEST_CLIPBOARD_LINES = {} local M = {} +---Create /tmp/nvt_func or /tmp/nvt_func/data if present +---Change running instance's directory to above +local function setup_cwd() + ---Return the value of an environment variable, asserting presence + ---return @string + local function env(var) + local val = os.getenv(var) + assert(val, "$" .. var .. " not set") + return val + end + + ---Execute vim.system and waits + ---Assers RC=0 only for nvim > 0.12 + ---@param cmd string[] Command to execute + local function sys(cmd) + if vim.fn and vim.fn.has("nvim-0.13") == 1 then + local out = vim.system(cmd):wait() + assert(out.code == 0, vim.inspect(out)) + else + -- vim.system and n.system are not available for neovim 0.12 func tests + -- this will fail silently + n.fn.system(cmd) + end + end + + local dir_cwd, dir_test = env("NVT_FUNC_DIR_CWD"), env("NVT_FUNC_DIR_TEST") + + -- always blow away and recreate the cwd of the test instance + sys({ "rm", "-rf", dir_cwd }) + sys({ "mkdir", "-p", dir_cwd }) + + -- if data is present, recursively copy it and use that as cwd + local dir_test_data = dir_test .. "/data" + if vim.uv.fs_stat(dir_test_data) then + sys({ "cp", "-p", "-r", dir_test_data, dir_cwd }) + dir_cwd = dir_cwd .. "/data" + end + + -- set the cwd of the running test instance + n.api.nvim_set_current_dir(dir_cwd) +end + ---Create a new neovim functest session with ---- nvim-tree.lua package added ---- fresh test data directory created and cd'd into @@ -34,6 +71,7 @@ function M.create_session(config, width, height, options) local screen = Screen.new(width or 80, height or 24, options) + -- add the nvim-tree package and setup globals n.exec_lua(function() vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH") or "") vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) @@ -43,11 +81,8 @@ function M.create_session(config, width, height, options) NVT_FUNCTEST_CLIPBOARD_LINES = {} end) - -- Change to the temp test (data) directory - -- TODO neovim 0.13: replace with vim.system calls; vim.system is not currenctly available in neovim 0.12 func tests - local out = n.fn.system({ os.getenv("NVT_FUNC_SCRIPT_CREATE_TEST_CWD"), }) - local dir = out:match("^DIR=(.*)$") or error(out) - n.api.nvim_set_current_dir(dir) + -- create the test instance cwd and change directory to it + setup_cwd() n.exec_lua(function() require("nvim-tree").setup(config) @@ -60,6 +95,11 @@ function M.create_session(config, width, height, options) return screen end +---Subscribed events captured during test execution +---@class (exact) nvt.functest.event +---@field event_type string value of nvim_tree.api.events.Event +---@field payload table deep copy + ---Subscribe to an event, to be recorded in session global NVT_FUNCTEST_EVENTS nvt.functest.event[] ---Assert events via events_received ---@param event_type nvim_tree.api.events.Event [nvim_tree_events_kind] From f166e8a63cb4f3d884a1a0c876fe8af0e70e5120 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 12:31:44 +1100 Subject: [PATCH 148/154] test: replace create_test_cwd.sh with lua --- test/nvt/func/fixtures.lua | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index 6b1f46ececb..e38e2ae02f6 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -13,8 +13,8 @@ NVT_FUNCTEST_CLIPBOARD_LINES = {} local M = {} ----Create /tmp/nvt_func or /tmp/nvt_func/data if present ----Change running instance's directory to above +---Create /tmp/nvt_func or populated /tmp/nvt_func/data +---@return string absolute path local function setup_cwd() ---Return the value of an environment variable, asserting presence ---return @string @@ -38,21 +38,20 @@ local function setup_cwd() end end - local dir_cwd, dir_test = env("NVT_FUNC_DIR_CWD"), env("NVT_FUNC_DIR_TEST") + local cwd, dir_test = env("NVT_FUNC_DIR_CWD"), env("NVT_FUNC_DIR_TEST") -- always blow away and recreate the cwd of the test instance - sys({ "rm", "-rf", dir_cwd }) - sys({ "mkdir", "-p", dir_cwd }) + sys({ "rm", "-rf", cwd }) + sys({ "mkdir", "-p", cwd }) -- if data is present, recursively copy it and use that as cwd local dir_test_data = dir_test .. "/data" if vim.uv.fs_stat(dir_test_data) then - sys({ "cp", "-p", "-r", dir_test_data, dir_cwd }) - dir_cwd = dir_cwd .. "/data" + sys({ "cp", "-p", "-r", dir_test_data, cwd }) + cwd = cwd .. "/data" end - -- set the cwd of the running test instance - n.api.nvim_set_current_dir(dir_cwd) + return cwd end ---Create a new neovim functest session with @@ -67,29 +66,35 @@ end ---@param options? test.functional.ui.screen.Opts ---@return test.functional.ui.screen function M.create_session(config, width, height, options) + -- instantiate a new session (nvim instance) and its screen n.clear() - local screen = Screen.new(width or 80, height or 24, options) - -- add the nvim-tree package and setup globals + -- create the test instance cwd + local cwd = setup_cwd() + + -- add the nvim-tree package, setup globals and cd n.exec_lua(function() + -- add the nvim-tree package vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH") or "") vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) + -- setup globals NVT_FUNCTEST_CONTEXT = true NVT_FUNCTEST_EVENTS = {} NVT_FUNCTEST_CLIPBOARD_LINES = {} - end) - -- create the test instance cwd and change directory to it - setup_cwd() + -- test intance dir + vim.api.nvim_set_current_dir(cwd) - n.exec_lua(function() + -- setup nvim-tree with requested config require("nvim-tree").setup(config) end) + -- create attr_ids for all nvim-tree test highlight groups M.add_nvt_attr_ids(screen) + -- instantiate the test clipboard M.use_dummy_clipboard() return screen From 60bdaa972070af89f0087ae1f056e383dda91d01 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 12:50:51 +1100 Subject: [PATCH 149/154] test: replace create_test_cwd.sh with lua --- scripts/functionaltest.sh | 5 +++ test/nvt/func/fixtures.lua | 70 ++++++++++++------------------------- test/nvt/func/init_live.lua | 6 ++-- test/nvt/func/util.lua | 49 +++++++++++++++++++------- 4 files changed, 67 insertions(+), 63 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 666f7d9e4b9..193d565cb65 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -149,8 +149,12 @@ setup() { teardown() { # nvim-tree source link rm -fv "${NVT_FUNC_DIR_ROOT}" + + # test/live instance cwd + rm -rf "${NVT_FUNC_DIR_CWD}" } +# TODO run with the compiled nvim version under test live() { if [ "${dir_live}" != "none" ]; then NVT_FUNC_DIR_TEST="$(realpath "${dir_live}")" @@ -171,6 +175,7 @@ live() { || failures=1 } +# TODO we can probably run this with a directory now instead of individual files run_tests() { # cmake must be run from nvim source root cd "${DIR_NVIM_SRC}" diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index e38e2ae02f6..fc22b00288f 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -1,5 +1,6 @@ local n = require("test.functional.testnvim")() local Screen = require("test.functional.ui.screen") +local nu = require("test.nvt.func.util") ---Globals used within test session context, noted in this test context only for type definition @@ -13,47 +14,6 @@ NVT_FUNCTEST_CLIPBOARD_LINES = {} local M = {} ----Create /tmp/nvt_func or populated /tmp/nvt_func/data ----@return string absolute path -local function setup_cwd() - ---Return the value of an environment variable, asserting presence - ---return @string - local function env(var) - local val = os.getenv(var) - assert(val, "$" .. var .. " not set") - return val - end - - ---Execute vim.system and waits - ---Assers RC=0 only for nvim > 0.12 - ---@param cmd string[] Command to execute - local function sys(cmd) - if vim.fn and vim.fn.has("nvim-0.13") == 1 then - local out = vim.system(cmd):wait() - assert(out.code == 0, vim.inspect(out)) - else - -- vim.system and n.system are not available for neovim 0.12 func tests - -- this will fail silently - n.fn.system(cmd) - end - end - - local cwd, dir_test = env("NVT_FUNC_DIR_CWD"), env("NVT_FUNC_DIR_TEST") - - -- always blow away and recreate the cwd of the test instance - sys({ "rm", "-rf", cwd }) - sys({ "mkdir", "-p", cwd }) - - -- if data is present, recursively copy it and use that as cwd - local dir_test_data = dir_test .. "/data" - if vim.uv.fs_stat(dir_test_data) then - sys({ "cp", "-p", "-r", dir_test_data, cwd }) - cwd = cwd .. "/data" - end - - return cwd -end - ---Create a new neovim functest session with ---- nvim-tree.lua package added ---- fresh test data directory created and cd'd into @@ -67,18 +27,19 @@ end ---@return test.functional.ui.screen function M.create_session(config, width, height, options) -- instantiate a new session (nvim instance) and its screen - n.clear() + n.clear({ + args = { + "--cmd", "set packpath^=" .. os.getenv("NVT_FUNC_PACKPATH"), + "--cmd", "packadd nvim-tree.lua", + } + }) local screen = Screen.new(width or 80, height or 24, options) -- create the test instance cwd - local cwd = setup_cwd() + local cwd = nu.setup_cwd() -- add the nvim-tree package, setup globals and cd n.exec_lua(function() - -- add the nvim-tree package - vim.opt.packpath:append(os.getenv("NVT_FUNC_PACKPATH") or "") - vim.api.nvim_cmd({ cmd = "packadd", args = { "nvim-tree.lua" } }, {}) - -- setup globals NVT_FUNCTEST_CONTEXT = true NVT_FUNCTEST_EVENTS = {} @@ -163,4 +124,19 @@ function M.add_nvt_attr_ids(screen) screen:add_extra_attr_ids(attr_ids) end +---Feed keys synchronously (deferred), blocking the test thread and instance until the instance's main loop is complete. +---This is needed as api-fast input will execute lua callbacks (such as nvim-tree mappings) then execute the next input without waiting for the callback to complete. +---Calls feedkeys() (non-deferred, api-fast) then poke_eventloop() for each input passed. +---See :help api-fast +---@param inputs string[] +function M.feed_sync(inputs) + for _, v in ipairs(inputs) do + -- api-fast, does not wait for callbacks or input to complete + n.feed(v) + + -- defer until complete + n.poke_eventloop() + end +end + return M diff --git a/test/nvt/func/init_live.lua b/test/nvt/func/init_live.lua index 6a4f9f888e0..b103b59e041 100644 --- a/test/nvt/func/init_live.lua +++ b/test/nvt/func/init_live.lua @@ -71,10 +71,8 @@ screen_resize() -- use dark background for readability under dark and light vim.o.background = "dark" --- create and change to the directory the test will execute from -local out = vim.fn.system({ os.getenv("NVT_FUNC_SCRIPT_CREATE_TEST_CWD") }) -local dir = out:match("^DIR=(.*)$") or error(out) -vim.api.nvim_set_current_dir(dir) +-- test instance cwd +vim.api.nvim_set_current_dir(require("test.nvt.func.dirs").setup_cwd()) -- mappings vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) diff --git a/test/nvt/func/util.lua b/test/nvt/func/util.lua index 8031f8b08b1..86f81304e5a 100644 --- a/test/nvt/func/util.lua +++ b/test/nvt/func/util.lua @@ -1,21 +1,46 @@ -local n = require("test.functional.testnvim")() +---General test utils that to not require test infra, for use by tests and live local M = {} +---Create /tmp/nvt_func or populated /tmp/nvt_func/data +---@return string absolute path +function M.setup_cwd() + ---Return the value of an environment variable, asserting presence + ---return @string + local function env(var) + local val = os.getenv(var) + assert(val, "$" .. var .. " not set") + return val + end + + ---Execute vim.system and waits + ---Assers RC=0 only for nvim > 0.12 + ---@param cmd string[] Command to execute + local function sys(cmd) + if vim.system then + local out = vim.system(cmd):wait() + assert(out.code == 0, vim.inspect(out)) + else + -- vim.system and n.system are not available for neovim 0.12 func tests + -- this will fail silently + require("test.functional.testnvim")().fn.system(cmd) + end + end ----Feed keys synchronously (deferred), blocking the test thread and instance until the instance's main loop is complete. ----This is needed as api-fast input will execute lua callbacks (such as nvim-tree mappings) then execute the next input without waiting for the callback to complete. ----Calls feedkeys() (non-deferred, api-fast) then poke_eventloop() for each input passed. ----See :help api-fast ----@param inputs string[] -function M.feed_sync(inputs) - for _, v in ipairs(inputs) do - -- api-fast, does not wait for callbacks or input to complete - n.feed(v) + local cwd, dir_test = env("NVT_FUNC_DIR_CWD"), env("NVT_FUNC_DIR_TEST") - -- defer until complete - n.poke_eventloop() + -- always blow away and recreate the cwd of the test instance + sys({ "rm", "-rf", cwd }) + sys({ "mkdir", "-p", cwd }) + + -- if data is present, recursively copy it and use that as cwd + local dir_test_data = dir_test .. "/data" + if vim.uv.fs_stat(dir_test_data) then + sys({ "cp", "-p", "-r", dir_test_data, cwd }) + cwd = cwd .. "/data" end + + return cwd end return M From 9b2dba6bd1b0fefcf506e0b57ac559d5413c7ba8 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 13:05:00 +1100 Subject: [PATCH 150/154] test: replace create_test_cwd.sh with lua --- .../clear_clipboard/clear_clipboard_spec.lua | 5 +- test/nvt/func/fs/copy/node_spec.lua | 23 ++++--- test/nvt/func/fs/create/dir_spec.lua | 21 +++--- test/nvt/func/fs/create/file_spec.lua | 17 +++-- test/nvt/func/fs/create/prompt_spec.lua | 9 ++- test/nvt/func/fs/cut/node_spec.lua | 27 ++++---- test/nvt/func/fs/move/node_spec.lua | 7 +- test/nvt/func/fs/paste/copied_spec.lua | 65 +++++++++---------- test/nvt/func/fs/paste/cut_spec.lua | 9 ++- .../print_clipboard/print_clipboard_spec.lua | 5 +- test/nvt/func/fs/trash/node_spec.lua | 23 ++++--- 11 files changed, 100 insertions(+), 111 deletions(-) diff --git a/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua index 6d467febd6c..921f14c7f83 100644 --- a/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua +++ b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua @@ -1,7 +1,6 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -18,7 +17,7 @@ end) t.describe("fs.clear_clipboard", function() t.it("empty", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", }) @@ -33,7 +32,7 @@ t.describe("fs.clear_clipboard", function() t.it("many", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index abaa1f5fefc..b14e343303d 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -1,7 +1,6 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -20,7 +19,7 @@ t.describe("fs.copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -48,7 +47,7 @@ t.describe("fs.copy", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", }) @@ -77,7 +76,7 @@ t.describe("fs.copy", function() t.it("single dir", function() n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -103,7 +102,7 @@ t.describe("fs.copy", function() t.it("toggle one", function() n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -125,7 +124,7 @@ NvimTree_1 [-] [No Name] ]], }) - nu.feed_sync({ + nf.feed_sync({ "c", }) @@ -150,7 +149,7 @@ NvimTree_1 [-] [No Name] t.it("toggle many", function() n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -172,7 +171,7 @@ NvimTree_1 [-] [No Name] ]], }) - nu.feed_sync({ + nf.feed_sync({ "", "", "c", @@ -208,7 +207,7 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") -- - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -237,7 +236,7 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", @@ -259,7 +258,7 @@ NvimTree_1 [-] [No Name] ]], }) - nu.feed_sync({ + nf.feed_sync({ "c", }) @@ -281,7 +280,7 @@ NvimTree_1 [-] [No Name] t.it("dir overrides file", function() n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "E", "", diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 5ef59c629a6..12d77918d9e 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -2,7 +2,6 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -21,7 +20,7 @@ end) t.describe("fs.create dir", function() t.it("single direct", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "direct/", @@ -49,7 +48,7 @@ NvimTree_1 [-] [No Name] t.it("single indirect", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "d1/indirect/", @@ -78,7 +77,7 @@ NvimTree_1 [-] [No Name] t.it("api single indirect", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", }) @@ -90,7 +89,7 @@ NvimTree_1 [-] [No Name] -- wait for the input n.poke_eventloop() - nu.feed_sync({ + nf.feed_sync({ "d1/indirect/", }) @@ -117,7 +116,7 @@ NvimTree_1 [-] [No Name] t.it("multiple direct", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "direct1/direct2/", @@ -149,7 +148,7 @@ NvimTree_1 [-] [No Name] t.it("multiple indirect", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "d1/indirect1/indirect2/", @@ -182,7 +181,7 @@ NvimTree_1 [-] [No Name] t.it("fails when file exists", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "d1/", @@ -205,7 +204,7 @@ NvimTree_1 [-] [No Name] t.it("fails when file exists", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "d1/d1f1/", @@ -231,7 +230,7 @@ NvimTree_1 [-] [No Name] t.it("fails on invalid path", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "", @@ -255,7 +254,7 @@ NvimTree_1 [-] [No Name] t.it("fails when dir exists", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "a", diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index 5acedf8fe90..f7e2b2de156 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -2,7 +2,6 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -23,7 +22,7 @@ end) t.describe("fs.create file", function() t.it("direct", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "direct", @@ -52,7 +51,7 @@ NvimTree_1 [-] [No Name] t.it("indirect", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "d1/indirect", @@ -82,7 +81,7 @@ NvimTree_1 [-] [No Name] t.it("api indirect", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", }) @@ -94,7 +93,7 @@ NvimTree_1 [-] [No Name] -- wait for the input n.poke_eventloop() - nu.feed_sync({ + nf.feed_sync({ "d1/indirect", }) @@ -122,7 +121,7 @@ NvimTree_1 [-] [No Name] t.it("fails when file exists", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "f1", @@ -147,7 +146,7 @@ NvimTree_1 [-] [No Name] t.it("fails when dir exists", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "d1", @@ -172,7 +171,7 @@ NvimTree_1 [-] [No Name] t.it("indirect creates dirs", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "newdir/newfile", @@ -204,7 +203,7 @@ NvimTree_1 [-] [No Name] t.it("fails on invalid path", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "", diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index 71219c3114d..640cdacbf2e 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -1,7 +1,6 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -17,7 +16,7 @@ end) t.describe("fs.create prompt", function() t.it("tree focused", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "a", @@ -30,7 +29,7 @@ t.describe("fs.create prompt", function() t.it("api tree not focused", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -51,7 +50,7 @@ t.describe("fs.create prompt", function() t.it("file focused", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "a", @@ -64,7 +63,7 @@ t.describe("fs.create prompt", function() t.it("cancelled", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "a", "foo", diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index 2e0dd2b47be..aa038e85d08 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -1,7 +1,6 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -24,7 +23,7 @@ t.describe("fs.cut", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", @@ -52,7 +51,7 @@ t.describe("fs.cut", function() n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", }) @@ -82,7 +81,7 @@ t.describe("fs.cut", function() t.it("single dir", function() n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", @@ -107,7 +106,7 @@ t.describe("fs.cut", function() t.it("toggle one", function() n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", @@ -129,7 +128,7 @@ NvimTree_1 [-] [No Name] ]], }) - nu.feed_sync({ + nf.feed_sync({ "x", }) @@ -154,7 +153,7 @@ NvimTree_1 [-] [No Name] t.it("toggle many", function() n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", @@ -176,7 +175,7 @@ NvimTree_1 [-] [No Name] ]], }) - nu.feed_sync({ + nf.feed_sync({ "", "", "x", @@ -212,7 +211,7 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") -- - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", @@ -241,7 +240,7 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -263,7 +262,7 @@ NvimTree_1 [-] [No Name] ]], }) - nu.feed_sync({ + nf.feed_sync({ "x", }) @@ -286,7 +285,7 @@ NvimTree_1 [-] [No Name] n.fn.setreg("1", "foo") n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -318,7 +317,7 @@ NvimTree_1 [-] [No Name] ]], }) - nu.feed_sync({ + nf.feed_sync({ "gg", "", "", @@ -352,7 +351,7 @@ NvimTree_1 [-] [No Name] t.it("dir overrides file", function() n.fn.setreg("+", "foo") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "E", "", diff --git a/test/nvt/func/fs/move/node_spec.lua b/test/nvt/func/fs/move/node_spec.lua index 64e9c3b4326..504cc90633e 100644 --- a/test/nvt/func/fs/move/node_spec.lua +++ b/test/nvt/func/fs/move/node_spec.lua @@ -2,7 +2,6 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -21,7 +20,7 @@ t.describe("fs.move", function() t.it("nothing", function() n.fn.setreg("+", "") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "gp", "E", @@ -46,7 +45,7 @@ NvimTree_1 [-] [No Name] t.it("inexistent", function() n.fn.setreg("+", "/tmp/nvt_func/data/inexistent") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "gp", "E", @@ -71,7 +70,7 @@ NvimTree_1 [-] [No Name] t.it("present", function() n.fn.setreg("+", "/tmp/nvt_func/data/src/f1") - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "E", "", diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index a2850d72789..e38fde37a3c 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -1,7 +1,6 @@ local t = require("test.testutil") local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -20,7 +19,7 @@ end) t.describe("fs.paste copied", function() t.it("single file", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -52,7 +51,7 @@ NvimTree_1 [-] [No Name] t.it("multiple files", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -90,7 +89,7 @@ NvimTree_1 [-] [No Name] t.it("single dir", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -129,7 +128,7 @@ NvimTree_1 [-] [No Name] t.it("single dir conflict resolved", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -141,7 +140,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - nu.feed_sync({ + nf.feed_sync({ "_copy", "", }) @@ -176,7 +175,7 @@ NvimTree_1 [-] [No Name] t.it("single dir conflict cancelled", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -188,7 +187,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - nu.feed_sync({ + nf.feed_sync({ "", }) @@ -196,7 +195,7 @@ NvimTree_1 [-] [No Name] cmdline = { { abort = true } }, }) - nu.feed_sync({ + nf.feed_sync({ "gg", "E", }) @@ -226,7 +225,7 @@ NvimTree_1 [-] [No Name] t.it("single dir conflict second conflict overwrite", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -238,7 +237,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - nu.feed_sync({ + nf.feed_sync({ "2" }) @@ -246,7 +245,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "y", }) @@ -284,7 +283,7 @@ Press ENTER or type command to continue^ t.it("single dir conflict second conflict cancel", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -296,7 +295,7 @@ Press ENTER or type command to continue^ cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - nu.feed_sync({ + nf.feed_sync({ "2", }) @@ -304,7 +303,7 @@ Press ENTER or type command to continue^ cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "n", "gg", "E", @@ -334,7 +333,7 @@ Press ENTER or type command to continue^ t.it("single dir conflict second conflict resolved", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -346,7 +345,7 @@ Press ENTER or type command to continue^ cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d1" } }, pos = 21, } }, }) - nu.feed_sync({ + nf.feed_sync({ "2", }) @@ -354,7 +353,7 @@ Press ENTER or type command to continue^ cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2 ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "R", }) @@ -362,7 +361,7 @@ Press ENTER or type command to continue^ cmdline = { { prompt = "Rename to ", content = { { "/tmp/nvt_func/data/d2" } }, pos = 21, } }, }) - nu.feed_sync({ + nf.feed_sync({ "1_copy", "", }) @@ -389,7 +388,7 @@ NvimTree_1 [-] [No Name] t.it("multiple", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "c", @@ -430,7 +429,7 @@ NvimTree_1 [-] [No Name] t.it("multiple conflict no rename", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -445,7 +444,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "n", }) @@ -477,7 +476,7 @@ NvimTree_1 [-] [No Name] t.it("multiple conflict rename suffix", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -492,7 +491,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "r", }) @@ -500,7 +499,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "Suffix: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ ".renamed", }) @@ -538,7 +537,7 @@ NvimTree_1 [-] [No Name] t.it("multiple conflict rename cancel", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -553,7 +552,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "", "", }) @@ -587,7 +586,7 @@ NvimTree_1 [-] [No Name] t.it("multiple conflict rename second conflict", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "a", @@ -596,7 +595,7 @@ NvimTree_1 [-] [No Name] na.file_exists("/tmp/nvt_func/data/d2/f2.renamed") - nu.feed_sync({ + nf.feed_sync({ "W", "gg", "", @@ -612,7 +611,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "", ".renamed", }) @@ -621,7 +620,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "Overwrite /tmp/nvt_func/data/d2/f2.renamed ? R(ename)/y/n: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "", ".again", }) @@ -663,7 +662,7 @@ NvimTree_1 [-] [No Name] t.it("multiple conflict overwrite", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -679,7 +678,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "2 file(s) already exist. R(ename suffix)/y/n: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "y", }) diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index 6462cf61f8f..c4874a2734c 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -2,7 +2,6 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -24,7 +23,7 @@ end) t.describe("fs.paste cut", function() t.it("single dir", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", @@ -69,7 +68,7 @@ NvimTree_1 [-] [No Name] t.it("single file", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", @@ -112,7 +111,7 @@ NvimTree_1 [-] /tmp/nvt_func/data/d3/f1 t.it("api node under cursor", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", @@ -157,7 +156,7 @@ NvimTree_1 [-] [No Name] t.it("api node specified", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "x", diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index 34835011de0..3e9d44bfa32 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -1,7 +1,6 @@ local t = require("test.testutil") local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -18,7 +17,7 @@ end) t.describe("fs.print_clipboard", function() t.it("none", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", }) @@ -33,7 +32,7 @@ t.describe("fs.print_clipboard", function() t.it("many", function() - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index 85b3ceeae5b..f02c206e995 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -1,7 +1,6 @@ local t = require("test.testutil") local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -local nu = require("test.nvt.func.util") -- 0.12 global compatibility t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global @@ -33,7 +32,7 @@ t.describe("fs.trash", function() } }) - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -47,7 +46,7 @@ t.describe("fs.trash", function() cmdline = { { prompt = "Trash d 1 f 1? y/N: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "y", }) @@ -80,7 +79,7 @@ t.describe("fs.trash", function() } }) - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "D", @@ -90,7 +89,7 @@ t.describe("fs.trash", function() cmdline = { { prompt = "Trash d 1? y/N: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "y", "gg", "E", @@ -124,7 +123,7 @@ NvimTree_1 [-] [No Name] } }) - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -139,7 +138,7 @@ NvimTree_1 [-] [No Name] showmode = { { "-- VISUAL LINE --", 5, "ModeMsg" } }, }) - nu.feed_sync({ + nf.feed_sync({ "y", "gg", "E", @@ -177,7 +176,7 @@ NvimTree_1 [-] [No Name] } }) - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -189,7 +188,7 @@ NvimTree_1 [-] [No Name] cmdline = { { prompt = "Trash d 1 f 1? y/N: ", content = { { "" } }, pos = 0, } }, }) - nu.feed_sync({ + nf.feed_sync({ "y", }) @@ -217,7 +216,7 @@ NvimTree_1 [-] [No Name] t.it("ignore root", function() screen = create_trash_session({}) - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "D", }) @@ -253,7 +252,7 @@ NvimTree_1 [-] [No Name] } }) - nu.feed_sync({ + nf.feed_sync({ ":NvimTreeOpen", "", "", @@ -268,7 +267,7 @@ NvimTree_1 [-] [No Name] showmode = { { "-- VISUAL LINE --", 5, "ModeMsg" } }, }) - nu.feed_sync({ + nf.feed_sync({ "y", }) From 859f649f255faa2b7ef3f0456967495024e74de9 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Fri, 16 Oct 2026 13:55:55 +1100 Subject: [PATCH 151/154] test: replace create_test_cwd.sh with lua --- test/nvt/func/fixtures.lua | 2 +- test/nvt/func/util.lua | 52 +++++++++++++++++++------------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index fc22b00288f..9d1aa707edc 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -29,7 +29,7 @@ function M.create_session(config, width, height, options) -- instantiate a new session (nvim instance) and its screen n.clear({ args = { - "--cmd", "set packpath^=" .. os.getenv("NVT_FUNC_PACKPATH"), + "--cmd", "set packpath^=" .. nu.env("NVT_FUNC_PACKPATH"), "--cmd", "packadd nvim-tree.lua", } }) diff --git a/test/nvt/func/util.lua b/test/nvt/func/util.lua index 86f81304e5a..e90b38f0f37 100644 --- a/test/nvt/func/util.lua +++ b/test/nvt/func/util.lua @@ -2,41 +2,41 @@ local M = {} ----Create /tmp/nvt_func or populated /tmp/nvt_func/data ----@return string absolute path -function M.setup_cwd() - ---Return the value of an environment variable, asserting presence - ---return @string - local function env(var) - local val = os.getenv(var) - assert(val, "$" .. var .. " not set") - return val - end +---Return the value of an environment variable, asserting presence +---return @string +function M.env(name) + local val = os.getenv(name) + assert(val, "$" .. name .. " not set") + return val +end - ---Execute vim.system and waits - ---Assers RC=0 only for nvim > 0.12 - ---@param cmd string[] Command to execute - local function sys(cmd) - if vim.system then - local out = vim.system(cmd):wait() - assert(out.code == 0, vim.inspect(out)) - else - -- vim.system and n.system are not available for neovim 0.12 func tests - -- this will fail silently - require("test.functional.testnvim")().fn.system(cmd) - end +---Execute vim.system and waits +---Assers RC=0 only for nvim > 0.12 +---@param cmd string[] Command to execute +function M.sys(cmd) + if vim.system then + local out = vim.system(cmd):wait() + assert(out.code == 0, vim.inspect(out)) + else + -- vim.system and n.system are not available for neovim 0.12 func tests + -- this will fail silently + require("test.functional.testnvim")().fn.system(cmd) end +end - local cwd, dir_test = env("NVT_FUNC_DIR_CWD"), env("NVT_FUNC_DIR_TEST") +---Create /tmp/nvt_func or populated /tmp/nvt_func/data +---@return string absolute path +function M.setup_cwd() + local cwd, dir_test = M.env("NVT_FUNC_DIR_CWD"), M.env("NVT_FUNC_DIR_TEST") -- always blow away and recreate the cwd of the test instance - sys({ "rm", "-rf", cwd }) - sys({ "mkdir", "-p", cwd }) + M.sys({ "rm", "-rf", cwd }) + M.sys({ "mkdir", "-p", cwd }) -- if data is present, recursively copy it and use that as cwd local dir_test_data = dir_test .. "/data" if vim.uv.fs_stat(dir_test_data) then - sys({ "cp", "-p", "-r", dir_test_data, cwd }) + M.sys({ "cp", "-p", "-r", dir_test_data, cwd }) cwd = cwd .. "/data" end From 35087f98c8a39b7fd2684beeeed42b3d9cc1283b Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 19 Oct 2026 10:48:00 +1100 Subject: [PATCH 152/154] test: each functest passes its own data dir --- scripts/functionaltest.sh | 4 --- test/nvt/func/asserts.lua | 2 +- test/nvt/func/fixtures.lua | 28 +++++++++++-------- .../clear_clipboard/clear_clipboard_spec.lua | 8 ++++-- test/nvt/func/fs/copy/node_spec.lua | 5 ++-- test/nvt/func/fs/create/dir_spec.lua | 5 ++-- test/nvt/func/fs/create/file_spec.lua | 5 ++-- test/nvt/func/fs/create/prompt_spec.lua | 8 ++++-- test/nvt/func/fs/cut/node_spec.lua | 5 ++-- test/nvt/func/fs/move/node_spec.lua | 5 ++-- test/nvt/func/fs/paste/copied_spec.lua | 8 ++++-- test/nvt/func/fs/paste/cut_spec.lua | 5 ++-- .../print_clipboard/print_clipboard_spec.lua | 8 ++++-- test/nvt/func/fs/trash/node_spec.lua | 9 ++++-- test/nvt/func/init_live.lua | 3 +- test/nvt/func/util.lua | 18 ++++++++---- 16 files changed, 82 insertions(+), 44 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 193d565cb65..b44206f6fe3 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -23,9 +23,6 @@ export NVT_FUNC_PACKPATH="${DIR_NVIM_SRC}/src/nvt" # absolute link to nvim-tree source root under Nvim source export NVT_FUNC_DIR_ROOT="${NVT_FUNC_PACKPATH}/pack/dist/opt/nvim-tree.lua" -# absolute path of the test's directory under Nvim source -export NVT_FUNC_DIR_TEST= - # absolute path of the test instance cwd export NVT_FUNC_DIR_CWD="/tmp/nvt_func" @@ -182,7 +179,6 @@ run_tests() { # execute all requested tests for f in ${files_test_lua}; do - NVT_FUNC_DIR_TEST="$(dirname "${f}")" # append nvim-tree lua/test to package.path, so that tests themselves may access nvim-tree source # don't exit on failure, just note it diff --git a/test/nvt/func/asserts.lua b/test/nvt/func/asserts.lua index 0d7aaa58138..db1eef936da 100644 --- a/test/nvt/func/asserts.lua +++ b/test/nvt/func/asserts.lua @@ -29,7 +29,7 @@ end ---Assert events received during a functest, recorded in session global NVT_FUNCTEST_EVENTS ---Must be subscribed via event_subscribe ---Clears events as per ext_messages ----@param events nvt.functest.event[] +---@param events test.nvt.func.fixtures.Event[] function M.events_received(events) t.eq(events, n.exec_lua(function() local ev = vim.deepcopy(NVT_FUNCTEST_EVENTS) diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index 9d1aa707edc..ae3899dd7ee 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -6,7 +6,7 @@ local nu = require("test.nvt.func.util") ---Globals used within test session context, noted in this test context only for type definition ---@type boolean NVT_FUNCTEST_CONTEXT = true ----@type nvt.functest.event[] +---@type test.nvt.func.fixtures.Event[] NVT_FUNCTEST_EVENTS = {} ---@type string[] NVT_FUNCTEST_CLIPBOARD_LINES = {} @@ -14,18 +14,25 @@ NVT_FUNCTEST_CLIPBOARD_LINES = {} local M = {} + +---@class (exact) test.nvt.func.fixtures.create_session.Opts +---@field data? string relative path of data directory to copy for test instance cwd +---@field config? nvim_tree.config passed to nvim-tree.setup +---@field width? integer default 80 +---@field height? integer default 24 +---@field screen_opts? test.functional.ui.screen.Opts + ---Create a new neovim functest session with ---- nvim-tree.lua package added ---- fresh test data directory created and cd'd into ---- nvim-tree setup called ---- nvim-tree HL attr_ids added ---- dummy clipboard setup ----@param config? nvim_tree.config passed to nvim-tree.setup ----@param width? integer default 80 ----@param height? integer default 24 ----@param options? test.functional.ui.screen.Opts +---@param opts? test.nvt.func.fixtures.create_session.Opts ---@return test.functional.ui.screen -function M.create_session(config, width, height, options) +function M.create_session(opts) + opts = opts or {} + -- instantiate a new session (nvim instance) and its screen n.clear({ args = { @@ -33,10 +40,10 @@ function M.create_session(config, width, height, options) "--cmd", "packadd nvim-tree.lua", } }) - local screen = Screen.new(width or 80, height or 24, options) + local screen = Screen.new(opts.width or 80, opts.height or 24, opts.screen_opts) -- create the test instance cwd - local cwd = nu.setup_cwd() + local cwd = nu.setup_cwd(opts.data) -- add the nvim-tree package, setup globals and cd n.exec_lua(function() @@ -49,7 +56,7 @@ function M.create_session(config, width, height, options) vim.api.nvim_set_current_dir(cwd) -- setup nvim-tree with requested config - require("nvim-tree").setup(config) + require("nvim-tree").setup(opts.config) end) -- create attr_ids for all nvim-tree test highlight groups @@ -61,8 +68,7 @@ function M.create_session(config, width, height, options) return screen end ----Subscribed events captured during test execution ----@class (exact) nvt.functest.event +---@class (exact) test.nvt.func.fixtures.Event ---@field event_type string value of nvim_tree.api.events.Event ---@field payload table deep copy diff --git a/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua index 921f14c7f83..ec5239167be 100644 --- a/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua +++ b/test/nvt/func/fs/clear_clipboard/clear_clipboard_spec.lua @@ -3,7 +3,8 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen @@ -11,7 +12,10 @@ local screen t.before_each(function() - screen = nf.create_session({}, nil, nil, { ext_messages = true, }) + screen = nf.create_session({ + data = "test/nvt/func/fs/clear_clipboard/data", + screen_opts = { ext_messages = true, }, + }) end) diff --git a/test/nvt/func/fs/copy/node_spec.lua b/test/nvt/func/fs/copy/node_spec.lua index b14e343303d..8ddee701ca3 100644 --- a/test/nvt/func/fs/copy/node_spec.lua +++ b/test/nvt/func/fs/copy/node_spec.lua @@ -3,14 +3,15 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen local screen t.before_each(function() - screen = nf.create_session() + screen = nf.create_session({ data = "test/nvt/func/fs/copy/data", }) end) diff --git a/test/nvt/func/fs/create/dir_spec.lua b/test/nvt/func/fs/create/dir_spec.lua index 12d77918d9e..a5eae7b5629 100644 --- a/test/nvt/func/fs/create/dir_spec.lua +++ b/test/nvt/func/fs/create/dir_spec.lua @@ -4,14 +4,15 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen local screen t.before_each(function() - screen = nf.create_session() + screen = nf.create_session({ data = "test/nvt/func/fs/create/data", }) local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.FolderCreated) diff --git a/test/nvt/func/fs/create/file_spec.lua b/test/nvt/func/fs/create/file_spec.lua index f7e2b2de156..2e4ec7eb958 100644 --- a/test/nvt/func/fs/create/file_spec.lua +++ b/test/nvt/func/fs/create/file_spec.lua @@ -4,14 +4,15 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen local screen t.before_each(function() - screen = nf.create_session() + screen = nf.create_session({ data = "test/nvt/func/fs/create/data", }) local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.FileCreated) diff --git a/test/nvt/func/fs/create/prompt_spec.lua b/test/nvt/func/fs/create/prompt_spec.lua index 640cdacbf2e..0f5bc48d000 100644 --- a/test/nvt/func/fs/create/prompt_spec.lua +++ b/test/nvt/func/fs/create/prompt_spec.lua @@ -3,14 +3,18 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen local screen t.before_each(function() - screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) + screen = nf.create_session({ + data = "test/nvt/func/fs/create/data", + screen_opts = { ext_cmdline = true }, + }) end) diff --git a/test/nvt/func/fs/cut/node_spec.lua b/test/nvt/func/fs/cut/node_spec.lua index aa038e85d08..6bb8a737650 100644 --- a/test/nvt/func/fs/cut/node_spec.lua +++ b/test/nvt/func/fs/cut/node_spec.lua @@ -3,7 +3,8 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each -- BUG single operations report "added to clipboard", not "cut to clipboard" as per bulk operations @@ -14,7 +15,7 @@ local screen t.before_each(function() - screen = nf.create_session() + screen = nf.create_session({ data = "test/nvt/func/fs/cut/data", }) end) diff --git a/test/nvt/func/fs/move/node_spec.lua b/test/nvt/func/fs/move/node_spec.lua index 504cc90633e..2a1a783627c 100644 --- a/test/nvt/func/fs/move/node_spec.lua +++ b/test/nvt/func/fs/move/node_spec.lua @@ -4,7 +4,8 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen @@ -12,7 +13,7 @@ local screen t.before_each(function() - screen = nf.create_session() + screen = nf.create_session({ data = "test/nvt/func/fs/move/data", }) end) diff --git a/test/nvt/func/fs/paste/copied_spec.lua b/test/nvt/func/fs/paste/copied_spec.lua index e38fde37a3c..907203ceec1 100644 --- a/test/nvt/func/fs/paste/copied_spec.lua +++ b/test/nvt/func/fs/paste/copied_spec.lua @@ -3,7 +3,8 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen local screen @@ -13,7 +14,10 @@ local screen t.before_each(function() - screen = nf.create_session(nil, nil, nil, { ext_cmdline = true }) + screen = nf.create_session({ + data = "test/nvt/func/fs/paste/data", + screen_opts = { ext_cmdline = true }, + }) end) diff --git a/test/nvt/func/fs/paste/cut_spec.lua b/test/nvt/func/fs/paste/cut_spec.lua index c4874a2734c..0c415fd7a5b 100644 --- a/test/nvt/func/fs/paste/cut_spec.lua +++ b/test/nvt/func/fs/paste/cut_spec.lua @@ -4,7 +4,8 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen local screen @@ -14,7 +15,7 @@ local screen t.before_each(function() - screen = nf.create_session() + screen = nf.create_session({ data = "test/nvt/func/fs/paste/data", }) local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.NodeRenamed) diff --git a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua index 3e9d44bfa32..5a8c4d7b6e9 100644 --- a/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua +++ b/test/nvt/func/fs/print_clipboard/print_clipboard_spec.lua @@ -3,7 +3,8 @@ local n = require("test.functional.testnvim")() local nf = require("test.nvt.func.fixtures") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen @@ -11,7 +12,10 @@ local screen t.before_each(function() - screen = nf.create_session({}, nil, nil, { ext_messages = true, }) + screen = nf.create_session({ + data = "test/nvt/func/fs/print_clipboard/data", + screen_opts = { ext_messages = true }, + }) end) diff --git a/test/nvt/func/fs/trash/node_spec.lua b/test/nvt/func/fs/trash/node_spec.lua index f02c206e995..fb024cf5d41 100644 --- a/test/nvt/func/fs/trash/node_spec.lua +++ b/test/nvt/func/fs/trash/node_spec.lua @@ -3,7 +3,8 @@ local nf = require("test.nvt.func.fixtures") local na = require("test.nvt.func.asserts") -- 0.12 global compatibility -t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each ---@diagnostic disable-line: inject-field, undefined-global +---@diagnostic disable-next-line: inject-field, undefined-global +t.describe, t.it, t.before_each = t.describe or describe, t.it or it, t.before_each or before_each --- @type test.functional.ui.screen @@ -13,7 +14,11 @@ local screen ---@param config nvim_tree.config ---@return test.functional.ui.screen local function create_trash_session(config) - screen = nf.create_session(config, nil, nil, { ext_messages = true, ext_cmdline = true, }) + screen = nf.create_session({ + config = config, + data = "test/nvt/func/fs/trash/data", + screen_opts = { ext_messages = true, ext_cmdline = true, }, + }) local Event = require("nvim-tree._meta.api.events").Event nf.event_subscribe(Event.FileRemoved) diff --git a/test/nvt/func/init_live.lua b/test/nvt/func/init_live.lua index b103b59e041..5dc97c00dc5 100644 --- a/test/nvt/func/init_live.lua +++ b/test/nvt/func/init_live.lua @@ -71,8 +71,9 @@ screen_resize() -- use dark background for readability under dark and light vim.o.background = "dark" +-- TODO find and pass dir_data if present -- test instance cwd -vim.api.nvim_set_current_dir(require("test.nvt.func.dirs").setup_cwd()) +vim.api.nvim_set_current_dir(require("test.nvt.func.util").setup_cwd()) -- mappings vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) diff --git a/test/nvt/func/util.lua b/test/nvt/func/util.lua index e90b38f0f37..2d2dc8cffe7 100644 --- a/test/nvt/func/util.lua +++ b/test/nvt/func/util.lua @@ -25,19 +25,27 @@ function M.sys(cmd) end ---Create /tmp/nvt_func or populated /tmp/nvt_func/data +---@param dir_data? string relative path of data directory to copy for test instance cwd ---@return string absolute path -function M.setup_cwd() - local cwd, dir_test = M.env("NVT_FUNC_DIR_CWD"), M.env("NVT_FUNC_DIR_TEST") +function M.setup_cwd(dir_data) + local cwd = M.env("NVT_FUNC_DIR_CWD") -- always blow away and recreate the cwd of the test instance M.sys({ "rm", "-rf", cwd }) M.sys({ "mkdir", "-p", cwd }) -- if data is present, recursively copy it and use that as cwd - local dir_test_data = dir_test .. "/data" - if vim.uv.fs_stat(dir_test_data) then - M.sys({ "cp", "-p", "-r", dir_test_data, cwd }) + if dir_data then + local abs_dir_data = M.env("NVT_FUNC_DIR_ROOT") .. "/" .. dir_data + local _, err = vim.uv.fs_stat(abs_dir_data) + assert(not err, err) + + M.sys({ "cp", "-p", "-r", abs_dir_data, cwd }) cwd = cwd .. "/data" + + print(" created test cwd " .. cwd .. " from " .. abs_dir_data) + else + print(" created empty test cwd " .. cwd) end return cwd From c824e52138278c9dc64ea5baff27414f7283b250 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 19 Oct 2026 11:36:46 +1100 Subject: [PATCH 153/154] test: copy data directory from source, enable live, allow dirs other than data --- scripts/functionaltest.sh | 51 +++++++++++++++---------------------- test/nvt/func/init_live.lua | 5 ++-- test/nvt/func/util.lua | 15 +++++++---- 3 files changed, 34 insertions(+), 37 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index b44206f6fe3..5984ba425e9 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -14,6 +14,15 @@ fi # define $DIR_NVIM_SRC . scripts/check-nvim-src.sh +# absolute path of nvim-tree source +export NVT_DIR_SRC="${PWD}" + +# absolute path of the test instance cwd +export NVT_FUNC_DIR_CWD="/tmp/nvt_func" + +# optional argument of -l +export NVT_DIR_LIVE= + # parent directory under which nvim-tree is linked under Nvim source # uses src (not test or runtime) to prevent luals from finding it # src can be found in build/Xtest_xdg, which contains only links to runtime, src and test @@ -21,17 +30,11 @@ fi export NVT_FUNC_PACKPATH="${DIR_NVIM_SRC}/src/nvt" # absolute link to nvim-tree source root under Nvim source -export NVT_FUNC_DIR_ROOT="${NVT_FUNC_PACKPATH}/pack/dist/opt/nvim-tree.lua" - -# absolute path of the test instance cwd -export NVT_FUNC_DIR_CWD="/tmp/nvt_func" +dir_src_linked="${NVT_FUNC_PACKPATH}/pack/dist/opt/nvim-tree.lua" # absolute paths of test spec files to execute, under Nvim source files_test_lua= -# live data directory or "none", empty when -l not specified -dir_live= - # number of test failures failures=0 @@ -39,7 +42,7 @@ failures=0 mode= usage() { - echo "Usage: ${0} [-a] [-h] [-t ] [-l []]" + echo "Usage: ${0} [-a] [-h] [-t ] [-l []]" echo echo " OPTION:" echo " -a Execute all tests" @@ -64,11 +67,11 @@ mode_set() { # add a single file $1 or all _spec.lua files under directory $1 to $files_test_lua files_test_lua_add() { if [ -f "${1}" ]; then - files_test_lua="${files_test_lua} ${NVT_FUNC_DIR_ROOT}/${1}" + files_test_lua="${files_test_lua} ${dir_src_linked}/${1}" elif [ -d "${1}" ]; then find "${1}" -type f -iname '*_spec.lua' > /tmp/nvt_files_test_lua while IFS= read -r f; do - files_test_lua="${files_test_lua} ${NVT_FUNC_DIR_ROOT}/${f}" + files_test_lua="${files_test_lua} ${dir_src_linked}/${f}" done < /tmp/nvt_files_test_lua rm /tmp/nvt_files_test_lua else @@ -81,20 +84,14 @@ files_test_lua_add() { fi } -# set $dir_live to "none" when not passed, otherwise test directory +# set $NVT_DIR_LIVE if present otherwise unset dir_live_set() { if [ -z "${1}" ]; then - dir_live="none" - elif [ -f "${1}" ]; then - dir_live="$(dirname "${1}")" + unset NVT_DIR_LIVE elif [ -d "${1}" ]; then - if [ "$(basename "${1}")" = "data" ]; then - dir_live="$(dirname "${1}")" - else - dir_live="${1}" - fi + NVT_DIR_LIVE="${1}" else - echo "${1} inexistent" >&2 + echo "${1} not a directory" >&2 exit 1 fi } @@ -138,14 +135,14 @@ setup() { teardown # nvim-tree source link - mkdir -p "$(dirname "${NVT_FUNC_DIR_ROOT}")" - ln -sv "${PWD}" "${NVT_FUNC_DIR_ROOT}" + mkdir -p "$(dirname "${dir_src_linked}")" + ln -sv "${PWD}" "${dir_src_linked}" } # after all tests: remove plugin and test links from Nvim source root teardown() { # nvim-tree source link - rm -fv "${NVT_FUNC_DIR_ROOT}" + rm -fv "${dir_src_linked}" # test/live instance cwd rm -rf "${NVT_FUNC_DIR_CWD}" @@ -153,11 +150,6 @@ teardown() { # TODO run with the compiled nvim version under test live() { - if [ "${dir_live}" != "none" ]; then - NVT_FUNC_DIR_TEST="$(realpath "${dir_live}")" - fi - - # options extracted from testnvim.lua nvim_argv, nvim_set nvim \ --clean \ --noplugin \ @@ -179,12 +171,11 @@ run_tests() { # execute all requested tests for f in ${files_test_lua}; do - # append nvim-tree lua/test to package.path, so that tests themselves may access nvim-tree source # don't exit on failure, just note it make functionaltest \ TEST_FILE="${f}" \ - TEST_ARGS="--lpath=${NVT_FUNC_DIR_ROOT}/?.lua --lpath=${NVT_FUNC_DIR_ROOT}/lua/?.lua --lpath=${NVT_FUNC_DIR_ROOT}/lua/?/init.lua" \ + TEST_ARGS="--lpath=${dir_src_linked}/?.lua --lpath=${dir_src_linked}/lua/?.lua --lpath=${dir_src_linked}/lua/?/init.lua" \ || failures=$((failures + 1)) done } diff --git a/test/nvt/func/init_live.lua b/test/nvt/func/init_live.lua index 5dc97c00dc5..96142fb91d1 100644 --- a/test/nvt/func/init_live.lua +++ b/test/nvt/func/init_live.lua @@ -1,3 +1,5 @@ +local nu = require("test.nvt.func.util") + -- match the test screen size: r to reapply if the terminal is not cooperating local function screen_resize() vim.o.columns = 80 @@ -71,9 +73,8 @@ screen_resize() -- use dark background for readability under dark and light vim.o.background = "dark" --- TODO find and pass dir_data if present -- test instance cwd -vim.api.nvim_set_current_dir(require("test.nvt.func.util").setup_cwd()) +vim.api.nvim_set_current_dir(nu.setup_cwd(os.getenv("NVT_DIR_LIVE"), true)) -- mappings vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) diff --git a/test/nvt/func/util.lua b/test/nvt/func/util.lua index 2d2dc8cffe7..900e6b641e3 100644 --- a/test/nvt/func/util.lua +++ b/test/nvt/func/util.lua @@ -26,8 +26,9 @@ end ---Create /tmp/nvt_func or populated /tmp/nvt_func/data ---@param dir_data? string relative path of data directory to copy for test instance cwd +---@param quiet? boolean do not print notices, default false ---@return string absolute path -function M.setup_cwd(dir_data) +function M.setup_cwd(dir_data, quiet) local cwd = M.env("NVT_FUNC_DIR_CWD") -- always blow away and recreate the cwd of the test instance @@ -36,16 +37,20 @@ function M.setup_cwd(dir_data) -- if data is present, recursively copy it and use that as cwd if dir_data then - local abs_dir_data = M.env("NVT_FUNC_DIR_ROOT") .. "/" .. dir_data + local abs_dir_data = M.env("NVT_DIR_SRC") .. "/" .. dir_data local _, err = vim.uv.fs_stat(abs_dir_data) assert(not err, err) - M.sys({ "cp", "-p", "-r", abs_dir_data, cwd }) cwd = cwd .. "/data" + M.sys({ "cp", "-p", "-r", abs_dir_data, cwd }) - print(" created test cwd " .. cwd .. " from " .. abs_dir_data) + if not quiet then + print(" created test cwd " .. cwd .. " from " .. abs_dir_data) + end else - print(" created empty test cwd " .. cwd) + if not quiet then + print(" created empty test cwd " .. cwd) + end end return cwd From e69b7f738bc992ba426a7228c5356b3861bd1100 Mon Sep 17 00:00:00 2001 From: Alexander Courtis Date: Mon, 19 Oct 2026 13:26:38 +1100 Subject: [PATCH 154/154] test: execute all test in one call to make functionaltest --- scripts/functionaltest.sh | 66 ++++++++++--------------------------- test/nvt/func/README.md | 4 +-- test/nvt/func/fixtures.lua | 1 + test/nvt/func/init_live.lua | 3 +- test/nvt/func/util.lua | 16 +++------ 5 files changed, 26 insertions(+), 64 deletions(-) diff --git a/scripts/functionaltest.sh b/scripts/functionaltest.sh index 5984ba425e9..95d69e29105 100755 --- a/scripts/functionaltest.sh +++ b/scripts/functionaltest.sh @@ -17,6 +17,7 @@ fi # absolute path of nvim-tree source export NVT_DIR_SRC="${PWD}" +# TODO just hardcode this # absolute path of the test instance cwd export NVT_FUNC_DIR_CWD="/tmp/nvt_func" @@ -29,24 +30,25 @@ export NVT_DIR_LIVE= # pack/dist/opt is added underneath to satisfy :packadd convention export NVT_FUNC_PACKPATH="${DIR_NVIM_SRC}/src/nvt" +# passed to make functionaltest; underneath Nvim source +export TEST_FILE= + # absolute link to nvim-tree source root under Nvim source dir_src_linked="${NVT_FUNC_PACKPATH}/pack/dist/opt/nvim-tree.lua" -# absolute paths of test spec files to execute, under Nvim source -files_test_lua= - # number of test failures failures=0 # a, t or l mode= +# TODO clarify messages usage() { echo "Usage: ${0} [-a] [-h] [-t ] [-l []]" echo echo " OPTION:" echo " -a Execute all tests" - echo " -t Execute single test file or all under directory" + echo " -t Executes single test file or all under directory, passed as TEST_FILE to Nvim make functionaltest" echo " -l Live environment, optionally using a data directory" echo " -h Show this help" } @@ -55,6 +57,7 @@ usage() { # CLI args # +# TODO remove, this is too complex # set $mode to $1, fail if another $mode already set mode_set() { if [ -n "${mode}" ] && [ "${mode}" != "${1}" ]; then @@ -64,43 +67,11 @@ mode_set() { mode="${1}" } -# add a single file $1 or all _spec.lua files under directory $1 to $files_test_lua -files_test_lua_add() { - if [ -f "${1}" ]; then - files_test_lua="${files_test_lua} ${dir_src_linked}/${1}" - elif [ -d "${1}" ]; then - find "${1}" -type f -iname '*_spec.lua' > /tmp/nvt_files_test_lua - while IFS= read -r f; do - files_test_lua="${files_test_lua} ${dir_src_linked}/${f}" - done < /tmp/nvt_files_test_lua - rm /tmp/nvt_files_test_lua - else - echo "${1} inexistent" >&2 - exit 1 - fi - if [ -z "${files_test_lua}" ]; then - echo "no tests found in ${1}" >&2 - exit 1 - fi -} - -# set $NVT_DIR_LIVE if present otherwise unset -dir_live_set() { - if [ -z "${1}" ]; then - unset NVT_DIR_LIVE - elif [ -d "${1}" ]; then - NVT_DIR_LIVE="${1}" - else - echo "${1} not a directory" >&2 - exit 1 - fi -} - while getopts "ahlt:" o; do case "${o}" in a) mode_set "${o}" - files_test_lua_add "test/nvt/func" + TEST_FILE="${dir_src_linked}/test/nvt/func" ;; h) usage @@ -109,11 +80,11 @@ while getopts "ahlt:" o; do l) shift mode_set "${o}" - dir_live_set "${1}" + NVT_DIR_LIVE="${1}" ;; t) mode_set "${o}" - files_test_lua_add "${OPTARG}" + TEST_FILE="${dir_src_linked}/${OPTARG}" ;; *) usage >&2 @@ -164,20 +135,17 @@ live() { || failures=1 } -# TODO we can probably run this with a directory now instead of individual files run_tests() { # cmake must be run from nvim source root cd "${DIR_NVIM_SRC}" - # execute all requested tests - for f in ${files_test_lua}; do - # append nvim-tree lua/test to package.path, so that tests themselves may access nvim-tree source - # don't exit on failure, just note it - make functionaltest \ - TEST_FILE="${f}" \ - TEST_ARGS="--lpath=${dir_src_linked}/?.lua --lpath=${dir_src_linked}/lua/?.lua --lpath=${dir_src_linked}/lua/?/init.lua" \ - || failures=$((failures + 1)) - done + # export TEST_COLOURS=false + + # append nvim-tree lua/test to package.path, so that tests themselves may access nvim-tree source + export TEST_ARGS="--lpath=${dir_src_linked}/?.lua --lpath=${dir_src_linked}/lua/?.lua --lpath=${dir_src_linked}/lua/?/init.lua" + + # don't exit on failure, just note it + make functionaltest || failures=$((failures + 1)) } # diff --git a/test/nvt/func/README.md b/test/nvt/func/README.md index 3db6635809d..e429b06971a 100644 --- a/test/nvt/func/README.md +++ b/test/nvt/func/README.md @@ -1,10 +1,10 @@ # Generating Test Data -Execute `scripts/functionaltest.sh -l [ ]` +Execute `scripts/functionaltest.sh -l [ ]` This will open an interactive vim session that closely matches the test headless session, using the init: `test/func/init_live.lua`. Add any test specific config to `require("nvim-tree").setup` when needed. -If a `data` directory is present, it will be copied and the session will execute in `/tmp/nvt_func/data` otherwise `/tmp/nvt_func`. +If a `data` directory is given, it will be recursively copied to cwd `/tmp/nvt_func/data` otherwise uses empty cwd `/tmp/nvt_func` Test's `data` directory will be used if present. diff --git a/test/nvt/func/fixtures.lua b/test/nvt/func/fixtures.lua index ae3899dd7ee..f2561bceb3f 100644 --- a/test/nvt/func/fixtures.lua +++ b/test/nvt/func/fixtures.lua @@ -59,6 +59,7 @@ function M.create_session(opts) require("nvim-tree").setup(opts.config) end) + -- TODO this is causing performance issues when running all as a single test execution, and they persist -- create attr_ids for all nvim-tree test highlight groups M.add_nvt_attr_ids(screen) diff --git a/test/nvt/func/init_live.lua b/test/nvt/func/init_live.lua index 96142fb91d1..f1459d786eb 100644 --- a/test/nvt/func/init_live.lua +++ b/test/nvt/func/init_live.lua @@ -74,7 +74,8 @@ screen_resize() vim.o.background = "dark" -- test instance cwd -vim.api.nvim_set_current_dir(nu.setup_cwd(os.getenv("NVT_DIR_LIVE"), true)) +local cwd = nu.setup_cwd(os.getenv("NVT_DIR_LIVE")) +vim.api.nvim_set_current_dir(cwd) -- mappings vim.keymap.set("n", "u", function() live_dump(false) end, { remap = false, }) diff --git a/test/nvt/func/util.lua b/test/nvt/func/util.lua index 900e6b641e3..8d1f8391beb 100644 --- a/test/nvt/func/util.lua +++ b/test/nvt/func/util.lua @@ -26,9 +26,8 @@ end ---Create /tmp/nvt_func or populated /tmp/nvt_func/data ---@param dir_data? string relative path of data directory to copy for test instance cwd ----@param quiet? boolean do not print notices, default false ---@return string absolute path -function M.setup_cwd(dir_data, quiet) +function M.setup_cwd(dir_data) local cwd = M.env("NVT_FUNC_DIR_CWD") -- always blow away and recreate the cwd of the test instance @@ -38,19 +37,12 @@ function M.setup_cwd(dir_data, quiet) -- if data is present, recursively copy it and use that as cwd if dir_data then local abs_dir_data = M.env("NVT_DIR_SRC") .. "/" .. dir_data - local _, err = vim.uv.fs_stat(abs_dir_data) - assert(not err, err) + local stat, err = vim.uv.fs_stat(abs_dir_data) + assert(not err, err) + assert(stat and stat.type == "directory", abs_dir_data .. " not a directory") cwd = cwd .. "/data" M.sys({ "cp", "-p", "-r", abs_dir_data, cwd }) - - if not quiet then - print(" created test cwd " .. cwd .. " from " .. abs_dir_data) - end - else - if not quiet then - print(" created empty test cwd " .. cwd) - end end return cwd