Skip to content

Commit 86ae3cf

Browse files
committed
Update tests to more accurately measure highlights
1 parent e52e04f commit 86ae3cf

File tree

4 files changed

+145
-149
lines changed

4 files changed

+145
-149
lines changed

lua/treewalker/operations.lua

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,24 +39,18 @@ end
3939
---@param hl_group string
4040
function M.highlight(range, duration, hl_group)
4141
local start_row, start_col, end_row, end_col = range[1], range[2], range[3], range[4]
42-
local ns_prefix = "treewalker.nvim-movement-highlight-"
43-
local ns_name = ns_prefix .. util.guid()
44-
local local_ns_id = vim.api.nvim_create_namespace(ns_name)
42+
local ns_name = "treewalker.nvim-movement-highlight"
43+
local ns_id = vim.api.nvim_create_namespace(ns_name)
4544

4645
-- clear any previous highlights so there aren't multiple active at the same time
47-
-- Find them by prefix, whole local name will only be used for timeout below
48-
for name, id in pairs(vim.api.nvim_get_namespaces()) do
49-
if vim.startswith(name, ns_prefix) then
50-
vim.api.nvim_buf_clear_namespace(0, id, 0, -1)
51-
end
52-
end
46+
vim.api.nvim_buf_clear_namespace(0, ns_id, 0, -1)
5347

5448
if vim.hl then
5549
-- vim.hl.range (Neovim 0.10+ replacement for nvim_buf_add_highlight)
5650
-- Has timeout option, but when it expires, _auto clears whole namespace_ for pete's sake
5751
vim.hl.range(
5852
0,
59-
local_ns_id,
53+
ns_id,
6054
hl_group,
6155
{ start_row, start_col },
6256
{ end_row, end_col },
@@ -65,13 +59,13 @@ function M.highlight(range, duration, hl_group)
6559
else
6660
-- support for lower versions of neovim
6761
for row = start_row, end_row do
68-
vim.api.nvim_buf_add_highlight(0, local_ns_id, hl_group, row, 0, -1)
62+
vim.api.nvim_buf_add_highlight(0, ns_id, hl_group, row, 0, -1)
6963
end
7064
end
7165

7266
-- Remove the local highlight after delay
7367
vim.defer_fn(function()
74-
vim.api.nvim_buf_clear_namespace(0, local_ns_id, start_row, end_row + 1)
68+
vim.api.nvim_buf_clear_namespace(0, ns_id, start_row, end_row + 1)
7569
end, duration)
7670
end
7771

tests/treewalker/helpers.lua

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,40 @@ end
8181
---@param scol integer
8282
---@param erow integer
8383
---@param ecol integer
84-
---@param stoob any
85-
---@param desc string | nil
86-
function M.assert_highlighted(srow, scol, erow, ecol, stoob, desc)
87-
assert(#stoob.calls >= 1, "highlight was not called at all")
88-
89-
assert.same(
90-
{ srow - 1, scol - 1, erow - 1, ecol },
91-
stoob.calls[#stoob.calls].refs[1],
92-
"highlight wrong for: " .. (desc or "")
93-
)
84+
function M.assert_highlighted(srow, scol, erow, ecol)
85+
local ns_id = vim.api.nvim_create_namespace("treewalker.nvim-movement-highlight")
86+
local highlights = vim.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })
87+
88+
for _, highlight in ipairs(highlights) do
89+
local actual_srow = highlight[2] + 1
90+
local actual_scol = highlight[3] + 1
91+
local actual_erow = highlight[4].end_row + 1
92+
local actual_ecol = highlight[4].end_col
93+
94+
-- print("actual_srow:", actual_srow)
95+
-- print("actual_scol:", actual_scol)
96+
-- print("actual_erow:", actual_erow)
97+
-- print("actual_ecol:", actual_ecol)
98+
99+
if
100+
srow == actual_srow
101+
and scol == actual_scol
102+
and erow == actual_erow
103+
and ecol == actual_ecol
104+
then
105+
return true
106+
end
107+
end
108+
109+
assert(false, "Specified highlight not found")
110+
end
111+
112+
-- Get count of active treewalker highlights
113+
---@return integer
114+
function M.get_highlight_count()
115+
local ns_id = vim.api.nvim_create_namespace("treewalker.nvim-movement-highlight")
116+
local highlights = vim.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, {})
117+
return #highlights
94118
end
95119

