refactor: Refactor everything
BREAKING CHANGE: Actually move to the next pair of quotes
This commit is contained in:
parent
9622219679
commit
6d065862b0
6 changed files with 1044 additions and 27 deletions
217
tests/test_runner.lua
Normal file
217
tests/test_runner.lua
Normal file
|
@ -0,0 +1,217 @@
|
|||
#!/usr/bin/env lua
|
||||
|
||||
--- Simple Test Runner for JQuote Plugin
|
||||
--- @author Jan
|
||||
--- @license MIT
|
||||
|
||||
local test_runner = {}
|
||||
|
||||
-- Test result tracking
|
||||
local stats = {
|
||||
total = 0,
|
||||
passed = 0,
|
||||
failed = 0,
|
||||
errors = {},
|
||||
start_time = os.clock()
|
||||
}
|
||||
|
||||
-- ANSI color codes for terminal output
|
||||
local colors = {
|
||||
reset = "\27[0m",
|
||||
red = "\27[31m",
|
||||
green = "\27[32m",
|
||||
yellow = "\27[33m",
|
||||
blue = "\27[34m",
|
||||
magenta = "\27[35m",
|
||||
cyan = "\27[36m",
|
||||
white = "\27[37m",
|
||||
bold = "\27[1m"
|
||||
}
|
||||
|
||||
-- Simple assertion library
|
||||
local assert = {
|
||||
is_true = function(value, message)
|
||||
if value ~= true then
|
||||
error(message or string.format("Expected true, got %s", tostring(value)))
|
||||
end
|
||||
end,
|
||||
|
||||
is_false = function(value, message)
|
||||
if value ~= false then
|
||||
error(message or string.format("Expected false, got %s", tostring(value)))
|
||||
end
|
||||
end,
|
||||
|
||||
are = {
|
||||
equal = function(expected, actual, message)
|
||||
if expected ~= actual then
|
||||
error(message or string.format("Expected %s, got %s", tostring(expected), tostring(actual)))
|
||||
end
|
||||
end,
|
||||
same = function(expected, actual, message)
|
||||
if not test_runner.deep_equal(expected, actual) then
|
||||
error(message or string.format("Tables are not the same.\nExpected: %s\nActual: %s",
|
||||
test_runner.table_tostring(expected), test_runner.table_tostring(actual)))
|
||||
end
|
||||
end
|
||||
},
|
||||
|
||||
is_not_nil = function(value, message)
|
||||
if value == nil then
|
||||
error(message or "Expected non-nil value")
|
||||
end
|
||||
end,
|
||||
|
||||
is_string = function(value, message)
|
||||
if type(value) ~= "string" then
|
||||
error(message or string.format("Expected string, got %s", type(value)))
|
||||
end
|
||||
end,
|
||||
|
||||
is_table = function(value, message)
|
||||
if type(value) ~= "table" then
|
||||
error(message or string.format("Expected table, got %s", type(value)))
|
||||
end
|
||||
end,
|
||||
|
||||
matches = function(pattern, str, message)
|
||||
if not string.match(str, pattern) then
|
||||
error(message or string.format("String '%s' does not match pattern '%s'", str, pattern))
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
-- Make assert global for tests
|
||||
_G.assert = assert
|
||||
|
||||
-- Test context management
|
||||
local current_context = ""
|
||||
local current_test = ""
|
||||
|
||||
-- Utility functions
|
||||
function test_runner.deep_equal(a, b)
|
||||
if type(a) ~= type(b) then return false end
|
||||
if type(a) ~= "table" then return a == b end
|
||||
|
||||
for k, v in pairs(a) do
|
||||
if not test_runner.deep_equal(v, b[k]) then return false end
|
||||
end
|
||||
for k, v in pairs(b) do
|
||||
if not test_runner.deep_equal(v, a[k]) then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function test_runner.table_tostring(t, indent)
|
||||
if type(t) ~= "table" then return tostring(t) end
|
||||
indent = indent or 0
|
||||
local spaces = string.rep(" ", indent)
|
||||
local result = "{\n"
|
||||
for k, v in pairs(t) do
|
||||
result = result .. spaces .. " " .. tostring(k) .. " = "
|
||||
if type(v) == "table" then
|
||||
result = result .. test_runner.table_tostring(v, indent + 1)
|
||||
else
|
||||
result = result .. tostring(v)
|
||||
end
|
||||
result = result .. ",\n"
|
||||
end
|
||||
result = result .. spaces .. "}"
|
||||
return result
|
||||
end
|
||||
|
||||
-- Test framework functions
|
||||
function describe(description, func)
|
||||
current_context = description
|
||||
print(colors.blue .. colors.bold .. "\n" .. description .. colors.reset)
|
||||
func()
|
||||
current_context = ""
|
||||
end
|
||||
|
||||
function it(description, func)
|
||||
current_test = description
|
||||
stats.total = stats.total + 1
|
||||
|
||||
local success, error_msg = pcall(func)
|
||||
|
||||
if success then
|
||||
stats.passed = stats.passed + 1
|
||||
print(colors.green .. " ✓ " .. description .. colors.reset)
|
||||
else
|
||||
stats.failed = stats.failed + 1
|
||||
local full_description = current_context .. " - " .. description
|
||||
table.insert(stats.errors, {
|
||||
test = full_description,
|
||||
error = error_msg
|
||||
})
|
||||
print(colors.red .. " ✗ " .. description .. colors.reset)
|
||||
print(colors.red .. " " .. error_msg .. colors.reset)
|
||||
end
|
||||
|
||||
current_test = ""
|
||||
end
|
||||
|
||||
function before_each(func)
|
||||
-- Simple implementation - just call the function before each test
|
||||
-- In a more sophisticated runner, this would be stored and called appropriately
|
||||
_G._before_each = func
|
||||
end
|
||||
|
||||
-- Override 'it' to call before_each if it exists
|
||||
local original_it = it
|
||||
function it(description, func)
|
||||
if _G._before_each then
|
||||
_G._before_each()
|
||||
end
|
||||
original_it(description, func)
|
||||
end
|
||||
|
||||
-- Test execution
|
||||
function test_runner.run_tests()
|
||||
print(colors.cyan .. colors.bold .. "JQuote Plugin Test Suite" .. colors.reset)
|
||||
print(colors.cyan .. "========================" .. colors.reset)
|
||||
|
||||
-- Load and run tests
|
||||
local success, error_msg = pcall(dofile, "tests/init_spec.lua")
|
||||
|
||||
if not success then
|
||||
print(colors.red .. colors.bold .. "Failed to load test file:" .. colors.reset)
|
||||
print(colors.red .. error_msg .. colors.reset)
|
||||
return false
|
||||
end
|
||||
|
||||
-- Print summary
|
||||
local duration = os.clock() - stats.start_time
|
||||
print(colors.cyan .. "\n========================" .. colors.reset)
|
||||
print(colors.white .. colors.bold .. "Test Summary:" .. colors.reset)
|
||||
print(string.format(" Total tests: %d", stats.total))
|
||||
print(colors.green .. string.format(" Passed: %d", stats.passed) .. colors.reset)
|
||||
|
||||
if stats.failed > 0 then
|
||||
print(colors.red .. string.format(" Failed: %d", stats.failed) .. colors.reset)
|
||||
print(colors.red .. "\nFailure Details:" .. colors.reset)
|
||||
for _, error_info in ipairs(stats.errors) do
|
||||
print(colors.red .. " • " .. error_info.test .. colors.reset)
|
||||
print(colors.red .. " " .. error_info.error .. colors.reset)
|
||||
end
|
||||
end
|
||||
|
||||
print(string.format(" Duration: %.3fs", duration))
|
||||
|
||||
local success_rate = stats.total > 0 and (stats.passed / stats.total * 100) or 0
|
||||
if success_rate == 100 then
|
||||
print(colors.green .. colors.bold .. "\n🎉 All tests passed!" .. colors.reset)
|
||||
else
|
||||
print(colors.red .. colors.bold .. string.format("\n❌ %.1f%% tests passed", success_rate) .. colors.reset)
|
||||
end
|
||||
|
||||
return stats.failed == 0
|
||||
end
|
||||
|
||||
-- Command line interface
|
||||
if arg and arg[0] and arg[0]:match("test_runner%.lua$") then
|
||||
local success = test_runner.run_tests()
|
||||
os.exit(success and 0 or 1)
|
||||
end
|
||||
|
||||
return test_runner
|
Loading…
Add table
Add a link
Reference in a new issue