Skip to content

About

Google Test adapter for nvim-neotest

Topics

Resources

Stars

60 stars

Watchers

7 watching

Forks

Repository files navigation

neotest-gtest

CI status License: MIT

This is a neotest adapter for Google Test, a popular C++ testing library. It allows easy interactions with tests from your neovim. It should work well out-of-the-box for most cases, though some features (see below) are not yet supported.

Requirements

  • Neovim 0.12+ or nightly.
  • Google Test 1.10+
  • neotest (latest, incl. nvim-nio and plenary.nvim)
  • Tree-sitter CPP parser (e.g., via nvim-treesitter's TSInstall cpp)
  • nvim-dap (latest, optional, required for debugging)

Features

The plugin provides full support of all neotest features:

  • running tests inside NeoVim
  • seeing pretty output
  • debugging tests
  • all other niceties of neotest

One major feature is not yet supported:

  • Build tool integration for recompilation - you have to do that manually (or with some other plugin) for now

TEST_P, TYPED_TEST, and TYPED_TEST_P source declarations remain selectable parents. After an executable is configured and the file is saved, the summary shows each compiled case beneath its source declaration. Select a leaf to run or debug its exact Google Test name, or select the parent to run every compiled case for that declaration. Buffer-based nearest-test selection chooses the source parent. Generated cases report their results independently; a failed case also marks its parent failed.

The executable's --gtest_list_tests output supplies the runtime names. After the first executable configuration, save the source file to show its compiled cases. Later executable rebuilds refresh those cases automatically, including when the source buffer is closed; :ConfigureGtest is only needed again to change the executable mapping. Other generated Google Test macro families are not yet supported.

To run each compiled case in a separate process, set process_isolation = true in the adapter setup. This applies to normal runs; DAP runs keep their normal debugging behavior. The default is false, so a selection runs grouped by executable. Isolated runs start one process per case, which costs more time for large selections but prevents process-local state and a crashed case from affecting later cases. Each case uses an exact Google Test filter and its own JSON report. Generated cases require a configured executable and a refreshed runtime inventory. Rebuilding the executable refreshes that inventory after the initial discovery.

You can override the setting for one run with require("neotest").run.run({ process_isolation = true }).

Contributions are welcome! :)

Installation

Use your favorite package manager. Don't forget to install neotest itself, which also has a couple dependencies. The plugin also depends on plenary.nvim, chances are that so do your other plugins.

For debugging, you also need nvim-dap, and a debug adapter (codelldb is recommended), you can install it manually or with mason.nvim. For setting it up, see nvim-dap wiki.

-- best to add to dependencies of `neotest`:
{
    "nvim-neotest/neotest",
    dependencies = {
        "nvim-lua/plenary.nvim",
        "alfaix/neotest-gtest"
        -- your other adapters here
    }
}

Usage

Simply add neotest-gtest to the adapters field of neotest's config:

require("neotest").setup({
  adapters = {
    require("neotest-gtest").setup({})
  }
})

Before running tests, you need to assign them to executables. For that, navigate to the neotest summary window (neotest.summary.open()), mark the tests you want to run (m by default), and run :ConfigureGtest in that same window. It will prompt you to enter the path to the executable. You can set the executable path only for parent directory, no need to set it for each test separately. This configuration is persisted on disk.

Once that's done, use neotest the way you usually do: see their documentation. You don't need to call any neotest-gtest functions for ordinary usage.

Configuration

neotest-gtest comes with the following defaults:

local utils = require("neotest-gtest.utils")
local lib = require("neotest.lib")

require("neotest-gtest").setup({
  -- fun(string) -> string: takes a file path as string and returns its project root
  -- directory
  -- neotest.lib.files.match_root_pattern() is a convenient factory for these functions:
  -- it returns a function that returns true if the directory contains any entries
  -- with matching names
  root = lib.files.match_root_pattern(
    "compile_commands.json",
    "compile_flags.txt",
    "WORKSPACE",
    ".clangd",
    "init.lua",
    "init.vim",
    "build",
    ".git"
  ),
  -- which debug adapter to use? dap.adapters.<this debug_adapter> must be defined.
  debug_adapter = "codelldb",
  -- fun(string) -> bool: takes a file path as string and returns true if it contains
  -- tests
  is_test_file = function(file)
    -- by default, returns true if the file stem starts with test_ or ends with _test
    -- the extension must be cpp/cppm/cc/cxx/c++
  end,
  -- How many old test results to keep on disk (stored in stdpath('data')/neotest-gtest/runs)
  history_size = 3,
  -- Run one compiled case per process for normal runs (slower on large selections).
  process_isolation = false,
  -- To prevent large projects from freezing your computer, there's some throttling
  -- for -- parsing test files. Decrease if your parsing is slow and you have a
  -- monster PC.
  parsing_throttle_ms = 10,
  -- set configure to a normal mode key which will run :ConfigureGtest (suggested:
  -- "C", nil by default)
  mappings = { configure = nil },
  summary_view = {
    -- How long should the header be in tests short summary?
    -- ________TestNamespace.TestName___________ <- this is the header
    header_length = 80,
    -- Your shell's colors, if the default ones don't work.
    shell_palette = {
      passed = "\27[32m",
      skipped = "\27[33m",
      failed = "\27[31m",
      stop = "\27[0m",
      bold = "\27[1m",
    },
  },
  -- What extra args should ALWAYS be sent to google test?
  -- if you want to send them for one given invocation only,
  -- send them to `neotest.run({extra_args = ...})`
  -- see :h neotest.RunArgs for details
  extra_args = {},
  -- see :h neotest.Config.discovery. Best to keep this as-is and set
  -- per-project settings in neotest instead.
  filter_dir = function(name, rel_path, root)
    -- see :h neotest.Config.discovery for defaults
  end,
})

Contributing

All contributions are welcome. If you would like to contribute, but not sure how to get started, please open an issue, and I'll do my best to help you.

Should you feel confident enough to write a PR on your own, please make sure to include tests. The plugin is tested quite extensively, you can run make to run the tests. Integration testsuite requires a functioning C++11 compiler, and will download googletests as a submodule.

License

MIT, see LICENSE

About

Google Test adapter for nvim-neotest

Topics

Resources

Stars

60 stars

Watchers

7 watching

Forks

Releases

Packages

Used by

Contributors

Languages