refactor: extract helpers, dedup patterns, add regression tests

Mechanical cleanup pass, behavior-preserving:
- remove dead code: reposition_bars (unused), sbar click infrastructure
  (zones never populated, handler iterated empty list)
- extract helpers in mode.lua: win_ok, buf_ok, is_dapui_pane_ft,
  for_each_dapui_pane (asymmetric filter preserved), safe_extmark,
  bar_set_lines, safe_set_height, if_still_active, invalidate_dead_bars,
  focus_source_win, unset_and_restore
- inline install_cs_listener inside define_highlights to dedup the three
  ColorScheme augroup+autocmd triples (italic, key, sep)
- data-drive sign_define in breakpoints.lua
- data-drive python interpreter candidate probing
- add tests/test_render_bars.lua pinning sbar/cbar output dimensions,
  zones, and overflow fallback behavior
- add tests/test_highlights_cs.lua verifying ColorScheme augroups and
  highlight group existence / re-apply on event
- add tests/test_helpers.lua unit-testing keyof and source_window
- expose M._test (direct function refs) so render/highlight internals are
  testable in headless mode
This commit is contained in:
swaits committed 2026-04-12 19:42:54 -06:00
1 parent 7a21d372ff
commit 85ff3b1688
7 files changed
+414 -164

No files matched your search

