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
inherit (pkgs) lib;
pluginStubs = pkgs.callPackage ../../../utils/plugin-stubs.nix { };
# Assertion for a number of plugins of given type defined in nvimPackage.packpathDirs
expectNPlugins =
@ -20,110 +20,26 @@ let
};
# Assertion that exactly one start plugin is defined in nvimPackage.packpathDirs
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
{
# Test basic functionality
default =
{ config, ... }:
let
extraPlugins = [
simplePlugin1
simplePlugin2
simplePlugin3
];
in
{
performance.combinePlugins.enable = true;
inherit extraPlugins;
extraConfigLuaPost = lib.concatMapStringsSep "\n" (
name:
# lua
''
-- Plugin is loadable
require("${name}")
extraPlugins = pluginStubs.pluginPack;
extraConfigLuaPost = ''
${pluginStubs.pluginChecks}
-- No separate plugin entry in vim.api.nvim_list_runtime_paths()
assert(not vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry)
return entry:find("${name}", 1, true)
end), "plugin '${name}' found in runtime, expected to be combined")
-- Help tags are generated
assert(vim.fn.getcompletion("${name}", "help")[1], "no help tags for '${name}'")
'') (map lib.getName extraPlugins);
-- No separate plugin entry in vim.api.nvim_list_runtime_paths()
${lib.concatMapStrings (
name: # lua
''
assert(not vim.iter(vim.api.nvim_list_runtime_paths()):any(function(entry)
return entry:find("${name}", 1, true)
end), "plugin '${name}' found in runtime, expected to be combined")
'') pluginStubs.pluginNames}
'';
assertions = [
(expectOneStartPlugin config)
];
@ -132,16 +48,9 @@ in
# Test disabled option
disabled =
{ config, ... }:
let
extraPlugins = [
simplePlugin1
simplePlugin2
simplePlugin3
];
in
{
performance.combinePlugins.enable = false;
inherit extraPlugins;
extraPlugins = pluginStubs.pluginPack;
extraConfigLuaPost = lib.concatMapStringsSep "\n" (
name:
# lua
@ -150,40 +59,9 @@ in
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);
'') pluginStubs.pluginNames;
assertions = [
(expectNPlugins config "start" (builtins.length extraPlugins))
];
};
# 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)
(expectNPlugins config "start" (builtins.length pluginStubs.pluginPack))
];
};
@ -195,8 +73,18 @@ in
enable = true;
pathsToLink = [ "/_extra" ];
};
extraPlugins = [ pluginWithExtraFiles ];
extraPlugins = [
# A plugin with extra directory
(pluginStubs.mkPlugin "extra" {
postInstall = ''
mkdir $out/_extra
touch $out/_extra/test
'';
})
];
extraConfigLuaPost = ''
${pluginStubs.pluginChecksFor [ "extra" ]}
-- Test file is in runtime
assert(
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
optional-plugins =
{ config, ... }:
{
performance.combinePlugins.enable = true;
extraPlugins = [
extraPlugins = with pluginStubs; [
# Start plugins
simplePlugin1
simplePlugin2
plugin1
plugin3
# Optional plugin
{
plugin = simplePlugin3;
plugin = plugin2;
optional = true;
}
# Optional plugin with dependency on simplePlugin1
# Optional plugin with dependencies on plugin3 and plugin4
# Dependencies should not be duplicated
{
plugin = pluginWithDeps1;
plugin = pluginWithDep4;
optional = true;
}
];
extraConfigLuaPost = ''
-- Start plugins are loadable
require("simple-plugin-1")
require("simple-plugin-2")
-- Start plugins are working. Dependencies of the optional plugins are also available.
${pluginStubs.pluginChecksFor [
"plugin1"
"plugin3"
"plugin4" # Dependency of the optional plugin
]}
-- Opt plugins are not loadable
local ok = pcall(require, "simple-plugin-3")
assert(not ok, "simplePlugin3 is loadable, expected it to be an opt plugin")
ok = pcall(require, "plugin-with-deps-1")
assert(not ok, "pluginWithDeps1 is loadable, expected it to be an opt plugin")
-- Lua libraries are available. Libs of the optional plugins are also available.
${pluginStubs.libChecksFor [
"lib1"
"lib2" # Dependency of the optional plugin
"lib3"
]}
-- Load plugins
vim.cmd.packadd("simple-plugin-3")
vim.cmd.packadd("plugin-with-deps-1")
${lib.concatMapStrings
(
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
require("simple-plugin-3")
require("plugin-with-deps-1")
-- Load plugin
vim.cmd.packadd("${name}")
-- Only one copy of simplePlugin1 should be available
local num_plugins = #vim.api.nvim_get_runtime_file("lua/simple-plugin-1/init.lua", true)
assert(num_plugins == 1, "expected 1 copy of simplePlugin1, got " .. num_plugins)
-- Now opt plugin is working
${pluginStubs.pluginChecksFor [ name ]}
'')
[
"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 = [
(expectOneStartPlugin config)
# simplePlugin3 pluginWithDeps1
# plugin2 plugin_with_dep4
(expectNPlugins config "opt" 2)
];
};
@ -314,25 +178,25 @@ in
{ config, ... }:
{
performance.combinePlugins.enable = true;
extraPlugins = [
extraPlugins = with pluginStubs; [
# A plugin without config
simplePlugin1
# Plugin with config
plugin1
# A plugin with config
{
plugin = simplePlugin2;
config = "let g:simple_plugin_2 = 1";
plugin = plugin2;
config = "let g:plugin2_var = 1";
}
# Optional plugin with config
{
plugin = simplePlugin3;
plugin = plugin3;
optional = true;
config = "let g:simple_plugin_3 = 1";
config = "let g:plugin3_var = 1";
}
];
extraConfigLuaPost = ''
-- Configs are evaluated
assert(vim.g.simple_plugin_2 == 1, "simplePlugin2's config isn't evaluated")
assert(vim.g.simple_plugin_3 == 1, "simplePlugin3's config isn't evaluated")
assert(vim.g.plugin2_var == 1, "plugin2's config isn't evaluated")
assert(vim.g.plugin3_var == 1, "plugin3's config isn't evaluated")
'';
assertions = [
(expectOneStartPlugin config)
@ -344,24 +208,24 @@ in
{ config, ... }:
{
performance.combinePlugins.enable = true;
extraPlugins = [
simplePlugin1
simplePlugin2
extraPlugins = with pluginStubs; [
plugin1
plugin2
];
# Ensure that build.extraFiles is added to extraPlugins
wrapRc = true;
# Extra user files colliding with plugins
extraFiles = {
"lua/simple-plugin-1/init.lua".text = "return 1";
"lua/plugin1/init.lua".text = "return 1";
};
# Another form of user files
files = {
"lua/simple-plugin-2/init.lua" = {
"lua/plugin2/init.lua" = {
extraConfigLua = "return 1";
};
};
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 num_found = #paths_found
@ -383,55 +247,53 @@ in
# Test that standalonePlugins option works
standalone-plugins =
{ 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 = {
enable = true;
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"
];
inherit standalonePlugins;
};
extraPlugins = [
simplePlugin1
pluginWithDeps2
pluginWithDeps3
pluginWithExtraFiles
];
extraPlugins = pluginStubs.pluginPack;
extraConfigLuaPost = ''
local tests = {
{"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]
${pluginStubs.pluginChecks}
-- Plugin is loadable
require(test[1])
local paths = vim.api.nvim_get_runtime_file("lua/" .. name, true)
-- 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
${lib.concatMapStringsSep "\n" (
name:
let
isStandalone = builtins.elem name (
map (x: if builtins.isString x then x else lib.getName x) standalonePlugins
);
expectedText = if isStandalone then "standalone" else "combined";
in
# lua
''
-- Check that ${name} plugin is ${expectedText}
local paths = vim.api.nvim_get_runtime_file("lua/${name}", true)
-- 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
assert(
is_standalone == ${lib.nixvim.toLuaObject isStandalone},
"expected '${name}' to be ${expectedText}, found path: " .. paths[1]
)
''
) pluginStubs.pluginNames}
'';
assertions = [
# plugin-pack, simplePlugin1, pluginWithDeps2, simplePlugin3
(expectNPlugins config "start" 4)
# plugin-pack and 'standalonePlugins'
(expectNPlugins config "start" (builtins.length standalonePlugins + 1))
];
};

View file

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