- 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
239 lines
6.4 KiB
Lua
239 lines
6.4 KiB
Lua
local test = dofile("test/test_harness.lua")
|
|
|
|
package.path = package.path .. ";lua/?.lua"
|
|
|
|
local db_parser = require("scl.db_parser")
|
|
|
|
local function test_db_parser_basic()
|
|
local content = [[
|
|
DATA_BLOCK "test_db"
|
|
TITLE = Test DB
|
|
VERSION : 0.1
|
|
//Test data block
|
|
VAR
|
|
member1 : Bool;
|
|
member2 : Int;
|
|
member3 : "other_udt";
|
|
END_VAR
|
|
|
|
END_DATA_BLOCK
|
|
]]
|
|
local db, err = db_parser.parse_db_content(content, "test.db")
|
|
if db then
|
|
db_parser.register_inline_db(db)
|
|
end
|
|
test.assert_not_nil(db, "parse_db_content should return db")
|
|
test.assert_equals(db.name, "test_db", "DB name should be extracted")
|
|
test.assert_equals(#db.members, 3, "should have 3 members")
|
|
test.assert_equals(db.members[1].name, "member1", "first member name")
|
|
test.assert_equals(db.members[3].is_udt, true, "third member is UDT type")
|
|
end
|
|
|
|
local function test_db_parser_attributes()
|
|
local content = [[
|
|
DATA_BLOCK "attr_db"
|
|
TITLE = Attr DB
|
|
VERSION : 0.1
|
|
VAR
|
|
attrMember{S7_SetPoint := 'True'}: Bool;
|
|
normalMember : Int;
|
|
END_VAR
|
|
|
|
END_DATA_BLOCK
|
|
]]
|
|
local db = db_parser.parse_db_content(content, "attr.db")
|
|
test.assert_not_nil(db, "parse_db_content should return db")
|
|
test.assert_equals(db.members[1].attributes.S7_SetPoint, "True", "attribute should be parsed")
|
|
end
|
|
|
|
local function test_db_parser_comments()
|
|
local content = [[
|
|
DATA_BLOCK "comment_db"
|
|
TITLE = Comment DB
|
|
VERSION : 0.1
|
|
//This is a DB comment
|
|
VAR
|
|
member1 : Bool; //first member
|
|
member2 : Int; //second member
|
|
END_VAR
|
|
|
|
END_DATA_BLOCK
|
|
]]
|
|
local db = db_parser.parse_db_content(content, "comment.db")
|
|
test.assert_not_nil(db, "parse_db_content should return db")
|
|
test.assert_equals(db.comment, "This is a DB comment", "DB comment should be extracted")
|
|
test.assert_equals(db.members[1].comment, "first member", "member comment should be extracted")
|
|
end
|
|
|
|
local function test_db_parser_array()
|
|
local content = [[
|
|
DATA_BLOCK "array_db"
|
|
TITLE = Array DB
|
|
VERSION : 0.1
|
|
VAR
|
|
arr : Array[0..9] of Int;
|
|
arr2 : Array[0..5, 0..3] of Bool;
|
|
END_VAR
|
|
|
|
END_DATA_BLOCK
|
|
]]
|
|
local db = db_parser.parse_db_content(content, "array.db")
|
|
test.assert_not_nil(db, "parse_db_content should return db")
|
|
test.assert(db.members[1].type:match("Array"), "array type should be preserved")
|
|
end
|
|
|
|
local function test_db_cache_operations()
|
|
db_parser.clear_cache()
|
|
test.assert_equals(db_parser.get_cache_count(), 0, "cache should be empty after clear")
|
|
|
|
local content = [[
|
|
DATA_BLOCK "cached_db"
|
|
TITLE = Cached DB
|
|
VERSION : 0.1
|
|
VAR
|
|
m1 : Bool;
|
|
END_VAR
|
|
|
|
END_DATA_BLOCK
|
|
]]
|
|
local db = db_parser.parse_db_content(content, "cached.db")
|
|
if db then
|
|
db_parser.register_inline_db(db)
|
|
end
|
|
local cached = db_parser.get_db("cached_db")
|
|
test.assert_not_nil(cached, "DB should be cached")
|
|
test.assert_equals(db_parser.get_cache_count(), 1, "cache should have 1 entry")
|
|
|
|
local names = db_parser.get_all_db_names()
|
|
test.assert_equals(#names, 1, "should have 1 DB name")
|
|
test.assert_equals(names[1], "cached_db", "DB name should match")
|
|
end
|
|
|
|
local function test_db_is_type()
|
|
db_parser.clear_cache()
|
|
|
|
local content = [[
|
|
DATA_BLOCK "known_db"
|
|
TITLE = Known
|
|
VERSION : 0.1
|
|
VAR
|
|
m1 : Bool;
|
|
END_VAR
|
|
|
|
END_DATA_BLOCK
|
|
]]
|
|
local db = db_parser.parse_db_content(content, "known.db")
|
|
if db then
|
|
db_parser.register_inline_db(db)
|
|
end
|
|
|
|
test.assert(db_parser.is_db_type("known_db"), "known_db should be recognized")
|
|
test.assert(db_parser.is_db_type('"known_db"'), "quoted known_db should be recognized")
|
|
test.assert(not db_parser.is_db_type("unknown_db"), "unknown_db should not be recognized")
|
|
end
|
|
|
|
local function test_db_members()
|
|
db_parser.clear_cache()
|
|
|
|
local content = [[
|
|
DATA_BLOCK "test_db"
|
|
TITLE = Test
|
|
VERSION : 0.1
|
|
VAR
|
|
inner : "other_db";
|
|
simple : Bool;
|
|
END_VAR
|
|
|
|
END_DATA_BLOCK
|
|
]]
|
|
local db = db_parser.parse_db_content(content, "test.db")
|
|
if db then
|
|
db_parser.register_inline_db(db)
|
|
end
|
|
|
|
local members = db_parser.get_db_members("test_db")
|
|
test.assert_not_nil(members, "members should not be nil")
|
|
if members and #members > 0 then
|
|
test.assert_equals(members[1].name, "inner", "first member name")
|
|
test.assert_equals(members[1].is_udt, true, "first member is UDT type")
|
|
end
|
|
end
|
|
|
|
local function test_db_reference_files()
|
|
db_parser.clear_cache()
|
|
|
|
local ref_path = test.REF_PROJECT .. "/Program blocks/01_Machine/GlobalMachineData.db"
|
|
local file = io.open(ref_path, "r")
|
|
if not file then
|
|
print("Warning: Reference DB file not found: " .. ref_path)
|
|
return
|
|
end
|
|
local content = file:read("*all")
|
|
file:close()
|
|
|
|
local db = db_parser.parse_db_content(content, ref_path)
|
|
if db then
|
|
db_parser.register_inline_db(db)
|
|
end
|
|
test.assert_not_nil(db, "should parse reference DB file")
|
|
test.assert_equals(db.name, "GlobalMachineData", "DB name should match")
|
|
test.assert_gt(#db.members, 0, "should have members")
|
|
|
|
local cached = db_parser.get_db("GlobalMachineData")
|
|
test.assert_not_nil(cached, "DB should be cached")
|
|
end
|
|
|
|
local function test_db_multiple_reference_files()
|
|
db_parser.clear_cache()
|
|
|
|
local files = {
|
|
test.REF_PROJECT .. "/Program blocks/01_Machine/GlobalMachineData.db",
|
|
test.REF_PROJECT .. "/Program blocks/01_Machine/Equipments.db",
|
|
test.REF_PROJECT .. "/Program blocks/10_Parameter/Parameter.db",
|
|
}
|
|
|
|
local parsed_count = 0
|
|
for _, filepath in ipairs(files) do
|
|
local file = io.open(filepath, "r")
|
|
if file then
|
|
local content = file:read("*all")
|
|
file:close()
|
|
local db = db_parser.parse_db_content(content, filepath)
|
|
if db then
|
|
db_parser.register_inline_db(db)
|
|
parsed_count = parsed_count + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
test.assert_gt(parsed_count, 0, "should parse at least one reference DB")
|
|
test.assert_equals(db_parser.get_cache_count(), parsed_count, "cache should have correct count")
|
|
end
|
|
|
|
local function run_db_tests()
|
|
test.run_suite("DB Parser Tests", function()
|
|
print("\n--- Basic Tests ---")
|
|
test_db_parser_basic()
|
|
test_db_parser_attributes()
|
|
test_db_parser_comments()
|
|
test_db_parser_array()
|
|
|
|
print("\n--- Cache Tests ---")
|
|
test_db_cache_operations()
|
|
test_db_is_type()
|
|
test_db_members()
|
|
|
|
print("\n--- Reference Project Tests ---")
|
|
test_db_reference_files()
|
|
test_db_multiple_reference_files()
|
|
end)
|
|
end
|
|
|
|
if vim then
|
|
vim.api.nvim_create_user_command("TestDb", function()
|
|
run_db_tests()
|
|
end, {})
|
|
end
|
|
|
|
run_db_tests()
|