Test Coverage

ForgeIEC is backed by a comprehensive automated test suite. Every commit is verified against 117 unit tests before merging, covering the complete IEC 61131-3 Structured Text language feature set, all standard function blocks, and the multi-task threading system.

Test Suites at a Glance

SuiteTestsVerifies
FStCompilerTest101Complete ST language feature set
FStLibraryTest8All 132 standard blocks (FBs + FCs)
FCodeGeneratorThreadingTest8Multi-task scheduling + lock-free sync
Total1170 failures

1. ST Language Feature Set (FStCompilerTest)

101 tests verify every supported IEC 61131-3 Structured Text language construct. Each test compiles an ST fragment through the FStCompiler and verifies the generated C++ code.

1.1 Assignments

TestST CodeVerifies
assignSimplea := 42;Simple assignment
assignExpressiona := b + 1;Expression assignment
assignExternalExtVar := 10;VAR_EXTERNAL access
assignGvlQualifiedGVL.ExtVar := 5;Qualified GVL path

1.2 Arithmetic Operators

TestST CodeC Operator
arithmeticAdda := b + 1;+
arithmeticSuba := b - 1;-
arithmeticMula := b * 2;*
arithmeticDiva := b / 2;/
arithmeticModa := b MOD 3;%
arithmeticPowerc := x ** 2.0;EXPT()
arithmeticNegatea := -b;-(...)
arithmeticParenthesesa := (b + 1) * 2;Parenthesization

1.3 Comparison Operators

TestST CodeC Operator
compareEqualflag := a = b;==
compareNotEqualflag := a <> b;!=
compareLessflag := a < b;<
compareGreaterflag := a > b;>
compareLessEqualflag := a <= b;<=
compareGreaterEqualflag := a >= b;>=

1.4 Boolean Operators

TestST CodeC Operator
boolAndflag := flag AND flag;&&
boolOrflag := flag OR flag;||
boolXorflag := flag XOR flag;^
boolNotflag := NOT flag;!

1.5 Literals

TestST CodeVerifies
literalIntegera := 12345;Integer
literalRealc := 3.14;Floating point
literalBoolTrueflag := TRUE;Boolean value
literalBoolFalseflag := FALSE;Boolean value
literalStringtext := 'hello';String
literalTimecounter := T#500ms;Time constant

1.6 Control Structures

IF / ELSIF / ELSE / END_IF

TestVerifies
ifSimpleSimple condition
ifElseIf-else branching
ifElsifMultiple branching with ELSIF
ifNestedNested IF blocks

FOR / WHILE / REPEAT

TestVerifies
forSimpleFOR idx := 0 TO 10 DO
forWithByFOR with BY step size
whileLoopWHILE loop
repeatUntilREPEAT/UNTIL loop

CASE

TestVerifies
caseStatementCASE/OF with multiple labels + switch/case/break

RETURN / EXIT

TestVerifies
returnStatementRETURN → goto __end
exitStatementEXIT inside FOR → break

1.7 Function Blocks (FB Calls)

