diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..ff4182a --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,436 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: JohnnyMorganz/stylua-action@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + version: 2.0.2 + args: --check . + + coverage: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - name: Clone guard.nvim + run: git clone --depth 1 https://github.com/nvimdev/guard.nvim && mv guard.nvim/lua/guard lua/ + - name: Check test coverage + run: | + export LUA_PATH="lua/?.lua;lua/?/init.lua;$LUA_PATH" + nvim -l scripts/coverage.lua + + test-pip: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install tools + run: | + pip install -q autopep8 black cmake-format codespell cpplint djhtml docformatter flake8 isort mdformat mypy pylint ruff sqlfluff yamlfix yapf + 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/pip/*_spec.lua + + test-npm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: actions/setup-node@v4 + with: + node-version: 20 + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install tools + run: | + npm install -g prettier @fsouza/prettierd @biomejs/biome sql-formatter @taplo/cli eslint eslint_d stylelint + 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/npm/*_spec.lua + + test-go: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: actions/setup-go@v5 + with: + go-version: stable + cache: false + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install tools + run: | + go install golang.org/x/tools/cmd/goimports@latest + go install mvdan.cc/gofumpt@latest + go install github.com/segmentio/golines@latest + go install github.com/google/yamlfmt/cmd/yamlfmt@latest + 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 + run: git clone --depth 1 https://github.com/nvimdev/guard.nvim && mv guard.nvim/lua/guard lua/ + - name: Run tests + run: | + export PATH="$HOME/go/bin:$PATH" + export LUA_PATH="lua/?.lua;lua/?/init.lua;$LUA_PATH" + busted --lua nlua test/go/*_spec.lua + + test-rust: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install test tools + run: | + 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/rust/*_spec.lua + + test-lua: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install tools + run: | + luarocks install busted --local + luarocks install nlua --local + luarocks install luacheck --local + luarocks install fnlfmt --local + mkdir -p $HOME/.local/bin + wget -q https://github.com/Kampfkarren/selene/releases/download/0.28.0/selene-0.28.0-linux.zip + unzip -q selene-0.28.0-linux.zip -d $HOME/.local/bin + chmod +x $HOME/.local/bin/selene + wget -q https://github.com/JohnnyMorganz/StyLua/releases/download/v2.0.2/stylua-linux-x86_64.zip + unzip -q stylua-linux-x86_64.zip -d $HOME/.local/bin + chmod +x $HOME/.local/bin/stylua + - 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 PATH="$HOME/.local/bin:$PATH" + export LUA_PATH="lua/?.lua;lua/?/init.lua;$LUA_PATH" + busted --lua nlua test/lua/*_spec.lua + + test-binary: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: dart-lang/setup-dart@v1 + - uses: mlugg/setup-zig@v2 + with: + version: 0.15.2 + - 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 jq libxml2-utils shellcheck fish pgformatter + luarocks install busted --local + luarocks install nlua --local + mkdir -p $HOME/.local/bin + cd $HOME/.local/bin + wget -q https://github.com/kamadorueda/alejandra/releases/download/4.0.0/alejandra-x86_64-unknown-linux-musl -O alejandra && chmod +x alejandra + wget -q https://github.com/bufbuild/buf/releases/download/v1.47.2/buf-Linux-x86_64 -O buf && chmod +x buf + wget -q https://github.com/mrtazz/checkmake/releases/download/0.2.2/checkmake-0.2.2.linux.amd64 -O checkmake && chmod +x checkmake + wget -q https://github.com/denoland/deno/releases/download/v2.1.4/deno-x86_64-unknown-linux-gnu.zip && unzip -q deno-x86_64-unknown-linux-gnu.zip && chmod +x deno + wget -q https://github.com/hadolint/hadolint/releases/download/v2.12.0/hadolint-Linux-x86_64 -O hadolint && chmod +x hadolint + wget -q https://github.com/crate-ci/typos/releases/download/v1.43.3/typos-v1.43.3-x86_64-unknown-linux-musl.tar.gz -O typos.tar.gz && tar xzf typos.tar.gz && chmod +x typos && rm typos.tar.gz + wget -q https://github.com/typstyle-rs/typstyle/releases/download/v0.14.4/typstyle-x86_64-unknown-linux-gnu -O typstyle && chmod +x typstyle + wget -q https://github.com/cmhughes/latexindent.pl/releases/download/V3.24.4/latexindent-linux -O latexindent && chmod +x latexindent + wget -q https://github.com/mvdan/sh/releases/download/v3.10.0/shfmt_v3.10.0_linux_amd64 -O shfmt && chmod +x shfmt + wget -q https://github.com/nicklockwood/SwiftFormat/releases/download/0.55.3/swiftformat_linux.zip && unzip -q swiftformat_linux.zip && mv swiftformat_linux swiftformat && chmod +x swiftformat + wget -q https://github.com/lukas-reineke/cbfmt/releases/download/v0.2.0/cbfmt_linux-x86_64_v0.2.0.tar.gz -O cbfmt.tar.gz && tar xzf cbfmt.tar.gz -C . cbfmt_linux-x86_64_v0.2.0/cbfmt --strip-components=1 && chmod +x cbfmt && rm cbfmt.tar.gz + wget -q https://github.com/pinterest/ktlint/releases/download/1.8.0/ktlint && chmod +x ktlint + wget -q https://github.com/google/google-java-format/releases/download/v1.34.1/google-java-format-1.34.1-all-deps.jar && printf '#!/bin/sh\njava -jar %s/google-java-format-1.34.1-all-deps.jar "$@"\n' "$HOME/.local/bin" > google-java-format && chmod +x google-java-format + wget -q https://github.com/tombi-toml/tombi/releases/download/v0.7.27/tombi-cli-0.7.27-x86_64-unknown-linux-musl.gz -O tombi.gz && gunzip tombi.gz && chmod +x tombi + wget -q https://github.com/detekt/detekt/releases/download/v1.23.7/detekt-cli-1.23.7-all.jar && printf '#!/bin/sh\njava -jar %s/detekt-cli-1.23.7-all.jar "$@"\n' "$HOME/.local/bin" > detekt && chmod +x detekt + wget -q https://repo1.maven.org/maven2/com/facebook/ktfmt/0.52/ktfmt-0.52-jar-with-dependencies.jar && printf '#!/bin/sh\njava -jar %s/ktfmt-0.52-jar-with-dependencies.jar "$@"\n' "$HOME/.local/bin" > ktfmt && chmod +x ktfmt + wget -q https://github.com/dprint/dprint/releases/download/0.49.0/dprint-x86_64-unknown-linux-gnu.zip && unzip -q dprint-x86_64-unknown-linux-gnu.zip -d . && chmod +x dprint + wget -q https://github.com/ndmitchell/hlint/releases/download/v3.10/hlint-3.10-x86_64-linux.tar.gz -O hlint.tar.gz && tar xzf hlint.tar.gz hlint-3.10/hlint --strip-components=1 && chmod +x hlint && rm hlint.tar.gz + wget -q https://github.com/tweag/ormolu/releases/download/0.8.0.2/ormolu-x86_64-linux.zip && unzip -q ormolu-x86_64-linux.zip && chmod +x ormolu + - 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 PATH="$HOME/.local/bin:$PATH" + export LUA_PATH="lua/?.lua;lua/?/init.lua;$LUA_PATH" + busted --lua nlua test/binary/*_spec.lua + + test-clang: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - 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 clang-format clang-tidy + 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" + for f in test/clang/*_spec.lua; do busted --lua nlua "$f"; done + + 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 + + test-clojure: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + 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 Clojure CLI + run: | + curl -L -O https://github.com/clojure/brew-install/releases/latest/download/linux-install.sh + chmod +x linux-install.sh + sudo ./linux-install.sh + - name: Install tools + run: | + mkdir -p $HOME/.local/bin + printf '#!/bin/sh\nclojure -Sdeps '"'"'{:deps {dev.weavejester/cljfmt {:mvn/version "0.13.0"}}}'"'"' -M -m cljfmt.main "$@"\n' > $HOME/.local/bin/cljfmt && chmod +x $HOME/.local/bin/cljfmt + luarocks install busted --local + luarocks install nlua --local + - name: Pre-warm cljfmt deps + run: | + export PATH="$HOME/.local/bin:$PATH" + echo "" | cljfmt fix - || true + - 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 PATH="$HOME/.local/bin:$PATH" + export LUA_PATH="lua/?.lua;lua/?/init.lua;$LUA_PATH" + busted --lua nlua test/clojure/*_spec.lua + + test-elixir: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: erlef/setup-beam@v1 + with: + otp-version: '27' + elixir-version: '1.17' + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install tools + run: | + 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/elixir/*_spec.lua + + test-nix: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: cachix/install-nix-action@v27 + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install tools + run: | + nix profile install nixpkgs#nixfmt-rfc-style + 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/nix/*_spec.lua + + test-swift: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rhysd/action-setup-vim@v1 + with: + neovim: true + version: nightly + - uses: swift-actions/setup-swift@v2 + with: + swift-version: '6.0' + - uses: leso-kn/gh-actions-lua@master + with: + luaVersion: "5.1" + - uses: hishamhm/gh-actions-luarocks@master + - name: Install tools + run: | + 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/swift/*_spec.lua diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index ca8ae6c..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,75 +0,0 @@ -name: CI - -on: [push, pull_request] - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Stylua - uses: JohnnyMorganz/stylua-action@v3 - with: - token: ${{ secrets.GITHUB_TOKEN }} - version: latest - args: --check . - - test: - name: Run Test - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/checkout@v3 - - - name: Test Setup (Neovim Nightly) - uses: rhysd/action-setup-vim@v1 - id: vim - with: - neovim: true - version: nightly - - - name: Test Setup (Lua) - uses: leafo/gh-actions-lua@v10 - with: - luaVersion: "luajit-openresty" - - - name: Test Setup (Luarocks) - uses: leafo/gh-actions-luarocks@v4 - - - name: Package Manager Setup (Python) - uses: actions/setup-python@v4 - - - name: Package Manager Setup (Rust) - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - components: rustfmt, cargo - - - name: Package Manager Setup (npm) - uses: actions/setup-node@v3 - with: - node-version: 18 - - - name: Package Manager Setup (homebrew) - id: set-up-homebrew - uses: Homebrew/actions/setup-homebrew@master - - - name: Install Tools - shell: bash - run: bash ./test/setup.sh - - - name: Formatter Test - shell: bash - run: | - source ./test/env.sh - vusted ./test/formatter - - - name: Linter Test - shell: bash - if: always() - run: | - source ./test/env.sh - for linter_test in ./test/linter/*_spec.lua; do - vusted $linter_test - done diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ceb2b98 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +CLAUDE.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cad0f7e..6878a41 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,107 +1,75 @@ # Contributing to guard-collection - Add your config to `formatter.lua` or `linter/.lua`, if it's a linter don't forget to export it in `linter/init.lua` -- Write a test. If it's a formatter, show that the config works by giving an example input and verify that the file did got formatted as intended. For example: +- Write a test in the appropriate `test//` directory. Tests run tools synchronously via `vim.system():wait()`, bypassing guard.nvim's async pipeline. + +Formatter example: ```lua describe('black', function() it('can format', function() - -- pre-test setup - local ft = require('guard.filetype') - ft('python'):fmt('black') - -- Giving example input to the helper - -- the helper creates a new buffer with it, formats, and returns the formatted output - local formatted = require('test.formatter.helper').test_with('python', { - -- The input code should somewhat reflect the filetype + local formatted = require('test.helper').run_fmt('black', 'python', { [[def foo(n):]], [[ if n in (1,2,3):]], [[ return n+1]], - [[a, b = 1, 2]], - [[b, a = a, b]], - [[print( f"The factorial of {a} is: {foo(a)}")]], }) - -- Show that the input is indeed formatted as intended assert.are.same({ [[def foo(n):]], [[ if n in (1, 2, 3):]], [[ return n + 1]], - [[]], - [[]], - [[a, b = 1, 2]], - [[b, a = a, b]], - [[print(f"The factorial of {a} is: {foo(a)}")]], }, formatted) end) end) ``` -- Or if it's a linter, show that the linter's output is converted correctly into neovim diagnostics +Linter example: ```lua -describe('selene', function() +describe('flake8', function() it('can lint', function() - -- pre-test setup - local helper = require('test.linter.helper') - local ns = helper.namespace - local ft = require('guard.filetype') - ft('lua'):lint('selene') - require('guard').setup() - -- Giving example input to the helper - -- the helper creates a new buffer with it, requires lint, and returns the diagnostics - local buf, diagnostics = require('test.linter.helper').test_with('lua', { - -- Make sure the input actually has some problems that the linter detects - [[local M = {}]], - [[function M.foo()]], - [[ print("foo")]], - [[end]], - [[U.bar()]], - [[return M]], + local helper = require('test.helper') + local buf, diagnostics = helper.run_lint('flake8', 'python', { + [[import os]], }) - -- Show that the diagnostics is indeed valid - assert.are.same({ - { - bufnr = buf, - col = 0, - end_col = 0, - end_lnum = 4, - lnum = 4, - message = '`U` is not defined [undefined_variable]', - -- sometimes the namespace is not fixed - namespace = ns, - severity = 1, - source = 'selene', - }, - }, diagnostics) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(buf, d.bufnr) + assert.equal('flake8', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end end) end) - ``` -- To run the test you just created, install [vusted](https://github.com/notomo/vusted) - ```shell - luarocks --lua-version=5.1 install vusted - ``` -- Create a symlink so that vusted recognizes guard.nvim namespaces +For linters with a custom `fn` (cpplint, checkmake, zsh), run the command directly and test `parse()`: -```shell -ln -s ~/.local/share/nvim/lazy/guard.nvim/lua/guard lua +```lua +describe('cpplint', function() + it('can lint', function() + local linter = require('test.helper').get_linter('cpplint') + local tmpfile = '/tmp/guard-test.cpp' + vim.fn.writefile({ [[int main(){int x=1;}]] }, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim.system({ 'cpplint', '--filter=-legal/copyright', tmpfile }, {}):wait() + local diagnostics = linter.parse(result.stderr or '', bufnr) + assert.is_true(#diagnostics > 0) + end) +end) ``` -- Run the test and make sure it passes - +- Add your tool to CI in `.github/workflows/ci.yaml` under the appropriate job +- Run the test locally: ```shell - - vusted ./test/formatter/_spec.lua - # or - vusted ./test/linter/\_spec.lua - - ok 1 - can format - ok 1 - can lint + # requires: neovim, lua 5.1, luarocks, busted, nlua + # also requires guard.nvim cloned: git clone --depth 1 https://github.com/nvimdev/guard.nvim && mv guard.nvim/lua/guard lua/ + make test-pip # or whichever category ``` - -- Modify `test/setup.sh` so that CI installs your tool - -- Optionally, format the code with stylua +- Verify test coverage passes (CI enforces this): + ```shell + make coverage + ``` +- Format with stylua before submitting: ```shell stylua . ``` diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0caedfa --- /dev/null +++ b/Makefile @@ -0,0 +1,51 @@ +LUA_PATH := lua/?.lua;lua/?/init.lua;$(LUA_PATH) +export LUA_PATH + +.PHONY: lint coverage test test-pip test-npm test-go test-rust test-lua test-binary test-clang test-dotnet test-ruby test-clojure test-elixir test-nix test-swift + +lint: + stylua --check . + +coverage: + nvim -l scripts/coverage.lua + +test: test-pip test-npm test-go test-rust test-lua test-binary test-clang test-dotnet test-ruby test-clojure test-elixir test-nix test-swift + +test-pip: + busted --lua nlua test/pip/*_spec.lua + +test-npm: + busted --lua nlua test/npm/*_spec.lua + +test-go: + busted --lua nlua test/go/*_spec.lua + +test-rust: + busted --lua nlua test/rust/*_spec.lua + +test-lua: + busted --lua nlua test/lua/*_spec.lua + +test-binary: + busted --lua nlua test/binary/*_spec.lua + +test-clang: + @for f in test/clang/*_spec.lua; do busted --lua nlua "$$f"; done + +test-dotnet: + busted --lua nlua test/dotnet/*_spec.lua + +test-ruby: + busted --lua nlua test/ruby/*_spec.lua + +test-clojure: + busted --lua nlua test/clojure/*_spec.lua + +test-elixir: + busted --lua nlua test/elixir/*_spec.lua + +test-nix: + busted --lua nlua test/nix/*_spec.lua + +test-swift: + busted --lua nlua test/swift/*_spec.lua diff --git a/lua/guard-collection/formatter.lua b/lua/guard-collection/formatter.lua index 711dfbb..1c5357b 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,8 +299,7 @@ M.ruff = { M.ruff_fix = { cmd = 'ruff', - args = { '--fix', '-', '--stdin-filename' }, - stdin = true, + args = { 'check', '--fix' }, fname = true, } @@ -319,8 +318,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/cpplint.lua b/lua/guard-collection/linter/cpplint.lua new file mode 100644 index 0000000..4054c95 --- /dev/null +++ b/lua/guard-collection/linter/cpplint.lua @@ -0,0 +1,33 @@ +local lint = require('guard.lint') + +return { + fn = function(_, fname) + local co = assert(coroutine.running()) + vim.system({ 'cpplint', '--filter=-legal/copyright', fname }, {}, function(result) + coroutine.resume(co, result.stderr or '') + end) + return coroutine.yield() + end, + parse = function(result, bufnr) + local diags = {} + for line in result:gmatch('[^\n]+') do + local lnum, msg, cat, sev = line:match('^[^:]+:(%d+):%s*(.-)%s+%[([^%]]+)%]%s+%[(%d+)%]$') + if lnum then + local severity = tonumber(sev) >= 3 and vim.diagnostic.severity.ERROR + or vim.diagnostic.severity.WARN + table.insert( + diags, + lint.diag_fmt( + bufnr, + tonumber(lnum) - 1, + 0, + ('[%s] %s'):format(cat, msg), + severity, + 'cpplint' + ) + ) + end + end + return diags + end, +} diff --git a/lua/guard-collection/linter/init.lua b/lua/guard-collection/linter/init.lua index 51a6599..1a377de 100644 --- a/lua/guard-collection/linter/init.lua +++ b/lua/guard-collection/linter/init.lua @@ -3,6 +3,7 @@ return { checkmake = require('guard-collection.linter.checkmake'), ['clang-tidy'] = require('guard-collection.linter.clang-tidy'), codespell = require('guard-collection.linter.codespell'), + cpplint = require('guard-collection.linter.cpplint'), detekt = require('guard-collection.linter.detekt'), eslint = require('guard-collection.linter.eslint'), eslint_d = require('guard-collection.linter.eslint_d'), @@ -23,4 +24,5 @@ return { mypy = require('guard-collection.linter.mypy').mypy, mypyc = require('guard-collection.linter.mypy').mypyc, dmypy = require('guard-collection.linter.mypy').dmypy, + zsh = require('guard-collection.linter.zsh'), } 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/zsh.lua b/lua/guard-collection/linter/zsh.lua new file mode 100644 index 0000000..24a2e6b --- /dev/null +++ b/lua/guard-collection/linter/zsh.lua @@ -0,0 +1,24 @@ +local lint = require('guard.lint') + +return { + fn = function(_, fname) + local co = assert(coroutine.running()) + vim.system({ 'zsh', '-n', fname }, {}, function(result) + coroutine.resume(co, result.stderr or '') + end) + return coroutine.yield() + end, + parse = function(result, bufnr) + local diags = {} + for line in result:gmatch('[^\n]+') do + local lnum, msg = line:match(':(%d+): (.+)$') + if lnum then + table.insert( + diags, + lint.diag_fmt(bufnr, tonumber(lnum) - 1, 0, msg, vim.diagnostic.severity.ERROR, 'zsh') + ) + end + end + return diags + end, +} diff --git a/scripts/coverage.lua b/scripts/coverage.lua new file mode 100644 index 0000000..d12bbf6 --- /dev/null +++ b/scripts/coverage.lua @@ -0,0 +1,68 @@ +local skip = { + lsp = 'requires a running language server', + dmypy = 'mypy daemon mode; requires persistent server', + npm_groovy_lint = 'CodeNarc server warm-up hangs CI', + npm_groovy_lint_fix = 'CodeNarc server warm-up hangs CI', +} + +local formatters = require('guard-collection.formatter') +local linters = require('guard-collection.linter') + +local all_tools = {} +for name in pairs(formatters) do + if not skip[name] then + all_tools[name] = 'formatter' + end +end +for name in pairs(linters) do + if not skip[name] then + all_tools[name] = all_tools[name] and 'formatter+linter' or 'linter' + end +end + +local test_files = vim.fn.glob('test/**/*_spec.lua', false, true) +local covered = {} +for _, file in ipairs(test_files) do + local content = table.concat(vim.fn.readfile(file), '\n') + for name in pairs(all_tools) do + local escaped = vim.pesc(name) + local alt = escaped:gsub('_', '[ _]') + -- match 'name' in string literals (describe/run_fmt) or .name table access (require().tool) + if content:find('[\'"]' .. alt .. '[\'"]') or content:find('%.' .. escaped .. '[^%w_]') then + covered[name] = true + end + end +end + +local missing = {} +for name in pairs(all_tools) do + if not covered[name] then + table.insert(missing, name) + end +end +table.sort(missing) + +local total = vim.tbl_count(all_tools) +local skipped = vim.tbl_count(skip) +local covered_count = vim.tbl_count(covered) +local missing_count = #missing + +print( + string.format( + 'Tools: %d total, %d skipped, %d covered, %d missing', + total, + skipped, + covered_count, + missing_count + ) +) + +if missing_count > 0 then + print('\nMissing tests:') + for _, name in ipairs(missing) do + print(string.format(' %s (%s)', name, all_tools[name])) + end + os.exit(1) +end + +print('All testable tools have coverage.') diff --git a/test/binary/alejandra_spec.lua b/test/binary/alejandra_spec.lua new file mode 100644 index 0000000..897e41a --- /dev/null +++ b/test/binary/alejandra_spec.lua @@ -0,0 +1,10 @@ +describe('alejandra', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('alejandra', 'nix', { + [[{inputs={nixpkgs.url="github:NixOS/nixpkgs/nixos-unstable";};}]], + }) + assert.are.same({ + [[{inputs = {nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";};}]], + }, formatted) + end) +end) diff --git a/test/binary/buf_spec.lua b/test/binary/buf_spec.lua new file mode 100644 index 0000000..32e5786 --- /dev/null +++ b/test/binary/buf_spec.lua @@ -0,0 +1,53 @@ +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, cwd = tmpdir }) + assert.is_true(#formatted > 3) + end) + + it('can lint', function() + local linter = require('test.helper').get_linter('buf') + vim.fn.writefile({ 'version: v2' }, tmpdir .. '/buf.yaml') + local protofile = tmpdir .. '/test.proto' + vim.fn.writefile({ + 'syntax = "proto3";', + 'message Foo {', + ' string bar = 1;', + '}', + }, protofile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'buf', + 'lint', + '--error-format=json', + protofile, + }, { cwd = tmpdir }) + :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) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('buf', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/binary/cbfmt_spec.lua b/test/binary/cbfmt_spec.lua new file mode 100644 index 0000000..fa49568 --- /dev/null +++ b/test/binary/cbfmt_spec.lua @@ -0,0 +1,25 @@ +describe('cbfmt', function() + it('can format', function() + local tmpdir = '/tmp/cbfmt-test' + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ '[languages]' }, tmpdir .. '/.cbfmt.toml') + local input = { + '# Title', + '', + 'Some text.', + } + local result = vim + .system({ 'cbfmt', '--best-effort', '-p', 'markdown' }, { + stdin = table.concat(input, '\n') .. '\n', + cwd = tmpdir, + }) + :wait() + assert(result.code == 0, 'cbfmt exited ' .. result.code .. ': ' .. (result.stderr or '')) + local formatted = vim.split(result.stdout, '\n', { trimempty = true }) + assert.are.same({ + '# Title', + '', + 'Some text.', + }, formatted) + end) +end) diff --git a/test/binary/checkmake_spec.lua b/test/binary/checkmake_spec.lua new file mode 100644 index 0000000..adda48a --- /dev/null +++ b/test/binary/checkmake_spec.lua @@ -0,0 +1,28 @@ +describe('checkmake', function() + it('can lint', function() + local linter = require('test.helper').get_linter('checkmake') + local tmpfile = '/tmp/guard-test.make' + local input = { + [[all:]], + [[\techo hello]], + } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'checkmake', + '--format={{.FileName}}:{{.LineNumber}}: [{{.Rule}}] {{.Violation}}\n', + tmpfile, + }, {}) + :wait() + local output = result.stdout or '' + local diagnostics = linter.parse(output, bufnr) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('checkmake', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/binary/dart_spec.lua b/test/binary/dart_spec.lua new file mode 100644 index 0000000..c209797 --- /dev/null +++ b/test/binary/dart_spec.lua @@ -0,0 +1,9 @@ +describe('dart', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('dart', 'dart', { + [[void main(){print('hello');}]], + }) + assert.is_true(#formatted > 1) + assert.is_true(formatted[1]:find('void main') ~= nil) + end) +end) diff --git a/test/formatter/deno_fmt_spec.lua b/test/binary/deno_fmt_spec.lua similarity index 79% rename from test/formatter/deno_fmt_spec.lua rename to test/binary/deno_fmt_spec.lua index 1b359c4..90860ee 100644 --- a/test/formatter/deno_fmt_spec.lua +++ b/test/binary/deno_fmt_spec.lua @@ -1,9 +1,6 @@ describe('deno fmt', function() it('can format', function() - local ft = require('guard.filetype') - ft('typescript'):fmt('deno_fmt') - - local formatted = require('test.formatter.helper').test_with('typescript', { + local formatted = require('test.helper').run_fmt('deno_fmt', 'typescript', { [[function ]], [[ fibonacci(num:]], [[ number):]], diff --git a/test/binary/detekt_spec.lua b/test/binary/detekt_spec.lua new file mode 100644 index 0000000..9db3049 --- /dev/null +++ b/test/binary/detekt_spec.lua @@ -0,0 +1,29 @@ +describe('detekt', function() + it('can lint', function() + local linter = require('test.helper').get_linter('detekt') + local tmpfile = '/tmp/guard-test.kt' + local input = { + [[fun main() {]], + [[ val x = 42]], + [[ if (x > 0) {]], + [[ println(x)]], + [[ }]], + [[}]], + } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim.system({ 'detekt', '-i', tmpfile }):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) + 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..c68342b --- /dev/null +++ b/test/binary/dprint_spec.lua @@ -0,0 +1,26 @@ +describe('dprint', function() + it('can format', function() + local tmpdir = '/tmp/dprint-test' + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + '{', + ' "typescript": {},', + ' "plugins": ["https://plugins.dprint.dev/typescript-0.93.3.wasm"]', + '}', + }, tmpdir .. '/dprint.json') + local input = { + [[const x=1;]], + [[function foo( ){return x}]], + } + local result = vim + .system({ 'dprint', 'fmt', '--stdin', 'test.ts' }, { + stdin = table.concat(input, '\n') .. '\n', + cwd = tmpdir, + }) + :wait() + assert(result.code == 0, 'dprint exited ' .. result.code .. ': ' .. (result.stderr or '')) + local formatted = vim.split(result.stdout, '\n', { trimempty = true }) + assert.is_true(#formatted > 0) + assert.is_true(formatted[1]:find('const x') ~= nil) + end) +end) diff --git a/test/binary/fish_indent_spec.lua b/test/binary/fish_indent_spec.lua new file mode 100644 index 0000000..f2ea7ee --- /dev/null +++ b/test/binary/fish_indent_spec.lua @@ -0,0 +1,14 @@ +describe('fish_indent', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('fish_indent', 'fish', { + [[if test "$x" = "y"]], + [[echo hello]], + [[end]], + }) + assert.are.same({ + [[if test "$x" = y]], + [[ echo hello]], + [[end]], + }, formatted) + end) +end) diff --git a/test/binary/google-java-format_spec.lua b/test/binary/google-java-format_spec.lua new file mode 100644 index 0000000..38fb99f --- /dev/null +++ b/test/binary/google-java-format_spec.lua @@ -0,0 +1,9 @@ +describe('google-java-format', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('google-java-format', 'java', { + '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/binary/hadolint_spec.lua b/test/binary/hadolint_spec.lua new file mode 100644 index 0000000..0ba3f02 --- /dev/null +++ b/test/binary/hadolint_spec.lua @@ -0,0 +1,29 @@ +describe('hadolint', function() + it('can lint', function() + local linter = require('test.helper').get_linter('hadolint') + local tmpfile = '/tmp/guard-test.dockerfile' + local input = { + [[FROM ubuntu]], + [[RUN apt-get install python]], + } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'hadolint', + '--no-fail', + '--format=json', + tmpfile, + }) + :wait() + local output = result.stdout or '' + local diagnostics = linter.parse(output, bufnr) + assert.is_true(#diagnostics > 0) + 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/hlint_spec.lua b/test/binary/hlint_spec.lua new file mode 100644 index 0000000..9584413 --- /dev/null +++ b/test/binary/hlint_spec.lua @@ -0,0 +1,17 @@ +describe('hlint', function() + it('can lint', function() + local helper = require('test.helper') + local buf, diagnostics = helper.run_lint('hlint', 'haskell', { + [[concat $ map escapeC s]], + [[ftable ++ (map (\ (c, x) -> (toUpper c, urlEncode x)) ftable)]], + [[mapM (delete_line (fn2fp f) line) old]], + }) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(buf, d.bufnr) + assert.equal('hlint', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/binary/jq_spec.lua b/test/binary/jq_spec.lua new file mode 100644 index 0000000..9612a1b --- /dev/null +++ b/test/binary/jq_spec.lua @@ -0,0 +1,13 @@ +describe('jq', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('jq', 'json', { + [[{"b":2,"a":1}]], + }) + assert.are.same({ + [[{]], + [[ "b": 2,]], + [[ "a": 1]], + [[}]], + }, formatted) + end) +end) diff --git a/test/binary/ktfmt_spec.lua b/test/binary/ktfmt_spec.lua new file mode 100644 index 0000000..f249720 --- /dev/null +++ b/test/binary/ktfmt_spec.lua @@ -0,0 +1,9 @@ +describe('ktfmt', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('ktfmt', 'kt', { + [[fun main(){val x=1;println(x)}]], + }) + assert.is_true(#formatted > 1) + assert.is_true(formatted[1]:find('fun main') ~= nil) + end) +end) diff --git a/test/binary/ktlint_spec.lua b/test/binary/ktlint_spec.lua new file mode 100644 index 0000000..9e99a55 --- /dev/null +++ b/test/binary/ktlint_spec.lua @@ -0,0 +1,42 @@ +describe('ktlint', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('ktlint', 'kt', { + [[fun main() {]], + [[ val x=1]], + [[ println(x)]], + [[}]], + }) + assert.are.same({ + [[fun main() {]], + [[ val x = 1]], + [[ println(x)]], + [[}]], + }, formatted) + end) + + it('can lint', function() + local linter = require('test.helper').get_linter('ktlint') + local tmpfile = '/tmp/guard-test.kt' + local input = { + [[fun main() {]], + [[ val x=1]], + [[ println(x)]], + [[}]], + } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim.system({ 'ktlint', '--log-level=error', tmpfile }):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) + 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/formatter/latexindent_spec.lua b/test/binary/latexindent_spec.lua similarity index 80% rename from test/formatter/latexindent_spec.lua rename to test/binary/latexindent_spec.lua index c4bba5d..4f22713 100644 --- a/test/formatter/latexindent_spec.lua +++ b/test/binary/latexindent_spec.lua @@ -1,9 +1,6 @@ describe('latexindent', function() it('can format', function() - local ft = require('guard.filetype') - ft('latex'):fmt('latexindent') - - local formatted = require('test.formatter.helper').test_with('latex', { + local formatted = require('test.helper').run_fmt('latexindent', 'latex', { [[\documentclass{article}]], [[\begin{document}]], [[Shopping list]], diff --git a/test/binary/ormolu_spec.lua b/test/binary/ormolu_spec.lua new file mode 100644 index 0000000..52edf0a --- /dev/null +++ b/test/binary/ormolu_spec.lua @@ -0,0 +1,13 @@ +describe('ormolu', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('ormolu', 'hs', { + [[module Main where]], + [[main = putStrLn "hello"]], + }) + assert.are.same({ + [[module Main where]], + [[]], + [[main = putStrLn "hello"]], + }, formatted) + end) +end) diff --git a/test/binary/pg_format_spec.lua b/test/binary/pg_format_spec.lua new file mode 100644 index 0000000..3e44720 --- /dev/null +++ b/test/binary/pg_format_spec.lua @@ -0,0 +1,9 @@ +describe('pg_format', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('pg_format', 'sql', { + [[select id, name from users where id = 1;]], + }) + assert.is_true(#formatted > 1) + assert.is_truthy(formatted[1]:match('SELECT')) + end) +end) diff --git a/test/binary/shellcheck_spec.lua b/test/binary/shellcheck_spec.lua new file mode 100644 index 0000000..5381bd9 --- /dev/null +++ b/test/binary/shellcheck_spec.lua @@ -0,0 +1,30 @@ +describe('shellcheck', function() + it('can lint', function() + local linter = require('test.helper').get_linter('shellcheck') + local tmpfile = '/tmp/guard-test.sh' + local input = { + [[#!/bin/sh]], + [[echo $FOO]], + } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'shellcheck', + '--format', + 'json1', + '--external-sources', + tmpfile, + }) + :wait() + local output = result.stdout or '' + local diagnostics = linter.parse(output, bufnr) + assert.is_true(#diagnostics > 0) + 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/binary/shfmt_spec.lua b/test/binary/shfmt_spec.lua new file mode 100644 index 0000000..e6c3a20 --- /dev/null +++ b/test/binary/shfmt_spec.lua @@ -0,0 +1,16 @@ +describe('shfmt', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('shfmt', 'sh', { + [[#!/bin/sh]], + [[if [ "$x" = "y" ]; then]], + [[echo "hello"]], + [[fi]], + }) + assert.are.same({ + [[#!/bin/sh]], + [[if [ "$x" = "y" ]; then]], + '\techo "hello"', + [[fi]], + }, formatted) + end) +end) diff --git a/test/formatter/swiftformat.lua b/test/binary/swiftformat_spec.lua similarity index 64% rename from test/formatter/swiftformat.lua rename to test/binary/swiftformat_spec.lua index 2580c0e..1c6b640 100644 --- a/test/formatter/swiftformat.lua +++ b/test/binary/swiftformat_spec.lua @@ -1,9 +1,6 @@ describe('swiftformat', function() it('can format', function() - local ft = require('guard.filetype') - ft('swift'):fmt('swiftformat') - - local formatted = require('test.formatter.helper').test_with('swift', { + local formatted = require('test.helper').run_fmt('swiftformat', 'swift', { [[func myFunc() { ]], [[print("hello") ]], [[ }]], diff --git a/test/binary/tombi_spec.lua b/test/binary/tombi_spec.lua new file mode 100644 index 0000000..8808fef --- /dev/null +++ b/test/binary/tombi_spec.lua @@ -0,0 +1,16 @@ +describe('tombi', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('tombi', 'toml', { + '[package]', + 'name="test"', + 'version = "0.1.0"', + }) + assert.is_true(#formatted > 0) + for _, line in ipairs(formatted) do + if line:find('name') then + assert.is_true(line:find('name = ') ~= nil) + break + end + end + end) +end) diff --git a/test/binary/typos_spec.lua b/test/binary/typos_spec.lua new file mode 100644 index 0000000..a942017 --- /dev/null +++ b/test/binary/typos_spec.lua @@ -0,0 +1,14 @@ +describe('typos', function() + it('can lint', function() + local helper = require('test.helper') + local buf, diagnostics = helper.run_lint('typos', 'txt', { + [[teh quick brown fox]], + }) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(buf, d.bufnr) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/binary/typstyle_spec.lua b/test/binary/typstyle_spec.lua new file mode 100644 index 0000000..7169c4f --- /dev/null +++ b/test/binary/typstyle_spec.lua @@ -0,0 +1,10 @@ +describe('typstyle', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('typstyle', 'typ', { + [[#let x = 1]], + }) + assert.are.same({ + [[#let x = 1]], + }, formatted) + end) +end) diff --git a/test/binary/xmllint_spec.lua b/test/binary/xmllint_spec.lua new file mode 100644 index 0000000..5c1f3fd --- /dev/null +++ b/test/binary/xmllint_spec.lua @@ -0,0 +1,13 @@ +describe('xmllint', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('xmllint', 'xml', { + [[text]], + }) + assert.are.same({ + [[]], + [[]], + [[ text]], + [[]], + }, formatted) + end) +end) diff --git a/test/binary/zigfmt_spec.lua b/test/binary/zigfmt_spec.lua new file mode 100644 index 0000000..d978f96 --- /dev/null +++ b/test/binary/zigfmt_spec.lua @@ -0,0 +1,10 @@ +describe('zigfmt', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('zigfmt', 'zig', { + [[const std = @import( "std" );]], + }) + assert.are.same({ + [[const std = @import("std");]], + }, formatted) + end) +end) diff --git a/test/binary/zsh_spec.lua b/test/binary/zsh_spec.lua new file mode 100644 index 0000000..78332d2 --- /dev/null +++ b/test/binary/zsh_spec.lua @@ -0,0 +1,18 @@ +describe('zsh', function() + it('can lint', function() + local linter = require('test.helper').get_linter('zsh') + local tmpfile = '/tmp/guard-test.zsh' + vim.fn.writefile({ 'if true; then' }, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim.system({ 'zsh', '-n', tmpfile }, {}):wait() + local output = result.stderr or '' + local diagnostics = linter.parse(output, bufnr) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('zsh', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/formatter/clang-format_spec.lua b/test/clang/clang-format_spec.lua similarity index 81% rename from test/formatter/clang-format_spec.lua rename to test/clang/clang-format_spec.lua index 2ca886c..c5bb344 100644 --- a/test/formatter/clang-format_spec.lua +++ b/test/clang/clang-format_spec.lua @@ -1,9 +1,6 @@ describe('clang-format', function() it('can format', function() - local ft = require('guard.filetype') - ft('c'):fmt('clang-format') - - local formatted = require('test.formatter.helper').test_with('c', { + local formatted = require('test.helper').run_fmt('clang-format', 'c', { [[#include ]], [[int main() {]], [[ int x = 0x87654321]], diff --git a/test/clang/clang-tidy_spec.lua b/test/clang/clang-tidy_spec.lua new file mode 100644 index 0000000..d3ef122 --- /dev/null +++ b/test/clang/clang-tidy_spec.lua @@ -0,0 +1,21 @@ +describe('clang-tidy', function() + it('can lint', function() + local helper = require('test.helper') + local buf, diagnostics = helper.run_lint('clang-tidy', 'c', { + [[#include ]], + [[int main() {]], + [[ int x = 10;]], + [[ int y = 0;]], + [[ printf("%d", x / y);]], + [[ return 0;]], + [[}]], + }) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(buf, d.bufnr) + assert.equal('clang-tidy', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/clojure/cljfmt_spec.lua b/test/clojure/cljfmt_spec.lua new file mode 100644 index 0000000..f333606 --- /dev/null +++ b/test/clojure/cljfmt_spec.lua @@ -0,0 +1,11 @@ +describe('cljfmt', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('cljfmt', 'clj', { + [[(defn hello]], + [[ [name] (println "hello"]], + [[name))]], + }) + assert.is_true(#formatted > 0) + assert.is_true(formatted[1]:find('defn hello') ~= nil) + 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/elixir/mixformat_spec.lua b/test/elixir/mixformat_spec.lua new file mode 100644 index 0000000..c11c294 --- /dev/null +++ b/test/elixir/mixformat_spec.lua @@ -0,0 +1,9 @@ +describe('mixformat', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('mixformat', 'ex', { + [[defmodule Foo do def bar( x,y) do x+y end end]], + }) + assert.is_true(#formatted > 0) + assert.is_true(formatted[1]:find('defmodule Foo') ~= nil) + end) +end) diff --git a/test/env.sh b/test/env.sh deleted file mode 100644 index a9788c8..0000000 --- a/test/env.sh +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/bash -export PATH="/home/linuxbrew/.linuxbrew/opt/clang-format/bin:$PATH" -export PATH="$HOME/.local/bin:$PATH" -export PATH="/home/linuxbrew/.linuxbrew/bin:$PATH" diff --git a/test/formatter/alejandra_spec.lua b/test/formatter/alejandra_spec.lua deleted file mode 100644 index 5282dbb..0000000 --- a/test/formatter/alejandra_spec.lua +++ /dev/null @@ -1,17 +0,0 @@ -describe('alejandra', function() - it('can format', function() - -- pre-test setup - local ft = require('guard.filetype') - ft('nix'):fmt('alejandra') - -- Giving example input to the helper - -- the helper creates a new buffer with it, formats, and returns the formatted output - local formatted = require('test.formatter.helper').test_with('nix', { - -- The input code should somewhat reflect the filetype - [[{inputs={nixpkgs.url="github:NixOS/nixpkgs/nixos-unstable";};}]], - }) - -- Show that the input is indeed formatted as intended - assert.are.same({ - [[{inputs = {nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";};}]], - }, formatted) - end) -end) diff --git a/test/formatter/buf_spec.lua b/test/formatter/buf_spec.lua deleted file mode 100644 index 1ea646a..0000000 --- a/test/formatter/buf_spec.lua +++ /dev/null @@ -1,17 +0,0 @@ -describe('buf', function() - it('can format', function() - local ft = require('guard.filetype') - ft('proto'):fmt('buf') - - local formatted = require('test.formatter.helper').test_with('proto', { - [[syntax = "proto3"; message Foo { string bar = 1; }]], - }) - assert.are.same({ - [[syntax = "proto3";]], - [[]], - [[message Foo {]], - [[ string bar = 1;]], - [[}]], - }, formatted) - end) -end) diff --git a/test/formatter/helper.lua b/test/formatter/helper.lua deleted file mode 100644 index 28292fd..0000000 --- a/test/formatter/helper.lua +++ /dev/null @@ -1,18 +0,0 @@ -local M = {} -local api = vim.api - -function M.test_with(ft, input) - local cmd = require('guard.filetype')(ft).formatter[1].cmd - assert(not cmd or vim.fn.executable(cmd) == 1) - local bufnr = api.nvim_create_buf(true, false) - vim.bo[bufnr].filetype = ft - api.nvim_set_current_buf(bufnr) - api.nvim_buf_set_lines(bufnr, 0, -1, false, input) - -- To provide fname - vim.cmd('silent! write! /tmp/file.' .. ft) - require('guard.format').do_fmt(bufnr) - vim.wait(3000) - return api.nvim_buf_get_lines(bufnr, 0, -1, false) -end - -return M diff --git a/test/formatter/sqlfluff_spec.lua b/test/formatter/sqlfluff_spec.lua deleted file mode 100644 index 393713c..0000000 --- a/test/formatter/sqlfluff_spec.lua +++ /dev/null @@ -1,42 +0,0 @@ -describe('sqlfluff', function() - it('can format', function() - local ft = require('guard.filetype') - local tool = ft('sql'):fmt('sqlfluff') - tool.formatter[1].args = vim.list_extend(tool.formatter[1].args, { '--dialect', 'ansi' }) - - local formatted = require('test.formatter.helper').test_with('sql', { - [[SELECT *]], - [[FROM]], - [[ World ]], - [[WHERE "Someone"]], - [[ LIKE '%YOU%']], - }) - assert.are.same({ - [[SELECT *]], - [[FROM]], - [[ World]], - [[WHERE]], - [[ "Someone"]], - [[ LIKE '%YOU%']], - }, formatted) - end) - - it('can fix', function() - local ft = require('guard.filetype') - local tool = ft('sql'):fmt('sqlfluff_fix') - tool.formatter[1].args = vim.list_extend(tool.formatter[1].args, { '--dialect', 'ansi' }) - - local formatted = require('test.formatter.helper').test_with('sql', { - [[SELECT]], - [[ a + b AS foo,]], - [[ c AS bar]], - [[FROM my_table]], - }) - assert.are.same({ - [[SELECT]], - [[ c AS bar,]], - [[ a + b AS foo]], - [[FROM my_table]], - }, formatted) - end) -end) diff --git a/test/formatter/gofmt_spec.lua b/test/go/gofmt_spec.lua similarity index 76% rename from test/formatter/gofmt_spec.lua rename to test/go/gofmt_spec.lua index a17d93d..8f3f213 100644 --- a/test/formatter/gofmt_spec.lua +++ b/test/go/gofmt_spec.lua @@ -1,9 +1,6 @@ describe('gofmt', function() it('can format', function() - local ft = require('guard.filetype') - ft('go'):fmt('gofmt') - - local formatted = require('test.formatter.helper').test_with('go', { + local formatted = require('test.helper').run_fmt('gofmt', 'go', { [[package main]], [[]], [[ import "fmt" ]], diff --git a/test/formatter/gofumpt_spec.lua b/test/go/gofumpt_spec.lua similarity index 76% rename from test/formatter/gofumpt_spec.lua rename to test/go/gofumpt_spec.lua index 933403c..86911ce 100644 --- a/test/formatter/gofumpt_spec.lua +++ b/test/go/gofumpt_spec.lua @@ -1,9 +1,6 @@ describe('gofumpt', function() it('can format', function() - local ft = require('guard.filetype') - ft('go'):fmt('gofumpt') - - local formatted = require('test.formatter.helper').test_with('go', { + local formatted = require('test.helper').run_fmt('gofumpt', 'go', { [[package main]], [[]], [[ import "fmt" ]], diff --git a/test/go/goimports_spec.lua b/test/go/goimports_spec.lua new file mode 100644 index 0000000..5cbdc1f --- /dev/null +++ b/test/go/goimports_spec.lua @@ -0,0 +1,26 @@ +describe('goimports', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('goimports', 'go', { + [[package main]], + [[]], + [[import "fmt"]], + [[import "os"]], + [[]], + [[func main() {]], + [[fmt.Println(os.Args)]], + [[}]], + }) + assert.are.same({ + [[package main]], + [[]], + [[import (]], + '\t"fmt"', + '\t"os"', + [[)]], + [[]], + [[func main() {]], + '\tfmt.Println(os.Args)', + [[}]], + }, formatted) + end) +end) diff --git a/test/go/golangci_lint_spec.lua b/test/go/golangci_lint_spec.lua new file mode 100644 index 0000000..aefde3e --- /dev/null +++ b/test/go/golangci_lint_spec.lua @@ -0,0 +1,37 @@ +describe('golangci_lint', function() + it('can lint', function() + local linter = require('test.helper').get_linter('golangci_lint') + local tmpdir = '/tmp/golangci-test' + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ 'module test', '', 'go 1.21' }, tmpdir .. '/go.mod') + local input = { + 'package main', + '', + 'import "fmt"', + '', + 'func main() {', + '\tfmt.Errorf("unused error")', + '}', + } + vim.fn.writefile(input, tmpdir .. '/main.go') + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'golangci-lint', + 'run', + '--fix=false', + '--out-format=json', + }, { + cwd = tmpdir, + }) + :wait() + local output = result.stdout or '' + local diagnostics = linter.parse(output, bufnr) + 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/formatter/golines_spec.lua b/test/go/golines_spec.lua similarity index 76% rename from test/formatter/golines_spec.lua rename to test/go/golines_spec.lua index 935b61e..0cd4a9b 100644 --- a/test/formatter/golines_spec.lua +++ b/test/go/golines_spec.lua @@ -1,9 +1,6 @@ describe('golines', function() it('can format', function() - local ft = require('guard.filetype') - ft('go'):fmt('golines') - - local formatted = require('test.formatter.helper').test_with('go', { + local formatted = require('test.helper').run_fmt('golines', 'go', { [[package main]], [[]], [[ import "fmt" ]], diff --git a/test/go/yamlfmt_spec.lua b/test/go/yamlfmt_spec.lua new file mode 100644 index 0000000..8b7bbd9 --- /dev/null +++ b/test/go/yamlfmt_spec.lua @@ -0,0 +1,12 @@ +describe('yamlfmt', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('yamlfmt', 'yaml', { + [[name: John]], + [[age: 30]], + }) + assert.are.same({ + [[name: John]], + [[age: 30]], + }, formatted) + end) +end) diff --git a/test/helper.lua b/test/helper.lua new file mode 100644 index 0000000..e73f168 --- /dev/null +++ b/test/helper.lua @@ -0,0 +1,61 @@ +local M = {} +local api = vim.api + +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 dir = opts.tmpdir or '/tmp' + local tmpfile = dir .. '/guard-test.' .. ft + if config.fname then + vim.fn.writefile(input, tmpfile) + table.insert(cmd, tmpfile) + end + 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 '')) + if config.stdin then + return vim.split(result.stdout, '\n', { trimempty = true }) + else + return vim.fn.readfile(tmpfile) + end +end + +function M.run_lint(name, ft, input) + 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 + vim.fn.writefile(input, tmpfile) + local bufnr = api.nvim_create_buf(false, true) + local cmd = vim.list_extend({ linter.cmd }, linter.args or {}) + if linter.fname then + table.insert(cmd, tmpfile) + end + local result = vim + .system(cmd, { + stdin = linter.stdin and input_str or nil, + }) + :wait() + local output = result.stdout or '' + if output == '' then + output = result.stderr or '' + end + local diags = linter.parse(output, bufnr) + return bufnr, diags +end + +function M.get_linter(name) + local linter = require('guard-collection.linter')[name] + assert(linter, 'unknown linter: ' .. name) + return linter +end + +return M diff --git a/test/linter/buf_spec.lua b/test/linter/buf_spec.lua deleted file mode 100644 index 7fe56eb..0000000 --- a/test/linter/buf_spec.lua +++ /dev/null @@ -1,25 +0,0 @@ -describe('buf', function() - it('can lint', function() - local helper = require('test.linter.helper') - local ns = helper.namespace - local ft = require('guard.filetype') - ft('proto'):lint('buf') - - local buf, diagnostics = helper.test_with('proto', { - [[syntax = "proto3"; message Foo { string bar = 1 }]], - }) - assert.are.same({ - { - bufnr = buf, - col = 48, - end_col = 48, - end_lnum = 0, - lnum = 0, - message = "syntax error: expecting ';'", - namespace = ns, - severity = 4, - source = 'buf', - }, - }, diagnostics) - end) -end) diff --git a/test/linter/checkmake_spec.lua b/test/linter/checkmake_spec.lua deleted file mode 100644 index 2964cd9..0000000 --- a/test/linter/checkmake_spec.lua +++ /dev/null @@ -1,48 +0,0 @@ -describe('checkmake', function() - it('can lint', function() - local helper = require('test.linter.helper') - local ns = helper.namespace - local ft = require('guard.filetype') - ft('make'):lint('checkmake') - - local buf, diagnostics = helper.test_with('make', { - [[all:]], - [[\techo hello]], - }) - assert.are.same({ - { - bufnr = buf, - col = 0, - end_col = 0, - end_lnum = 0, - lnum = 0, - message = '[minphony] Missing required phony target "all"', - namespace = ns, - severity = 2, - source = 'checkmake', - }, - { - bufnr = buf, - col = 0, - end_col = 0, - end_lnum = 0, - lnum = 0, - message = '[minphony] Missing required phony target "clean"', - namespace = ns, - severity = 2, - source = 'checkmake', - }, - { - bufnr = buf, - col = 0, - end_col = 0, - end_lnum = 0, - lnum = 0, - message = '[minphony] Missing required phony target "test"', - namespace = ns, - severity = 2, - source = 'checkmake', - }, - }, diagnostics) - end) -end) diff --git a/test/linter/clang-tidy_spec.lua b/test/linter/clang-tidy_spec.lua deleted file mode 100644 index 9eee7bd..0000000 --- a/test/linter/clang-tidy_spec.lua +++ /dev/null @@ -1,31 +0,0 @@ -describe('clang-tidy', function() - it('can lint', function() - local helper = require('test.linter.helper') - local ns = helper.namespace - local ft = require('guard.filetype') - ft('c'):lint('clang-tidy') - - local buf, diagnostics = helper.test_with('c', { - [[#include ]], - [[int main() {]], - [[ int x = 10;]], - [[ int y = 0;]], - [[ printf("%d", x / y);]], - [[ return 0;]], - [[}]], - }) - assert.are.same({ - { - bufnr = buf, - col = 19, - end_col = 19, - end_lnum = 4, - lnum = 4, - message = 'Division by zero[clang-analyzer-core.DivideZero]', - namespace = ns, - severity = 2, - source = 'clang-tidy', - }, - }, diagnostics) - end) -end) diff --git a/test/linter/flake8_spec.lua b/test/linter/flake8_spec.lua deleted file mode 100644 index e12b780..0000000 --- a/test/linter/flake8_spec.lua +++ /dev/null @@ -1,107 +0,0 @@ -describe('flake8', function() - it('can lint', function() - local helper = require('test.linter.helper') - local ns = helper.namespace - local ft = require('guard.filetype') - ft('python'):lint('flake8') - - local buf, diagnostics = helper.test_with('python', { - [[import os]], - [[]], - [[def foo(n):]], - [[ if n == 0:]], - [[ return bar]], - [[print("it's too long sentence to be displayed in one line, blah blah blah blah")]], - }) - assert.are.same({ - { - bufnr = buf, - col = 0, - end_col = 0, - end_lnum = 0, - lnum = 0, - message = "'os' imported but unused[401]", - namespace = ns, - severity = 3, - source = 'flake8', - }, - { - bufnr = buf, - col = 0, - end_col = 0, - end_lnum = 2, - lnum = 2, - message = 'expected 2 blank lines, found 1[302]', - namespace = ns, - severity = 1, - source = 'flake8', - }, - { - bufnr = buf, - col = 9, - end_col = 9, - end_lnum = 4, - lnum = 4, - message = 'indentation is not a multiple of 4[111]', - namespace = ns, - severity = 1, - source = 'flake8', - }, - { - bufnr = buf, - col = 9, - end_col = 9, - end_lnum = 4, - lnum = 4, - message = 'over-indented[117]', - namespace = ns, - severity = 1, - source = 'flake8', - }, - { - bufnr = buf, - col = 15, - end_col = 15, - end_lnum = 4, - lnum = 4, - message = 'multiple spaces after keyword[271]', - namespace = ns, - severity = 1, - source = 'flake8', - }, - { - bufnr = buf, - col = 17, - end_col = 17, - end_lnum = 4, - lnum = 4, - message = "undefined name 'bar'[821]", - namespace = ns, - severity = 3, - source = 'flake8', - }, - { - bufnr = buf, - col = 0, - end_col = 0, - end_lnum = 5, - lnum = 5, - message = 'expected 2 blank lines after class or function definition, found 0[305]', - namespace = ns, - severity = 1, - source = 'flake8', - }, - { - bufnr = buf, - col = 79, - end_col = 79, - end_lnum = 5, - lnum = 5, - message = 'line too long (80 > 79 characters)[501]', - namespace = ns, - severity = 1, - source = 'flake8', - }, - }, diagnostics) - end) -end) diff --git a/test/linter/helper.lua b/test/linter/helper.lua deleted file mode 100644 index fb43a42..0000000 --- a/test/linter/helper.lua +++ /dev/null @@ -1,22 +0,0 @@ -local M = {} -local api = vim.api -local lint = require('guard.lint') -M.namespace = api.nvim_get_namespaces().Guard - -function M.test_with(ft, input) - local cmd = require('guard.filetype')(ft).linter[1].cmd - assert(vim.fn.executable(cmd) == 1) - - local bufnr = api.nvim_create_buf(true, false) - vim.bo[bufnr].filetype = ft - api.nvim_set_current_buf(bufnr) - api.nvim_buf_set_lines(bufnr, 0, -1, false, input) - -- To make linters happy - vim.cmd('silent! write! /tmp/test.' .. ft) - - lint.do_lint(bufnr) - vim.wait(3000) - return bufnr, vim.diagnostic.get(bufnr) -end - -return M diff --git a/test/linter/hlint_spec.lua b/test/linter/hlint_spec.lua deleted file mode 100644 index 02864da..0000000 --- a/test/linter/hlint_spec.lua +++ /dev/null @@ -1,49 +0,0 @@ -describe('hlint', function() - it('can lint', function() - local helper = require('test.linter.helper') - local ns = helper.namespace - local ft = require('guard.filetype') - ft('haskell'):lint('hlint') - - local buf, diagnostics = helper.test_with('haskell', { - [[concat $ map escapeC s]], - [[ftable ++ (map (\ (c, x) -> (toUpper c, urlEncode x)) ftable)]], - [[mapM (delete_line (fn2fp f) line) old]], - }) - assert.are.same({ - { - bufnr = buf, - col = 0, - end_col = 0, - end_lnum = 0, - lnum = 0, - message = 'Use concatMap: concatMap escapeC s', - namespace = ns, - severity = 2, - source = 'hlint', - }, - { - bufnr = buf, - col = 10, - end_col = 10, - end_lnum = 1, - lnum = 1, - message = [[Redundant bracket: ftable ++ map (\ (c, x) -> (toUpper c, urlEncode x)) ftable]], - namespace = ns, - severity = 3, - source = 'hlint', - }, - { - bufnr = buf, - col = 16, - end_col = 16, - end_lnum = 1, - lnum = 1, - message = 'Use bimap: Data.Bifunctor.bimap toUpper urlEncode', - namespace = ns, - severity = 3, - source = 'hlint', - }, - }, diagnostics) - end) -end) diff --git a/test/linter/luacheck_spec.lua b/test/linter/luacheck_spec.lua deleted file mode 100644 index 0731c74..0000000 --- a/test/linter/luacheck_spec.lua +++ /dev/null @@ -1,30 +0,0 @@ -describe('luacheck', function() - it('can lint', function() - local helper = require('test.linter.helper') - local ns = helper.namespace - local ft = require('guard.filetype') - ft('lua'):lint('luacheck') - - local buf, diagnostics = helper.test_with('lua', { - [[local M = {}]], - [[function M.foo()]], - [[ print("foo")]], - [[end]], - [[U.bar()]], - [[return M]], - }) - assert.are.same({ - { - bufnr = buf, - col = 0, - end_col = 0, - end_lnum = 4, - lnum = 4, - message = "accessing undefined variable 'U'[113]", - namespace = ns, - severity = 2, - source = 'luacheck', - }, - }, diagnostics) - end) -end) diff --git a/test/linter/selene_spec.lua b/test/linter/selene_spec.lua deleted file mode 100644 index 9be18f9..0000000 --- a/test/linter/selene_spec.lua +++ /dev/null @@ -1,25 +0,0 @@ -describe('selene', function() - it('can lint', function() - local helper = require('test.linter.helper') - local ns = helper.namespace - local ft = require('guard.filetype') - ft('lua'):lint('selene') - - local buf, diagnostics = helper.test_with('lua', { - [[print(a)]], - }) - assert.are.same({ - { - bufnr = buf, - col = 6, - end_col = 0, - end_lnum = 0, - lnum = 0, - message = '`a` is not defined[undefined_variable]', - namespace = ns, - severity = 1, - source = 'selene', - }, - }, diagnostics) - end) -end) diff --git a/test/lua/fnlfmt_spec.lua b/test/lua/fnlfmt_spec.lua new file mode 100644 index 0000000..2173e44 --- /dev/null +++ b/test/lua/fnlfmt_spec.lua @@ -0,0 +1,10 @@ +describe('fnlfmt', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('fnlfmt', 'fnl', { + [[(fn hello [] (print "hello"]], + [[))]], + }) + assert.is_true(#formatted > 0) + assert.is_true(formatted[1]:find('fn hello') ~= nil) + end) +end) diff --git a/test/lua/luacheck_spec.lua b/test/lua/luacheck_spec.lua new file mode 100644 index 0000000..e043ea7 --- /dev/null +++ b/test/lua/luacheck_spec.lua @@ -0,0 +1,20 @@ +describe('luacheck', function() + it('can lint', function() + local helper = require('test.helper') + local buf, diagnostics = helper.run_lint('luacheck', 'lua', { + [[local M = {}]], + [[function M.foo()]], + [[ print("foo")]], + [[end]], + [[U.bar()]], + [[return M]], + }) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(buf, d.bufnr) + assert.equal('luacheck', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/lua/selene_spec.lua b/test/lua/selene_spec.lua new file mode 100644 index 0000000..04d25d5 --- /dev/null +++ b/test/lua/selene_spec.lua @@ -0,0 +1,15 @@ +describe('selene', function() + it('can lint', function() + local helper = require('test.helper') + local buf, diagnostics = helper.run_lint('selene', 'lua', { + [[print(a)]], + }) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(buf, d.bufnr) + assert.equal('selene', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/formatter/stylua_spec.lua b/test/lua/stylua_spec.lua similarity index 65% rename from test/formatter/stylua_spec.lua rename to test/lua/stylua_spec.lua index a98d5b1..0e2b054 100644 --- a/test/formatter/stylua_spec.lua +++ b/test/lua/stylua_spec.lua @@ -1,9 +1,6 @@ describe('stylua', function() it('can format', function() - local ft = require('guard.filetype') - ft('lua'):fmt('stylua') - - local formatted = require('test.formatter.helper').test_with('lua', { + local formatted = require('test.helper').run_fmt('stylua', 'lua', { [[local M={}]], [[ M.foo =]], [[ "foo"]], diff --git a/test/nix/nixfmt_spec.lua b/test/nix/nixfmt_spec.lua new file mode 100644 index 0000000..254d631 --- /dev/null +++ b/test/nix/nixfmt_spec.lua @@ -0,0 +1,9 @@ +describe('nixfmt', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('nixfmt', 'nix', { + [[{pkgs,...}:{environment.systemPackages=[pkgs.vim];}]], + }) + assert.is_true(#formatted > 0) + assert.is_true(formatted[1]:find('pkgs') ~= nil) + end) +end) diff --git a/test/formatter/biome_spec.lua b/test/npm/biome_spec.lua similarity index 67% rename from test/formatter/biome_spec.lua rename to test/npm/biome_spec.lua index dedb733..a697946 100644 --- a/test/formatter/biome_spec.lua +++ b/test/npm/biome_spec.lua @@ -1,9 +1,6 @@ describe('biome', function() it('can format json', function() - local ft = require('guard.filetype') - ft('json'):fmt('biome') - - local formatted = require('test.formatter.helper').test_with('json', { + local formatted = require('test.helper').run_fmt('biome', 'json', { [[{"name": "dove" , "age":10 ]], [[,"gender": "male"}]], }) @@ -13,10 +10,7 @@ describe('biome', function() end) it('can format javascript', function() - local ft = require('guard.filetype') - ft('js'):fmt('biome') - - local formatted = require('test.formatter.helper').test_with('js', { + local formatted = require('test.helper').run_fmt('biome', 'js', { [[ const randomNumber = Math.floor(]], [[ Math.random() * 10]], [[ ) + 1]], diff --git a/test/npm/eslint_d_spec.lua b/test/npm/eslint_d_spec.lua new file mode 100644 index 0000000..f8a4893 --- /dev/null +++ b/test/npm/eslint_d_spec.lua @@ -0,0 +1,66 @@ +describe('eslint_d', function() + it('can lint', function() + local linter = require('test.helper').get_linter('eslint_d') + local tmpdir = '/tmp/eslintd-test' + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + 'module.exports = [{ rules: { "no-unused-vars": "error" } }];', + }, tmpdir .. '/eslint.config.js') + local tmpfile = tmpdir .. '/test.js' + local input = { + [[const x = 1;]], + } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'npx', + 'eslint_d', + '--format', + 'json', + '--stdin', + '--stdin-filename', + tmpfile, + }, { + stdin = table.concat(input, '\n') .. '\n', + cwd = tmpdir, + }) + :wait() + local output = result.stdout or '' + local diagnostics = linter.parse(output, bufnr) + assert.is_true(#diagnostics > 0) + 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() + local tmpdir = '/tmp/eslintd-test' + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + 'module.exports = [{ rules: { "semi": ["error", "always"] } }];', + }, tmpdir .. '/eslint.config.js') + local tmpfile = tmpdir .. '/test.js' + local input = { + [[const x = 1]], + } + vim.fn.writefile(input, tmpfile) + local config = require('guard-collection.formatter').eslint_d + local cmd = vim.list_extend({ config.cmd }, config.args) + table.insert(cmd, tmpfile) + local result = vim + .system(cmd, { + stdin = table.concat(input, '\n') .. '\n', + cwd = tmpdir, + }) + :wait() + assert(result.code == 0, 'eslint_d exited ' .. result.code .. ': ' .. (result.stderr or '')) + local formatted = vim.split(result.stdout, '\n', { trimempty = true }) + 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..8ea0339 --- /dev/null +++ b/test/npm/eslint_spec.lua @@ -0,0 +1,39 @@ +describe('eslint', function() + it('can lint', function() + local linter = require('test.helper').get_linter('eslint') + local tmpdir = '/tmp/eslint-test' + vim.fn.mkdir(tmpdir, 'p') + vim.fn.writefile({ + 'module.exports = [{ rules: { "no-unused-vars": "error" } }];', + }, tmpdir .. '/eslint.config.js') + local tmpfile = tmpdir .. '/test.js' + local input = { + [[const x = 1;]], + } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'npx', + 'eslint', + '--format', + 'json', + '--stdin', + '--stdin-filename', + tmpfile, + }, { + stdin = table.concat(input, '\n') .. '\n', + cwd = tmpdir, + }) + :wait() + local output = result.stdout or '' + local diagnostics = linter.parse(output, bufnr) + assert.is_true(#diagnostics > 0) + 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/formatter/prettier_spec.lua b/test/npm/prettier_spec.lua similarity index 70% rename from test/formatter/prettier_spec.lua rename to test/npm/prettier_spec.lua index aa381af..2be27a7 100644 --- a/test/formatter/prettier_spec.lua +++ b/test/npm/prettier_spec.lua @@ -1,9 +1,6 @@ describe('prettier', function() it('can format', function() - local ft = require('guard.filetype') - ft('javascript'):fmt('prettier') - - local formatted = require('test.formatter.helper').test_with('javascript', { + local formatted = require('test.helper').run_fmt('prettier', 'javascript', { [[ const randomNumber = Math.floor(]], [[ Math.random() * 10]], [[ ) + 1]], diff --git a/test/npm/prettierd_spec.lua b/test/npm/prettierd_spec.lua new file mode 100644 index 0000000..61cecd6 --- /dev/null +++ b/test/npm/prettierd_spec.lua @@ -0,0 +1,20 @@ +describe('prettierd', function() + it('can format', function() + local tmpfile = '/tmp/guard-test.js' + local input = { + 'const x={a:1,b:2,c:3}', + 'const y = [1,2,3,4,5]', + } + vim.fn.writefile(input, tmpfile) + local result = vim + .system({ 'prettierd', tmpfile }, { stdin = table.concat(input, '\n') }) + :wait() + assert.equal(0, result.code) + local expected = table.concat({ + 'const x = { a: 1, b: 2, c: 3 };', + 'const y = [1, 2, 3, 4, 5];', + '', + }, '\n') + assert.equal(expected, result.stdout) + end) +end) diff --git a/test/formatter/sql-formatter_spec.lua b/test/npm/sql-formatter_spec.lua similarity index 66% rename from test/formatter/sql-formatter_spec.lua rename to test/npm/sql-formatter_spec.lua index 2063998..7d03101 100644 --- a/test/formatter/sql-formatter_spec.lua +++ b/test/npm/sql-formatter_spec.lua @@ -1,9 +1,6 @@ describe('sql-formatter', function() it('can format', function() - local ft = require('guard.filetype') - ft('sql'):fmt('sql-formatter') - - local formatted = require('test.formatter.helper').test_with('sql', { + local formatted = require('test.helper').run_fmt('sql-formatter', 'sql', { [[SELECT *]], [[FROM]], [[World]], @@ -17,8 +14,6 @@ describe('sql-formatter', function() [[ World]], [[WHERE]], [[ "Someone" LIKE '%YOU%']], - -- /> no results! - -- /> :sob }, formatted) end) end) diff --git a/test/npm/stylelint_spec.lua b/test/npm/stylelint_spec.lua new file mode 100644 index 0000000..70639c1 --- /dev/null +++ b/test/npm/stylelint_spec.lua @@ -0,0 +1,46 @@ +describe('stylelint', function() + it('can lint', function() + local linter = require('test.helper').get_linter('stylelint') + local tmpdir = '/tmp/stylelint-test' + vim.fn.mkdir(tmpdir, 'p') + local configfile = tmpdir .. '/.stylelintrc.json' + vim.fn.writefile({ + '{ "rules": { "color-no-invalid-hex": true } }', + }, configfile) + local tmpfile = tmpdir .. '/test.css' + local input = { + [[a { color: #fff1az; }]], + } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'npx', + 'stylelint', + '--formatter', + 'json', + '--stdin', + '--stdin-filename', + tmpfile, + '--config', + configfile, + }, { + stdin = table.concat(input, '\n') .. '\n', + cwd = tmpdir, + }) + :wait() + local output = result.stdout or '' + if output == '' then + output = result.stderr or '' + end + assert(output ~= '', 'stylelint: no output (code=' .. result.code .. ')') + local diagnostics = linter.parse(output, bufnr) + assert.is_true(#diagnostics > 0) + 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/formatter/taplo_spec.lua b/test/npm/taplo_spec.lua similarity index 79% rename from test/formatter/taplo_spec.lua rename to test/npm/taplo_spec.lua index bdada26..d92bec6 100644 --- a/test/formatter/taplo_spec.lua +++ b/test/npm/taplo_spec.lua @@ -1,9 +1,6 @@ describe('taplo', function() it('can format', function() - local ft = require('guard.filetype') - ft('toml'):fmt('taplo') - - local formatted = require('test.formatter.helper').test_with('toml', { + local formatted = require('test.helper').run_fmt('taplo', 'toml', { [[ [dependencies] ]], [[ async-process = "^1.7"]], [[strum = { version = "^0.25", features = ["derive"] } ]], diff --git a/test/formatter/autopep8_spec.lua b/test/pip/autopep8_spec.lua similarity index 78% rename from test/formatter/autopep8_spec.lua rename to test/pip/autopep8_spec.lua index 7f89f4a..3e96edf 100644 --- a/test/formatter/autopep8_spec.lua +++ b/test/pip/autopep8_spec.lua @@ -1,9 +1,6 @@ describe('autopep8', function() it('can format', function() - local ft = require('guard.filetype') - ft('python'):fmt('autopep8') - - local formatted = require('test.formatter.helper').test_with('python', { + local formatted = require('test.helper').run_fmt('autopep8', 'python', { [[def foo(n):]], [[ if n in (1,2,3):]], [[ return n+1]], diff --git a/test/formatter/black_spec.lua b/test/pip/black_spec.lua similarity index 78% rename from test/formatter/black_spec.lua rename to test/pip/black_spec.lua index 2312e76..1deffcd 100644 --- a/test/formatter/black_spec.lua +++ b/test/pip/black_spec.lua @@ -1,9 +1,6 @@ describe('black', function() it('can format', function() - local ft = require('guard.filetype') - ft('python'):fmt('black') - - local formatted = require('test.formatter.helper').test_with('python', { + local formatted = require('test.helper').run_fmt('black', 'python', { [[def foo(n):]], [[ if n in (1,2,3):]], [[ return n+1]], diff --git a/test/formatter/cmake-format_spec.lua b/test/pip/cmake-format_spec.lua similarity index 69% rename from test/formatter/cmake-format_spec.lua rename to test/pip/cmake-format_spec.lua index 2e5a817..25af6e5 100644 --- a/test/formatter/cmake-format_spec.lua +++ b/test/pip/cmake-format_spec.lua @@ -1,9 +1,6 @@ describe('cmake-format', function() it('can format', function() - local ft = require('guard.filetype') - ft('cmake'):fmt('cmake-format') - - local formatted = require('test.formatter.helper').test_with('cmake', { + local formatted = require('test.helper').run_fmt('cmake-format', 'cmake', { [[cmake_minimum_required(VERSION 3.10)]], [[project(test)]], [[add_executable(test main.cpp)]], diff --git a/test/pip/codespell_spec.lua b/test/pip/codespell_spec.lua new file mode 100644 index 0000000..b16fdc1 --- /dev/null +++ b/test/pip/codespell_spec.lua @@ -0,0 +1,15 @@ +describe('codespell', function() + it('can lint', function() + local helper = require('test.helper') + local buf, diagnostics = helper.run_lint('codespell', 'txt', { + [[teh quick brown fox]], + }) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(buf, d.bufnr) + assert.equal('codespell', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/pip/cpplint_spec.lua b/test/pip/cpplint_spec.lua new file mode 100644 index 0000000..cb0095a --- /dev/null +++ b/test/pip/cpplint_spec.lua @@ -0,0 +1,19 @@ +describe('cpplint', function() + it('can lint', function() + local linter = require('test.helper').get_linter('cpplint') + local tmpfile = '/tmp/guard-test.cpp' + local input = { [[int main(){int x=1;}]] } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim.system({ 'cpplint', '--filter=-legal/copyright', tmpfile }, {}):wait() + local output = result.stderr or '' + local diagnostics = linter.parse(output, bufnr) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('cpplint', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/pip/djhtml_spec.lua b/test/pip/djhtml_spec.lua new file mode 100644 index 0000000..32529b1 --- /dev/null +++ b/test/pip/djhtml_spec.lua @@ -0,0 +1,14 @@ +describe('djhtml', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('djhtml', 'html', { + [[
]], + [[

hello

]], + [[
]], + }) + assert.are.same({ + [[
]], + [[

hello

]], + [[
]], + }, formatted) + end) +end) diff --git a/test/formatter/docformatter_spec.lua b/test/pip/docformatter_spec.lua similarity index 69% rename from test/formatter/docformatter_spec.lua rename to test/pip/docformatter_spec.lua index 977d80d..1871572 100644 --- a/test/formatter/docformatter_spec.lua +++ b/test/pip/docformatter_spec.lua @@ -1,9 +1,6 @@ describe('docformatter', function() it('can format', function() - local ft = require('guard.filetype') - ft('python'):fmt('docformatter') - - local formatted = require('test.formatter.helper').test_with('python', { + local formatted = require('test.helper').run_fmt('docformatter', 'python', { [[def foo():]], [[ """]], [[ Hello foo.]], diff --git a/test/pip/flake8_spec.lua b/test/pip/flake8_spec.lua new file mode 100644 index 0000000..fab866a --- /dev/null +++ b/test/pip/flake8_spec.lua @@ -0,0 +1,21 @@ +describe('flake8', function() + it('can lint', function() + local helper = require('test.helper') + local buf, diagnostics = helper.run_lint('flake8', 'python', { + [[import os]], + [[]], + [[def foo(n):]], + [[ if n == 0:]], + [[ return bar]], + [[print("it's too long sentence to be displayed in one line, blah blah blah blah")]], + }) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(buf, d.bufnr) + assert.equal('flake8', d.source) + assert.is_number(d.lnum) + assert.is_number(d.col) + assert.is_string(d.message) + end + end) +end) diff --git a/test/pip/isort_spec.lua b/test/pip/isort_spec.lua new file mode 100644 index 0000000..b91a95e --- /dev/null +++ b/test/pip/isort_spec.lua @@ -0,0 +1,14 @@ +describe('isort', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('isort', 'python', { + [[import sys]], + [[import os]], + [[import json]], + }) + assert.are.same({ + [[import json]], + [[import os]], + [[import sys]], + }, formatted) + end) +end) diff --git a/test/pip/mdformat_spec.lua b/test/pip/mdformat_spec.lua new file mode 100644 index 0000000..f30a03c --- /dev/null +++ b/test/pip/mdformat_spec.lua @@ -0,0 +1,13 @@ +describe('mdformat', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('mdformat', 'markdown', { + [[# title]], + [[text]], + }) + assert.are.same({ + [[# title]], + [[]], + [[text]], + }, formatted) + end) +end) diff --git a/test/pip/mypy_spec.lua b/test/pip/mypy_spec.lua new file mode 100644 index 0000000..40fa9a9 --- /dev/null +++ b/test/pip/mypy_spec.lua @@ -0,0 +1,29 @@ +describe('mypy', function() + it('can lint', function() + local linter = require('test.helper').get_linter('mypy') + local tmpfile = '/tmp/guard-test.py' + local input = { + '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) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('mypy', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/pip/mypyc_spec.lua b/test/pip/mypyc_spec.lua new file mode 100644 index 0000000..850fd33 --- /dev/null +++ b/test/pip/mypyc_spec.lua @@ -0,0 +1,29 @@ +describe('mypyc', function() + it('can lint', function() + local linter = require('test.helper').get_linter('mypyc') + local tmpfile = '/tmp/guard-test.py' + local input = { + '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) + for _, d in ipairs(diagnostics) do + assert.equal(bufnr, d.bufnr) + assert.equal('mypy', d.source) + assert.is_number(d.lnum) + assert.is_string(d.message) + end + end) +end) diff --git a/test/pip/pylint_spec.lua b/test/pip/pylint_spec.lua new file mode 100644 index 0000000..54bf7ae --- /dev/null +++ b/test/pip/pylint_spec.lua @@ -0,0 +1,32 @@ +describe('pylint', function() + it('can lint', function() + local linter = require('test.helper').get_linter('pylint') + local tmpfile = '/tmp/guard-test.py' + local input = { + [[import os]], + [[x = 1]], + } + vim.fn.writefile(input, tmpfile) + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'pylint', + '--from-stdin', + '--output-format', + 'json', + tmpfile, + }, { + stdin = table.concat(input, '\n') .. '\n', + }) + :wait() + local output = result.stdout or '' + local diagnostics = linter.parse(output, bufnr) + assert.is_true(#diagnostics > 0) + 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/formatter/ruff_spec.lua b/test/pip/ruff_spec.lua similarity index 52% rename from test/formatter/ruff_spec.lua rename to test/pip/ruff_spec.lua index 11dcb07..8439bd0 100644 --- a/test/formatter/ruff_spec.lua +++ b/test/pip/ruff_spec.lua @@ -1,9 +1,6 @@ describe('ruff', function() it('can format', function() - local ft = require('guard.filetype') - ft('python'):fmt('ruff') - - local formatted = require('test.formatter.helper').test_with('python', { + local formatted = require('test.helper').run_fmt('ruff', 'python', { [[def foo(n):]], [[ if n in (1,2,3):]], [[ return n+1]], @@ -22,4 +19,19 @@ describe('ruff', function() [[print(f"The factorial of {a} is: {foo(a)}")]], }, formatted) end) + + it('can lint', function() + local helper = require('test.helper') + local buf, diagnostics = helper.run_lint('ruff', 'py', { + [[import os]], + [[x = 1]], + }) + assert.is_true(#diagnostics > 0) + for _, d in ipairs(diagnostics) do + assert.equal(buf, 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 new file mode 100644 index 0000000..cb8452b --- /dev/null +++ b/test/pip/sqlfluff_spec.lua @@ -0,0 +1,54 @@ +describe('sqlfluff', function() + 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 = { + [[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 }) + assert.are.same({ + [[SELECT *]], + [[FROM]], + [[ World]], + [[WHERE]], + [[ "Someone"]], + [[ LIKE '%YOU%']], + }, formatted) + 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 = { + [[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 }) + assert.are.same({ + [[SELECT]], + [[ c AS bar,]], + [[ a + b AS foo]], + [[FROM my_table]], + }, formatted) + end) +end) diff --git a/test/pip/yamlfix_spec.lua b/test/pip/yamlfix_spec.lua new file mode 100644 index 0000000..1fad53e --- /dev/null +++ b/test/pip/yamlfix_spec.lua @@ -0,0 +1,13 @@ +describe('yamlfix', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('yamlfix', 'yaml', { + [[name: John]], + [[age: 30]], + }) + assert.are.same({ + [[---]], + [[name: John]], + [[age: 30]], + }, formatted) + end) +end) diff --git a/test/formatter/yapf_spec.lua b/test/pip/yapf_spec.lua similarity index 78% rename from test/formatter/yapf_spec.lua rename to test/pip/yapf_spec.lua index a1678a4..69ff808 100644 --- a/test/formatter/yapf_spec.lua +++ b/test/pip/yapf_spec.lua @@ -1,9 +1,6 @@ describe('yapf', function() it('can format', function() - local ft = require('guard.filetype') - ft('python'):fmt('yapf') - - local formatted = require('test.formatter.helper').test_with('python', { + local formatted = require('test.helper').run_fmt('yapf', 'python', { [[def foo(n):]], [[ if n in (1,2,3):]], [[ return n+1]], diff --git a/test/ruby/rubocop_spec.lua b/test/ruby/rubocop_spec.lua new file mode 100644 index 0000000..16f0df2 --- /dev/null +++ b/test/ruby/rubocop_spec.lua @@ -0,0 +1,68 @@ +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 format', function() + local input = { + [[x = { :a=>1,:b => 2 }]], + } + local result = vim + .system({ + 'bundle', + 'exec', + 'rubocop', + '-A', + '-f', + 'quiet', + '--stderr', + '--stdin', + 'test.rb', + }, { + stdin = table.concat(input, '\n') .. '\n', + cwd = tmpdir, + }) + :wait() + local output = result.stderr or '' + local formatted = vim.split(output, '\n', { trimempty = true }) + assert.is_true(#formatted > 0) + end) + + it('can lint', function() + local linter = require('test.helper').get_linter('rubocop') + local input = { + [[x = { :a=>1,:b => 2 }]], + } + local bufnr = vim.api.nvim_create_buf(false, true) + local result = vim + .system({ + 'bundle', + 'exec', + 'rubocop', + '--format', + 'json', + '--force-exclusion', + '--stdin', + 'test.rb', + }, { + stdin = table.concat(input, '\n') .. '\n', + cwd = tmpdir, + }) + :wait() + local output = result.stdout or '' + local diagnostics = linter.parse(output, bufnr) + 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/formatter/rustfmt_nightly_spec.lua b/test/rust/rustfmt_nightly_spec.lua similarity index 74% rename from test/formatter/rustfmt_nightly_spec.lua rename to test/rust/rustfmt_nightly_spec.lua index 584c279..d37b01e 100644 --- a/test/formatter/rustfmt_nightly_spec.lua +++ b/test/rust/rustfmt_nightly_spec.lua @@ -1,9 +1,6 @@ describe('rustfmt_nightly', function() it('can format', function() - local ft = require('guard.filetype') - ft('rust'):fmt('rustfmt_nightly') - - local formatted = require('test.formatter.helper').test_with('rust', { + local formatted = require('test.helper').run_fmt('rustfmt_nightly', 'rust', { [[use std::{collections::HashMap, collections::HashSet};]], [[fn main() {]], [[let var:usize=1;]], diff --git a/test/formatter/rustfmt_spec.lua b/test/rust/rustfmt_spec.lua similarity index 65% rename from test/formatter/rustfmt_spec.lua rename to test/rust/rustfmt_spec.lua index bec9e5b..6782c85 100644 --- a/test/formatter/rustfmt_spec.lua +++ b/test/rust/rustfmt_spec.lua @@ -1,9 +1,6 @@ describe('rustfmt', function() it('can format', function() - local ft = require('guard.filetype') - ft('rust'):fmt('rustfmt') - - local formatted = require('test.formatter.helper').test_with('rust', { + local formatted = require('test.helper').run_fmt('rustfmt', 'rust', { [[use std::{collections::HashMap, collections::HashSet};]], [[fn main() {]], [[let var:usize=1;]], @@ -11,7 +8,7 @@ describe('rustfmt', function() [[}]], }) assert.are.same({ - [[use std::{collections::HashMap, collections::HashSet};]], + [[use std::collections::{HashMap, HashSet};]], [[fn main() {]], [[ let var: usize = 1;]], [[ println!("{var}");]], diff --git a/test/setup.sh b/test/setup.sh deleted file mode 100644 index d1db3e1..0000000 --- a/test/setup.sh +++ /dev/null @@ -1,62 +0,0 @@ -#! /bin/bash -# Setup homebrew -eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - -# Install packages with package managers -luarocks install luacheck & - -pip -qqq install autopep8 black djhtml docformatter flake8 isort pylint yapf codespell ruff sqlfluff clang-tidy mypy & - -npm install -g --silent \ - prettier @fsouza/prettierd sql-formatter shellcheck shfmt @taplo/cli @biomejs/biome & - -brew install \ - hlint ormolu clang-format golines gofumpt detekt swiftformat & - -# Install standalone binary packages -bin="$HOME/.local/bin" -gh="https://github.com" -mkdir -p $bin - -# alejandra -wget -q $gh"/kamadorueda/alejandra/releases/download/4.0.0/alejandra-x86_64-unknown-linux-musl" -mv ./alejandra-x86_64-unknown-linux-musl $bin/alejandra -chmod +x $bin/alejandra - -# cbfmt -wget -q $gh"/lukas-reineke/cbfmt/releases/download/v0.2.0/cbfmt_linux-x86_64_v0.2.0.tar.gz" -tar -xvf cbfmt_linux-x86_64_v0.2.0.tar.gz -mv ./cbfmt_linux-x86_64_v0.2.0/cbfmt $bin -chmod +x $bin/cbfmt - -# selene -wget -q "$gh/Kampfkarren/selene/releases/download/0.28.0/selene-0.28.0-linux.zip" -unzip selene-0.28.0-linux.zip -d $bin -chmod +x $bin/selene - -# stylua -wget -q "$gh/JohnnyMorganz/StyLua/releases/download/v0.18.0/stylua-linux.zip" -unzip stylua-linux.zip -d $bin -chmod +x $bin/stylua - -# latexindent -wget -q "$gh/cmhughes/latexindent.pl/releases/download/V3.22.2/latexindent-linux" -chmod +x latexindent-linux -mv latexindent-linux $bin/latexindent - -# nixfmt -wget -q "$gh/serokell/nixfmt/releases/download/v0.5.0/nixfmt" -chmod +x nixfmt -mv nixfmt $bin/nixfmt - -# ktlint -wget -q "$gh/pinterest/ktlint/releases/download/1.0.0/ktlint" -chmod +x ktlint -mv ktlint $bin/ktlint - -# test setup -export PATH="$HOME/.local/bin:$PATH" -luarocks install vusted -git clone "$gh/nvimdev/guard.nvim" "$HOME/guard.nvim" -mv "$HOME/guard.nvim/lua/guard" ./lua/ -wait diff --git a/test/swift/swift_format_spec.lua b/test/swift/swift_format_spec.lua new file mode 100644 index 0000000..e545f65 --- /dev/null +++ b/test/swift/swift_format_spec.lua @@ -0,0 +1,9 @@ +describe('swift-format', function() + it('can format', function() + local formatted = require('test.helper').run_fmt('swift-format', 'swift', { + [[func foo( ){let x=1;print(x)}]], + }) + assert.is_true(#formatted > 0) + assert.is_true(formatted[1]:find('func foo') ~= nil) + end) +end)