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