| | 1 | | #pragma rtGlobals=3 |
| | 2 | | #pragma rtFunctionErrors=1 |
| | 3 | | #pragma version=1.10 |
| | 4 | | #pragma TextEncoding="UTF-8" |
| | 5 | | #pragma ModuleName=IUTF_Basics |
| | 6 | |
|
| | 7 | | #undef UTF_ALLOW_TRACING |
| | 8 | | #if Exists("TUFXOP_Version") |
| | 9 | |
|
| | 10 | | #if IgorVersion() >= 10.00 |
| | 11 | | #define UTF_ALLOW_TRACING |
| | 12 | | #elif (IgorVersion() >= 9.00) && (NumberByKey("BUILD", IgorInfo(0)) >= 38812) |
| | 13 | | #define UTF_ALLOW_TRACING |
| | 14 | | #endif |
| | 15 | |
|
| | 16 | | #endif |
| | 17 | |
|
| | 18 | | ///@cond HIDDEN_SYMBOL |
| | 19 | |
|
| | 20 | | static Constant FFNAME_OK = 0x00 |
| | 21 | | static Constant FFNAME_NOT_FOUND = 0x01 |
| | 22 | | static Constant FFNAME_NO_MODULE = 0x02 |
| | 23 | | static Constant TC_MATCH_OK = 0x00 |
| | 24 | | static Constant TC_REGEX_INVALID = 0x04 |
| | 25 | | static Constant TC_NOT_FOUND = 0x08 |
| | 26 | | static Constant TC_LIST_EMPTY = 0x10 |
| | 27 | | static Constant GREPLIST_ERROR = 0x20 |
| | 28 | |
|
| | 29 | | static Constant IGOR_MAX_DIMENSIONS = 4 |
| | 30 | |
|
| | 31 | | static StrConstant FIXED_LOG_FILENAME = "IUTF_Test" |
| | 32 | |
|
| | 33 | | static StrConstant NO_SOURCE_PROCEDURE = "No source procedure" |
| | 34 | |
|
| | 35 | | static StrConstant BACKGROUNDMONTASK = "IUTFBackgroundMonitor" |
| | 36 | | static StrConstant BACKGROUNDMONFUNC = "IUTFBackgroundMonitor" |
| | 37 | | static StrConstant BACKGROUNDINFOSTR = ":UNUSED_FOR_REENTRY:" |
| | 38 | |
|
| | 39 | | static Constant TC_MODE_NORMAL = 0 |
| | 40 | | static Constant TC_MODE_MD = 1 |
| | 41 | | static Constant TC_MODE_MMD = 2 |
| | 42 | |
|
| | 43 | | static Constant MAX_PROCTAGS_SCAN_LINES = 20 |
| | 44 | |
|
| | 45 | | /// @brief Returns a global wave that stores data about this testrun |
| 336 | 46 | | static Function/WAVE GetTestRunData() |
| | 47 | |
|
| 336 | 48 | | string name = "TestRunData" |
| | 49 | |
|
| 336 | 50 | | DFREF dfr = GetPackageFolder() |
| 336 | 51 | | WAVE/Z/T wv = dfr:$name |
| 336 | 52 | | if(WaveExists(wv)) |
| 325 | 53 | | return wv |
| 11 | 54 | | endif |
| | 55 | |
|
| 11 | 56 | | Make/T/N=(0, 6) dfr:$name/WAVE=wv |
| | 57 | |
|
| 11 | 58 | | SetDimLabel UTF_COLUMN, 0, PROCWIN, wv |
| 11 | 59 | | SetDimLabel UTF_COLUMN, 1, TESTCASE, wv |
| 11 | 60 | | SetDimLabel UTF_COLUMN, 2, FULLFUNCNAME, wv |
| 11 | 61 | | SetDimLabel UTF_COLUMN, 3, DGENLIST, wv |
| 11 | 62 | | SetDimLabel UTF_COLUMN, 4, SKIP, wv |
| 11 | 63 | | SetDimLabel UTF_COLUMN, 5, EXPECTFAIL, wv |
| | 64 | |
|
| 11 | 65 | | return wv |
| 336 | 66 | | End |
| | 67 | |
|
| | 68 | | /// @brief Helper function for try/catch with AbortOnRTE |
| | 69 | | /// |
| | 70 | | /// Not clearing the RTE before calling `AbortOnRTE` will always trigger the RTE no |
| | 71 | | /// matter what you do in that line. |
| | 72 | | /// |
| | 73 | | /// Usage: |
| | 74 | | /// @code |
| | 75 | | /// |
| | 76 | | /// try |
| | 77 | | /// ClearRTError() |
| | 78 | | /// myFunc(); AbortOnRTE |
| | 79 | | /// catch |
| | 80 | | /// err = GetRTError(1) |
| | 81 | | /// endtry |
| | 82 | | /// |
| | 83 | | /// @endcode |
| 39 | 84 | | static Function ClearRTError() |
| | 85 | |
|
| 39 | 86 | | variable err = GetRTError(1) |
| 39 | 87 | | End |
| | 88 | |
|
| | 89 | | /// @brief Convert the mode parameter for `EqualWaves` to a string |
| 0 | 90 | | Function/S EqualWavesModeToString(mode) |
| | 91 | | variable mode |
| | 92 | |
|
| 0 | 93 | | switch(mode) |
| 0 | 94 | | case WAVE_DATA: |
| 0 | 95 | | return "WAVE_DATA" |
| 0 | 96 | | case WAVE_DATA_TYPE: |
| 0 | 97 | | return "WAVE_DATA_TYPE" |
| 0 | 98 | | case WAVE_SCALING: |
| 0 | 99 | | return "WAVE_SCALING" |
| 0 | 100 | | case DATA_UNITS: |
| 0 | 101 | | return "DATA_UNITS" |
| 0 | 102 | | case DIMENSION_UNITS: |
| 0 | 103 | | return "DIMENSION_UNITS" |
| 0 | 104 | | case DIMENSION_LABELS: |
| 0 | 105 | | return "DIMENSION_LABELS" |
| 0 | 106 | | case WAVE_NOTE: |
| 0 | 107 | | return "WAVE_NOTE" |
| 0 | 108 | | case WAVE_LOCK_STATE: |
| 0 | 109 | | return "WAVE_LOCK_STATE" |
| 0 | 110 | | case DATA_FULL_SCALE: |
| 0 | 111 | | return "DATA_FULL_SCALE" |
| 0 | 112 | | case DIMENSION_SIZES: |
| 0 | 113 | | return "DIMENSION_SIZES" |
| 0 | 114 | | default: |
| 0 | 115 | | return "unknown mode" |
| 0 | 116 | | endswitch |
| 0 | 117 | | End |
| | 118 | |
|
| | 119 | | /// @class FUNC_REF_IS_ASSIGNED_DOCU |
| | 120 | | /// @brief Check wether the function reference points to |
| | 121 | | /// the prototype function or to an assigned function |
| | 122 | | /// |
| | 123 | | /// Due to Igor Pro limitations you need to pass the function |
| | 124 | | /// info from `FuncRefInfo` and not the function reference itself. |
| | 125 | | /// |
| | 126 | | /// @return 0 if pointing to prototype function, 1 otherwise |
| 159 | 127 | | Function IUTF_FuncRefIsAssigned(funcInfo) |
| | 128 | | string funcInfo |
| | 129 | |
|
| 159 | 130 | | return NumberByKey("ISPROTO", funcInfo) == 0 |
| 159 | 131 | | End |
| | 132 | |
|
| | 133 | | /// @copydoc FUNC_REF_IS_ASSIGNED_DOCU |
| | 134 | | /// @deprecated Use IUTF_FuncRefIsAssigned instead |
| 0 | 135 | | Function UTF_FuncRefIsAssigned(funcInfo) |
| | 136 | | string funcInfo |
| | 137 | |
|
| 0 | 138 | | return IUTF_FuncRefIsAssigned(funcInfo) |
| 0 | 139 | | End |
| | 140 | |
|
| | 141 | | /// @brief Return a free text wave with the dimension labels of the |
| | 142 | | /// given dimension of the wave |
| 0 | 143 | | static Function/WAVE GetDimLabels(wv, dim) |
| | 144 | | WAVE/Z wv |
| | 145 | | variable dim |
| | 146 | |
|
| 0 | 147 | | variable size |
| | 148 | |
|
| 0 | 149 | | if(!WaveExists(wv)) |
| 0 | 150 | | return $"" |
| 0 | 151 | | endif |
| | 152 | |
|
| 0 | 153 | | size = DimSize(wv, dim) |
| | 154 | |
|
| 0 | 155 | | if(size == 0) |
| 0 | 156 | | return $"" |
| 0 | 157 | | endif |
| | 158 | |
|
| 0 | 159 | | Make/FREE/T/N=(size) labels = GetDimLabel(wv, dim, p) |
| | 160 | |
|
| 0 | 161 | | return labels |
| 0 | 162 | | End |
| | 163 | |
|
| | 164 | | /// @brief Create a diagnostic message of the differing dimension labels |
| | 165 | | /// |
| | 166 | | /// @param[in] wv1 Possible non-existing wave |
| | 167 | | /// @param[in] wv2 Possible non-existing wave |
| | 168 | | /// @param[out] str Diagnostic message indicating the deviations, empty string on success |
| | 169 | | /// |
| | 170 | | /// @return 1 with no differences, 0 with differences |
| 0 | 171 | | Function GenerateDimLabelDifference(wv1, wv2, msg) |
| | 172 | | WAVE/Z wv1, wv2 |
| | 173 | | string &msg |
| | 174 | |
|
| 0 | 175 | | variable i, j, numEntries |
| 0 | 176 | | string str1, str2, tmpStr1, tmpStr2 |
| 0 | 177 | | variable ret |
| | 178 | |
|
| 0 | 179 | | msg = "" |
| | 180 | |
|
| 0 | 181 | | for(i = 0; i < IGOR_MAX_DIMENSIONS; i += 1) |
| | 182 | |
|
| 0 | 183 | | WAVE/Z/T label1 = GetDimLabels(wv1, i) |
| 0 | 184 | | WAVE/Z/T label2 = GetDimLabels(wv2, i) |
| | 185 | |
|
| 0 | 186 | | if(!WaveExists(label1) && !WaveExists(label2)) |
| 0 | 187 | | break |
| 0 | 188 | | endif |
| | 189 | |
|
| 0 | 190 | | if(!WaveExists(label1)) |
| 0 | 191 | | sprintf msg, "Empty dimension vs non-empty dimension" |
| 0 | 192 | | return 0 |
| 0 | 193 | | elseif(!WaveExists(label2)) |
| 0 | 194 | | sprintf msg, "Non-empty dimension vs empty dimension" |
| 0 | 195 | | return 0 |
| 0 | 196 | | else |
| 0 | 197 | | // both exist but differ |
| 0 | 198 | | str1 = GetDimLabel(wv1, i, -1) |
| 0 | 199 | | str2 = GetDimLabel(wv2, i, -1) |
| | 200 | |
|
| 0 | 201 | | if(cmpstr(str1, str2)) |
| 0 | 202 | | tmpStr1 = IUTF_Utils#IUTF_PrepareStringForOut(str1) |
| 0 | 203 | | tmpStr2 = IUTF_Utils#IUTF_PrepareStringForOut(str2) |
| 0 | 204 | | sprintf msg, "Dimension labels for the entire dimension %d differ: %s vs %s", i, tmpStr1, tmpStr2 |
| 0 | 205 | | return 0 |
| 0 | 206 | | endif |
| | 207 | |
|
| 0 | 208 | | if(EqualWaves(label1, label2, WAVE_DATA)) |
| 0 | 209 | | continue |
| 0 | 210 | | endif |
| | 211 | |
|
| 0 | 212 | | if(DimSize(label1, i) != DimSize(label2, i)) |
| 0 | 213 | | sprintf msg, "The sizes for dimension %d don't match: %d vs %d", i, DimSize(label1, i), DimSize(label2, i) |
| 0 | 214 | | return 0 |
| 0 | 215 | | endif |
| | 216 | |
|
| 0 | 217 | | numEntries = DimSize(label1, i) |
| 0 | 218 | | for(j = 0; j < numEntries; j += 1) |
| 0 | 219 | | if(!cmpstr(label1[j], label2[j], 1)) |
| 0 | 220 | | continue |
| 0 | 221 | | endif |
| 0 | 222 | | str1 = label1[j] |
| 0 | 223 | | str2 = label2[j] |
| 0 | 224 | | tmpStr1 = IUTF_Utils#IUTF_PrepareStringForOut(str1) |
| 0 | 225 | | tmpStr2 = IUTF_Utils#IUTF_PrepareStringForOut(str2) |
| 0 | 226 | | sprintf msg, "Differing dimension label in dimension %d at index %d: %s vs %s", i, j, tmpStr1, tmpStr2 |
| 0 | 227 | | return 0 |
| 0 | 228 | | endfor |
| 0 | 229 | | endif |
| 0 | 230 | | endfor |
| | 231 | |
|
| 0 | 232 | | return 1 |
| 0 | 233 | | End |
| | 234 | |
|
| 5 | 235 | | Function/S GetVersion() |
| 5 | 236 | | string version |
| 5 | 237 | | sprintf version, "%.2f", PKG_VERSION |
| | 238 | |
|
| 5 | 239 | | return version |
| 5 | 240 | | End |
| | 241 | |
|
| | 242 | | /// Returns the package folder |
| 5487 | 243 | | Function/DF GetPackageFolder() |
| | 244 | |
|
| 5487 | 245 | | DFREF dfr = $PKG_FOLDER |
| 5487 | 246 | | if(!DataFolderRefStatus(dfr)) |
| 0 | 247 | | NewDataFolder/O root:Packages |
| 0 | 248 | | NewDataFolder/O root:Packages:igortest |
| 0 | 249 | | DFREF dfr = $PKG_FOLDER |
| 5487 | 250 | | endif |
| | 251 | |
|
| 5487 | 252 | | return dfr |
| 5487 | 253 | | End |
| | 254 | |
|
| | 255 | | /// Evaluate the result of an assertion that was used in a testcase. For evaluating internal errors use |
| | 256 | | /// ReportError* functions. |
| | 257 | | /// @param result Set to 0 to signal an error. Any value different to 0 will be considered as success. |
| | 258 | | /// @param str The message to report. |
| | 259 | | /// @param flags A combination flags that are used by ReportResults() to determine what to do if result |
| | 260 | | /// is in an error state. |
| | 261 | | /// @param cleanupInfo [optional, default enabled] If set different to zero it will cleanup |
| | 262 | | /// any assertion info message at the end of this function. |
| | 263 | | /// Cleanup is enforced if flags contains the ABORT_FUNCTION flag. |
| | 264 | | /// @param callStack [optional, default current callStack] Can be used to set the callStack |
| | 265 | | /// to a previous recorded callStack (GetRTStackInfo(3)). |
| 355 | 266 | | Function EvaluateResults(result, str, flags, [cleanupInfo, callStack]) |
| | 267 | | variable result, flags |
| | 268 | | string str |
| | 269 | | variable cleanupInfo |
| | 270 | | string callStack |
| | 271 | |
|
| 355 | 272 | | cleanupInfo = ParamIsDefault(cleanupInfo) ? 1 : !!cleanupInfo |
| | 273 | |
|
| 355 | 274 | | IUTF_Debug#DebugFailedAssertion(result) |
| 355 | 275 | | if(ParamIsDefault(callStack)) |
| 351 | 276 | | IUTF_Reporting#ReportResults(result, str, flags, cleanupInfo = cleanupInfo) |
| 4 | 277 | | else |
| 4 | 278 | | IUTF_Reporting#ReportResults(result, str, flags, cleanupInfo = cleanupInfo, callStack = callStack) |
| 355 | 279 | | endif |
| 355 | 280 | | End |
| | 281 | |
|
| | 282 | | /// Returns 1 if the abortFlag is set and zero otherwise |
| 700 | 283 | | Function shouldDoAbort() |
| 700 | 284 | | NVAR/Z/SDFR=GetPackageFolder() abortFlag |
| 700 | 285 | | if(NVAR_Exists(abortFlag) && abortFlag == 1) |
| 0 | 286 | | return 1 |
| 700 | 287 | | else |
| 700 | 288 | | return 0 |
| 0 | 289 | | endif |
| 700 | 290 | | End |
| | 291 | |
|
| | 292 | | /// Sets the abort flag |
| 0 | 293 | | static Function setAbortFlag() |
| 0 | 294 | | DFREF dfr = GetPackageFolder() |
| 0 | 295 | | variable/G dfr:abortFlag = 1 |
| 0 | 296 | | End |
| | 297 | |
|
| | 298 | | /// Resets the abort flag |
| 11 | 299 | | static Function InitAbortFlag() |
| 11 | 300 | | DFREF dfr = GetPackageFolder() |
| 11 | 301 | | variable/G dfr:abortFlag = 0 |
| 11 | 302 | | End |
| | 303 | |
|
| | 304 | | /// Returns 1 if the abortFromSkipFlag is set and zero otherwise |
| 0 | 305 | | static Function IsAbortFromSkip() |
| 0 | 306 | | NVAR/Z/SDFR=GetPackageFolder() abortFromSkipFlag |
| 0 | 307 | | if(NVAR_Exists(abortFromSkipFlag) && abortFromSkipFlag == 1) |
| 0 | 308 | | return 1 |
| 0 | 309 | | else |
| 0 | 310 | | return 0 |
| 0 | 311 | | endif |
| 0 | 312 | | End |
| | 313 | |
|
| | 314 | | /// Sets the abortFromSkipFlag flag |
| 0 | 315 | | static Function SetAbortFromSkipFlag() |
| 0 | 316 | | DFREF dfr = GetPackageFolder() |
| 0 | 317 | | variable/G dfr:abortFromSkipFlag = 1 |
| 0 | 318 | | End |
| | 319 | |
|
| | 320 | | /// Resets the abortFromSkipFlag flag |
| 5 | 321 | | static Function InitAbortFromSkipFlag() |
| 5 | 322 | | DFREF dfr = GetPackageFolder() |
| 5 | 323 | | variable/G dfr:abortFromSkipFlag = 0 |
| 5 | 324 | | End |
| | 325 | |
|
| | 326 | | /// @brief returns 1 if the current testcase is marked as expected failure, zero otherwise |
| | 327 | | /// |
| | 328 | | /// @returns 1 if the current testcase is marked as expected failure, zero otherwise |
| 84 | 329 | | Function IsExpectedFailure() |
| 84 | 330 | | NVAR/Z/SDFR=GetPackageFolder() expected_failure_flag |
| | 331 | |
|
| 84 | 332 | | if(NVAR_Exists(expected_failure_flag) && expected_failure_flag == 1) |
| 0 | 333 | | return 1 |
| 84 | 334 | | else |
| 84 | 335 | | return 0 |
| 0 | 336 | | endif |
| 84 | 337 | | End |
| | 338 | |
|
| | 339 | | /// Sets the expected_failure_flag global |
| 79 | 340 | | static Function SetExpectedFailure(val) |
| | 341 | | variable val |
| | 342 | |
|
| 79 | 343 | | DFREF dfr = GetPackageFolder() |
| 79 | 344 | | NVAR/Z/SDFR=dfr expected_failure_flag |
| | 345 | |
|
| 79 | 346 | | if(!NVAR_Exists(expected_failure_flag)) |
| 5 | 347 | | variable/G dfr:expected_failure_flag |
| 5 | 348 | | NVAR/SDFR=dfr expected_failure_flag |
| 79 | 349 | | endif |
| | 350 | |
|
| 79 | 351 | | expected_failure_flag = val |
| 79 | 352 | | End |
| | 353 | |
|
| | 354 | | /// Return true if running in `ProcGlobal`, false otherwise |
| 17 | 355 | | static Function IsProcGlobal() |
| | 356 | |
|
| 17 | 357 | | return !cmpstr("ProcGlobal", GetIndependentModuleName()) |
| 17 | 358 | | End |
| | 359 | |
|
| | 360 | | /// Returns the full name of a function including its module |
| | 361 | | /// @param &err returns 0 for no error, 1 if function not found, 2 is static function in proc without ModuleName |
| 84 | 362 | | static Function/S getFullFunctionName(err, funcName, procName) |
| | 363 | | variable &err |
| | 364 | | string funcName, procName |
| | 365 | |
|
| 84 | 366 | | err = FFNAME_OK |
| 84 | 367 | | string errMsg, module, infoStr, funcNameReturn |
| | 368 | |
|
| 84 | 369 | | infoStr = FunctionInfo(funcName, procName) |
| | 370 | |
|
| 84 | 371 | | if(IUTF_Utils#IsEmpty(infoStr)) |
| 0 | 372 | | sprintf errMsg, "Function %s in procedure file %s is unknown", funcName, procName |
| 0 | 373 | | err = FFNAME_NOT_FOUND |
| 0 | 374 | | return errMsg |
| 84 | 375 | | endif |
| | 376 | |
|
| 84 | 377 | | funcNameReturn = StringByKey("NAME", infoStr) |
| | 378 | |
|
| 84 | 379 | | if(!cmpstr(StringByKey("SPECIAL", infoStr), "static")) |
| 84 | 380 | | module = StringByKey("MODULE", infoStr) |
| | 381 | |
|
| 84 | 382 | | // we can only use static functions if they live in a module |
| 84 | 383 | | if(IUTF_Utils#IsEmpty(module)) |
| 0 | 384 | | sprintf errMsg, "The procedure file %s is missing a \"#pragma ModuleName=myName\" declaration.", procName |
| 0 | 385 | | err = FFNAME_NO_MODULE |
| 0 | 386 | | return errMsg |
| 84 | 387 | | endif |
| | 388 | |
|
| 84 | 389 | | funcNameReturn = module + "#" + funcNameReturn |
| 84 | 390 | | endif |
| | 391 | |
|
| 84 | 392 | | // even if we are running in an independent module we don't need its name prepended as we |
| 84 | 393 | | // 1.) run in the same IM anyway |
| 84 | 394 | | // 2.) FuncRef does not accept that |
| | 395 | |
|
| 84 | 396 | | return funcNameReturn |
| 84 | 397 | | End |
| | 398 | |
|
| | 399 | | /// Evaluates an RTE and puts a composite error message into message/type |
| 0 | 400 | | static Function EvaluateRTE(err, errmessage, abortCode, funcName, funcType, procWin) |
| | 401 | | variable err |
| | 402 | | string errmessage |
| | 403 | | variable abortCode, funcType |
| | 404 | | string funcName |
| | 405 | | string procWin |
| | 406 | |
|
| 0 | 407 | | DFREF dfr = GetPackageFolder() |
| 0 | 408 | | string message = "" |
| 0 | 409 | | string str, funcTypeString |
| 0 | 410 | | variable i, length |
| | 411 | |
|
| 0 | 412 | | if(!err && !abortCode) |
| 0 | 413 | | return NaN |
| 0 | 414 | | endif |
| | 415 | |
|
| 0 | 416 | | switch(funcType) |
| 0 | 417 | | case IUTF_TEST_CASE_TYPE: |
| 0 | 418 | | funcTypeString = "test case" |
| 0 | 419 | | break |
| 0 | 420 | | case IUTF_USER_HOOK_TYPE: |
| 0 | 421 | | funcTypeString = "user hook" |
| 0 | 422 | | break |
| 0 | 423 | | case IUTF_DATA_GEN_TYPE: |
| 0 | 424 | | funcTypeString = "data generator" |
| 0 | 425 | | break |
| 0 | 426 | | default: |
| 0 | 427 | | IUTF_Reporting#ReportErrorAndAbort("Unknown func type in EvaluateRTE") |
| 0 | 428 | | break |
| 0 | 429 | | endswitch |
| | 430 | |
|
| 0 | 431 | | if(err) |
| 0 | 432 | | sprintf str, "Uncaught runtime error %d:\"%s\" in %s \"%s\" (%s)", err, errmessage, funcTypeString, funcName, procWi |
| 0 | 433 | | IUTF_Reporting#AddFailedSummaryInfo(str) |
| 0 | 434 | | IUTF_Reporting#AddError(str, IUTF_STATUS_ERROR) |
| 0 | 435 | | message = str |
| 0 | 436 | | endif |
| 0 | 437 | | if(abortCode != -4) |
| 0 | 438 | | str = "" |
| 0 | 439 | | switch(abortCode) |
| 0 | 440 | | case -1: |
| 0 | 441 | | sprintf str, "User aborted Test Run manually in %s \"%s\" (%s)", funcTypeString, funcName, procWin |
| 0 | 442 | | IUTF_Reporting#AddFailedSummaryInfo(str) |
| 0 | 443 | | IUTF_Reporting#AddError(str, IUTF_STATUS_ERROR) |
| 0 | 444 | | break |
| 0 | 445 | | case -2: |
| 0 | 446 | | sprintf str, "Stack Overflow in %s \"%s\" (%s)", funcTypeString, funcName, procWin |
| 0 | 447 | | IUTF_Reporting#AddFailedSummaryInfo(str) |
| 0 | 448 | | IUTF_Reporting#AddError(str, IUTF_STATUS_ERROR) |
| 0 | 449 | | break |
| 0 | 450 | | case -3: |
| 0 | 451 | | sprintf str, "Encountered \"Abort\" in %s \"%s\" (%s)", funcTypeString, funcName, procWin |
| 0 | 452 | | IUTF_Reporting#AddFailedSummaryInfo(str) |
| 0 | 453 | | IUTF_Reporting#AddError(str, IUTF_STATUS_ERROR) |
| 0 | 454 | | break |
| 0 | 455 | | default: |
| 0 | 456 | | break |
| 0 | 457 | | endswitch |
| 0 | 458 | | message += str |
| 0 | 459 | | if(abortCode > 0) |
| 0 | 460 | | sprintf str, "Encountered \"AbortOnValue\" Code %d in %s \"%s\" (%s)", abortCode, funcTypeString, funcName, procWi |
| 0 | 461 | | IUTF_Reporting#AddFailedSummaryInfo(str) |
| 0 | 462 | | IUTF_Reporting#AddError(str, IUTF_STATUS_ERROR) |
| 0 | 463 | | message += str |
| 0 | 464 | | endif |
| 0 | 465 | | endif |
| | 466 | |
|
| 0 | 467 | | IUTF_Reporting#ReportError(message, incrGlobalErrorCounter = 0) |
| 0 | 468 | | WAVE/T wvInfoMsg = IUTF_Reporting#GetInfoMsg() |
| 0 | 469 | | length = IUTF_Utils_Vector#GetLength(wvInfoMsg) |
| 0 | 470 | | for(i = 0; i < length; i += 1) |
| 0 | 471 | | IUTF_Reporting#ReportError(wvInfoMsg[i], incrGlobalErrorCounter = 0) |
| 0 | 472 | | endfor |
| | 473 | |
|
| 0 | 474 | | CheckAbortCondition(abortCode) |
| 0 | 475 | | End |
| | 476 | |
|
| | 477 | | /// Check if the User manually pressed Abort and set Abort flag |
| | 478 | | /// |
| | 479 | | /// @param abortCode V_AbortCode output from try...catch |
| 0 | 480 | | static Function CheckAbortCondition(abortCode) |
| | 481 | | variable abortCode |
| | 482 | |
|
| 0 | 483 | | if(abortCode == -1) |
| 0 | 484 | | setAbortFlag() |
| 0 | 485 | | endif |
| 0 | 486 | | End |
| | 487 | |
|
| | 488 | | /// Returns List of Test Functions in Procedure Window procWin |
| 27 | 489 | | static Function/S GetTestCaseList(procWin) |
| | 490 | | string procWin |
| | 491 | |
|
| 27 | 492 | | string testCaseList = FunctionList("!*_IGNORE", ";", "KIND:18,NPARAMS:0,VALTYPE:1,WIN:" + procWin) |
| 27 | 493 | | string testCaseMDList = FunctionList("!*_IGNORE", ";", "KIND:18,NPARAMS:1,VALTYPE:1,WIN:" + procWin) |
| | 494 | |
|
| 27 | 495 | | testCaseList = GrepList(testCaseList, PROCNAME_NOT_REENTRY) |
| 27 | 496 | | testCaseMDList = GrepList(testCaseMDList, PROCNAME_NOT_REENTRY) |
| | 497 | |
|
| 27 | 498 | | if(!IUTF_Utils#IsEmpty(testCaseMDList)) |
| 0 | 499 | | testCaseList = testCaseList + testCaseMDList |
| 27 | 500 | | endif |
| | 501 | |
|
| 27 | 502 | | return SortTestCaseList(procWin, testCaseList) |
| 27 | 503 | | End |
| | 504 | |
|
| | 505 | | /// Returns the list of testcases sorted by line number |
| 27 | 506 | | static Function/S SortTestCaseList(procWin, testCaseList) |
| | 507 | | string procWin, testCaseList |
| | 508 | |
|
| 27 | 509 | | if(IUTF_Utils#IsEmpty(testCaseList)) |
| 0 | 510 | | return "" |
| 27 | 511 | | endif |
| | 512 | |
|
| 27 | 513 | | WAVE/T testCaseWave = ListToTextWave(testCaseList, ";") |
| | 514 | |
|
| 27 | 515 | | Make/FREE/N=(ItemsInList(testCaseList)) lineNumberWave |
| 27 | 516 | | lineNumberWave[] = str2num(StringByKey("PROCLINE", FunctionInfo(testCaseWave[p], procWin))) |
| | 517 | |
|
| 27 | 518 | | Sort lineNumberWave, testCaseWave |
| | 519 | |
|
| 27 | 520 | | return IUTF_Utils#TextWaveToList(testCaseWave, ";") |
| 27 | 521 | | End |
| | 522 | |
|
| | 523 | | /// @brief Checks if the procedure window has the global tag to ban shuffling test cases. This will |
| | 524 | | /// keep the test cases in their original order for this single procedure file only. |
| | 525 | | /// |
| | 526 | | /// @param procWin The name of the procedure window. This can include independent module names. |
| | 527 | | /// |
| | 528 | | /// @returns 1 if procedure file has the ban tag, 0 if not |
| 0 | 529 | | static Function HasProcedureShuffleBan(procWin) |
| | 530 | | string procWin |
| | 531 | |
|
| 0 | 532 | | variable i, numLines |
| 0 | 533 | | string fullText, line, tagValue |
| | 534 | |
|
| 0 | 535 | | fullText = ProcedureText("", 0, procWin + " [" + GetIndependentModuleName() + "]") |
| 0 | 536 | | WAVE/T wv = ListToTextWave(fullText, "\r") |
| 0 | 537 | | numLines = DimSize(wv, UTF_ROW) |
| | 538 | |
|
| 0 | 539 | | numLines = min(numLines, MAX_PROCTAGS_SCAN_LINES) |
| 0 | 540 | | for(i = 0; i < numLines; i += 1) |
| 0 | 541 | | line = wv[i] |
| 0 | 542 | | if(IUTF_Utils#IsEmpty(line)) |
| 0 | 543 | | continue |
| 0 | 544 | | endif |
| | 545 | |
|
| 0 | 546 | | if(IUTF_FunctionTags#IsTagMatch(IUTF_NO_SHUFFLE_TEST_CASE, line, tagValue)) |
| 0 | 547 | | return 1 |
| 0 | 548 | | endif |
| 0 | 549 | | endfor |
| | 550 | |
|
| 0 | 551 | | return 0 |
| 0 | 552 | | End |
| | 553 | |
|
| | 554 | | /// @brief get test cases matching a certain pattern and fill TesRunSetup wave |
| | 555 | | /// |
| | 556 | | /// This function searches for test cases in a given list of test suites. The |
| | 557 | | /// search can be performed either using a regular expression or on a defined |
| | 558 | | /// list of test cases. All Matches are checked. |
| | 559 | | /// The function returns an error |
| | 560 | | /// * If a given test case is not found |
| | 561 | | /// * If no test case was found |
| | 562 | | /// * if fullFunctionName returned an error |
| | 563 | | /// |
| | 564 | | /// @param[in] procWinList List of test suites, separated by ";" |
| | 565 | | /// @param[in] matchStr * List of test cases, separated by ";" (enableRegExp = 0) |
| | 566 | | /// * *one* regular expression without ";" (enableRegExp = 1) |
| | 567 | | /// @param[in] enableRegExp (0,1) defining the type of search for matchStr |
| | 568 | | /// @param[out] errMsg error message in case of error |
| | 569 | | /// @param[in] enableTAP Specify if TAP output is enabled or not |
| | 570 | | /// @param[in] debugMode The current debug mode |
| | 571 | | /// @param[in] shuffleMode The current test shuffle mode |
| | 572 | | /// |
| | 573 | | /// @returns Numeric Error Code |
| 6 | 574 | | static Function CreateTestRunSetup(procWinList, matchStr, enableRegExp, errMsg, enableTAP, debugMode, shuffleMode) |
| | 575 | | string procWinList |
| | 576 | | string matchStr |
| | 577 | | variable enableRegExp |
| | 578 | | string &errMsg |
| | 579 | | variable enableTAP, debugMode, shuffleMode |
| | 580 | |
|
| 6 | 581 | | string procWin |
| 6 | 582 | | string funcName |
| 6 | 583 | | string funcList |
| 6 | 584 | | string fullFuncName, dgenList |
| 6 | 585 | | string testCase, testCaseMatch |
| 6 | 586 | | variable numTC, numpWL, numFL, markSkip |
| 6 | 587 | | variable i, j, tdIndex |
| 6 | 588 | | variable err = TC_MATCH_OK |
| 6 | 589 | | variable hasDGen = 0 |
| | 590 | |
|
| 6 | 591 | | if(enableRegExp && !(strsearch(matchStr, ";", 0) < 0)) |
| 0 | 592 | | errMsg = "semicolon is not allowed in given regex pattern: " + matchStr |
| 0 | 593 | | return TC_REGEX_INVALID |
| 6 | 594 | | endif |
| | 595 | |
|
| 6 | 596 | | if(enableRegExp) |
| 6 | 597 | | sprintf matchStr, "^(?i)%s$", matchStr |
| 6 | 598 | | endif |
| | 599 | |
|
| 6 | 600 | | if(shuffleMode & IUTF_SHUFFLE_TEST_SUITES) |
| 0 | 601 | | procWinList = IUTF_Utils_Strings#ShuffleList(procWinList) |
| 6 | 602 | | endif |
| | 603 | |
|
| 6 | 604 | | WAVE/T testRunData = GetTestRunData() |
| | 605 | |
|
| 6 | 606 | | numTC = ItemsInList(matchStr) |
| 6 | 607 | | numpWL = ItemsInList(procWinList) |
| 6 | 608 | | Make/FREE/N=(numTC) usedTC |
| 6 | 609 | | for(i = 0; i < numpWL; i += 1) |
| 27 | 610 | | procWin = StringFromList(i, procWinList) |
| 27 | 611 | | funcList = getTestCaseList(procWin) |
| 27 | 612 | | testCaseMatch = "" |
| | 613 | |
|
| 27 | 614 | | if(enableRegExp) |
| 27 | 615 | | try |
| 27 | 616 | | ClearRTError() |
| 27 | 617 | | testCaseMatch = GrepList(funcList, matchStr, 0, ";"); AbortOnRTE |
| 27 | 618 | | catch |
| 0 | 619 | | testCaseMatch = "" |
| 0 | 620 | | err = GetRTError(1) |
| 0 | 621 | | switch(err) |
| 0 | 622 | | case 1233: |
| 0 | 623 | | errMsg = "Regular expression error: " + matchStr |
| 0 | 624 | | err = TC_REGEX_INVALID |
| 0 | 625 | | break |
| 0 | 626 | | default: |
| 0 | 627 | | errMsg = GetErrMessage(err) |
| 0 | 628 | | err = GREPLIST_ERROR |
| 0 | 629 | | endswitch |
| 0 | 630 | | sprintf errMsg, "Error executing GrepList: %s", errMsg |
| 0 | 631 | | return err |
| 0 | 632 | | endtry |
| 0 | 633 | | else |
| 0 | 634 | | for(j = 0; j < numTC; j += 1) |
| 0 | 635 | | testCase = StringFromList(j, matchStr) |
| 0 | 636 | | if(WhichListItem(testCase, funcList, ";", 0, 0) < 0) |
| 0 | 637 | | continue |
| 0 | 638 | | endif |
| 0 | 639 | | testCaseMatch = AddListItem(testCase, testCaseMatch, ";", Inf) |
| 0 | 640 | | usedTC[j] = 1 |
| 0 | 641 | | endfor |
| 27 | 642 | | endif |
| | 643 | |
|
| 27 | 644 | | if((shuffleMode & IUTF_SHUFFLE_TEST_CASES) && !HasProcedureShuffleBan(procWin)) |
| 0 | 645 | | testCaseMatch = IUTF_Utils_Strings#ShuffleList(testCaseMatch) |
| 27 | 646 | | endif |
| | 647 | |
|
| 27 | 648 | | numFL = ItemsInList(testCaseMatch) |
| 27 | 649 | | for(j = 0; j < numFL; j += 1) |
| 79 | 650 | | funcName = StringFromList(j, testCaseMatch) |
| 79 | 651 | | fullFuncName = getFullFunctionName(err, funcName, procWin) |
| 79 | 652 | | if(err) |
| 0 | 653 | | sprintf errMsg, "Could not get full function name: %s", fullFuncName |
| 0 | 654 | | return err |
| 79 | 655 | | endif |
| | 656 | |
|
| 79 | 657 | | IUTF_FunctionTags#AddFunctionTagWave(fullFuncName) |
| | 658 | |
|
| 79 | 659 | | if(IUTF_Test_MD#GetDataGeneratorListTC(procWin, fullFuncName, dgenList)) |
| 0 | 660 | | continue |
| 79 | 661 | | endif |
| | 662 | |
|
| 79 | 663 | | IUTF_Utils_Vector#EnsureCapacity(testRunData, tdIndex) |
| 79 | 664 | | testRunData[tdIndex][%PROCWIN] = procWin |
| 79 | 665 | | testRunData[tdIndex][%TESTCASE] = fullFuncName |
| 79 | 666 | | testRunData[tdIndex][%FULLFUNCNAME] = fullFuncName |
| 79 | 667 | | testRunData[tdIndex][%DGENLIST] = dgenList |
| 79 | 668 | | markSkip = IUTF_FunctionTags#HasFunctionTag(fullFuncName, UTF_FTAG_SKIP) |
| 79 | 669 | | testRunData[tdIndex][%SKIP] = SelectString(enableTAP, num2istr(markSkip), num2istr(IUTF_TAP#TAP_IsFunction |
| 79 | 670 | | testRunData[tdIndex][%EXPECTFAIL] = num2istr(IUTF_FunctionTags#HasFunctionTag(fullFuncName, UTF_FTAG_EXPECTED_FA |
| 79 | 671 | | tdIndex += 1 |
| | 672 | |
|
| 79 | 673 | | hasDGen = hasDGen | !IUTF_Utils#IsEmpty(dgenList) |
| 79 | 674 | | endfor |
| 27 | 675 | | endfor |
| | 676 | |
|
| 6 | 677 | | if(!enableRegExp) |
| 0 | 678 | | for(i = 0; i < numTC; i += 1) |
| 0 | 679 | | if(!usedTC[i]) |
| 0 | 680 | | testCase = StringFromList(i, matchStr) |
| 0 | 681 | | sprintf errMsg, "Could not find test case \"%s\" in procedure list \"%s\".", testCase, procWinList |
| 0 | 682 | | return TC_NOT_FOUND |
| 0 | 683 | | endif |
| 0 | 684 | | endfor |
| 6 | 685 | | endif |
| | 686 | |
|
| 6 | 687 | | Redimension/N=(tdIndex, -1, -1, -1) testRunData |
| | 688 | |
|
| 6 | 689 | | if(hasDGen) |
| 0 | 690 | | IUTF_Test_MD_Gen#ExecuteAllDataGenerators(debugMode) |
| 6 | 691 | | endif |
| | 692 | |
|
| 6 | 693 | | for(i = 0; i < tdIndex; i += 1) |
| 79 | 694 | | dgenList = testRunData[i][%DGENLIST] |
| | 695 | |
|
| 79 | 696 | | if(IUTF_Utils#IsEmpty(dgenList)) |
| 79 | 697 | | continue |
| 0 | 698 | | endif |
| | 699 | |
|
| 0 | 700 | | procWin = testRunData[i][%PROCWIN] |
| 0 | 701 | | fullFuncName = testRunData[i][%FULLFUNCNAME] |
| | 702 | |
|
| 0 | 703 | | if(IUTF_Test_MD#CheckFunctionSignatureTC(procWin, fullFuncName, markSkip)) |
| 0 | 704 | | // There is something wrong which is already reported. The old approach was to remove |
| 0 | 705 | | // this test case from the list which isn't possible anymore. So let's skip it safely. |
| 0 | 706 | | testRunData[i][%SKIP] = "1" |
| 0 | 707 | | continue |
| 0 | 708 | | endif |
| | 709 | |
|
| 0 | 710 | | if(markSkip) |
| 0 | 711 | | testRunData[i][%SKIP] = "1" |
| 0 | 712 | | endif |
| 0 | 713 | | endfor |
| | 714 | |
|
| 6 | 715 | | if(!tdIndex) |
| 0 | 716 | | errMsg = "No test cases found." |
| 0 | 717 | | return TC_LIST_EMPTY |
| 6 | 718 | | endif |
| | 719 | |
|
| 6 | 720 | | return TC_MATCH_OK |
| 6 | 721 | | End |
| | 722 | |
|
| | 723 | | /// Function determines the total number of test cases |
| | 724 | | /// Normal test cases are counted with 1 |
| | 725 | | /// MD test cases are counted by multiplying all data generator wave sizes |
| | 726 | | /// When the optional string procWin is given then the number of test cases for that |
| | 727 | | /// procedure window (test suite) is returned. |
| | 728 | | /// Returns the total number of all test cases to be called |
| 6 | 729 | | static Function GetTestCaseCount([procWin]) |
| | 730 | | string procWin |
| | 731 | |
|
| 6 | 732 | | variable i, j, size, dgenSize, index |
| 6 | 733 | | variable tcCount, dgenCount |
| 6 | 734 | | string dgenList, dgen |
| | 735 | |
|
| 6 | 736 | | WAVE/WAVE dgenWaves = IUTF_Test_MD_Gen#GetDataGeneratorWaves() |
| 6 | 737 | | WAVE/T testRunData = GetTestRunData() |
| 6 | 738 | | size = DimSize(testRunData, UTF_ROW) |
| 6 | 739 | | for(i = 0; i < size; i += 1) |
| 79 | 740 | | if(!ParamIsDefault(procWin) && CmpStr(procWin, testRunData[i][%PROCWIN])) |
| 0 | 741 | | continue |
| 79 | 742 | | endif |
| | 743 | |
|
| 79 | 744 | | dgenCount = 1 |
| 79 | 745 | | dgenList = testRunData[i][%DGENLIST] |
| 79 | 746 | | dgenSize = ItemsInList(dgenList) |
| 79 | 747 | | for(j = 0; j < dgenSize; j += 1) |
| 0 | 748 | | dgen = StringFromList(j, dgenList) |
| 0 | 749 | | index = IUTF_Test_MD_Gen#GetDataGeneratorRef(dgen) |
| 0 | 750 | | WAVE wv = dgenWaves[index] |
| 0 | 751 | | dgenCount *= DimSize(wv, UTF_ROW) |
| 0 | 752 | | endfor |
| 79 | 753 | | tcCount += dgenCount |
| 79 | 754 | | endfor |
| | 755 | |
|
| 6 | 756 | | return tcCount |
| 6 | 757 | | End |
| | 758 | |
|
| | 759 | | // Return the status of an `SetIgorOption` setting |
| 1 | 760 | | static Function QueryIgorOption(option) |
| | 761 | | string option |
| | 762 | |
|
| 1 | 763 | | variable state |
| | 764 | |
|
| 1 | 765 | | Execute/Q "SetIgorOption " + option + "=?" |
| 1 | 766 | | NVAR V_Flag |
| | 767 | |
|
| 1 | 768 | | state = V_Flag |
| 1 | 769 | | KillVariables/Z V_Flag |
| | 770 | |
|
| 1 | 771 | | return state |
| 1 | 772 | | End |
| | 773 | |
|
| | 774 | | /// Add an IM specification to every procedure name if running in an IM |
| 6 | 775 | | static Function/S AdaptProcWinList(procWinList, enableRegExp) |
| | 776 | | string procWinList |
| | 777 | | variable enableRegExp |
| | 778 | |
|
| 6 | 779 | | variable i, numEntries |
| 6 | 780 | | string str |
| 6 | 781 | | string list = "" |
| | 782 | |
|
| 6 | 783 | | if(IsProcGlobal()) |
| 5 | 784 | | return procWinList |
| 1 | 785 | | endif |
| | 786 | |
|
| 1 | 787 | | numEntries = ItemsInList(procWinList) |
| 1 | 788 | | for(i = 0; i < numEntries; i += 1) |
| 1 | 789 | | if(enableRegExp) |
| 1 | 790 | | str = StringFromList(i, procWinList) + "[[:space:]]\[" + GetIndependentModuleName() + "\]" |
| 0 | 791 | | else |
| 0 | 792 | | str = StringFromList(i, procWinList) + " [" + GetIndependentModuleName() + "]" |
| 1 | 793 | | endif |
| 1 | 794 | | list = AddListItem(str, list, ";", Inf) |
| 1 | 795 | | endfor |
| | 796 | |
|
| 1 | 797 | | return list |
| 6 | 798 | | End |
| | 799 | |
|
| | 800 | | /// get all available procedures as a ";" separated list |
| 6 | 801 | | static Function/S GetProcedureList() |
| | 802 | |
|
| 6 | 803 | | string msg |
| | 804 | |
|
| 6 | 805 | | if(!IsProcGlobal()) |
| 1 | 806 | | if(!QueryIgorOption("IndependentModuleDev")) |
| 0 | 807 | | sprintf msg, "Error: The universal testing framework lives in the IM \"%s\" but \"SetIgorOption IndependentModuleD |
| 0 | 808 | | IUTF_Reporting#ReportError(msg) |
| 0 | 809 | | return "" |
| 1 | 810 | | endif |
| 1 | 811 | | return WinList("* [" + GetIndependentModuleName() + "]", ";", "WIN:128,INDEPENDENTMODULE:1") |
| 5 | 812 | | endif |
| 5 | 813 | | return WinList("*", ";", "WIN:128") |
| 6 | 814 | | End |
| | 815 | |
|
| | 816 | | /// verify that the selected procedures are available. |
| | 817 | | /// |
| | 818 | | /// @param procWinList a list of procedures to check |
| | 819 | | /// @param enableRegExp treat list items as regular expressions |
| | 820 | | /// @returns parsed list of procedures |
| 6 | 821 | | static Function/S FindProcedures(procWinListIn, enableRegExp) |
| | 822 | | string procWinListIn |
| | 823 | | variable enableRegExp |
| | 824 | |
|
| 6 | 825 | | string procWin |
| 6 | 826 | | string procWinMatch |
| 6 | 827 | | string allProcWindows |
| 6 | 828 | | string errMsg, msg |
| 6 | 829 | | variable numItemsPW |
| 6 | 830 | | variable numMatches |
| 6 | 831 | | variable err |
| 6 | 832 | | variable i, j |
| 6 | 833 | | string procWinListOut = "" |
| | 834 | |
|
| 6 | 835 | | numItemsPW = ItemsInList(procWinListIn) |
| 6 | 836 | | if(numItemsPW <= 0) |
| 0 | 837 | | return "" |
| 6 | 838 | | endif |
| | 839 | |
|
| 6 | 840 | | allProcWindows = GetProcedureList() |
| 6 | 841 | | numItemsPW = ItemsInList(procWinListIn) |
| 6 | 842 | | for(i = 0; i < numItemsPW; i += 1) |
| 6 | 843 | | procWin = StringFromList(i, procWinListIn) |
| 6 | 844 | | if(enableRegExp) |
| 6 | 845 | | procWin = "^(?i)" + procWin + "$" |
| 6 | 846 | | try |
| 6 | 847 | | ClearRTError() |
| 6 | 848 | | procWinMatch = GrepList(allProcWindows, procWin, 0, ";"); AbortOnRTE |
| 6 | 849 | | catch |
| 0 | 850 | | procWinMatch = "" |
| 0 | 851 | | err = GetRTError(1) |
| 0 | 852 | | switch(err) |
| 0 | 853 | | case 1233: |
| 0 | 854 | | errMsg = "Regular expression error" |
| 0 | 855 | | break |
| 0 | 856 | | default: |
| 0 | 857 | | errMsg = GetErrMessage(err) |
| 0 | 858 | | endswitch |
| 0 | 859 | | sprintf msg, "Error executing GrepList: %s", errMsg |
| 0 | 860 | | IUTF_Reporting#ReportError(msg) |
| 0 | 861 | | endtry |
| 0 | 862 | | else |
| 0 | 863 | | procWinMatch = StringFromList(WhichListItem(procWin, allProcWindows, ";", 0, 0), allProcWindows) |
| 6 | 864 | | endif |
| | 865 | |
|
| 6 | 866 | | numMatches = ItemsInList(procWinMatch) |
| 6 | 867 | | if(numMatches <= 0) |
| 0 | 868 | | sprintf msg, "Error: A procedure window matching the pattern \"%s\" could not be found.", procWin |
| 0 | 869 | | IUTF_Reporting#ReportError(msg) |
| 0 | 870 | | return "" |
| 6 | 871 | | endif |
| | 872 | |
|
| 6 | 873 | | for(j = 0; j < numMatches; j += 1) |
| 27 | 874 | | procWin = StringFromList(j, procWinMatch) |
| 27 | 875 | | if(FindListItem(procWin, procWinListOut, ";", 0, 0) == -1) |
| 27 | 876 | | procWinListOut = AddListItem(procWin, procWinListOut, ";", Inf) |
| 0 | 877 | | else |
| 0 | 878 | | sprintf msg, "Error: The procedure window named \"%s\" is a duplicate entry in the input list of procedures.", p |
| 0 | 879 | | IUTF_Reporting#ReportError(msg) |
| 0 | 880 | | return "" |
| 27 | 881 | | endif |
| 27 | 882 | | endfor |
| 6 | 883 | | endfor |
| | 884 | |
|
| 6 | 885 | | return procWinListOut |
| 6 | 886 | | End |
| | 887 | |
|
| | 888 | | /// @copydoc BACKGROUND_MONITOR_DOCU |
| | 889 | | /// @deprecated use IUTFBackgroundMonitor instead |
| 0 | 890 | | Function UTFBackgroundMonitor(s) |
| | 891 | | STRUCT WMBackgroundStruct &s |
| | 892 | |
|
| 0 | 893 | | IUTFBackgroundMonitor(s) |
| 0 | 894 | | End |
| | 895 | |
|
| | 896 | | /// @class BACKGROUND_MONITOR_DOCU |
| | 897 | | /// @brief Background monitor of the Universal Testing Framework |
| 0 | 898 | | Function IUTFBackgroundMonitor(s) |
| | 899 | | STRUCT WMBackgroundStruct &s |
| | 900 | |
|
| 0 | 901 | | variable i, numTasks, result, stopState |
| 0 | 902 | | string task |
| | 903 | |
|
| 0 | 904 | | DFREF df = GetPackageFolder() |
| 0 | 905 | | SVAR/Z tList = df:BCKG_TaskList |
| 0 | 906 | | SVAR/Z rFunc = df:BCKG_ReentryFunc |
| 0 | 907 | | NVAR/Z timeout = df:BCKG_EndTime |
| 0 | 908 | | NVAR/Z mode = df:BCKG_Mode |
| 0 | 909 | | NVAR/Z failOnTimeout = df:BCKG_failOnTimeout |
| | 910 | |
|
| 0 | 911 | | if(!SVAR_Exists(tList) || !SVAR_Exists(rFunc) || !NVAR_Exists(mode) || !NVAR_Exists(timeout) || !NVAR_Exists(failOnTim |
| 0 | 912 | | IUTF_Reporting#ReportErrorAndAbort("IUTF BackgroundMonitor can not find monitoring data in package DF, aborting moni |
| 0 | 913 | | ClearReentrytoIUTF() |
| 0 | 914 | | QuitOnAutoRunFull() |
| 0 | 915 | | return 2 |
| 0 | 916 | | endif |
| | 917 | |
|
| 0 | 918 | | if(mode == BACKGROUNDMONMODE_OR) |
| 0 | 919 | | result = 0 |
| 0 | 920 | | elseif(mode == BACKGROUNDMONMODE_AND) |
| 0 | 921 | | result = 1 |
| 0 | 922 | | else |
| 0 | 923 | | IUTF_Reporting#ReportErrorAndAbort("Unknown mode set for background monitor", setFlagOnly = 1) |
| 0 | 924 | | ClearReentrytoIUTF() |
| 0 | 925 | | QuitOnAutoRunFull() |
| 0 | 926 | | return 2 |
| 0 | 927 | | endif |
| | 928 | |
|
| 0 | 929 | | if(timeout && datetime > timeout) |
| 0 | 930 | | IUTF_Reporting#ReportError("IUTF background monitor has reached the timeout for reentry", incrGlobalErrorCounter = f |
| | 931 | |
|
| 0 | 932 | | RunTest(BACKGROUNDINFOSTR) |
| 0 | 933 | | return 0 |
| 0 | 934 | | endif |
| | 935 | |
|
| 0 | 936 | | numTasks = ItemsInList(tList) |
| 0 | 937 | | for(i = 0; i < numTasks; i += 1) |
| 0 | 938 | | task = StringFromList(i, tList) |
| 0 | 939 | | CtrlNamedBackground $task, status |
| 0 | 940 | | stopState = !NumberByKey("RUN", S_Info) |
| 0 | 941 | | if(mode == BACKGROUNDMONMODE_OR) |
| 0 | 942 | | result = result | stopState |
| 0 | 943 | | elseif(mode == BACKGROUNDMONMODE_AND) |
| 0 | 944 | | result = result & stopState |
| 0 | 945 | | endif |
| 0 | 946 | | endfor |
| | 947 | |
|
| 0 | 948 | | if(result) |
| 0 | 949 | | RunTest(BACKGROUNDINFOSTR) |
| 0 | 950 | | endif |
| | 951 | |
|
| 0 | 952 | | return 0 |
| 0 | 953 | | End |
| | 954 | |
|
| | 955 | | /// @brief Clear the glboal reentry flag, removes any saved RunTest state and stops the IUTF monitoring task |
| 15 | 956 | | static Function ClearReentrytoIUTF() |
| | 957 | |
|
| 15 | 958 | | ResetBckgRegistered() |
| 15 | 959 | | KillDataFolder/Z $PKG_FOLDER_SAVE |
| 15 | 960 | | CtrlNamedBackground $BACKGROUNDMONTASK, stop |
| 15 | 961 | | End |
| | 962 | |
|
| | 963 | | /// @brief Saves the variable state of RunTest from a strRunTest structure to a dfr |
| 5 | 964 | | static Function SaveState(dfr, s) |
| | 965 | | DFREF dfr |
| | 966 | | STRUCT strRunTest &s |
| | 967 | |
|
| 5 | 968 | | // save all local vars |
| 5 | 969 | | string/G dfr:SprocWinList = s.procWinList |
| 5 | 970 | | string/G dfr:Sname = s.name |
| 5 | 971 | | string/G dfr:StestCase = s.testCase |
| 5 | 972 | | variable/G dfr:SenableJU = s.enableJU |
| 5 | 973 | | variable/G dfr:SenableTAP = s.enableTAP |
| 5 | 974 | | variable/G dfr:SenableRegExp = s.enableRegExp |
| 5 | 975 | | variable/G dfr:SkeepDataFolder = s.keepDataFolder |
| 5 | 976 | | variable/G dfr:SenableRegExpTC = s.enableRegExpTC |
| 5 | 977 | | variable/G dfr:SenableRegExpTS = s.enableRegExpTS |
| 5 | 978 | | variable/G dfr:SdgenIndex = s.dgenIndex |
| 5 | 979 | | variable/G dfr:SdgenSize = s.dgenSize |
| 5 | 980 | | variable/G dfr:SmdMode = s.mdMode |
| 5 | 981 | | variable/G dfr:StracingEnabled = s.tracingEnabled |
| 5 | 982 | | variable/G dfr:ShtmlCreation = s.htmlCreation |
| 5 | 983 | | variable/G dfr:Sshuffle = s.shuffle |
| 5 | 984 | | variable/G dfr:Scobertura = s.cobertura |
| 5 | 985 | | string/G dfr:ScoberturaSources = s.coberturaSources |
| 5 | 986 | | string/G dfr:ScoberturaOut = s.coberturaOut |
| 5 | 987 | | string/G dfr:StcSuffix = s.tcSuffix |
| 5 | 988 | | variable/G dfr:SretryMode = s.retryMode |
| 5 | 989 | | variable/G dfr:SretryCount = s.retryCount |
| 5 | 990 | | variable/G dfr:SretryIndex = s.retryIndex |
| 5 | 991 | | variable/G dfr:SretryFailedProc = s.retryFailedProc |
| | 992 | |
|
| 5 | 993 | | variable/G dfr:Si = s.i |
| 5 | 994 | | variable/G dfr:Serr = s.err |
| 5 | 995 | | IUTF_Hooks#StoreHooks(dfr, s.hooks, "TH") |
| 5 | 996 | | IUTF_Hooks#StoreHooks(dfr, s.procHooks, "PH") |
| 5 | 997 | | End |
| | 998 | |
|
| | 999 | | /// @brief Restores the variable state of RunTest from dfr to a strRunTest structure |
| 10 | 1000 | | static Function RestoreState(dfr, s) |
| | 1001 | | DFREF dfr |
| | 1002 | | STRUCT strRunTest &s |
| | 1003 | |
|
| 10 | 1004 | | SVAR str = dfr:SprocWinList |
| 10 | 1005 | | s.procWinList = str |
| 10 | 1006 | | SVAR str = dfr:Sname |
| 10 | 1007 | | s.name = str |
| 10 | 1008 | | SVAR str = dfr:StestCase |
| 10 | 1009 | | s.testCase = str |
| 10 | 1010 | | NVAR var = dfr:SenableJU |
| 10 | 1011 | | s.enableJU = var |
| 10 | 1012 | | NVAR var = dfr:SenableTAP |
| 10 | 1013 | | s.enableTAP = var |
| 10 | 1014 | | NVAR var = dfr:SenableRegExp |
| 10 | 1015 | | s.enableRegExp = var |
| 10 | 1016 | | NVAR var = dfr:SkeepDataFolder |
| 10 | 1017 | | s.keepDataFolder = var |
| 10 | 1018 | | NVAR var = dfr:SenableRegExpTC |
| 10 | 1019 | | s.enableRegExpTC = var |
| 10 | 1020 | | NVAR var = dfr:SenableRegExpTS |
| 10 | 1021 | | s.enableRegExpTS = var |
| | 1022 | |
|
| 10 | 1023 | | NVAR var = dfr:SdgenIndex |
| 10 | 1024 | | s.dgenIndex = var |
| 10 | 1025 | | NVAR var = dfr:SdgenSize |
| 10 | 1026 | | s.dgenSize = var |
| 10 | 1027 | | NVAR var = dfr:SmdMode |
| 10 | 1028 | | s.mdMode = var |
| 10 | 1029 | | NVAR var = dfr:StracingEnabled |
| 10 | 1030 | | s.tracingEnabled = var |
| 10 | 1031 | | NVAR var = dfr:ShtmlCreation |
| 10 | 1032 | | s.htmlCreation = var |
| 10 | 1033 | | NVAR var = dfr:Sshuffle |
| 10 | 1034 | | s.shuffle = var |
| 10 | 1035 | | NVAR var = dfr:Scobertura |
| 10 | 1036 | | s.cobertura = var |
| 10 | 1037 | | SVAR str = dfr:ScoberturaSources |
| 10 | 1038 | | s.coberturaSources = str |
| 10 | 1039 | | SVAR str = dfr:ScoberturaOut |
| 10 | 1040 | | s.coberturaOut = str |
| 10 | 1041 | | SVAR str = dfr:StcSuffix |
| 10 | 1042 | | s.tcSuffix = str |
| | 1043 | |
|
| 10 | 1044 | | NVAR var = dfr:SretryMode |
| 10 | 1045 | | s.retryMode = var |
| 10 | 1046 | | NVAR var = dfr:SretryCount |
| 10 | 1047 | | s.retryCount = var |
| 10 | 1048 | | NVAR var = dfr:SretryIndex |
| 10 | 1049 | | s.retryIndex = var |
| 10 | 1050 | | NVAR var = dfr:SretryFailedProc |
| 10 | 1051 | | s.retryFailedProc = var |
| | 1052 | |
|
| 10 | 1053 | | NVAR var = dfr:Si |
| 10 | 1054 | | s.i = var |
| 10 | 1055 | | NVAR var = dfr:Serr |
| 10 | 1056 | | s.err = var |
| | 1057 | |
|
| 10 | 1058 | | IUTF_Hooks#RestoreHooks(dfr, s.hooks, "TH") |
| 10 | 1059 | | IUTF_Hooks#RestoreHooks(dfr, s.procHooks, "PH") |
| 10 | 1060 | | End |
| | 1061 | |
|
| 94 | 1062 | | static Function IsBckgRegistered() |
| 94 | 1063 | | DFREF dfr = GetPackageFolder() |
| 94 | 1064 | | NVAR/Z bckgRegistered = dfr:BCKG_Registered |
| 94 | 1065 | | return NVAR_Exists(bckgRegistered) && bckgRegistered == 1 |
| 94 | 1066 | | End |
| | 1067 | |
|
| 25 | 1068 | | static Function ResetBckgRegistered() |
| 25 | 1069 | | DFREF dfr = GetPackageFolder() |
| 25 | 1070 | | variable/G dfr:BCKG_Registered = 0 |
| 25 | 1071 | | End |
| | 1072 | |
|
| 84 | 1073 | | static Function CallTestCase(s, reentry) |
| | 1074 | | STRUCT strRunTest &s |
| | 1075 | | variable reentry |
| | 1076 | |
|
| 84 | 1077 | | STRUCT IUTF_mData mData |
| | 1078 | |
|
| 84 | 1079 | | variable wType0, wType1, wRefSubType, err, tcIndex, refIndex |
| 84 | 1080 | | string func, msg, dgenFuncName, origTCName, funcInfo |
| | 1081 | |
|
| 84 | 1082 | | WAVE/T testRunData = GetTestRunData() |
| 84 | 1083 | | tcIndex = s.i |
| | 1084 | |
|
| 84 | 1085 | | if(reentry) |
| 5 | 1086 | | DFREF dfr = GetPackageFolder() |
| 5 | 1087 | | NVAR/Z compMode = dfr:COMP_Mode |
| | 1088 | |
|
| 5 | 1089 | | if(NVAR_Exists(compMode)) |
| 5 | 1090 | | if(compMode == 1) |
| 4 | 1091 | | IUTF_Test_Compilation#TestCompilationReentry() |
| 4 | 1092 | | return NaN |
| 1 | 1093 | | else |
| 1 | 1094 | | KillVariables/Z dfr:COMP_Mode |
| 1 | 1095 | | endif |
| 1 | 1096 | | endif |
| | 1097 | |
|
| 1 | 1098 | | SVAR reentryFuncName = dfr:BCKG_ReentryFunc |
| 1 | 1099 | | func = reentryFuncName |
| | 1100 | |
|
| 1 | 1101 | | // Require only optional parameter |
| 1 | 1102 | | funcInfo = FunctionInfo(func) |
| 1 | 1103 | | if(NumberByKey("N_PARAMS", funcInfo) != NumberByKey("N_OPT_PARAMS", funcInfo)) |
| 0 | 1104 | | sprintf msg, "Reentry functions require all its parameter as optional: \"%s\"", func |
| 0 | 1105 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 1 | 1106 | | endif |
| | 1107 | |
|
| 1 | 1108 | | sprintf msg, "Entering reentry \"%s\"", func |
| 1 | 1109 | | IUTF_Reporting#IUTF_PrintStatusMessage(msg) |
| 79 | 1110 | | else |
| 79 | 1111 | | func = testRunData[tcIndex][%FULLFUNCNAME] |
| 80 | 1112 | | endif |
| | 1113 | |
|
| 80 | 1114 | | if(s.mdMode == TC_MODE_MD) |
| | 1115 | |
|
| 0 | 1116 | | WAVE/WAVE dgenWaves = IUTF_Test_MD_Gen#GetDataGeneratorWaves() |
| 0 | 1117 | | dgenFuncName = StringFromList(0, testRunData[tcIndex][%DGENLIST]) |
| 0 | 1118 | | refIndex = IUTF_Test_MD_Gen#GetDataGeneratorRef(dgenFuncName) |
| 0 | 1119 | | WAVE wGenerator = dgenWaves[refIndex] |
| 0 | 1120 | | wType0 = WaveType(wGenerator) |
| 0 | 1121 | | wType1 = WaveType(wGenerator, 1) |
| 0 | 1122 | | if(wType1 == IUTF_WAVETYPE1_NUM) |
| 0 | 1123 | | if(wType0 & IUTF_WAVETYPE0_CMPL) |
| | 1124 | |
|
| 0 | 1125 | | FUNCREF TEST_CASE_PROTO_MD_CMPL fTCMD_CMPL = $func |
| 0 | 1126 | | if(reentry && !IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD_CMPL))) |
| 0 | 1127 | | sprintf msg, "Reentry function %s does not meet required format for Complex argument.", func |
| 0 | 1128 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 0 | 1129 | | endif |
| 0 | 1130 | | fTCMD_CMPL(cmpl = wGenerator[s.dgenIndex]); AbortOnRTE |
| | 1131 | |
|
| 0 | 1132 | | elseif(wType0 & IUTF_WAVETYPE0_INT64) |
| | 1133 | |
|
| 0 | 1134 | | FUNCREF TEST_CASE_PROTO_MD_INT fTCMD_INT = $func |
| 0 | 1135 | | if(reentry && !IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD_INT))) |
| 0 | 1136 | | sprintf msg, "Reentry function %s does not meet required format for INT64 argument.", func |
| 0 | 1137 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 0 | 1138 | | endif |
| 0 | 1139 | | fTCMD_INT(int = wGenerator[s.dgenIndex]); AbortOnRTE |
| | 1140 | |
|
| 0 | 1141 | | else |
| | 1142 | |
|
| 0 | 1143 | | FUNCREF TEST_CASE_PROTO_MD_VAR fTCMD_VAR = $func |
| 0 | 1144 | | if(reentry && !IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD_VAR))) |
| 0 | 1145 | | sprintf msg, "Reentry function %s does not meet required format for numeric argument.", func |
| 0 | 1146 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 0 | 1147 | | endif |
| 0 | 1148 | | fTCMD_VAR(var = wGenerator[s.dgenIndex]); AbortOnRTE |
| | 1149 | |
|
| 0 | 1150 | | endif |
| 0 | 1151 | | elseif(wType1 == IUTF_WAVETYPE1_TEXT) |
| | 1152 | |
|
| 0 | 1153 | | WAVE/T wGeneratorStr = wGenerator |
| 0 | 1154 | | FUNCREF TEST_CASE_PROTO_MD_STR fTCMD_STR = $func |
| 0 | 1155 | | if(reentry && !IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD_STR))) |
| 0 | 1156 | | sprintf msg, "Reentry function %s does not meet required format for string argument.", func |
| 0 | 1157 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 0 | 1158 | | endif |
| 0 | 1159 | | fTCMD_STR(str = wGeneratorStr[s.dgenIndex]); AbortOnRTE |
| | 1160 | |
|
| 0 | 1161 | | elseif(wType1 == IUTF_WAVETYPE1_DFR) |
| | 1162 | |
|
| 0 | 1163 | | WAVE/DF wGeneratorDF = wGenerator |
| 0 | 1164 | | FUNCREF TEST_CASE_PROTO_MD_DFR fTCMD_DFR = $func |
| 0 | 1165 | | if(reentry && !IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD_DFR))) |
| 0 | 1166 | | sprintf msg, "Reentry function %s does not meet required format for data folder reference argument.", func |
| 0 | 1167 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 0 | 1168 | | endif |
| 0 | 1169 | | fTCMD_DFR(dfr = wGeneratorDF[s.dgenIndex]); AbortOnRTE |
| | 1170 | |
|
| 0 | 1171 | | elseif(wType1 == IUTF_WAVETYPE1_WREF) |
| | 1172 | |
|
| 0 | 1173 | | WAVE/WAVE wGeneratorWV = wGenerator |
| 0 | 1174 | | FUNCREF TEST_CASE_PROTO_MD_WV fTCMD_WV = $func |
| 0 | 1175 | | if(IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD_WV))) |
| 0 | 1176 | | fTCMD_WV(wv = wGeneratorWV[s.dgenIndex]); AbortOnRTE |
| 0 | 1177 | | else |
| 0 | 1178 | | wRefSubType = WaveType(wGeneratorWV[s.dgenIndex], 1) |
| 0 | 1179 | | if(wRefSubType == IUTF_WAVETYPE1_TEXT) |
| 0 | 1180 | | FUNCREF TEST_CASE_PROTO_MD_WVTEXT fTCMD_WVTEXT = $func |
| 0 | 1181 | | if(IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD_WVTEXT))) |
| 0 | 1182 | | fTCMD_WVTEXT(wv = wGeneratorWV[s.dgenIndex]); AbortOnRTE |
| 0 | 1183 | | else |
| 0 | 1184 | | err = 1 |
| 0 | 1185 | | endif |
| 0 | 1186 | | elseif(wRefSubType == IUTF_WAVETYPE1_DFR) |
| 0 | 1187 | | FUNCREF TEST_CASE_PROTO_MD_WVDFREF fTCMD_WVDFREF = $func |
| 0 | 1188 | | if(IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD_WVDFREF))) |
| 0 | 1189 | | fTCMD_WVDFREF(wv = wGeneratorWV[s.dgenIndex]); AbortOnRTE |
| 0 | 1190 | | else |
| 0 | 1191 | | err = 1 |
| 0 | 1192 | | endif |
| 0 | 1193 | | elseif(wRefSubType == IUTF_WAVETYPE1_WREF) |
| 0 | 1194 | | FUNCREF TEST_CASE_PROTO_MD_WVWAVEREF fTCMD_WVWAVEREF = $func |
| 0 | 1195 | | if(IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD_WVWAVEREF))) |
| 0 | 1196 | | fTCMD_WVWAVEREF(wv = wGeneratorWV[s.dgenIndex]); AbortOnRTE |
| 0 | 1197 | | else |
| 0 | 1198 | | err = 1 |
| 0 | 1199 | | endif |
| 0 | 1200 | | else |
| 0 | 1201 | | sprintf msg, "Got wave reference wave from Data Generator %s with waves of unsupported type for reentry of tes |
| 0 | 1202 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 0 | 1203 | | endif |
| 0 | 1204 | | if(err) |
| 0 | 1205 | | sprintf msg, "Reentry function %s does not meet required format for wave reference argument from data generato |
| 0 | 1206 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 0 | 1207 | | endif |
| 0 | 1208 | | endif |
| | 1209 | |
|
| 0 | 1210 | | endif |
| 80 | 1211 | | elseif(s.mdMode == TC_MODE_MMD) |
| 0 | 1212 | | origTCName = testRunData[tcIndex][%FULLFUNCNAME] |
| 0 | 1213 | | IUTF_Test_MD_MMD#SetupMMDStruct(mData, origTCName) |
| 0 | 1214 | | FUNCREF TEST_CASE_PROTO_MD fTCMD = $func |
| 0 | 1215 | | if(!IUTF_FuncRefIsAssigned(FuncRefInfo(fTCMD))) |
| 0 | 1216 | | sprintf msg, "Reentry function %s does not meet required format for multi-multi-data test case.", func |
| 0 | 1217 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 0 | 1218 | | else |
| 0 | 1219 | | fTCMD(md = mData); AbortOnRTE |
| 0 | 1220 | | endif |
| 80 | 1221 | | elseif(s.mdMode == TC_MODE_NORMAL) |
| 80 | 1222 | | FUNCREF TEST_CASE_PROTO TestCaseFunc = $func |
| 80 | 1223 | | TestCaseFunc(); AbortOnRTE |
| 0 | 1224 | | else |
| 0 | 1225 | | sprintf msg, "Unknown test case mode for function %s.", func |
| 0 | 1226 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 80 | 1227 | | endif |
| 84 | 1228 | | End |
| | 1229 | |
|
| | 1230 | | /// @brief initialize all strings in strRunTest structure to be non <null> |
| 10 | 1231 | | static Function InitStrRunTest(s) |
| | 1232 | | STRUCT strRunTest &s |
| | 1233 | |
|
| 10 | 1234 | | s.procWinList = "" |
| 10 | 1235 | | s.name = "" |
| 10 | 1236 | | s.testCase = "" |
| | 1237 | |
|
| 10 | 1238 | | s.coberturaSources = "" |
| 10 | 1239 | | s.coberturaOut = "" |
| 10 | 1240 | | s.tcSuffix = "" |
| | 1241 | |
|
| 10 | 1242 | | IUTF_Hooks#InitHooks(s.hooks) |
| 10 | 1243 | | IUTF_Hooks#InitHooks(s.procHooks) |
| 10 | 1244 | | End |
| | 1245 | |
|
| | 1246 | | /// @brief this structure stores all local variables used in RunTest. It is used to store the complete function state. |
| | 1247 | | static Structure strRunTest |
| | 1248 | | string procWinList |
| | 1249 | | string name |
| | 1250 | | string testCase |
| | 1251 | | variable enableJU |
| | 1252 | | variable enableTAP |
| | 1253 | | variable enableRegExp |
| | 1254 | | variable debugMode |
| | 1255 | | variable keepDataFolder |
| | 1256 | | variable enableRegExpTC |
| | 1257 | | variable enableRegExpTS |
| | 1258 | | variable dgenIndex |
| | 1259 | | variable dgenSize |
| | 1260 | | variable mdMode |
| | 1261 | | variable tracingEnabled |
| | 1262 | | variable htmlCreation |
| | 1263 | | variable shuffle |
| | 1264 | | variable cobertura |
| | 1265 | | string coberturaSources |
| | 1266 | | string coberturaOut |
| | 1267 | | string tcSuffix |
| | 1268 | | STRUCT IUTF_TestHooks hooks |
| | 1269 | | STRUCT IUTF_TestHooks procHooks |
| | 1270 | | variable retryMode |
| | 1271 | | variable retryCount |
| | 1272 | | variable retryIndex |
| | 1273 | | variable retryFailedProc |
| | 1274 | | variable i |
| | 1275 | | variable err |
| | 1276 | | EndStructure |
| | 1277 | |
|
| | 1278 | | ///@endcond // HIDDEN_SYMBOL |
| | 1279 | |
|
| | 1280 | | /// @copydoc REGISTER_IUTF_MONITOR_DOCU |
| | 1281 | | /// @deprecated use RegisterIUTFMonitor instead |
| 0 | 1282 | | Function RegisterUTFMonitor(taskList, mode, reentryFunc, [timeout, failOnTimeout]) |
| | 1283 | | string taskList |
| | 1284 | | variable mode |
| | 1285 | | string reentryFunc |
| | 1286 | | variable timeout, failOnTimeout |
| | 1287 | |
|
| 0 | 1288 | | if(ParamIsDefault(timeout)) |
| 0 | 1289 | | if(ParamIsDefault(failOnTimeout)) |
| 0 | 1290 | | RegisterIUTFMonitor(taskList, mode, reentryFunc) |
| 0 | 1291 | | else |
| 0 | 1292 | | RegisterIUTFMonitor(taskList, mode, reentryFunc, failOnTimeout = failOnTimeout) |
| 0 | 1293 | | endif |
| 0 | 1294 | | else |
| 0 | 1295 | | if(ParamIsDefault(failOnTimeout)) |
| 0 | 1296 | | RegisterIUTFMonitor(taskList, mode, reentryFunc, timeout = timeout) |
| 0 | 1297 | | else |
| 0 | 1298 | | RegisterIUTFMonitor(taskList, mode, reentryFunc, timeout = timeout, failOnTimeout = failOnTimeout) |
| 0 | 1299 | | endif |
| 0 | 1300 | | endif |
| 0 | 1301 | | End |
| | 1302 | |
|
| | 1303 | | /// @class REGISTER_IUTF_MONITOR_DOCU |
| | 1304 | | /// @brief Registers a background monitor for a list of other background tasks |
| | 1305 | | /// |
| | 1306 | | /// @verbatim embed:rst:leading-slashes |
| | 1307 | | /// .. code-block:: igor |
| | 1308 | | /// :caption: usage example |
| | 1309 | | /// |
| | 1310 | | /// RegisterIUTFMonitor("TestCaseTask1;TestCaseTask2", BACKGROUNDMONMODE_OR, \ |
| | 1311 | | /// "testcase_REENTRY", timeout = 60) |
| | 1312 | | /// |
| | 1313 | | /// This command will register the IUTF background monitor task to monitor |
| | 1314 | | /// the state of `TestCaseTask1` and `TestCaseTask2`. As mode is set to |
| | 1315 | | /// `BACKGROUNDMONMODE_OR`, when `TestCaseTask1` OR `TestCaseTask2` has |
| | 1316 | | /// finished the function `testcase_REENTRY()` is called to continue the |
| | 1317 | | /// current test case. The reentry function is also called if after 60 seconds |
| | 1318 | | /// both tasks are still running. |
| | 1319 | | /// |
| | 1320 | | /// @endverbatim |
| | 1321 | | /// |
| | 1322 | | /// @param taskList A list of background task names that should be monitored by the universal testing framework |
| | 1323 | | /// @n The list should be given semicolon (";") separated. |
| | 1324 | | /// |
| | 1325 | | /// @param mode Mode sets how multiple tasks are evaluated. If set to |
| | 1326 | | /// `BACKGROUNDMONMODE_AND` all tasks of the list must finish (AND). |
| | 1327 | | /// If set to `BACKGROUNDMONMODE_OR` one task of the list must finish (OR). |
| | 1328 | | /// |
| | 1329 | | /// @param reentryFunc Name of the function that the universal testing framework calls when the monitored background |
| | 1330 | | /// The function name must end with _REENTRY and it must be of the form `$fun_REENTRY()` (same fo |
| | 1331 | | /// The reentry function *continues* the current test case therefore no hooks are called. |
| | 1332 | | /// |
| | 1333 | | /// @param timeout (optional) default 0. Timeout in seconds that the background monitor waits for the test case |
| | 1334 | | /// A timeout of 0 equals no timeout. If the timeout is reached the registered reentry function i |
| | 1335 | | /// @param failOnTimeout (optional) default to false. If the test case should be failed on reaching the timeout. |
| 0 | 1336 | | Function RegisterIUTFMonitor(taskList, mode, reentryFunc, [timeout, failOnTimeout]) |
| | 1337 | | string taskList |
| | 1338 | | variable mode |
| | 1339 | | string reentryFunc |
| | 1340 | | variable timeout, failOnTimeout |
| | 1341 | |
|
| 0 | 1342 | | string procWinList, rFunc |
| 0 | 1343 | | variable tmpVar |
| 0 | 1344 | | DFREF dfr = GetPackageFolder() |
| | 1345 | |
|
| 0 | 1346 | | if(ParamIsDefault(timeout)) |
| 0 | 1347 | | timeout = 0 |
| 0 | 1348 | | endif |
| 0 | 1349 | | timeout = timeout <= 0 ? 0 : datetime + timeout |
| | 1350 | |
|
| 0 | 1351 | | failOnTimeout = ParamIsDefault(failOnTimeout) ? 0 : !!failOnTimeout |
| | 1352 | |
|
| 0 | 1353 | | if(IUTF_Utils#IsEmpty(tasklist)) |
| 0 | 1354 | | IUTF_Reporting#ReportErrorAndAbort("Tasklist is empty.") |
| 0 | 1355 | | endif |
| | 1356 | |
|
| 0 | 1357 | | if(!(mode == BACKGROUNDMONMODE_OR || mode == BACKGROUNDMONMODE_AND)) |
| 0 | 1358 | | IUTF_Reporting#ReportErrorAndAbort("Unknown mode set") |
| 0 | 1359 | | endif |
| | 1360 | |
|
| 0 | 1361 | | if(FindListItem(BACKGROUNDMONTASK, taskList) != -1) |
| 0 | 1362 | | IUTF_Reporting#ReportErrorAndAbort("Igor Universal Testing framework will not monitor its own monitoring task (" + B |
| 0 | 1363 | | endif |
| | 1364 | |
|
| 0 | 1365 | | // check valid reentry function |
| 0 | 1366 | | if(GrepString(reentryFunc, PROCNAME_NOT_REENTRY)) |
| 0 | 1367 | | IUTF_Reporting#ReportErrorAndAbort("Name of Reentry function must end with _REENTRY") |
| 0 | 1368 | | endif |
| 0 | 1369 | | FUNCREF TEST_CASE_PROTO rFuncRef = $reentryFunc |
| 0 | 1370 | | FUNCREF TEST_CASE_PROTO_MD rFuncRefMMD = $reentryFunc |
| 0 | 1371 | | if(!IUTF_FuncRefIsAssigned(FuncRefInfo(rFuncRef)) && !IUTF_FuncRefIsAssigned(FuncRefInfo(rFuncRefMMD)) && !IUTF_Test_M |
| 0 | 1372 | | IUTF_Reporting#ReportErrorAndAbort("Specified reentry procedure has wrong format. The format must be function_REENTR |
| 0 | 1373 | | endif |
| | 1374 | |
|
| 0 | 1375 | | string/G dfr:BCKG_TaskList = taskList |
| 0 | 1376 | | string/G dfr:BCKG_ReentryFunc = reentryFunc |
| 0 | 1377 | | variable/G dfr:BCKG_Mode = mode |
| | 1378 | |
|
| 0 | 1379 | | variable/G dfr:BCKG_EndTime = timeout |
| 0 | 1380 | | variable/G dfr:BCKG_Registered = 1 |
| 0 | 1381 | | variable/G dfr:BCKG_FailOnTimeout = failOnTimeout |
| | 1382 | |
|
| 0 | 1383 | | CtrlNamedBackground $BACKGROUNDMONTASK, proc=IUTFBackgroundMonitor, period=10, start |
| 0 | 1384 | | End |
| | 1385 | |
|
| | 1386 | | /// @brief Unregisters the IUTF background monitor task |
| 0 | 1387 | | Function UnRegisterIUTFMonitor() |
| | 1388 | |
|
| 0 | 1389 | | DFREF dfr = GetPackageFolder() |
| 0 | 1390 | | variable/G dfr:BCKG_Registered = 0 |
| | 1391 | |
|
| 0 | 1392 | | CtrlNamedBackground $BACKGROUNDMONTASK, stop |
| 0 | 1393 | | End |
| | 1394 | |
|
| | 1395 | | // Checks if a test case can be retried with the given conditions. Returns 1 if the test case can be |
| | 1396 | | // retried and 0 if not. |
| 79 | 1397 | | static Function CanRetry(skip, s, fullFuncName, tcResultIndex) |
| | 1398 | | variable skip, tcResultIndex |
| | 1399 | | STRUCT strRunTest &s |
| | 1400 | | string fullFuncName |
| | 1401 | |
|
| 79 | 1402 | | // if the test case is marked as skipped, the maximum retries are reached the test case will |
| 79 | 1403 | | // no longer be retried or if retry is not enabled |
| 79 | 1404 | | if(skip || s.retryIndex >= s.retryCount || !(s.retryMode & IUTF_RETRY_FAILED_UNTIL_PASS)) |
| 79 | 1405 | | return 0 |
| 0 | 1406 | | endif |
| | 1407 | |
|
| 0 | 1408 | | // check if the test run should be aborted and IUTF_RETRY_REQUIRES is not set |
| 0 | 1409 | | if(!(s.retryMode & IUTF_RETRY_REQUIRES) && shouldDoAbort()) |
| 0 | 1410 | | return 0 |
| 0 | 1411 | | endif |
| | 1412 | |
|
| 0 | 1413 | | // check if test case succeeded |
| 0 | 1414 | | WAVE/T wvTestCaseResults = IUTF_Reporting#GetTestCaseWave() |
| 0 | 1415 | | if(!CmpStr(wvTestCaseResults[tcResultIndex][%STATUS], IUTF_STATUS_SUCCESS)) |
| 0 | 1416 | | return 0 |
| 0 | 1417 | | endif |
| | 1418 | |
|
| 0 | 1419 | | // check if function is not allowed to be retried |
| 0 | 1420 | | if(!((s.retryMode & IUTF_RETRY_MARK_ALL_AS_RETRY) || IUTF_FunctionTags#HasFunctionTag(fullFuncName, UTF_FTAG_RETRY_FAI |
| 0 | 1421 | | return 0 |
| 0 | 1422 | | endif |
| | 1423 | |
|
| 0 | 1424 | | // function has to be retried! |
| 0 | 1425 | | return 1 |
| 79 | 1426 | | End |
| | 1427 | |
|
| 0 | 1428 | | static Function CleanupRetry(s, tcResultIndex) |
| | 1429 | | STRUCT strRunTest &s |
| | 1430 | | variable tcResultIndex |
| | 1431 | |
|
| 0 | 1432 | | // increment retry counter |
| 0 | 1433 | | s.retryIndex += 1 |
| 0 | 1434 | | // update test case status |
| 0 | 1435 | | WAVE/T wvTestCaseResults = IUTF_Reporting#GetTestCaseWave() |
| 0 | 1436 | | wvTestCaseResults[tcResultIndex][%STATUS] = IUTF_STATUS_RETRY |
| 0 | 1437 | | // remove errors from test suite |
| 0 | 1438 | | WAVE/T wvTestSuite = IUTF_Reporting#GetTestSuiteWave() |
| 0 | 1439 | | wvTestSuite[%CURRENT][%NUM_ERROR] = num2istr(str2num(wvTestSuite[%CURRENT][%NUM_ERROR]) - 1) |
| 0 | 1440 | | wvTestSuite[%CURRENT][%NUM_ASSERT_ERROR] = num2istr(str2num(wvTestSuite[%CURRENT][%NUM_ASSERT_ERROR]) - str2num(wvTest |
| 0 | 1441 | | // cleanup test summary |
| 0 | 1442 | | WAVE/T wvFailedProc = IUTF_Reporting#GetFailedProcWave() |
| 0 | 1443 | | IUTF_Utils_Vector#SetLength(wvFailedProc, s.retryFailedProc) |
| 0 | 1444 | | IUTF_Utils_Waves#MoveDimLabel(wvFailedProc, UTF_ROW, "CURRENT", s.retryFailedProc - 1) |
| 0 | 1445 | | // cleanup abort flag to allow failed REQUIRE |
| 0 | 1446 | | InitAbortFlag() |
| 0 | 1447 | | End |
| | 1448 | |
|
| 5 | 1449 | | static Function ClearTestSetupWaves() |
| | 1450 | |
|
| 5 | 1451 | | WAVE/T testRunData = GetTestRunData() |
| 5 | 1452 | | WAVE/WAVE dgenWaves = IUTF_Test_MD_Gen#GetDataGeneratorWaves() |
| 5 | 1453 | | WAVE/T dgenRefs = IUTF_Test_MD_Gen#GetDataGeneratorRefs() |
| 5 | 1454 | | WAVE/WAVE ftagWaves = IUTF_FunctionTags#GetFunctionTagWaves() |
| 5 | 1455 | | WAVE/WAVE ftagRefs = IUTF_FunctionTags#GetFunctionTagRefs() |
| 5 | 1456 | | WAVE/WAVE mdState = IUTF_Test_MD_MMD#GetMMDataState() |
| 5 | 1457 | | WAVE/T mdStateRefs = IUTF_Test_MD_MMD#GetMMDataStateRefs() |
| | 1458 | |
|
| 5 | 1459 | | KillWaves testRunData, dgenWaves, dgenRefs, ftagWaves, ftagRefs, mdState, mdStateRefs |
| 5 | 1460 | | End |
| | 1461 | |
|
| | 1462 | | /// @brief Detects if deprecated files are included and prompt a warning. |
| 5 | 1463 | | static Function DetectDeprecation() |
| 5 | 1464 | | string text = ProcedureText("", 0, "unit-testing.ipf") |
| 5 | 1465 | | if(IUTF_Utils#IsEmpty(text)) |
| 5 | 1466 | | return NaN |
| 0 | 1467 | | endif |
| | 1468 | |
|
| 0 | 1469 | | IUTF_Reporting#IUTF_PrintStatusMessage("WARNING: You are using a deprecated method to include the Igor Pro Universal T |
| 0 | 1470 | | IUTF_Reporting#IUTF_PrintStatusMessage("WARNING: Search in your code for all") |
| 0 | 1471 | | IUTF_Reporting#IUTF_PrintStatusMessage("WARNING: #include \"unit-testing\"") |
| 0 | 1472 | | IUTF_Reporting#IUTF_PrintStatusMessage("WARNING: and replace it with") |
| 0 | 1473 | | IUTF_Reporting#IUTF_PrintStatusMessage("WARNING: #include \"igortest\"") |
| 0 | 1474 | | IUTF_Reporting#IUTF_PrintStatusMessage("WARNING: In a future release will this warning and the deprecated file removed |
| 0 | 1475 | | IUTF_Reporting#IUTF_PrintStatusMessage("", allowEmptyLine = 1) |
| 5 | 1476 | | End |
| | 1477 | |
|
| | 1478 | | /// @brief Main function to execute test suites with the universal testing framework. |
| | 1479 | | /// |
| | 1480 | | /// You can abort the test run using Command-dot on Macintosh, Ctrl+Break on Windows or Shift+Escape |
| | 1481 | | /// on all platforms. |
| | 1482 | | /// |
| | 1483 | | /// @verbatim embed:rst:leading-slashes |
| | 1484 | | /// .. code-block:: igor |
| | 1485 | | /// :caption: usage example |
| | 1486 | | /// |
| | 1487 | | /// RunTest("proc0;proc1", name="myTest") |
| | 1488 | | /// |
| | 1489 | | /// This command will run the test suites `proc0` and `proc1` in a test named `myTest`. |
| | 1490 | | /// @endverbatim |
| | 1491 | | /// |
| | 1492 | | /// @param procWinList A list of procedure files that should be treated as test suites. |
| | 1493 | | /// @n The list should be given semicolon (";") separated. |
| | 1494 | | /// @n The procedure name must not include Independent Module specifications. |
| | 1495 | | /// @n This parameter can be given as a regular expression with enableRegExp set to 1. |
| | 1496 | | /// |
| | 1497 | | /// @param name (optional) default "Unnamed" @n |
| | 1498 | | /// descriptive name for the executed test suites. This can be |
| | 1499 | | /// used to group multiple test suites into a single test run. |
| | 1500 | | /// |
| | 1501 | | /// @param testCase (optional) default ".*" (all test cases in the list of test suites) @n |
| | 1502 | | /// function names, resembling test cases, which should be |
| | 1503 | | /// executed in the given list of test suites (procWinList). |
| | 1504 | | /// @n The list should be given semicolon (";") separated. |
| | 1505 | | /// @n This parameter can be treated as a regular expression with enableRegExp set to 1. |
| | 1506 | | /// |
| | 1507 | | /// @param enableJU (optional) default disabled, enabled when set to 1: @n |
| | 1508 | | /// A JUNIT compatible XML file is written at the end of the Test Run. |
| | 1509 | | /// It allows the combination of this framework with continuous integration |
| | 1510 | | /// servers like Atlassian Bamboo/GitLab/etc. |
| | 1511 | | /// The experiment is required to be saved somewhere on the disk. (it is okay to have unsaved ch |
| | 1512 | | /// |
| | 1513 | | /// @param enableTAP (optional) default disabled, enabled when set to 1: @n |
| | 1514 | | /// A TAP compatible file is written at the end of the test run. |
| | 1515 | | /// @verbatim embed:rst:leading-slashes |
| | 1516 | | /// `Test Anything Protocol (TAP) <https://testanything.org>`__ |
| | 1517 | | /// `standard 13 <https://testanything.org/tap-version-13-specification.html>`__ |
| | 1518 | | /// @endverbatim |
| | 1519 | | /// The experiment is required to be saved somewhere on the disk. (it is okay to have unsaved ch |
| | 1520 | | /// |
| | 1521 | | /// @param enableRegExp (optional) default disabled, enabled when set to 1: @n |
| | 1522 | | /// The input for test suites (procWinList) and test cases (testCase) is |
| | 1523 | | /// treated as a regular expression. |
| | 1524 | | /// @verbatim embed:rst:leading-slashes |
| | 1525 | | /// .. code-block:: igor |
| | 1526 | | /// :caption: Example |
| | 1527 | | /// |
| | 1528 | | /// RunTest("example[1-3]-plain\\.ipf", enableRegExp=1) |
| | 1529 | | /// |
| | 1530 | | /// This command will run all test cases in the following test suites: |
| | 1531 | | /// |
| | 1532 | | /// * :ref:`example1-plain.ipf<example1>` |
| | 1533 | | /// * :ref:`example2-plain.ipf<example2>` |
| | 1534 | | /// * :ref:`example3-plain.ipf<example3>` |
| | 1535 | | /// @endverbatim |
| | 1536 | | /// |
| | 1537 | | /// @param allowDebug (optional) default disabled, enabled when set to 1: @n |
| | 1538 | | /// The Igor debugger will be left in its current state when running the |
| | 1539 | | /// tests. Is ignored when debugMode is also enabled. |
| | 1540 | | /// |
| | 1541 | | /// @param debugMode (optional) default disabled, enabled when set to 1-15: @n |
| | 1542 | | /// The Igor debugger will be turned on in the state: @n |
| | 1543 | | /// 1st bit = 1 (IUTF_DEBUG_ENABLE): Enable Debugger (only breakpoints) @n |
| | 1544 | | /// 2nd bit = 1 (IUTF_DEBUG_ON_ERROR): Debug on Error @n |
| | 1545 | | /// 3rd bit = 1 (IUTF_DEBUG_NVAR_SVAR_WAVE): Check NVAR SVAR WAVE @n |
| | 1546 | | /// 4th bit = 1 (IUTF_DEBUG_FAILED_ASSERTION): Debug on failed assertion |
| | 1547 | | /// @verbatim embed:rst:leading-slashes |
| | 1548 | | /// .. code-block:: igor |
| | 1549 | | /// :caption: Example |
| | 1550 | | /// |
| | 1551 | | /// RunTest(..., debugMode = IUTF_DEBUG_ON_ERROR | IUTF_DEBUG_FAILED_ASSERTION) |
| | 1552 | | /// |
| | 1553 | | /// This will enable the debugger with Debug On Error and debugging on failed assertion. |
| | 1554 | | /// @endverbatim |
| | 1555 | | /// |
| | 1556 | | /// @param keepDataFolder (optional) default disabled, enabled when set to 1: @n |
| | 1557 | | /// The temporary data folder wherein each test case is executed is not |
| | 1558 | | /// removed at the end of the test case. This allows to review the |
| | 1559 | | /// produced data. |
| | 1560 | | /// |
| | 1561 | | /// @param traceWinList (optional) default "" |
| | 1562 | | /// A list of windows where execution gets traced. The universal testing framework saves a RTF d |
| | 1563 | | /// for each traced procedure file. When REGEXP was set in traceOptions then traceWinList is als |
| | 1564 | | /// as a regular expression. |
| | 1565 | | /// The experiment is required to be saved somewhere on the disk. (it is okay to have unsaved ch |
| | 1566 | | /// |
| | 1567 | | /// @param traceOptions (optional) default "" |
| | 1568 | | /// A key:value pair list of additional tracing options. Currently supported is: |
| | 1569 | | /// INSTRUMENTONLY:boolean When set, run instrumentation only and return. No tests are executed. |
| | 1570 | | /// HTMLCREATION:boolean When set to zero, no htm result files are created at the end of the run |
| | 1571 | | /// REGEXP:boolean When set, traceWinList is interpreted as regular expression |
| | 1572 | | /// COBERTURA:boolean When set, it will export the tracing results in Cobertura format |
| | 1573 | | /// COBERTURA_SOURCES:string A comma (,) delimited list of directory paths that should be used |
| | 1574 | | /// as source paths for the procedure files. If this list is empty or this option not set it |
| | 1575 | | /// will use the current home directory of this experiment as the source path for all proced |
| | 1576 | | /// files. |
| | 1577 | | /// COBERTURA_OUT:string The output directory to locate the generated cobertura files. The defau |
| | 1578 | | /// is to use the current home directory. |
| | 1579 | | /// |
| | 1580 | | /// @param fixLogName (optional) default 0 disabled, enabled when set to 1: @n |
| | 1581 | | /// If enabled the output files that will be generated after an autorun will have predictable na |
| | 1582 | | /// "IUTF_Test.log". If disabled the file names will always contain the name of the procedure fi |
| | 1583 | | /// timestamp. |
| | 1584 | | /// |
| | 1585 | | /// @param waveTrackingMode (optional) default disabled, enabled when set to a value different than 0: @n |
| | 1586 | | /// Monitors the number of free waves before and after a test case run. If for some reasons the |
| | 1587 | | /// the same as before this considered as an error. If you want to opt-out a single test case yo |
| | 1588 | | /// it with IUTF_NO_WAVE_TRACKING. |
| | 1589 | | /// This uses the flags UTF_WAVE_TRACKING_FREE, UTF_WAVE_TRACKING_LOCAL and UTF_WAVE_TRACKING_AL |
| | 1590 | | /// This feature is only available since Igor Pro 9. |
| | 1591 | | /// |
| | 1592 | | /// @param retry (optional) default IUTF_RETRY_NORETRY |
| | 1593 | | /// Set the conditions and options when IUTF should retry a test case. The following flags are a |
| | 1594 | | /// - IUTF_RETRY_FAILED_UNTIL_PASS: Reruns every failed flaky test up to retryMaxCount. A flaky |
| | 1595 | | /// the IUTF_RETRY_FAILED function tag. |
| | 1596 | | /// - IUTF_RETRY_MARK_ALL_AS_RETRY: Treats all test cases as flaky. There is no need to use the |
| | 1597 | | /// function tag. This option does nothing if IUTF_RETRY_FAILED_UNTIL_PASS is not set. |
| | 1598 | | /// - IUTF_RETRY_REQUIRES: Allow to retry failed REQUIRE assertions. This option does nothing if |
| | 1599 | | /// IUTF_RETRY_FAILED_UNTIL_PASS is not set. |
| | 1600 | | /// |
| | 1601 | | /// @param retryMaxCount (optional) default IUTF_MAX_SUPPORTED_RETRY |
| | 1602 | | /// Sets the maximum number of retries if rerunning of flaky tests is enabled. Setting this numb |
| | 1603 | | /// higher than IUTF_MAX_SUPPORTED_RETRY is not allowed. |
| | 1604 | | /// |
| | 1605 | | /// @param shuffle (optional) default IUTF_SHUFFLE_NONE |
| | 1606 | | /// A combination of flags which specify the current shuffle mode. Supported flags are: |
| | 1607 | | /// IUTF_SHUFFLE_NONE: Shuffle nothing. Use a deterministic execution order. |
| | 1608 | | /// IUTF_SHUFFLE_TEST_SUITES: Shuffle the order of execution of the test suites |
| | 1609 | | /// IUTF_SHUFFLE_TEST_CASES: Shuffle the order of execution of the test cases inside the test su |
| | 1610 | | /// You can opt-out single procedure files if you place the tag IUTF_NO_SHUFFLE_TEST_CASE some |
| | 1611 | | /// specific files. |
| | 1612 | | /// IUTF_SHUFFLE_ALL: A combination of IUTF_SHUFFLE_TEST_SUITES and IUTF_SHUFFLE_TEST_CASES |
| | 1613 | | /// |
| | 1614 | | /// @return total number of errors |
| 10 | 1615 | | Function RunTest(procWinList, [name, testCase, enableJU, enableTAP, enableRegExp, allowDebug, debugMode, keepDataFolder, |
| | 1616 | | string procWinList, name, testCase |
| | 1617 | | variable enableJU, enableTAP, enableRegExp |
| | 1618 | | variable allowDebug, debugMode, keepDataFolder |
| | 1619 | | string traceWinList, traceOptions |
| | 1620 | | variable fixLogName |
| | 1621 | | variable waveTrackingMode, retry, retryMaxCount, shuffle |
| | 1622 | |
|
| 10 | 1623 | | // All variables that are needed to keep the local function state are wrapped in s |
| 10 | 1624 | | // new var/str must be added to strRunTest and added in SaveState/RestoreState functions |
| 10 | 1625 | | STRUCT strRunTest s |
| 10 | 1626 | | InitStrRunTest(s) |
| | 1627 | |
|
| 10 | 1628 | | DFREF dfr = GetPackageFolder() |
| | 1629 | |
|
| 10 | 1630 | | // do not save these for reentry |
| 10 | 1631 | | // |
| 10 | 1632 | | variable reentry |
| 10 | 1633 | | variable testSuiteCreated = 0 |
| 10 | 1634 | | // these use a very local scope where used |
| 10 | 1635 | | // loop counter and loop end derived vars |
| 10 | 1636 | | variable i, j, tcFuncCount, startNextTS, skip, tcCount, reqSave, tcResultIndex |
| 10 | 1637 | | string procWin, fullFuncName, previousProcWin, dgenFuncName |
| 10 | 1638 | | // used as temporal locals |
| 10 | 1639 | | variable var, err |
| 10 | 1640 | | string msg, errMsg |
| | 1641 | |
|
| 10 | 1642 | | fixLogName = ParamIsDefault(fixLogName) ? 0 : !!fixLogName |
| 10 | 1643 | | waveTrackingMode = ParamIsDefault(waveTrackingMode) ? UTF_WAVE_TRACKING_NONE : waveTrackingMode |
| | 1644 | |
|
| 10 | 1645 | | reentry = IsBckgRegistered() |
| 10 | 1646 | | ResetBckgRegistered() |
| 10 | 1647 | | if(reentry) |
| | 1648 | |
|
| 5 | 1649 | | // check also if a saved state is existing |
| 5 | 1650 | | if(!DataFolderExists(PKG_FOLDER_SAVE)) |
| 0 | 1651 | | IUTF_Reporting#ReportErrorAndAbort("No saved test state found, aborting. (Did you RegisterIUTFMonitor in an End Ho |
| 5 | 1652 | | endif |
| 5 | 1653 | | DFREF dfr = GetPackageFolder() |
| 5 | 1654 | | NVAR/Z compMode = dfr:COMP_Mode |
| 5 | 1655 | | // check if the reentry call originates from our own background monitor or compilation tester |
| 5 | 1656 | | if(!NVAR_Exists(compMode) && CmpStr(GetRTStackInfo(2), BACKGROUNDMONFUNC)) |
| 0 | 1657 | | ClearReentrytoIUTF() |
| 0 | 1658 | | IUTF_Reporting#ReportErrorAndAbort("RunTest was called by user after background monitoring was registered. This is |
| 5 | 1659 | | endif |
| | 1660 | |
|
| 5 | 1661 | | // a test suite must have been created if this is a reentry |
| 5 | 1662 | | testSuiteCreated = 1 |
| | 1663 | |
|
| 5 | 1664 | | else |
| 5 | 1665 | | // no early return/abort above this point |
| 5 | 1666 | | DetectDeprecation() |
| 5 | 1667 | | IUTF_Utils_Paths#ClearHomePath() |
| 5 | 1668 | | DFREF dfr = GetPackageFolder() |
| 5 | 1669 | | string/G dfr:baseFilenameOverwrite = SelectString(fixLogName, "", FIXED_LOG_FILENAME) |
| 5 | 1670 | | ClearTestSetupWaves() |
| 5 | 1671 | | IUTF_Reporting#ClearTestResultWaves() |
| 5 | 1672 | | ClearBaseFilename() |
| 5 | 1673 | | CreateHistoryLog() |
| 5 | 1674 | | InitAbortFlag() |
| 5 | 1675 | | InitAbortFromSkipFlag() |
| 5 | 1676 | | IUTF_Reporting_Control#SetupTestRun() |
| | 1677 | |
|
| 5 | 1678 | | allowDebug = ParamIsDefault(allowDebug) ? 0 : !!allowDebug |
| | 1679 | |
|
| 5 | 1680 | | // transfer parameters to s. variables |
| 5 | 1681 | | s.enableRegExp = enableRegExp |
| 5 | 1682 | | s.enableRegExpTC = ParamIsDefault(enableRegExp) ? 0 : !!enableRegExp |
| 5 | 1683 | | s.enableRegExpTS = s.enableRegExpTC |
| 5 | 1684 | | s.enableJU = ParamIsDefault(enableJU) ? 0 : !!enableJU |
| 5 | 1685 | | s.enableTAP = ParamIsDefault(enableTAP) ? 0 : !!enableTAP |
| 5 | 1686 | | s.debugMode = ParamIsDefault(debugMode) ? 0 : debugMode |
| 5 | 1687 | | s.keepDataFolder = ParamIsDefault(keepDataFolder) ? 0 : !!keepDataFolder |
| 5 | 1688 | | s.retryMode = ParamIsDefault(retry) ? IUTF_RETRY_NORETRY : retry |
| 5 | 1689 | | s.retryCount = ParamIsDefault(retryMaxCount) ? IUTF_MAX_SUPPORTED_RETRY : retryMaxCount |
| 5 | 1690 | | s.shuffle = ParamIsDefault(shuffle) ? IUTF_SHUFFLE_NONE : shuffle |
| | 1691 | |
|
| 5 | 1692 | | s.tracingEnabled = !ParamIsDefault(traceWinList) && !IUTF_Utils#IsEmpty(traceWinList) |
| | 1693 | |
|
| 5 | 1694 | | if(s.enableJU || s.enableTAP || s.tracingEnabled) |
| 5 | 1695 | | // the path is only needed locally |
| 5 | 1696 | | msg = IUTF_Utils_Paths#GetHomePath() |
| 5 | 1697 | | if(IUTF_Utils#IsEmpty(msg)) |
| 0 | 1698 | | IUTF_Reporting#ReportError("Error: Please Save experiment first.") |
| 0 | 1699 | | return NaN |
| 5 | 1700 | | endif |
| 5 | 1701 | | endif |
| | 1702 | |
|
| 5 | 1703 | | var = IUTF_DEBUG_ENABLE | IUTF_DEBUG_ON_ERROR | IUTF_DEBUG_NVAR_SVAR_WAVE | IUTF_DEBUG_FAILED_ASSERTION |
| 5 | 1704 | | if(s.debugMode > var || s.debugMode < 0 || !IUTF_Utils#IsInteger(s.debugMode)) |
| 0 | 1705 | | sprintf msg, "debugMode can only be an integer between 0 and %d. The input %g is wrong, aborting!.\r", var, s.debu |
| 0 | 1706 | | msg = msg + "Use the constants IUTF_DEBUG_ENABLE, IUTF_DEBUG_ON_ERROR,\r" |
| 0 | 1707 | | msg = msg + "IUTF_DEBUG_NVAR_SVAR_WAVE and IUTF_DEBUG_FAILED_ASSERTION for debugMode.\r\r" |
| 0 | 1708 | | msg = msg + "Example: debugMode = IUTF_DEBUG_ON_ERROR | IUTF_DEBUG_NVAR_SVAR_WAVE" |
| 0 | 1709 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 5 | 1710 | | endif |
| | 1711 | |
|
| 5 | 1712 | | if(s.debugMode > 0 && allowDebug > 0) |
| 0 | 1713 | | print "Note: debugMode parameter is set, allowDebug parameter is ignored." |
| 5 | 1714 | | endif |
| 5 | 1715 | | if(s.debugMode == 0 && allowDebug > 0) |
| 0 | 1716 | | s.debugMode = IUTF_Debug#GetCurrentDebuggerState() |
| 5 | 1717 | | endif |
| | 1718 | |
|
| 5 | 1719 | | if(shuffle & ~IUTF_SHUFFLE_ALL) |
| 0 | 1720 | | sprintf msg, "Invalid shuffle mode %d", shuffle |
| 0 | 1721 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 5 | 1722 | | endif |
| | 1723 | |
|
| | 1724 | | #if IgorVersion() < 9.00 |
| 0 | 1725 | | if(waveTrackingMode) |
| 0 | 1726 | | IUTF_Reporting#ReportErrorAndAbort("Error: wave tracking is only allowed to be used in Igor Pro 9 or higher.") |
| 0 | 1727 | | else |
| 0 | 1728 | | variable/G dfr:waveTrackingMode = UTF_WAVE_TRACKING_NONE |
| 0 | 1729 | | endif |
| | 1730 | | #else |
| 5 | 1731 | | if((waveTrackingMode & UTF_WAVE_TRACKING_ALL) != waveTrackingMode) |
| 0 | 1732 | | sprintf msg, "Error: Invalid wave tracking mode %d", waveTrackingMode |
| 0 | 1733 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 5 | 1734 | | endif |
| 5 | 1735 | | variable/G dfr:waveTrackingMode = waveTrackingMode |
| | 1736 | | #endif |
| | 1737 | |
|
| 5 | 1738 | | if(s.retryMode & ~(IUTF_RETRY_FAILED_UNTIL_PASS | IUTF_RETRY_MARK_ALL_AS_RETRY | IUTF_RETRY_REQUIRES)) |
| 0 | 1739 | | sprintf msg, "Error: Invalid retry mode %d", s.retryMode |
| 0 | 1740 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 5 | 1741 | | endif |
| | 1742 | |
|
| 5 | 1743 | | if(!IUTF_Utils#IsFinite(s.retryCount) || s.retryCount < 0 || s.retryCount > IUTF_MAX_SUPPORTED_RETRY) |
| 0 | 1744 | | sprintf msg, "Error: Invalid number of maximum retries: %d (maximum supported: %d)", s.retryCount, IUTF_MAX_SUPPOR |
| 0 | 1745 | | IUTF_Reporting#ReportErrorAndAbort(msg) |
| 5 | 1746 | | endif |
| | 1747 | |
|
| 5 | 1748 | | traceOptions = SelectString(ParamIsDefault(traceOptions), traceOptions, "") |
| | 1749 | |
|
| 5 | 1750 | | if(ParamIsDefault(name)) |
| 5 | 1751 | | s.name = "Unnamed" |
| 0 | 1752 | | else |
| 0 | 1753 | | s.name = name |
| 5 | 1754 | | endif |
| | 1755 | |
|
| 5 | 1756 | | if(ParamIsDefault(testCase)) |
| 5 | 1757 | | s.testCase = ".*" |
| 5 | 1758 | | s.enableRegExpTC = 1 |
| 0 | 1759 | | else |
| 0 | 1760 | | s.testCase = testCase |
| 5 | 1761 | | endif |
| 5 | 1762 | | s.procWinList = procWinList |
| | 1763 | |
|
| 5 | 1764 | | if(s.tracingEnabled) |
| | 1765 | | #ifdef UTF_ALLOW_TRACING |
| 5 | 1766 | | if(!CmpStr(traceWinList, IUTF_TRACE_REENTRY_KEYWORD)) |
| 5 | 1767 | | DFREF dfSave = $PKG_FOLDER_SAVE |
| 5 | 1768 | | RestoreState(dfSave, s) |
| 5 | 1769 | | ClearReentrytoIUTF() |
| 0 | 1770 | | else |
| 0 | 1771 | | ClearReentrytoIUTF() |
| | 1772 | |
|
| 0 | 1773 | | var = NumberByKey(UTF_KEY_HTMLCREATION, traceOptions) |
| 0 | 1774 | | s.htmlCreation = IUTF_Utils#IsNaN(var) ? 1 : var |
| | 1775 | |
|
| 0 | 1776 | | var = NumberByKey(UTF_KEY_COBERTURA, traceOptions) |
| 0 | 1777 | | s.cobertura = IUTF_Utils#IsNaN(var) ? 0 : !!var |
| 0 | 1778 | | s.coberturaSources = StringByKey(UTF_KEY_COBERTURA_SOURCES, traceOptions) |
| 0 | 1779 | | s.coberturaOut = StringByKey(UTF_KEY_COBERTURA_OUT, traceOptions) |
| | 1780 | |
|
| 0 | 1781 | | NewDataFolder $PKG_FOLDER_SAVE |
| 0 | 1782 | | DFREF dfSave = $PKG_FOLDER_SAVE |
| 0 | 1783 | | SaveState(dfSave, s) |
| 0 | 1784 | | TUFXOP_Init/N="IUTF_Testrun" |
| 0 | 1785 | | TUFXOP_Clear/Q/Z/N="IUTF_Error" |
| 0 | 1786 | | IUTF_Tracing#SetupTracing(traceWinList, traceOptions) |
| 0 | 1787 | | return NaN |
| 5 | 1788 | | endif |
| | 1789 | | #else |
| 0 | 1790 | | IUTF_Reporting#ReportErrorAndAbort("Tracing requires Igor Pro 9 Build 38812 (or later) and the Thread Utilities XO |
| | 1791 | | #endif // UTF_ALLOW_TRACING |
| 0 | 1792 | | else |
| | 1793 | | #ifdef UTF_ALLOW_TRACING |
| 0 | 1794 | | TUFXOP_Init/N="IUTF_Testrun" |
| | 1795 | | #endif // UTF_ALLOW_TRACING |
| 6 | 1796 | | endif |
| | 1797 | |
|
| 6 | 1798 | | // below here use only s. variables to keep local state in struct |
| | 1799 | |
|
| 6 | 1800 | | s.procWinList = AdaptProcWinList(s.procWinList, s.enableRegExpTS) |
| 6 | 1801 | | s.procWinList = FindProcedures(s.procWinList, s.enableRegExpTS) |
| | 1802 | |
|
| 6 | 1803 | | if(ItemsInList(s.procWinList) <= 0) |
| 0 | 1804 | | IUTF_Reporting#ReportError("Error: The list of procedure windows is empty or invalid.") |
| 0 | 1805 | | return NaN |
| 6 | 1806 | | endif |
| | 1807 | |
|
| 6 | 1808 | | err = CreateTestRunSetup(s.procWinList, s.testCase, s.enableRegExpTC, errMsg, s.enableTAP, s.debugMode, shuffle) |
| 6 | 1809 | | tcCount = GetTestCaseCount() |
| | 1810 | |
|
| 6 | 1811 | | if(err != TC_MATCH_OK) |
| 0 | 1812 | | if(err == TC_LIST_EMPTY) |
| 0 | 1813 | | errMsg = s.procWinList |
| 0 | 1814 | | errMsg = IUTF_Utils#IUTF_PrepareStringForOut(errMsg) |
| 0 | 1815 | | sprintf msg, "Error: A test case matching the pattern \"%s\" could not be found in test suite(s) \"%s\".", s.tes |
| 0 | 1816 | | IUTF_Reporting#ReportError(msg) |
| 0 | 1817 | | return NaN |
| 0 | 1818 | | endif |
| | 1819 | |
|
| 0 | 1820 | | errMsg = IUTF_Utils#IUTF_PrepareStringForOut(errMsg) |
| 0 | 1821 | | sprintf msg, "Error %d in CreateTestRunSetup: %s", err, errMsg |
| 0 | 1822 | | IUTF_Reporting#ReportError(msg) |
| 0 | 1823 | | return NaN |
| 6 | 1824 | | endif |
| | 1825 | |
|
| 6 | 1826 | | // 1.) set the hooks to the default implementations |
| 6 | 1827 | | IUTF_Hooks#setDefaultHooks(s.hooks) |
| 6 | 1828 | | // 2.) get global user hooks which reside in ProcGlobal and replace the default ones |
| 6 | 1829 | | IUTF_Hooks#getGlobalHooks(s.hooks) |
| | 1830 | |
|
| 6 | 1831 | | // Reinitializes |
| 6 | 1832 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_BEGIN_CONST, s.hooks, s.enableTAP, s.enableJU, s.name, NO_SOURCE_PROCEDURE, s.i, p |
| | 1833 | |
|
| 6 | 1834 | | // TAP Handling, find out if all should be skipped and number of all test cases |
| 6 | 1835 | | if(s.enableTAP) |
| 0 | 1836 | | if(IUTF_TAP#TAP_AreAllFunctionsSkip()) |
| 0 | 1837 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_END_CONST, s.hooks, s.enableTAP, s.enableJU, s.name, NO_SOURCE_PROCEDURE, s.i, |
| 0 | 1838 | | return 0 |
| 0 | 1839 | | endif |
| 6 | 1840 | | endif |
| | 1841 | |
|
| 11 | 1842 | | endif |
| | 1843 | |
|
| 11 | 1844 | | // The Test Run itself is split into Test Suites for each Procedure File |
| 11 | 1845 | | WAVE/WAVE dgenWaves = IUTF_Test_MD_Gen#GetDataGeneratorWaves() |
| 11 | 1846 | | WAVE/T testRunData = GetTestRunData() |
| 11 | 1847 | | tcFuncCount = DimSize(testRunData, UTF_ROW) |
| 11 | 1848 | | for(i = 0; i < tcFuncCount; i += 1) |
| 84 | 1849 | | s.i = i |
| | 1850 | |
|
| 84 | 1851 | | procWin = testRunData[i][%PROCWIN] |
| 84 | 1852 | | fullFuncName = testRunData[i][%FULLFUNCNAME] |
| 84 | 1853 | | if(s.i > 0) |
| 73 | 1854 | | previousProcWin = testRunData[s.i - 1][%PROCWIN] |
| 11 | 1855 | | else |
| 11 | 1856 | | previousProcWin = "" |
| 84 | 1857 | | endif |
| 84 | 1858 | | startNextTS = !!CmpStr(previousProcWin, procWin) |
| | 1859 | |
|
| 84 | 1860 | | if(!reentry) |
| | 1861 | |
|
| 79 | 1862 | | if(startNextTS) |
| 27 | 1863 | | if(i > 0) |
| 21 | 1864 | | s.procHooks = s.hooks |
| 21 | 1865 | | // 3.) get local user hooks which reside in the same Module as the requested procedure |
| 21 | 1866 | | IUTF_Hooks#getLocalHooks(s.procHooks, previousProcWin) |
| 21 | 1867 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_SUITE_END_CONST, s.procHooks, s.enableTAP, s.enableJU, previousProcWin, prev |
| 27 | 1868 | | endif |
| | 1869 | |
|
| 27 | 1870 | | if(shouldDoAbort()) |
| 0 | 1871 | | break |
| 27 | 1872 | | endif |
| 79 | 1873 | | endif |
| | 1874 | |
|
| 79 | 1875 | | s.procHooks = s.hooks |
| 79 | 1876 | | // 3.) dito |
| 79 | 1877 | | IUTF_Hooks#getLocalHooks(s.procHooks, procWin) |
| | 1878 | |
|
| 79 | 1879 | | if(startNextTS) |
| 27 | 1880 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_SUITE_BEGIN_CONST, s.procHooks, s.enableTAP, s.enableJU, procWin, procWin, s.i |
| 27 | 1881 | | testSuiteCreated = 1 |
| 79 | 1882 | | endif |
| | 1883 | |
|
| 79 | 1884 | | SetExpectedFailure(str2num(testRunData[s.i][%EXPECTFAIL])) |
| 79 | 1885 | | skip = str2num(testRunData[s.i][%SKIP]) |
| 79 | 1886 | | s.dgenIndex = 0 |
| 79 | 1887 | | s.tcSuffix = "" |
| 79 | 1888 | | FUNCREF TEST_CASE_PROTO TestCaseFunc = $fullFuncName |
| 79 | 1889 | | FUNCREF TEST_CASE_PROTO_MD TestCaseFuncMMD = $fullFuncName |
| 79 | 1890 | | if(IUTF_FuncRefIsAssigned(FuncRefInfo(TestCaseFunc))) |
| 79 | 1891 | | s.mdMode = TC_MODE_NORMAL |
| 0 | 1892 | | elseif(IUTF_FuncRefIsAssigned(FuncRefInfo(TestCaseFuncMMD))) |
| 0 | 1893 | | s.mdMode = TC_MODE_MMD |
| 0 | 1894 | | else |
| 0 | 1895 | | s.mdMode = TC_MODE_MD |
| 0 | 1896 | | dgenFuncName = StringFromList(0, testRunData[s.i][%DGENLIST]) |
| 0 | 1897 | | var = IUTF_Test_MD_Gen#GetDataGeneratorRef(dgenFuncName) |
| 0 | 1898 | | WAVE wGenerator = dgenWaves[var] |
| 0 | 1899 | | s.dgenSize = DimSize(wGenerator, UTF_ROW) |
| 79 | 1900 | | endif |
| | 1901 | |
|
| 84 | 1902 | | endif |
| | 1903 | |
|
| 84 | 1904 | | s.retryIndex = 0 |
| | 1905 | |
|
| 84 | 1906 | | do |
| | 1907 | |
|
| 84 | 1908 | | if(!reentry) |
| | 1909 | |
|
| 79 | 1910 | | if(s.mdMode == TC_MODE_MD) |
| 0 | 1911 | | dgenFuncName = StringFromList(0, testRunData[s.i][%DGENLIST]) |
| 0 | 1912 | | var = IUTF_Test_MD_Gen#GetDataGeneratorRef(dgenFuncName) |
| 0 | 1913 | | WAVE wGenerator = dgenWaves[var] |
| 0 | 1914 | | s.tcSuffix = ":" + GetDimLabel(wGenerator, UTF_ROW, s.dgenIndex) |
| 0 | 1915 | | if(strlen(s.tcSuffix) == 1) |
| 0 | 1916 | | s.tcSuffix = IUTF_TC_SUFFIX_SEP + num2istr(s.dgenIndex) |
| 0 | 1917 | | endif |
| 79 | 1918 | | elseif(s.mdMode == TC_MODE_MMD) |
| 0 | 1919 | | s.tcSuffix = IUTF_Test_MD_MMD#GetMMDTCSuffix(i) |
| 79 | 1920 | | endif |
| | 1921 | |
|
| 79 | 1922 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_CASE_BEGIN_CONST, s.procHooks, s.enableTAP, s.enableJU, fullFuncName + s.tcSuf |
| 5 | 1923 | | else |
| | 1924 | |
|
| 5 | 1925 | | DFREF dfSave = $PKG_FOLDER_SAVE |
| 5 | 1926 | | RestoreState(dfSave, s) |
| 5 | 1927 | | // restore state done |
| 5 | 1928 | | DFREF dfSave = $"" |
| 5 | 1929 | | ClearReentrytoIUTF() |
| 5 | 1930 | | // restore all loop counters and end loop locals |
| 5 | 1931 | | i = s.i |
| 5 | 1932 | | procWin = testRunData[s.i][%PROCWIN] |
| 5 | 1933 | | fullFuncName = testRunData[s.i][%FULLFUNCNAME] |
| 5 | 1934 | | skip = str2num(testRunData[s.i][%SKIP]) |
| | 1935 | |
|
| 84 | 1936 | | endif |
| | 1937 | |
|
| 84 | 1938 | | if(!skip) |
| | 1939 | |
|
| 84 | 1940 | | WAVE/T wvFailedProc = IUTF_Reporting#GetFailedProcWave() |
| 84 | 1941 | | s.retryFailedProc = IUTF_Utils_Vector#GetLength(wvFailedProc) |
| | 1942 | |
|
| 84 | 1943 | | if(GetRTError(0)) |
| 0 | 1944 | | msg = GetRTErrMessage() |
| 0 | 1945 | | err = GetRTError(1) |
| 0 | 1946 | | sprintf msg, "Internal runtime error in IUTF %d:\"%s\" before executing test case \"%s\".", err, msg, fullFunc |
| 0 | 1947 | | IUTF_Reporting#ReportErrorAndAbort(msg, setFlagOnly = 1) |
| 84 | 1948 | | endif |
| | 1949 | |
|
| 84 | 1950 | | try |
| 84 | 1951 | | CallTestCase(s, reentry) |
| 84 | 1952 | | catch |
| 0 | 1953 | | msg = GetRTErrMessage() |
| 0 | 1954 | | s.err = GetRTError(1) |
| 0 | 1955 | | // clear the abort code from setAbortFlag() |
| 0 | 1956 | | V_AbortCode = shouldDoAbort() || IsAbortFromSkip() ? 0 : V_AbortCode |
| 0 | 1957 | | EvaluateRTE(s.err, msg, V_AbortCode, fullFuncName, IUTF_TEST_CASE_TYPE, procWin) |
| | 1958 | |
|
| 0 | 1959 | | if(shouldDoAbort() && !(s.enableTAP && IUTF_TAP#TAP_IsFunctionTodo(fullFuncName))) |
| 0 | 1960 | | // check if a retry is possible |
| 0 | 1961 | | WAVE/T wvTestCaseResults = IUTF_Reporting#GetTestCaseWave() |
| 0 | 1962 | | tcResultIndex = FindDimLabel(wvTestCaseResults, UTF_ROW, "CURRENT") |
| | 1963 | |
|
| 0 | 1964 | | if(CanRetry(skip, s, fullFuncName, tcResultIndex)) |
| 0 | 1965 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_CASE_END_CONST, s.procHooks, s.enableTAP, s.enableJU, fullFuncName + s.t |
| 0 | 1966 | | CleanupRetry(s, tcResultIndex) |
| 0 | 1967 | | continue |
| 0 | 1968 | | endif |
| | 1969 | |
|
| 0 | 1970 | | // abort condition is on hold while in catch/endtry, so all cleanup must happen here |
| 0 | 1971 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_CASE_END_CONST, s.procHooks, s.enableTAP, s.enableJU, fullFuncName + s.tcS |
| | 1972 | |
|
| 0 | 1973 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_SUITE_END_CONST, s.procHooks, s.enableTAP, s.enableJU, procWin, procWin, s |
| | 1974 | |
|
| 0 | 1975 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_END_CONST, s.hooks, s.enableTAP, s.enableJU, s.name, NO_SOURCE_PROCEDURE, |
| | 1976 | |
|
| 0 | 1977 | | ClearReentrytoIUTF() |
| 0 | 1978 | | QuitOnAutoRunFull() |
| | 1979 | |
|
| 0 | 1980 | | WAVE/T wvTestRun = IUTF_Reporting#GetTestRunWave() |
| 0 | 1981 | | return str2num(wvTestRun[%CURRENT][%NUM_ERROR]) |
| 0 | 1982 | | endif |
| | 1983 | |
|
| 0 | 1984 | | InitAbortFromSkipFlag() |
| 0 | 1985 | | endtry |
| | 1986 | |
|
| | 1987 | | #ifdef UTF_ALLOW_TRACING |
| 84 | 1988 | | // check if Z_ has stored some errors |
| 84 | 1989 | | if(s.tracingEnabled) |
| 75 | 1990 | | TUFXOP_GetStorage/Z/Q/N="IUTF_Error" wvAllStorage |
| 75 | 1991 | | if(!V_flag) |
| 0 | 1992 | | variable numThreads = NumberByKey("Index", note(wvAllStorage)) |
| 0 | 1993 | | for(j = 0; j < numThreads; ++j) |
| 0 | 1994 | | WAVE/WAVE wvStorage = wvAllStorage[j] |
| 0 | 1995 | | WAVE/T data = wvStorage[0] |
| 0 | 1996 | | IUTF_Reporting#ReportError(data[0]) |
| 0 | 1997 | | endfor |
| 75 | 1998 | | endif |
| 84 | 1999 | | endif |
| | 2000 | | #endif // UTF_ALLOW_TRACING |
| | 2001 | |
|
| 84 | 2002 | | endif |
| | 2003 | |
|
| 84 | 2004 | | reentry = 0 |
| | 2005 | |
|
| 84 | 2006 | | if(IsBckgRegistered()) |
| 5 | 2007 | | // save state |
| 5 | 2008 | | NewDataFolder $PKG_FOLDER_SAVE |
| 5 | 2009 | | DFREF dfSave = $PKG_FOLDER_SAVE |
| 5 | 2010 | | SaveState(dfSave, s) |
| | 2011 | |
|
| 5 | 2012 | | return RUNTEST_RET_BCKG |
| 79 | 2013 | | endif |
| | 2014 | |
|
| 79 | 2015 | | WAVE/T wvTestCaseResults = IUTF_Reporting#GetTestCaseWave() |
| 79 | 2016 | | tcResultIndex = FindDimLabel(wvTestCaseResults, UTF_ROW, "CURRENT") |
| | 2017 | |
|
| 79 | 2018 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_CASE_END_CONST, s.procHooks, s.enableTAP, s.enableJU, fullFuncName + s.tcSuffix, |
| | 2019 | |
|
| 79 | 2020 | | if(CanRetry(skip, s, fullFuncName, tcResultIndex)) |
| 0 | 2021 | | CleanupRetry(s, tcResultIndex) |
| 0 | 2022 | | // retry the the current test case. If this is a multi-data test case or |
| 0 | 2023 | | // multi-multi-data test case it will retry the current index which failed and not |
| 0 | 2024 | | // all previous runs. |
| 0 | 2025 | | continue |
| 79 | 2026 | | else |
| 79 | 2027 | | s.retryIndex = 0 |
| 79 | 2028 | | endif |
| | 2029 | |
|
| 79 | 2030 | | if(shouldDoAbort()) |
| 0 | 2031 | | break |
| 79 | 2032 | | endif |
| | 2033 | |
|
| 79 | 2034 | | if(s.mdMode == TC_MODE_MD) |
| 0 | 2035 | | s.dgenIndex += 1 |
| 79 | 2036 | | elseif(s.mdMode == TC_MODE_MMD) |
| 0 | 2037 | | s.dgenIndex = IUTF_Test_MD_MMD#IncreaseMMDIndices(fullFuncName) |
| 79 | 2038 | | endif |
| | 2039 | |
|
| 79 | 2040 | | while((s.mdMode == TC_MODE_MD && s.dgenIndex < s.dgenSize) || (s.mdMode == TC_MODE_MMD && !s.dgenIndex)) |
| | 2041 | |
|
| 79 | 2042 | | if(shouldDoAbort()) |
| 0 | 2043 | | break |
| 79 | 2044 | | endif |
| | 2045 | |
|
| 79 | 2046 | | endfor |
| | 2047 | |
|
| 6 | 2048 | | // at this code path it is unclear if a test suite was ever started, so we have to check this manually |
| 6 | 2049 | | if(testSuiteCreated) |
| 6 | 2050 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_SUITE_END_CONST, s.procHooks, s.enableTAP, s.enableJU, procWin, procWin, s.i) |
| 6 | 2051 | | endif |
| 6 | 2052 | | IUTF_Hooks#ExecuteHooks(IUTF_TEST_END_CONST, s.hooks, s.enableTAP, s.enableJU, s.name, NO_SOURCE_PROCEDURE, s.i, param |
| | 2053 | |
|
| 5 | 2054 | | ClearReentrytoIUTF() |
| | 2055 | |
|
| | 2056 | | #ifdef UTF_ALLOW_TRACING |
| 5 | 2057 | | if(s.htmlCreation) |
| 0 | 2058 | | IUTF_Tracing#AnalyzeTracingResult() |
| 5 | 2059 | | endif |
| 5 | 2060 | | if(s.cobertura) |
| 5 | 2061 | | IUTF_Tracing_Cobertura#PrintReport(s.coberturaSources, s.coberturaOut) |
| 0 | 2062 | | endif |
| | 2063 | | #endif // UTF_ALLOW_TRACING |
| | 2064 | |
|
| 0 | 2065 | | QuitOnAutoRunFull() |
| | 2066 | |
|
| 0 | 2067 | | WAVE/T wvTestRun = IUTF_Reporting#GetTestRunWave() |
| 0 | 2068 | | return str2num(wvTestRun[%CURRENT][%NUM_ERROR]) |
| 10 | 2069 | | End |