Feat: Sort Discussions by File Name (#102)
This MR adds the ability to sort discussions by file name, rather than just by date. This is an optional configuration that can be passed in on startup. The MR also introduces a test suite for the Lua code that runs through Neovim, so that the plugin can be fully tested with required dependencies and APIs. Major props to @johnybx for the hard work on this change!
This commit is contained in:
40
tests/init.lua
Normal file
40
tests/init.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
---Initialize neovim to use lua modules from luarocks and prepare correct search paths for
|
||||
---modules, neovim plugins and load busted frameworks.
|
||||
|
||||
local function build_path(modules, extensions)
|
||||
local path = ""
|
||||
for _, module_path in ipairs(modules) do
|
||||
for _, lua_path_extension in ipairs(extensions) do
|
||||
path = path .. module_path .. lua_path_extension .. ";"
|
||||
end
|
||||
end
|
||||
return path
|
||||
end
|
||||
|
||||
local plugins_folder = "tests/plugins/*/lua"
|
||||
local luarocks_cmd = "luarocks config --scope project"
|
||||
|
||||
-- Project path
|
||||
local modules = { "lua" }
|
||||
-- External plugins - dependencies
|
||||
for plugin_path in vim.fn.glob(plugins_folder):gmatch("[^\r\n]+") do
|
||||
table.insert(modules, plugin_path)
|
||||
end
|
||||
-- Lua modules path
|
||||
table.insert(modules, vim.fn.trim(vim.fn.system(luarocks_cmd .. " deploy_lua_dir")))
|
||||
|
||||
local lua_path_extensions = { "/?.lua", "/?/init.lua" }
|
||||
package.path = build_path(modules, lua_path_extensions) .. package.path
|
||||
|
||||
local cmodules = {
|
||||
vim.fn.trim(vim.fn.system(luarocks_cmd .. " deploy_lib_dir")),
|
||||
}
|
||||
local lua_lib_extensions = { "/?.so", "/?/init.so" }
|
||||
package.cpath = build_path(cmodules, lua_lib_extensions) .. package.cpath
|
||||
|
||||
-- Initialize required plugins which needs it
|
||||
require("diffview").setup()
|
||||
|
||||
-- Run busted -
|
||||
require("busted.runner")({ standalone = false })
|
||||
os.exit(0)
|
||||
0
tests/plugins/.placeholder
Normal file
0
tests/plugins/.placeholder
Normal file
6
tests/spec/discussions_spec.lua
Normal file
6
tests/spec/discussions_spec.lua
Normal file
@@ -0,0 +1,6 @@
|
||||
describe("gitlab/actions/discussions/init.lua", function()
|
||||
it("Loads package", function()
|
||||
local utils_ok, _ = pcall(require, "gitlab.actions.discussions")
|
||||
assert._is_true(utils_ok)
|
||||
end)
|
||||
end)
|
||||
707
tests/spec/discussions_tree_spec.lua
Normal file
707
tests/spec/discussions_tree_spec.lua
Normal file
@@ -0,0 +1,707 @@
|
||||
---@class ResultNodeTree
|
||||
---@field type string
|
||||
---@field text string
|
||||
---@field children ResultNodeTree[]?
|
||||
|
||||
---Transform nui nodes to table for easier comparison in tests We could compare directly
|
||||
---NuiTree.Node but that have a lot of parameters which we don't care about
|
||||
---@param nodes NuiTree.Node[]
|
||||
---@param allowed_node_types table<string, boolean>
|
||||
---@return ResultNodeTree
|
||||
local function tree_nodes_to_table(nodes, allowed_node_types)
|
||||
local result = {}
|
||||
for _, node in ipairs(nodes) do
|
||||
assert._is_true(allowed_node_types[node.type])
|
||||
local current = {
|
||||
type = node.type,
|
||||
text = node.text,
|
||||
children = tree_nodes_to_table(node.__children, allowed_node_types),
|
||||
}
|
||||
table.insert(result, current)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
math.randomseed(os.time())
|
||||
---Create new discussion node, change ids and path
|
||||
---@param discussion Discussion
|
||||
---@param path string
|
||||
local function copy_discussion_with_new_path(discussion, path)
|
||||
local new_discussion = vim.fn.deepcopy(discussion)
|
||||
new_discussion.id = tostring(math.random(1000, 10000000))
|
||||
new_discussion.notes[1].id = math.random(1000, 10000000)
|
||||
new_discussion.notes[1].position.new_path = path
|
||||
new_discussion.notes[1].position.old_path = path
|
||||
return new_discussion
|
||||
end
|
||||
|
||||
describe("gitlab/actions/discussions/tree.lua", function()
|
||||
it("Loads package", function()
|
||||
local utils_ok, _ = pcall(require, "gitlab.actions.discussions.tree")
|
||||
assert._is_true(utils_ok)
|
||||
end)
|
||||
describe("add_discussions_to_table", function()
|
||||
local tree = require("gitlab.actions.discussions.tree")
|
||||
local state = require("gitlab.state")
|
||||
local utils = require("gitlab.utils")
|
||||
local original_time_since = utils.time_since
|
||||
local discussions
|
||||
local unlinked_discussions
|
||||
local spy_time_since
|
||||
local all_node_types = { note = true, note_body = true, path = true, file_name = true }
|
||||
|
||||
it("Returns empty list with no discussions", function()
|
||||
assert.are.same(tree.add_discussions_to_table({}), {})
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
utils.time_since = original_time_since
|
||||
end)
|
||||
before_each(function()
|
||||
spy_time_since = spy.new(function()
|
||||
return "5 days ago"
|
||||
end)
|
||||
utils.time_since = spy_time_since
|
||||
local author = {
|
||||
avatar_url = "https://secure.gravatar.com/avatar/a857c8a11e80d5c9116ad6ac4c0fb98a?s=80&d=identicon",
|
||||
email = "",
|
||||
id = 12345,
|
||||
name = "Gitlab Name",
|
||||
state = "active",
|
||||
username = "gitlab.username",
|
||||
web_url = "https://gitlab.com/gitlab.username",
|
||||
}
|
||||
local empty_resolved_by = {
|
||||
avatar_url = "",
|
||||
email = "",
|
||||
id = 0,
|
||||
name = "",
|
||||
state = "",
|
||||
username = "",
|
||||
web_url = "",
|
||||
}
|
||||
|
||||
discussions = {
|
||||
{
|
||||
id = "17c7b7558925d0caa7f73684482x9055977bf454",
|
||||
individual_note = false,
|
||||
notes = {
|
||||
{
|
||||
attachment = "",
|
||||
author = author,
|
||||
body = "Multiline comment",
|
||||
commit_id = "",
|
||||
created_at = "2023-10-28T18:27:34.082Z",
|
||||
expires_at = vim.NIL,
|
||||
file_name = "",
|
||||
id = 1624411,
|
||||
noteable_id = 240727,
|
||||
noteable_iid = 1,
|
||||
noteable_type = "MergeRequest",
|
||||
position = {
|
||||
base_sha = "d687b5ad4ad5ccd5ae9517efcd103629af1750d6",
|
||||
head_sha = "18f76ebeb6e8fcd76a80dce5b592a4f133d2ad05",
|
||||
line_range = {
|
||||
["end"] = {
|
||||
line_code = "8ec9a01bfd10b3191ac6b22252dba2aa95a0579d_18_17",
|
||||
new_line = 0,
|
||||
old_line = 0,
|
||||
type = "new",
|
||||
},
|
||||
start = {
|
||||
line_code = "8ec9a01bfd10b3191ac6b22252dba2aa95a0579d_18_19",
|
||||
new_line = 0,
|
||||
old_line = 0,
|
||||
type = "new",
|
||||
},
|
||||
},
|
||||
new_line = 17,
|
||||
new_path = "README.md",
|
||||
old_path = "README.md",
|
||||
position_type = "text",
|
||||
start_sha = "d687b5ad4ad5ccd5ae9517efcd103629af1750d6",
|
||||
},
|
||||
resolvable = true,
|
||||
resolved = false,
|
||||
resolved_at = vim.NIL,
|
||||
resolved_by = empty_resolved_by,
|
||||
system = false,
|
||||
title = "",
|
||||
type = "DiffNote",
|
||||
updated_at = "2023-10-28T18:27:34.082Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "c418928237e9e542b676d25c4211160agcs11733",
|
||||
individual_note = false,
|
||||
notes = {
|
||||
{
|
||||
attachment = "",
|
||||
author = author,
|
||||
body = "test single line comment!",
|
||||
commit_id = "",
|
||||
created_at = "2023-10-28T18:26:22.336Z",
|
||||
expires_at = vim.NIL,
|
||||
file_name = "",
|
||||
id = 1624415,
|
||||
noteable_id = 240727,
|
||||
noteable_iid = 1,
|
||||
noteable_type = "MergeRequest",
|
||||
position = {
|
||||
base_sha = "d687b5ad4ad5ccd5ae9517efcd103629af1750d6",
|
||||
head_sha = "18f76ebeb6e8fcd76a80dce5b592a4f133d2ad05",
|
||||
new_line = 11,
|
||||
new_path = "folder_1/folder_2/folder_3/file.lua",
|
||||
old_path = "folder_1/folder_2/folder_3/file.lua",
|
||||
position_type = "text",
|
||||
start_sha = "d687b5ad4ad5ccd5ae9517efcd103629af1750d6",
|
||||
},
|
||||
resolvable = true,
|
||||
resolved = false,
|
||||
resolved_at = vim.NIL,
|
||||
resolved_by = empty_resolved_by,
|
||||
system = false,
|
||||
title = "",
|
||||
type = "DiffNote",
|
||||
updated_at = "2023-10-28T18:26:22.336Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
unlinked_discussions = {
|
||||
{
|
||||
id = "16c5b7558923d0caa7f73684481c9055976bf454",
|
||||
individual_note = false,
|
||||
notes = {
|
||||
{
|
||||
attachment = "",
|
||||
author = author,
|
||||
body = "Test just unlinked note",
|
||||
commit_id = "",
|
||||
created_at = "2021-05-20T10:10:00.648Z",
|
||||
expires_at = vim.NIL,
|
||||
file_name = "",
|
||||
id = 165260,
|
||||
noteable_id = 25024,
|
||||
noteable_iid = 1,
|
||||
noteable_type = "MergeRequest",
|
||||
position = vim.NIL,
|
||||
resolvable = true,
|
||||
resolved = false,
|
||||
resolved_at = vim.NIL,
|
||||
resolved_by = empty_resolved_by,
|
||||
system = false,
|
||||
title = "",
|
||||
type = "DiscussionNote",
|
||||
updated_at = "2023-11-16T24:15:49.648Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id = "38bbe42a1bb8f2a014c4fd87d87760772f090a3c",
|
||||
individual_note = false,
|
||||
notes = {
|
||||
{
|
||||
attachment = "",
|
||||
author = author,
|
||||
body = "Other unlinked note",
|
||||
commit_id = "",
|
||||
created_at = "2022-10-25T12:20:30.648Z",
|
||||
expires_at = vim.NIL,
|
||||
file_name = "",
|
||||
id = 165260,
|
||||
noteable_id = 25024,
|
||||
noteable_iid = 1,
|
||||
noteable_type = "MergeRequest",
|
||||
position = vim.NIL,
|
||||
resolvable = true,
|
||||
resolved = false,
|
||||
resolved_at = vim.NIL,
|
||||
resolved_by = empty_resolved_by,
|
||||
system = false,
|
||||
title = "",
|
||||
type = "DiscussionNote",
|
||||
updated_at = "2023-11-16T20:15:49.648Z",
|
||||
},
|
||||
{
|
||||
attachment = "",
|
||||
author = author,
|
||||
body = "Response to the unlinked note",
|
||||
commit_id = "",
|
||||
created_at = "2023-11-18T20:15:49.648Z",
|
||||
expires_at = vim.NIL,
|
||||
file_name = "",
|
||||
id = 165260,
|
||||
noteable_id = 25024,
|
||||
noteable_iid = 1,
|
||||
noteable_type = "MergeRequest",
|
||||
position = vim.NIL,
|
||||
resolvable = true,
|
||||
resolved = false,
|
||||
resolved_at = vim.NIL,
|
||||
resolved_by = empty_resolved_by,
|
||||
system = false,
|
||||
title = "",
|
||||
type = "DiscussionNote",
|
||||
updated_at = "2023-11-16T20:15:49.648Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
end)
|
||||
|
||||
it("Returns list of note nodes if `tree_type` is `simple`", function()
|
||||
state.settings.discussion_tree.tree_type = "simple"
|
||||
local nodes = tree.add_discussions_to_table(discussions)
|
||||
assert.are.same(tree_nodes_to_table(nodes, { note = true, note_body = true }), {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
text = "Multiline comment",
|
||||
type = "note_body",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "test single line comment!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
end)
|
||||
|
||||
it("Returns path tree of note nodes if tree_type is `by_file_name`", function()
|
||||
state.settings.discussion_tree.tree_type = "by_file_name"
|
||||
local nodes = tree.add_discussions_to_table(discussions)
|
||||
assert.are.same(tree_nodes_to_table(nodes, all_node_types), {
|
||||
{
|
||||
text = "folder_1/folder_2/folder_3",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "file.lua",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "test single line comment!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "README.md",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "Multiline comment",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
end)
|
||||
it("Merges the paths in path tree if there is no file in folder", function()
|
||||
state.settings.discussion_tree.tree_type = "by_file_name"
|
||||
local nodes = tree.add_discussions_to_table({ discussions[2] })
|
||||
assert.are.same(tree_nodes_to_table(nodes, all_node_types), {
|
||||
{
|
||||
text = "folder_1/folder_2/folder_3",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "file.lua",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "test single line comment!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
end)
|
||||
it("Correctly places files in folders in file tree", function()
|
||||
state.settings.discussion_tree.tree_type = "by_file_name"
|
||||
local discussion1 = copy_discussion_with_new_path(discussions[2], "folder_1/first_level.txt")
|
||||
local discussion2 = copy_discussion_with_new_path(discussions[2], "folder_1/folder_2/second_level.txt")
|
||||
local expected_result = {
|
||||
{
|
||||
text = "folder_1",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "folder_2",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "folder_3",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "file.lua",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "test single line comment!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "second_level.txt",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "test single line comment!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "first_level.txt",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "test single line comment!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
-- Make sure that order of nodes does not change result!
|
||||
assert.are.same(
|
||||
tree_nodes_to_table(tree.add_discussions_to_table({ discussions[2], discussion2, discussion1 }), all_node_types),
|
||||
expected_result
|
||||
)
|
||||
assert.are.same(
|
||||
tree_nodes_to_table(tree.add_discussions_to_table({ discussion2, discussions[2], discussion1 }), all_node_types),
|
||||
expected_result
|
||||
)
|
||||
assert.are.same(
|
||||
tree_nodes_to_table(tree.add_discussions_to_table({ discussion2, discussion1, discussions[2] }), all_node_types),
|
||||
expected_result
|
||||
)
|
||||
assert.are.same(
|
||||
tree_nodes_to_table(tree.add_discussions_to_table({ discussion1, discussion2, discussions[2] }), all_node_types),
|
||||
expected_result
|
||||
)
|
||||
end)
|
||||
it("Correctly places files with same filenames and different paths", function()
|
||||
state.settings.discussion_tree.tree_type = "by_file_name"
|
||||
local discussion1 = copy_discussion_with_new_path(discussions[2], "folder_1/diffent_folder/folder_3/file.lua")
|
||||
discussion1.notes[1].body = "path: folder_1/diffent_folder/folder_3/file.lua"
|
||||
local discussion2 = copy_discussion_with_new_path(discussions[2], "another/folder_2/folder_3/file.lua")
|
||||
discussion2.notes[1].body = "path: another/folder_2/folder_3/file.lua"
|
||||
local expected_result = {
|
||||
{
|
||||
text = "another/folder_2/folder_3",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "file.lua",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "path: another/folder_2/folder_3/file.lua",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "folder_1",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "diffent_folder/folder_3",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "file.lua",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "path: folder_1/diffent_folder/folder_3/file.lua",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "folder_2/folder_3",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "file.lua",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "test single line comment!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.are.same(
|
||||
tree_nodes_to_table(tree.add_discussions_to_table({ discussions[2], discussion2, discussion1 }), all_node_types),
|
||||
expected_result
|
||||
)
|
||||
end)
|
||||
it("Correctly places multiple notes in same file", function()
|
||||
state.settings.discussion_tree.tree_type = "by_file_name"
|
||||
local discussion1 = copy_discussion_with_new_path(discussions[2], "folder_1/folder_2/folder_3/file.lua")
|
||||
discussion1.notes[1].body = "This is different note!"
|
||||
local expected_result = {
|
||||
{
|
||||
text = "folder_1/folder_2/folder_3",
|
||||
type = "path",
|
||||
children = {
|
||||
{
|
||||
text = "file.lua",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "test single line comment!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "This is different note!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.are.same(
|
||||
tree_nodes_to_table(tree.add_discussions_to_table({ discussions[2], discussion1 }), all_node_types),
|
||||
expected_result
|
||||
)
|
||||
end)
|
||||
it("Correctly places multiple notes in same top level file", function()
|
||||
state.settings.discussion_tree.tree_type = "by_file_name"
|
||||
local discussion1 = copy_discussion_with_new_path(discussions[1], "README.md")
|
||||
discussion1.notes[1].body = "This is different note!"
|
||||
local expected_result = {
|
||||
{
|
||||
text = "README.md",
|
||||
type = "file_name",
|
||||
children = {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "Multiline comment",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "This is different note!",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
assert.are.same(
|
||||
tree_nodes_to_table(tree.add_discussions_to_table({ discussions[1], discussion1 }), all_node_types),
|
||||
expected_result
|
||||
)
|
||||
end)
|
||||
|
||||
it("Returns list of note nodes for unlinked discussions", function()
|
||||
state.settings.discussion_tree.tree_type = "simple"
|
||||
local nodes = tree.add_discussions_to_table(unlinked_discussions, true)
|
||||
assert.are.same(tree_nodes_to_table(nodes, { note = true, note_body = true }), {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
text = "Test just unlinked note",
|
||||
type = "note_body",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "Other unlinked note",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
text = "Response to the unlinked note",
|
||||
type = "note_body",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
assert.spy(spy_time_since).was.called_with("2021-05-20T10:10:00.648Z")
|
||||
assert.spy(spy_time_since).was.called_with("2022-10-25T12:20:30.648Z")
|
||||
assert.spy(spy_time_since).was.called_with("2023-11-18T20:15:49.648Z")
|
||||
end)
|
||||
|
||||
it("Returns list of note nodes for unlinked discussions even if tree_type is not `simple`", function()
|
||||
state.settings.discussion_tree.tree_type = "by_file_name"
|
||||
local nodes = tree.add_discussions_to_table(unlinked_discussions, true)
|
||||
assert.are.same(tree_nodes_to_table(nodes, { note = true, note_body = true }), {
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
text = "Test just unlinked note",
|
||||
type = "note_body",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
text = "Other unlinked note",
|
||||
type = "note_body",
|
||||
children = {},
|
||||
},
|
||||
{
|
||||
text = "@gitlab.username 5 days ago ",
|
||||
type = "note",
|
||||
children = {
|
||||
{
|
||||
children = {},
|
||||
text = "Response to the unlinked note",
|
||||
type = "note_body",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
end)
|
||||
end)
|
||||
end)
|
||||
7
tests/spec/gitlab_spec.lua
Normal file
7
tests/spec/gitlab_spec.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
describe("gitlab", function()
|
||||
it("Loads module", function()
|
||||
require("gitlab")
|
||||
local utils_ok, _ = pcall(require, "gitlab")
|
||||
assert._is_true(utils_ok)
|
||||
end)
|
||||
end)
|
||||
219
tests/spec/util_spec.lua
Normal file
219
tests/spec/util_spec.lua
Normal file
@@ -0,0 +1,219 @@
|
||||
describe("utils/init.lua", function()
|
||||
it("Loads package", function()
|
||||
local utils_ok, _ = pcall(require, "gitlab.utils")
|
||||
assert._is_true(utils_ok)
|
||||
end)
|
||||
|
||||
local _, u = pcall(require, "gitlab.utils")
|
||||
describe("extract", function()
|
||||
it("Extracts a single value", function()
|
||||
local t = { { one = 1, two = 2 }, { three = 3, four = 4 } }
|
||||
local got = u.extract(t, "one")
|
||||
local want = { 1 }
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
it("Returns nothing with empty table", function()
|
||||
local t = {}
|
||||
local got = u.extract(t, "one")
|
||||
local want = {}
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("get_last_word", function()
|
||||
it("Returns the last word in a sentence", function()
|
||||
local sentence = "Hello world!"
|
||||
local got = u.get_last_word(sentence)
|
||||
local want = "world!"
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
it("Returns an empty string without text", function()
|
||||
local sentence = ""
|
||||
local got = u.get_last_word(sentence)
|
||||
local want = ""
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
it("Returns whole string w/out divider", function()
|
||||
local sentence = "Thisdoesnothavebreaks"
|
||||
local got = u.get_last_word(sentence)
|
||||
assert.are.same(sentence, got)
|
||||
end)
|
||||
it("Returns correct word w/ different divider", function()
|
||||
local sentence = "this|uses|a|different|divider"
|
||||
local got = u.get_last_word(sentence, "|")
|
||||
local want = "divider"
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("format_date", function()
|
||||
local current_date = {
|
||||
day = 19,
|
||||
hour = 22,
|
||||
isdst = false,
|
||||
min = 0,
|
||||
month = 11,
|
||||
sec = 44,
|
||||
wday = 1,
|
||||
yday = 323,
|
||||
year = 2023,
|
||||
}
|
||||
it("Returns days since a valid UTC timestamp", function()
|
||||
local stamp = "2023-11-16T19:52:36.946Z"
|
||||
local got = u.time_since(stamp, current_date)
|
||||
local want = "3 days ago"
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
|
||||
it("Returns hours since a valid UTC timestamp", function()
|
||||
local stamp = "2023-11-19T19:52:36.946Z"
|
||||
local got = u.time_since(stamp, current_date)
|
||||
local want = "2 hours ago"
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
it("Returns readable time if > 1 year", function()
|
||||
local stamp = "2011-11-19T19:52:36.946Z"
|
||||
local got = u.time_since(stamp, current_date)
|
||||
local want = "November 19, 2011"
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("remove_first_value", function()
|
||||
it("Removes the first value correctly", function()
|
||||
local got = u.remove_first_value({ 1, 2 })
|
||||
local want = { 2 }
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
it("Handles a one-length list", function()
|
||||
local got = u.remove_first_value({ 1 })
|
||||
local want = {}
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
it("Handles a zero-length list", function()
|
||||
local got = u.remove_first_value({})
|
||||
local want = {}
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("table_size", function()
|
||||
it("Works for associative tables", function()
|
||||
local got = u.remove_first_value({ 1, 2 })
|
||||
local want = { 2 }
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
it("Handles a one-length list", function()
|
||||
local got = u.remove_first_value({ 1 })
|
||||
local want = {}
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
it("Handles a zero-length list", function()
|
||||
local got = u.remove_first_value({})
|
||||
local want = {}
|
||||
assert.are.same(want, got)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("contains", function()
|
||||
it("Finds a value in a list", function()
|
||||
local got = u.contains({ 1, 2 }, 1)
|
||||
assert._is_true(got)
|
||||
end)
|
||||
it("Handles missing values", function()
|
||||
local got = u.contains({ 1, 3, 4 }, 2)
|
||||
assert._is_false(got)
|
||||
end)
|
||||
it("Handles empty lists", function()
|
||||
local got = u.contains({}, 1)
|
||||
assert._is_false(got)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("reverse", function()
|
||||
it("Reverses the values in a list", function()
|
||||
local got = u.reverse({ 1, 2, 3, 4 })
|
||||
local want = { 4, 3, 2, 1 }
|
||||
assert.are.same(got, want)
|
||||
end)
|
||||
it("Handles single value", function()
|
||||
local got = u.reverse({ 1 })
|
||||
local want = { 1 }
|
||||
assert.are.same(got, want)
|
||||
end)
|
||||
it("Handles empty list", function()
|
||||
local got = u.reverse({})
|
||||
local want = {}
|
||||
assert.are.same(got, want)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("spread", function()
|
||||
it("Spreads the values", function()
|
||||
local t1 = { 1, 2, 3 }
|
||||
local t2 = { 4, 5, 6 }
|
||||
local got = u.spread(t1, t2)
|
||||
local want = { 1, 2, 3, 4, 5, 6 }
|
||||
assert.are.same(got, want)
|
||||
end)
|
||||
it("Handles an empty t1 table", function()
|
||||
local t1 = {}
|
||||
local t2 = { 4, 5, 6 }
|
||||
local got = u.spread(t1, t2)
|
||||
local want = { 4, 5, 6 }
|
||||
assert.are.same(got, want)
|
||||
end)
|
||||
it("Handles an empty t2 table", function()
|
||||
local t1 = { 1, 2, 3 }
|
||||
local t2 = {}
|
||||
local got = u.spread(t1, t2)
|
||||
local want = { 1, 2, 3 }
|
||||
assert.are.same(got, want)
|
||||
end)
|
||||
it("Handles both empty tables", function()
|
||||
local t1 = {}
|
||||
local t2 = {}
|
||||
local got = u.spread(t1, t2)
|
||||
local want = {}
|
||||
assert.are.same(got, want)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("offset_to_seconds", function()
|
||||
local tests = {
|
||||
est = { "-0500", -18000 },
|
||||
pst = { "-0800", -28800 },
|
||||
gmt = { "+0000", 0 },
|
||||
cet = { "+0100", 360 },
|
||||
jst = { "+0900", 32400 },
|
||||
ist = { "+0530", 19800 },
|
||||
art = { "-0300", -10800 },
|
||||
aest = { "+1100", 39600 },
|
||||
mmt = { "+0630", 23400 },
|
||||
}
|
||||
|
||||
for _, val in ipairs(tests) do
|
||||
local got = u.offset_to_seconds(val[1])
|
||||
local want = val[2]
|
||||
assert.are.same(got, want)
|
||||
end
|
||||
end)
|
||||
|
||||
describe("format_to_local", function()
|
||||
local tests = {
|
||||
{ "2023-10-28T16:25:09.482Z", "-0500", "10/28/2023 at 11:25" },
|
||||
{ "2016-11-22T1:25:09.482Z", "-0500", "11/21/2016 at 20:25" },
|
||||
{ "2016-11-22T1:25:09.482Z", "-0000", "11/22/2016 at 01:25" },
|
||||
{ "2017-3-22T13:25:09.482Z", "+0700", "03/22/2017 at 20:25" },
|
||||
{ "2023-10-28T11:25:09.482-05:00", "-0500", "10/28/2023 at 11:25" },
|
||||
{ "2016-11-21T20:25:09.482-05:00", "-0500", "11/21/2016 at 20:25" },
|
||||
{ "2016-11-22T1:25:09.482-00:00", "-0000", "11/22/2016 at 01:25" },
|
||||
{ "2017-3-22T20:25:09.482+07:00", "+0700", "03/22/2017 at 20:25" },
|
||||
}
|
||||
for _, val in ipairs(tests) do
|
||||
local got = u.format_to_local(val[1], val[2])
|
||||
local want = val[3]
|
||||
assert.are.same(got, want)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
Reference in New Issue
Block a user