tests: improve testing (#80)

* chore: setup mini.test

* chore(ci): setup new test runner, install plugin deps

* chore(ci): test only on stable and nightly releases

* test: iferr

* test: struct_tags

* test: impl

* test: gotests
This commit is contained in:
Smirnov Oleksandr 2025-02-24 14:21:01 +02:00 committed by GitHub
parent 0ed14a40d9
commit da960189c1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 435 additions and 101 deletions

View file

@ -0,0 +1 @@
package main

View file

@ -0,0 +1,2 @@
// Package main provides main
package main

9
spec/fixtures/iferr/iferr_input.go vendored Normal file
View file

@ -0,0 +1,9 @@
package main
func test() error {
return nil
}
func main() {
err := test()
}

12
spec/fixtures/iferr/iferr_output.go vendored Normal file
View file

@ -0,0 +1,12 @@
package main
func test() error {
return nil
}
func main() {
err := test()
if err != nil {
return
}
}

3
spec/fixtures/impl/closer_input.go vendored Normal file
View file

@ -0,0 +1,3 @@
package main
type CloserTest struct{}

8
spec/fixtures/impl/closer_output.go vendored Normal file
View file

@ -0,0 +1,8 @@
package main
type CloserTest2 struct{}
func (closertest *CloserTest2) Close() error {
panic("not implemented") // TODO: Implement
}

3
spec/fixtures/impl/reader_input.go vendored Normal file
View file

@ -0,0 +1,3 @@
package main
type Read struct{}

8
spec/fixtures/impl/reader_output.go vendored Normal file
View file

@ -0,0 +1,8 @@
package main
func (r Read2) Read(p []byte) (n int, err error) {
panic("not implemented") // TODO: Implement
}
type Read2 struct{}

3
spec/fixtures/impl/writer_input.go vendored Normal file
View file

@ -0,0 +1,3 @@
package main
type WriterTest struct{}

8
spec/fixtures/impl/writer_output.go vendored Normal file
View file

@ -0,0 +1,8 @@
package main
type WriterTest2 struct{}
func (w *WriterTest2) Write(p []byte) (n int, err error) {
panic("not implemented") // TODO: Implement
}

View file

@ -1,11 +1,11 @@
package main
type Test struct {
ID int
Name string
Num int64
ID int
Name string
Num int64
Another struct {
First int
Second string
}
First int
Second string
}
}

5
spec/fixtures/tests/function_input.go vendored Normal file
View file

@ -0,0 +1,5 @@
package fortest
func Add(x, y int) int {
return 2 + x + y
}

24
spec/fixtures/tests/function_output.go vendored Normal file
View file

@ -0,0 +1,24 @@
package fortest
import "testing"
func TestAdd(t *testing.T) {
type args struct {
x int
y int
}
tests := []struct {
name string
args args
want int
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.args.x, tt.args.y); got != tt.want {
t.Errorf("Add() = %v, want %v", got, tt.want)
}
})
}
}

7
spec/fixtures/tests/method_input.go vendored Normal file
View file

@ -0,0 +1,7 @@
package fortest
type ForTest struct{}
func (t *ForTest) Add(x, y int) int {
return 2 + x + y
}

26
spec/fixtures/tests/method_output.go vendored Normal file
View file

