tests/modules/performance/combine-plugins: use stub plugins for tests

During the last half of the year many dependencies of plugins used in
the tests were changed in nixpkgs. To make tests more robust use a
specially crafted stub plugins.
This commit is contained in:
Stanislav Asunkin 2025-04-27 17:49:29 +03:00
parent 9c39ea4ccb
commit 57e19ec3ec

View file

@ -6,31 +6,99 @@ let
pluginCount = pluginCount =
pkg: files: type: pkg: files: type:
builtins.length (builtins.filter (p: p != files) pkg.packpathDirs.myNeovimPackages.${type}); builtins.length (builtins.filter (p: p != files) pkg.packpathDirs.myNeovimPackages.${type});
# Stub plugins
mkPlugin =
name: args:
pkgs.vimUtils.buildVimPlugin (
{
pname = name;
version = "2025-04-27";
src = pkgs.runCommand "${name}-source" { } ''
mkdir "$out"
# Add some colliding files
echo "# ${name}" > "$out/README.md"
echo "Copyright (c) ${name}" > "$out/LICENSE"
mkdir "$out/tests"
echo "return '${name}'" > "$out/tests/test.lua"
# Add import path
mkdir -p "$out/lua/${name}"
echo "return '${name}'" > "$out/lua/${name}/init.lua"
# Add doc
mkdir "$out/doc"
echo "*${name}.txt* ${name}" > "$out/doc/${name}.txt"
'';
}
// args
);
# Simple plugins without any features
simplePlugin1 = mkPlugin "simple-plugin-1" { };
simplePlugin2 = mkPlugin "simple-plugin-2" { };
simplePlugin3 = mkPlugin "simple-plugin-3" { };
# Plugins with dependencies
pluginWithDeps1 = mkPlugin "plugin-with-deps-1" {
dependencies = [ simplePlugin1 ];
};
pluginWithDeps2 = mkPlugin "plugin-with-deps-2" {
dependencies = [ simplePlugin2 ];
};
pluginWithDeps3 = mkPlugin "plugin-with-deps-3" {
dependencies = [ simplePlugin3 ];
};
# Plugin with recursive dependencies
pluginWithRecDeps = mkPlugin "plugin-with-rec-deps" {
dependencies = [
pluginWithDeps1
pluginWithDeps2
];
};
# Plugin with non-standard files
pluginWithExtraFiles = mkPlugin "plugin-with-extra-files" {
postInstall = ''
mkdir "$out/_extra"
touch "$out/_extra/test"
'';
};
# Plugins with Python dependencies
pluginWithPyDeps1 = mkPlugin "plugin-with-py-deps-1" {
passthru.python3Dependencies = ps: [ ps.pyyaml ];
};
pluginWithPyDeps2 = mkPlugin "plugin-with-py-deps-2" {
passthru.python3Dependencies = ps: [ ps.pyyaml ];
};
pluginWithPyDeps3 = mkPlugin "plugin-with-py-deps-3" {
passthru.python3Dependencies = ps: [ ps.requests ];
};
in in
{ {
# Test basic functionality # Test basic functionality
default = default =
{ config, ... }: { config, ... }:
let
extraPlugins = [
simplePlugin1
simplePlugin2
simplePlugin3
];
in
{ {
performance.combinePlugins.enable = true; performance.combinePlugins.enable = true;
extraPlugins = with pkgs.vimPlugins; [ inherit extraPlugins;
nvim-lspconfig extraConfigLuaPost = lib.concatMapStringsSep "\n" (
nvim-treesitter name:
]; # lua
extraConfigLuaPost = '' ''
-- Plugins are loadable -- Plugin is loadable
require("lspconfig") require("${name}")
require("nvim-treesitter")
-- No separate plugin entries in nvim_list_runtime_paths -- No separate plugin entry in vim.api.nvim_list_runtime_paths()
assert(not vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry) assert(not vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry)
return entry:find("treesitter") or entry:find("lspconfig") return entry:find("${name}", 1, true)
end), "separate plugins are found in runtime") end), "plugin '${name}' found in runtime, expected to be combined")
-- Help tags are generated -- Help tags are generated
assert(vim.fn.getcompletion("lspconfig", "help")[1], "no help tags for nvim-lspconfig") assert(vim.fn.getcompletion("${name}", "help")[1], "no help tags for '${name}'")
assert(vim.fn.getcompletion("nvim-treesitter", "help")[1], "no help tags for nvim-treesitter") '') (map lib.getName extraPlugins);
'';
assertions = [ assertions = [
{ {
assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1; assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 1;
@ -42,12 +110,25 @@ in
# Test disabled option # Test disabled option
disabled = disabled =
{ config, ... }: { config, ... }:
let
extraPlugins = [
simplePlugin1
simplePlugin2
simplePlugin3
];
in
{ {
performance.combinePlugins.enable = false; performance.combinePlugins.enable = false;
extraPlugins = with pkgs.vimPlugins; [ inherit extraPlugins;
nvim-lspconfig extraConfigLuaPost = lib.concatMapStringsSep "\n" (
nvim-treesitter name:
]; # lua
''
-- Separate plugin entry in vim.api.nvim_list_runtime_paths()
assert(vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry)
return entry:find("${name}", 1, true)
end), "plugin '${name}' isn't found in runtime as a separate entry, expected not to be combined")
'') (map lib.getName extraPlugins);
assertions = [ assertions = [
{ {
assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" >= 2; assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" >= 2;
@ -61,19 +142,26 @@ in
{ config, ... }: { config, ... }:
{ {
performance.combinePlugins.enable = true; performance.combinePlugins.enable = true;
extraPlugins = with pkgs.vimPlugins; [ extraPlugins = [
# Depends on nui-nvim # Depends on pluginWithDeps1 and pluginWithDeps2 which themselves depend on simplePlugin1 and simplePlugin2
noice-nvim pluginWithRecDeps
# Depends on null-ls-nvim which itself depends on plenary-nvim # Depends on simplePlugin3
mason-null-ls-nvim pluginWithDeps3
# Duplicated dependency
pluginWithDeps2
# Duplicated plugin
simplePlugin2
]; ];
extraConfigLuaPost = '' extraConfigLuaPost = ''
-- Plugins and its dependencies are loadable -- Plugin 'pluginWithRecDeps' and its dependencies are loadable
require("noice") require("plugin-with-rec-deps")
require("nui.popup") require("plugin-with-deps-1")
require("mason-null-ls.settings") -- Avoid calling deprecated functions require("plugin-with-deps-2")
require("null-ls.helpers") -- Avoid calling deprecated functions require("simple-plugin-1")
require("plenary") require("simple-plugin-2")
-- Plugin 'pluginWithDeps3' and its dependencies are loadable
require("plugin-with-deps-3")
require("simple-plugin-3")
''; '';
assertions = [ assertions = [
{ {
@ -89,19 +177,15 @@ in
{ {
performance.combinePlugins = { performance.combinePlugins = {
enable = true; enable = true;
# fzf native library is in build directory pathsToLink = [ "/_extra" ];
pathsToLink = [ "/build" ];
}; };
extraPlugins = [ pkgs.vimPlugins.telescope-fzf-native-nvim ]; extraPlugins = [ pluginWithExtraFiles ];
extraConfigLuaPost = '' extraConfigLuaPost = ''
-- Native library is in runtimepath -- Test file is in runtime
assert( assert(
vim.api.nvim_get_runtime_file("build/libfzf.so", false)[1], vim.api.nvim_get_runtime_file("_extra/test", false)[1],
"build/libfzf.so is not found in runtimepath" "'_extra/test' file isn't found in runtime, expected to be found"
) )
-- Native library is loadable
require("fzf_lib")
''; '';
assertions = [ assertions = [
{ {
@ -116,14 +200,14 @@ in
{ config, ... }: { config, ... }:
{ {
performance.combinePlugins.enable = true; performance.combinePlugins.enable = true;
extraPlugins = with pkgs.vimPlugins; [ extraPlugins = [
# No python3 dependencies # No python3 dependencies
plenary-nvim simplePlugin1
# Duplicate python3 dependencies # Duplicated python3-pyyaml dependency
(nvim-lspconfig.overrideAttrs { passthru.python3Dependencies = ps: [ ps.pyyaml ]; }) pluginWithPyDeps1
(nvim-treesitter.overrideAttrs { passthru.python3Dependencies = ps: [ ps.pyyaml ]; }) pluginWithPyDeps2
# Another python3 dependency # Python3-requests dependency
(nvim-cmp.overrideAttrs { passthru.python3Dependencies = ps: [ ps.requests ]; }) pluginWithPyDeps3
]; ];
extraConfigLuaPost = '' extraConfigLuaPost = ''
-- Python modules are importable -- Python modules are importable
@ -143,46 +227,44 @@ in
{ config, ... }: { config, ... }:
{ {
performance.combinePlugins.enable = true; performance.combinePlugins.enable = true;
extraPlugins = with pkgs.vimPlugins; [ extraPlugins = [
# Start plugins # Start plugins
plenary-nvim simplePlugin1
nvim-lspconfig simplePlugin2
# Optional plugin # Optional plugin
{ {
plugin = nvim-treesitter; plugin = simplePlugin3;
optional = true; optional = true;
} }
# Optional plugin with dependency on plenary-nvim # Optional plugin with dependency on simplePlugin1
# Dependencies should not be duplicated # Dependencies should not be duplicated
{ {
plugin = none-ls-nvim; plugin = pluginWithDeps1;
optional = true; optional = true;
} }
]; ];
extraConfigLuaPost = '' extraConfigLuaPost = ''
-- Start plugins are loadable -- Start plugins are loadable
require("plenary") require("simple-plugin-1")
require("lspconfig") require("simple-plugin-2")
-- Opt plugins are not loadable -- Opt plugins are not loadable
local ok = pcall(require, "nvim-treesitter") local ok = pcall(require, "simple-plugin-3")
assert(not ok, "nvim-treesitter plugin is loadable") assert(not ok, "simplePlugin3 is loadable, expected it to be an opt plugin")
ok = pcall(require, "null-ls") ok = pcall(require, "plugin-with-deps-1")
assert(not ok, "null-ls-nvim plugin is loadable") assert(not ok, "pluginWithDeps1 is loadable, expected it to be an opt plugin")
-- Load plugins -- Load plugins
vim.cmd.packadd("nvim-treesitter") vim.cmd.packadd("simple-plugin-3")
vim.cmd.packadd("none-ls.nvim") vim.cmd.packadd("plugin-with-deps-1")
-- Now opt plugins are loadable -- Now opt plugins are loadable
require("nvim-treesitter") require("simple-plugin-3")
require("null-ls") require("plugin-with-deps-1")
-- Only one copy of plenary-nvim should be available -- Only one copy of simplePlugin1 should be available
assert( local num_plugins = #vim.api.nvim_get_runtime_file("lua/simple-plugin-1/init.lua", true)
#vim.api.nvim_get_runtime_file("lua/plenary/init.lua", true) == 1, assert(num_plugins == 1, "expected 1 copy of simplePlugin1, got " .. num_plugins)
"plenary-nvim is duplicated"
)
''; '';
assertions = [ assertions = [
{ {
@ -201,35 +283,25 @@ in
{ config, ... }: { config, ... }:
{ {
performance.combinePlugins.enable = true; performance.combinePlugins.enable = true;
extraPlugins = with pkgs.vimPlugins; [ extraPlugins = [
# A plugin without config # A plugin without config
plenary-nvim simplePlugin1
# Plugins with configs # Plugin with config
{ {
plugin = nvim-treesitter; plugin = simplePlugin2;
config = "let g:treesitter_config = 1"; config = "let g:simple_plugin_2 = 1";
}
{
plugin = nvim-lspconfig;
config = "let g:lspconfig_config = 1";
} }
# Optional plugin with config # Optional plugin with config
{ {
plugin = telescope-nvim; plugin = simplePlugin3;
optional = true; optional = true;
config = "let g:telescope_config = 1"; config = "let g:simple_plugin_3 = 1";
} }
]; ];
extraConfigLuaPost = '' extraConfigLuaPost = ''
-- Plugins are loadable
require("plenary")
require("nvim-treesitter")
require("lspconfig")
-- Configs are evaluated -- Configs are evaluated
assert(vim.g.treesitter_config == 1, "nvim-treesitter config isn't evaluated") assert(vim.g.simple_plugin_2 == 1, "simplePlugin2's config isn't evaluated")
assert(vim.g.lspconfig_config == 1, "nvim-lspconfig config isn't evaluated") assert(vim.g.simple_plugin_3 == 1, "simplePlugin3's config isn't evaluated")
assert(vim.g.telescope_config == 1, "telescope-nvim config isn't evaluated")
''; '';
assertions = [ assertions = [
{ {
@ -244,62 +316,36 @@ in
{ config, ... }: { config, ... }:
{ {
performance.combinePlugins.enable = true; performance.combinePlugins.enable = true;
extraPlugins = with pkgs.vimPlugins; [ extraPlugins = [
nvim-treesitter simplePlugin1
vim-nix simplePlugin2
]; ];
# Ensure that build.extraFiles is added extraPlugins # Ensure that build.extraFiles is added to extraPlugins
wrapRc = true; wrapRc = true;
# Extra user files colliding with plugins # Extra user files colliding with plugins
extraFiles = { extraFiles = {
"ftplugin/nix.vim".text = "let b:test = 1"; "lua/simple-plugin-1/init.lua".text = "return 1";
"queries/nix/highlights.scm".text = ''
;; extends
(comment) @comment
'';
}; };
# Another form of user files # Another form of user files
files = { files = {
"ftdetect/nix.vim" = { "lua/simple-plugin-2/init.lua" = {
autoCmd = [ extraConfigLua = "return 1";
{
event = [
"BufRead"
"BufNewFile"
];
pattern = "*.nix";
command = "setf nix";
}
];
}; };
}; };
extraConfigLuaPost = '' extraConfigLuaPost = ''
local function get_paths(name) for _, file in ipairs({"lua/simple-plugin-1/init.lua", "lua/simple-plugin-2/init.lua"}) do
local paths = vim.api.nvim_get_runtime_file(name, true); local paths_found = vim.api.nvim_get_runtime_file(file, true)
return vim.tbl_filter(function(v) local num_found = #paths_found
-- Skip paths from neovim runtime
return not v:find("/nvim/runtime/") -- Both plugin and user version are available
end, paths) assert(num_found == 2, "expected exactly 2 versions of '" .. file .. "', got " .. num_found)
-- First found file is from build.extraFiles
assert(
paths_found[1]:find("${lib.getName config.build.extraFiles}", 1, true),
"expected first found '" .. file .. "' to be from build.extraFiles, got " .. paths_found[1]
)
end end
-- Both plugin and user version are available
assert(#get_paths("ftplugin/nix.vim") == 2, "only one version of ftplugin/nix.vim")
assert(#get_paths("ftdetect/nix.vim") == 2, "only one version of ftdetect/nix.vim")
assert(#get_paths("queries/nix/highlights.scm") == 2, "only one version of queries/nix/highlights.scm")
-- First found file is from build.extraFiles
assert(
get_paths("ftplugin/nix.vim")[1]:find("${lib.getName config.build.extraFiles}", 1, true),
"first found ftplugin/nix.vim isn't in build.extraFiles runtime path"
)
assert(
get_paths("queries/nix/highlights.scm")[1]:find("${lib.getName config.build.extraFiles}", 1, true),
"first found queries/nix/highlights.scm isn't in build.extraFiles runtime path"
)
assert(
get_paths("queries/nix/highlights.scm")[1]:find("${lib.getName config.build.extraFiles}", 1, true),
"first found queries/nix/highlights.scm isn't in build.extraFiles runtime path"
)
''; '';
assertions = [ assertions = [
{ {
@ -315,60 +361,53 @@ in
{ {
performance.combinePlugins = { performance.combinePlugins = {
enable = true; enable = true;
standalonePlugins = with pkgs.vimPlugins; [ standalonePlugins = [
# By plugin name # By plugin name
"nvim-treesitter" "simple-plugin-1"
# By package itself # By package itself. Its dependency, simplePlugin2, not in this list, so will be combined
nvim-lspconfig pluginWithDeps2
# Its dependency, plenary-nvim, not in this list, so will be combined
none-ls-nvim
# Dependency of other plugin # Dependency of other plugin
"nui.nvim" "simple-plugin-3"
]; ];
}; };
extraPlugins = with pkgs.vimPlugins; [ extraPlugins = [
nvim-treesitter simplePlugin1
nvim-lspconfig pluginWithDeps2
none-ls-nvim pluginWithDeps3
# Only its dependency (nui-nvim) won't be combined, but not the plugin itself pluginWithExtraFiles
noice-nvim
# More plugins
gitsigns-nvim
luasnip
]; ];
extraConfigLuaPost = '' extraConfigLuaPost = ''
-- Plugins are loadable local tests = {
require("nvim-treesitter") {"simple-plugin-1", true},
require("lspconfig") {"plugin-with-deps-2", true},
require("null-ls") {"simple-plugin-2", false},
require("plenary") {"plugin-with-deps-3", false},
require("noice") {"simple-plugin-3", true},
require("nui.popup") {"plugin-with-extra-files", false},
require("gitsigns") }
require("luasnip") for _, test in ipairs(tests) do
local name = test[1]
local expected_standalone = test[2]
-- Verify if plugin is standalone or combined -- Plugin is loadable
local function is_standalone(name, dirname) require(test[1])
local paths = vim.api.nvim_get_runtime_file("lua/" .. name, true);
assert(#paths == 1, "more than one copy of " .. name .. " in runtime") local paths = vim.api.nvim_get_runtime_file("lua/" .. name, true)
return paths[1]:match("^(.+)/lua/"):find(dirname or name, 1, true) ~= nil -- Plugins shouldn't be duplicated
assert(#paths == 1, "expected exactly 1 copy of '" .. name .. "' in runtime, got ", #paths)
-- Test if plugin is standalone. This matches directory name before '/lua/'.
local is_standalone = paths[1]:match("^(.+)/lua/"):find(name, 1, true) ~= nil
local expected_text = expected_standalone and "standalone" or "combined"
assert(
is_standalone == expected_standalone,
"expected '" .. name .. "' to be " .. expected_text .. ", found path: " .. paths[1]
)
end end
-- Standalone plugins
assert(is_standalone("nvim-treesitter"), "nvim-treesitter is combined, expected standalone")
assert(is_standalone("lspconfig"), "nvim-lspconfig is combined, expected standalone")
assert(is_standalone("null-ls", "none-ls.nvim"), "none-ls-nvim is combined, expected standalone")
assert(is_standalone("nui"), "nui-nvim is combined, expected standalone")
-- Combined plugins
assert(not is_standalone("plenary"), "plenary-nvim is standalone, expected combined")
assert(not is_standalone("noice"), "noice-nvim is standalone, expected combined")
assert(not is_standalone("gitsigns"), "gitsigns-nvim is standalone, expected combined")
assert(not is_standalone("luasnip"), "luasnip is standalone, expected combined")
''; '';
assertions = [ assertions = [
{ {
# plugin-pack, nvim-treesitter, nvim-lspconfig, none-ls-nvim, nui-nvim # plugin-pack, simplePlugin1, pluginWithDeps2, simplePlugin3
assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 5; assertion = pluginCount config.build.nvimPackage config.build.extraFiles "start" == 4;
message = "Wrong number of plugins in packpathDirs"; message = "Wrong number of plugins in packpathDirs";
} }
]; ];