TestVerifies
fbCallWithInputsMyTon(IN := flag, PT := T#500ms);
fbCallWithOutputAssignMyTimer(IN := flag, Q => flag); — OUT => assignment

1.8 Array Access

TestVerifies
arrayReadSubscripta := arr[3];
arrayWriteSubscriptarr[5] := 42;
arrayComputedIndexa := arr[idx + 1];
arrayInForLoopArray access inside FOR loop

1.9 Type Conversions

The compiler recognizes the XXX_TO_YYY pattern and generates C-style casts ((TYPE)value), conforming to the IEC standard.

TestST CodeGenerated
typeConvIntToRealINT_TO_REAL(a)(REAL)a
convRealToIntREAL_TO_INT(c)(INT)c
convBoolToIntBOOL_TO_INT(flag)(INT)flag
convIntToBoolINT_TO_BOOL(a)(BOOL)a
convDintToRealDINT_TO_REAL(counter)(REAL)counter
convIntToDintINT_TO_DINT(a)(DINT)a

1.10 Struct Member Access

TestVerifies
structMemberAccesspos.x := 42;data__->pos.value.x

1.11 Cross-Task Variables (Multi-Task)

TestVerifies
crossPrimitiveGet__GET_EXTERNAL_ATOMIC for lock-free reads
crossPrimitiveSet__SET_EXTERNAL_ATOMIC for lock-free writes
crossStructuredGet__snap_ thread-local snapshot access
crossStructuredMemberAccess__snap_Struct.field access

1.12 Standard Function Blocks

Each IEC standard FB is instantiated and called:

TestFB TypeVerifies
fbTonTONOn-delay timer
fbTofTOFOff-delay timer
fbTpTPPulse timer
fbCtuCTUUp counter
fbCtdCTDDown counter
fbRtrigR_TRIGRising edge
fbFtrigF_TRIGFalling edge
fbRsRSReset-dominant
fbSrSRSet-dominant

1.13 Standard Functions

CategoryTestsFunctions
Math12ABS, SQRT, SIN, COS, TAN, ASIN, ACOS, ATAN, EXP, LN, LOG, TRUNC
Selection4SEL, LIMIT, MIN, MAX
String6LEN, LEFT, RIGHT, MID, CONCAT, FIND
Bit shift4SHL, SHR, ROL, ROR
Type conversion6INT_TO_REAL, REAL_TO_INT, BOOL_TO_INT, …

1.14 Edge Cases

TestVerifies
complexNestedExpressionNested expressions
multipleStatementsOnSeparateLinesMulti-line programs
emptyBodyEmpty POU body
commentOnlyBodyComments only
caseInsensitiveKeywordsIF/if/If
caseInsensitiveVariablesCase insensitivity

2. Standard Library (FStLibraryTest)

8 data-driven tests verify all 132 blocks from the standard library (standard_library.sql) automatically.

2.1 Function Blocks (13 FBs)

TestVerifies
fbSingleInstanceEach FB can be instantiated and called individually
fbDoubleInstanceTwo instances of the same FB type simultaneously
fbOutputReadAll outputs readable after the call

Covered FBs: SR, RS, R_TRIG, F_TRIG, CTU, CTD, CTUD, TON, TOF, TP, RTC, SEMA, RampGen

2.2 Functions (119 FCs)

TestVerifies
fcCallEach FC callable with correct parameters (104 tested)
fcInExpressionFC return value usable in expressions

Covered categories:

  • Arithmetic: ADD, SUB, MUL, DIV, MOD, EXPT, ABS
  • Comparison: EQ, NE, LT, GT, LE, GE
  • Trigonometry: SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2
  • Logarithmic: EXP, LN, LOG, SQRT
  • Selection: SEL, MUX, LIMIT, MIN, MAX, MOVE, CLAMP
  • String: LEN, LEFT, RIGHT, MID, CONCAT, INSERT, DELETE, REPLACE, FIND
  • Bit shift: SHL, SHR, ROL, ROR
  • Type conversion: 60+ conversion functions (BOOL_TO_INT, INT_TO_REAL, …)
  • ForgeIEC extensions: LERP, MAP_RANGE, HYPOT, DEG, RAD, IK_2Link, CABS, CADD, CMUL, CSUB, CARG, CCONJ, CPOLAR, CRECT

3. Multi-Task Threading (FCodeGeneratorThreadingTest)

8 tests verify the complete multi-task scheduling system according to the design specification (MT-spec, docs/design/multi-task-scheduler.md).

TestVerifies
singleProgramDefaultTaskOne PROGRAM without explicit task → DefaultTask synthesis, no threading
twoProgramsTwoTasksTwo tasks → RESOURCE0_start__, legacy shim config_run__, both task threads
crossPrimitiveAtomicEmissionShared INT variable → std::atomic<> location storage, __GET_EXTERNAL_ATOMIC in body
crossStructuredDoubleBufferShared STRUCT → __DBUF_[2] + thread_local __snap_ + double-buffer copy-in/out
localVarNoSyncVariable used in one task only → normal __SET_EXTERNAL, no atomic
conflictTwoWritersTwo tasks write the same variable → compile warning
singleProgramDefaultTaskBackward compatibility: existing projects run unchanged

Multi-Task Architecture

Primary Task (Task 0)          Secondary Tasks (1..N)
    |                               |
    | config_run__()                | RESOURCE0_task_thread__()
    |   ├─ sync_in                  |   ├─ dbuf_rd (copy-in)
    |   ├─ TASK0_body__()           |   ├─ TASKn_body__()
    |   └─ sync_out                 |   └─ dbuf_wr (copy-out)
    |                               |
    | [under bufferLock]            | [lock-free]

Synchronization mechanisms:

  • CrossPrimitive (BOOL, INT, REAL, …): std::atomic<T> on the location variable, __GET_EXTERNAL_ATOMIC / __SET_EXTERNAL_ATOMIC in body code
  • CrossStructured (STRUCT, ARRAY, STRING): Double-buffer __DBUF_[2] with atomic write index, thread_local snapshots __snap_ for set consistency

Quality Assurance

Automated Verification

The tests run with every build using -DBUILD_TESTS=ON. Integration into the CI pipeline (Forgejo Actions) is prepared.

Data-Driven Tests

The library tests (FStLibraryTest) read block definitions directly from standard_library.sql. When new blocks are added, they are automatically included in the test run — no manual creation of test cases required.

Completeness

The test suite covers the entire IEC 61131-3 Structured Text language feature set as supported by ForgeIEC:

  • All operators (arithmetic, comparison, boolean, bit shift)
  • All control structures (IF, FOR, WHILE, REPEAT, CASE)
  • All literal types (integer, real, bool, string, time)
  • All standard FBs and FCs (132 blocks)
  • Array and struct access
  • GVL-qualified variables
  • Cross-task synchronization (atomics + double-buffer)
  • Type conversions (C-cast generation)