diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9f77d84..1530cbc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: # neovim: true # version: nightly - # 2. Checkout Neovim source into a subdirectory + # 2. Checkout Neovim source into a subdirectory. - name: Checkout Neovim uses: actions/checkout@v4 with: @@ -26,19 +26,25 @@ jobs: path: neovim fetch-depth: 1 - # 3. Install test dependencies (Neovim's framework needs them) + # 3. Install Neovim's test dependencies. - name: Install deps run: | # sudo apt-get update sudo apt-get install -y ninja-build gettext cmake curl build-essential git - # 4. Build Neovim’s test environment (no need to build the binary) + # 4. Build Neovim. Run a dummy test. This avoids build noise in the logs for the next step. - name: Setup Neovim test environment - run: make -C neovim deps + env: + GH_TOKEN: ${{ github.token }} + NEOVIM_PATH: ${{ github.workspace }}/neovim + run: | + make patch-runner + cd neovim + TEST_FILE=test/functional/example_spec.lua make functionaltest - # 5. Run your plugin tests using Neovim’s framework + # 5. Run the plugin tests using Neovim’s framework. - name: Run plugin tests - run: make test env: GH_TOKEN: ${{ github.token }} NEOVIM_PATH: ${{ github.workspace }}/neovim + run: make test diff --git a/Makefile b/Makefile index 6fbc011..872e06c 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,18 @@ # Run tests with "nvim -l" instead of "-ll", so tests can use the full "vim." # API from the Nvim test harness process itself. patch-runner: - sed -i.bak 's/-ll /-l /' $(NEOVIM_PATH)/cmake/RunTests.cmake && rm $(NEOVIM_PATH)/cmake/RunTests.cmake.bak + @if grep -q -- "-ll " "$(NEOVIM_PATH)/cmake/RunTests.cmake"; then \ + echo "Patching RunTests.cmake (-ll → -l)..."; \ + sed -i.bak 's/-ll /-l /' "$(NEOVIM_PATH)/cmake/RunTests.cmake" && rm -f "$(NEOVIM_PATH)/cmake/RunTests.cmake.bak"; \ + else \ + echo "RunTests.cmake already patched; skipping."; \ + fi + test: patch-runner ifeq ($(NEOVIM_PATH),) $(error NEOVIM_PATH is not set) endif ln -sf $(shell pwd) $(NEOVIM_PATH)/test/functional/guh.nvim - cd $(NEOVIM_PATH) && TEST_FILE=test/functional/guh.nvim/test/gh_spec.lua make functionaltest + @cd $(NEOVIM_PATH) && env GH_TOKEN=$${GH_TOKEN:-$(shell gh auth token 2>/dev/null)} \ + TEST_FILE=test/functional/guh.nvim/test/gh_spec.lua make functionaltest diff --git a/lua/guh/utils.lua b/lua/guh/utils.lua index ff2f755..b0df862 100644 --- a/lua/guh/utils.lua +++ b/lua/guh/utils.lua @@ -10,6 +10,7 @@ function M.system_str(cmd, cb) if result.code ~= 0 and #result.stderr > 0 then config.log('system_str error', result.stderr) M.notify(result.stderr, vim.log.levels.ERROR) + error(result.stderr) end cb(result.stdout, result.stderr) diff --git a/test/gh_spec.lua b/test/gh_spec.lua index 56622f3..891ca76 100644 --- a/test/gh_spec.lua +++ b/test/gh_spec.lua @@ -7,6 +7,7 @@ vim.opt.runtimepath:append{ local t = require('test.testutil') local n = require('test.functional.testnvim')() +local Screen = require('test.functional.ui.screen') local clear, eq, eval, command, feed, insert, wait = n.clear, t.eq, n.eval, n.command, n.feed, n.insert, n.wait local async = require('async') @@ -20,11 +21,10 @@ local get_issue_async = async.wrap(2, gh.get_issue) local tests = {} -function tests.test_get_pr_info(ctx) +function tests.test_get_pr_info() return async.run(function() - local result = system_str_async('gh pr list --json number') - local pr_num = assert(vim.json.decode(assert(result))[1].number, 'failed to get a repo issue') - ctx.desc = ('(pr=%s)'):format(pr_num) + local result = assert(system_str_async('gh pr list --json number')) + local pr_num = assert(vim.json.decode(result)[1].number, 'failed to get a repo issue') local pr = get_pr_info_async(pr_num) assert(pr, 'pr is nil') @@ -34,11 +34,10 @@ function tests.test_get_pr_info(ctx) end) end -function tests.test_get_issue(ctx) +function tests.test_get_issue() return async.run(function() local result = system_str_async('gh issue list --json number') local issue_num = assert(vim.json.decode(assert(result))[1].number, 'failed to get a repo issue') - ctx.desc = ('(issue=%s)'):format(issue_num) local issue = get_issue_async(issue_num) assert(issue, 'issue is nil') @@ -49,7 +48,7 @@ function tests.test_get_issue(ctx) end -- Tests hardcoded diff. -function tests.test_get_prepare_comment(ctx) +function tests.test_get_prepare_comment() local pr_id = 42 local buf = state.get_buf('diff', pr_id) state.show_buf(buf) @@ -81,68 +80,14 @@ function tests.test_get_prepare_comment(ctx) assert(buf == info.buf, info.buf) end --- Tests real response from "gh pr diff". -function tests.test_get_prepare_comment2(ctx) - return async.run(function() - local pr_id = 1 - ctx.desc = ('(pr=%s)'):format(pr_id) - - return async.await(function(callback) - vim.schedule(function() - vim.cmd(('GuhDiff %d'):format(pr_id)) - - -- Wait for the buffer to be created and have content - local ok, buf = vim.wait(5000, function() - local b = vim.fn.bufnr(('guh://diff/%d'):format(pr_id)) - if b <= 0 then return false end - local lines = vim.api.nvim_buf_get_lines(b, 0, -1, false) - return #lines > 0, b - end) - assert(ok) - - -- Set the current buffer - vim.api.nvim_set_current_buf(buf) - - -- Find a line with a '+' (added line or +++ header) - local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false) - local target_line - for i, line in ipairs(lines) do - if line:match('^%+') and not line:match('^%+%+%+') then - target_line = i - break - end - end - assert(target_line, 'No added line (+) found in diff') - - -- Move cursor to the found line - vim.api.nvim_win_set_cursor(0, {target_line, 0}) - - -- Call prepare_to_comment - local info = pr_commands.prepare_to_comment(target_line, target_line) - - -- Assert the returned info - assert(info, 'prepare_to_comment returned nil') - assert(type(info.file) == 'string', 'file is not a string') - assert(16 == info.start_line) - assert(type(info.start_line) == 'number', 'start_line is not a number') - assert(type(info.end_line) == 'number', 'end_line is not a number') - assert(info.pr_id == pr_id, ('pr_id is not %s'):format(pr_id)) - - callback() - end) - end) - end) -end - -- Tests real comments response Github. -- Calls load_comments() and asserts that some comments were loaded into quickfix. -function tests.test_get_comments(ctx) +function tests.test_get_comments() return async.run(function() local result = system_str_async('gh pr list --json number') local prs = assert(vim.json.decode(assert(result)), 'failed to get PRs') assert(#prs > 0, 'no PRs found') local pr_num = prs[1].number - ctx.desc = ('(pr=%s)'):format(pr_num) return async.await(function(callback) vim.schedule(function() @@ -175,11 +120,10 @@ function tests.test_get_comments(ctx) end -- Tests that ":Guh 1" shows the issue in a buffer. -function tests.test_Guh(ctx) +function tests.test_Guh() return async.run(function() - local result = system_str_async('gh issue list --json number') - local issue_num = assert(vim.json.decode(assert(result))[1].number, 'failed to get a repo issue') - ctx.desc = ('(issue=%s)'):format(issue_num) + local result = assert(system_str_async('gh issue list --json number')) + local issue_num = assert(vim.json.decode(result)[1].number, 'failed to get a repo issue') return async.await(function(callback) vim.schedule(function() @@ -205,11 +149,66 @@ function tests.test_Guh(ctx) end describe('guh.gh', function() - -- THIS IS AN EXAMPLE. DO NOT TOUCH. USE IT TO CREATE OTHER it() CASES. - it('get_pr_info', function() + local screen + before_each(function() + clear() + screen = Screen.new(80, 10) + n.exec_lua[[ + -- TODO: do this in global test setup + vim.opt.runtimepath:append{ + vim.fn.getcwd() .. '/test/functional/guh.nvim/', + } + require('guh').setup({}) + ]] + end) + + it(':GuhDiff', function() + n.command('GuhDiff 1') + -- screen:snapshot_util() + + screen:expect{ + attr_ids = {}, -- Don't care about colors. + grid = [[ + ^diff --git {MATCH:a/.* b/.* +}| + new file mode {MATCH:%d+ +}| + index {MATCH:.*}| + --- {MATCH:.*}| + +++ {MATCH:.*}| + @@ {MATCH:.*} @@ {MATCH: +}| + {MATCH:.*}| + {MATCH:.*}| + {MATCH:.*}| + {MATCH:.*}| + ]] + } + end) + + pending('get_pr_info', function() local task = tests.test_get_pr_info() - local ok, rv = task:pwait() - assert(ok) + local ok, err = task:wait(5000) + assert(ok, err or 'get_pr_info failed') + end) + + pending('get_issue', function() + local task = tests.test_get_issue() + local ok, err = task:wait(5000) + assert(ok, err or 'get_issue failed') + end) + + it('prepare_to_comment (static diff)', function() + tests.test_get_prepare_comment({}) + end) + + pending('get_comments', function() + local task = tests.test_get_comments() + local ok, err = task:wait(5000) + assert(ok, err or 'get_comments failed') + end) + + pending('Guh command shows issue buffer', function() + local task = tests.test_Guh() + local ok, err = task:wait(5000) + assert(ok, err or 'Guh command failed') end) end)