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

This commit replaces stub plugins with the shared ones from utils
module.
This also removes separate tests for checking python and lua
dependencies. This is now tested in the 'default' test thanks to
`pluginChecks` code.
This commit is contained in:
Stanislav Asunkin 2025-05-11 18:34:41 +03:00
parent a49b270861
commit 4c23fb2738
2 changed files with 133 additions and 270 deletions

View file

@ -1,6 +1,6 @@
{ pkgs, ... }: { lib, pkgs, ... }:
let let
inherit (pkgs) lib; pluginStubs = pkgs.callPackage ../../../utils/plugin-stubs.nix { };
# Assertion for a number of plugins of given type defined in nvimPackage.packpathDirs # Assertion for a number of plugins of given type defined in nvimPackage.packpathDirs
expectNPlugins = expectNPlugins =
@ -20,110 +20,26 @@ let
}; };
# Assertion that exactly one start plugin is defined in nvimPackage.packpathDirs # Assertion that exactly one start plugin is defined in nvimPackage.packpathDirs
expectOneStartPlugin = config: expectNPlugins config "start" 1; expectOneStartPlugin = config: expectNPlugins config "start" 1;
# 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 ];
};
# Plugins with Lua dependencies
ensureDep =
drv: dep:
drv.overrideAttrs (prev: {
propagatedBuildInputs = lib.unique (
prev.propagatedBuildInputs or [ ] ++ [ prev.passthru.lua.pkgs.${dep} ]
);
});
pluginWithLuaDeps1 = ensureDep pkgs.vimPlugins.telescope-nvim "plenary-nvim";
pluginWithLuaDeps2 = ensureDep pkgs.vimPlugins.nvim-cmp "plenary-nvim";
pluginWithLuaDeps3 = ensureDep pkgs.vimPlugins.gitsigns-nvim "nui-nvim";
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;
inherit extraPlugins; extraPlugins = pluginStubs.pluginPack;
extraConfigLuaPost = lib.concatMapStringsSep "\n" ( extraConfigLuaPost = ''
name: ${pluginStubs.pluginChecks}
# lua
''
-- Plugin is loadable
require("${name}")
-- No separate plugin entry in vim.api.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) ${lib.concatMapStrings (
return entry:find("${name}", 1, true) name: # lua
end), "plugin '${name}' found in runtime, expected to be combined") ''
assert(not vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry)
-- Help tags are generated return entry:find("${name}", 1, true)
assert(vim.fn.getcompletion("${name}", "help")[1], "no help tags for '${name}'") end), "plugin '${name}' found in runtime, expected to be combined")
'') (map lib.getName extraPlugins); '') pluginStubs.pluginNames}
'';
assertions = [ assertions = [
(expectOneStartPlugin config) (expectOneStartPlugin config)
]; ];
@ -132,16 +48,9 @@ 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;
inherit extraPlugins; extraPlugins = pluginStubs.pluginPack;
extraConfigLuaPost = lib.concatMapStringsSep "\n" ( extraConfigLuaPost = lib.concatMapStringsSep "\n" (
name: name:
# lua # lua
@ -150,40 +59,9 @@ in
assert(vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry) assert(vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry)
return entry:find("${name}", 1, true) return entry:find("${name}", 1, true)
end), "plugin '${name}' isn't found in runtime as a separate entry, expected not to be combined") end), "plugin '${name}' isn't found in runtime as a separate entry, expected not to be combined")
'') (map lib.getName extraPlugins); '') pluginStubs.pluginNames;
assertions = [ assertions = [
(expectNPlugins config "start" (builtins.length extraPlugins)) (expectNPlugins config "start" (builtins.length pluginStubs.pluginPack))
];
};
# Test that plugin dependencies are handled
dependencies =
{ config, ... }:
{
performance.combinePlugins.enable = true;
extraPlugins = [
# Depends on pluginWithDeps1 and pluginWithDeps2 which themselves depend on simplePlugin1 and simplePlugin2
pluginWithRecDeps
# Depends on simplePlugin3
pluginWithDeps3
# Duplicated dependency
pluginWithDeps2
# Duplicated plugin
simplePlugin2
];
extraConfigLuaPost = ''
-- Plugin 'pluginWithRecDeps' and its dependencies are loadable
require("plugin-with-rec-deps")
require("plugin-with-deps-1")
require("plugin-with-deps-2")
require("simple-plugin-1")
require("simple-plugin-2")
-- Plugin 'pluginWithDeps3' and its dependencies are loadable
require("plugin-with-deps-3")
require("simple-plugin-3")
'';
assertions = [
(expectOneStartPlugin config)
]; ];
}; };
@ -195,8 +73,18 @@ in
enable = true; enable = true;
pathsToLink = [ "/_extra" ]; pathsToLink = [ "/_extra" ];
}; };
extraPlugins = [ pluginWithExtraFiles ]; extraPlugins = [
# A plugin with extra directory
(pluginStubs.mkPlugin "extra" {
postInstall = ''
mkdir $out/_extra
touch $out/_extra/test
'';
})
];
extraConfigLuaPost = '' extraConfigLuaPost = ''
${pluginStubs.pluginChecksFor [ "extra" ]}
-- Test file is in runtime -- Test file is in runtime
assert( assert(
vim.api.nvim_get_runtime_file("_extra/test", false)[1], vim.api.nvim_get_runtime_file("_extra/test", false)[1],
@ -208,103 +96,79 @@ in
]; ];
}; };
# Test that plugin python3 dependencies are handled
python-dependencies =
{ config, ... }:
{
performance.combinePlugins.enable = true;
extraPlugins = [
# No python3 dependencies
simplePlugin1
# Duplicated python3-pyyaml dependency
pluginWithPyDeps1
pluginWithPyDeps2
# Python3-requests dependency
pluginWithPyDeps3
];
extraConfigLuaPost = ''
-- Python modules are importable
vim.cmd.py3("import yaml")
vim.cmd.py3("import requests")
'';
assertions = [
(expectOneStartPlugin config)
];
};
# Test that plugin lua dependencies are handled
lua-dependencies =
{ config, ... }:
{
performance.combinePlugins.enable = true;
extraPlugins = [
simplePlugin1
# Duplicated plenary-nvim dependency
pluginWithLuaDeps1
pluginWithLuaDeps2
# nui-nvim dependency
pluginWithLuaDeps3
];
extraConfigLuaPost = ''
-- All packages and its dependencies are importable
require("telescope")
require("plenary")
require("cmp")
require("gitsigns")
require("nui.popup")
'';
assertions = [
(expectOneStartPlugin config)
];
};
# Test that optional plugins are handled # Test that optional plugins are handled
optional-plugins = optional-plugins =
{ config, ... }: { config, ... }:
{ {
performance.combinePlugins.enable = true; performance.combinePlugins.enable = true;
extraPlugins = [ extraPlugins = with pluginStubs; [
# Start plugins # Start plugins
simplePlugin1 plugin1
simplePlugin2 plugin3
# Optional plugin # Optional plugin
{ {
plugin = simplePlugin3; plugin = plugin2;
optional = true; optional = true;
} }
# Optional plugin with dependency on simplePlugin1 # Optional plugin with dependencies on plugin3 and plugin4
# Dependencies should not be duplicated # Dependencies should not be duplicated
{ {
plugin = pluginWithDeps1; plugin = pluginWithDep4;
optional = true; optional = true;
} }
]; ];
extraConfigLuaPost = '' extraConfigLuaPost = ''
-- Start plugins are loadable -- Start plugins are working. Dependencies of the optional plugins are also available.
require("simple-plugin-1") ${pluginStubs.pluginChecksFor [
require("simple-plugin-2") "plugin1"
"plugin3"
"plugin4" # Dependency of the optional plugin
]}
-- Opt plugins are not loadable -- Lua libraries are available. Libs of the optional plugins are also available.
local ok = pcall(require, "simple-plugin-3") ${pluginStubs.libChecksFor [
assert(not ok, "simplePlugin3 is loadable, expected it to be an opt plugin") "lib1"
ok = pcall(require, "plugin-with-deps-1") "lib2" # Dependency of the optional plugin
assert(not ok, "pluginWithDeps1 is loadable, expected it to be an opt plugin") "lib3"
]}
-- Load plugins ${lib.concatMapStrings
vim.cmd.packadd("simple-plugin-3") (
vim.cmd.packadd("plugin-with-deps-1") name: # lua
''
-- Optional plugin is not loadable
local ok = pcall(require, "${name}")
assert(not ok, "${name} is loadable, expected it to be an opt plugin")
-- Now opt plugins are loadable -- Load plugin
require("simple-plugin-3") vim.cmd.packadd("${name}")
require("plugin-with-deps-1")
-- Only one copy of simplePlugin1 should be available -- Now opt plugin is working
local num_plugins = #vim.api.nvim_get_runtime_file("lua/simple-plugin-1/init.lua", true) ${pluginStubs.pluginChecksFor [ name ]}
assert(num_plugins == 1, "expected 1 copy of simplePlugin1, got " .. num_plugins) '')
[
"plugin2"
"plugin_with_dep4"
]
}
-- Only one copy of dependent plugin should be available
${lib.concatMapStrings
(
name: # lua
''
local num_plugins = #vim.api.nvim_get_runtime_file("lua/${name}/init.lua", true)
assert(num_plugins == 1, "expected 1 copy of ${name}, got " .. num_plugins)
'')
[
"plugin3"
"plugin4"
]
}
''; '';
assertions = [ assertions = [
(expectOneStartPlugin config) (expectOneStartPlugin config)
# simplePlugin3 pluginWithDeps1 # plugin2 plugin_with_dep4
(expectNPlugins config "opt" 2) (expectNPlugins config "opt" 2)
]; ];
}; };
@ -314,25 +178,25 @@ in
{ config, ... }: { config, ... }:
{ {
performance.combinePlugins.enable = true; performance.combinePlugins.enable = true;
extraPlugins = [ extraPlugins = with pluginStubs; [
# A plugin without config # A plugin without config
simplePlugin1 plugin1
# Plugin with config # A plugin with config
{ {
plugin = simplePlugin2; plugin = plugin2;
config = "let g:simple_plugin_2 = 1"; config = "let g:plugin2_var = 1";
} }
# Optional plugin with config # Optional plugin with config
{ {
plugin = simplePlugin3; plugin = plugin3;
optional = true; optional = true;
config = "let g:simple_plugin_3 = 1"; config = "let g:plugin3_var = 1";
} }
]; ];
extraConfigLuaPost = '' extraConfigLuaPost = ''
-- Configs are evaluated -- Configs are evaluated
assert(vim.g.simple_plugin_2 == 1, "simplePlugin2's config isn't evaluated") assert(vim.g.plugin2_var == 1, "plugin2's config isn't evaluated")
assert(vim.g.simple_plugin_3 == 1, "simplePlugin3's config isn't evaluated") assert(vim.g.plugin3_var == 1, "plugin3's config isn't evaluated")
''; '';
assertions = [ assertions = [
(expectOneStartPlugin config) (expectOneStartPlugin config)
@ -344,24 +208,24 @@ in
{ config, ... }: { config, ... }:
{ {
performance.combinePlugins.enable = true; performance.combinePlugins.enable = true;
extraPlugins = [ extraPlugins = with pluginStubs; [
simplePlugin1 plugin1
simplePlugin2 plugin2
]; ];
# Ensure that build.extraFiles is added to 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 = {
"lua/simple-plugin-1/init.lua".text = "return 1"; "lua/plugin1/init.lua".text = "return 1";
}; };
# Another form of user files # Another form of user files
files = { files = {
"lua/simple-plugin-2/init.lua" = { "lua/plugin2/init.lua" = {
extraConfigLua = "return 1"; extraConfigLua = "return 1";
}; };
}; };
extraConfigLuaPost = '' extraConfigLuaPost = ''
for _, file in ipairs({"lua/simple-plugin-1/init.lua", "lua/simple-plugin-2/init.lua"}) do for _, file in ipairs({"lua/plugin1/init.lua", "lua/plugin2/init.lua"}) do
local paths_found = vim.api.nvim_get_runtime_file(file, true) local paths_found = vim.api.nvim_get_runtime_file(file, true)
local num_found = #paths_found local num_found = #paths_found
@ -383,55 +247,53 @@ in
# Test that standalonePlugins option works # Test that standalonePlugins option works
standalone-plugins = standalone-plugins =
{ config, ... }: { config, ... }:
let
standalonePlugins = [
# By plugin name
"plugin1"
# By package itself. Its dependency, plugin4, not in this list, so will be combined
pluginStubs.pluginWithDep4
# Dependency of other plugin
"plugin5"
# Both dependency and top-level plugin
"plugin3"
];
in
{ {
performance.combinePlugins = { performance.combinePlugins = {
enable = true; enable = true;
standalonePlugins = [ inherit standalonePlugins;
# By plugin name
"simple-plugin-1"
# By package itself. Its dependency, simplePlugin2, not in this list, so will be combined
pluginWithDeps2
# Dependency of other plugin
"simple-plugin-3"
];
}; };
extraPlugins = [ extraPlugins = pluginStubs.pluginPack;
simplePlugin1
pluginWithDeps2
pluginWithDeps3
pluginWithExtraFiles
];
extraConfigLuaPost = '' extraConfigLuaPost = ''
local tests = { ${pluginStubs.pluginChecks}
{"simple-plugin-1", true},
{"plugin-with-deps-2", true},
{"simple-plugin-2", false},
{"plugin-with-deps-3", false},
{"simple-plugin-3", true},
{"plugin-with-extra-files", false},
}
for _, test in ipairs(tests) do
local name = test[1]
local expected_standalone = test[2]
-- Plugin is loadable ${lib.concatMapStringsSep "\n" (
require(test[1]) name:
let
local paths = vim.api.nvim_get_runtime_file("lua/" .. name, true) isStandalone = builtins.elem name (
-- Plugins shouldn't be duplicated map (x: if builtins.isString x then x else lib.getName x) standalonePlugins
assert(#paths == 1, "expected exactly 1 copy of '" .. name .. "' in runtime, got ", #paths) );
-- Test if plugin is standalone. This matches directory name before '/lua/'. expectedText = if isStandalone then "standalone" else "combined";
local is_standalone = paths[1]:match("^(.+)/lua/"):find(name, 1, true) ~= nil in
local expected_text = expected_standalone and "standalone" or "combined" # lua
assert( ''
is_standalone == expected_standalone, -- Check that ${name} plugin is ${expectedText}
"expected '" .. name .. "' to be " .. expected_text .. ", found path: " .. paths[1] local paths = vim.api.nvim_get_runtime_file("lua/${name}", true)
) -- Plugins shouldn't be duplicated
end 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
assert(
is_standalone == ${lib.nixvim.toLuaObject isStandalone},
"expected '${name}' to be ${expectedText}, found path: " .. paths[1]
)
''
) pluginStubs.pluginNames}
''; '';
assertions = [ assertions = [
# plugin-pack, simplePlugin1, pluginWithDeps2, simplePlugin3 # plugin-pack and 'standalonePlugins'
(expectNPlugins config "start" 4) (expectNPlugins config "start" (builtins.length standalonePlugins + 1))
]; ];
}; };

View file

@ -58,6 +58,7 @@ let
prev: prev:
{ {
inherit name; inherit name;
pname = name;
buildCommand = '' buildCommand = ''
${prev.buildCommand} ${prev.buildCommand}
# Activate vimGenDocHook for doc checks to pass # Activate vimGenDocHook for doc checks to pass