96120
return M

tests/treewalker/highlight_spec.lua

Lines changed: 94 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -1,199 +1,181 @@
1-
local spy = require('luassert.spy')
2-
local match = require('luassert.match')
31
local load_fixture = require "tests.load_fixture"
4-
local stub = require 'luassert.stub'
52
local assert = require "luassert"
3+
local stub = require 'luassert.stub'
64
local tw = require 'treewalker'
75
local h = require 'tests.treewalker.helpers'
86
local operations = require 'treewalker.operations'
97

10-
-- Test for highlight clear-before-highlight behavior
11-
describe("Clears previous highlights before applying new", function()
12-
local clear_spy, hlrange_spy
8+
describe("Highlights", function()
9+
load_fixture("/lua.lua")
1310

1411
before_each(function()
15-
clear_spy = spy.on(vim.api, "nvim_buf_clear_namespace")
16-
hlrange_spy = spy.on(vim.hl, "range")
17-
end)
18-
19-
after_each(function()
20-
clear_spy:revert()
21-
hlrange_spy:revert()
22-
end)
23-
24-
it("calls clear_namespace before every highlight", function()
25-
local range1 = { 1, 2, 3, 4 }
26-
local range2 = { 10, 2, 12, 4 }
27-
operations.highlight(range1, 50, "CursorLine")
28-
operations.highlight(range2, 50, "CursorLine")
29-
30-
-- For each highlight call, we should first clear, then range highlight
31-
assert.spy(clear_spy).was.called_with(0, match.is_number(), 0, -1)
32-
assert.spy(clear_spy).was.called(3)
33-
assert.spy(hlrange_spy).was.called(2)
34-
-- check arguments
35-
local call1 = hlrange_spy.calls[1].vals
36-
local call2 = hlrange_spy.calls[2].vals
37-
assert.equal(0, call1[1])
38-
assert.is_number(call1[2])
39-
assert.equal("CursorLine", call1[3])
40-
assert.same({1,2}, call1[4])
41-
assert.same({3,4}, call1[5])
42-
assert.same({ inclusive = true }, call1[6])
43-
44-
assert.equal(0, call2[1])
45-
assert.is_number(call2[2])
46-
assert.equal("CursorLine", call2[3])
47-
assert.same({10,2}, call2[4])
48-
assert.same({12,4}, call2[5])
49-
assert.same({ inclusive = true }, call2[6])
50-
end)
51-
end)
12+
-- Clear any leftover namespaces from previous tests
13+
local ns_id = vim.api.nvim_create_namespace("treewalker.nvim-movement-highlight")
14+
vim.api.nvim_buf_clear_namespace(0, ns_id, 0, -1)
5215

53-
describe("Highlights in a lua spec file: ", function()
54-
local highlight_stub
16+
tw.setup({ highlight = true, highlight_duration = 5 })
17+
end)
5518

56-
load_fixture("/lua-spec.lua")
19+
it("creates visible highlights when moving and clears them after timeout", function()
20+
-- Start with clean state - count initial highlights
21+
local initial_count = h.get_highlight_count()
22+
assert.equal(0, initial_count)
5723

58-
before_each(function()
59-
highlight_stub = stub.new(operations, "highlight")
60-
end)
24+
vim.fn.cursor(10, 1)
25+
tw.move_down()
6126

62-
after_each(function()
63-
highlight_stub:revert()
64-
end)
27+
local after_move_count = h.get_highlight_count()
28+
assert.equal(1, after_move_count, "No OG highlight detected")
6529

66-
it("highlights full block on move_in() (identified in gh #30)", function()
67-
vim.fn.cursor(64, 3)
68-
tw.move_in()
69-
h.assert_highlighted(67, 5, 85, 8, highlight_stub, "it block")
30+
-- Wait for timeout and verify highlights are cleared
31+
vim.wait(20, function() return false end)
32+
local after_timeout_count = h.get_highlight_count()
33+
assert.equal(0, after_timeout_count, "Highlights not cleared after timeout")
7034
end)
71-
end)
7235

73-
describe("Highlights in a regular lua file: ", function()
74-
local highlight_stub
36+
it("clears previous highlights when making new movement", function()
37+
assert.equal(0, h.get_highlight_count())
7538

76-
load_fixture("/lua.lua")
39+
vim.fn.cursor(10, 1)
40+
tw.move_down()
41+
tw.move_up()
7742

78-
before_each(function()
79-
highlight_stub = stub.new(operations, "highlight")
43+
assert.equal(1, h.get_highlight_count())
8044
end)
8145

82-
after_each(function()
83-
highlight_stub:revert()
84-
end)
46+
it("does not create highlights when highlight option is disabled", function()
47+
tw.setup({ highlight = false })
48+
assert.equal(0, h.get_highlight_count())
8549

86-
it("respects default highlight option", function()
87-
tw.setup() -- highlight defaults to true, doesn't blow up with empty setup
88-
vim.fn.cursor(23, 5)
89-
tw.move_out()
50+
vim.fn.cursor(10, 1)
9051
tw.move_down()
9152
tw.move_up()
9253
tw.move_in()
93-
assert.equal(4, #highlight_stub.calls)
54+
tw.move_out()
55+
56+
assert.equal(0, h.get_highlight_count(), "Highlights created when disabled")
9457
end)
9558

96-
it("respects highlight config option", function()
97-
highlight_stub = stub.new(operations, "highlight")
98-
tw.setup({ highlight = false })
99-
vim.fn.cursor(23, 5)
100-
tw.move_out()
101-
tw.move_down()
102-
tw.move_up()
59+
it("highlights appear when moving in any direction", function()
60+
assert.equal(0, h.get_highlight_count())
61+
62+
vim.fn.cursor(10, 1)
10363
tw.move_in()
104-
assert.equal(0, #highlight_stub.calls)
10564

106-
highlight_stub = stub(operations, "highlight")
107-
tw.setup({ highlight = true })
108-
vim.fn.cursor(23, 5)
109-
tw.move_out()
110-
tw.move_down()
111-
tw.move_up()
65+
assert.equal(1, h.get_highlight_count())
66+
end)
67+
68+
it("highlights full block on move_in() (identified in gh #30)", function()
69+
vim.fn.cursor(21, 1)
11270
tw.move_in()
113-
assert.equal(4, #highlight_stub.calls)
71+
h.assert_highlighted(22, 3, 26, 5)
11472
end)
11573

11674
it("respects default highlight_duration", function()
117-
tw.setup({ highlight = true })
118-
tw.move_out()
119-
local duration_arg = highlight_stub.calls[1].refs[2]
120-
assert.equal(250, duration_arg)
121-
end)
75+
-- Clear any leftover namespaces from previous tests
76+
local ns_id = vim.api.nvim_create_namespace("treewalker.nvim-movement-highlight")
77+
vim.api.nvim_buf_clear_namespace(0, ns_id, 0, -1)
78+
79+
-- Directly set opts to default values to bypass before_each
80+
local tw_init = require('treewalker')
81+
tw_init.opts = {
82+
highlight = true,
83+
highlight_duration = 250,
84+
highlight_group = "CursorLine",
85+
jumplist = true,
86+
}
87+
88+
-- Stub the highlight function to capture arguments
89+
local highlight_stub = stub.new(operations, "highlight")
12290

123-
it("respects highlight_duration config option", function()
124-
local duration = 50
125-
tw.setup({ highlight = true, highlight_duration = duration })
126-
tw.move_out()
91+
vim.fn.cursor(10, 1)
12792
tw.move_down()
128-
tw.move_up()
129-
tw.move_in()
130-
assert.stub(highlight_stub).was.called(4)
93+
94+
-- Verify highlight function was called with default duration (250)
95+
assert.stub(highlight_stub).was.called(1)
13196
local duration_arg = highlight_stub.calls[1].refs[2]
132-
assert.equal(duration, duration_arg)
97+
assert.equal(250, duration_arg)
98+
99+
-- Restore the original function
100+
highlight_stub:revert()
133101
end)
134102

135103
it("respects default highlight_group", function()
136-
tw.setup({ highlight = true, highlight_duration = 250 })
104+
tw.setup({ highlight = true })
105+
106+
vim.fn.cursor(10, 1)
137107
tw.move_down()
138-
local hl_group_arg = highlight_stub.calls[1].refs[3]
139-
assert.equal("CursorLine", hl_group_arg)
108+
109+
-- Verify the highlight uses the default group
110+
local ns_id = vim.api.nvim_create_namespace("treewalker.nvim-movement-highlight")
111+
local highlights = vim.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })
112+
113+
assert.equal(1, #highlights)
114+
assert.equal("CursorLine", highlights[1][4].hl_group)
140115
end)
141116

142117
it("respects highlight_group config option", function()
143-
tw.setup({ highlight = true, highlight_duration = 50, highlight_group = "DiffAdd" })
118+
tw.setup({ highlight = true, highlight_group = "DiffAdd" })
119+
120+
vim.fn.cursor(10, 1)
144121
tw.move_down()
145-
local hl_group_arg = highlight_stub.calls[1].refs[3]
146-
assert.equal("DiffAdd", hl_group_arg)
122+
123+
-- Verify the highlight uses the configured group
124+
local ns_id = vim.api.nvim_create_namespace("treewalker.nvim-movement-highlight")
125+
local highlights = vim.api.nvim_buf_get_extmarks(0, ns_id, 0, -1, { details = true })
126+
127+
assert.equal(1, #highlights)
128+
assert.equal("DiffAdd", highlights[1][4].hl_group)
147129
end)
148130

149131
it("highlights whole functions", function()
150132
vim.fn.cursor(10, 1)
151133
tw.move_down()
152-
h.assert_highlighted(21, 1, 28, 3, highlight_stub, "is_jump_target function")
134+
h.assert_highlighted(21, 1, 28, 3)
153135
end)
154136

155137
it("highlights whole lines starting with identifiers", function()
156138
vim.fn.cursor(134, 5)
157139
tw.move_up()
158-
h.assert_highlighted(133, 5, 133, 33, highlight_stub, "table.insert call")
140+
h.assert_highlighted(133, 5, 133, 33)
159141
end)
160142

161143
it("highlights whole lines starting with assignments", function()
162144
vim.fn.cursor(133, 5)
163145
tw.move_down()
164-
h.assert_highlighted(134, 5, 134, 18, highlight_stub, "child = iter()")
146+
h.assert_highlighted(134, 5, 134, 18)
165147
end)
166148

167149
it("highlights out reliably", function()
168150
vim.fn.cursor(133, 5)
169151
tw.move_out()
170-
h.assert_highlighted(132, 3, 135, 5, highlight_stub, "while child")
152+
h.assert_highlighted(132, 3, 135, 5)
171153
end)
172154

173155
it("highlights out reliably", function()
174156
vim.fn.cursor(132, 3)
175157
tw.move_out()
176-
h.assert_highlighted(128, 1, 137, 3, highlight_stub, "local f get_children")
158+
h.assert_highlighted(128, 1, 137, 3)
177159
end)
178160

179161
it("doesn't highlight the whole file", function()
180162
vim.fn.cursor(3, 1)
181163
tw.move_up()
182-
h.assert_highlighted(1, 1, 1, 39, highlight_stub, "first line")
164+
h.assert_highlighted(1, 1, 1, 39)
183165
end)
184166

185167
-- Note this is highly language dependent, so this test is not so powerful
186168
it("highlights only the first item in a block", function()
187169
vim.fn.cursor(27, 3)
188170
tw.move_up()
189-
h.assert_highlighted(22, 3, 26, 5, highlight_stub, "for _")
171+
h.assert_highlighted(22, 3, 26, 5)
190172
end)
191173

192174
it("given in a line with no parent, move_out highlights the whole node", function()
193175
vim.fn.cursor(21, 16) -- |is_jump_target
194176
tw.move_out()
195177
h.assert_cursor_at(21, 1)
196-
h.assert_highlighted(21, 1, 28, 3, highlight_stub, "is_jump_target function")
178+
h.assert_highlighted(21, 1, 28, 3)
197179
end)
198180
end)
199181

0 commit comments

Comments
 (0)