| | 1 | | #pragma rtGlobals=3 |
| | 2 | | #pragma TextEncoding="UTF-8" |
| | 3 | | #pragma rtFunctionErrors=1 |
| | 4 | | #pragma version=1.10 |
| | 5 | | #pragma ModuleName=IUTF_Reporting |
| | 6 | |
|
| | 7 | | static Constant IP8_PRINTF_STR_MAX_LENGTH = 2400 |
| | 8 | |
|
| | 9 | | /// @brief Get the current time in seconds since the start of the computer. This conversion is |
| | 10 | | /// required as the time has to be stored in a TextGrid later. |
| 245 | 11 | | static Function/S GetTimeString() |
| 245 | 12 | | string msg |
| | 13 | |
|
| 245 | 14 | | sprintf msg, "%.6f", StopMSTimer(-2) * IUTF_MICRO_TO_ONE |
| 245 | 15 | | return msg |
| 245 | 16 | | End |
| | 17 | |
|
| | 18 | | /// @brief Set parentWave[%CURRENT][%CHILD_END] to the length of the child wave. This is recommended |
| | 19 | | /// to do after a row is added to the child wave or a new entry in the parent wave is created. |
| | 20 | | /// |
| | 21 | | /// @param parentWave the parent wave to update |
| | 22 | | /// @param childWave the child wave to get the length |
| | 23 | | /// @param init [optional, default 0] if set to non zero this will also set |
| | 24 | | /// parentWave[%CURRENT][%CHILD_START] to the length of the child wave. |
| 251 | 25 | | static Function UpdateChildRange(parentWave, childWave, [init]) |
| | 26 | | WAVE/T parentWave, childWave |
| | 27 | | variable init |
| | 28 | |
|
| 251 | 29 | | variable length = IUTF_Utils_Vector#GetLength(childWave) |
| | 30 | |
|
| 251 | 31 | | init = ParamIsDefault(init) ? 0 : !!init |
| | 32 | |
|
| 251 | 33 | | if(init) |
| 123 | 34 | | parentWave[%CURRENT][%CHILD_START] = num2istr(length) |
| 251 | 35 | | endif |
| 251 | 36 | | parentWave[%CURRENT][%CHILD_END] = num2istr(length) |
| 251 | 37 | | End |
| | 38 | |
|
| | 39 | | /// @brief Get the results wave for the whole test run. This wave contains the following column |
| | 40 | | /// dimension labels: |
| | 41 | | /// - HOSTNAME: the name of the computer |
| | 42 | | /// - USERNAME: the username for which Igor is run |
| | 43 | | /// - STARTTIME: time in seconds (since since computer start) when this test run was started |
| | 44 | | /// - ENDTIME: time in seconds (since since computer start) when this test run was finished. Empty |
| | 45 | | /// if still running. |
| | 46 | | /// - NUM_ERROR: number of failed test cases |
| | 47 | | /// - NUM_SKIPPED: number of skipped test cases |
| | 48 | | /// - NUM_TESTS: number of test cases |
| | 49 | | /// - NUM_ASSERT: number of called assertions in all test cases |
| | 50 | | /// - NUM_ASSERT_ERROR: number of failed or errored assertions in all test cases |
| | 51 | | /// - SYSTEMINFO: information of the current system |
| | 52 | | /// - IGORINFO: information of the current igor instance |
| | 53 | | /// - VERSION: version number of the used IUTF |
| | 54 | | /// - EXPERIMENT: name of the experiment file |
| | 55 | | /// - CHILD_START: the start index (inclusive) for all test suites that belong to this test run |
| | 56 | | /// - CHILD_END: the end index (exclusive) for all test suites that belong to this test run |
| | 57 | | /// |
| | 58 | | /// Warning: You have to initialize the TestRunWave with IUTF_Reporting_Control#SetupTestRun() |
| | 59 | | /// before its first usage. This should usually be done at the start of IUTF_Basics#RunTest() after |
| | 60 | | /// clearing the waves. |
| 211 | 61 | | static Function/WAVE GetTestRunWave() |
| 211 | 62 | | DFREF dfr = GetPackageFolder() |
| 211 | 63 | | string name = "TestRunResult" |
| 211 | 64 | | WAVE/Z/T wv = dfr:$name |
| 211 | 65 | | if(WaveExists(wv)) |
| 206 | 66 | | return wv |
| 5 | 67 | | endif |
| | 68 | |
|
| 5 | 69 | | WAVE/T wv = IUTF_Utils_TextGrid#Create("HOSTNAME;USERNAME;STARTTIME;ENDTIME;NUM_ERROR;NUM_SKIPPED;NUM_TESTS;NUM_ASSERT |
| 5 | 70 | | MoveWave wv, dfr:$name |
| | 71 | |
|
| 5 | 72 | | return wv |
| 211 | 73 | | End |
| | 74 | |
|
| | 75 | | /// @brief Get the results wave for the test suites. This wave contains the following column |
| | 76 | | /// dimension labels: |
| | 77 | | /// - PROCEDURENAME: the name of the procedure file |
| | 78 | | /// - STARTTIME: time in seconds (since since computer start) when this test suite was started |
| | 79 | | /// - ENDTIME: time in seconds (since since computer start) when this test suite was finished. |
| | 80 | | /// Empty if still running. |
| | 81 | | /// - NUM_ERROR: number of failed test cases |
| | 82 | | /// - NUM_SKIPPED: number of skipped test cases |
| | 83 | | /// - NUM_TESTS: number of test cases |
| | 84 | | /// - NUM_ASSERT: number of called assertions in all test cases |
| | 85 | | /// - NUM_ASSERT_ERROR: number of failed or errored assertions in all test cases |
| | 86 | | /// - STDOUT: the copy of the output that was printed to the history during execution of this test |
| | 87 | | /// suite |
| | 88 | | /// - STDERR: the error messages that are collected during execution of this test suite |
| | 89 | | /// - CHILD_START: the start index (inclusive) for all test cases that belong to this test suite |
| | 90 | | /// - CHILD_END: the end index (exclusive) for all test cases that belong to this test suite |
| 376 | 91 | | static Function/WAVE GetTestSuiteWave() |
| 376 | 92 | | DFREF dfr = GetPackageFolder() |
| 376 | 93 | | string name = "TestSuiteResult" |
| 376 | 94 | | WAVE/Z/T wv = dfr:$name |
| 376 | 95 | | if(WaveExists(wv)) |
| 365 | 96 | | return wv |
| 11 | 97 | | endif |
| | 98 | |
|
| 11 | 99 | | WAVE/T wv = IUTF_Utils_TextGrid#Create("PROCEDURENAME;STARTTIME;ENDTIME;NUM_ERROR;NUM_SKIPPED;NUM_TESTS;NUM_ASSERT;NUM |
| 11 | 100 | | MoveWave wv, dfr:$name |
| | 101 | |
|
| 11 | 102 | | return wv |
| 376 | 103 | | End |
| | 104 | |
|
| | 105 | | /// @brief Get the results wave for the test cases. This wave contains the following column |
| | 106 | | /// dimension labels: |
| | 107 | | /// - NAME: the full name of the testcase |
| | 108 | | /// - STARTTIME: time in seconds (since since computer start) when this test case was started |
| | 109 | | /// - ENDTIME: time in seconds (since since computer start) when this test case was finished. |
| | 110 | | /// Empty if still running. |
| | 111 | | /// - STATUS: The resulting status of this test case. Its one of IUTF_STATUS_UNKNOWN, |
| | 112 | | /// IUTF_STATUS_ERROR, IUTF_STATUS_FAIL, IUTF_STATUS_SKIP, IUTF_STATUS_SUCCESS or |
| | 113 | | /// IUTF_STATUS_RETRY. |
| | 114 | | /// - NUM_ASSERT: number of called assertions in this test case |
| | 115 | | /// - NUM_ASSERT_ERROR: number of failed or errored assertions in this test case |
| | 116 | | /// - STDOUT: the copy of the output that was printed to the history during execution of this test |
| | 117 | | /// case |
| | 118 | | /// - STDERR: the error messages that are collected during execution of this test case |
| | 119 | | /// - CHILD_START: the start index (inclusive) for all assertion that belong to this test case |
| | 120 | | /// - CHILD_END: the end index (exclusive) for all assertion that belong to this test case |
| 1133 | 121 | | static Function/WAVE GetTestCaseWave() |
| 1133 | 122 | | DFREF dfr = GetPackageFolder() |
| 1133 | 123 | | string name = "TestCaseResult" |
| 1133 | 124 | | WAVE/Z/T wv = dfr:$name |
| 1133 | 125 | | if(WaveExists(wv)) |
| 1122 | 126 | | return wv |
| 11 | 127 | | endif |
| | 128 | |
|
| 11 | 129 | | WAVE/T wv = IUTF_Utils_TextGrid#Create("NAME;STARTTIME;ENDTIME;STATUS;NUM_ASSERT;NUM_ASSERT_ERROR;STDOUT;STDERR;CHILD_ |
| 11 | 130 | | MoveWave wv, dfr:$name |
| | 131 | |
|
| 11 | 132 | | return wv |
| 1133 | 133 | | End |
| | 134 | |
|
| | 135 | | /// @brief Get the results wave for the test assertions. This wave contains the following column |
| | 136 | | /// dimension labels: |
| | 137 | | /// - MESSAGE: the full message of this assertion |
| | 138 | | /// - TYPE: the type of this assertion. Currently used are IUTF_STATUS_ERROR and IUTF_STATUS_FAIL. |
| | 139 | | /// - SEVERITY: the severity of this assertion. Currently used are IUTF_SEVERITY_WARN and |
| | 140 | | /// IUTF_SEVERITY_ERROR. |
| | 141 | | /// - STACKTRACE: the partial stack trace between the entry of the test case and the call of the |
| | 142 | | /// assertion |
| | 143 | | /// - CHILD_START: the start index (inclusive) for all information that belong to this assertion |
| | 144 | | /// - CHILD_END: the end index (exclusive) for all information that belong to this assertion |
| 185 | 145 | | static Function/WAVE GetTestAssertionWave() |
| 185 | 146 | | DFREF dfr = GetPackageFolder() |
| 185 | 147 | | string name = "TestAssertionResult" |
| 185 | 148 | | WAVE/Z/T wv = dfr:$name |
| 185 | 149 | | if(WaveExists(wv)) |
| 174 | 150 | | return wv |
| 11 | 151 | | endif |
| | 152 | |
|
| 11 | 153 | | WAVE/T wv = IUTF_Utils_TextGrid#Create("MESSAGE;TYPE;SEVERITY;STACKTRACE;CHILD_START;CHILD_END;") |
| 11 | 154 | | MoveWave wv, dfr:$name |
| | 155 | |
|
| 11 | 156 | | return wv |
| 185 | 157 | | End |
| | 158 | |
|
| | 159 | | /// @brief Get the results wave for the test information. This wave contains the following column |
| | 160 | | /// dimension labels: |
| | 161 | | /// - MESSAGE: the full information text for the parent assertion |
| 15 | 162 | | static Function/WAVE GetTestInfoWave() |
| 15 | 163 | | DFREF dfr = GetPackageFolder() |
| 15 | 164 | | string name = "TestInfoResult" |
| 15 | 165 | | WAVE/Z/T wv = dfr:$name |
| 15 | 166 | | if(WaveExists(wv)) |
| 5 | 167 | | return wv |
| 10 | 168 | | endif |
| | 169 | |
|
| 10 | 170 | | WAVE/T wv = IUTF_Utils_TextGrid#Create("MESSAGE;") |
| 10 | 171 | | MoveWave wv, dfr:$name |
| | 172 | |
|
| 10 | 173 | | return wv |
| 15 | 174 | | End |
| | 175 | |
|
| 5 | 176 | | static Function ClearTestResultWaves() |
| 5 | 177 | | WAVE/T wvTestRun = GetTestRunWave() |
| 5 | 178 | | WAVE/T wvTestSuite = GetTestSuiteWave() |
| 5 | 179 | | WAVE/T wvTestCase = GetTestCaseWave() |
| 5 | 180 | | WAVE/T wvAssertion = GetTestAssertionWave() |
| 5 | 181 | | WAVE/T wvInfo = GetTestInfoWave() |
| | 182 | |
|
| 5 | 183 | | KillWaves wvTestRun, wvTestSuite, wvTestCase, wvAssertion, wvInfo |
| 5 | 184 | | End |
| | 185 | |
|
| | 186 | | /// @brief Add a failed assertion to the current test case. |
| | 187 | | /// @param message The message to add to this assertion. |
| | 188 | | /// @param type The type of failed assertion |
| | 189 | | /// @param incrErrorCounter [optional, default enabled] If set different to zero it will increment |
| | 190 | | /// the current assertion error counter of the current test case. |
| 5 | 191 | | static Function AddError(message, type, [incrErrorCounter]) |
| | 192 | | string message, type |
| | 193 | | variable incrErrorCounter |
| | 194 | |
|
| 5 | 195 | | string msg |
| 5 | 196 | | variable i, length, startIndex |
| | 197 | |
|
| 5 | 198 | | incrErrorCounter = ParamIsDefault(incrErrorCounter) ? 1 : !!incrErrorCounter |
| | 199 | |
|
| 5 | 200 | | WAVE/T wvAssertion = GetTestAssertionWave() |
| 5 | 201 | | IUTF_Utils_Vector#AddRow(wvAssertion) |
| 5 | 202 | | wvAssertion[%CURRENT][%MESSAGE] = message |
| 5 | 203 | | wvAssertion[%CURRENT][%TYPE] = type |
| 5 | 204 | | wvAssertion[%CURRENT][%SEVERITY] = SelectString(incrErrorCounter, IUTF_SEVERITY_WARN, IUTF_SEVERITY_ERROR) |
| | 205 | |
|
| 5 | 206 | | WAVE/T wvTestCase = GetTestCaseWave() |
| 5 | 207 | | UpdateChildRange(wvTestCase, wvAssertion) |
| 5 | 208 | | if(incrErrorCounter) |
| 0 | 209 | | wvTestCase[%CURRENT][%STATUS] = type |
| 0 | 210 | | wvTestCase[%CURRENT][%NUM_ASSERT_ERROR] = num2istr(str2num(wvTestCase[%CURRENT][%NUM_ASSERT_ERROR]) + 1) |
| 5 | 211 | | endif |
| 5 | 212 | | if(!IUTF_Utils#IsEmpty(message)) |
| 5 | 213 | | wvTestCase[%CURRENT][%STDERR] = AddListItem(message, wvTestCase[%CURRENT][%STDERR], "\n", Inf) |
| 5 | 214 | | endif |
| | 215 | |
|
| 5 | 216 | | WAVE/T wvInfo = GetTestInfoWave() |
| 5 | 217 | | UpdateChildRange(wvAssertion, wvInfo, init = 1) |
| | 218 | |
|
| 5 | 219 | | WAVE/T wvInfoMsg = GetInfoMsg() |
| 5 | 220 | | length = IUTF_Utils_Vector#GetLength(wvInfoMsg) |
| 5 | 221 | | if(length > 0) |
| 5 | 222 | | startIndex = IUTF_Utils_Vector#GetLength(wvInfo) |
| 5 | 223 | | IUTF_Utils_Vector#AddRows(wvInfo, length) |
| 5 | 224 | | UpdateChildRange(wvAssertion, wvInfo) |
| 5 | 225 | | wvInfo[startIndex, startIndex + length - 1][%MESSAGE] = wvInfoMsg[p - startIndex] |
| | 226 | |
|
| 5 | 227 | | for(i = 0; i < length; i += 1) |
| 5 | 228 | | msg = " " + TC_ASSERTION_INFO_INDICATOR + " " + wvInfoMsg[i] |
| 5 | 229 | | wvTestCase[%CURRENT][%STDERR] = AddListItem(msg, wvTestCase[%CURRENT][%STDERR], "\n", Inf) |
| 5 | 230 | | endfor |
| 5 | 231 | | endif |
| 5 | 232 | | End |
| | 233 | |
|
| | 234 | | /// Increments the assertion counter for the current test case |
| 515 | 235 | | static Function incrAssert() |
| 515 | 236 | | WAVE/T wvTestCase = IUTF_Reporting#GetTestCaseWave() |
| 515 | 237 | | wvTestCase[%CURRENT][%NUM_ASSERT] = num2istr(str2num(wvTestCase[%CURRENT][%NUM_ASSERT]) + 1) |
| 515 | 238 | | End |
| | 239 | |
|
| | 240 | | /// Increments the global error counter for the complete test run. This wont change the error |
| | 241 | | /// counter for test cases. Use AddError for these cases. |
| 0 | 242 | | static Function incrGlobalError() |
| 0 | 243 | | WAVE/T wvTestRun = IUTF_Reporting#GetTestRunWave() |
| 0 | 244 | | wvTestRun[%CURRENT][%NUM_ASSERT_ERROR] = num2istr(str2num(wvTestRun[%CURRENT][%NUM_ASSERT_ERROR]) + 1) |
| 0 | 245 | | End |
| | 246 | |
|
| | 247 | | /// Get the wave that can store information for the next assertion. These wave is cleared |
| | 248 | | /// automatically at the end of the test case or assertion. This wave is considered as a list. Use |
| | 249 | | /// IUTF_Utils_Waves#GetListLength to retrieve its length. |
| 799 | 250 | | static Function/WAVE GetInfoMsg() |
| 799 | 251 | | DFREF dfr = GetPackageFolder() |
| 799 | 252 | | string name = "InfoMsg" |
| 799 | 253 | | WAVE/Z/T wv = dfr:$name |
| 799 | 254 | | if(WaveExists(wv)) |
| 794 | 255 | | return wv |
| 5 | 256 | | endif |
| | 257 | |
|
| 5 | 258 | | MAKE/FREE/T/N=(IUTF_WAVECHUNK_SIZE) wv |
| 5 | 259 | | IUTF_Utils_Vector#SetLength(wv, 0) |
| 5 | 260 | | MoveWave wv, dfr:$name |
| | 261 | |
|
| 5 | 262 | | return wv |
| 799 | 263 | | End |
| | 264 | |
|
| | 265 | | /// Clears all stored information for the next assertion. This will only update the length of the |
| | 266 | | /// list and not its contents. |
| 594 | 267 | | static Function CleanupInfoMsg() |
| 594 | 268 | | WAVE/T wv = GetInfoMsg() |
| | 269 | |
|
| 594 | 270 | | IUTF_Utils_Vector#SetLength(wv, 0) |
| 594 | 271 | | End |
| | 272 | |
|
| | 273 | | /// Get or create the wave that contains the failed procedures |
| 100 | 274 | | static Function/WAVE GetFailedProcWave() |
| 100 | 275 | | string name = "FailedProcWave" |
| | 276 | |
|
| 100 | 277 | | DFREF dfr = GetPackageFolder() |
| 100 | 278 | | WAVE/Z/T wv = dfr:$name |
| 100 | 279 | | if(WaveExists(wv)) |
| 95 | 280 | | return wv |
| 5 | 281 | | endif |
| | 282 | |
|
| 5 | 283 | | Make/T/N=(IUTF_WAVECHUNK_SIZE) dfr:$name/WAVE=wv |
| 5 | 284 | | IUTF_Utils_Vector#SetLength(wv, 0) |
| | 285 | |
|
| 5 | 286 | | return wv |
| 100 | 287 | | End |
| | 288 | |
|
| | 289 | | /// @brief Add msg to the failed summary. This list will be printed to the |
| | 290 | | /// history area to reference errors briefly. |
| | 291 | | /// |
| | 292 | | /// @param msg The message to add to list |
| 5 | 293 | | static Function AddFailedSummaryInfo(msg) |
| | 294 | | string msg |
| | 295 | |
|
| 5 | 296 | | variable index |
| 5 | 297 | | WAVE/T wvFailed = GetFailedProcWave() |
| | 298 | |
|
| 5 | 299 | | index = IUTF_Utils_Vector#GetLength(wvFailed) |
| 5 | 300 | | IUTF_Utils_Vector#EnsureCapacity(wvFailed, index) |
| 5 | 301 | | IUTF_Utils_Vector#SetLength(wvFailed, index + 1) |
| 5 | 302 | | wvFailed[index] = msg |
| 5 | 303 | | End |
| | 304 | |
|
| | 305 | | /// Make a test case fail. This method is intended to use outside the user code |
| | 306 | | /// of the test case as such as it won't look in the stack trace which assertion |
| | 307 | | /// triggered the error. |
| | 308 | | /// |
| | 309 | | /// This method is a short version of |
| | 310 | | /// ReportResults(0, msg, OUTPUT_MESSAGE | INCREASE_ERROR) |
| | 311 | | /// without the stack trace detection and special handling of output. |
| | 312 | | /// |
| | 313 | | /// @param message The message to output to the history |
| | 314 | | /// @param summaryMsg (optional, default is message) The message to output in the summary at the |
| | 315 | | /// end of the test run. If this parameter is omitted it will use message for the |
| | 316 | | /// summary. |
| | 317 | | /// @param isFailure (optional, default disabled) If set to non zero this will be handled as a |
| | 318 | | /// FAILURE instead an ERROR. This changes the following: |
| | 319 | | /// - the test case status is set to IUTF_STATUS_FAIL |
| | 320 | | /// - updateStatus is set to 0 in AddError |
| | 321 | | /// @param incrErrorCounter (optional, default enabled) Enabled if set to a value different to 0. |
| | 322 | | /// Increases the assertion error counter for the current test case. |
| 5 | 323 | | static Function TestCaseFail(message, [summaryMsg, isFailure, incrErrorCounter]) |
| | 324 | | string message |
| | 325 | | string summaryMsg |
| | 326 | | variable isFailure, incrErrorCounter |
| | 327 | |
|
| 5 | 328 | | summaryMsg = SelectString(ParamIsDefault(summaryMsg), summaryMsg, message) |
| 5 | 329 | | isFailure = ParamIsDefault(isFailure) ? 0 : !!isFailure |
| 5 | 330 | | incrErrorCounter = ParamIsDefault(incrErrorCounter) ? 1 : !!incrErrorCounter |
| | 331 | |
|
| 5 | 332 | | AddError(message, SelectString(isFailure, IUTF_STATUS_ERROR, IUTF_STATUS_FAIL), incrErrorCounter = incrErrorCounter) |
| | 333 | |
|
| 5 | 334 | | // We are increasing the local error counter so there is no need to increase the global error |
| 5 | 335 | | // counter. |
| 5 | 336 | | ReportError(message, incrGlobalErrorCounter = 0) |
| 5 | 337 | | ShowInfoMsg() |
| | 338 | |
|
| 5 | 339 | | AddFailedSummaryInfo(summaryMsg) |
| 5 | 340 | | End |
| | 341 | |
|
| | 342 | | /// Prints message that was stored through the INFO assertion |
| 5 | 343 | | static Function ShowInfoMsg() |
| | 344 | |
|
| 5 | 345 | | variable i, length |
| | 346 | |
|
| 5 | 347 | | WAVE/T wvInfoMsg = GetInfoMsg() |
| 5 | 348 | | length = IUTF_Utils_Vector#GetLength(wvInfoMsg) |
| 5 | 349 | | for(i = 0; i < length; i += 1) |
| 5 | 350 | | ReportError(" " + TC_ASSERTION_INFO_INDICATOR + " " + wvInfoMsg[i], incrGlobalErrorCounter = 0) |
| 5 | 351 | | endfor |
| 5 | 352 | | End |
| | 353 | |
|
| | 354 | | /// Prints an informative message that the test case failed |
| | 355 | | /// |
| | 356 | | /// @param message the fail message to print to the output |
| | 357 | | /// @param expectedFailure if set to non zero the error will be considered as expected |
| | 358 | | /// @param incrErrorCounter if set to non zero the assertion error counter for the current test case |
| | 359 | | /// will be updated. This setting is ignored if expectedFailure is set to |
| | 360 | | /// non zero |
| | 361 | | /// @param callStack [optional, default current callStack] Can be used to set the callStack |
| | 362 | | /// to a previous recorded callStack (GetRTStackInfo(3)). |
| 5 | 363 | | static Function PrintFailInfo(message, expectedFailure, incrErrorCounter, [callStack]) |
| | 364 | | string message |
| | 365 | | variable expectedFailure, incrErrorCounter |
| | 366 | | string callStack |
| | 367 | |
|
| 5 | 368 | | string str, partialStack |
| 5 | 369 | | string prefix = SelectString(expectedFailure, "", "Expected Failure: ") |
| | 370 | |
|
| 5 | 371 | | if(ParamIsDefault(callStack)) |
| 5 | 372 | | str = getInfo(0, partialStack) |
| 0 | 373 | | else |
| 0 | 374 | | str = getInfo(0, partialStack, callStack = callStack) |
| 5 | 375 | | endif |
| 5 | 376 | | message = prefix + message + " " + str |
| | 377 | |
|
| 5 | 378 | | TestCaseFail(message, summaryMsg = str, isFailure = 1, incrErrorCounter = incrErrorCounter) |
| | 379 | |
|
| 5 | 380 | | if(!expectedFailure) |
| 5 | 381 | | WAVE/T wvAssertion = GetTestAssertionWave() |
| 5 | 382 | | wvAssertion[%CURRENT][%STACKTRACE] = partialStack |
| 5 | 383 | | endif |
| 5 | 384 | | End |
| | 385 | |
|
| | 386 | | /// @brief returns the informative message about the assertions state and location. |
| | 387 | | /// |
| | 388 | | /// @param result Assertion states: 0 failed, 1 succeeded |
| | 389 | | /// @param[out] partialStack The partial stacktrace between the entry of the test case and the call |
| | 390 | | /// of the assertion. |
| | 391 | | /// @param callStack [optional, default current callStack] Can be used to set the callStack |
| | 392 | | /// to a previous recorded callStack (GetRTStackInfo(3)). |
| | 393 | | /// |
| | 394 | | /// @returns The informative message |
| 5 | 395 | | static Function/S getInfo(result, partialStack, [callStack]) |
| | 396 | | variable result |
| | 397 | | string &partialStack |
| | 398 | | string callStack |
| | 399 | |
|
| 5 | 400 | | string caller, func, procedure, contents, moduleName |
| 5 | 401 | | string text, cleanText, line, callerTestCase, tmpStr |
| 5 | 402 | | variable numCallers, i, assertLine, err |
| 5 | 403 | | variable callerIndex = NaN |
| 5 | 404 | | variable testCaseIndex |
| | 405 | |
|
| 5 | 406 | | callStack = SelectString(ParamIsDefault(callStack), callStack, GetRTStackInfo(3)) |
| 5 | 407 | | numCallers = ItemsInList(callStack) |
| 5 | 408 | | moduleName = "" |
| 5 | 409 | | partialStack = "" |
| | 410 | |
|
| 5 | 411 | | // traverse the callstack from bottom up, |
| 5 | 412 | | // the first function not in one of the igortest procedures is |
| 5 | 413 | | // the one we want to report. Except if helper functions are involved. |
| 5 | 414 | | for(i = numCallers - 1; i >= 0; i -= 1) |
| 40 | 415 | | caller = StringFromList(i, callStack) |
| 40 | 416 | | procedure = StringFromList(1, caller, ",") |
| | 417 | |
|
| 40 | 418 | | if(StringMatch(procedure, "igortest*")) |
| 35 | 419 | | if(IUTF_Utils#IsNaN(callerIndex)) |
| 30 | 420 | | continue |
| 5 | 421 | | endif |
| 5 | 422 | | testCaseIndex = i + 1 |
| 5 | 423 | | break |
| 5 | 424 | | else |
| 5 | 425 | | if(IUTF_Utils#IsNaN(callerIndex)) |
| 5 | 426 | | callerIndex = i |
| 5 | 427 | | endif |
| 5 | 428 | | endif |
| 5 | 429 | | endfor |
| | 430 | |
|
| 5 | 431 | | if(IUTF_Utils#IsNaN(callerIndex)) |
| 0 | 432 | | WAVE/T wvTestCase = IUTF_Reporting#GetTestCaseWave() |
| 0 | 433 | | if(str2num(wvTestCase[%CURRENT][%NUM_ASSERT]) == 0) |
| 0 | 434 | | // We have no external caller, assuming the internal call was the check in AfterTestCase() |
| 0 | 435 | | return "The test case did not make any assertions!" |
| 0 | 436 | | else |
| 0 | 437 | | // We have no external caller, but a test case assertion - should never happen |
| 0 | 438 | | return "Assertion failed in unknown location" |
| 0 | 439 | | endif |
| 5 | 440 | | endif |
| | 441 | |
|
| 5 | 442 | | callerTestCase = StringFromList(testCaseIndex, callStack) |
| | 443 | |
|
| 5 | 444 | | caller = StringFromList(callerIndex, callStack) |
| 5 | 445 | | func = StringFromList(0, caller, ",") |
| 5 | 446 | | procedure = StringFromList(1, caller, ",") |
| 5 | 447 | | line = StringFromList(2, caller, ",") |
| 5 | 448 | | assertLine = str2num(StringFromList(2, caller, ",")) |
| | 449 | |
|
| 5 | 450 | | text = IUTF_Basics#getFullFunctionName(err, func, procedure) |
| 5 | 451 | | if(!err) |
| 5 | 452 | | func = text |
| 5 | 453 | | endif |
| | 454 | |
|
| 5 | 455 | | if(callerIndex != testcaseIndex) |
| 0 | 456 | | tmpStr = StringFromList(0, callerTestCase, ",") |
| 0 | 457 | | text = IUTF_Basics#getFullFunctionName(err, tmpStr, StringFromList(1, callerTestCase, ",")) |
| 0 | 458 | | if(!err) |
| 0 | 459 | | tmpStr = text |
| 0 | 460 | | endif |
| | 461 | |
|
| 0 | 462 | | func = tmpStr + TC_ASSERTION_MLINE_INDICATOR + func |
| 0 | 463 | | line = StringFromList(2, callerTestCase, ",") + TC_ASSERTION_MLINE_INDICATOR + line |
| 5 | 464 | | endif |
| | 465 | |
|
| 5 | 466 | | for(i = testcaseIndex; i <= callerIndex; i += 1) |
| 5 | 467 | | partialStack = AddListItem(StringFromList(i, callStack), partialStack, ";", Inf) |
| 5 | 468 | | endfor |
| | 469 | |
|
| 5 | 470 | | if(!IUTF_Basics#IsProcGlobal()) |
| 0 | 471 | | moduleName = " [" + GetIndependentModuleName() + "]" |
| 5 | 472 | | endif |
| | 473 | |
|
| 5 | 474 | | contents = ProcedureText("", -1, procedure + moduleName) |
| 5 | 475 | | text = StringFromList(assertLine, contents, "\r") |
| | 476 | |
|
| 5 | 477 | | cleanText = trimstring(text) |
| | 478 | |
|
| 5 | 479 | | tmpStr = IUTF_Utils#IUTF_PrepareStringForOut(cleanText) |
| 5 | 480 | | sprintf text, "Assertion \"%s\" %s in %s%s (%s, line %s)", tmpStr, SelectString(result, "failed", "succeeded"), func, |
| 5 | 481 | | return text |
| 5 | 482 | | End |
| | 483 | |
|
| | 484 | | /// @brief Wrapper function result reporting. This functions should only be called for |
| | 485 | | /// assertions in user test cases. For internal errors use ReportError* functions. |
| | 486 | | /// |
| | 487 | | /// @param result Return value of a check function from `igortest-assertion-checks.ipf` |
| | 488 | | /// @param str Message string |
| | 489 | | /// @param flags Wrapper function `flags` argument |
| | 490 | | /// @param cleanupInfo [optional, default enabled] If set different to zero it will cleanup |
| | 491 | | /// any assertion info message at the end of this function. |
| | 492 | | /// Cleanup is enforced if flags contains the ABORT_FUNCTION flag. |
| | 493 | | /// @param callStack [optional, default current callStack] Can be used to set the callStack |
| | 494 | | /// to a previous recorded callStack (GetRTStackInfo(3)). |
| 355 | 495 | | static Function ReportResults(result, str, flags, [cleanupInfo, callStack]) |
| | 496 | | variable result, flags |
| | 497 | | string str |
| | 498 | | variable cleanupInfo |
| | 499 | | string callStack |
| | 500 | |
|
| 355 | 501 | | variable expectedFailure |
| | 502 | |
|
| 355 | 503 | | cleanupInfo = ParamIsDefault(cleanupInfo) ? 1 : !!cleanupInfo |
| | 504 | |
|
| 355 | 505 | | if(!result) |
| | 506 | |
|
| 5 | 507 | | str = str + ": is false." |
| 5 | 508 | | expectedFailure = IsExpectedFailure() |
| | 509 | |
|
| 5 | 510 | | if(flags & OUTPUT_MESSAGE) |
| 5 | 511 | | if(ParamIsDefault(callStack)) |
| 5 | 512 | | PrintFailInfo(str, expectedFailure, flags & INCREASE_ERROR) |
| 0 | 513 | | else |
| 0 | 514 | | PrintFailInfo(str, expectedFailure, flags & INCREASE_ERROR, callStack = callStack) |
| 5 | 515 | | endif |
| 5 | 516 | | endif |
| | 517 | |
|
| 5 | 518 | | if(!expectedFailure && (flags & ABORT_FUNCTION)) |
| 0 | 519 | | IUTF_Reporting#CleanupInfoMsg() |
| 0 | 520 | | IUTF_Basics#setAbortFlag() |
| 0 | 521 | | Abort |
| 5 | 522 | | endif |
| 355 | 523 | | endif |
| | 524 | |
|
| 355 | 525 | | if(cleanupInfo) |
| 355 | 526 | | IUTF_Reporting#CleanupInfoMsg() |
| 355 | 527 | | endif |
| 355 | 528 | | End |
| | 529 | |
|
| | 530 | | /// @brief Print the given message to the Igor history area and to stdout (IP8 only) |
| | 531 | | /// |
| | 532 | | /// Always use this function if you want to inform the user about something. |
| | 533 | | /// |
| | 534 | | /// @param msg message to be outputted, without trailing end-of-line |
| | 535 | | /// @param allowEmptyLine (optional, default 0 disabled) If set to 1 it will allow to print empty |
| | 536 | | /// strings to the output. The default behavior is to skip printing empty strings. |
| 271 | 537 | | threadsafe static Function IUTF_PrintStatusMessage(msg, [allowEmptyLine]) |
| | 538 | | string msg |
| | 539 | | variable allowEmptyLine |
| | 540 | |
|
| 271 | 541 | | string tmpStr |
| 271 | 542 | | variable len |
| | 543 | |
|
| 271 | 544 | | allowEmptyLine = ParamIsDefault(allowEmptyLine) ? 0 : !!allowEmptyLine |
| | 545 | |
|
| 271 | 546 | | // Copy of IUTF_Tracing#IsNull() and IUTF_Tracing#IsEmpty(). |
| 271 | 547 | | // These functions cannot be used here as in Igor <= 8.0 can no threadsafe function use another |
| 271 | 548 | | // static threadsafe function with the full name when using Independent Modules. |
| 271 | 549 | | len = strlen(msg) |
| 271 | 550 | | if(!allowEmptyLine && (numtype(len) == 2 || len <= 0)) |
| 0 | 551 | | return NaN |
| 271 | 552 | | endif |
| | 553 | |
|
| | 554 | | #if (IgorVersion() >= 9.0) |
| 271 | 555 | | printf "%s\r", msg |
| | 556 | | #elif (IgorVersion() >= 8.0) |
| 0 | 557 | | print/LEN=2500 msg |
| | 558 | | #elif (IgorVersion() >= 7.0) |
| 0 | 559 | | print/LEN=1000 msg |
| | 560 | | #elif (IgorVersion() >= 6.0) |
| 0 | 561 | | print/LEN=400 msg |
| | 562 | | #endif |
| | 563 | |
|
| | 564 | | #if (IgorVersion() >= 9.0) |
| 271 | 565 | | fprintf -1, "%s\r\n", msg |
| | 566 | | #elif (IgorVersion() >= 8.0) |
| 0 | 567 | | tmpStr = IUTF_PrepareStringForOut(msg, maxLen = IP8_PRINTF_STR_MAX_LENGTH - 2) |
| 0 | 568 | | fprintf -1, "%s\r\n", tmpStr |
| | 569 | | #endif |
| 271 | 570 | | End |
| | 571 | |
|
| | 572 | | /// @brief Reports an internal error. |
| | 573 | | /// The execution of the current testcase will NOT be aborted! |
| | 574 | | /// |
| | 575 | | /// @param message The message to output to the history. |
| | 576 | | /// @param incrGlobalErrorCounter (optional, default enabled) Enabled if set to a value different |
| | 577 | | /// to 0. Increases the global error counter. |
| 10 | 578 | | static Function ReportError(message, [incrGlobalErrorCounter]) |
| | 579 | | string message |
| | 580 | | variable incrGlobalErrorCounter |
| | 581 | |
|
| 10 | 582 | | variable currentIndex |
| | 583 | |
|
| 10 | 584 | | incrGlobalErrorCounter = ParamIsDefault(incrGlobalErrorCounter) ? 1 : !!incrGlobalErrorCounter |
| | 585 | |
|
| 10 | 586 | | IUTF_PrintStatusMessage(message) |
| | 587 | |
|
| 10 | 588 | | WAVE/T wvTestCase = IUTF_Reporting#GetTestCaseWave() |
| 10 | 589 | | currentIndex = FindDimLabel(wvTestCase, UTF_COLUMN, "CURRENT") |
| 10 | 590 | | if(currentIndex >= 0) |
| 0 | 591 | | wvTestCase[currentIndex][%STDERR] += message + "\r" |
| 10 | 592 | | endif |
| | 593 | |
|
| 10 | 594 | | if(incrGlobalErrorCounter) |
| 0 | 595 | | incrGlobalError() |
| 10 | 596 | | endif |
| 10 | 597 | | End |
| | 598 | |
|
| | 599 | | /// @brief Reports an internal error that prevents further execution of the current test case. |
| | 600 | | /// The current testcase is always aborted afterwards. |
| | 601 | | /// |
| | 602 | | /// @param message The message to output to the history. |
| | 603 | | /// @param setFlagOnly (optional, default: 0) If set to zero it will call abort at the end of |
| | 604 | | /// the execution. If set to something different to zero it will only set |
| | 605 | | /// the abort flag. |
| 0 | 606 | | static Function ReportErrorAndAbort(message, [setFlagOnly]) |
| | 607 | | string message |
| | 608 | | variable setFlagOnly |
| | 609 | |
|
| 0 | 610 | | setFlagOnly = ParamIsDefault(setFlagOnly) ? 0 : !!setFlagOnly |
| | 611 | |
|
| 0 | 612 | | ReportError("Fatal: " + message, incrGlobalErrorCounter = 1) |
| 0 | 613 | | IUTF_Basics#setAbortFlag() |
| 0 | 614 | | if(!setFlagOnly) |
| 0 | 615 | | Abort |
| 0 | 616 | | endif |
| 0 | 617 | | End |