FB_AssertArrayResultStatic  Function Block

This function block is responsible for keeping track of which array-asserts that have been made. The reason we need to keep track of these is because if the user does the same assert twice (because of running a test suite over several PLC-cycles) we want to know it so we don't print several times (if the assert fails). An instance of an array-assert is keyed/identified with the following parameters as key: - Array-size (in bytes) of the expecteds - Datatype of the expecteds - Array-size (in bytes) of the actuals - Datatype of the actuals - Message (string) - Test instance path (string)


Variables

Name Type Default Description
AssertArrayResults ARRAY[1..GVL_Param_TcUnit.MaxNumberOfAssertsForEachTestSuite] OF ST_AssertArrayResult
TotalArrayAsserts UINT 0
GetCurrentTaskIndex GETCURTASKINDEX
AssertArrayResultInstances ARRAY[1..GVL_Param_TcUnit.MaxNumberOfAssertsForEachTestSuite] OF ST_AssertArrayResultInstances
CycleCount UDINT
FirstCycleExecuted BOOL

Methods

AddAssertArrayResult PRIVATE

Parameters

Name Type Description
ExpectedsSize UDINT
ExpectedsTypeClass IBaseLibrary.TypeClass
ActualsSize UDINT
ActualsTypeClass IBaseLibrary.TypeClass
Message T_MaxString
TestInstancePath T_MaxString
Implementation
IF TotalArrayAsserts < GVL_Param_TcUnit.MaxNumberOfAssertsForEachTestSuite THEN
	TotalArrayAsserts := TotalArrayAsserts + 1;
	AssertArrayResults[TotalArrayAsserts].ExpectedsSize := ExpectedsSize;
	AssertArrayResults[TotalArrayAsserts].ExpectedsTypeClass := ExpectedsTypeClass;
	AssertArrayResults[TotalArrayAsserts].ActualsSize := ActualsSize;
	AssertArrayResults[TotalArrayAsserts].ActualsTypeClass := ActualsTypeClass;
	AssertArrayResults[TotalArrayAsserts].Message := Message;
	AssertArrayResults[TotalArrayAsserts].TestInstancePath := TestInstancePath;
ELSE
	IF NOT AssertResultOverflow THEN
        sErrorString := CONCAT(STR1 := F_GetTestSuiteNameFromTestInstancePath(TestInstancePath := TestInstancePath),
                               STR2 := '. Max number of assertions exceeded. Check parameter MaxNumberOfAssertsForEachTestSuite.');
		GVL_TcUnit.AdsMessageQueue.WriteLog(MsgCtrlMask := ADSLOG_MSGTYPE_ERROR,
											MsgFmtStr := sErrorString,
											StrArg := '');
		AssertResultOverflow := TRUE;
	END_IF
END_IF
CopyDetectionCountAndResetDetectionCountInThisCycle PRIVATE
Implementation
FOR IteratorCounter := 1 TO GVL_Param_TcUnit.MaxNumberOfAssertsForEachTestSuite BY 1 DO
    AssertArrayResultInstances[IteratorCounter].DetectionCount := AssertArrayResultInstances[IteratorCounter].DetectionCountThisCycle;
    AssertArrayResultInstances[IteratorCounter].DetectionCountThisCycle := 0;
END_FOR
CreateAssertResultInstance PRIVATE

Parameters

Name Type Description
ExpectedsSize UDINT
ExpectedsTypeClass IBaseLibrary.TypeClass
ActualsSize UDINT
ActualsTypeClass IBaseLibrary.TypeClass
Message T_MaxString
TestInstancePath T_MaxString
Implementation
FOR IteratorCounter := 1 TO GVL_Param_TcUnit.MaxNumberOfAssertsForEachTestSuite BY 1 DO
    IF AssertArrayResultInstances[IteratorCounter].DetectionCount = 0 AND
        AssertArrayResultInstances[IteratorCounter].DetectionCountThisCycle = 0 THEN // Find first free spot
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ExpectedsSize := ExpectedsSize;
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ExpectedsTypeClass := ExpectedsTypeClass;
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ActualsSize := ActualsSize;
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ActualsTypeClass := ActualsTypeClass;
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.Message := Message;
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.TestInstancePath := TestInstancePath;
        AssertArrayResultInstances[IteratorCounter].DetectionCountThisCycle := 1;
        EXIT;
    END_IF
