| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /** Whether to include elapsed time. */ |
| 6 bool includeTime; |
| 7 |
| 8 /** Whether to regenerate layout test files. */ |
| 9 bool regenerate; |
| 10 |
| 11 /** Whether to output test summary. */ |
| 12 bool summarize; |
| 13 |
| 14 /** Whether to print results immediately as they come in. */ |
| 15 bool immediate; |
| 16 |
| 17 /** Format strings to use for test result messages. */ |
| 18 String listFormat, passFormat, failFormat, errorFormat; |
| 19 |
| 20 /** Path of the running test file. */ |
| 21 String testfile; |
| 22 |
| 23 /** The filters must be set by the caller. */ |
| 24 List includeFilters; |
| 25 List excludeFilters; |
| 26 |
| 27 /** The print function to use. */ |
| 28 Function tprint; |
| 29 |
| 30 /** A callback function to notify the caller we are done. */ |
| 31 Function notifyDone; |
| 32 |
| 33 /** The action function to use. */ |
| 34 Function action; |
| 35 |
| 36 class Macros { |
| 37 static const String testTime = '<TIME>'; |
| 38 static const String testfile = '<FILENAME>'; |
| 39 static const String testGroup = '<GROUPNAME>'; |
| 40 static const String testDescription = '<TESTNAME>'; |
| 41 static const String testMessage = '<MESSAGE>'; |
| 42 static const String testStacktrace = '<STACK>'; |
| 43 } |
| 44 |
| 45 class TestRunnerConfiguration extends unittest.Configuration { |
| 46 get name => 'Minimal test runner configuration'; |
| 47 get autoStart => false; |
| 48 |
| 49 String formatMessage(filename, groupname, |
| 50 [ testname = '', testTime = '', result = '', |
| 51 message = '', stack = '' ]) { |
| 52 var format = errorFormat; |
| 53 if (result == 'pass') format = passFormat; |
| 54 else if (result == 'fail') format = failFormat; |
| 55 return format. |
| 56 replaceAll(Macros.testTime, testTime). |
| 57 replaceAll(Macros.testfile, filename). |
| 58 replaceAll(Macros.testGroup, groupname). |
| 59 replaceAll(Macros.testDescription, testname). |
| 60 replaceAll(Macros.testMessage, message). |
| 61 replaceAll(Macros.testStacktrace, stack); |
| 62 } |
| 63 |
| 64 String elapsed(unittest.TestCase t) { |
| 65 if (includeTime) { |
| 66 double duration = t.runningTime.inMilliseconds.toDouble(); |
| 67 duration /= 1000; |
| 68 return '${duration.toStringAsFixed(3)}s '; |
| 69 } else { |
| 70 return ''; |
| 71 } |
| 72 } |
| 73 |
| 74 void dumpTestResult(source, unittest.TestCase t) { |
| 75 var groupName = '', testName = ''; |
| 76 var idx = t.description.lastIndexOf('###'); |
| 77 if (idx >= 0) { |
| 78 groupName = t.description.substring(0, idx).replaceAll('###', ' '); |
| 79 testName = t.description.substring(idx+3); |
| 80 } else { |
| 81 testName = t.description; |
| 82 } |
| 83 var stack = (t.stackTrace == null) ? '' : '${t.stackTrace} '; |
| 84 var message = (t.message.length > 0) ? '${t.message} ' : ''; |
| 85 var duration = elapsed(t); |
| 86 tprint(formatMessage(source, '$groupName ', '$testName ', |
| 87 duration, t.result, message, stack)); |
| 88 } |
| 89 |
| 90 void onTestResult(unittest.TestCase testCase) { |
| 91 if (immediate) { |
| 92 dumpTestResult('$testfile ', testCase); |
| 93 } |
| 94 } |
| 95 |
| 96 void printSummary(int passed, int failed, int errors, |
| 97 [String uncaughtError = '']) { |
| 98 tprint(''); |
| 99 if (passed == 0 && failed == 0 && errors == 0) { |
| 100 tprint('$testfile: No tests found.'); |
| 101 } else if (failed == 0 && errors == 0 && uncaughtError == null) { |
| 102 tprint('$testfile: All $passed tests passed.'); |
| 103 } else { |
| 104 if (uncaughtError != null) { |
| 105 tprint('$testfile: Top-level uncaught error: $uncaughtError'); |
| 106 } |
| 107 tprint('$testfile: $passed PASSED, $failed FAILED, $errors ERRORS'); |
| 108 } |
| 109 } |
| 110 |
| 111 void onDone(int passed, int failed, int errors, |
| 112 List<unittest.TestCase> results, |
| 113 String uncaughtError) { |
| 114 var success = (passed > 0 && failed == 0 && errors == 0 && |
| 115 uncaughtError == null); |
| 116 if (!immediate) { |
| 117 for (final testCase in results) { |
| 118 dumpTestResult('$testfile ', testCase); |
| 119 } |
| 120 } |
| 121 if (summarize) { |
| 122 printSummary(passed, failed, errors, uncaughtError); |
| 123 } |
| 124 if (notifyDone != null) { |
| 125 notifyDone(success ? 0 : -1); |
| 126 } |
| 127 } |
| 128 } |
| 129 |
| 130 // Support for listing tests and groups. We use a minimal config. |
| 131 class MinimalTestRunnerConfiguration extends unittest.Configuration { |
| 132 get name => 'Minimal test runner configuration'; |
| 133 get autoStart => false; |
| 134 } |
| 135 |
| 136 String formatListMessage(filename, groupname, [ testname = '']) { |
| 137 return listFormat. |
| 138 replaceAll(Macros.testfile, filename). |
| 139 replaceAll(Macros.testGroup, groupname). |
| 140 replaceAll(Macros.testDescription, testname); |
| 141 } |
| 142 |
| 143 listGroups() { |
| 144 List tests = unittest.testCases; |
| 145 Map groups = {}; |
| 146 for (var t in tests) { |
| 147 var groupName, testName = ''; |
| 148 var idx = t.description.lastIndexOf('###'); |
| 149 if (idx >= 0) { |
| 150 groupName = t.description.substring(0, idx).replaceAll('###', ' '); |
| 151 if (!groups.containsKey(groupName)) { |
| 152 groups[groupName] = ''; |
| 153 } |
| 154 } |
| 155 } |
| 156 for (var g in groups.getKeys()) { |
| 157 var msg = formatListMessage('$testfile ', '$g '); |
| 158 print('###$msg'); |
| 159 } |
| 160 } |
| 161 |
| 162 listTests() { |
| 163 List tests = unittest.testCases; |
| 164 for (var t in tests) { |
| 165 var groupName, testName = ''; |
| 166 var idx = t.description.lastIndexOf('###'); |
| 167 if (idx >= 0) { |
| 168 groupName = t.description.substring(0, idx).replaceAll('###', ' '); |
| 169 testName = t.description.substring(idx+3); |
| 170 } else { |
| 171 groupName = ''; |
| 172 testName = t.description; |
| 173 } |
| 174 var msg = formatListMessage('$testfile ', '$groupName ', '$testName '); |
| 175 print('###$msg'); |
| 176 } |
| 177 } |
| 178 |
| 179 // Support for running in isolates. |
| 180 |
| 181 class TestRunnerChildConfiguration extends unittest.Configuration { |
| 182 get name => 'Test runner child configuration'; |
| 183 get autoStart => false; |
| 184 |
| 185 void onDone(int passed, int failed, int errors, |
| 186 List<unittest.TestCase> results, String uncaughtError) { |
| 187 unittest.TestCase test = results[0]; |
| 188 parentPort.send([test.result, test.runningTime.inMilliseconds, |
| 189 test.message, test.stackTrace]); |
| 190 } |
| 191 } |
| 192 |
| 193 var parentPort; |
| 194 var childTestMain; |
| 195 runChildTest() { |
| 196 port.receive((testName, sendport) { |
| 197 parentPort = sendport; |
| 198 unittest.configure(new TestRunnerChildConfiguration()); |
| 199 unittest.groupSep = '###'; |
| 200 unittest.group('', childTestMain); |
| 201 unittest.filterTests(testName); |
| 202 unittest.runTests(); |
| 203 }); |
| 204 } |
| 205 |
| 206 var testNum; |
| 207 var failed; |
| 208 var errors; |
| 209 var passed; |
| 210 |
| 211 runParentTest() { |
| 212 var tests = unittest.testCases; |
| 213 tests[testNum].startTime = new Date.now(); |
| 214 SendPort childPort = spawnFunction(runChildTest); |
| 215 childPort.call(tests[testNum].description).then((results) { |
| 216 var result = results[0]; |
| 217 var duration = new Duration(milliseconds: results[1]); |
| 218 var message = results[2]; |
| 219 var stack = results[3]; |
| 220 if (result == 'pass') { |
| 221 tests[testNum].pass(); |
| 222 ++passed; |
| 223 } else if (result == 'fail') { |
| 224 tests[testNum].fail(message, stack); |
| 225 ++failed; |
| 226 } else { |
| 227 tests[testNum].error(message, stack); |
| 228 ++errors; |
| 229 } |
| 230 tests[testNum].runningTime = duration; |
| 231 ++testNum; |
| 232 if (testNum < tests.length) { |
| 233 runParentTest(); |
| 234 } else { |
| 235 unittest.config.onDone(passed, failed, errors, |
| 236 unittest.testCases, null); |
| 237 } |
| 238 }); |
| 239 } |
| 240 |
| 241 runIsolateTests() { |
| 242 testNum = 0; |
| 243 passed = failed = errors = 0; |
| 244 runParentTest(); |
| 245 } |
| 246 |
| 247 // Main |
| 248 |
| 249 filterTest(t) { |
| 250 var name = t.description.replaceAll("###", " "); |
| 251 if (includeFilters.length > 0) { |
| 252 for (var f in includeFilters) { |
| 253 if (name.indexOf(f) >= 0) return true; |
| 254 } |
| 255 return false; |
| 256 } else if (excludeFilters.length > 0) { |
| 257 for (var f in excludeFilters) { |
| 258 if (name.indexOf(f) >= 0) return false; |
| 259 } |
| 260 return true; |
| 261 } else { |
| 262 return true; |
| 263 } |
| 264 } |
| 265 |
| 266 runTests(testMain) { |
| 267 childTestMain = testMain; |
| 268 unittest.groupSep = '###'; |
| 269 unittest.configure(new TestRunnerConfiguration()); |
| 270 unittest.group('', testMain); |
| 271 // Do any user-specified test filtering. |
| 272 unittest.filterTests(filterTest); |
| 273 if (action == null) { |
| 274 unittest.runTests(); |
| 275 } else { |
| 276 action(); |
| 277 } |
| 278 } |
| OLD | NEW |