Skip to content

Commit

Permalink
fix: go test -f needs backslash escaping on Windows (#277)
Browse files Browse the repository at this point in the history
This adds support for testing on Windows with plenary. I was able to get Busted to run tests but it was a nightmare on Windows and I gave up. The entire setup also involved a lot of moving parts, so I feel PlenaryBusted is still the solution I'd like to keep.
  • Loading branch information
fredrikaverpil authored Jan 24, 2025
1 parent 797b9a2 commit 3d259fd
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 101 deletions.
21 changes: 13 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,31 @@ jobs:
nvim:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
version: [stable, nightly]
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Cache
uses: actions/cache@v4
with:
path: .tests
key: ${{ runner.os }}-nvim-${{ matrix.version }}-${{ hashFiles('tests/minimal_init.lua') }}-${{ hashFiles('tests/bootstrap.lua') }}
- name: Neovim setup
uses: rhysd/action-setup-vim@v1
with:
neovim: true
version: ${{ matrix.version }}
- name: Neovim version
run: nvim --version
- name: Bootstrap plenary for CI
run: |
mkdir -p ~/.local/share/nvim/site/pack/vendor/start
git clone --depth 1 https://github.com/nvim-lua/plenary.nvim ~/.local/share/nvim/site/pack/vendor/start/plenary.nvim
ln -s $(pwd) ~/.local/share/nvim/site/pack/vendor/start
- name: Run tests
run: make test-lua
go:
runs-on: ubuntu-latest
go-test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -41,3 +45,4 @@ jobs:
go-version: 1.23
- name: Run tests
run: make test-go

20 changes: 13 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
TESTS_INIT=tests/minimal_init.lua
TESTS_DIR=tests/

# --- Default targets ---

.PHONY: install
Expand All @@ -21,19 +18,28 @@ vuln: vuln-go

# --- Targets ---

.PHONY: clean
clean:
rm -rf .tests

.PHONY: test-lua
test-lua:
nvim \
--headless \
--noplugin \
-u ${TESTS_INIT} \
-c "PlenaryBustedDirectory ${TESTS_DIR} { minimal_init = '${TESTS_INIT}' }"
-i NONE \
-u tests/bootstrap.lua \
-c "PlenaryBustedDirectory tests/ { minimal_init = 'tests/minimal_init.lua', timeout = 50000 }"

.PHONY: test-go
test-go:
# Do not allow tests to be skipped
cd tests/go && \
go test -v ./... | tee /dev/fd/2 | grep -q "SKIP" && exit 1 || exit 0
@cd tests/go && output=$$(go test -v -count=1 ./...); \
echo "$$output"; \
if echo "$$output" | grep -q "SKIP"; then \
echo "Error: Skipped tests detected"; \
exit 1; \
fi

.PHONY: format-go
format-go:
Expand Down
13 changes: 4 additions & 9 deletions lua/neotest-golang/lib/cmd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,22 @@ function M.golist_command()
-- NOTE: original command can contain a lot of data:
-- local cmd = { "go", "list", "-json" }

-- NOTE: optimized command only outputs fields needed:
-- NOTE: optimized command only outputs fields needed.
-- NOTE: Dir and GoMod needs %q to escape backslashes on Windows.
local cmd = {
"go",
"list",
"-f",
[[{
"Dir": "{{.Dir}}",
"Dir": {{printf "%q" .Dir}},
"ImportPath": "{{.ImportPath}}",
"Name": "{{.Name}}",
"TestGoFiles": [{{range $i, $f := .TestGoFiles}}{{if ne $i 0}},{{end}}"{{$f}}"{{end}}],
"XTestGoFiles": [{{range $i, $f := .XTestGoFiles}}{{if ne $i 0}},{{end}}"{{$f}}"{{end}}],
"Module": { "GoMod": "{{.Module.GoMod}}" }
"Module": { "GoMod": {{printf "%q" .Module.GoMod}} }
}]],
}

-- FIXME: this is a workaround for Windows, where there is a bug with the output
-- when using the -f flag: https://github.com/fredrikaverpil/neotest-golang/issues/276
if vim.fn.has("win32") == 1 then
cmd = { "go", "list", "-json" }
end

local go_list_args = options.get().go_list_args
if type(go_list_args) == "function" then
go_list_args = go_list_args()
Expand Down
59 changes: 59 additions & 0 deletions tests/bootstrap.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
local M = {}

--- Initialize the test environment.
--- Thie file will run once before attempting to run PlenaryBustedDirectory.
function M.init()
vim.cmd([[set runtimepath=$VIMRUNTIME]]) -- reset, otherwise it contains all of $PATH
print("Runtime path: " .. vim.inspect(vim.opt.runtimepath:get()))
-- vim.opt.runtimepath:append(".") -- add project root to runtime path
vim.opt.swapfile = false
local site_dir = ".tests/all/site"
vim.opt.packpath = { site_dir } -- set packpath to the site directory

-- Clone down plugins, add to runtimepath
local plugins = {
["plenary.nvim"] = { url = "https://github.com/nvim-lua/plenary.nvim" },
["nvim-nio"] = { url = "https://github.com/nvim-neotest/nvim-nio" },
["nvim-treesitter"] = {
url = "https://github.com/nvim-treesitter/nvim-treesitter",
},
neotest = { url = "https://github.com/nvim-neotest/neotest" },
}
for plugin, data in pairs(plugins) do
local plugin_path = site_dir .. "/pack/deps/start/" .. plugin
if vim.fn.isdirectory(plugin_path) ~= 1 then
os.execute("git clone " .. data.url .. " " .. plugin_path)
else
print("Plugin " .. plugin .. " already downloaded")
end
print("Adding to runtimepath: " .. plugin_path)
vim.opt.runtimepath:append(plugin_path)
end

print("Runtime path: " .. vim.inspect(vim.opt.runtimepath:get()))
print("Package path: " .. package.path)

-- Check availability
require("plenary")
require("neotest")
require("nvim-treesitter")

-- Install go parser, if not already installed
require("nvim-treesitter.configs").setup({
ensure_installed = { "go" },
auto_install = true,
sync_install = true,
})

-- Check if PlenaryBustedDirectory command is available
vim.cmd([[runtime plugin/plenary.vim]])
if vim.fn.exists(":PlenaryBustedDirectory") == 0 then
vim.notify(
"minimal_init.lua: Failed to find PlenaryBustedDirectory command. Aborting!",
vim.log.levels.ERROR
)
vim.cmd("q!")
end
end

M.init()
7 changes: 7 additions & 0 deletions tests/go/internal/positions/positions_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,18 @@ local function compareIgnoringKeys(t1, t2, ignoreKeys)
return copyTable(t1, ignoreKeys), copyTable(t2, ignoreKeys)
end

local function normalize_windows_path(path)
return path:gsub("/", "\\")
end

describe("Discovery of test positions", function()
it("Discover OK", function()
-- Arrange
local test_filepath = vim.uv.cwd()
.. "/tests/go/internal/positions/positions_test.go"
if vim.fn.has("win32") == 1 then
test_filepath = normalize_windows_path(test_filepath)
end
local expected = {
{
id = test_filepath,
Expand Down
10 changes: 10 additions & 0 deletions tests/go/internal/testify/positions_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,18 @@ local function compareIgnoringKeys(t1, t2, ignoreKeys)
return copyTable(t1, ignoreKeys), copyTable(t2, ignoreKeys)
end

local function normalize_windows_path(path)
return path:gsub("/", "\\")
end

describe("With testify_enabled=false", function()
it("Discover test functions", function()
-- Arrange
local test_filepath = vim.uv.cwd()
.. "/tests/go/internal/testify/positions_test.go"
if vim.fn.has("win32") == 1 then
test_filepath = normalize_windows_path(test_filepath)
end
local expected = {
{
id = test_filepath,
Expand Down Expand Up @@ -81,6 +88,9 @@ describe("With testify_enabled=true", function()
-- Arrange
local test_filepath = vim.uv.cwd()
.. "/tests/go/internal/testify/positions_test.go"
if vim.fn.has("win32") == 1 then
test_filepath = normalize_windows_path(test_filepath)
end
options.set({ testify_enabled = true }) -- enable testify
local filepaths = lib.find.go_test_filepaths(test_filepath)
testify.lookup.initialize_lookup(filepaths) -- generate lookup
Expand Down
12 changes: 12 additions & 0 deletions tests/go/lookup_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,24 @@ local options = require("neotest-golang.options")
local lib = require("neotest-golang.lib")
local testify = require("neotest-golang.features.testify")

local function normalize_windows_path(path)
return path:gsub("\\", "/")
end

describe("Lookup", function()
it("Generates tree replacement instructions", function()
-- Arrange
options.set({ testify_enabled = true }) -- enable testify
local folderpath = vim.uv.cwd() .. "/tests/go"
if vim.fn.has("win32") == 1 then
folderpath = normalize_windows_path(folderpath)
end
local filepaths = lib.find.go_test_filepaths(vim.uv.cwd())
if vim.fn.has("win32") == 1 then
for i, filepath in ipairs(filepaths) do
filepaths[i] = normalize_windows_path(filepath)
end
end
local expected_lookup = {
[folderpath .. "/internal/operand/operand_test.go"] = {
package = "operand",
Expand Down
29 changes: 0 additions & 29 deletions tests/install.sh

This file was deleted.

25 changes: 3 additions & 22 deletions tests/minimal_init.lua
Original file line number Diff line number Diff line change
@@ -1,29 +1,10 @@
local M = {}

--- Initialize before running each test.
function M.init()
vim.cmd([[set runtimepath=$VIMRUNTIME]])
vim.opt.runtimepath:append(".")
vim.cmd([[set runtimepath=$VIMRUNTIME]]) -- reset, otherwise it contains all of $PATH
vim.opt.swapfile = false

vim.opt.packpath = {
".tests/all/site",
}

vim.cmd([[
packadd plenary.nvim
packadd neotest
packadd nvim-nio
packadd nvim-treesitter
]])

require("nvim-treesitter.configs").setup({
ensure_installed = { "go", "lua" }, -- This will install go and lua parsers
auto_install = true,
sync_install = true,
})
vim.opt.packpath = { ".tests/all/site" } -- set packpath to the site directory
end

-- Ensure the required Neovim plugins are installed/cloned
os.execute("tests/install.sh")

M.init()
Loading

0 comments on commit 3d259fd

Please sign in to comment.