tcunit / TcUnit

An unit testing framework for Beckhoff's TwinCAT 3
Other
273 stars 75 forks source link

Doing assert two times or more in different cycles for arrays #15

Closed sagatowski closed 5 years ago

sagatowski commented 5 years ago

If you do a (failing) assert for standard data types in two different cycles, the framework takes care of this and only prints one of them.

If the same is done for an array, then both of them are printed (actually, one gets printed for every cycle the assert is called).

The behavior should be the same for both arrays and non-arrays.

sagatowski commented 5 years ago

The test-function block "FB_AssertEveryFailedTestTwice_ArrayVersion" in TcUnit-Verifier has been created to show this behavior.

sagatowski commented 5 years ago

The reason for this bug is that the public method "ReportResult" does not have support for arrays. The reason for that is because it uses a free function called "F_IsAnyEqualToUnionValue()" in where one of the parameters is an union of all primitive/standard data types, which is compared to the incoming ANY (which can be an an array).

This issue can be solved by checking whether the two incoming ANY in ReportResult are an instance of array, and if so, special handling should be done. A suggestion is to use the available data we have for an array, which is the data that is stored in the underlying data for ANY, which is:

TYPE AnyType : STRUCT // the type of the actual parameter typeclass : __SYSTEM.TYPE_CLASS ; // the pointer to the actual parameter pvalue : POINTER TO BYTE; // the size of the data, to which the pointer points diSize : DINT; END_STRUCT END_TYPE

described in more details here.

The only usable available data here is the size of the data of which the pointer points. It needs to be investigated whether the size of this is the total size of the array, or just the size of the underlying data type of one datapoint, or something else. In any case, if it is an array, the free function F_IsAnyEqualToUnionValue() should definitely not be used.

sagatowski commented 5 years ago

A minor update. I tested to create an array of 30 INTs, and provided that array as an ANY-input, and then checked the size (AnyValue.diSize), and it returned 60. This means that the size returns the complete size of the array, which is good. Given the fact that we will always know the underlying type of the array (INT, BOOL, WORD, etc...) we could store the total size + the primitive type of the array as the "key" just as the key for ordinary data types is the type.

sagatowski commented 5 years ago

Another update. The problem is unforutnaetly much deeper than that. When for example calling the following method

METHOD PUBLIC AssertArrayEquals_BOOL VAR_IN_OUT Expecteds : ARRAY[] OF BOOL; // BOOL array with expected values Actuals : ARRAY[] OF BOOL; // BOOL array with actual values END_VAR

And then pushing the expecteds and actuals to METHOD PUBLIC ReportResult VAR_INPUT Expected : ANY; Actual : ANY; Message : Tc2_System.T_MaxString; TestInstancePath : Tc2_System.T_MaxString; END_VAR

The [*]-Arrays are actually POINTERS. So what the ANY.TypeClass returns is the type POINTER and ANY.diSize is the size of the pointer, so no usable information is given here.

The suggestion is basically to write a separate METHOD PUBLIC ReportResult_Array.

That can utilize the information about "Expecteds : ARRAY[*] OF BOOL;" (which is the TYPE + the total size of the array by LOWER and UPPER-bounds.

sagatowski commented 5 years ago

Solved in commit 7fa7c05.