feat: first draft
This commit is contained in:
parent
bf2dfb970d
commit
fefd6ad5e4
48 changed files with 7201 additions and 1 deletions
311
tests/files_spec.lua
Normal file
311
tests/files_spec.lua
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
require("plenary.async").tests.add_to_env()
|
||||
local fs = require("oil.fs")
|
||||
local files = require("oil.adapters.files")
|
||||
local cache = require("oil.cache")
|
||||
|
||||
local function throwiferr(err, ...)
|
||||
if err then
|
||||
error(err)
|
||||
else
|
||||
return ...
|
||||
end
|
||||
end
|
||||
|
||||
local function await(fn, nargs, ...)
|
||||
return throwiferr(a.wrap(fn, nargs)(...))
|
||||
end
|
||||
|
||||
---@param path string
|
||||
---@param cb fun(err: nil|string)
|
||||
local function touch(path, cb)
|
||||
vim.loop.fs_open(path, "w", 420, function(err, fd) -- 0644
|
||||
if err then
|
||||
cb(err)
|
||||
else
|
||||
local shortpath = path:gsub("^[^" .. fs.sep .. "]*" .. fs.sep, "")
|
||||
vim.loop.fs_write(fd, shortpath, nil, function(err2)
|
||||
if err2 then
|
||||
cb(err2)
|
||||
else
|
||||
vim.loop.fs_close(fd, cb)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
---@param filepath string
|
||||
---@return boolean
|
||||
local function exists(filepath)
|
||||
local stat = vim.loop.fs_stat(filepath)
|
||||
return stat ~= nil and stat.type ~= nil
|
||||
end
|
||||
|
||||
local TmpDir = {}
|
||||
|
||||
TmpDir.new = function()
|
||||
local path = await(vim.loop.fs_mkdtemp, 2, "oil_test_XXXXXXXXX")
|
||||
return setmetatable({ path = path }, {
|
||||
__index = TmpDir,
|
||||
})
|
||||
end
|
||||
|
||||
---@param paths string[]
|
||||
function TmpDir:create(paths)
|
||||
for _, path in ipairs(paths) do
|
||||
local pieces = vim.split(path, fs.sep)
|
||||
local partial_path = self.path
|
||||
for i, piece in ipairs(pieces) do
|
||||
partial_path = fs.join(partial_path, piece)
|
||||
if i == #pieces and not vim.endswith(partial_path, fs.sep) then
|
||||
await(touch, 2, partial_path)
|
||||
elseif not exists(partial_path) then
|
||||
vim.loop.fs_mkdir(partial_path, 493)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---@param filepath string
|
||||
---@return string?
|
||||
local read_file = function(filepath)
|
||||
local fd = vim.loop.fs_open(filepath, "r", 420)
|
||||
if not fd then
|
||||
return nil
|
||||
end
|
||||
local stat = vim.loop.fs_fstat(fd)
|
||||
local content = vim.loop.fs_read(fd, stat.size)
|
||||
vim.loop.fs_close(fd)
|
||||
return content
|
||||
end
|
||||
|
||||
---@param dir string
|
||||
---@param cb fun(err: nil|string, entry: {type: oil.EntryType, name: string, root: string}
|
||||
local function walk(dir)
|
||||
local ret = {}
|
||||
for name, type in vim.fs.dir(dir) do
|
||||
table.insert(ret, {
|
||||
name = name,
|
||||
type = type,
|
||||
root = dir,
|
||||
})
|
||||
if type == "directory" then
|
||||
vim.list_extend(ret, walk(fs.join(dir, name)))
|
||||
end
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
---@param paths table<string, string>
|
||||
local assert_fs = function(root, paths)
|
||||
local unlisted_dirs = {}
|
||||
for k in pairs(paths) do
|
||||
local pieces = vim.split(k, "/")
|
||||
local partial_path = ""
|
||||
for i, piece in ipairs(pieces) do
|
||||
partial_path = fs.join(partial_path, piece) .. "/"
|
||||
if i ~= #pieces then
|
||||
unlisted_dirs[partial_path:sub(2)] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
for k in pairs(unlisted_dirs) do
|
||||
paths[k] = true
|
||||
end
|
||||
|
||||
local entries = walk(root)
|
||||
for _, entry in ipairs(entries) do
|
||||
local fullpath = fs.join(entry.root, entry.name)
|
||||
local shortpath = fullpath:sub(root:len() + 2)
|
||||
if entry.type == "directory" then
|
||||
shortpath = shortpath .. "/"
|
||||
end
|
||||
local expected_content = paths[shortpath]
|
||||
paths[shortpath] = nil
|
||||
assert.truthy(expected_content, string.format("Unexpected entry '%s'", shortpath))
|
||||
if entry.type == "file" then
|
||||
local data = read_file(fullpath)
|
||||
assert.equals(
|
||||
expected_content,
|
||||
data,
|
||||
string.format(
|
||||
"File '%s' expected content '%s' received '%s'",
|
||||
shortpath,
|
||||
expected_content,
|
||||
data
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in pairs(paths) do
|
||||
assert.falsy(
|
||||
k,
|
||||
string.format(
|
||||
"Expected %s '%s', but it was not found",
|
||||
v == true and "directory" or "file",
|
||||
k
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
---@param paths table<string, string>
|
||||
function TmpDir:assert_fs(paths)
|
||||
a.util.scheduler()
|
||||
assert_fs(self.path, paths)
|
||||
end
|
||||
|
||||
function TmpDir:dispose()
|
||||
await(fs.recursive_delete, 3, "directory", self.path)
|
||||
end
|
||||
|
||||
a.describe("files adapter", function()
|
||||
local tmpdir
|
||||
a.before_each(function()
|
||||
tmpdir = TmpDir.new()
|
||||
end)
|
||||
a.after_each(function()
|
||||
if tmpdir then
|
||||
tmpdir:dispose()
|
||||
a.util.scheduler()
|
||||
tmpdir = nil
|
||||
end
|
||||
for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
|
||||
vim.api.nvim_buf_delete(bufnr, { force = true })
|
||||
end
|
||||
cache.clear_everything()
|
||||
end)
|
||||
|
||||
a.it("tmpdir creates files and asserts they exist", function()
|
||||
tmpdir:create({ "a.txt", "foo/b.txt", "foo/c.txt", "bar/" })
|
||||
tmpdir:assert_fs({
|
||||
["a.txt"] = "a.txt",
|
||||
["foo/b.txt"] = "foo/b.txt",
|
||||
["foo/c.txt"] = "foo/c.txt",
|
||||
["bar/"] = true,
|
||||
})
|
||||
end)
|
||||
|
||||
a.it("Creates files", function()
|
||||
local err = a.wrap(files.perform_action, 2)({
|
||||
url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a.txt",
|
||||
entry_type = "file",
|
||||
type = "create",
|
||||
})
|
||||
assert.is_nil(err)
|
||||
tmpdir:assert_fs({
|
||||
["a.txt"] = "",
|
||||
})
|
||||
end)
|
||||
|
||||
a.it("Creates directories", function()
|
||||
local err = a.wrap(files.perform_action, 2)({
|
||||
url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a",
|
||||
entry_type = "directory",
|
||||
type = "create",
|
||||
})
|
||||
assert.is_nil(err)
|
||||
tmpdir:assert_fs({
|
||||
["a/"] = true,
|
||||
})
|
||||
end)
|
||||
|
||||
a.it("Deletes files", function()
|
||||
tmpdir:create({ "a.txt" })
|
||||
a.util.scheduler()
|
||||
local url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a.txt"
|
||||
local err = a.wrap(files.perform_action, 2)({
|
||||
url = url,
|
||||
entry_type = "file",
|
||||
type = "delete",
|
||||
})
|
||||
assert.is_nil(err)
|
||||
tmpdir:assert_fs({})
|
||||
end)
|
||||
|
||||
a.it("Deletes directories", function()
|
||||
tmpdir:create({ "a/" })
|
||||
local url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a"
|
||||
local err = a.wrap(files.perform_action, 2)({
|
||||
url = url,
|
||||
entry_type = "directory",
|
||||
type = "delete",
|
||||
})
|
||||
assert.is_nil(err)
|
||||
tmpdir:assert_fs({})
|
||||
end)
|
||||
|
||||
a.it("Moves files", function()
|
||||
tmpdir:create({ "a.txt" })
|
||||
a.util.scheduler()
|
||||
local src_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a.txt"
|
||||
local dest_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "b.txt"
|
||||
local err = a.wrap(files.perform_action, 2)({
|
||||
src_url = src_url,
|
||||
dest_url = dest_url,
|
||||
entry_type = "file",
|
||||
type = "move",
|
||||
})
|
||||
assert.is_nil(err)
|
||||
tmpdir:assert_fs({
|
||||
["b.txt"] = "a.txt",
|
||||
})
|
||||
end)
|
||||
|
||||
a.it("Moves directories", function()
|
||||
tmpdir:create({ "a/a.txt" })
|
||||
a.util.scheduler()
|
||||
local src_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a"
|
||||
local dest_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "b"
|
||||
local err = a.wrap(files.perform_action, 2)({
|
||||
src_url = src_url,
|
||||
dest_url = dest_url,
|
||||
entry_type = "directory",
|
||||
type = "move",
|
||||
})
|
||||
assert.is_nil(err)
|
||||
tmpdir:assert_fs({
|
||||
["b/a.txt"] = "a/a.txt",
|
||||
["b/"] = true,
|
||||
})
|
||||
end)
|
||||
|
||||
a.it("Copies files", function()
|
||||
tmpdir:create({ "a.txt" })
|
||||
a.util.scheduler()
|
||||
local src_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a.txt"
|
||||
local dest_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "b.txt"
|
||||
local err = a.wrap(files.perform_action, 2)({
|
||||
src_url = src_url,
|
||||
dest_url = dest_url,
|
||||
entry_type = "file",
|
||||
type = "copy",
|
||||
})
|
||||
assert.is_nil(err)
|
||||
tmpdir:assert_fs({
|
||||
["a.txt"] = "a.txt",
|
||||
["b.txt"] = "a.txt",
|
||||
})
|
||||
end)
|
||||
|
||||
a.it("Recursively copies directories", function()
|
||||
tmpdir:create({ "a/a.txt" })
|
||||
a.util.scheduler()
|
||||
local src_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "a"
|
||||
local dest_url = "oil://" .. vim.fn.fnamemodify(tmpdir.path, ":p") .. "b"
|
||||
local err = a.wrap(files.perform_action, 2)({
|
||||
src_url = src_url,
|
||||
dest_url = dest_url,
|
||||
entry_type = "directory",
|
||||
type = "copy",
|
||||
})
|
||||
assert.is_nil(err)
|
||||
tmpdir:assert_fs({
|
||||
["b/a.txt"] = "a/a.txt",
|
||||
["b/"] = true,
|
||||
["a/a.txt"] = "a/a.txt",
|
||||
["a/"] = true,
|
||||
})
|
||||
end)
|
||||
end)
|
||||
11
tests/minimal_init.lua
Normal file
11
tests/minimal_init.lua
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
vim.cmd([[set runtimepath+=.]])
|
||||
|
||||
vim.o.swapfile = false
|
||||
vim.bo.swapfile = false
|
||||
require("oil").setup({
|
||||
columms = {},
|
||||
adapters = {
|
||||
["oil-test://"] = "test",
|
||||
},
|
||||
trash = false,
|
||||
})
|
||||
540
tests/mutator_spec.lua
Normal file
540
tests/mutator_spec.lua
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
require("plenary.async").tests.add_to_env()
|
||||
local FIELD = require("oil.constants").FIELD
|
||||
local view = require("oil.view")
|
||||
local cache = require("oil.cache")
|
||||
local mutator = require("oil.mutator")
|
||||
local parser = require("oil.mutator.parser")
|
||||
local test_adapter = require("oil.adapters.test")
|
||||
local util = require("oil.util")
|
||||
|
||||
local function set_lines(bufnr, lines)
|
||||
vim.bo[bufnr].modifiable = true
|
||||
vim.api.nvim_buf_set_lines(bufnr, 0, -1, true, lines)
|
||||
end
|
||||
|
||||
a.describe("mutator", function()
|
||||
after_each(function()
|
||||
for _, bufnr in ipairs(vim.api.nvim_list_bufs()) do
|
||||
vim.api.nvim_buf_delete(bufnr, { force = true })
|
||||
end
|
||||
cache.clear_everything()
|
||||
end)
|
||||
|
||||
describe("parser", function()
|
||||
it("detects new files", function()
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
set_lines(bufnr, {
|
||||
"a.txt",
|
||||
})
|
||||
local diffs = parser.parse(bufnr)
|
||||
assert.are.same({ { entry_type = "file", name = "a.txt", type = "new" } }, diffs)
|
||||
end)
|
||||
|
||||
it("detects new directories", function()
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
set_lines(bufnr, {
|
||||
"foo/",
|
||||
})
|
||||
local diffs = parser.parse(bufnr)
|
||||
assert.are.same({ { entry_type = "directory", name = "foo", type = "new" } }, diffs)
|
||||
end)
|
||||
|
||||
it("detects deleted files", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///foo/", "a.txt", "file")
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
set_lines(bufnr, {})
|
||||
local diffs = parser.parse(bufnr)
|
||||
assert.are.same({
|
||||
{ name = "a.txt", type = "delete", id = file[FIELD.id] },
|
||||
}, diffs)
|
||||
end)
|
||||
|
||||
it("detects deleted directories", function()
|
||||
local dir = cache.create_and_store_entry("oil-test:///foo/", "bar", "directory")
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
set_lines(bufnr, {})
|
||||
local diffs = parser.parse(bufnr)
|
||||
assert.are.same({
|
||||
{ name = "bar", type = "delete", id = dir[FIELD.id] },
|
||||
}, diffs)
|
||||
end)
|
||||
|
||||
it("ignores empty lines", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///foo/", "a.txt", "file")
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local cols = view.format_entry_cols(file, {}, {}, test_adapter)
|
||||
local lines = util.render_table({ cols }, {})
|
||||
table.insert(lines, "")
|
||||
table.insert(lines, " ")
|
||||
set_lines(bufnr, lines)
|
||||
local diffs = parser.parse(bufnr)
|
||||
assert.are.same({}, diffs)
|
||||
end)
|
||||
|
||||
it("errors on missing filename", function()
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
set_lines(bufnr, {
|
||||
"/008",
|
||||
})
|
||||
local _, errors = parser.parse(bufnr)
|
||||
assert.are_same({
|
||||
{
|
||||
message = "Malformed ID at start of line",
|
||||
lnum = 0,
|
||||
col = 0,
|
||||
},
|
||||
}, errors)
|
||||
end)
|
||||
|
||||
it("errors on empty dirname", function()
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
set_lines(bufnr, {
|
||||
"/008 /",
|
||||
})
|
||||
local _, errors = parser.parse(bufnr)
|
||||
assert.are.same({
|
||||
{
|
||||
message = "No filename found",
|
||||
lnum = 1,
|
||||
col = 0,
|
||||
},
|
||||
}, errors)
|
||||
end)
|
||||
|
||||
it("ignores new dirs with empty name", function()
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
set_lines(bufnr, {
|
||||
"/",
|
||||
})
|
||||
local diffs = parser.parse(bufnr)
|
||||
assert.are.same({}, diffs)
|
||||
end)
|
||||
|
||||
it("parses a rename as a delete + new", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///foo/", "a.txt", "file")
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
set_lines(bufnr, {
|
||||
string.format("/%d b.txt", file[FIELD.id]),
|
||||
})
|
||||
local diffs = parser.parse(bufnr)
|
||||
assert.are.same({
|
||||
{ type = "new", id = file[FIELD.id], name = "b.txt", entry_type = "file" },
|
||||
{ type = "delete", id = file[FIELD.id], name = "a.txt" },
|
||||
}, diffs)
|
||||
end)
|
||||
|
||||
it("detects renamed files that conflict", function()
|
||||
local afile = cache.create_and_store_entry("oil-test:///foo/", "a.txt", "file")
|
||||
local bfile = cache.create_and_store_entry("oil-test:///foo/", "b.txt", "file")
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
set_lines(bufnr, {
|
||||
string.format("/%d a.txt", bfile[FIELD.id]),
|
||||
string.format("/%d b.txt", afile[FIELD.id]),
|
||||
})
|
||||
local diffs = parser.parse(bufnr)
|
||||
local first_two = { diffs[1], diffs[2] }
|
||||
local last_two = { diffs[3], diffs[4] }
|
||||
table.sort(first_two, function(a, b)
|
||||
return a.id < b.id
|
||||
end)
|
||||
table.sort(last_two, function(a, b)
|
||||
return a.id < b.id
|
||||
end)
|
||||
assert.are.same({
|
||||
{ name = "b.txt", type = "new", id = afile[FIELD.id], entry_type = "file" },
|
||||
{ name = "a.txt", type = "new", id = bfile[FIELD.id], entry_type = "file" },
|
||||
}, first_two)
|
||||
assert.are.same({
|
||||
{ name = "a.txt", type = "delete", id = afile[FIELD.id] },
|
||||
{ name = "b.txt", type = "delete", id = bfile[FIELD.id] },
|
||||
}, last_two)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("build actions", function()
|
||||
it("empty diffs produce no actions", function()
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local actions = mutator.create_actions_from_diffs({
|
||||
[bufnr] = {},
|
||||
})
|
||||
assert.are.same({}, actions)
|
||||
end)
|
||||
|
||||
it("constructs CREATE actions", function()
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local diffs = {
|
||||
{ type = "new", name = "a.txt", entry_type = "file" },
|
||||
}
|
||||
local actions = mutator.create_actions_from_diffs({
|
||||
[bufnr] = diffs,
|
||||
})
|
||||
assert.are.same({
|
||||
{
|
||||
type = "create",
|
||||
entry_type = "file",
|
||||
url = "oil-test:///foo/a.txt",
|
||||
},
|
||||
}, actions)
|
||||
end)
|
||||
|
||||
it("constructs DELETE actions", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///foo/", "a.txt", "file")
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local diffs = {
|
||||
{ type = "delete", name = "a.txt", id = file[FIELD.id] },
|
||||
}
|
||||
local actions = mutator.create_actions_from_diffs({
|
||||
[bufnr] = diffs,
|
||||
})
|
||||
assert.are.same({
|
||||
{
|
||||
type = "delete",
|
||||
entry_type = "file",
|
||||
url = "oil-test:///foo/a.txt",
|
||||
},
|
||||
}, actions)
|
||||
end)
|
||||
|
||||
it("constructs COPY actions", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///foo/", "a.txt", "file")
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local diffs = {
|
||||
{ type = "new", name = "b.txt", entry_type = "file", id = file[FIELD.id] },
|
||||
}
|
||||
local actions = mutator.create_actions_from_diffs({
|
||||
[bufnr] = diffs,
|
||||
})
|
||||
assert.are.same({
|
||||
{
|
||||
type = "copy",
|
||||
entry_type = "file",
|
||||
src_url = "oil-test:///foo/a.txt",
|
||||
dest_url = "oil-test:///foo/b.txt",
|
||||
},
|
||||
}, actions)
|
||||
end)
|
||||
|
||||
it("constructs MOVE actions", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///foo/", "a.txt", "file")
|
||||
vim.cmd.edit({ args = { "oil-test:///foo/" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local diffs = {
|
||||
{ type = "delete", name = "a.txt", id = file[FIELD.id] },
|
||||
{ type = "new", name = "b.txt", entry_type = "file", id = file[FIELD.id] },
|
||||
}
|
||||
local actions = mutator.create_actions_from_diffs({
|
||||
[bufnr] = diffs,
|
||||
})
|
||||
assert.are.same({
|
||||
{
|
||||
type = "move",
|
||||
entry_type = "file",
|
||||
src_url = "oil-test:///foo/a.txt",
|
||||
dest_url = "oil-test:///foo/b.txt",
|
||||
},
|
||||
}, actions)
|
||||
end)
|
||||
|
||||
it("correctly orders MOVE + CREATE", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///", "a.txt", "file")
|
||||
vim.cmd.edit({ args = { "oil-test:///" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local diffs = {
|
||||
{ type = "delete", name = "a.txt", id = file[FIELD.id] },
|
||||
{ type = "new", name = "b.txt", entry_type = "file", id = file[FIELD.id] },
|
||||
{ type = "new", name = "a.txt", entry_type = "file" },
|
||||
}
|
||||
local actions = mutator.create_actions_from_diffs({
|
||||
[bufnr] = diffs,
|
||||
})
|
||||
assert.are.same({
|
||||
{
|
||||
type = "move",
|
||||
entry_type = "file",
|
||||
src_url = "oil-test:///a.txt",
|
||||
dest_url = "oil-test:///b.txt",
|
||||
},
|
||||
{
|
||||
type = "create",
|
||||
entry_type = "file",
|
||||
url = "oil-test:///a.txt",
|
||||
},
|
||||
}, actions)
|
||||
end)
|
||||
|
||||
it("resolves MOVE loops", function()
|
||||
local afile = cache.create_and_store_entry("oil-test:///", "a.txt", "file")
|
||||
local bfile = cache.create_and_store_entry("oil-test:///", "b.txt", "file")
|
||||
vim.cmd.edit({ args = { "oil-test:///" } })
|
||||
local bufnr = vim.api.nvim_get_current_buf()
|
||||
local diffs = {
|
||||
{ type = "delete", name = "a.txt", id = afile[FIELD.id] },
|
||||
{ type = "new", name = "b.txt", entry_type = "file", id = afile[FIELD.id] },
|
||||
{ type = "delete", name = "b.txt", id = bfile[FIELD.id] },
|
||||
{ type = "new", name = "a.txt", entry_type = "file", id = bfile[FIELD.id] },
|
||||
}
|
||||
math.randomseed(2983982)
|
||||
local actions = mutator.create_actions_from_diffs({
|
||||
[bufnr] = diffs,
|
||||
})
|
||||
local tmp_url = "oil-test:///a.txt__oil_tmp_510852"
|
||||
assert.are.same({
|
||||
{
|
||||
type = "move",
|
||||
entry_type = "file",
|
||||
src_url = "oil-test:///a.txt",
|
||||
dest_url = tmp_url,
|
||||
},
|
||||
{
|
||||
type = "move",
|
||||
entry_type = "file",
|
||||
src_url = "oil-test:///b.txt",
|
||||
dest_url = "oil-test:///a.txt",
|
||||
},
|
||||
{
|
||||
type = "move",
|
||||
entry_type = "file",
|
||||
src_url = tmp_url,
|
||||
dest_url = "oil-test:///b.txt",
|
||||
},
|
||||
}, actions)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("order actions", function()
|
||||
it("Creates files inside dir before move", function()
|
||||
local move = {
|
||||
type = "move",
|
||||
src_url = "oil-test:///a",
|
||||
dest_url = "oil-test:///b",
|
||||
entry_type = "directory",
|
||||
}
|
||||
local create = { type = "create", url = "oil-test:///a/hi.txt", entry_type = "file" }
|
||||
local actions = { move, create }
|
||||
local ordered_actions = mutator.enforce_action_order(actions)
|
||||
assert.are.same({ create, move }, ordered_actions)
|
||||
end)
|
||||
|
||||
it("Handles parent child move ordering", function()
|
||||
-- move parent into a child and child OUT of parent
|
||||
-- MOVE /a/b -> /b
|
||||
-- MOVE /a -> /b/a
|
||||
local move1 = {
|
||||
type = "move",
|
||||
src_url = "oil-test:///a/b",
|
||||
dest_url = "oil-test:///b",
|
||||
entry_type = "directory",
|
||||
}
|
||||
local move2 = {
|
||||
type = "move",
|
||||
src_url = "oil-test:///a",
|
||||
dest_url = "oil-test:///b/a",
|
||||
entry_type = "directory",
|
||||
}
|
||||
local actions = { move2, move1 }
|
||||
local ordered_actions = mutator.enforce_action_order(actions)
|
||||
assert.are.same({ move1, move2 }, ordered_actions)
|
||||
end)
|
||||
|
||||
it("Detects move directory loops", function()
|
||||
local move = {
|
||||
type = "move",
|
||||
src_url = "oil-test:///a",
|
||||
dest_url = "oil-test:///a/b",
|
||||
entry_type = "directory",
|
||||
}
|
||||
assert.has_error(function()
|
||||
mutator.enforce_action_order({ move })
|
||||
end)
|
||||
end)
|
||||
|
||||
it("Detects copy directory loops", function()
|
||||
local move = {
|
||||
type = "copy",
|
||||
src_url = "oil-test:///a",
|
||||
dest_url = "oil-test:///a/b",
|
||||
entry_type = "directory",
|
||||
}
|
||||
assert.has_error(function()
|
||||
mutator.enforce_action_order({ move })
|
||||
end)
|
||||
end)
|
||||
|
||||
it("Detects nested copy directory loops", function()
|
||||
local move = {
|
||||
type = "copy",
|
||||
src_url = "oil-test:///a",
|
||||
dest_url = "oil-test:///a/b/a",
|
||||
entry_type = "directory",
|
||||
}
|
||||
assert.has_error(function()
|
||||
mutator.enforce_action_order({ move })
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("change", function()
|
||||
it("applies CHANGE after CREATE", function()
|
||||
local create = { type = "create", url = "oil-test:///a/hi.txt", entry_type = "file" }
|
||||
local change = {
|
||||
type = "change",
|
||||
url = "oil-test:///a/hi.txt",
|
||||
entry_type = "file",
|
||||
column = "TEST",
|
||||
value = "TEST",
|
||||
}
|
||||
local actions = { change, create }
|
||||
local ordered_actions = mutator.enforce_action_order(actions)
|
||||
assert.are.same({ create, change }, ordered_actions)
|
||||
end)
|
||||
|
||||
it("applies CHANGE after COPY src", function()
|
||||
local copy = {
|
||||
type = "copy",
|
||||
src_url = "oil-test:///a/hi.txt",
|
||||
dest_url = "oil-test:///b.txt",
|
||||
entry_type = "file",
|
||||
}
|
||||
local change = {
|
||||
type = "change",
|
||||
url = "oil-test:///a/hi.txt",
|
||||
entry_type = "file",
|
||||
column = "TEST",
|
||||
value = "TEST",
|
||||
}
|
||||
local actions = { change, copy }
|
||||
local ordered_actions = mutator.enforce_action_order(actions)
|
||||
assert.are.same({ copy, change }, ordered_actions)
|
||||
end)
|
||||
|
||||
it("applies CHANGE after COPY dest", function()
|
||||
local copy = {
|
||||
type = "copy",
|
||||
src_url = "oil-test:///b.txt",
|
||||
dest_url = "oil-test:///a/hi.txt",
|
||||
entry_type = "file",
|
||||
}
|
||||
local change = {
|
||||
type = "change",
|
||||
url = "oil-test:///a/hi.txt",
|
||||
entry_type = "file",
|
||||
column = "TEST",
|
||||
value = "TEST",
|
||||
}
|
||||
local actions = { change, copy }
|
||||
local ordered_actions = mutator.enforce_action_order(actions)
|
||||
assert.are.same({ copy, change }, ordered_actions)
|
||||
end)
|
||||
|
||||
it("applies CHANGE after MOVE dest", function()
|
||||
local move = {
|
||||
type = "move",
|
||||
src_url = "oil-test:///b.txt",
|
||||
dest_url = "oil-test:///a/hi.txt",
|
||||
entry_type = "file",
|
||||
}
|
||||
local change = {
|
||||
type = "change",
|
||||
url = "oil-test:///a/hi.txt",
|
||||
entry_type = "file",
|
||||
column = "TEST",
|
||||
value = "TEST",
|
||||
}
|
||||
local actions = { change, move }
|
||||
local ordered_actions = mutator.enforce_action_order(actions)
|
||||
assert.are.same({ move, change }, ordered_actions)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
|
||||
a.describe("perform actions", function()
|
||||
a.it("creates new entries", function()
|
||||
local actions = {
|
||||
{ type = "create", url = "oil-test:///a.txt", entry_type = "file" },
|
||||
}
|
||||
a.wrap(mutator.process_actions, 2)(actions)
|
||||
local files = cache.list_url("oil-test:///")
|
||||
assert.are.same({
|
||||
["a.txt"] = {
|
||||
[FIELD.id] = 1,
|
||||
[FIELD.type] = "file",
|
||||
[FIELD.name] = "a.txt",
|
||||
},
|
||||
}, files)
|
||||
end)
|
||||
|
||||
a.it("deletes entries", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///", "a.txt", "file")
|
||||
local actions = {
|
||||
{ type = "delete", url = "oil-test:///a.txt", entry_type = "file" },
|
||||
}
|
||||
a.wrap(mutator.process_actions, 2)(actions)
|
||||
local files = cache.list_url("oil-test:///")
|
||||
assert.are.same({}, files)
|
||||
assert.is_nil(cache.get_entry_by_id(file[FIELD.id]))
|
||||
assert.has_error(function()
|
||||
cache.get_parent_url(file[FIELD.id])
|
||||
end)
|
||||
end)
|
||||
|
||||
a.it("moves entries", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///", "a.txt", "file")
|
||||
local actions = {
|
||||
{
|
||||
type = "move",
|
||||
src_url = "oil-test:///a.txt",
|
||||
dest_url = "oil-test:///b.txt",
|
||||
entry_type = "file",
|
||||
},
|
||||
}
|
||||
a.wrap(mutator.process_actions, 2)(actions)
|
||||
local files = cache.list_url("oil-test:///")
|
||||
local new_entry = {
|
||||
[FIELD.id] = file[FIELD.id],
|
||||
[FIELD.type] = "file",
|
||||
[FIELD.name] = "b.txt",
|
||||
}
|
||||
assert.are.same({
|
||||
["b.txt"] = new_entry,
|
||||
}, files)
|
||||
assert.are.same(new_entry, cache.get_entry_by_id(file[FIELD.id]))
|
||||
assert.equals("oil-test:///", cache.get_parent_url(file[FIELD.id]))
|
||||
end)
|
||||
|
||||
a.it("copies entries", function()
|
||||
local file = cache.create_and_store_entry("oil-test:///", "a.txt", "file")
|
||||
local actions = {
|
||||
{
|
||||
type = "copy",
|
||||
src_url = "oil-test:///a.txt",
|
||||
dest_url = "oil-test:///b.txt",
|
||||
entry_type = "file",
|
||||
},
|
||||
}
|
||||
a.wrap(mutator.process_actions, 2)(actions)
|
||||
local files = cache.list_url("oil-test:///")
|
||||
local new_entry = {
|
||||
[FIELD.id] = file[FIELD.id] + 1,
|
||||
[FIELD.type] = "file",
|
||||
[FIELD.name] = "b.txt",
|
||||
}
|
||||
assert.are.same({
|
||||
["a.txt"] = file,
|
||||
["b.txt"] = new_entry,
|
||||
}, files)
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
32
tests/path_spec.lua
Normal file
32
tests/path_spec.lua
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
local pathutil = require("oil.pathutil")
|
||||
describe("pathutil", function()
|
||||
it("calculates parent path", function()
|
||||
local cases = {
|
||||
{ "/foo/bar", "/foo/" },
|
||||
{ "/foo/bar/", "/foo/" },
|
||||
{ "/", "/" },
|
||||
{ "", "" },
|
||||
{ "foo/bar/", "foo/" },
|
||||
{ "foo", "" },
|
||||
}
|
||||
for _, case in ipairs(cases) do
|
||||
local input, expected = unpack(case)
|
||||
local output = pathutil.parent(input)
|
||||
assert.equals(expected, output, string.format('Parent path "%s" failed', input))
|
||||
end
|
||||
end)
|
||||
|
||||
it("calculates basename", function()
|
||||
local cases = {
|
||||
{ "/foo/bar", "bar" },
|
||||
{ "/foo/bar/", "bar" },
|
||||
{ "/", nil },
|
||||
{ "", nil },
|
||||
}
|
||||
for _, case in ipairs(cases) do
|
||||
local input, expected = unpack(case)
|
||||
local output = pathutil.basename(input)
|
||||
assert.equals(expected, output, string.format('Basename "%s" failed', input))
|
||||
end
|
||||
end)
|
||||
end)
|
||||
24
tests/url_spec.lua
Normal file
24
tests/url_spec.lua
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
local oil = require("oil")
|
||||
local util = require("oil.util")
|
||||
describe("url", function()
|
||||
it("get_url_for_path", function()
|
||||
local cases = {
|
||||
{ "", "oil://" .. util.addslash(vim.fn.getcwd()) },
|
||||
{ "/foo/bar.txt", "oil:///foo/", "bar.txt" },
|
||||
{ "oil:///foo/bar.txt", "oil:///foo/", "bar.txt" },
|
||||
{ "oil:///", "oil:///" },
|
||||
{ "scp://user@hostname:8888//bar.txt", "oil-ssh://user@hostname:8888//", "bar.txt" },
|
||||
{ "oil-ssh://user@hostname:8888//", "oil-ssh://user@hostname:8888//" },
|
||||
}
|
||||
for _, case in ipairs(cases) do
|
||||
local input, expected, expected_basename = unpack(case)
|
||||
local output, basename = oil.get_buffer_parent_url(input)
|
||||
assert.equals(expected, output, string.format('Parent url for path "%s" failed', input))
|
||||
assert.equals(
|
||||
expected_basename,
|
||||
basename,
|
||||
string.format('Basename for path "%s" failed', input)
|
||||
)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
Loading…
Add table
Add a link
Reference in a new issue