diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/plugin_conformance.lua | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/tests/plugin_conformance.lua b/tests/plugin_conformance.lua new file mode 100644 index 0000000..90603a9 --- /dev/null +++ b/tests/plugin_conformance.lua @@ -0,0 +1,196 @@ +local script = debug.getinfo(1, "S").source:sub(2) +local root = script:match("^(.*)/tests/plugin_conformance%.lua$") or "." +vim.opt.runtimepath:prepend(root) + +local domain = require("clever_f.domain") +local assertions = dofile(root .. "/tests/assertions.lua") +local same = assertions.same +local truthy = assertions.truthy + +vim.g.clever_f_mark_cursor = 0 +vim.g.clever_f_mark_char = 0 +vim.g.clever_f_mark_direct = 0 +vim.g.clever_f_hide_cursor_on_cmdline = 0 +vim.g.clever_f_clean_labels_eagerly = 1 +vim.g.clever_f_highlight_timeout_ms = 0 +vim.cmd.runtime("plugin/clever_f.lua") + +local clever_f = require("clever_f") +local checks = 0 + +local function check_same(expected, actual, message) + same(expected, actual, message) + checks = checks + 1 +end + +local function check_truthy(value, message) + truthy(value, message) + checks = checks + 1 +end + +local function feed(keys) + vim.api.nvim_feedkeys(vim.keycode(keys), "xt", false) + vim.cmd("redraw") + vim.wait(10) +end + +local function setup(lines, column) + feed("<Esc>") + clever_f._diagnostic_full_reset() + vim.g.clever_f_mark_char = 0 + vim.g.clever_f_highlight_timeout_ms = 0 + vim.api.nvim_buf_set_lines(0, 0, -1, true, lines) + vim.api.nvim_win_set_cursor(0, { 1, (column or 1) - 1 }) +end + +local visual_cases = { + { prefix = "v", mode = "v", adjusted = true }, + { prefix = "V", mode = "V", adjusted = true }, + { prefix = "<C-v>", mode = string.char(0x16), adjusted = false }, +} +for _, selection in ipairs({ "inclusive", "exclusive" }) do + vim.o.selection = selection + for _, case in ipairs(visual_cases) do + setup({ "axz", "second" }) + feed(case.prefix .. "fx") + local expected_column = selection == "exclusive" and case.adjusted and 2 or 1 + check_same(expected_column, vim.api.nvim_win_get_cursor(0)[2], selection .. case.prefix) + check_same(case.mode, vim.api.nvim_get_mode().mode, selection .. case.prefix) + end +end + +vim.o.selection = "inclusive" +local select_cases = { + { prefix = "gh", mode = "s" }, + { prefix = "gH", mode = "S" }, + { prefix = "g<C-h>", mode = string.char(0x13) }, +} +for _, case in ipairs(select_cases) do + setup({ "axz", "second" }) + feed(case.prefix) + check_same(case.mode, vim.api.nvim_get_mode().mode, case.prefix) + vim.api.nvim_feedkeys("x", "n", false) + local outcome = clever_f.StartFindForward() + check_same(domain.ActionKind.MOVEMENT, outcome.kind, case.prefix) + check_same(1, vim.api.nvim_win_get_cursor(0)[2], case.prefix) + check_same(case.mode, vim.api.nvim_get_mode().mode, case.prefix) +end + +local source = "hoge fuge piye poye" +local operator_cases = { + { keys = "dfe", column = 1, text = " fuge piye poye", cursor = 0 }, + { keys = "dte", column = 1, text = "e fuge piye poye", cursor = 0 }, + { keys = "dFe", column = 19, text = "hoge fuge piye", cursor = 13 }, + { keys = "dTe", column = 19, text = "hoge fuge piyee", cursor = 14 }, +} +for _, selection in ipairs({ "inclusive", "exclusive" }) do + vim.o.selection = selection + for _, case in ipairs(operator_cases) do + setup({ source }, case.column) + feed(case.keys) + check_same(case.text, vim.api.nvim_get_current_line(), selection .. case.keys) + check_same(case.cursor, vim.api.nvim_win_get_cursor(0)[2], selection .. case.keys) + check_same(selection, vim.o.selection, selection .. case.keys) + end +end + +vim.o.selection = "inclusive" +local multibyte = "\227\129\130" +setup({ "x" .. multibyte .. "x" .. multibyte }) +feed("f" .. multibyte) +check_same(1, vim.api.nvim_win_get_cursor(0)[2], "first multibyte target") +feed("f") +check_same(5, vim.api.nvim_win_get_cursor(0)[2], "second multibyte target") +feed("F") +check_same(1, vim.api.nvim_win_get_cursor(0)[2], "backward multibyte target") + +setup({ "abc" }) +feed("f<F1>") +check_same(0, vim.api.nvim_win_get_cursor(0)[2], "encoded special key") +check_same( + domain.TargetKind.SPECIAL_KEY.value, + clever_f.state():get_previous_target("n").kind.value, + "encoded special key target kind" +) + +setup({ "1a 2a 3a 4a 5a" }) +vim.fn.setreg("q", "fax") +feed("5@q") +check_same("1 2 3 4 5", vim.api.nvim_get_current_line(), "macro acquisitions") + +local saved_foldmethod = vim.wo.foldmethod +local saved_foldopen = vim.o.foldopen +setup({ "one", "two", "xax", "four", "five" }) +vim.wo.foldmethod = "manual" +vim.cmd("1,5fold") +vim.cmd("2,4fold") +vim.cmd("normal! zM") +vim.o.foldopen = "hor" +vim.api.nvim_win_set_cursor(0, { 3, 0 }) +check_truthy(vim.fn.foldclosed(3) ~= -1, "nested fold starts closed") +feed("fa") +check_same(-1, vim.fn.foldclosed(3), "nested folds opened") +check_same(1, vim.api.nvim_win_get_cursor(0)[2], "fold motion endpoint") +vim.cmd("normal! zE") +vim.wo.foldmethod = saved_foldmethod +vim.o.foldopen = saved_foldopen + +local function setup_feedback(timeout) + setup({ "ahahah" }) + vim.g.clever_f_mark_char = 1 + vim.g.clever_f_highlight_timeout_ms = timeout or 0 + feed("fh") + local state = clever_f.state():to_table() + check_same(1, #state.target_overlays, "target overlay created") + check_same(1, #state.finalizers, "finalizer created") + return state +end + +setup_feedback() +vim.api.nvim_win_set_cursor(0, { 1, 2 }) +vim.api.nvim_exec_autocmds("CursorMoved", { buffer = 0 }) +local finalized = clever_f.state():to_table() +check_same(0, #finalized.target_overlays, "CursorMoved overlay cleanup") +check_same(0, #finalized.finalizers, "CursorMoved finalizer cleanup") +check_same(nil, finalized.contexts.n.previous_landing, "CursorMoved landing cleanup") + +setup_feedback() +vim.api.nvim_exec_autocmds("InsertEnter", { buffer = 0 }) +finalized = clever_f.state():to_table() +check_same(0, #finalized.target_overlays, "InsertEnter overlay cleanup") +check_same(nil, finalized.contexts.n.previous_landing, "InsertEnter landing cleanup") + +setup_feedback() +vim.api.nvim_exec_autocmds("TextChanged", { buffer = 0 }) +finalized = clever_f.state():to_table() +check_same(0, #finalized.target_overlays, "TextChanged overlay cleanup") +check_same(nil, finalized.contexts.n.previous_landing, "TextChanged landing cleanup") + +for _, event in ipairs({ "WinEnter", "WinLeave", "CmdwinLeave" }) do + local before = setup_feedback() + vim.api.nvim_exec_autocmds(event, {}) + local eager = clever_f.state():to_table() + check_same(0, #eager.target_overlays, event .. " overlay cleanup") + check_same(1, #eager.finalizers, event .. " finalizer retention") + check_same( + before.contexts.n.previous_landing.byte_column, + eager.contexts.n.previous_landing.byte_column, + event .. " landing retention" + ) +end + +setup_feedback(20) +local timed_landing = clever_f.state():get_previous_landing("n") +vim.wait(60) +local timed = clever_f.state():to_table() +check_same(0, #timed.target_overlays, "timer overlay cleanup") +check_same(nil, timed.highlight_timer, "timer identity cleanup") +check_same(timed_landing, clever_f.state():get_previous_landing("n"), "timer history retention") +feed("f") +local restored = clever_f.state():to_table() +check_same(4, restored.contexts.n.previous_landing.byte_column, "repeat after timer cleanup") +check_same(1, #restored.target_overlays, "repeat restores target overlay") +check_truthy(restored.highlight_timer ~= nil, "repeat starts a replacement timer") + +clever_f._diagnostic_full_reset() +io.stdout:write(string.format("Phase 16 plugin conformance: %d checks passed\n", checks)) |
