From 20ce93335e86970a8759812a8d0cd4a499ee80dd Mon Sep 17 00:00:00 2001 From: Rishikesh Vaishnav Date: Sun, 25 Jul 2021 11:21:06 -0700 Subject: [PATCH] Make testing more general/complete. --- lua/lean/infoview.lua | 4 +- lua/tests/helpers.lua | 327 +++++++++++++++----------- lua/tests/infoview/autoopen_spec.lua | 8 +- lua/tests/infoview/close_all_spec.lua | 101 ++++---- lua/tests/infoview/run_spec.lua | 14 +- lua/tests/infoview/start_spec.lua | 2 +- 6 files changed, 258 insertions(+), 198 deletions(-) diff --git a/lua/lean/infoview.lua b/lua/lean/infoview.lua index 5e7d189c..f930f5d1 100644 --- a/lua/lean/infoview.lua +++ b/lua/lean/infoview.lua @@ -184,11 +184,9 @@ function Infoview:is_empty() end --- Close all open infoviews (across all tabs). -function infoview.close_all(pre_close_hook, post_close_hook) +function infoview.close_all() for _, each in pairs(infoview._by_id) do - if pre_close_hook then pre_close_hook(each) end each:close() - if post_close_hook then post_close_hook(each) end end end diff --git a/lua/tests/helpers.lua b/lua/tests/helpers.lua index 7d111008..3ffff2cc 100644 --- a/lua/tests/helpers.lua +++ b/lua/tests/helpers.lua @@ -96,14 +96,6 @@ function helpers.wait_for_line_diagnostics() assert.message("Waited for line diagnostics but none came.").True(succeeded) end ---- The number of current windows. -function helpers.get_num_wins() return #vim.api.nvim_list_wins() end - -local last_num_wins - -local function set_num_wins() last_num_wins = helpers.get_num_wins() end -set_num_wins() - --- Assert about the entire buffer contents. local function has_buf_contents(_, arguments) local buf = table.concat(vim.api.nvim_buf_get_lines(0, 0, -1, false), '\n') @@ -122,161 +114,226 @@ local function has_all(_, arguments) return true end -local prev_buf_max = -1 -local prev_win_max = -1 -local prev_buf -local prev_win - -local function change_infoview(state, _) - local this_infoview = infoview.get_current_infoview() - local buf = this_infoview.bufnr - local win = this_infoview.window - local result = - ((not buf and not this_infoview.is_open) or (buf and prev_buf ~= buf and this_infoview.is_open - and vim.api.nvim_buf_is_valid(buf))) and - ((not win and not this_infoview.is_open) or (win and prev_win ~= win and this_infoview.is_open - and vim.api.nvim_win_is_valid(win))) and - helpers.get_num_wins() == last_num_wins - prev_buf = buf - prev_win = win - state.failure_message = table.concat({ - "Failed to change: ", - ("prev_buf: %s, buf: %s, buf valid: %s"):format(vim.inspect(prev_buf), vim.inspect(buf), - vim.inspect(buf and vim.api.nvim_buf_is_valid(buf))), - ("prev_win: %s, win: %s, win valid: %s"):format(vim.inspect(prev_win), vim.inspect(win), - vim.inspect(win and vim.api.nvim_win_is_valid(win))), - "is_open: " .. vim.inspect(this_infoview.is_open), - ("num_wins: %d, last_num_wins: %d"):format(helpers.get_num_wins(), last_num_wins) - }, "\n") - - return result +--- The number of current windows. +function helpers.get_num_wins() return #vim.api.nvim_list_wins() end + +local last_wins = {} +local last_win = nil +local last_win_max = -1 + +local function get_wins() + local wins = {} + for _, win in pairs(vim.api.nvim_list_wins()) do + wins[win] = true + end + + return wins end -local function opened_infoview(failure_message, maintain) - local result - local this_infoview = infoview.get_current_infoview() - - local buf = this_infoview.bufnr - local win = this_infoview.window - - vim.list_extend(failure_message, - { - "Failed to open: ", - "maintain: " .. vim.inspect(maintain), - ("prev_buf_max: %s, buf: %s, prev_buf: %s, buf valid: %s"):format(vim.inspect(prev_buf_max), - vim.inspect(buf), vim.inspect(prev_buf), - vim.inspect(buf and vim.api.nvim_buf_is_valid(buf))), - ("prev_win_max: %s, win: %s, prev_win: %s, win valid: %s"):format(vim.inspect(prev_win_max), - vim.inspect(win), vim.inspect(prev_win), - vim.inspect(win and vim.api.nvim_win_is_valid(win))), - "is_open: " .. vim.inspect(this_infoview.is_open), - ("num_wins: %d, last_num_wins: %d"):format(helpers.get_num_wins(), last_num_wins) - }) - if maintain then - result = this_infoview.is_open and - buf and prev_buf == buf and vim.api.nvim_buf_is_valid(buf) and - win and prev_win == win and vim.api.nvim_win_is_valid(win) and - helpers.get_num_wins() == last_num_wins - else - -- make sure this is a brand new buffer/window - result = this_infoview.is_open and - prev_buf_max < buf and vim.api.nvim_buf_is_valid(buf) and - prev_win_max < win and vim.api.nvim_win_is_valid(win) and - helpers.get_num_wins() == last_num_wins + 1 - prev_buf_max = buf - prev_win_max = win +local function update_wins(_, arguments) + -- inductive hypothesis: last_wins is accurate to immediately before creating/closing any of the given windows + local expected_wins = vim.deepcopy(last_wins) + + local opened_wins = arguments[1] or {} + local closed_wins = arguments[2] or {} + + -- for ensuring no collisions + local opened_win_set = {} + + for _, opened_win in pairs(opened_wins) do + -- should be an actual window + assert.is_truthy(vim.api.nvim_win_is_valid(opened_win)) + + -- should be brand new + assert.is_truthy(opened_win > last_win_max) + assert.is_falsy(opened_win_set[opened_win]) + + expected_wins[opened_win] = true + opened_win_set[opened_win] = true + end + + for _, closed_win in pairs(closed_wins) do + -- should not be a window + assert.is_falsy(vim.api.nvim_win_is_valid(closed_win)) + + -- should have previously existed (should not pass a random previously/never closed window) + assert.is_truthy(expected_wins[closed_win]) + + expected_wins[closed_win] = nil + end + + assert.message("expected: " .. vim.inspect(expected_wins) .. "\n got: " .. vim.inspect(get_wins())).is_truthy( + vim.deep_equal(expected_wins, get_wins())) + + for _, opened_win in pairs(opened_wins) do + if opened_win > last_win_max then last_win_max = opened_win end end - prev_buf = buf - prev_win = win + -- maintain IH + last_wins = get_wins() - return result + -- also maintain IH for closed_win + last_win = vim.api.nvim_get_current_win() + + return true end -local function closed_infoview(failure_message, maintain, unopened) - local result - local this_infoview = infoview.get_current_infoview() - - local buf = this_infoview.bufnr - local win = this_infoview.window - - vim.list_extend(failure_message, - { - "Failed to close: ", - "maintain: " .. vim.inspect(maintain), - ("buf: %s, prev_buf: %s, buf valid: %s"):format(vim.inspect(buf), vim.inspect(prev_buf), - prev_buf and vim.inspect(vim.api.nvim_buf_is_valid(prev_buf))), - ("win: %s, prev_win: %s, win valid: %s"):format(vim.inspect(win), vim.inspect(prev_win), - prev_win and vim.inspect(vim.api.nvim_win_is_valid(prev_win))), - "is_open: " .. vim.inspect(this_infoview.is_open), - ("num_wins: %d, last_num_wins: %d"):format(helpers.get_num_wins(), last_num_wins) - }) - if maintain then - result = not buf and not win and not prev_win and not prev_buf and not this_infoview.is_open - and helpers.get_num_wins() == last_num_wins +local function created_win(_, arguments) + local new_wins = arguments[1] + if new_wins then + assert.update_wins(arguments[1], nil) else - vim.list_extend(failure_message, {"unopened: " .. vim.inspect(unopened)}) - if unopened then - -- if not previously opened, we don't care about prev_win or prev_buf being accurate - result = not buf and not win and not this_infoview.is_open - and helpers.get_num_wins() == last_num_wins - else - -- make sure the previous window was closed - result = not this_infoview.is_open and not buf and not win and - prev_buf and not vim.api.nvim_buf_is_valid(prev_buf) and - prev_win and not vim.api.nvim_win_is_valid(prev_win) and - helpers.get_num_wins() == last_num_wins - 1 - end + assert.changed_win() + assert.update_wins({vim.api.nvim_get_current_win()}, nil) end - prev_buf = buf - prev_win = win + return true +end - return result +local function closed_win(_, arguments) + local closed_wins = arguments[1] + if closed_wins then + assert.update_wins(nil, arguments[1]) + else + -- inductive hypothesis: in addition to that of update_wins, + -- last_win must be the window we were in immediately before closing + assert.changed_win() + assert.update_wins(nil, {last_win}) + end + + return true +end + +local function changed_win(_, _) + -- no nested assertion to allow for negation + return last_win ~= vim.api.nvim_get_current_win() +end + + +local function opened_infoview(_, arguments) + local this_info = arguments[1] + + assert.is_truthy(this_info.is_open) + assert.is_truthy(this_info.bufnr) + assert.is_truthy(this_info.window) + assert.is_falsy(this_info.prev_buf) + assert.is_falsy(this_info.prev_win) + + return true +end + +local function opened_infoview_kept(_, arguments) + local this_info = arguments[1] + + assert.is_truthy(this_info.is_open) + assert.is_truthy(this_info.bufnr) + assert.is_truthy(this_info.window) + assert.is_truthy(this_info.bufnr == this_info.prev_buf) + assert.is_truthy(this_info.window == this_info.prev_win) + + return true end -local function close_win() - local result = helpers.get_num_wins() == last_num_wins - 1 - set_num_wins() - return result +local function closed_infoview(_, arguments) + local this_info = arguments[1] + + assert.is_falsy(this_info.is_open) + assert.is_falsy(this_info.bufnr) + assert.is_falsy(this_info.window) + assert.is_truthy(this_info.prev_buf) + assert.is_truthy(this_info.prev_win) + + return true end -local function new_win() - local result = helpers.get_num_wins() == last_num_wins + 1 - set_num_wins() - return result +local function closed_infoview_kept(_, arguments) + local this_info = arguments[1] + + assert.is_falsy(this_info.is_open) + assert.is_falsy(this_info.bufnr) + assert.is_falsy(this_info.window) + assert.is_falsy(this_info.prev_buf) + assert.is_falsy(this_info.prev_win) + + return true end -local function infoview_check(state, checker, ...) - local failure_message = {} +local function infoview_check(list) + local opened_wins = {} + local closed_wins = {} + + for _, id in pairs(vim.api.nvim_list_tabpages()) do + local check = list[id] + + local this_info = infoview._by_id[id] + + -- infer check + if not check then + if this_info.prev_check == "opened" then + check = "opened_kept" + elseif this_info.prev_check == "opened_kept" then + check = "opened_kept" + elseif this_info.prev_check == "closed" then + check = "closed_kept" + elseif this_info.prev_check == "closed_kept" then + check = "closed_kept" + end + end - local result = checker(failure_message, ...) + if check == "opened" then + vim.list_extend(opened_wins, {this_info.window}) + assert.opened_infoview_state(this_info) + elseif check == "opened_kept" then + assert.opened_infoview_kept_state(this_info) + elseif check == "closed" then + vim.list_extend(closed_wins, {this_info.prev_win}) + assert.closed_infoview_state(this_info) + elseif check == "closed_kept" then + assert.closed_infoview_kept_state(this_info) + end - state.failure_message = table.concat(failure_message, "\n") + this_info.prev_buf = this_info.bufnr + this_info.prev_win = this_info.window + this_info.prev_check = check + end - set_num_wins() + assert.update_wins(opened_wins, closed_wins) - return result + return true end assert:register("assertion", "has_all", has_all) -assert:register("assertion", "opened_infoview", function(state, _) - return infoview_check(state, opened_infoview, false) +assert:register("assertion", "updated_infoviews", function(_, arguments) + return infoview_check(arguments[1] or {}) +end) +assert:register("assertion", "opened_infoview", function(_, arguments) + return infoview_check(arguments[1] or {[vim.api.nvim_win_get_tabpage(0)] = "opened"}) end) -assert:register("assertion", "opened_infoview_kept", function(state, _) - return infoview_check(state, opened_infoview, true) +assert:register("assertion", "opened_infoview_kept", function(_, arguments) + return infoview_check(arguments[1] or {[vim.api.nvim_win_get_tabpage(0)] = "opened_kept"}) end) -assert:register("assertion", "closed_infoview", function(state, _) - return infoview_check(state, closed_infoview, false, false) +assert:register("assertion", "closed_infoview", function(_, arguments) + return infoview_check(arguments[1] or {[vim.api.nvim_win_get_tabpage(0)] = "closed"}) end) -assert:register("assertion", "closed_infoview_kept", function(state, _) - return infoview_check(state, closed_infoview, true, false) +assert:register("assertion", "closed_infoview_kept", function(_, arguments) + return infoview_check(arguments[1] or {[vim.api.nvim_win_get_tabpage(0)] = "closed_kept"}) end) -assert:register("assertion", "unopened_infoview", function(state, _) - return infoview_check(state, closed_infoview, false, true) +assert:register("assertion", "unopened_infoview", function(_, arguments) + return infoview_check(arguments[1] or {[vim.api.nvim_win_get_tabpage(0)] = "closed_kept"}) end) -assert:register("assertion", "change_infoview", change_infoview) -assert:register("assertion", "close_win", close_win) -assert:register("assertion", "new_win", new_win) + +-- internal state checks +assert:register("assertion", "opened_infoview_state", opened_infoview) +assert:register("assertion", "opened_infoview_kept_state", opened_infoview_kept) +assert:register("assertion", "closed_infoview_state", closed_infoview) +assert:register("assertion", "closed_infoview_kept_state", closed_infoview_kept) + +assert:register("assertion", "update_wins", update_wins) +assert:register("assertion", "closed_win", closed_win) +assert:register("assertion", "created_win", created_win) +assert:register("assertion", "changed_win", changed_win) + +-- initialize on very first nvim window (base case satisfied pretty trivially) +assert.created_win() return helpers diff --git a/lua/tests/infoview/autoopen_spec.lua b/lua/tests/infoview/autoopen_spec.lua index f16d0280..5948c289 100644 --- a/lua/tests/infoview/autoopen_spec.lua +++ b/lua/tests/infoview/autoopen_spec.lua @@ -15,7 +15,7 @@ describe('infoview', function() it('new tab automatically opens', function(_) vim.api.nvim_command('tabnew') - assert.new_win() + assert.created_win() vim.api.nvim_command('edit ' .. fixtures.lean3_project.some_existing_file) assert.opened_infoview() end) @@ -29,7 +29,7 @@ describe('infoview', function() it('opens automatically after having closen previous infoviews', function(_) vim.api.nvim_command("tabnew") - assert.new_win() + assert.created_win() vim.api.nvim_command("edit lua/tests/fixtures/example-lean3-project/test/test1.lean") assert.opened_infoview() end) @@ -38,7 +38,7 @@ describe('infoview', function() function(_) vim.api.nvim_command("tabnew") infoview.set_autoopen(false) - assert.new_win() + assert.created_win() vim.api.nvim_command("edit lua/tests/fixtures/example-lean3-project/test/test1.lean") assert.unopened_infoview() end) @@ -59,7 +59,7 @@ describe('infoview', function() function(_) vim.api.nvim_command("tabnew") infoview.set_autoopen(true) - assert.new_win() + assert.created_win() vim.api.nvim_command("edit lua/tests/fixtures/example-lean3-project/test/test1.lean") assert.opened_infoview() end) diff --git a/lua/tests/infoview/close_all_spec.lua b/lua/tests/infoview/close_all_spec.lua index 0a3737c7..b6724a00 100644 --- a/lua/tests/infoview/close_all_spec.lua +++ b/lua/tests/infoview/close_all_spec.lua @@ -4,51 +4,60 @@ require('tests.helpers').setup { infoview = {}, } describe('infoview', function() - it('close_all succeeds', - function(_) - vim.api.nvim_command("edit temp.lean") - infoview.get_current_infoview():open() - assert.opened_infoview() - - vim.api.nvim_command("tabnew") - assert.new_win() - vim.api.nvim_command("edit temp.lean") - infoview.get_current_infoview():open() - assert.opened_infoview() - - vim.api.nvim_command("tabnew") - assert.new_win() - vim.api.nvim_command("edit temp.lean") - infoview.get_current_infoview():open() - assert.opened_infoview() - infoview.get_current_infoview():close() - assert.closed_infoview() - - vim.api.nvim_command("tabnew") - assert.new_win() - vim.api.nvim_command("edit temp.lean") - infoview.get_current_infoview():open() - assert.opened_infoview() - - - local already_closed = false - local already_closed_count = 0 - infoview.close_all( - function(info) - if info.window ~= vim.api.nvim_get_current_win() then - vim.api.nvim_set_current_win(info.window) - assert.change_infoview() - end - if not info.is_open then - already_closed = true - already_closed_count = already_closed_count + 1 - end - end, - function() - assert.is_not.opened_infoview(already_closed) - already_closed = false - end - ) - assert.equals(1, already_closed_count) + describe('close_all succeeds', function() + it('single infoview', + function(_) + local info_changes = {} + + vim.api.nvim_command("edit temp.lean") + infoview.get_current_infoview():open() + assert.opened_infoview() + info_changes[vim.api.nvim_win_get_tabpage(0)] = "closed" + + infoview.close_all() + + assert.updated_infoviews(info_changes) + end) + + it('multiple infoviews, not all opened', + function(_) + local info_changes = {} + + vim.api.nvim_command("tabnew") + assert.created_win() + vim.api.nvim_command("edit temp.lean") + infoview.get_current_infoview():open() + assert.opened_infoview() + info_changes[vim.api.nvim_win_get_tabpage(0)] = "closed" + + vim.api.nvim_command("tabnew") + assert.created_win() + vim.api.nvim_command("edit temp.lean") + infoview.get_current_infoview():open() + assert.opened_infoview() + info_changes[vim.api.nvim_win_get_tabpage(0)] = "closed" + + vim.api.nvim_command("tabnew") + assert.created_win() + vim.api.nvim_command("edit temp.lean") + infoview.get_current_infoview():open() + assert.opened_infoview() + infoview.get_current_infoview():close() + assert.closed_infoview() + -- can actually omit this because it would be inferred by assert.updated_infoviews() + info_changes[vim.api.nvim_win_get_tabpage(0)] = "closed_kept" + + vim.api.nvim_command("tabnew") + assert.created_win() + vim.api.nvim_command("edit temp.lean") + infoview.get_current_infoview():open() + assert.opened_infoview() + info_changes[vim.api.nvim_win_get_tabpage(0)] = "closed" + + + infoview.close_all() + + assert.updated_infoviews(info_changes) + end) end) end) diff --git a/lua/tests/infoview/run_spec.lua b/lua/tests/infoview/run_spec.lua index 51edc653..d5e6dfb5 100644 --- a/lua/tests/infoview/run_spec.lua +++ b/lua/tests/infoview/run_spec.lua @@ -33,16 +33,18 @@ describe('infoview', function() it('remains closed on BufEnter', function(_) vim.api.nvim_command("edit lua/tests/fixtures/example-lean3-project/test/test1.lean") + -- would be equivalent to just do assert.updated_infoviews() here, because this would + -- correctly infer closed_infoview_kept; kept it (and others like it) for readability assert.closed_infoview_kept() end) it('remains closed on WinEnter', function(_) vim.api.nvim_command("split lua/tests/fixtures/example-lean3-project/test.lean") - assert.new_win() + assert.created_win() assert.closed_infoview_kept() vim.api.nvim_command("close") - assert.close_win() + assert.closed_win() end) it('CursorHold(I) disabled when closed', @@ -90,14 +92,13 @@ describe('infoview', function() infoview.get_current_infoview():open() assert.opened_infoview() vim.api.nvim_command("tabnew") - assert.new_win() + assert.created_win() vim.api.nvim_command("edit lua/tests/fixtures/example-lean4-project/Test.lean") assert.opened_infoview() infoview.get_current_infoview():close() assert.closed_infoview() assert.is_not.update_enabled() vim.api.nvim_command("tabprevious") - assert.change_infoview() assert.opened_infoview_kept() end) @@ -116,7 +117,6 @@ describe('infoview', function() it('CursorHold(I) updated on WinEnter', function(_) vim.api.nvim_command("tabnext") - assert.change_infoview() assert.closed_infoview_kept() assert.is_not.update_enabled() end) @@ -130,18 +130,14 @@ describe('infoview', function() it('opens independently', function(_) vim.api.nvim_command("tabprevious") - assert.change_infoview() infoview.get_current_infoview():close() assert.closed_infoview() vim.api.nvim_command("tabnext") - assert.change_infoview() infoview.get_current_infoview():open() assert.opened_infoview() vim.api.nvim_command("tabprevious") - assert.change_infoview() assert.closed_infoview_kept() vim.api.nvim_command("tabnext") - assert.change_infoview() assert.opened_infoview_kept() end) diff --git a/lua/tests/infoview/start_spec.lua b/lua/tests/infoview/start_spec.lua index 3443560d..3b55ffe3 100644 --- a/lua/tests/infoview/start_spec.lua +++ b/lua/tests/infoview/start_spec.lua @@ -29,7 +29,7 @@ describe('infoview', function() it('created valid distinct infoview', function(_) vim.api.nvim_command("tabnew") - assert.new_win() + assert.created_win() src_win = vim.api.nvim_get_current_win() vim.api.nvim_command('edit ' .. fixtures.lean_project.some_existing_file) assert.opened_infoview()