local runner = require("test-samurai-go-runner") describe("test-samurai-go-runner", function() it("detects Go test files by suffix", function() local bufnr1 = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_name(bufnr1, "/tmp/go_suffix_test.go") assert.is_true(runner.is_test_file(bufnr1)) local bufnr2 = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_name(bufnr2, "/tmp/go_main.go") assert.is_false(runner.is_test_file(bufnr2)) end) it("finds subtest when cursor is inside t.Run block", function() local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_name(bufnr, "/tmp/go_subtest_test.go") local lines = { "package main", "import \"testing\"", "", "func TestFoo(t *testing.T) {", " t.Run(\"first\", func(t *testing.T) {", " -- inside first", " })", "", " t.Run(\"second\", func(t *testing.T) {", " -- inside second", " })", "}", } vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) local orig_fs_find = vim.fs.find vim.fs.find = function(_, _) return { "/tmp/go.mod" } end local row_inside_first = 5 local spec, err = runner.find_nearest(bufnr, row_inside_first, 0) vim.fs.find = orig_fs_find assert.is_nil(err) assert.is_not_nil(spec) assert.equals("TestFoo/first", spec.test_path) assert.equals("subtest", spec.scope) assert.is_true(spec.file:match("go_subtest_test%.go$") ~= nil) assert.is_true(spec.cwd:match("/tmp$") ~= nil) end) it("falls back to whole test function when between subtests", function() local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_name(bufnr, "/tmp/go_between_test.go") local lines = { "package main", "import \"testing\"", "", "func TestFoo(t *testing.T) {", " t.Run(\"first\", func(t *testing.T) {", " -- inside first", " })", "", " t.Run(\"second\", func(t *testing.T) {", " -- inside second", " })", "}", } vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) local orig_fs_find = vim.fs.find vim.fs.find = function(_, _) return { "/tmp/go.mod" } end local row_between = 7 local spec, err = runner.find_nearest(bufnr, row_between, 0) vim.fs.find = orig_fs_find assert.is_nil(err) assert.is_not_nil(spec) assert.equals("TestFoo", spec.test_path) assert.equals("function", spec.scope) assert.is_true(spec.file:match("go_between_test%.go$") ~= nil) assert.is_true(spec.cwd:match("/tmp$") ~= nil) end) it("build_command uses current package and correct run pattern", function() local spec_sub = { file = "/tmp/project/pkg/foo_test.go", cwd = "/tmp/project", test_path = "TestFoo/first", scope = "subtest", } local cmd_spec_sub = runner.build_command(spec_sub) assert.are.same( { "go", "test", "-json", "-v", "./pkg", "-run", "^TestFoo$/^first$" }, cmd_spec_sub.cmd ) local spec_func = { file = "/tmp/project/foo_test.go", cwd = "/tmp/project", test_path = "TestFoo", scope = "function", } local cmd_spec_func = runner.build_command(spec_func) assert.are.same( { "go", "test", "-json", "-v", "./", "-run", "^TestFoo$" }, cmd_spec_func.cmd ) end) it("build_file_command uses exact test names from current file", function() local bufnr = vim.api.nvim_create_buf(false, true) vim.api.nvim_buf_set_name(bufnr, "/tmp/project/get_test.go") local lines = { "package main", "import \"testing\"", "", "func TestHandleGet(t *testing.T) {", " t.Run(\"returns_200\", func(t *testing.T) {", " -- inside test", " })", "}", } vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) local orig_fs_find = vim.fs.find vim.fs.find = function(_, _) return { "/tmp/project/go.mod" } end local cmd_spec = runner.build_file_command(bufnr) vim.fs.find = orig_fs_find assert.are.same( { "go", "test", "-json", "-v", "./", "-run", "^(TestHandleGet)$" }, cmd_spec.cmd ) assert.equals("/tmp/project", cmd_spec.cwd) end) it("parse_results reports subtests and display names", function() local output = table.concat({ vim.json.encode({ Action = "run", Test = "TestFoo" }), vim.json.encode({ Action = "pass", Test = "TestFoo/first" }), vim.json.encode({ Action = "fail", Test = "TestFoo/second" }), vim.json.encode({ Action = "skip", Test = "TestFoo/third" }), }, "\n") local results = runner.parse_results(output) assert.are.same({ "TestFoo/first" }, results.passes) assert.are.same({ "TestFoo/second" }, results.failures) assert.are.same({ "TestFoo/third" }, results.skips) assert.are.same({ "TestFoo/first" }, results.display.passes) assert.are.same({ "TestFoo/second" }, results.display.failures) assert.are.same({ "TestFoo/third" }, results.display.skips) end) it("orders parent tests before subtests within each status", function() local output = table.concat({ vim.json.encode({ Action = "fail", Test = "TestHandleGet/returns_200" }), vim.json.encode({ Action = "fail", Test = "TestHandleGet" }), vim.json.encode({ Action = "pass", Test = "TestOther/alpha" }), vim.json.encode({ Action = "pass", Test = "TestOther" }), }, "\n") local results = runner.parse_results(output) assert.are.same({ "TestHandleGet", "TestHandleGet/returns_200" }, results.failures) assert.are.same({ "TestOther", "TestOther/alpha" }, results.passes) assert.are.same({ "TestHandleGet", "TestHandleGet/returns_200" }, results.display.failures) assert.are.same({ "TestOther", "TestOther/alpha" }, results.display.passes) end) it("parse_test_output groups output per test", function() local output = table.concat({ vim.json.encode({ Action = "output", Test = "TestFoo", Output = "line1\n" }), vim.json.encode({ Action = "output", Test = "TestFoo", Output = "line2\n" }), vim.json.encode({ Action = "output", Test = "TestFoo/first", Output = "sub1\n" }), }, "\n") local results = runner.parse_test_output(output) assert.are.same({ "line1", "line2" }, results["TestFoo"]) assert.are.same({ "sub1" }, results["TestFoo/first"]) end) it("build_failed_command narrows to failed tests", function() local last_command = { cmd = { "go", "test", "-json", "-v", "./", "-run", "^TestFoo($|/)" }, cwd = "/tmp/project", } local failures = { "TestFoo/first", "TestBar" } local cmd_spec = runner.build_failed_command(last_command, failures, "file") assert.are.same( { "go", "test", "-json", "-v", "./", "-run", "(^TestFoo$/^first$|^TestBar$)" }, cmd_spec.cmd ) end) it("collect_failed_locations finds subtest positions", function() local temp_dir = vim.fn.tempname() vim.fn.mkdir(temp_dir, "p") local file = temp_dir .. "/sample_test.go" local lines = { "package main", "import \"testing\"", "", "func TestFoo(t *testing.T) {", " t.Run(\"first\", func(t *testing.T) {", " -- inside test", " })", "}", } vim.fn.writefile(lines, file) local items = runner.collect_failed_locations({ "TestFoo/first" }, { cwd = temp_dir }, "all") assert.is_true(#items > 0) assert.equals(file, items[1].filename) assert.equals(5, items[1].lnum) end) end)