@ -0,0 +1,26 @@
package fortest
import "testing"
func TestForTest_Add(t *testing.T) {
type args struct {
x int
y int
}
tests := []struct {
name string
tr *ForTest
args args
want int
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tr := &ForTest{}
if got := tr.Add(tt.args.x, tt.args.y); got != tt.want {
t.Errorf("ForTest.Add() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -0,0 +1,27 @@
local t = require "spec.testutils"
local child = MiniTest.new_child_neovim()
local T = MiniTest.new_set {
hooks = {
post_once = child.stop,
pre_case = function()
MiniTest.skip "This module should be fixed first"
child.restart { "-u", t.mininit_path }
end,
},
}
T["comment"] = MiniTest.new_set {}
T["comment"]["should add comment to package"] = function() end
T["comment"]["should add comment to struct"] = function() end
T["comment"]["should add comment to function"] = function() end
T["comment"]["should add comment to method"] = function() end
T["comment"]["should add comment to interface"] = function() end
T["comment"]["otherwise should add // above cursor"] = function() end
return T

View file

@ -0,0 +1,47 @@
local t = require "spec.testutils"
local child = MiniTest.new_child_neovim()
local T = MiniTest.new_set {
hooks = {
post_once = child.stop,
pre_case = function()
child.restart { "-u", t.mininit_path }
end,
},
}
T["gotests"] = MiniTest.new_set {}
--- NOTE: :GoTestAdd is the only place that has actual logic
--- All other parts are handled `gotests` itself.
---@param fpath string
---@return string
local function read_testfile(fpath)
return t.readfile(fpath:gsub(".go", "_test.go"))
end
T["gotests"]["should add test for function under cursor"] = function()
local tmp = t.tmpfile()
local fixtures = t.get_fixtures "tests/function"
t.writefile(tmp, fixtures.input)
child.cmd("silent edit " .. tmp)
child.fn.setpos(".", { child.fn.bufnr "%", 3, 6 })
child.cmd "GoTestAdd"
t.eq(fixtures.output, read_testfile(tmp))
end
T["gotests"]["should add test for method under cursor"] = function()
local tmp = t.tmpfile()
local fixtures = t.get_fixtures "tests/method"
t.writefile(tmp, fixtures.input)
child.cmd("silent edit " .. tmp)
child.fn.setpos(".", { child.fn.bufnr "%", 5, 19 })
child.cmd "GoTestAdd"
t.eq(fixtures.output, read_testfile(tmp))
end
return T

View file

@ -0,0 +1,26 @@
local t = require "spec.testutils"
local child = MiniTest.new_child_neovim()
local T = MiniTest.new_set {
hooks = {
post_once = child.stop,
pre_case = function()
child.restart { "-u", t.mininit_path }
end,
},
}
T["iferr"] = MiniTest.new_set {}
T["iferr"]["works"] = function()
local tmp = t.tmpfile()
local fixtures = t.get_fixtures "iferr/iferr"
t.writefile(tmp, fixtures.input)
child.cmd("silent edit " .. tmp)
child.fn.setpos(".", { child.fn.bufnr "%", 8, 2, 0 })
child.cmd "GoIfErr"
child.cmd "write"
t.eq(t.readfile(tmp), fixtures.output)
end
return T

View file

@ -0,0 +1,55 @@
local t = require "spec.testutils"
local child = MiniTest.new_child_neovim()
local T = MiniTest.new_set {
hooks = {
post_once = child.stop,
pre_case = function()
child.restart { "-u", t.mininit_path }
end,
},
}
T["impl"] = MiniTest.new_set {}
T["impl"]["works w io.Writer"] = function()
local tmp = t.tmpfile()
local fixtures = t.get_fixtures "impl/writer"
t.writefile(tmp, fixtures.input)
child.cmd("silent edit " .. tmp)
child.fn.setpos(".", { child.fn.bufnr(tmp), 3, 6 })
child.cmd "GoImpl w io.Writer"
child.cmd "write"
-- NOTE: since "impl" won't implement interface if it's already implemented i went with this hack
local rhs = fixtures.output:gsub("Test2", "Test")
t.eq(t.readfile(tmp), rhs)
end
T["impl"]["works r Read io.Reader"] = function()
local tmp = t.tmpfile()
local fixtures = t.get_fixtures "impl/reader"
t.writefile(tmp, fixtures.input)
child.cmd("silent edit " .. tmp)
child.cmd "GoImpl r Read io.Reader"
child.cmd "write"
local rhs = fixtures.output:gsub("Read2", "Read")
t.eq(t.readfile(tmp), rhs)
end
T["impl"]["works io.Closer"] = function()
local tmp = t.tmpfile()
local fixtures = t.get_fixtures "impl/closer"
t.writefile(tmp, fixtures.input)
child.cmd("silent edit " .. tmp)
child.fn.setpos(".", { child.fn.bufnr(tmp), 3, 6 })
child.cmd "GoImpl io.Closer"
child.cmd "write"
local rhs = fixtures.output:gsub("Test2", "Test")
t.eq(t.readfile(tmp), rhs)
end
return T

View file

@ -0,0 +1,37 @@
local t = require "spec.testutils"
local child = MiniTest.new_child_neovim()
local T = MiniTest.new_set {
hooks = {
post_once = child.stop,
pre_case = function()
child.restart { "-u", t.mininit_path }
end,
},
}
T["struct_tags"] = MiniTest.new_set {}
T["struct_tags"]["works add"] = function()
local tmp = t.tmpfile()
local fixtures = t.get_fixtures "tags/add"
t.writefile(tmp, fixtures.input)
child.cmd("silent edit " .. tmp)
child.fn.setpos(".", { child.fn.bufnr "%", 3, 6, 0 })
child.cmd "GoTagAdd json"
t.eq(t.readfile(tmp), fixtures.output)
end
T["struct_tags"]["works remove"] = function()
local tmp = t.tmpfile()
local fixtures = t.get_fixtures "tags/remove"
t.writefile(tmp, fixtures.input)
child.cmd("silent edit " .. tmp)
child.fn.setpos(".", { child.fn.bufnr "%", 4, 6, 0 })
child.cmd "GoTagRm json"
t.eq(t.readfile(tmp), fixtures.output)
end
return T

43
spec/testutils.lua Normal file
View file

@ -0,0 +1,43 @@
local base_dir = vim.env.GOPHER_DIR or vim.fn.expand "%:p:h"
---@class gopher.TestUtils
local testutils = {}
testutils.mininit_path = vim.fs.joinpath(base_dir, "scripts", "minimal_init.lua")
testutils.fixtures_dir = vim.fs.joinpath(base_dir, "spec/fixtures")
---@generic T
---@param a T
---@param b T
---@return boolean
function testutils.eq(a, b)
return MiniTest.expect.equality(a, b)
end
---@return string
function testutils.tmpfile()
return vim.fn.tempname() .. ".go"
end
---@param path string
---@return string
function testutils.readfile(path)
return vim.fn.join(vim.fn.readfile(path), "\n")
end
---@param fpath string
---@param contents string
function testutils.writefile(fpath, contents)
vim.fn.writefile(vim.split(contents, "\n"), fpath)
end
---@param fixture string
---@return {input: string, output: string}
function testutils.get_fixtures(fixture)
return {
input = testutils.readfile(vim.fs.joinpath(testutils.fixtures_dir, fixture) .. "_input.go"),
output = testutils.readfile(vim.fs.joinpath(testutils.fixtures_dir, fixture) .. "_output.go"),
}
end
return testutils

View file

@ -1,29 +0,0 @@
describe("gopher.config", function()
it(".setup() should provide default when .setup() is not called", function()
local c = require "gopher.config"
assert.are.same(c.commands.go, "go")
assert.are.same(c.commands.gomodifytags, "gomodifytags")
assert.are.same(c.commands.gotests, "gotests")
assert.are.same(c.commands.impl, "impl")
assert.are.same(c.commands.iferr, "iferr")
assert.are.same(c.commands.dlv, "dlv")
end)
it(".setup() should change options on users config", function()
local c = require "gopher.config"
c.setup {
commands = {
go = "go1.420",
gomodifytags = "iDontUseRustBtw",
},
}
assert.are.same(c.commands.go, "go1.420")
assert.are.same(c.commands.gomodifytags, "iDontUseRustBtw")
assert.are.same(c.commands.gotests, "gotests")
assert.are.same(c.commands.impl, "impl")
assert.are.same(c.commands.iferr, "iferr")
assert.are.same(c.commands.dlv, "dlv")
end)
end)

View file

@ -1,15 +0,0 @@
describe("gopher._utils", function()
local u = require "gopher._utils"
describe(".sreq()", function()
it("can require existing module", function()
assert.are.same(require "gopher", u.sreq "gopher")
end)
it("cannot require non-existing module", function()
assert.has.errors(function()
u.sreq "iDontExistBtw"
end)
end)
end)
end)