| | 1 | | #pragma TextEncoding="UTF-8" |
| | 2 | | #pragma rtGlobals=3 |
| | 3 | | #pragma rtFunctionErrors=1 |
| | 4 | | #pragma version=1.10 |
| | 5 | | #pragma ModuleName=IUTF_JUnit |
| | 6 | |
|
| | 7 | | /// trim leading and trailing white spaces from |
| | 8 | | /// every line of the given string |
| 10 | 9 | | static Function/S JU_TrimSOUT(input, [listSepStr]) |
| | 10 | | string input |
| | 11 | | string listSepStr |
| | 12 | |
|
| 10 | 13 | | variable i, numItems |
| 10 | 14 | | string output = "" |
| | 15 | |
|
| 10 | 16 | | if(ParamIsDefault(listSepStr)) |
| 10 | 17 | | listSepStr = "\r" |
| 10 | 18 | | endif |
| | 19 | |
|
| 10 | 20 | | numItems = ItemsInList(input, listSepStr) |
| 10 | 21 | | for(i = 0; i < numItems; i += 1) |
| 20 | 22 | | output += TrimString(StringFromList(i, input, listSepStr)) |
| 20 | 23 | | output += listSepStr |
| 20 | 24 | | endfor |
| | 25 | |
|
| 10 | 26 | | return output |
| 10 | 27 | | End |
| | 28 | |
|
| | 29 | | /// Formats the specified TimeStamp in the form yyyy-mm-ddThh:mm:ss in local time |
| 30 | 30 | | static Function/S JU_GetISO8601TimeStamp(localtime) |
| | 31 | | variable localtime |
| | 32 | |
|
| 30 | 33 | | return (Secs2Date(localtime, -2) + "T" + Secs2Time(localtime, 3)) |
| 30 | 34 | | End |
| | 35 | |
|
| 5 | 36 | | static Function/S JU_AssertionOut(assertionIndex) |
| | 37 | | variable assertionIndex |
| | 38 | |
|
| 5 | 39 | | string out, message, type, context, severity |
| 5 | 40 | | variable i, startIndex, endIndex |
| | 41 | |
|
| 5 | 42 | | WAVE/T wvAssertion = IUTF_Reporting#GetTestAssertionWave() |
| 5 | 43 | | WAVE/T wvInfo = IUTF_Reporting#GetTestInfoWave() |
| | 44 | |
|
| 5 | 45 | | if(!CmpStr(IUTF_SEVERITY_WARN, wvAssertion[assertionIndex][%SEVERITY])) |
| 5 | 46 | | // skip JUnit output for warning severity |
| 5 | 47 | | return "" |
| 0 | 48 | | endif |
| | 49 | |
|
| 0 | 50 | | startIndex = str2num(wvAssertion[assertionIndex][%CHILD_START]) |
| 0 | 51 | | endIndex = str2num(wvAssertion[assertionIndex][%CHILD_END]) |
| 0 | 52 | | context = "" |
| 0 | 53 | | for(i = startIndex; i < endIndex; i += 1) |
| 0 | 54 | | context += "\t\t\t\tInfo: " + wvInfo[i][%MESSAGE] + "\n" |
| 0 | 55 | | endfor |
| | 56 | |
|
| 0 | 57 | | message = IUTF_Utils_XML#ToXMLCharacters(wvAssertion[assertionIndex][%MESSAGE]) |
| 0 | 58 | | type = IUTF_Utils_XML#ToXMLCharacters(wvAssertion[assertionIndex][%TYPE]) |
| 0 | 59 | | // we are outputing everything as error to keep the same behavior as older versions of IUTF |
| | 60 | |
|
| 0 | 61 | | // strswitch(wvAssertion[i][%TYPE]) |
| 0 | 62 | | // case IUTF_STATUS_FAIL: |
| 0 | 63 | | // s += "\t\t\t<failure message=\"" + message + "\" type=\"" + type + "\"></failure>\n" |
| 0 | 64 | | // break |
| 0 | 65 | | // case IUTF_STATUS_ERROR: |
| 0 | 66 | | out = "\t\t\t<error message=\"" + message + "\" type=\"" + type + "\">\n" |
| 0 | 67 | | out += context |
| 0 | 68 | | out += "\t\t\t</error>\n" |
| 0 | 69 | | // break |
| 0 | 70 | | // default: |
| 0 | 71 | | // break |
| 0 | 72 | | // endswitch |
| | 73 | |
|
| 0 | 74 | | return out |
| 5 | 75 | | End |
| | 76 | |
|
| | 77 | | /// Evaluates last Test Case and returns JUNIT XML Output from Test Case |
| 80 | 78 | | static Function/S JU_CaseToOut(testSuiteIndex, testCaseIndex) |
| | 79 | | variable testSuiteIndex, testCaseIndex |
| | 80 | |
|
| 80 | 81 | | string out, name, classname, message, type |
| 80 | 82 | | variable i, timeTaken, startIndex, endIndex |
| | 83 | |
|
| 80 | 84 | | variable skip = 0 |
| | 85 | |
|
| 80 | 86 | | WAVE/T wvTestSuite = IUTF_Reporting#GetTestSuiteWave() |
| 80 | 87 | | WAVE/T wvTestCase = IUTF_Reporting#GetTestCaseWave() |
| 80 | 88 | | WAVE/T wvAssertion = IUTF_Reporting#GetTestAssertionWave() |
| | 89 | |
|
| 80 | 90 | | classname = IUTF_Utils_XML#ToXMLToken(IUTF_Utils_XML#ToXMLCharacters(wvTestCase[testCaseIndex][%NAME])) |
| 80 | 91 | | name = IUTF_Utils_XML#ToXMLToken(IUTF_Utils_XML#ToXMLCharacters(wvTestSuite[testSuiteIndex][%PROCEDURENAME])) |
| 80 | 92 | | sprintf name, "%s in %s (%d)", classname, name, testCaseIndex |
| 80 | 93 | | timeTaken = str2num(wvTestCase[testCaseIndex][%ENDTIME]) - str2num(wvTestCase[testCaseIndex][%STARTTIME]) |
| | 94 | |
|
| 80 | 95 | | sprintf out, "\t\t<testcase name=\"%s\" classname=\"%s\" time=\"%.3f\">\n", name, classname, timeTaken |
| 80 | 96 | | if(!CmpStr(IUTF_STATUS_SKIP, wvTestCase[testCaseIndex][%STATUS])) |
| 0 | 97 | | skip = 1 |
| 80 | 98 | | endif |
| 80 | 99 | | if(!CmpStr(IUTF_STATUS_RETRY, wvTestCase[testCaseIndex][%STATUS])) |
| 0 | 100 | | skip = 1 |
| 80 | 101 | | endif |
| | 102 | |
|
| 80 | 103 | | if(skip) |
| 0 | 104 | | out += "\t\t\t<skipped/>\n" |
| 80 | 105 | | else |
| 80 | 106 | | startIndex = str2num(wvTestCase[testCaseIndex][%CHILD_START]) |
| 80 | 107 | | endIndex = str2num(wvTestCase[testCaseIndex][%CHILD_END]) |
| 80 | 108 | | for(i = startIndex; i < endIndex; i += 1) |
| 5 | 109 | | out += JU_AssertionOut(i) |
| 5 | 110 | | endfor |
| 80 | 111 | | endif |
| | 112 | |
|
| 80 | 113 | | message = wvTestCase[testCaseIndex][%STDOUT] |
| 80 | 114 | | if(!IUTF_Utils#IsEmpty(message)) |
| 5 | 115 | | out += "\t\t<system-out>" + IUTF_Utils_XML#ToXMLCharacters(JU_TrimSOUT(message)) + "</system-out>\n" |
| 80 | 116 | | endif |
| 80 | 117 | | message = wvTestCase[testCaseIndex][%STDERR] |
| 80 | 118 | | if(!IUTF_Utils#IsEmpty(message)) |
| 5 | 119 | | out += "\t\t<system-err>" + IUTF_Utils_XML#ToXMLCharacters(message) + "</system-err>\n" |
| 80 | 120 | | endif |
| | 121 | |
|
| 80 | 122 | | return (out + "\t\t</testcase>\n") |
| 80 | 123 | | End |
| | 124 | |
|
| | 125 | | /// Converts the reference time string that is stored in the result storage waves into an absolute |
| | 126 | | /// time which counts the seconds since 1904-01-01. |
| 30 | 127 | | static Function JU_ToAbsoluteTime(str) |
| | 128 | | string str |
| | 129 | |
|
| 30 | 130 | | // Seconds since the start of the computer |
| 30 | 131 | | variable num = str2num(str) |
| | 132 | |
|
| 30 | 133 | | // This is the difference between two time measuring systems. DateTime is counting the seconds |
| 30 | 134 | | // since 1904-01-01 and StopMSTimer(-2) * IUTF_MICRO_TO_ONE since the start of the computer. |
| 30 | 135 | | // We need this difference as num is a time stamp in the seconds time system and need to |
| 30 | 136 | | // convert it to the first one. |
| 30 | 137 | | // During test executing runtime it is very unlikely that this difference change and therefore |
| 30 | 138 | | // can be treaded as constant. |
| 30 | 139 | | variable difference = DateTime - StopMSTimer(-2) * IUTF_MICRO_TO_ONE |
| | 140 | |
|
| 30 | 141 | | // Seconds since 1904-01-01 |
| 30 | 142 | | return num + difference |
| 30 | 143 | | End |
| | 144 | |
|
| | 145 | | /// Returns combined JUNIT XML Output for TestSuite consisting of all TestCases run in Suite |
| 30 | 146 | | static Function/S JU_ToTestSuiteString(testRunIndex, testSuiteIndex) |
| | 147 | | variable testRunIndex, testSuiteIndex |
| | 148 | |
|
| 30 | 149 | | string out, format, s |
| 30 | 150 | | string package, name, timestamp, hostname, tests, failures, errors, skipped |
| 30 | 151 | | variable i, timeTaken, childStart, childEnd |
| | 152 | |
|
| 30 | 153 | | WAVE/T wvTestRun = IUTF_Reporting#GetTestRunWave() |
| 30 | 154 | | WAVE/T wvTestSuite = IUTF_Reporting#GetTestSuiteWave() |
| | 155 | |
|
| 30 | 156 | | package = IUTF_Utils_XML#ToXMLToken(IUTF_Utils_XML#ToXMLCharacters(wvTestSuite[testSuiteIndex][%PROCEDURENAME])) |
| 30 | 157 | | name = IUTF_Utils_XML#ToXMLToken(IUTF_Utils_XML#ToXMLCharacters(wvTestSuite[testSuiteIndex][%PROCEDURENAME])) |
| 30 | 158 | | timestamp = JU_GetISO8601TimeStamp(JU_ToAbsoluteTime(wvTestSuite[testSuiteIndex][%STARTTIME])) |
| 30 | 159 | | hostname = IUTF_Utils_XML#ToXMLToken(IUTF_Utils_XML#ToXMLCharacters(wvTestRun[testRunIndex][%HOSTNAME])) |
| 30 | 160 | | tests = wvTestSuite[testSuiteIndex][%NUM_TESTS] |
| 30 | 161 | | failures = "0" // the number of failures are not tracked right now |
| 30 | 162 | | errors = wvTestSuite[testSuiteIndex][%NUM_ERROR] |
| 30 | 163 | | skipped = wvTestSuite[testSuiteIndex][%NUM_SKIPPED] |
| 30 | 164 | | timeTaken = str2num(wvTestSuite[testSuiteIndex][%ENDTIME]) - str2num(wvTestSuite[testSuiteIndex][%STARTTIME]) |
| | 165 | |
|
| 30 | 166 | | format = "\t<testsuite package=\"%s\" id=\"%d\" name=\"%s\" timestamp=\"%s\" hostname=\"%s\" tests=\"%s\" failures=\"% |
| 30 | 167 | | sprintf out, format, package, testSuiteIndex, name, timestamp, hostname, tests, failures, errors, skipped, timeTaken |
| | 168 | |
|
| 30 | 169 | | out += "\t\t<properties>\n" |
| 30 | 170 | | out += JU_ToPropertyString("User", wvTestRun[testRunIndex][%USERNAME]) |
| 30 | 171 | | out += JU_ToPropertyString("System", JU_NicifyList(wvTestRun[testRunIndex][%SYSTEMINFO])) |
| 30 | 172 | | out += JU_ToPropertyString("Experiment", wvTestRun[testRunIndex][%EXPERIMENT]) |
| 30 | 173 | | out += JU_ToPropertyString("IUTFversion", wvTestRun[testRunIndex][%VERSION]) |
| 30 | 174 | | out += JU_ToPropertyString("IgorInfo", JU_NicifyList(wvTestRun[testRunIndex][%IGORINFO])) |
| 30 | 175 | | out += "\t\t</properties>\n" |
| | 176 | |
|
| 30 | 177 | | childStart = str2num(wvTestSuite[testSuiteIndex][%CHILD_START]) |
| 30 | 178 | | childEnd = str2num(wvTestSuite[testSuiteIndex][%CHILD_END]) |
| 30 | 179 | | for(i = childStart; i < childEnd; i += 1) |
| 80 | 180 | | out += JU_CaseToOut(testSuiteIndex, i) |
| 80 | 181 | | endfor |
| | 182 | |
|
| 30 | 183 | | s = wvTestSuite[testSuiteIndex][%STDOUT] |
| 30 | 184 | | if(!IUTF_Utils#IsEmpty(s)) |
| 5 | 185 | | out += "\t\t<system-out>" + IUTF_Utils_XML#ToXMLCharacters(JU_TrimSOUT(s)) + "</system-out>\n" |
| 30 | 186 | | endif |
| 30 | 187 | | s = wvTestSuite[testSuiteIndex][%STDERR] |
| 30 | 188 | | if(!IUTF_Utils#IsEmpty(s)) |
| 5 | 189 | | out += "\t\t<system-err>" + IUTF_Utils_XML#ToXMLCharacters(s) + "</system-err>\n" |
| 30 | 190 | | endif |
| | 191 | |
|
| 30 | 192 | | return (out + "\t</testsuite>\n") |
| 30 | 193 | | End |
| | 194 | |
|
| 150 | 195 | | static Function/S JU_ToPropertyString(name, value) |
| | 196 | | string name, value |
| | 197 | |
|
| 150 | 198 | | string s |
| | 199 | |
|
| 150 | 200 | | if(IUTF_Utils#IsEmpty(value)) |
| 0 | 201 | | return "" |
| 150 | 202 | | endif |
| | 203 | |
|
| 150 | 204 | | name = IUTF_Utils_XML#ToXMLToken(IUTF_Utils_XML#ToXMLCharacters(name)) |
| 150 | 205 | | value = IUTF_Utils_XML#ToXMLCharacters(value) |
| 150 | 206 | | sprintf s, "\t\t\t<property name=\"%s\" value=\"%s\"/>\n", name, value |
| | 207 | |
|
| 150 | 208 | | return s |
| 150 | 209 | | End |
| | 210 | |
|
| | 211 | | /// Replaces all chars >= 0x80 by "?" in str and returns the resulting string |
| 0 | 212 | | static Function/S JU_UTF8Filter(str) |
| | 213 | | string str |
| | 214 | |
|
| 0 | 215 | | string sret |
| 0 | 216 | | variable i, len |
| | 217 | |
|
| 0 | 218 | | sret = "" |
| 0 | 219 | | len = strlen(str) |
| 0 | 220 | | for(i = 0; i < len; i += 1) |
| 0 | 221 | | if(char2num(str[i]) < 0) |
| 0 | 222 | | sret += "?" |
| 0 | 223 | | else |
| 0 | 224 | | sret += str[i] |
| 0 | 225 | | endif |
| 0 | 226 | | endfor |
| 0 | 227 | | return sret |
| 0 | 228 | | End |
| | 229 | |
|
| | 230 | | /// Writes JUNIT XML output to derived file name |
| 5 | 231 | | static Function JU_WriteOutput() |
| 5 | 232 | | variable fnum, i, childStart, childEnd |
| 5 | 233 | | string out, juFileName, msg |
| | 234 | |
|
| 5 | 235 | | WAVE/T wvTestRun = IUTF_Reporting#GetTestRunWave() |
| 5 | 236 | | childStart = str2num(wvTestRun[%CURRENT][%CHILD_START]) |
| 5 | 237 | | childEnd = str2num(wvTestRun[%CURRENT][%CHILD_END]) |
| | 238 | |
|
| 5 | 239 | | out = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<testsuites>\n" |
| 5 | 240 | | for(i = childStart; i < childEnd; i += 1) |
| 30 | 241 | | out += JU_ToTestSuiteString(0, i) |
| 30 | 242 | | endfor |
| 5 | 243 | | out += "</testsuites>\n" |
| | 244 | | #if (IgorVersion() >= 7.0) |
| 5 | 245 | | // UTF-8 support |
| | 246 | | #else |
| 0 | 247 | | out = JU_UTF8Filter(out) |
| | 248 | | #endif |
| | 249 | |
|
| 5 | 250 | | IUTF_Utils_XML#WriteXML("JU_", out) |
| 5 | 251 | | End |
| | 252 | |
|
| | 253 | | /// Add a EOL (`\r`) after every element of a `;` separated list. |
| | 254 | | /// Intended for better readability. |
| 60 | 255 | | static Function/S JU_NicifyList(list) |
| | 256 | | string list |
| | 257 | |
|
| 60 | 258 | | list = RemoveEnding(list, ";") |
| | 259 | |
|
| 60 | 260 | | if(IUTF_Utils#IsEmpty(list)) |
| 0 | 261 | | return list |
| 60 | 262 | | endif |
| | 263 | |
|
| 60 | 264 | | return ReplaceString(";", list, ";\r") |
| 60 | 265 | | End |