+12
View File
@@ -6,4 +6,16 @@ function M.assert_eq(a, b, msg)
end
end
function M.assert_true(v, msg)
if not v then
error(string.format("FAIL: %s — expected truthy, got %s", msg, vim.inspect(v)))
end
end
function M.assert_false(v, msg)
if v then
error(string.format("FAIL: %s — expected falsy, got %s", msg, vim.inspect(v)))
end
end
return M
+49
View File
@@ -0,0 +1,49 @@
-- Unit tests for the helpers introduced during cleanup refactor.
-- Exercises helpers indirectly via observable side effects on bar/pane state.
local h = require("helpers")
local assert_eq = h.assert_eq
local assert_true = h.assert_true
local assert_false = h.assert_false
local mode = require("turbo-debug.mode")
local config = require("turbo-debug.config")
config.merge({})
-- keyof ---------------------------------------------------------------------
-- Reset, then exercise the three return paths.
config.merge({})
assert_eq(mode._test.keyof("continue", "c"), "c", "default key")
config.merge({ keys = { continue = "n" } })
assert_eq(mode._test.keyof("continue", "c"), "n", "user override")
config.merge({ keys = { continue = false } })
assert_eq(mode._test.keyof("continue", "c"), nil, "disabled returns nil")
config.merge({})
-- source_window -------------------------------------------------------------
-- Skips bars/dapui-panes; returns a source window when one exists.
do
local buf = vim.api.nvim_create_buf(false, true)
vim.bo[buf].filetype = "lua"
vim.api.nvim_set_current_buf(buf)
local w = mode._test.source_window()
assert_true(w ~= nil, "source_window finds lua buffer")
end
do
-- Switch current to a dapui-pane filetype; source_window should still
-- find another source window if one exists.
local buf = vim.api.nvim_create_buf(false, true)
vim.bo[buf].filetype = "dapui_scopes"
vim.cmd("split")
vim.api.nvim_set_current_buf(buf)
local w = mode._test.source_window()
if w then
local ft = vim.bo[vim.api.nvim_win_get_buf(w)].filetype
assert_false(ft:match("^dapui_"), "source_window skips dapui_* filetypes")
assert_true(ft ~= "dap-repl", "source_window skips dap-repl")
assert_true(ft ~= "TurboDebugBar", "source_window skips TurboDebugBar")
end
end
print("ALL HELPER TESTS PASSED")
+40
View File
@@ -0,0 +1,40 @@
local h = require("helpers")
local assert_eq = h.assert_eq
local assert_true = h.assert_true
local mode = require("turbo-debug.mode")
local config = require("turbo-debug.config")
config.merge({})
-- Invoke define_highlights via the _test hook.
mode._test.define_highlights()
-- The three ColorScheme augroups must exist with at least one autocmd each.
local function group_has_colorscheme_autocmd(group_name)
local ok, autocmds = pcall(vim.api.nvim_get_autocmds, { group = group_name, event = "ColorScheme" })
return ok and autocmds and #autocmds >= 1
end
assert_true(group_has_colorscheme_autocmd("TurboDebugBarItalicHL"), "italic augroup has ColorScheme autocmd")
assert_true(group_has_colorscheme_autocmd("TurboDebugBarKeyHL"), "key augroup has ColorScheme autocmd")
assert_true(group_has_colorscheme_autocmd("TurboDebugBarSepHL"), "sep augroup has ColorScheme autocmd")
-- The highlight groups must exist after define_highlights.
local function hl_exists(name)
local ok, hl = pcall(vim.api.nvim_get_hl, 0, { name = name })
return ok and hl ~= nil and next(hl) ~= nil
end
assert_true(hl_exists("TurboDebugBarItalic"), "TurboDebugBarItalic exists")
assert_true(hl_exists("TurboDebugBarKey"), "TurboDebugBarKey exists")
assert_true(hl_exists("TurboDebugBarSeparator"), "TurboDebugBarSeparator exists")
assert_true(hl_exists("TurboDebugBar"), "TurboDebugBar exists")
assert_true(hl_exists("TurboDebugBarBrand"), "TurboDebugBarBrand exists")
-- Fire ColorScheme event; the callbacks should re-apply highlights (idempotent).
vim.cmd("doautocmd ColorScheme")
assert_true(hl_exists("TurboDebugBarItalic"), "TurboDebugBarItalic still exists after ColorScheme")
assert_true(hl_exists("TurboDebugBarKey"), "TurboDebugBarKey still exists after ColorScheme")
assert_true(hl_exists("TurboDebugBarSeparator"), "TurboDebugBarSeparator still exists after ColorScheme")
print("ALL HIGHLIGHT CS TESTS PASSED")
+147
View File
@@ -0,0 +1,147 @@
local h = require("helpers")
local assert_eq = h.assert_eq
local assert_true = h.assert_true
local assert_false = h.assert_false
local mode = require("turbo-debug.mode")
local config = require("turbo-debug.config")
-- Ensure config is initialized with defaults so keyof/render_cbar can read it
config.merge({})
-- Helpers --------------------------------------------------------------------
local function make_bar_win()
vim.cmd("noautocmd keepalt topleft split")
local win = vim.api.nvim_get_current_win()
local buf = vim.api.nvim_create_buf(false, true)
vim.api.nvim_win_set_buf(win, buf)
vim.api.nvim_win_set_height(win, 2)
return win, buf
end
local function cleanup(win)
if win and vim.api.nvim_win_is_valid(win) then
pcall(vim.api.nvim_win_close, win, true)
end
end
local function line(buf, i)
return vim.api.nvim_buf_get_lines(buf, i, i + 1, false)[1] or ""
end
-- build_control_text -------------------------------------------------------
-- Inline form when key matches first letter case-insensitively.
local text, kcol, kend, icol, iend = mode._test.build_control_text(">", "s", "step", "over")
assert_true(text:find("%(s%)tep") ~= nil, "inline form: (s)tep present")
assert_true(kcol < kend, "inline form: key_col < key_end_col")
assert_true(icol ~= nil and iend ~= nil, "inline form: italic span present")
assert_true(text:sub(icol + 1, iend) == "over", "inline form: italic text is 'over'")
-- Prefix form when key does NOT match first letter.
local text2, _, _, icol2 = mode._test.build_control_text(">", "n", "step", "over")
assert_true(text2:find("%(n%) step") ~= nil, "prefix form: (n) step present")
assert_true(icol2 ~= nil, "prefix form: italic still rendered")
-- No italic when italic param is nil.
local text3, _, _, icol3 = mode._test.build_control_text(">", "c", "continue", nil)
assert_eq(icol3, nil, "no italic span when italic=nil")
assert_true(text3:find("%(c%)ontinue") ~= nil, "no italic: (c)ontinue rendered")
-- keyof ----------------------------------------------------------------------
-- Save any user override then reset to defaults
config.merge({})
assert_eq(mode._test.keyof("continue", "c"), "c", "keyof returns default when unset")
-- Disabled action returns nil
config.merge({ keys = { continue = false } })
assert_eq(mode._test.keyof("continue", "c"), nil, "keyof returns nil when key=false")
-- User override
config.merge({ keys = { continue = "g" } })
assert_eq(mode._test.keyof("continue", "c"), "g", "keyof returns user override")
-- Empty string falls back to default
config.merge({ keys = { continue = "" } })
assert_eq(mode._test.keyof("continue", "c"), "c", "keyof falls back on empty string")
-- Reset config to defaults for subsequent render tests
config.merge({})
-- render_sbar ----------------------------------------------------------------
do
local win, buf = make_bar_win()
mode._test.set_bars(win, buf, nil, nil)
mode._test.render_sbar()
local count = vim.api.nvim_buf_line_count(buf)
assert_eq(count, 2, "sbar has exactly 2 lines")
local sep = line(buf, 0)
local content = line(buf, 1)
assert_true(#sep > 0, "sbar separator non-empty")
assert_true(content:find(" turbo%-debug ") ~= nil, "sbar contains brand text")
assert_true(content:find("DEBUG") ~= nil, "sbar contains DEBUG chip")
-- sbar has no click zones
local zones = mode._test.get_sbar_zones()
assert_eq(#zones, 0, "sbar has zero click zones")
mode._test.set_bars(nil, nil, nil, nil)
cleanup(win)
end
-- render_cbar ----------------------------------------------------------------
do
local win, buf = make_bar_win()
vim.api.nvim_win_set_width(win, 120)
mode._test.set_bars(nil, nil, win, buf)
mode._test.render_cbar()
local count = vim.api.nvim_buf_line_count(buf)
assert_eq(count, 2, "cbar has exactly 2 lines")
local content = line(buf, 0)
local sep = line(buf, 1)
assert_true(#sep > 0, "cbar separator non-empty")
assert_true(content:find(" help ") ~= nil, "cbar contains 'help' text")
-- Click zones: at least 5 controls (continue, step_over, step_into, step_out, terminate) + 1 help
-- When no session, restart is hidden so zone count = 5 + 1 = 6.
local zones = mode._test.get_cbar_zones()
assert_true(#zones >= 6, "cbar has at least 6 click zones: " .. #zones)
mode._test.set_bars(nil, nil, nil, nil)
cleanup(win)
end
-- overflow fallback: at narrow widths, italic qualifiers are dropped
do
local win, buf = make_bar_win()
vim.api.nvim_win_set_width(win, 25)
mode._test.set_bars(nil, nil, win, buf)
mode._test.render_cbar()
local content = line(buf, 0)
-- italic qualifiers are "over", "into", "out" — on overflow they're omitted.
-- At width 25 with 5+ controls, there's no way they all fit with italics.
assert_false(content:find(" over ") or content:find(" into ") or content:find(" out "),
"overflow: italic qualifiers absent at narrow width")
mode._test.set_bars(nil, nil, nil, nil)
cleanup(win)
end
-- disabling step_over reduces zone count
do
local win, buf = make_bar_win()
vim.api.nvim_win_set_width(win, 120)
mode._test.set_bars(nil, nil, win, buf)
mode._test.render_cbar()
local default_count = #mode._test.get_cbar_zones()
config.merge({ keys = { step_over = false } })
mode._test.render_cbar()
local disabled_count = #mode._test.get_cbar_zones()
assert_eq(disabled_count, default_count - 1, "disabling step_over drops one zone")
config.merge({}) -- reset
mode._test.set_bars(nil, nil, nil, nil)
cleanup(win)
end
print("ALL RENDER BAR TESTS PASSED")