END_FOR
GetDetectionCount PRIVATE

Parameters

Name Type Description
ExpectedsSize UDINT
ExpectedsTypeClass IBaseLibrary.TypeClass
ActualsSize UDINT
ActualsTypeClass IBaseLibrary.TypeClass
Message T_MaxString
TestInstancePath T_MaxString
Implementation
FOR IteratorCounter := 1 TO GVL_Param_TcUnit.MaxNumberOfAssertsForEachTestSuite BY 1 DO
    IF AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ExpectedsSize = ExpectedsSize AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ExpectedsTypeClass = ExpectedsTypeClass AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ActualsSize = ActualsSize AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ActualsTypeClass = ActualsTypeClass AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.Message = Message AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.TestInstancePath = TestInstancePath THEN
        GetDetectionCount := AssertArrayResultInstances[IteratorCounter].DetectionCount;
    END_IF
END_FOR
GetDetectionCountThisCycle PRIVATE

Parameters

Name Type Description
ExpectedsSize UDINT
ExpectedsTypeClass IBaseLibrary.TypeClass
ActualsSize UDINT
ActualsTypeClass IBaseLibrary.TypeClass
Message T_MaxString
TestInstancePath T_MaxString
Implementation
FOR IteratorCounter := 1 TO GVL_Param_TcUnit.MaxNumberOfAssertsForEachTestSuite BY 1 DO
    IF AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ExpectedsSize = ExpectedsSize AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ExpectedsTypeClass = ExpectedsTypeClass AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ActualsSize = ActualsSize AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ActualsTypeClass = ActualsTypeClass AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.Message = Message AND
       AssertArrayResultInstances[IteratorCounter].AssertArrayResult.TestInstancePath = TestInstancePath THEN

        GetDetectionCountThisCycle := AssertArrayResultInstances[IteratorCounter].DetectionCountThisCycle;
    END_IF
END_FOR
GetNumberOfArrayAssertsForTest INTERNAL

Parameters

Name Type Description
CompleteTestInstancePath T_MaxString
Implementation
IF TotalArrayAsserts > 0 THEN
    FOR Counter := 1 TO TotalArrayAsserts BY 1 DO
        IF AssertArrayResults[Counter].TestInstancePath = CompleteTestInstancePath THEN
            NumberOfArrayAsserts := NumberOfArrayAsserts + 1;
        END_IF
    END_FOR
END_IF

GetNumberOfArrayAssertsForTest := NumberOfArrayAsserts;
ReportResult INTERNAL

This method is called in every assert and returns whether this particular assert has already been called. The reason one would like to know whether this assert has already been reported or not is to not report it several times to any logging service. Because a test-suite can consist of several tests, and certain tests can require the test to run over several cycles it means that certain asserts could be called several times and thus we need to keep track of which asserts we've already reported. The user of the framework should not need to care for any of this and he/she should be able to call the asserts in any way they find suitable. To know what assert this is we need to check for the total combination of: - Test message - Test instance path - Expecteds size (in bytes) - Actuals size (in bytes) - Expecteds datatype - Actuals datatype Theoretically we can have a situation where a test has three different asserts, each and one with the same test message/test instance path/actuals size&datatype/expecteds size&datatype but called within the same or different cycles. In order for us to handle all situations we need a simple algorithm that works according to: - Keep track of how many instances the combination of test message/test instance path/expecteds size&datatype/ actuals size&datatype we have. So for example, if we have called Assert(Exp := [5,4,3], Act := [5,4,3], 'Hello there', 'PRG.InstanceTestSuite.Test') two times in one cycle, we have two instances of that combination. This is done according to: - Iterate all existing reports. - If we have a new PLC-cycle, set the current detection-count to zero. - If new report does not match in any of the above fields, create it (together with current PLC-cycle). Also store the information that we have one instance of this combination and +1 on the detection-count. - If new report matches in all of the above, +1 in the detection-count. If this detection-count is larger than the stored detection-count for this combination, create a new report and add +1 to the storage of the detection-count.

Parameters

Name Type Description
ExpectedsSize UDINT
ExpectedsTypeClass IBaseLibrary.TypeClass
ActualsSize UDINT
ActualsTypeClass IBaseLibrary.TypeClass
Message T_MaxString
TestInstancePath T_MaxString

Outputs

