Files
vimpack/tests/fs_spec.lua
T
unkin-agent 35b9df9eba
ci/woodpecker/pr/pre-commit Pipeline failed
ci/woodpecker/pr/lint Pipeline failed
ci/woodpecker/pr/test Pipeline failed
Add vimpack: archive-based Neovim plugin manager
## Why
Cloning plugins from git ties the editor to GitHub uptime and moving branches; archives at a pinned version from our own registry are reproducible and reachable offline.

## How
- Add a registry resolver interface `(spec, registry) -> {url, headers, filename, sha256?}` with builtin `template` and `artifactapi` kinds, a per-plugin registry override and a `url` escape hatch.
- Take auth tokens only from an env var or a `token_cmd`; reject a literal token at setup.
- Download with curl, verify an optional sha256, extract to a staging dir and rename into `pack/vimpack/{start,opt}/<name>`, restoring the previous tree if the swap fails.
- Track installed name/version/sha256 in `stdpath('data')/vimpack/manifest.json` and skip plugins already at the wanted version.
- Add `:VimpackInstall`, `:VimpackUpdate`, `:VimpackClean` and `:VimpackStatus`, running downloads through `vim.system` under a concurrency cap.
- Hash with a pure-Lua SHA-256; `vim.fn.sha256()` rejects binary archives with E976.
- Add a dependency-free `tests/minimal.lua` harness and 57 specs covering resolution, auth, manifest, planning, checksum mismatch, orphan detection and end-to-end install.
- Add `.woodpecker/{test,lint,pre-commit}.yaml`, luacheck/stylua config and pre-commit hooks.
2026-09-05 13:28:53 +10:00

106 lines
3.5 KiB
Lua

local fsmod = require('vimpack.fs')
describe('scan', function()
it('maps directories to their bucket', function()
local root = tmpdir()
vim.fn.mkdir(root .. '/start/a/lua', 'p')
vim.fn.mkdir(root .. '/opt/b', 'p')
vim.fn.writefile({ '' }, root .. '/start/loose.txt')
local found = fsmod.scan(root)
assert_eq(false, found.a.opt)
assert_eq(true, found.b.opt)
assert_nil(found['loose.txt'])
end)
it('returns nothing for a missing root', function()
assert_eq({}, fsmod.scan(tmpdir() .. '/absent'))
end)
end)
describe('target_dir', function()
it('splits start and opt', function()
assert_eq('/r/start/a', fsmod.target_dir({ name = 'a', dir_name = 'a', opt = false }, '/r'))
assert_eq('/r/opt/a', fsmod.target_dir({ name = 'a', dir_name = 'a', opt = true }, '/r'))
end)
end)
describe('strip_top_level', function()
it('hoists a single wrapper directory', function()
local root = tmpdir()
vim.fn.mkdir(root .. '/oil.nvim-2.11.0/lua', 'p')
assert_eq(root .. '/oil.nvim-2.11.0', fsmod.strip_top_level(root))
end)
it('leaves a flat archive alone', function()
local root = tmpdir()
vim.fn.mkdir(root .. '/lua', 'p')
vim.fn.mkdir(root .. '/plugin', 'p')
assert_eq(root, fsmod.strip_top_level(root))
end)
end)
describe('swap', function()
it('replaces an existing install', function()
local root = tmpdir()
vim.fn.mkdir(root .. '/target', 'p')
vim.fn.writefile({ 'old' }, root .. '/target/marker')
vim.fn.mkdir(root .. '/staged', 'p')
vim.fn.writefile({ 'new' }, root .. '/staged/marker')
assert_true(fsmod.swap(root .. '/staged', root .. '/target'))
assert_eq({ 'new' }, vim.fn.readfile(root .. '/target/marker'))
assert_true(not fsmod.exists(root .. '/target.vimpack-old'))
end)
it('keeps the previous install when the staged tree is missing', function()
local root = tmpdir()
vim.fn.mkdir(root .. '/target', 'p')
vim.fn.writefile({ 'old' }, root .. '/target/marker')
local ok, err = fsmod.swap(root .. '/absent', root .. '/target')
assert_true(not ok)
assert_match('cannot move new install into place', err)
assert_eq({ 'old' }, vim.fn.readfile(root .. '/target/marker'))
end)
end)
describe('extract', function()
local function wait_extract(archive, dest)
local result
fsmod.extract(archive, dest, function(ok, err)
result = { ok = ok, err = err }
end)
vim.wait(10000, function()
return result ~= nil
end)
return result
end
it('unpacks a tarball', function()
local root = tmpdir()
vim.fn.mkdir(root .. '/src/plug/lua', 'p')
vim.fn.writefile({ 'return {}' }, root .. '/src/plug/lua/plug.lua')
vim.fn.system({ 'tar', '-czf', root .. '/plug.tar.gz', '-C', root .. '/src', 'plug' })
local result = wait_extract(root .. '/plug.tar.gz', root .. '/dest')
assert_true(result.ok, tostring(result.err))
assert_true(fsmod.exists(root .. '/dest/plug/lua/plug.lua'))
assert_eq(root .. '/dest/plug', fsmod.strip_top_level(root .. '/dest'))
end)
it('rejects an unknown archive type', function()
local result = wait_extract(tmpdir() .. '/thing.rpm', tmpdir() .. '/dest')
assert_true(not result.ok)
assert_match('unsupported archive type', result.err)
end)
it('reports a corrupt tarball', function()
local root = tmpdir()
vim.fn.writefile({ 'definitely not a tarball' }, root .. '/bad.tar.gz')
local result = wait_extract(root .. '/bad.tar.gz', root .. '/dest')
assert_true(not result.ok)
assert_match('extraction failed', result.err)
end)
end)