telescope-frecency.nvim/lua/frecency/tests/frecency_spec.lua
JINNOUCHI Yasushi 58c0089414
fix!: register realpath for consistency (#240)
Now it uses realpath for registering and validating DB. This means, if you have entries that has filenames differing only for case, it can deal with them as they exist.

Before this, it has miscalculated scores for such cases. For example, in case you have `/path/to/foo.lua` and `/path/to/Foo.lua`, it registers entries for each file. Now it detects accurate filename for the specified one, and removes it in validation.

* test: separate logic for utils

* fix!: register realpath for consistency

* refactor: convert fs module from class

* refactor: move db initialization phase to start()

* fix: run database:start() truly asynchronously

* fix: call each functions with async wrapping

* refactor: add types for args in command

* fix: run register() synchronously

Because vim.api.nvim_* cannot be used in asynchronous functions.

* docs: add note for calling setup() twice

* fix: run non-fast logic on next tick
2024-08-15 17:40:03 +09:00

326 lines
13 KiB
Lua

-- HACK: This is needed because plenary.test_harness resets &rtp.
-- https://github.com/nvim-lua/plenary.nvim/blob/663246936325062427597964d81d30eaa42ab1e4/lua/plenary/test_harness.lua#L86-L86
vim.opt.runtimepath:append(vim.env.TELESCOPE_PATH)
local util = require "frecency.tests.util"
local log = require "plenary.log"
local filepath = util.filepath
local make_epoch = util.make_epoch
local make_register = util.make_register
local with_fake_register = util.with_fake_register
local with_files = util.with_files
describe("frecency", function()
describe("register", function()
describe("when opening files", function()
with_files({ "hoge1.txt", "hoge2.txt" }, function(frecency, finder, dir)
local register = make_register(frecency, dir)
local epoch1 = make_epoch "2023-07-29T00:00:00+09:00"
local epoch2 = make_epoch "2023-07-29T01:00:00+09:00"
-- HACK: This suspicious 'swapfile' setting is for avoiding E303.
vim.o.swapfile = false
register("hoge1.txt", epoch1)
vim.o.swapfile = true
register("hoge2.txt", epoch2)
it("has valid records in DB", function()
local results = finder:get_results(nil, make_epoch "2023-07-29T02:00:00+09:00")
assert.are.same({
{ count = 1, path = filepath(dir, "hoge2.txt"), score = 10, timestamps = { epoch2 } },
{ count = 1, path = filepath(dir, "hoge1.txt"), score = 10, timestamps = { epoch1 } },
}, results)
end)
end)
end)
describe("when opening again", function()
with_files({ "hoge1.txt", "hoge2.txt" }, function(frecency, finder, dir)
local register = make_register(frecency, dir)
local epoch11 = make_epoch "2023-07-29T00:00:00+09:00"
local epoch2 = make_epoch "2023-07-29T01:00:00+09:00"
local epoch12 = make_epoch "2023-07-29T02:00:00+09:00"
register("hoge1.txt", epoch11)
register("hoge2.txt", epoch2)
register("hoge1.txt", epoch12, true)
it("increases the score", function()
local results = finder:get_results(nil, make_epoch "2023-07-29T03:00:00+09:00")
assert.are.same({
{ count = 2, path = filepath(dir, "hoge1.txt"), score = 40, timestamps = { epoch11, epoch12 } },
{ count = 1, path = filepath(dir, "hoge2.txt"), score = 10, timestamps = { epoch2 } },
}, results)
end)
end)
end)
describe("when opening again but the same instance", function()
with_files({ "hoge1.txt", "hoge2.txt" }, function(frecency, finder, dir)
local register = make_register(frecency, dir)
local epoch11 = make_epoch "2023-07-29T00:00:00+09:00"
local epoch2 = make_epoch "2023-07-29T01:00:00+09:00"
local epoch12 = make_epoch "2023-07-29T02:00:00+09:00"
register("hoge1.txt", epoch11)
register("hoge2.txt", epoch2)
register("hoge1.txt", epoch12)
it("does not increase the score", function()
local results = finder:get_results(nil, make_epoch "2023-07-29T03:00:00+09:00")
assert.are.same({
{ count = 1, path = filepath(dir, "hoge2.txt"), score = 10, timestamps = { epoch2 } },
{ count = 1, path = filepath(dir, "hoge1.txt"), score = 10, timestamps = { epoch11 } },
}, results)
end)
end)
end)
describe("when opening more than 10 times", function()
with_files({ "hoge1.txt", "hoge2.txt" }, function(frecency, finder, dir)
local register = make_register(frecency, dir)
local epoch11 = make_epoch "2023-07-29T00:00:00+09:00"
local epoch12 = make_epoch "2023-07-29T00:01:00+09:00"
register("hoge1.txt", epoch11)
register("hoge1.txt", epoch12, true)
local epoch201 = make_epoch "2023-07-29T00:00:00+09:00"
local epoch202 = make_epoch "2023-07-29T00:01:00+09:00"
local epoch203 = make_epoch "2023-07-29T00:02:00+09:00"
local epoch204 = make_epoch "2023-07-29T00:03:00+09:00"
local epoch205 = make_epoch "2023-07-29T00:04:00+09:00"
local epoch206 = make_epoch "2023-07-29T00:05:00+09:00"
local epoch207 = make_epoch "2023-07-29T00:06:00+09:00"
local epoch208 = make_epoch "2023-07-29T00:07:00+09:00"
local epoch209 = make_epoch "2023-07-29T00:08:00+09:00"
local epoch210 = make_epoch "2023-07-29T00:09:00+09:00"
local epoch211 = make_epoch "2023-07-29T00:10:00+09:00"
local epoch212 = make_epoch "2023-07-29T00:11:00+09:00"
register("hoge2.txt", epoch201)
register("hoge2.txt", epoch202, true)
register("hoge2.txt", epoch203, true)
register("hoge2.txt", epoch204, true)
register("hoge2.txt", epoch205, true)
register("hoge2.txt", epoch206, true)
register("hoge2.txt", epoch207, true)
register("hoge2.txt", epoch208, true)
register("hoge2.txt", epoch209, true)
register("hoge2.txt", epoch210, true)
register("hoge2.txt", epoch211, true)
register("hoge2.txt", epoch212, true)
it("calculates score from the recent 10 times", function()
local results = finder:get_results(nil, make_epoch "2023-07-29T00:12:00+09:00")
assert.are.same({
{
count = 12,
path = filepath(dir, "hoge2.txt"),
score = 12 * (10 * 100) / 10,
timestamps = {
epoch203,
epoch204,
epoch205,
epoch206,
epoch207,
epoch208,
epoch209,
epoch210,
epoch211,
epoch212,
},
},
{
count = 2,
path = filepath(dir, "hoge1.txt"),
score = 2 * (2 * 100) / 10,
timestamps = { epoch11, epoch12 },
},
}, results)
end)
end)
end)
describe("when ignore_register is set", function()
with_files({ "hoge1.txt", "hoge2.txt" }, {
ignore_register = function(bufnr)
local _, bufname = pcall(vim.api.nvim_buf_get_name, bufnr)
local should_ignore = not not (bufname and bufname:find "hoge2%.txt$")
log.debug { bufnr = bufnr, bufname = bufname, should_ignore = should_ignore }
return should_ignore
end,
}, function(frecency, finder, dir)
local register = make_register(frecency, dir)
local epoch1 = make_epoch "2023-07-29T00:00:00+09:00"
register("hoge1.txt", epoch1)
local epoch2 = make_epoch "2023-07-29T01:00:00+09:00"
register("hoge2.txt", epoch2)
it("ignores the file the func returns true", function()
local results = finder:get_results(nil, make_epoch "2023-07-29T02:00:00+09:00")
assert.are.same({
{ count = 1, path = filepath(dir, "hoge1.txt"), score = 10, timestamps = { epoch1 } },
}, results)
end)
end)
end)
end)
describe("benchmark", function()
describe("after registered over >5000 files", function()
with_files({}, function(frecency, finder, dir)
with_fake_register(frecency, dir, function(register)
-- TODO: 6000 records is too many to use with native?
-- local file_count = 6000
local file_count = 600
if not os.getenv "CI" then
log.info "It works not on CI. Files is decreased into 10 count."
file_count = 10
end
local expected = {}
log.info(("making %d files and register them"):format(file_count))
for i = 1, file_count do
local file = ("hoge%08d.txt"):format(i)
table.insert(expected, { count = 1, path = filepath(dir, file), score = 10 })
-- HACK: disable log because it fails with too many logging
log.new({ level = "info" }, true)
register(file, make_epoch "2023-07-29T00:00:00+09:00")
log.new({}, true)
end
local start = os.clock()
local results = vim.tbl_map(function(result)
result.timestamps = nil
return result
end, finder:get_results(nil, make_epoch "2023-07-29T00:01:00+09:00"))
table.sort(results, function(a, b)
return a.path < b.path
end)
local elapsed = os.clock() - start
log.info(("it takes %f seconds in fetching all results"):format(elapsed))
it("returns appropriate latency (<1.0 second)", function()
assert.are.is_true(elapsed < 1.0)
end)
it("returns valid response", function()
assert.are.same(expected, results)
end)
end)
end)
end)
end)
describe("delete", function()
describe("when file exists", function()
with_files({ "hoge1.txt", "hoge2.txt" }, function(frecency, finder, dir)
local register = make_register(frecency, dir)
local epoch1 = make_epoch "2023-07-29T00:00:00+09:00"
local epoch2 = make_epoch "2023-07-29T00:01:00+09:00"
register("hoge1.txt", epoch1)
register("hoge2.txt", epoch2)
it("deletes the file successfully", function()
local path = filepath(dir, "hoge2.txt")
local result
---@diagnostic disable-next-line: duplicate-set-field, invisible
frecency.notify = function(self, fmt, ...)
---@diagnostic disable-next-line: invisible
vim.notify(self:message(fmt, ...))
result = true
end
frecency:delete(path)
assert.are.same(result, true)
end)
it("returns valid results", function()
local results = finder:get_results(nil, make_epoch "2023-07-29T02:00:00+09:00")
assert.are.same({
{ count = 1, path = filepath(dir, "hoge1.txt"), score = 10, timestamps = { epoch1 } },
}, results)
end)
end)
end)
end)
describe("query", function()
with_files({ "hoge1.txt", "hoge2.txt", "hoge3.txt", "hoge4.txt" }, function(frecency, _, dir)
local register = make_register(frecency, dir)
local epoch11 = make_epoch "2023-07-29T00:00:00+09:00"
local epoch2 = make_epoch "2023-07-29T00:01:00+09:00"
local epoch12 = make_epoch "2023-07-29T00:02:00+09:00"
local epoch31 = make_epoch "2023-07-29T00:03:00+09:00"
local epoch13 = make_epoch "2023-07-29T00:04:00+09:00"
local epoch32 = make_epoch "2023-07-29T00:05:00+09:00"
local epoch4 = make_epoch "2023-07-29T00:06:00+09:00"
register("hoge1.txt", epoch11)
register("hoge2.txt", epoch2)
register("hoge1.txt", epoch12, true)
register("hoge3.txt", epoch31)
register("hoge1.txt", epoch13, true)
register("hoge3.txt", epoch32, true)
register("hoge4.txt", epoch4)
for _, c in ipairs {
{
desc = "with no opts",
opts = nil,
results = {
filepath(dir, "hoge1.txt"),
filepath(dir, "hoge3.txt"),
filepath(dir, "hoge2.txt"),
filepath(dir, "hoge4.txt"),
},
},
{
desc = "with an empty opts",
opts = {},
results = {
filepath(dir, "hoge1.txt"),
filepath(dir, "hoge3.txt"),
filepath(dir, "hoge2.txt"),
filepath(dir, "hoge4.txt"),
},
},
{
desc = "with limit",
opts = { limit = 3 },
results = {
filepath(dir, "hoge1.txt"),
filepath(dir, "hoge3.txt"),
filepath(dir, "hoge2.txt"),
},
},
{
desc = "with limit, direction",
opts = { direction = "asc", limit = 3 },
results = {
filepath(dir, "hoge2.txt"),
filepath(dir, "hoge4.txt"),
filepath(dir, "hoge3.txt"),
},
},
{
desc = "with limit, direction, order",
opts = { direction = "asc", limit = 3, order = "path" },
results = {
filepath(dir, "hoge1.txt"),
filepath(dir, "hoge2.txt"),
filepath(dir, "hoge3.txt"),
},
},
{
desc = "with limit, direction, order, record",
opts = { direction = "asc", limit = 3, order = "path", record = true },
results = {
{ count = 3, path = filepath(dir, "hoge1.txt"), score = 90, timestamps = { epoch11, epoch12, epoch13 } },
{ count = 1, path = filepath(dir, "hoge2.txt"), score = 10, timestamps = { epoch2 } },
{ count = 2, path = filepath(dir, "hoge3.txt"), score = 40, timestamps = { epoch31, epoch32 } },
},
},
} do
describe(c.desc, function()
it("returns valid results", function()
assert.are.same(c.results, frecency:query(c.opts, make_epoch "2023-07-29T04:00:00+09:00"))
end)
end)
end
end)
end)
end)