Files
neovim/test/functional/core/path_spec.lua
Justin M. Keyes 6d8c8b18d5 test(harness): migrate away from magic globals
Problem:
The magic globals `it`, `describe`, etc., are more trouble than they are
worth.

- Hooking into `after_each` requires `getfenv()` hacks.
- They confuse luals/emmylua, because the top-level `.luarc.json` isn't
  merged with `test/.luarc.json` (apparently a luals limitation?)
- They totally defeat discoverability because the user just has to
  "know" about the various magic symbols.

So they harm DX, which means they serve no purpose at all.

Solution:
- Expose the test API from `testutil`, so tests can call `t.it()`,
  `t.describe()`, etc., in the conventional way.
- Drop `getfenv()` hacks.
- Drop the `setfenv()` injection in `load_chunk`.
- Drop `test/_meta.lua`.
2026-07-21 13:22:39 +02:00

266 lines
7.8 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local t = require('test.testutil')
local n = require('test.functional.testnvim')()
local describe, it, before_each, setup, teardown =
t.describe, t.it, t.before_each, t.setup, t.teardown
local clear = n.clear
local command = n.command
local eq = t.eq
local eval = n.eval
local feed = n.feed
local fn = n.fn
local insert = n.insert
local is_os = t.is_os
local mkdir = t.mkdir
local rmdir = n.rmdir
local write_file = t.write_file
local api = n.api
local function join_path(...)
return table.concat({ ... }, '/')
end
describe('path', function()
local targetdir
local expected_path
before_each(function()
targetdir = join_path('test', 'functional', 'fixtures')
clear()
command('edit ' .. join_path(targetdir, 'tty-test.c'))
expected_path = eval('expand("%:p")')
end)
it('with /./ segment #7117', function()
command('edit ' .. join_path(targetdir, '.', 'tty-test.c'))
eq(expected_path, eval('expand("%:p")'))
end)
it('with ./ prefix #7117', function()
command('edit ' .. join_path('.', targetdir, 'tty-test.c'))
eq(expected_path, eval('expand("%:p")'))
end)
it('with ./ prefix, after directory change #7117', function()
command('edit ' .. join_path('.', targetdir, 'tty-test.c'))
command('cd test')
eq(expected_path, eval('expand("%:p")'))
end)
it('with /../ segment #7117', function()
command('edit ' .. join_path(targetdir, '..', 'fixtures', 'tty-test.c'))
eq(expected_path, eval('expand("%:p")'))
end)
it('with ../ and different starting directory #7117', function()
command('cd test')
command('edit ' .. join_path('..', targetdir, 'tty-test.c'))
eq(expected_path, eval('expand("%:p")'))
end)
it('with ./../ and different starting directory #7117', function()
command('cd test')
command('edit ' .. join_path('.', '..', targetdir, 'tty-test.c'))
eq(expected_path, eval('expand("%:p")'))
end)
it('with implicit drive letter #40013', function()
t.skip(not is_os('win'), 'N/A: only works on Windows')
command('edit ' .. expected_path:sub(3))
eq(1, #fn.getbufinfo())
eq(expected_path, eval('expand("%:p")'))
end)
end)
describe('startup', function()
local home, foo, bar = vim.fs.normalize('~'), 'Xtest-foo.lua', 'Xtest-bar.lua'
setup(function()
write_file(('%s/%s'):format(home, foo), 'local foo = 1;')
write_file(('%s/%s'):format(home, bar), '')
end)
teardown(function()
os.remove(('%s/%s'):format(home, foo))
os.remove(('%s/%s'):format(home, bar))
end)
it('expands tilde-prefixed paths #29380', function()
t.skip(not is_os('win'), 'N/A: shell expands ~ on Unix')
clear {
args = { ('~/%s'):format(foo), ('~\\%s'):format(bar) },
}
local expected = { ('%s/%s'):format(home, foo), ('%s/%s'):format(home, bar) }
eq(expected, vim.tbl_map(fn.bufname, api.nvim_list_bufs()))
eq(expected, fn.argv())
end)
it('normalizes v:progpath #39382', function()
clear()
eq(
n.nvim_prog,
fn.system({
is_os('win') and n.nvim_prog:gsub('/', '\\') or n.nvim_prog,
'--clean',
'--headless',
'+echo v:progpath',
'+q',
})
)
end)
it('normalizes -u arguments and triggers autocmd events #39382', function()
local file = ('%s/%s'):format(home, foo)
if is_os('win') then
file = file:gsub('/', '\\')
end
clear {
args_rm = { '--cmd', '-u' },
args = {
'--cmd',
('autocmd SourcePre */%s let g:matched = 1'):format(foo),
'-u',
file,
},
}
local scripts = fn.getscriptinfo({ name = foo })
eq(1, #scripts)
eq(('%s/%s'):format(home, foo), scripts[1].name)
t.ok(fn.eval('g:matched'))
end)
end)
describe('expand wildcard', function()
before_each(clear)
it('with special characters #24421', function()
local folders = is_os('win') and {
'{folder}',
'folder$name',
} or {
'folder-name',
'folder#name',
}
for _, folder in ipairs(folders) do
mkdir(folder)
local file = ('%s%sfile.txt'):format(folder, n.get_pathsep())
write_file(file, '')
eq(file, fn.expand(('%s/*'):format(folder)))
rmdir(folder)
end
end)
end)
describe('file search', function()
local testdir = 'Xtest_path_spec'
before_each(clear)
setup(function()
mkdir(testdir)
end)
teardown(function()
rmdir(testdir)
end)
it('gf finds multibyte filename in line #20517', function()
command('cd test/functional/fixtures')
insert('filename_with_unicode_ααα')
eq('', eval('expand("%")'))
feed('gf')
eq('filename_with_unicode_ααα', eval('expand("%:t")'))
end)
it('gf/<cfile> matches Windows drive-letter filepaths (without ":" in &isfname)', function()
local iswin = is_os('win')
local function test_cfile(input, expected, expected_win)
expected = (iswin and expected_win or expected) or input
command('%delete')
insert(input)
command('norm! 0')
eq(expected, eval('expand("<cfile>")'))
end
-- test_cfile([[c:/d:/e:/foo/bar.txt]], 'c:/d:/e') -- TODO(justinmk): should return "d:/foo/bar.txt" ?
test_cfile([[c:/d:/foo/bar.txt]]) -- TODO(justinmk): should return "d:/foo/bar.txt" ?
test_cfile([[//share/c:/foo/bar/]])
test_cfile([[file://c:/foo/bar]])
test_cfile([[file://c:/foo/bar:42]])
test_cfile([[file://c:/foo/bar:42:666]])
test_cfile([[https://c:/foo/bar]])
test_cfile([[\foo\bar]], [[foo]], [[\foo\bar]])
test_cfile([[/foo/bar]], [[/foo/bar]])
test_cfile([[c:\foo\bar]], [[c:]], [[c:\foo\bar]])
test_cfile([[c:\foo\bar:42:666]], [[c:]], [[c:\foo\bar]])
test_cfile([[c:/foo/bar]])
test_cfile([[c:/foo/bar:42]], [[c:/foo/bar]])
test_cfile([[c:/foo/bar:42:666]], [[c:/foo/bar]])
test_cfile([[c:foo\bar]], [[c]])
test_cfile([[c:foo/bar]], [[c]])
test_cfile([[c:foo]], [[c]])
-- Examples from: https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats#example-ways-to-refer-to-the-same-file
test_cfile([[c:\temp\test-file.txt]], [[c:]], [[c:\temp\test-file.txt]])
test_cfile(
[[\\127.0.0.1\c$\temp\test-file.txt]],
[[127.0.0.1]],
[[\\127.0.0.1\c$\temp\test-file.txt]]
)
test_cfile(
[[\\LOCALHOST\c$\temp\test-file.txt]],
[[LOCALHOST]],
[[\\LOCALHOST\c$\temp\test-file.txt]]
)
-- not supported yet
test_cfile([[\\.\c:\temp\test-file.txt]], [[.]], [[\\.\c]])
-- not supported yet
test_cfile([[\\?\c:\temp\test-file.txt]], [[c:]], [[\\]])
test_cfile(
[[\\.\UNC\LOCALHOST\c$\temp\test-file.txt]],
[[.]],
[[\\.\UNC\LOCALHOST\c$\temp\test-file.txt]]
)
test_cfile(
[[\\127.0.0.1\c$\temp\test-file.txt]],
[[127.0.0.1]],
[[\\127.0.0.1\c$\temp\test-file.txt]]
)
end)
it('gf/<cfile> handles local file: paths', function()
local path = fn.fnamemodify(join_path(testdir, 'gf-target.txt'), ':p'):gsub('\\', '/')
local uri = 'file:' .. (is_os('win') and '/' or '') .. path
write_file(path, '')
insert(uri)
command('norm! 0')
eq(path, eval('expand("<cfile>")'))
feed('gf')
eq(path, fn.fnamemodify(eval('expand("%:p")'), ':p'):gsub('\\', '/'))
end)
---@param funcname 'finddir' | 'findfile'
local function test_find_func(funcname, folder, item)
local d = join_path(testdir, folder)
mkdir(d)
local expected = join_path(d, item)
if funcname == 'finddir' then
mkdir(expected)
else
write_file(expected, '')
end
eq(expected, fn[funcname](item, d:gsub(' ', [[\ ]])))
end
it('finddir()', function()
test_find_func('finddir', 'directory', 'folder')
test_find_func('finddir', 'directory', 'folder name')
test_find_func('finddir', 'fold#er name', 'directory')
end)
it('findfile()', function()
test_find_func('findfile', 'directory', 'file.txt')
test_find_func('findfile', 'directory', 'file name.txt')
test_find_func('findfile', 'fold#er name', 'file.txt')
end)
end)