Skip to content

Commit 7566388

Browse files
committed
test: add an automatic test runner
This commit removes the `spec` folder and adds an `auto_test_runner.lua` file. The `.busted` file is configured to only scan for this file and run it. The auto test runner scans all the lua files, requires them and looks for an exposed `__test` function. If it finds one, it calls it with the global function environment (if we didn't override the fenv the `__test` functions wouldn't have access to busted and luassert functions). For modules which error upon `require` a special dummy test is made which prints the error message, thus failing the entire suite. This solution not only makes testing extremely flexible, it also allows for easy testing of private implementation.
1 parent 0e90b8b commit 7566388

File tree

10 files changed

+200
-160
lines changed

10 files changed

+200
-160
lines changed

.busted

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
return {
22
_all = {
33
coverage = false,
4-
lpath = "lua/?.lua;lua/?/init.lua",
5-
lua = "nlua",
4+
lpath = 'lua/?.lua;lua/?/init.lua',
5+
pattern = '^auto_test_runner.lua$',
6+
lua = 'nlua',
7+
ROOT = { 'lua/' }
68
},
79
default = {
810
verbose = true

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,5 @@
2828
!*.rockspec
2929

3030
# Plugin test & lint
31-
!spec/
3231
!.busted
3332
!.luacheckrc

.luacheckrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
std = "luajit"
22
cache = true
3-
include_files = {"spec/**.lua", "lua/**.lua", "*.rockspec", ".luacheckrc"}
3+
include_files = {"lua/**.lua", "*.rockspec", ".luacheckrc"}
44

55
read_globals = {
66
"vim",

lua/cpp-tools/auto_test_runner.lua

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
--- This is a special file which gets called by busted.
2+
--- This file scans all the requirable `lua/` files from here
3+
--- and runs their __test functions with busted test context.
4+
5+
local current_filename = debug.getinfo(1).source:match('([%w_%.]+)$')
6+
7+
local function project_lua_files(path, type)
8+
return type == 'file' and vim.endswith(path, 'lua') and not vim.endswith(path, current_filename)
9+
end
10+
11+
local function path_to_requirable(path)
12+
return path:match('lua/(.*)'):gsub('/init%.lua', ''):gsub('%.lua', ''):gsub('/', '.')
13+
end
14+
15+
local function run_module_test(name)
16+
local ok, module = pcall(require, name)
17+
if not ok then
18+
describe(name, function()
19+
it('Has an error!', function()
20+
assert.message(('Requiring this module failed with the following error:\n%s'):format(module)).truthy(false)
21+
end)
22+
end)
23+
return
24+
end
25+
26+
-- This module is something else, we don't fw it
27+
if type(module) ~= 'table' then
28+
return
29+
end
30+
31+
local test_func = vim.tbl_get(module, '__test')
32+
if test_func then
33+
setfenv(test_func, getfenv())()
34+
end
35+
end
36+
37+
local function is_lua_dir(dir)
38+
return vim.startswith(dir, 'lua')
39+
end
40+
41+
vim
42+
.iter(vim.fs.dir('.', { depth = 10, skip = is_lua_dir }))
43+
:filter(project_lua_files)
44+
:map(path_to_requirable)
45+
:each(run_module_test)

lua/cpp-tools/health.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ local function ensure_dependencies()
3838
:each(function(not_found_dep) end)
3939
end
4040

41-
local M
41+
local M = {}
4242

4343
function M.check()
4444
validate_config()

lua/cpp-tools/lib/iter.lua

Lines changed: 0 additions & 49 deletions
This file was deleted.

lua/cpp-tools/lib/iter/init.lua

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
local M = {}
2+
3+
---Counts the lines in a string
4+
---@param str string the string to count lines for
5+
---@return number line count # The number of lines
6+
function M.line_count(str)
7+
local count = 1
8+
local length = #str
9+
for i = 1, length - 1 do
10+
local c = str:sub(i, i)
11+
if c == '\n' then
12+
if i ~= (length - 2) then
13+
count = count + 1
14+
end
15+
end
16+
end
17+
18+
return count
19+
end
20+
21+
---Splits the string into lines and immediately returns the amount as well
22+
---@param str string the string to split
23+
---@return string[] lines # An array of lines
24+
---@return number # The amount of lines in the array
25+
function M.lines(str)
26+
local lines = vim.split(str, '\n')
27+
return lines, #lines
28+
end
29+
30+
---Checks if two array tables have equal values
31+
---@generic T
32+
---@param arr1 `T`[] first array
33+
---@param arr2 T[] second array
34+
---@return boolean # are the arrays equal
35+
function M.arrays_equal(arr1, arr2)
36+
if arr1 == arr2 then
37+
return true
38+
elseif #arr1 ~= #arr2 then
39+
return false
40+
end
41+
42+
for i = 1, #arr1 do
43+
if arr1[i] ~= arr2[i] then
44+
return false
45+
end
46+
end
47+
48+
return true
49+
end
50+
51+
function M.__test()
52+
describe('array_equals', function()
53+
local iter = require('lua.cpp-tools.lib.iter.init')
54+
55+
it('Two same references to empty are equal', function()
56+
local empty = {}
57+
local a = empty
58+
local b = empty
59+
60+
assert.is.truthy(iter.arrays_equal(a, b))
61+
end)
62+
63+
it('Two different references to empty are equal', function()
64+
local a = {}
65+
local b = {}
66+
67+
assert.is.truthy(iter.arrays_equal(a, b))
68+
end)
69+
70+
it('Two same values are equal', function()
71+
local a = { 1, 2 }
72+
local b = { 1, 2 }
73+
74+
assert.is.truthy(iter.arrays_equal(a, b))
75+
end)
76+
77+
it('Two same values with different order are not equal', function()
78+
local a = { 1, 2 }
79+
local b = { 2, 1 }
80+
81+
assert.is.falsy(iter.arrays_equal(a, b))
82+
end)
83+
84+
it('Two same values with different values', function()
85+
local a = { '' }
86+
local b = { 1 }
87+
88+
assert.is.falsy(iter.arrays_equal(a, b))
89+
end)
90+
end)
91+
92+
describe('line_count', function()
93+
local iter = require('lua.cpp-tools.lib.iter.init')
94+
95+
it('Returns 1 for an empty string', function()
96+
assert.are.equal(iter.line_count(''), 1)
97+
end)
98+
99+
it('Returns 1 for a non empty string with one line', function()
100+
assert.are.equal(iter.line_count('Hello there'), 1)
101+
end)
102+
103+
it('Returns 1 for a string with a trailing newlien', function()
104+
assert.are.equal(iter.line_count('Foo\n'), 1)
105+
end)
106+
107+
it('Returns 2 for a string with a trailing newline and content after it', function()
108+
assert.are.equal(iter.line_count('Foo\nBar'), 2)
109+
end)
110+
111+
it('Returns X for a string with X lines (ignoring last newline)', function()
112+
local three_lined_string = [[
113+
first line
114+
second line
115+
third line]]
116+
117+
assert.are.equal(iter.line_count(three_lined_string), 3)
118+
end)
119+
end)
120+
121+
describe('lines', function()
122+
local iter = require('lua.cpp-tools.lib.iter.init')
123+
124+
it('Returns one empty line untouched', function()
125+
local empty_line = ''
126+
local lines = iter.lines(empty_line)
127+
128+
assert.are.equal(#lines, 1)
129+
assert.are.equal(lines[1], empty_line)
130+
end)
131+
132+
it('Returns one non empty line untouched', function()
133+
local empty_line = 'asdasdasdasdasd'
134+
local lines = iter.lines(empty_line)
135+
136+
assert.are.equal(#lines, 1)
137+
assert.are.equal(lines[1], empty_line)
138+
end)
139+
140+
it('Returns X lines for a string with X lines', function()
141+
local lines_arr = { 'line1', 'line2', 'line3' }
142+
local lines_str = vim.fn.join(lines_arr, '\n')
143+
144+
assert.is.truthy(iter.arrays_equal(iter.lines(lines_str), lines_arr))
145+
end)
146+
end)
147+
end
148+
149+
return M

nix/checks.nix

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
inherit root;
3939
fileset = fs.unions [
4040
(root + /ftplugin)
41-
(root + /spec)
4241
(root + /lua)
4342
(root + /.busted)
4443
(fs.fileFilter (f: f.hasExt "rockspec") root)

spec/dummy_spec.lua

Lines changed: 0 additions & 10 deletions
This file was deleted.

spec/iter_spec.lua

Lines changed: 0 additions & 95 deletions
This file was deleted.

0 commit comments

Comments
 (0)