1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-03 21:50:05 +08:00
SpaceVim/bundle/nui.nvim/tests/nui/popup/init_spec.lua

1131 lines
23 KiB
Lua
Raw Normal View History

2023-05-30 21:09:18 +08:00
pcall(require, "luacov")
local Popup = require("nui.popup")
local event = require("nui.utils.autocmd").event
local h = require("tests.helpers")
local spy = require("luassert.spy")
local eq, feedkeys = h.eq, h.feedkeys
local function percent(number, percentage)
return math.floor(number * percentage / 100)
end
describe("nui.popup", function()
local popup
after_each(function()
if popup then
popup:unmount()
popup = nil
end
end)
it("supports o.bufnr (unmanaed buffer)", function()
local bufnr = vim.api.nvim_create_buf(false, true)
local lines = {
"a",
"b",
"c",
}
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines)
popup = Popup({
bufnr = bufnr,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
h.assert_buf_lines(bufnr, lines)
eq(popup.bufnr, bufnr)
popup:mount()
h.assert_buf_lines(bufnr, lines)
popup:unmount()
eq(popup.bufnr, bufnr)
h.assert_buf_lines(bufnr, lines)
end)
it("accepts number as o.ns_id", function()
local ns = "NuiPopupTest"
local ns_id = vim.api.nvim_create_namespace(ns)
popup = Popup({
ns_id = ns_id,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
eq(popup.ns_id, ns_id)
end)
it("accepts string as o.ns_id", function()
local ns = "NuiPopupTest"
popup = Popup({
ns_id = ns,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
eq(popup.ns_id, vim.api.nvim_create_namespace(ns))
end)
it("uses fallback ns_id if o.ns_id=nil", function()
popup = Popup({
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
eq(type(popup.ns_id), "number")
eq(popup.ns_id > 0, true)
end)
h.describe_flipping_feature("lua_keymap", "method :map", function()
it("works before :mount", function()
local callback = spy.new(function() end)
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:map("n", "l", function()
callback()
end)
popup:mount()
feedkeys("l", "x")
assert.spy(callback).called()
end)
it("works after :mount", function()
local callback = spy.new(function() end)
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:map("n", "l", function()
callback()
end)
feedkeys("l", "x")
assert.spy(callback).called()
end)
it("supports lhs table", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:map("n", { "k", "l" }, "o42<esc>")
feedkeys("k", "x")
feedkeys("l", "x")
h.assert_buf_lines(popup.bufnr, {
"",
"42",
"42",
})
end)
it("supports rhs function", function()
local callback = spy.new(function() end)
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:map("n", "l", function()
callback()
end)
feedkeys("l", "x")
assert.spy(callback).called()
end)
it("supports rhs string", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:map("n", "l", "o42<esc>")
feedkeys("l", "x")
h.assert_buf_lines(popup.bufnr, {
"",
"42",
})
end)
it("supports o.remap=true", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:map("n", "k", "o42<Esc>")
popup:map("n", "l", "k", { remap = true })
feedkeys("k", "x")
feedkeys("l", "x")
h.assert_buf_lines(popup.bufnr, {
"",
"42",
"42",
})
end)
it("supports o.remap=false", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:map("n", "k", "o42<Esc>")
popup:map("n", "l", "k", { remap = false })
feedkeys("k", "x")
feedkeys("l", "x")
h.assert_buf_lines(popup.bufnr, {
"",
"42",
})
end)
it("throws if .bufnr is nil", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup.bufnr = nil
local ok, result = pcall(function()
popup:map("n", "l", function() end)
end)
eq(ok, false)
eq(type(string.match(result, "buffer not found")), "string")
end)
end)
h.describe_flipping_feature("lua_keymap", "method :unmap", function()
it("works before :mount", function()
local callback = spy.new(function() end)
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:map("n", "l", function()
callback()
end)
popup:unmap("n", "l")
popup:mount()
feedkeys("l", "x")
assert.spy(callback).not_called()
end)
it("works after :mount", function()
local callback = spy.new(function() end)
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:map("n", "l", function()
callback()
end)
popup:unmap("n", "l")
feedkeys("l", "x")
assert.spy(callback).not_called()
end)
it("supports lhs string", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:map("n", "l", "o42<esc>")
popup:unmap("n", "l")
feedkeys("l", "x")
h.assert_buf_lines(popup.bufnr, {
"",
})
end)
it("supports lhs table", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:map("n", "k", "o42<esc>")
popup:map("n", "l", "o42<esc>")
popup:unmap("n", { "k", "l" })
feedkeys("k", "x")
feedkeys("l", "x")
h.assert_buf_lines(popup.bufnr, {
"",
})
end)
it("throws if .bufnr is nil", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup.bufnr = nil
local ok, result = pcall(function()
popup:unmap("n", "l")
end)
eq(ok, false)
eq(type(string.match(result, "buffer not found")), "string")
end)
end)
h.describe_flipping_feature("lua_autocmd", "method :on", function()
it("works before :mount", function()
local callback = spy.new(function() end)
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:on(event.InsertEnter, function()
callback()
end)
popup:mount()
feedkeys("i", "x")
feedkeys("<esc>", "x")
assert.spy(callback).called()
end)
it("works after :mount", function()
local callback = spy.new(function() end)
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:on(event.InsertEnter, function()
callback()
end)
feedkeys("i", "x")
feedkeys("<esc>", "x")
assert.spy(callback).called()
end)
it("throws if .bufnr is nil", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup.bufnr = nil
local ok, result = pcall(function()
popup:on(event.InsertEnter, function() end)
end)
eq(ok, false)
eq(type(string.match(result, "buffer not found")), "string")
end)
end)
h.describe_flipping_feature("lua_autocmd", "method :off", function()
it("works before :mount", function()
local callback = spy.new(function() end)
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:on(event.InsertEnter, function()
callback()
end)
popup:off(event.InsertEnter)
popup:mount()
feedkeys("i", "x")
feedkeys("<esc>", "x")
assert.spy(callback).not_called()
end)
it("works after :mount", function()
local callback = spy.new(function() end)
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup:mount()
popup:on(event.InsertEnter, function()
callback()
end)
popup:off(event.InsertEnter)
feedkeys("i", "x")
feedkeys("<esc>", "x")
assert.spy(callback).not_called()
end)
it("throws if .bufnr is nil", function()
popup = Popup({
enter = true,
position = "50%",
size = {
height = "60%",
width = "80%",
},
})
popup.bufnr = nil
local ok, result = pcall(function()
popup:off()
end)
eq(ok, false)
eq(type(string.match(result, "buffer not found")), "string")
end)
end)
describe("method :update_layout", function()
local function assert_size(size, border_size)
if border_size and type(border_size) ~= "table" then
border_size = {
width = size.width + 2,
height = size.height + 2,
}
end
local win_config = vim.api.nvim_win_get_config(popup.winid)
eq(win_config.width, size.width)
eq(win_config.height, size.height)
if popup.border.winid then
local border_win_config = vim.api.nvim_win_get_config(popup.border.winid)
eq(border_win_config.width, border_size.width)
eq(border_win_config.height, border_size.height)
end
end
local function assert_position(position, container_winid)
container_winid = container_winid or vim.api.nvim_get_current_win()
local win_config = vim.api.nvim_win_get_config(popup.winid)
eq(win_config.win, popup.border.winid or container_winid)
local row, col = win_config.row[vim.val_idx], win_config.col[vim.val_idx]
if popup.border.winid then
eq(row, 1)
eq(col, 1)
local border_win_config = vim.api.nvim_win_get_config(popup.border.winid)
local border_row, border_col = border_win_config.row[vim.val_idx], border_win_config.col[vim.val_idx]
local border_width, border_height = border_win_config.width, border_win_config.height
local delta_width = border_width - win_config.width
local delta_height = border_height - win_config.height
eq(border_row + math.floor(delta_height / 2 + 0.5), position.row)
eq(border_col + math.floor(delta_width / 2 + 0.5), position.col)
else
eq(row, position.row)
eq(col, position.col)
end
end
it("can change size (w/ simple border)", function()
local size = {
width = 2,
height = 1,
}
popup = Popup({
position = "50%",
size = size,
})
popup:mount()
eq(type(popup.border.winid), "nil")
assert_size(size)
local new_size = {
width = size.width + 2,
height = size.height + 2,
}
popup:update_layout({ size = new_size })
assert_size(new_size)
end)
it("can change size (w/ complex border)", function()
local hl_group = "NuiPopupTest"
local style = h.popup.create_border_style_map_with_tuple(hl_group)
local size = {
width = 2,
height = 1,
}
popup = Popup({
ns_id = vim.api.nvim_create_namespace("NuiTest"),
border = {
style = style,
padding = { 0 },
},
position = "50%",
size = size,
})
popup:mount()
eq(type(popup.border.winid), "number")
assert_size(size, true)
h.popup.assert_border_lines({
size = size,
border = { style = style },
}, popup.border.bufnr)
h.popup.assert_border_highlight({
size = size,
ns_id = popup.ns_id,
}, popup.border.bufnr, hl_group)
local new_size = {
width = size.width + 2,
height = size.height + 2,
}
popup:update_layout({ size = new_size })
assert_size(new_size, true)
h.popup.assert_border_lines({
size = new_size,
border = { style = style },
}, popup.border.bufnr)
h.popup.assert_border_highlight({
size = new_size,
ns_id = popup.ns_id,
}, popup.border.bufnr, hl_group)
end)
it("can change position (w/ simple border)", function()
local position = {
row = 0,
col = 0,
}
popup = Popup({
position = position,
size = {
width = 4,
height = 2,
},
})
popup:mount()
eq(type(popup.border.winid), "nil")
assert_position(position)
local new_position = {
row = position.row + 2,
col = position.col + 2,
}
popup:update_layout({ position = new_position })
assert_position(new_position)
end)
it("can change position (w/ complex border)", function()
local hl_group = "NuiPopupTest"
local style = h.popup.create_border_style_map_with_tuple(hl_group)
local position = {
row = 0,
col = 0,
}
popup = Popup({
ns_id = vim.api.nvim_create_namespace("NuiTest"),
border = {
style = style,
padding = { 0 },
},
position = position,
size = {
width = 4,
height = 2,
},
})
popup:mount()
eq(type(popup.border.winid), "number")
assert_position(position)
local new_position = {
row = position.row + 2,
col = position.col + 2,
}
popup:update_layout({ position = new_position })
assert_position(new_position)
end)
it("refreshes layout if container size changes", function()
local container_size = {
width = 20,
height = 10,
}
local container_popup = Popup({
position = 0,
size = container_size,
})
container_popup:mount()
popup = Popup({
relative = {
type = "win",
winid = container_popup.winid,
},
position = "20%",
size = "50%",
})
popup:mount()
assert_size({
width = percent(container_size.width, 50),
height = percent(container_size.height, 50),
})
assert_position({
row = percent(container_size.height - percent(container_size.height, 50), 20),
col = percent(container_size.width - percent(container_size.width, 50), 20),
}, container_popup.winid)
container_size = {
width = 16,
height = 8,
}
container_popup:update_layout({
size = container_size,
})
popup:update_layout()
assert_size({
width = percent(container_size.width, 50),
height = percent(container_size.height, 50),
})
assert_position({
row = percent(container_size.height - percent(container_size.height, 50), 20),
col = percent(container_size.width - percent(container_size.width, 50), 20),
}, container_popup.winid)
end)
it("throws if missing config 'relative'", function()
popup = Popup({})
local ok, result = pcall(function()
popup:update_layout({})
end)
eq(ok, false)
eq(type(string.match(result, "missing layout config: relative")), "string")
end)
it("throws if missing config 'size'", function()
popup = Popup({})
local ok, result = pcall(function()
popup:update_layout({
relative = "win",
})
end)
eq(ok, false)
eq(type(string.match(result, "missing layout config: size")), "string")
end)
it("throws if missing config 'position'", function()
popup = Popup({})
local ok, result = pcall(function()
popup:update_layout({
relative = "win",
size = "50%",
})
end)
eq(ok, false)
eq(type(string.match(result, "missing layout config: position")), "string")
end)
end)
describe("method :mount", function()
it("throws if layout is not ready", function()
popup = Popup({})
local ok, result = pcall(function()
popup:mount()
end)
eq(ok, false)
eq(type(string.match(result, "layout is not ready")), "string")
end)
it("is idempotent", function()
popup = Popup({
position = 0,
size = 10,
})
local border_mount = spy.on(popup.border, "mount")
popup:mount()
local bufnr, winid = popup.bufnr, popup.winid
eq(type(bufnr), "number")
eq(type(winid), "number")
assert.spy(border_mount).was_called(1)
popup:mount()
eq(bufnr, popup.bufnr)
eq(winid, popup.winid)
assert.spy(border_mount).was_called(1)
end)
end)
h.describe_flipping_feature("lua_autocmd", "method :unmount", function()
it("is called when quitted", function()
popup = Popup({
position = 0,
size = 10,
})
local popup_unmount = spy.on(popup, "unmount")
popup:mount()
vim.api.nvim_buf_call(popup.bufnr, function()
vim.cmd([[quit]])
end)
vim.wait(100, function()
return not popup._.mounted
end, 10)
assert.spy(popup_unmount).was_called()
end)
end)
h.describe_flipping_feature("lua_autocmd", "method :hide", function()
it("works", function()
popup = Popup({
position = 0,
size = 10,
})
popup:mount()
vim.api.nvim_buf_set_lines(popup.bufnr, 0, -1, false, {
"42",
})
eq(type(popup.bufnr), "number")
eq(type(popup.winid), "number")
popup:hide()
eq(type(popup.bufnr), "number")
eq(type(popup.winid), "nil")
h.assert_buf_lines(popup.bufnr, {
"42",
})
end)
it("is idempotent", function()
popup = Popup({
position = 0,
size = 10,
})
popup:mount()
local prev_winids = vim.api.nvim_list_wins()
popup:hide()
local curr_winids = vim.api.nvim_list_wins()
eq(#prev_winids, #curr_winids + 1)
popup:hide()
eq(#curr_winids, #vim.api.nvim_list_wins())
end)
it("does nothing if not mounted", function()
popup = Popup({
position = 0,
size = 10,
})
local prev_winids = vim.api.nvim_list_wins()
popup:hide()
local curr_winids = vim.api.nvim_list_wins()
eq(#prev_winids, #curr_winids)
end)
it("is called when window is closed", function()
popup = Popup({
position = 0,
size = 10,
})
local popup_hide = spy.on(popup, "hide")
popup:mount()
vim.api.nvim_buf_call(popup.bufnr, function()
vim.cmd([[:bdelete]])
end)
assert.spy(popup_hide).was_called()
end)
it("is not called when other popup using same buffer is hidden", function()
popup = Popup({
position = 0,
size = 10,
})
local another_popup = Popup({
bufnr = popup.bufnr,
position = 11,
size = 5,
})
local popup_hide = spy.on(popup, "hide")
popup:mount()
another_popup:mount()
another_popup:hide()
assert.spy(popup_hide).was_not_called()
another_popup:unmount()
end)
end)
h.describe_flipping_feature("lua_autocmd", "method :show", function()
it("works", function()
popup = Popup({
position = 0,
size = 10,
})
popup:mount()
vim.api.nvim_buf_set_lines(popup.bufnr, 0, -1, false, {
"42",
})
local bufnr, winid = popup.bufnr, popup.winid
eq(type(bufnr), "number")
eq(type(winid), "number")
popup:hide()
popup:show()
eq(bufnr, popup.bufnr)
eq(type(popup.winid), "number")
eq(winid ~= popup.winid, true)
h.assert_buf_lines(popup.bufnr, {
"42",
})
end)
it("is idempotent", function()
popup = Popup({
position = 0,
size = 10,
})
popup:mount()
popup:hide()
local prev_winids = vim.api.nvim_list_wins()
popup:show()
local curr_winids = vim.api.nvim_list_wins()
eq(#prev_winids + 1, #curr_winids)
popup:show()
eq(#curr_winids, #vim.api.nvim_list_wins())
end)
it("does nothing if not mounted", function()
popup = Popup({
position = 0,
size = 10,
})
local prev_winids = vim.api.nvim_list_wins()
popup:show()
local curr_winids = vim.api.nvim_list_wins()
eq(#prev_winids, #curr_winids)
end)
it("does nothing if not hidden", function()
popup = Popup({
position = 0,
size = 10,
})
popup:mount()
local prev_winids = vim.api.nvim_list_wins()
popup:show()
local curr_winids = vim.api.nvim_list_wins()
eq(#prev_winids, #curr_winids)
end)
it("can show popups using the same buffer", function()
popup = Popup({
position = 0,
size = 10,
})
vim.api.nvim_buf_set_lines(popup.bufnr, 0, -1, false, {
"42",
})
local another_popup = Popup({
bufnr = popup.bufnr,
position = 11,
size = 5,
})
popup:mount()
another_popup:mount()
local bufnr, winid = popup.bufnr, popup.winid
eq(type(bufnr), "number")
eq(type(winid), "number")
local another_bufnr, another_winid = another_popup.bufnr, another_popup.winid
eq(type(another_bufnr), "number")
eq(type(another_winid), "number")
eq(bufnr, another_bufnr)
popup:hide()
another_popup:hide()
popup:show()
another_popup:show()
eq(bufnr, popup.bufnr)
eq(type(popup.winid), "number")
eq(winid ~= popup.winid, true)
eq(another_bufnr, another_popup.bufnr)
eq(type(another_popup.winid), "number")
eq(another_winid ~= another_popup.winid, true)
h.assert_buf_lines(bufnr, {
"42",
})
end)
end)
end)