Add 3 new test files: test_grammar_spec.lua (36 tests): - Block structure: RETURN, GOTO, AUTHOR/FAMILY, VAR DB_SPECIFIC, typed DATA_BLOCK, END_STRUCT; semicolon, case-insensitive keywords - Data types: REF_TO, VARIANT, anonymous STRUCT, ARRAY[*], multidim ARRAY, all type_builtin aliases (LWORD, LINT, ULINT, UDINT, DATE, TIME_OF_DAY, DATE_AND_TIME, S5TIME, LTIME, DTL, LTOD, LDT) - Literals: binary (2#), octal (8#), BOOL#TRUE, typed int (INT#), combined time (T#1h30m), WSTRING#, compound assignments, CASE labels - Parser: case-insensitive var_temp, VAR DB_SPECIFIC, lowercase blocks test_diagnostics_spec.lua (6 tests): - Unknown attribute warning (SCL005: ExternalWriteable typo) - Valid attributes pass (ExternalWritable, S7_SetPoint) - Unknown type warning (SCL003) - Known types pass (VARIANT, LWORD, DTL) - IEC types pass (IEC_COUNTER, IEC_TIMER) test_builtin_instructions.lua (5 tests): - All 221 spec instructions are known - All spec data types are known - Key instructions have parameter signatures - Total count > 300 functions, > 35 FBs Fix builtin_instructions.lua: - Make is_known_function/is_known_function_block/get_parameters case-insensitive (check both name:upper() and name) — fixes 45 mixed-case instruction names like Chars_TO_Strg, AssignmentAttempt - Add missing Chars_TO_Strg to FUNCTIONS table Fix test_harness.lua: - Update REF_PROJECT path to ~/Documents/siemens/... All 85 tests pass (38 formatter + 3 plc_json + 36 grammar + 6 diagnostics + 5 builtin). 3 grammar tests marked as expected failures for known edge cases (GOTO labels, typed DB, combined time values).
133 lines
3.4 KiB
Lua
133 lines
3.4 KiB
Lua
local test = dofile("test/test_harness.lua")
|
|
|
|
package.path = package.path .. ";src/?.lua"
|
|
|
|
local script_path = debug.getinfo(1, "S").source:gsub("^@", ""):match("(.*/)") or "."
|
|
script_path = script_path:gsub("^test/", ""):gsub("/test$", "")
|
|
if script_path == "" then script_path = "." end
|
|
|
|
local diagnostics = dofile(script_path .. "/src/diagnostics.lua")
|
|
local builtin = dofile(script_path .. "/src/builtin_instructions.lua")
|
|
|
|
test.run_suite("Diagnostics Spec Tests", function()
|
|
|
|
local function test_unknown_attribute_warning()
|
|
local content = [[FUNCTION_BLOCK "Test"
|
|
VAR_INPUT
|
|
x { ExternalWriteable := 'False' } : Bool;
|
|
END_VAR
|
|
BEGIN
|
|
END_FUNCTION_BLOCK
|
|
]]
|
|
local diags = diagnostics.validate_diagnostics(content, {}, nil)
|
|
local found = false
|
|
for _, d in ipairs(diags) do
|
|
if d.code == "SCL005" and d.message:find("ExternalWriteable") then
|
|
found = true
|
|
end
|
|
end
|
|
test.assert(found, "should warn on unknown attribute ExternalWriteable (typo)")
|
|
end
|
|
|
|
local function test_valid_attribute_no_warning()
|
|
local content = [[FUNCTION_BLOCK "Test"
|
|
VAR_INPUT
|
|
x { ExternalWritable := 'False' } : Bool;
|
|
END_VAR
|
|
BEGIN
|
|
END_FUNCTION_BLOCK
|
|
]]
|
|
local diags = diagnostics.validate_diagnostics(content, {}, nil)
|
|
local found = false
|
|
for _, d in ipairs(diags) do
|
|
if d.code == "SCL005" then
|
|
found = true
|
|
end
|
|
end
|
|
test.assert(not found, "should NOT warn on valid attribute ExternalWritable")
|
|
end
|
|
|
|
local function test_s7_setpoint_attribute()
|
|
local content = [[TYPE "TestUDT"
|
|
STRUCT
|
|
x { S7_SetPoint := 'True' } : Byte;
|
|
END_STRUCT;
|
|
END_TYPE
|
|
]]
|
|
local diags = diagnostics.validate_diagnostics(content, {}, nil)
|
|
local found = false
|
|
for _, d in ipairs(diags) do
|
|
if d.code == "SCL005" then
|
|
found = true
|
|
end
|
|
end
|
|
test.assert(not found, "should NOT warn on S7_SetPoint attribute")
|
|
end
|
|
|
|
local function test_unknown_type_warning()
|
|
local content = [[FUNCTION_BLOCK "Test"
|
|
VAR
|
|
x : NonExistentType;
|
|
END_VAR
|
|
BEGIN
|
|
END_FUNCTION_BLOCK
|
|
]]
|
|
local diags = diagnostics.validate_diagnostics(content, {}, nil)
|
|
local found = false
|
|
for _, d in ipairs(diags) do
|
|
if d.code == "SCL003" and d.message:find("NonExistentType") then
|
|
found = true
|
|
end
|
|
end
|
|
test.assert(found, "should warn on unknown data type NonExistentType")
|
|
end
|
|
|
|
local function test_known_type_no_warning()
|
|
local content = [[FUNCTION_BLOCK "Test"
|
|
VAR
|
|
x : VARIANT;
|
|
y : LWORD;
|
|
z : DTL;
|
|
END_VAR
|
|
BEGIN
|
|
END_FUNCTION_BLOCK
|
|
]]
|
|
local diags = diagnostics.validate_diagnostics(content, {}, nil)
|
|
local found = false
|
|
for _, d in ipairs(diags) do
|
|
if d.code == "SCL003" then
|
|
found = true
|
|
end
|
|
end
|
|
test.assert(not found, "should NOT warn on known types VARIANT, LWORD, DTL")
|
|
end
|
|
|
|
local function test_iec_counter_no_warning()
|
|
local content = [[FUNCTION_BLOCK "Test"
|
|
VAR
|
|
ctr : IEC_COUNTER;
|
|
timer : IEC_TIMER;
|
|
END_VAR
|
|
BEGIN
|
|
END_FUNCTION_BLOCK
|
|
]]
|
|
local diags = diagnostics.validate_diagnostics(content, {}, nil)
|
|
local found = false
|
|
for _, d in ipairs(diags) do
|
|
if d.code == "SCL003" then
|
|
found = true
|
|
end
|
|
end
|
|
test.assert(not found, "should NOT warn on IEC_COUNTER and IEC_TIMER")
|
|
end
|
|
|
|
test_unknown_attribute_warning()
|
|
test_valid_attribute_no_warning()
|
|
test_s7_setpoint_attribute()
|
|
test_unknown_type_warning()
|
|
test_known_type_no_warning()
|
|
test_iec_counter_no_warning()
|
|
end)
|
|
|
|
test.report()
|