Name Type Default Description
AlreadyReported BOOL FALSE
Implementation
IF NOT FirstCycleExecuted THEN
    GetCurrentTaskIndex();
    FirstCycleExecuted := TRUE;
END_IF

CurrentCycleCount := TwinCAT_SystemInfoVarList._TaskInfo[GetCurrentTaskIndex.index].CycleCount;
(* Is current cycle the same as the last call to this method?
   If not, reset the detection count *)
IF CurrentCycleCount <> CycleCount THEN
    CopyDetectionCountAndResetDetectionCountInThisCycle();
END_IF

FOR IteratorCounter := 1 TO TotalArrayAsserts BY 1 DO
    IF AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ExpectedsSize = ExpectedsSize AND
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ExpectedsTypeClass = ExpectedsTypeClass AND
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ActualsSize = ActualsSize AND
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.ActualsTypeClass = ActualsTypeClass AND
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.Message = Message AND
        AssertArrayResultInstances[IteratorCounter].AssertArrayResult.TestInstancePath = TestInstancePath THEN
        AssertArrayResultInstances[IteratorCounter].DetectionCountThisCycle :=
            AssertArrayResultInstances[IteratorCounter].DetectionCountThisCycle + 1;
            FoundOne := TRUE;
        IF AssertArrayResultInstances[IteratorCounter].DetectionCountThisCycle >
                AssertArrayResultInstances[IteratorCounter].DetectionCount THEN // This assert is new
                AdditionalIdenticalAssert := TRUE;
        END_IF
        EXIT;
    END_IF
END_FOR

// If not found anything, create the first
IF NOT FoundOne THEN
    // No existing match found, create a new entry
    AddAssertArrayResult(ExpectedsSize := ExpectedsSize,
                         ExpectedsTypeClass := ExpectedsTypeClass,
                         ActualsSize := ActualsSize,
                         ActualsTypeClass := ActualsTypeClass,
                         Message := Message,
                         TestInstancePath := TestInstancePath);
    CreateAssertResultInstance(ExpectedsSize := ExpectedsSize,
                               ExpectedsTypeClass := ExpectedsTypeClass,
                               ActualsSize := ActualsSize,
                               ActualsTypeClass := ActualsTypeClass,
                               Message := Message,
                               TestInstancePath := TestInstancePath);
// An additional instance of this assert needs to be created
ELSIF AdditionalIdenticalAssert THEN
    AddAssertArrayResult(ExpectedsSize := ExpectedsSize,
                         ExpectedsTypeClass := ExpectedsTypeClass,
                         ActualsSize := ActualsSize,
                         ActualsTypeClass := ActualsTypeClass,
                         Message := Message,
                         TestInstancePath := TestInstancePath);
// In all other cases, this assert has already been reported, we don't need to do anything
ELSE
    AlreadyReported := TRUE;
END_IF

// Update the cycle count
CycleCount := TwinCAT_SystemInfoVarList._TaskInfo[GetCurrentTaskIndex.index].CycleCount;

Used by

Declaration source
(*
    This function block is responsible for keeping track of which array-asserts that have been made.
    The reason we need to keep track of these is because if the user does the same assert twice
    (because of running a test suite over several PLC-cycles) we want to know it so we don't print several times
    (if the assert fails). An instance of an array-assert is keyed/identified with the following parameters as key:
    - Array-size (in bytes) of the expecteds
    - Datatype of the expecteds
    - Array-size (in bytes) of the actuals
    - Datatype of the actuals
    - Message (string)
    - Test instance path (string)
*)
FUNCTION_BLOCK FB_AssertArrayResultStatic
VAR
    // The total number of instances of each of the "AssertArrayResults"
    AssertArrayResults : ARRAY[1..GVL_Param_TcUnit.MaxNumberOfAssertsForEachTestSuite] OF ST_AssertArrayResult;

    // The total number of unique asserts
    TotalArrayAsserts : UINT := 0;

    // Function block to get the current task cycle
    GetCurrentTaskIndex : GETCURTASKINDEX;

    // The total number of instances of each of the "AssertArrayResults"
    AssertArrayResultInstances : ARRAY[1..GVL_Param_TcUnit.MaxNumberOfAssertsForEachTestSuite] OF ST_AssertArrayResultInstances;

    // The last PLC cycle count
    CycleCount : UDINT;

    // Only run first cycle
    FirstCycleExecuted : BOOL;
END_VAR