From add140c798a463f82dcba199f0ef5275df2ed998 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 9 Feb 2026 00:33:03 -0500 Subject: [PATCH 1/2] fix: correct broken tool definitions Problem: several formatter and linter configs produced invalid commands when invoked by guard.nvim. pylint, shellcheck, and rubocop were missing fname=true so guard never appended the required filename argument. hadolint lacked the '-' arg needed to read stdin. ruff linter used the deprecated -e flag and was missing the 'check' subcommand. buf format was configured for stdin which it does not support. csharpier referenced the old dotnet-csharpier binary renamed in v1.0+. ruff_fix was missing the 'check' subcommand. Solution: add fname=true to pylint, shellcheck, and rubocop linters. Add '-' to hadolint args. Replace ruff linter's -e with check subcommand. Change buf from stdin to fname with -w flag. Update csharpier cmd and args for v1.0+. Add check to ruff_fix args. --- lua/guard-collection/formatter.lua | 10 +++++----- lua/guard-collection/linter/hadolint.lua | 2 +- lua/guard-collection/linter/pylint.lua | 1 + lua/guard-collection/linter/rubocop.lua | 1 + lua/guard-collection/linter/ruff.lua | 2 +- lua/guard-collection/linter/shellcheck.lua | 1 + 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lua/guard-collection/formatter.lua b/lua/guard-collection/formatter.lua index 711dfbb..6bffdf5 100644 --- a/lua/guard-collection/formatter.lua +++ b/lua/guard-collection/formatter.lua @@ -48,8 +48,8 @@ M.cljfmt = { } M.csharpier = { - cmd = 'dotnet-csharpier', - args = { '--write-stdout' }, + cmd = 'csharpier', + args = { 'format', '--write-stdout' }, stdin = true, } @@ -299,7 +299,7 @@ M.ruff = { M.ruff_fix = { cmd = 'ruff', - args = { '--fix', '-', '--stdin-filename' }, + args = { 'check', '--fix', '-', '--stdin-filename' }, stdin = true, fname = true, } @@ -319,8 +319,8 @@ M.biome = { M.buf = { cmd = 'buf', - args = { 'format' }, - stdin = true, + args = { 'format', '-w' }, + fname = true, } M.xmllint = { diff --git a/lua/guard-collection/linter/hadolint.lua b/lua/guard-collection/linter/hadolint.lua index 4b7d5fd..4b0a868 100644 --- a/lua/guard-collection/linter/hadolint.lua +++ b/lua/guard-collection/linter/hadolint.lua @@ -1,6 +1,6 @@ return { cmd = 'hadolint', - args = { '--no-fail', '--format=json' }, + args = { '--no-fail', '--format=json', '-' }, stdin = true, parse = require('guard.lint').from_json({ attributes = { diff --git a/lua/guard-collection/linter/pylint.lua b/lua/guard-collection/linter/pylint.lua index a94fa5c..50e1ba6 100644 --- a/lua/guard-collection/linter/pylint.lua +++ b/lua/guard-collection/linter/pylint.lua @@ -4,6 +4,7 @@ return { cmd = 'pylint', args = { '--from-stdin', '--output-format', 'json' }, stdin = true, + fname = true, parse = lint.from_json({ attributes = { severity = 'type', diff --git a/lua/guard-collection/linter/rubocop.lua b/lua/guard-collection/linter/rubocop.lua index 4f8995d..732d8c5 100644 --- a/lua/guard-collection/linter/rubocop.lua +++ b/lua/guard-collection/linter/rubocop.lua @@ -4,6 +4,7 @@ return { cmd = 'bundle', args = { 'exec', 'rubocop', '--format', 'json', '--force-exclusion', '--stdin' }, stdin = true, + fname = true, parse = lint.from_json({ get_diagnostics = function(...) return vim.json.decode(...).files[1].offenses diff --git a/lua/guard-collection/linter/ruff.lua b/lua/guard-collection/linter/ruff.lua index 31bb583..724bca9 100644 --- a/lua/guard-collection/linter/ruff.lua +++ b/lua/guard-collection/linter/ruff.lua @@ -3,8 +3,8 @@ local lint = require('guard.lint') return { cmd = 'ruff', args = { + 'check', '-n', - '-e', '--output-format', 'json', '-', diff --git a/lua/guard-collection/linter/shellcheck.lua b/lua/guard-collection/linter/shellcheck.lua index 7293118..0fff3fa 100644 --- a/lua/guard-collection/linter/shellcheck.lua +++ b/lua/guard-collection/linter/shellcheck.lua @@ -1,6 +1,7 @@ return { cmd = 'shellcheck', args = { '--format', 'json1', '--external-sources' }, + fname = true, parse = require('guard.lint').from_json({ get_diagnostics = function(...) return vim.json.decode(...).comments From dc5209b19d792be21bc4d27362df483fd88e8361 Mon Sep 17 00:00:00 2001 From: Barrett Ruth Date: Mon, 9 Feb 2026 00:33:19 -0500 Subject: [PATCH 2/2] test: add tests for fixed tool definitions Problem: the config fixes in the previous commit had no test coverage proving the definitions produce valid commands. Solution: add opts (cwd, tmpdir) and assert_diag to the test helper. Add tests for all 8 fixed tools using run_fmt/run_lint to exercise the actual configs. Add pylint to pip.txt, hadolint to binary.txt, shellcheck to the binary CI job, and new test-dotnet and test-ruby CI jobs. --- .github/scripts/install-binary-tools.sh | 5 ++ .github/tools/binary.txt | 5 ++ .github/tools/npm.txt | 3 ++ .github/tools/pip.txt | 1 + .github/workflows/ci.yaml | 66 ++++++++++++++++++++++++- test/binary/buf_spec.lua | 20 ++++++++ test/binary/cbfmt_spec.lua | 25 ++++++++++ test/binary/detekt_spec.lua | 24 +++++++++ test/binary/dprint_spec.lua | 28 +++++++++++ test/binary/hadolint_spec.lua | 21 ++++++++ test/binary/ktlint_spec.lua | 22 +++++++++ test/binary/shellcheck_spec.lua | 22 +++++++++ test/dotnet/csharpier_spec.lua | 9 ++++ test/go/golangci_lint_spec.lua | 35 +++++++++++++ test/helper.lua | 39 +++++++++++++-- test/npm/eslint_d_spec.lua | 42 ++++++++++++++++ test/npm/eslint_spec.lua | 32 ++++++++++++ test/npm/stylelint_spec.lua | 32 ++++++++++++ test/pip/mypy_spec.lua | 21 +++----- test/pip/pylint_spec.lua | 20 ++++++++ test/pip/ruff_fix_spec.lua | 15 ++++++ test/pip/ruff_spec.lua | 19 +++++++ test/pip/sqlfluff_spec.lua | 39 ++++++--------- test/ruby/rubocop_spec.lua | 28 +++++++++++ 24 files changed, 530 insertions(+), 43 deletions(-) create mode 100644 test/binary/buf_spec.lua create mode 100644 test/binary/cbfmt_spec.lua create mode 100644 test/binary/detekt_spec.lua create mode 100644 test/binary/dprint_spec.lua create mode 100644 test/binary/hadolint_spec.lua create mode 100644 test/binary/ktlint_spec.lua create mode 100644 test/binary/shellcheck_spec.lua create mode 100644 test/dotnet/csharpier_spec.lua create mode 100644 test/go/golangci_lint_spec.lua create mode 100644 test/npm/eslint_d_spec.lua create mode 100644 test/npm/eslint_spec.lua create mode 100644 test/npm/stylelint_spec.lua create mode 100644 test/pip/pylint_spec.lua create mode 100644 test/pip/ruff_fix_spec.lua create mode 100644 test/ruby/rubocop_spec.lua diff --git a/.github/scripts/install-binary-tools.sh b/.github/scripts/install-binary-tools.sh index 8a4eb70..3578406 100755 --- a/.github/scripts/install-binary-tools.sh +++ b/.github/scripts/install-binary-tools.sh @@ -30,5 +30,10 @@ while read -r name type url extra; do chmod +x "$dest/$name" rm -rf "$tmpdir" ;; + jar) + wget -q "$url" -O "$dest/$name.jar" + printf '#!/usr/bin/env bash\nexec java -jar "%s/%s.jar" "$@"\n' "$(cd "$dest" && pwd)" "$name" > "$dest/$name" + chmod +x "$dest/$name" + ;; esac done < "$manifest" diff --git a/.github/tools/binary.txt b/.github/tools/binary.txt index 524d567..5dcdab5 100644 --- a/.github/tools/binary.txt +++ b/.github/tools/binary.txt @@ -1,7 +1,12 @@ alejandra bin https://github.com/kamadorueda/alejandra/releases/download/4.0.0/alejandra-x86_64-unknown-linux-musl buf bin https://github.com/bufbuild/buf/releases/download/v1.47.2/buf-Linux-x86_64 +hadolint bin https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 checkmake bin https://github.com/mrtazz/checkmake/releases/download/0.2.2/checkmake-0.2.2.linux.amd64 deno zip https://github.com/denoland/deno/releases/download/v2.1.4/deno-x86_64-unknown-linux-gnu.zip +detekt jar https://github.com/detekt/detekt/releases/download/v1.23.7/detekt-cli-1.23.7-all.jar hlint tar https://github.com/ndmitchell/hlint/releases/download/v3.10/hlint-3.10-x86_64-linux.tar.gz hlint-3.10/hlint latexindent bin https://github.com/cmhughes/latexindent.pl/releases/download/V3.24.4/latexindent-linux swiftformat zip https://github.com/nicklockwood/SwiftFormat/releases/download/0.55.3/swiftformat_linux.zip swiftformat_linux +cbfmt tar https://github.com/lukas-reineke/cbfmt/releases/download/v0.2.0/cbfmt_linux-x86_64_v0.2.0.tar.gz cbfmt_linux-x86_64_v0.2.0/cbfmt +dprint zip https://github.com/dprint/dprint/releases/download/0.49.0/dprint-x86_64-unknown-linux-gnu.zip +ktlint bin https://github.com/pinterest/ktlint/releases/download/1.8.0/ktlint diff --git a/.github/tools/npm.txt b/.github/tools/npm.txt index e83b681..f690d5f 100644 --- a/.github/tools/npm.txt +++ b/.github/tools/npm.txt @@ -2,3 +2,6 @@ prettier @biomejs/biome sql-formatter @taplo/cli +eslint +eslint_d +stylelint diff --git a/.github/tools/pip.txt b/.github/tools/pip.txt index ada9cb6..1be75bd 100644 --- a/.github/tools/pip.txt +++ b/.github/tools/pip.txt @@ -5,6 +5,7 @@ cpplint docformatter flake8 mypy +pylint ruff sqlfluff yapf diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7a220a9..e181a68 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -90,6 +90,7 @@ jobs: - name: Install tools run: | xargs -L1 go install < .github/tools/go.txt + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.64.8 luarocks install busted --local luarocks install nlua --local - name: Clone guard.nvim @@ -163,13 +164,17 @@ jobs: with: neovim: true version: nightly + - uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 - uses: leso-kn/gh-actions-lua@master with: luaVersion: "5.1" - uses: hishamhm/gh-actions-luarocks@master - name: Install tools run: | - sudo apt-get install -y zsh + sudo apt-get install -y zsh shellcheck luarocks install busted --local luarocks install nlua --local bash .github/scripts/install-binary-tools.sh "$HOME/.local/bin" @@ -205,3 +210,62 @@ jobs: export LUA_PATH="lua/?.lua;lua/?/init.lua;$LUA_PATH" busted --lua nlua test/apt/*_spec.lua + test-dotnet: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.0' + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install tools + run: | + dotnet tool install -g csharpier + luarocks install busted --local + luarocks install nlua --local + - name: Clone guard.nvim + run: git clone --depth 1 https://github.com/nvimdev/guard.nvim && mv guard.nvim/lua/guard lua/ + - name: Run tests + run: | + export LUA_PATH="lua/?.lua;lua/?/init.lua;$LUA_PATH" + busted --lua nlua test/dotnet/*_spec.lua + + test-ruby: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.3' + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install tools + run: | + gem install rubocop bundler + luarocks install busted --local + luarocks install nlua --local + - name: Setup rubocop Gemfile + run: | + mkdir -p /tmp/rubocop-test + printf "source 'https://rubygems.org'\ngem 'rubocop'\n" > /tmp/rubocop-test/Gemfile + cd /tmp/rubocop-test && bundle install + - name: Clone guard.nvim + run: git clone --depth 1 https://github.com/nvimdev/guard.nvim && mv guard.nvim/lua/guard lua/ + - name: Run tests + run: | + export LUA_PATH="lua/?.lua;lua/?/init.lua;$LUA_PATH" + busted --lua nlua test/ruby/*_spec.lua + diff --git a/test/binary/buf_spec.lua b/test/binary/buf_spec.lua new file mode 100644 index 0000000..7040439 --- /dev/null +++ b/test/binary/buf_spec.lua @@ -0,0 +1,20 @@ +describe('buf', function() + local tmpdir = vim.fn.getcwd() .. '/tmp-buf-test' + + setup(function() + vim.fn.mkdir(tmpdir, 'p') + end) + + teardown(function() + vim.fn.delete(tmpdir, 'rf') + end) + + it('can format', function() + local formatted = require('test.helper').run_fmt('buf', 'proto', { + 'syntax="proto3";', + 'package test;', + 'message Foo{string bar=1;}', + }, { tmpdir = tmpdir }) + assert.is_true(#formatted > 3) + end) +end) diff --git a/test/binary/cbfmt_spec.lua b/test/binary/cbfmt_spec.lua new file mode 100644 index 0000000..9e31cc8 --- /dev/null +++ b/test/binary/cbfmt_spec.lua @@ -0,0 +1,25 @@ +describe('cbfmt', function() + local tmpdir = vim.fn.getcwd() .. '/tmp-cbfmt-test' + + setup(function() + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ '[languages]' }, tmpdir .. '/.cbfmt.toml') + end) + + teardown(function() + vim.fn.delete(tmpdir, 'rf') + end) + + it('can format', function() + local formatted = require('test.helper').run_fmt('cbfmt', 'md', { + '# Title', + '', + 'Some text.', + }, { cwd = tmpdir }) + assert.are.same({ + '# Title', + '', + 'Some text.', + }, formatted) + end) +end) diff --git a/test/binary/detekt_spec.lua b/test/binary/detekt_spec.lua new file mode 100644 index 0000000..f94f6d1 --- /dev/null +++ b/test/binary/detekt_spec.lua @@ -0,0 +1,24 @@ +describe('detekt', function() + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('detekt', 'kt', { + [[fun main() {]], + [[ val x = 42]], + [[ if (x > 0) {]], + [[ println(x)]], + [[ }]], + [[}]], + }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'detekt', + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('detekt', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/binary/dprint_spec.lua b/test/binary/dprint_spec.lua new file mode 100644 index 0000000..8a4e58e --- /dev/null +++ b/test/binary/dprint_spec.lua @@ -0,0 +1,28 @@ +describe('dprint', function() + local tmpdir = vim.fn.getcwd() .. '/tmp-dprint-test' + + setup(function() + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + '{', + ' "typescript": {},', + ' "plugins": [', + ' "https://plugins.dprint.dev/typescript-0.93.3.wasm"', + ' ]', + '}', + }, tmpdir .. '/dprint.json') + end) + + teardown(function() + vim.fn.delete(tmpdir, 'rf') + end) + + it('can format', function() + local formatted = require('test.helper').run_fmt('dprint', 'ts', { + 'const x=1;', + 'function foo( ){return x}', + }, { cwd = tmpdir, tmpdir = tmpdir }) + assert.is_true(#formatted > 0) + assert.is_truthy(formatted[1]:find('const x')) + end) +end) diff --git a/test/binary/hadolint_spec.lua b/test/binary/hadolint_spec.lua new file mode 100644 index 0000000..2bfa1a0 --- /dev/null +++ b/test/binary/hadolint_spec.lua @@ -0,0 +1,21 @@ +describe('hadolint', function() + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('hadolint', 'dockerfile', { + [[FROM ubuntu]], + [[RUN apt-get install python]], + }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'hadolint', + severity = vim.diagnostic.severity.WARN, + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('hadolint', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/binary/ktlint_spec.lua b/test/binary/ktlint_spec.lua new file mode 100644 index 0000000..98093c2 --- /dev/null +++ b/test/binary/ktlint_spec.lua @@ -0,0 +1,22 @@ +describe('ktlint', function() + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('ktlint', 'kt', { + 'fun main() {', + ' val x=1', + ' println(x)', + '}', + }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'ktlint', + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('ktlint', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/binary/shellcheck_spec.lua b/test/binary/shellcheck_spec.lua new file mode 100644 index 0000000..9913321 --- /dev/null +++ b/test/binary/shellcheck_spec.lua @@ -0,0 +1,22 @@ +describe('shellcheck', function() + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('shellcheck', 'sh', { + [[#!/bin/sh]], + [[echo $FOO]], + }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'shellcheck', + severity = vim.diagnostic.severity.INFO, + message_pat = 'Double quote', + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('shellcheck', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/dotnet/csharpier_spec.lua b/test/dotnet/csharpier_spec.lua new file mode 100644 index 0000000..2429d22 --- /dev/null +++ b/test/dotnet/csharpier_spec.lua @@ -0,0 +1,9 @@ +describe('csharpier', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('csharpier', 'cs', { + [[class A{void M(){int x=1;}}]], + }) + assert.is_true(#formatted > 1) + assert.is_true(formatted[1]:find('class A') ~= nil) + end) +end) diff --git a/test/go/golangci_lint_spec.lua b/test/go/golangci_lint_spec.lua new file mode 100644 index 0000000..c07b22c --- /dev/null +++ b/test/go/golangci_lint_spec.lua @@ -0,0 +1,35 @@ +describe('golangci_lint', function() + local tmpdir = vim.fn.getcwd() .. '/tmp-golangci-lint-test' + + setup(function() + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + 'module testmod', + '', + 'go 1.21', + }, tmpdir .. '/go.mod') + end) + + teardown(function() + vim.fn.delete(tmpdir, 'rf') + end) + + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('golangci_lint', 'go', { + 'package main', + '', + 'import "fmt"', + '', + 'func main() {', + '\tfmt.Errorf("unused error")', + '}', + }, { cwd = tmpdir, tmpdir = tmpdir }) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/helper.lua b/test/helper.lua index ef63342..d57204a 100644 --- a/test/helper.lua +++ b/test/helper.lua @@ -1,12 +1,14 @@ local M = {} local api = vim.api -function M.run_fmt(name, ft, input) +function M.run_fmt(name, ft, input, opts) + opts = opts or {} local config = require('guard-collection.formatter')[name] assert(config, 'unknown formatter: ' .. name) assert(not config.fn, name .. ' uses custom fn, not testable this way') local cmd = vim.list_extend({ config.cmd }, config.args or {}) - local tmpfile = '/tmp/guard-test.' .. ft + local dir = opts.tmpdir or '/tmp' + local tmpfile = dir .. '/guard-test.' .. ft if config.fname then vim.fn.writefile(input, tmpfile) table.insert(cmd, tmpfile) @@ -14,6 +16,7 @@ function M.run_fmt(name, ft, input) local result = vim .system(cmd, { stdin = config.stdin and (table.concat(input, '\n') .. '\n') or nil, + cwd = opts.cwd, }) :wait() assert(result.code == 0, name .. ' exited ' .. result.code .. ': ' .. (result.stderr or '')) @@ -24,12 +27,14 @@ function M.run_fmt(name, ft, input) end end -function M.run_lint(name, ft, input) +function M.run_lint(name, ft, input, opts) + opts = opts or {} local linter = require('guard-collection.linter')[name] assert(linter, 'unknown linter: ' .. name) assert(not linter.fn, name .. ' uses custom fn — test parse() directly instead') local input_str = table.concat(input, '\n') .. '\n' - local tmpfile = '/tmp/guard-test.' .. ft + local dir = opts.tmpdir or '/tmp' + local tmpfile = dir .. '/guard-test.' .. ft vim.fn.writefile(input, tmpfile) local bufnr = api.nvim_create_buf(false, true) local cmd = vim.list_extend({ linter.cmd }, linter.args or {}) @@ -39,6 +44,7 @@ function M.run_lint(name, ft, input) local result = vim .system(cmd, { stdin = linter.stdin and input_str or nil, + cwd = opts.cwd, }) :wait() local output = result.stdout or '' @@ -49,6 +55,31 @@ function M.run_lint(name, ft, input) return bufnr, diags end +function M.assert_diag(d, expect) + local a = require('luassert') + if expect.bufnr then + a.equal(expect.bufnr, d.bufnr) + end + if expect.source then + a.equal(expect.source, d.source) + end + if expect.severity then + a.equal(expect.severity, d.severity) + end + if expect.lnum then + a.equal(expect.lnum, d.lnum) + end + if expect.code then + a.equal(expect.code, d.code) + end + if expect.message_pat then + a.is_true( + d.message ~= nil and d.message:find(expect.message_pat, 1, true) ~= nil, + ('expected message containing %q, got %q'):format(expect.message_pat, d.message or '') + ) + end +end + function M.get_linter(name) local linter = require('guard-collection.linter')[name] assert(linter, 'unknown linter: ' .. name) diff --git a/test/npm/eslint_d_spec.lua b/test/npm/eslint_d_spec.lua new file mode 100644 index 0000000..465a6af --- /dev/null +++ b/test/npm/eslint_d_spec.lua @@ -0,0 +1,42 @@ +describe('eslint_d', function() + local tmpdir = vim.fn.getcwd() .. '/tmp-eslint-d-test' + + setup(function() + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + 'module.exports = [{ rules: { "no-unused-vars": "error" } }];', + }, tmpdir .. '/eslint.config.js') + end) + + teardown(function() + vim.fn.delete(tmpdir, 'rf') + end) + + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('eslint_d', 'js', { + 'const x = 1;', + }, { cwd = tmpdir, tmpdir = tmpdir }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'eslint_d', + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('eslint_d', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) + + it('can format', function() + vim.fn.writefile({ + 'module.exports = [{ rules: { "semi": ["error", "always"] } }];', + }, tmpdir .. '/eslint.config.js') + local formatted = require('test.helper').run_fmt('eslint_d', 'js', { + 'const x = 1', + }, { cwd = tmpdir, tmpdir = tmpdir }) + assert.are.same({ 'const x = 1;' }, formatted) + end) +end) diff --git a/test/npm/eslint_spec.lua b/test/npm/eslint_spec.lua new file mode 100644 index 0000000..21c5566 --- /dev/null +++ b/test/npm/eslint_spec.lua @@ -0,0 +1,32 @@ +describe('eslint', function() + local tmpdir = vim.fn.getcwd() .. '/tmp-eslint-test' + + setup(function() + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + 'module.exports = [{ rules: { "no-unused-vars": "error" } }];', + }, tmpdir .. '/eslint.config.js') + end) + + teardown(function() + vim.fn.delete(tmpdir, 'rf') + end) + + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('eslint', 'js', { + 'const x = 1;', + }, { cwd = tmpdir, tmpdir = tmpdir }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'eslint', + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('eslint', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/npm/stylelint_spec.lua b/test/npm/stylelint_spec.lua new file mode 100644 index 0000000..06d654a --- /dev/null +++ b/test/npm/stylelint_spec.lua @@ -0,0 +1,32 @@ +describe('stylelint', function() + local tmpdir = vim.fn.getcwd() .. '/tmp-stylelint-test' + + setup(function() + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + '{ "rules": { "color-no-invalid-hex": true } }', + }, tmpdir .. '/.stylelintrc.json') + end) + + teardown(function() + vim.fn.delete(tmpdir, 'rf') + end) + + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('stylelint', 'css', { + 'a { color: #fff1az; }', + }, { cwd = tmpdir, tmpdir = tmpdir }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'stylelint', + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('stylelint', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/pip/mypy_spec.lua b/test/pip/mypy_spec.lua index 40fa9a9..f915015 100644 --- a/test/pip/mypy_spec.lua +++ b/test/pip/mypy_spec.lua @@ -1,24 +1,17 @@ describe('mypy', function() it('can lint', function() - local linter = require('test.helper').get_linter('mypy') - local tmpfile = '/tmp/guard-test.py' - local input = { + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('mypy', 'py', { 'def add(x: int, y: int) -> int:', ' return x + y', '', 'add("hello", "world")', - } - vim.fn.writefile(input, tmpfile) - local bufnr = vim.api.nvim_create_buf(false, true) - local cmd = vim.list_extend({ linter.cmd }, linter.args or {}) - table.insert(cmd, tmpfile) - local result = vim.system(cmd):wait() - local output = result.stdout or '' - if output == '' then - output = result.stderr or '' - end - local diagnostics = linter.parse(output, bufnr) + }) assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'mypy', + }) for _, d in ipairs(diagnostics) do assert.equal(bufnr, d.bufnr) assert.equal('mypy', d.source) diff --git a/test/pip/pylint_spec.lua b/test/pip/pylint_spec.lua new file mode 100644 index 0000000..f209df1 --- /dev/null +++ b/test/pip/pylint_spec.lua @@ -0,0 +1,20 @@ +describe('pylint', function() + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('pylint', 'py', { + [[import os]], + [[x = 1]], + }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'pylint', + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('pylint', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/pip/ruff_fix_spec.lua b/test/pip/ruff_fix_spec.lua new file mode 100644 index 0000000..91c862b --- /dev/null +++ b/test/pip/ruff_fix_spec.lua @@ -0,0 +1,15 @@ +describe('ruff_fix', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('ruff_fix', 'py', { + [[import os]], + [[import sys]], + [[]], + [[print(sys.argv)]], + }) + assert.are.same({ + [[import sys]], + [[]], + [[print(sys.argv)]], + }, formatted) + end) +end) diff --git a/test/pip/ruff_spec.lua b/test/pip/ruff_spec.lua index 866b13f..8aecb47 100644 --- a/test/pip/ruff_spec.lua +++ b/test/pip/ruff_spec.lua @@ -19,4 +19,23 @@ describe('ruff', function() [[print(f"The factorial of {a} is: {foo(a)}")]], }, formatted) end) + + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('ruff', 'py', { + [[import os]], + [[x = 1]], + }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + source = 'ruff', + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('ruff', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) end) diff --git a/test/pip/sqlfluff_spec.lua b/test/pip/sqlfluff_spec.lua index cb8452b..664414f 100644 --- a/test/pip/sqlfluff_spec.lua +++ b/test/pip/sqlfluff_spec.lua @@ -1,22 +1,23 @@ describe('sqlfluff', function() + local tmpdir = vim.fn.getcwd() .. '/tmp-sqlfluff-test' + + setup(function() + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ '[sqlfluff]', 'dialect = ansi' }, tmpdir .. '/.sqlfluff') + end) + + teardown(function() + vim.fn.delete(tmpdir, 'rf') + end) + it('can format', function() - local config = require('guard-collection.formatter').sqlfluff - local cmd = vim.list_extend({ config.cmd }, config.args) - vim.list_extend(cmd, { '--dialect', 'ansi' }) - local input = { + local formatted = require('test.helper').run_fmt('sqlfluff', 'sql', { [[SELECT *]], [[FROM]], [[ World ]], [[WHERE "Someone"]], [[ LIKE '%YOU%']], - } - local result = vim - .system(cmd, { - stdin = table.concat(input, '\n') .. '\n', - }) - :wait() - assert(result.code == 0, 'sqlfluff exited ' .. result.code .. ': ' .. (result.stderr or '')) - local formatted = vim.split(result.stdout, '\n', { trimempty = true }) + }, { cwd = tmpdir }) assert.are.same({ [[SELECT *]], [[FROM]], @@ -28,22 +29,12 @@ describe('sqlfluff', function() end) it('can fix', function() - local config = require('guard-collection.formatter').sqlfluff_fix - local cmd = vim.list_extend({ config.cmd }, config.args) - vim.list_extend(cmd, { '--dialect', 'ansi' }) - local input = { + local formatted = require('test.helper').run_fmt('sqlfluff_fix', 'sql', { [[SELECT]], [[ a + b AS foo,]], [[ c AS bar]], [[FROM my_table]], - } - local result = vim - .system(cmd, { - stdin = table.concat(input, '\n') .. '\n', - }) - :wait() - assert(result.code == 0, 'sqlfluff_fix exited ' .. result.code .. ': ' .. (result.stderr or '')) - local formatted = vim.split(result.stdout, '\n', { trimempty = true }) + }, { cwd = tmpdir }) assert.are.same({ [[SELECT]], [[ c AS bar,]], diff --git a/test/ruby/rubocop_spec.lua b/test/ruby/rubocop_spec.lua new file mode 100644 index 0000000..0a1f24b --- /dev/null +++ b/test/ruby/rubocop_spec.lua @@ -0,0 +1,28 @@ +describe('rubocop', function() + local tmpdir = '/tmp/rubocop-test' + + setup(function() + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + "source 'https://rubygems.org'", + "gem 'rubocop'", + }, tmpdir .. '/Gemfile') + vim.system({ 'bundle', 'install' }, { cwd = tmpdir }):wait() + end) + + it('can lint', function() + local helper = require('test.helper') + local bufnr, diagnostics = helper.run_lint('rubocop', 'rb', { + [[x = { :a=>1,:b => 2 }]], + }, { cwd = tmpdir }) + assert.is_true(#diagnostics > 0) + helper.assert_diag(diagnostics[1], { + bufnr = bufnr, + }) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end)