+7
-1
.github/workflows/linters.yml
+7
-1
.github/workflows/linters.yml
+33
-23
.github/workflows/tests.yml
+33
-23
.github/workflows/tests.yml
···
1
1
name: tests
2
-
on: [push, pull_request]
2
+
3
+
on:
4
+
push:
5
+
branches:
6
+
- main
7
+
- develop
8
+
pull_request:
3
9
4
10
jobs:
5
11
tests:
6
12
strategy:
7
13
matrix:
8
14
os: [ubuntu-latest]
9
-
nvim_version:
15
+
version:
16
+
- v0.10.4
10
17
- nightly
11
-
- v0.7.0
12
-
- v0.7.2
13
-
- v0.8.0
14
-
- v0.8.1
15
-
- v0.8.2
16
-
- v0.8.3
17
-
- v0.9.0
18
-
- v0.9.1
19
-
- v0.9.2
20
-
- v0.9.4
21
-
- v0.9.5
22
-
- v0.10.0
23
18
runs-on: ${{ matrix.os }}
24
19
steps:
25
20
- name: Install Task
···
28
23
version: 3.x
29
24
repo-token: ${{ secrets.GITHUB_TOKEN }}
30
25
26
+
- name: Install Go
27
+
uses: actions/setup-go@v5
28
+
with:
29
+
go-version: "1.24.0"
30
+
check-latest: false
31
+
32
+
- name: Install NeoVim
33
+
uses: rhysd/action-setup-vim@v1
34
+
with:
35
+
neovim: true
36
+
version: ${{ matrix.version }}
37
+
31
38
- uses: actions/checkout@v3
32
39
33
-
- name: Install Neovim
34
-
run: |
35
-
mkdir -p /tmp/nvim
36
-
wget -q https://github.com/neovim/neovim/releases/download/${{ matrix.nvim_version }}/nvim.appimage -O /tmp/nvim/nvim.appimage
37
-
cd /tmp/nvim
38
-
chmod a+x ./nvim.appimage
39
-
./nvim.appimage --appimage-extract
40
-
echo "/tmp/nvim/squashfs-root/usr/bin/" >> $GITHUB_PATH
40
+
- name: Cache .tests
41
+
uses: actions/cache@v4
42
+
with:
43
+
path: |
44
+
${{ github.workspace }}/.tests
45
+
~/.cache/go-build
46
+
~/go/pkg/mod
47
+
key: ${{ runner.os }}-tests-${{ hashFiles('${{ github.workspace }}/.tests') }}
48
+
49
+
- name: Install Go bins
50
+
run: nvim --headless -u "./scripts/minimal_init.lua" -c "GoInstallDeps" -c "qa!"
41
51
42
52
- name: Run Tests
43
53
run: |
44
54
nvim --version
45
-
task test
55
+
task tests
+3
-2
README.md
+3
-2
README.md
···
10
10
11
11
## Install (using [lazy.nvim](https://github.com/folke/lazy.nvim))
12
12
13
-
Pre-dependency:
13
+
Requirements:
14
14
15
-
- [Go](https://github.com/golang/go)
15
+
- **Neovim 0.10** or later
16
16
- `go` treesitter parser, install by `:TSInstall go`
17
+
- [Go](https://github.com/golang/go) installed (tested on 1.23)
17
18
18
19
```lua
19
20
{
+4
-8
Taskfile.yml
+4
-8
Taskfile.yml
···
26
26
cmds:
27
27
- stylua .
28
28
29
-
test:
30
-
desc: runs all tests
31
-
aliases: [tests, spec]
29
+
tests:
30
+
desc: run all tests
32
31
cmds:
33
32
- |
34
33
nvim --headless \
35
-
-u ./scripts/minimal_init.lua \
36
-
-c "PlenaryBustedDirectory spec \
37
-
{minimal_init='./scripts/minimal_init.lua' \
38
-
,sequential=true}" \
39
-
-c ":qa!"
34
+
-u ./scripts/minimal_init.lua \
35
+
-c "lua MiniTest.run()"
40
36
41
37
docgen:
42
38
desc: generate vimhelp
-3
doc/gopher.nvim.txt
-3
doc/gopher.nvim.txt
···
116
116
}
117
117
<
118
118
119
-
120
119
==============================================================================
121
120
------------------------------------------------------------------------------
122
121
*gopher.nvim-impl*
···
147
146
}
148
147
<
149
148
150
-
151
149
==============================================================================
152
150
------------------------------------------------------------------------------
153
151
*gopher.nvim-gotests*
···
166
164
167
165
you can also specify the template to use for generating the tests. see |gopher.nvim-config|
168
166
more details about templates can be found at: https://github.com/cweill/gotests
169
-
170
167
171
168
------------------------------------------------------------------------------
172
169
*gopher.nvim-gotests-named*
-8
lua/gopher/_utils/init.lua
-8
lua/gopher/_utils/init.lua
···
23
23
log.debug(msg)
24
24
end
25
25
26
-
-- safe require
27
-
---@param module string module name
28
-
function utils.sreq(module)
29
-
local ok, m = pcall(require, module)
30
-
assert(ok, string.format("gopher.nvim dependency error: %s not installed", module))
31
-
return m
32
-
end
33
-
34
26
return utils
+1
-1
lua/gopher/config.lua
+1
-1
lua/gopher/config.lua
···
23
23
--minidoc_replace_start {
24
24
25
25
---@tag gopher.nvim-config-defaults
26
-
---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section):gsub(">", ">lua")
26
+
---@eval return MiniDoc.afterlines_to_code(MiniDoc.current.eval_section)
27
27
---
28
28
---@class gopher.Config
29
29
local default_config = {
+3
nvim.toml
+3
nvim.toml
+20
-5
scripts/minimal_init.lua
+20
-5
scripts/minimal_init.lua
···
6
6
local function install_plug(plugin)
7
7
local name = plugin:match ".*/(.*)"
8
8
local package_root = root ".tests/site/pack/deps/start/"
9
-
if not vim.loop.fs_stat(package_root .. name) then
9
+
if not vim.uv.fs_stat(package_root .. name) then
10
10
print("Installing " .. plugin)
11
11
vim.fn.mkdir(package_root, "p")
12
12
vim.fn.system {
···
18
18
}
19
19
end
20
20
end
21
+
22
+
vim.env.XDG_CONFIG_HOME = root ".tests/config"
23
+
vim.env.XDG_DATA_HOME = root ".tests/data"
24
+
vim.env.XDG_STATE_HOME = root ".tests/state"
25
+
vim.env.XDG_CACHE_HOME = root ".tests/cache"
21
26
22
27
vim.cmd [[set runtimepath=$VIMRUNTIME]]
23
28
vim.opt.runtimepath:append(root())
···
27
32
install_plug "nvim-lua/plenary.nvim"
28
33
install_plug "nvim-treesitter/nvim-treesitter"
29
34
install_plug "echasnovski/mini.doc" -- used for docs generation
35
+
install_plug "echasnovski/mini.test"
30
36
31
-
vim.env.XDG_CONFIG_HOME = root ".tests/config"
32
-
vim.env.XDG_DATA_HOME = root ".tests/data"
33
-
vim.env.XDG_STATE_HOME = root ".tests/state"
34
-
vim.env.XDG_CACHE_HOME = root ".tests/cache"
37
+
-- install go treesitter parse
38
+
require("nvim-treesitter.install").ensure_installed_sync "go"
39
+
40
+
-- setup mini.test only when running headless nvim
41
+
if #vim.api.nvim_list_uis() == 0 then
42
+
require("mini.test").setup {
43
+
collect = {
44
+
find_files = function()
45
+
return vim.fn.globpath("spec", "**/*_test.lua", true, true)
46
+
end,
47
+
},
48
+
}
49
+
end
+1
spec/fixtures/comment/package_input.go
+1
spec/fixtures/comment/package_input.go
···
1
+
package main
+9
spec/fixtures/iferr/iferr_input.go
+9
spec/fixtures/iferr/iferr_input.go
+12
spec/fixtures/iferr/iferr_output.go
+12
spec/fixtures/iferr/iferr_output.go
+8
spec/fixtures/impl/closer_output.go
+8
spec/fixtures/impl/closer_output.go
+8
spec/fixtures/impl/reader_output.go
+8
spec/fixtures/impl/reader_output.go
+8
spec/fixtures/impl/writer_output.go
+8
spec/fixtures/impl/writer_output.go
+5
spec/fixtures/tests/function_input.go
+5
spec/fixtures/tests/function_input.go
+24
spec/fixtures/tests/function_output.go
+24
spec/fixtures/tests/function_output.go
···
1
+
package fortest
2
+
3
+
import "testing"
4
+
5
+
func TestAdd(t *testing.T) {
6
+
type args struct {
7
+
x int
8
+
y int
9
+
}
10
+
tests := []struct {
11
+
name string
12
+
args args
13
+
want int
14
+
}{
15
+
// TODO: Add test cases.
16
+
}
17
+
for _, tt := range tests {
18
+
t.Run(tt.name, func(t *testing.T) {
19
+
if got := Add(tt.args.x, tt.args.y); got != tt.want {
20
+
t.Errorf("Add() = %v, want %v", got, tt.want)
21
+
}
22
+
})
23
+
}
24
+
}
+7
spec/fixtures/tests/method_input.go
+7
spec/fixtures/tests/method_input.go
+26
spec/fixtures/tests/method_output.go
+26
spec/fixtures/tests/method_output.go
···
1
+
package fortest
2
+
3
+
import "testing"
4
+
5
+
func TestForTest_Add(t *testing.T) {
6
+
type args struct {
7
+
x int
8
+
y int
9
+
}
10
+
tests := []struct {
11
+
name string
12
+
tr *ForTest
13
+
args args
14
+
want int
15
+
}{
16
+
// TODO: Add test cases.
17
+
}
18
+
for _, tt := range tests {
19
+
t.Run(tt.name, func(t *testing.T) {
20
+
tr := &ForTest{}
21
+
if got := tr.Add(tt.args.x, tt.args.y); got != tt.want {
22
+
t.Errorf("ForTest.Add() = %v, want %v", got, tt.want)
23
+
}
24
+
})
25
+
}
26
+
}
+27
spec/integration/comment_test.lua
+27
spec/integration/comment_test.lua
···
1
+
local t = require "spec.testutils"
2
+
3
+
local child = MiniTest.new_child_neovim()
4
+
local T = MiniTest.new_set {
5
+
hooks = {
6
+
post_once = child.stop,
7
+
pre_case = function()
8
+
MiniTest.skip "This module should be fixed first"
9
+
child.restart { "-u", t.mininit_path }
10
+
end,
11
+
},
12
+
}
13
+
T["comment"] = MiniTest.new_set {}
14
+
15
+
T["comment"]["should add comment to package"] = function() end
16
+
17
+
T["comment"]["should add comment to struct"] = function() end
18
+
19
+
T["comment"]["should add comment to function"] = function() end
20
+
21
+
T["comment"]["should add comment to method"] = function() end
22
+
23
+
T["comment"]["should add comment to interface"] = function() end
24
+
25
+
T["comment"]["otherwise should add // above cursor"] = function() end
26
+
27
+
return T
+47
spec/integration/gotests_test.lua
+47
spec/integration/gotests_test.lua
···
1
+
local t = require "spec.testutils"
2
+
3
+
local child = MiniTest.new_child_neovim()
4
+
local T = MiniTest.new_set {
5
+
hooks = {
6
+
post_once = child.stop,
7
+
pre_case = function()
8
+
child.restart { "-u", t.mininit_path }
9
+
end,
10
+
},
11
+
}
12
+
T["gotests"] = MiniTest.new_set {}
13
+
14
+
--- NOTE: :GoTestAdd is the only place that has actual logic
15
+
--- All other parts are handled `gotests` itself.
16
+
17
+
---@param fpath string
18
+
---@return string
19
+
local function read_testfile(fpath)
20
+
return t.readfile(fpath:gsub(".go", "_test.go"))
21
+
end
22
+
23
+
T["gotests"]["should add test for function under cursor"] = function()
24
+
local tmp = t.tmpfile()
25
+
local fixtures = t.get_fixtures "tests/function"
26
+
t.writefile(tmp, fixtures.input)
27
+
28
+
child.cmd("silent edit " .. tmp)
29
+
child.fn.setpos(".", { child.fn.bufnr "%", 3, 6 })
30
+
child.cmd "GoTestAdd"
31
+
32
+
t.eq(fixtures.output, read_testfile(tmp))
33
+
end
34
+
35
+
T["gotests"]["should add test for method under cursor"] = function()
36
+
local tmp = t.tmpfile()
37
+
local fixtures = t.get_fixtures "tests/method"
38
+
t.writefile(tmp, fixtures.input)
39
+
40
+
child.cmd("silent edit " .. tmp)
41
+
child.fn.setpos(".", { child.fn.bufnr "%", 5, 19 })
42
+
child.cmd "GoTestAdd"
43
+
44
+
t.eq(fixtures.output, read_testfile(tmp))
45
+
end
46
+
47
+
return T
+26
spec/integration/iferr_test.lua
+26
spec/integration/iferr_test.lua
···
1
+
local t = require "spec.testutils"
2
+
3
+
local child = MiniTest.new_child_neovim()
4
+
local T = MiniTest.new_set {
5
+
hooks = {
6
+
post_once = child.stop,
7
+
pre_case = function()
8
+
child.restart { "-u", t.mininit_path }
9
+
end,
10
+
},
11
+
}
12
+
T["iferr"] = MiniTest.new_set {}
13
+
T["iferr"]["works"] = function()
14
+
local tmp = t.tmpfile()
15
+
local fixtures = t.get_fixtures "iferr/iferr"
16
+
t.writefile(tmp, fixtures.input)
17
+
18
+
child.cmd("silent edit " .. tmp)
19
+
child.fn.setpos(".", { child.fn.bufnr "%", 8, 2, 0 })
20
+
child.cmd "GoIfErr"
21
+
child.cmd "write"
22
+
23
+
t.eq(t.readfile(tmp), fixtures.output)
24
+
end
25
+
26
+
return T
+55
spec/integration/impl_test.lua
+55
spec/integration/impl_test.lua
···
1
+
local t = require "spec.testutils"
2
+
3
+
local child = MiniTest.new_child_neovim()
4
+
local T = MiniTest.new_set {
5
+
hooks = {
6
+
post_once = child.stop,
7
+
pre_case = function()
8
+
child.restart { "-u", t.mininit_path }
9
+
end,
10
+
},
11
+
}
12
+
T["impl"] = MiniTest.new_set {}
13
+
T["impl"]["works w io.Writer"] = function()
14
+
local tmp = t.tmpfile()
15
+
local fixtures = t.get_fixtures "impl/writer"
16
+
t.writefile(tmp, fixtures.input)
17
+
18
+
child.cmd("silent edit " .. tmp)
19
+
child.fn.setpos(".", { child.fn.bufnr(tmp), 3, 6 })
20
+
child.cmd "GoImpl w io.Writer"
21
+
child.cmd "write"
22
+
23
+
-- NOTE: since "impl" won't implement interface if it's already implemented i went with this hack
24
+
local rhs = fixtures.output:gsub("Test2", "Test")
25
+
t.eq(t.readfile(tmp), rhs)
26
+
end
27
+
28
+
T["impl"]["works r Read io.Reader"] = function()
29
+
local tmp = t.tmpfile()
30
+
local fixtures = t.get_fixtures "impl/reader"
31
+
t.writefile(tmp, fixtures.input)
32
+
33
+
child.cmd("silent edit " .. tmp)
34
+
child.cmd "GoImpl r Read io.Reader"
35
+
child.cmd "write"
36
+
37
+
local rhs = fixtures.output:gsub("Read2", "Read")
38
+
t.eq(t.readfile(tmp), rhs)
39
+
end
40
+
41
+
T["impl"]["works io.Closer"] = function()
42
+
local tmp = t.tmpfile()
43
+
local fixtures = t.get_fixtures "impl/closer"
44
+
t.writefile(tmp, fixtures.input)
45
+
46
+
child.cmd("silent edit " .. tmp)
47
+
child.fn.setpos(".", { child.fn.bufnr(tmp), 3, 6 })
48
+
child.cmd "GoImpl io.Closer"
49
+
child.cmd "write"
50
+
51
+
local rhs = fixtures.output:gsub("Test2", "Test")
52
+
t.eq(t.readfile(tmp), rhs)
53
+
end
54
+
55
+
return T
+43
spec/testutils.lua
+43
spec/testutils.lua
···
1
+
local base_dir = vim.env.GOPHER_DIR or vim.fn.expand "%:p:h"
2
+
3
+
---@class gopher.TestUtils
4
+
local testutils = {}
5
+
6
+
testutils.mininit_path = vim.fs.joinpath(base_dir, "scripts", "minimal_init.lua")
7
+
testutils.fixtures_dir = vim.fs.joinpath(base_dir, "spec/fixtures")
8
+
9
+
---@generic T
10
+
---@param a T
11
+
---@param b T
12
+
---@return boolean
13
+
function testutils.eq(a, b)
14
+
return MiniTest.expect.equality(a, b)
15
+
end
16
+
17
+
---@return string
18
+
function testutils.tmpfile()
19
+
return vim.fn.tempname() .. ".go"
20
+
end
21
+
22
+
---@param path string
23
+
---@return string
24
+
function testutils.readfile(path)
25
+
return vim.fn.join(vim.fn.readfile(path), "\n")
26
+
end
27
+
28
+
---@param fpath string
29
+
---@param contents string
30
+
function testutils.writefile(fpath, contents)
31
+
vim.fn.writefile(vim.split(contents, "\n"), fpath)
32
+
end
33
+
34
+
---@param fixture string
35
+
---@return {input: string, output: string}
36
+
function testutils.get_fixtures(fixture)
37
+
return {
38
+
input = testutils.readfile(vim.fs.joinpath(testutils.fixtures_dir, fixture) .. "_input.go"),
39
+
output = testutils.readfile(vim.fs.joinpath(testutils.fixtures_dir, fixture) .. "_output.go"),
40
+
}
41
+
end
42
+
43
+
return testutils
-29
spec/units/config_spec.lua
-29
spec/units/config_spec.lua
···
1
-
describe("gopher.config", function()
2
-
it(".setup() should provide default when .setup() is not called", function()
3
-
local c = require "gopher.config"
4
-
5
-
assert.are.same(c.commands.go, "go")
6
-
assert.are.same(c.commands.gomodifytags, "gomodifytags")
7
-
assert.are.same(c.commands.gotests, "gotests")
8
-
assert.are.same(c.commands.impl, "impl")
9
-
assert.are.same(c.commands.iferr, "iferr")
10
-
assert.are.same(c.commands.dlv, "dlv")
11
-
end)
12
-
13
-
it(".setup() should change options on users config", function()
14
-
local c = require "gopher.config"
15
-
c.setup {
16
-
commands = {
17
-
go = "go1.420",
18
-
gomodifytags = "iDontUseRustBtw",
19
-
},
20
-
}
21
-
22
-
assert.are.same(c.commands.go, "go1.420")
23
-
assert.are.same(c.commands.gomodifytags, "iDontUseRustBtw")
24
-
assert.are.same(c.commands.gotests, "gotests")
25
-
assert.are.same(c.commands.impl, "impl")
26
-
assert.are.same(c.commands.iferr, "iferr")
27
-
assert.are.same(c.commands.dlv, "dlv")
28
-
end)
29
-
end)
-15
spec/units/utils_spec.lua
-15
spec/units/utils_spec.lua
···
1
-
describe("gopher._utils", function()
2
-
local u = require "gopher._utils"
3
-
4
-
describe(".sreq()", function()
5
-
it("can require existing module", function()
6
-
assert.are.same(require "gopher", u.sreq "gopher")
7
-
end)
8
-
9
-
it("cannot require non-existing module", function()
10
-
assert.has.errors(function()
11
-
u.sreq "iDontExistBtw"
12
-
end)
13
-
end)
14
-
end)
15
-
end)