- Add test/ directory with test harness and test files - Add UDT, DB, FB parser tests - Add PLC JSON and integration tests - Test against reference project (239 UDTs, 12 DBs, 37 SCL, 13 XML) - Fix attribute parsing to handle underscores (S7_SetPoint) - Add ORGANIZATION_BLOCK support to FB parser
169 lines
4.1 KiB
Lua
169 lines
4.1 KiB
Lua
local M = {}
|
|
|
|
M.test_count = 0
|
|
M.pass_count = 0
|
|
M.fail_count = 0
|
|
M.failures = {}
|
|
|
|
M.REF_PROJECT = os.getenv("SCL_REF_PROJECT") or "/home/lazar/dev/siemens/projects/scl_lang_support_lazyvim_ref_project"
|
|
|
|
local function inspect(val)
|
|
local _G = {}
|
|
setmetatable(_G, {__index = function(_, k)
|
|
return function(v)
|
|
if type(v) == "string" then return string.format("%q", v) end
|
|
return tostring(v)
|
|
end
|
|
end})
|
|
local env = {inspect = _G}
|
|
if type(val) == "table" then
|
|
local lines = {"{"}
|
|
for k, v in pairs(val) do
|
|
table.insert(lines, string.format(" [%s] = %s,", inspect(k), inspect(v)))
|
|
end
|
|
table.insert(lines, "}")
|
|
return table.concat(lines, "\n")
|
|
elseif type(val) == "string" then
|
|
return string.format("%q", val)
|
|
else
|
|
return tostring(val)
|
|
end
|
|
end
|
|
|
|
function M.assert(condition, message)
|
|
M.test_count = M.test_count + 1
|
|
if condition then
|
|
M.pass_count = M.pass_count + 1
|
|
return true
|
|
else
|
|
M.fail_count = M.fail_count + 1
|
|
table.insert(M.failures, {
|
|
test = message or "unnamed test",
|
|
msg = "assertion failed"
|
|
})
|
|
return false
|
|
end
|
|
end
|
|
|
|
function M.assert_equals(actual, expected, message)
|
|
M.test_count = M.test_count + 1
|
|
local actual_str = inspect(actual)
|
|
local expected_str = inspect(expected)
|
|
if actual == expected then
|
|
M.pass_count = M.pass_count + 1
|
|
return true
|
|
else
|
|
M.fail_count = M.fail_count + 1
|
|
table.insert(M.failures, {
|
|
test = message or "assert_equals",
|
|
msg = string.format("expected: %s, got: %s", expected_str, actual_str)
|
|
})
|
|
return false
|
|
end
|
|
end
|
|
|
|
function M.assert_not_nil(value, message)
|
|
M.test_count = M.test_count + 1
|
|
if value ~= nil then
|
|
M.pass_count = M.pass_count + 1
|
|
return true
|
|
else
|
|
M.fail_count = M.fail_count + 1
|
|
table.insert(M.failures, {
|
|
test = message or "assert_not_nil",
|
|
msg = "value is nil"
|
|
})
|
|
return false
|
|
end
|
|
end
|
|
|
|
function M.assert_nil(value, message)
|
|
M.test_count = M.test_count + 1
|
|
if value == nil then
|
|
M.pass_count = M.pass_count + 1
|
|
return true
|
|
else
|
|
M.fail_count = M.fail_count + 1
|
|
table.insert(M.failures, {
|
|
test = message or "assert_nil",
|
|
msg = string.format("expected nil, got: %s", inspect(value))
|
|
})
|
|
return false
|
|
end
|
|
end
|
|
|
|
function M.assert_gt(actual, expected, message)
|
|
M.test_count = M.test_count + 1
|
|
if actual > expected then
|
|
M.pass_count = M.pass_count + 1
|
|
return true
|
|
else
|
|
M.fail_count = M.fail_count + 1
|
|
table.insert(M.failures, {
|
|
test = message or "assert_gt",
|
|
msg = string.format("expected %s > %s", tostring(actual), tostring(expected))
|
|
})
|
|
return false
|
|
end
|
|
end
|
|
|
|
function M.assert_items_equal(actual, expected, message)
|
|
M.test_count = M.test_count + 1
|
|
if not actual or not expected then
|
|
M.fail_count = M.fail_count + 1
|
|
table.insert(M.failures, {
|
|
test = message or "assert_items_equal",
|
|
msg = "nil table passed"
|
|
})
|
|
return false
|
|
end
|
|
if #actual ~= #expected then
|
|
M.fail_count = M.fail_count + 1
|
|
table.insert(M.failures, {
|
|
test = message or "assert_items_equal",
|
|
msg = string.format("length mismatch: expected %d, got %d", #expected, #actual)
|
|
})
|
|
return false
|
|
end
|
|
for i, v in ipairs(actual) do
|
|
if v ~= expected[i] then
|
|
M.fail_count = M.fail_count + 1
|
|
table.insert(M.failures, {
|
|
test = message or "assert_items_equal",
|
|
msg = string.format("index %d: expected %s, got %s", i, inspect(expected[i]), inspect(v))
|
|
})
|
|
return false
|
|
end
|
|
end
|
|
M.pass_count = M.pass_count + 1
|
|
return true
|
|
end
|
|
|
|
function M.reset()
|
|
M.test_count = 0
|
|
M.pass_count = 0
|
|
M.fail_count = 0
|
|
M.failures = {}
|
|
end
|
|
|
|
function M.report()
|
|
print(string.format("\n=== Test Results ==="))
|
|
print(string.format("Total: %d | Passed: %d | Failed: %d", M.test_count, M.pass_count, M.fail_count))
|
|
if M.fail_count > 0 then
|
|
print("\nFailures:")
|
|
for _, f in ipairs(M.failures) do
|
|
print(string.format(" - %s: %s", f.test, f.msg))
|
|
end
|
|
end
|
|
return M.fail_count == 0
|
|
end
|
|
|
|
function M.run_suite(name, fn)
|
|
print(string.format("\n=== Running %s ===", name))
|
|
M.reset()
|
|
fn()
|
|
M.report()
|
|
end
|
|
|
|
return M
|