Chromium Code Reviews| 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 /** | 5 /** |
| 6 * The DartWrapTask generates a Dart wrapper for a test file, that has a | 6 * The DartWrapTask generates a Dart wrapper for a test file, that has a |
| 7 * test Configuration customized for the options specified by the user. | 7 * test Configuration customized for the options specified by the user. |
| 8 */ | 8 */ |
| 9 class DartWrapTask extends PipelineTask { | 9 class DartWrapTask extends PipelineTask { |
| 10 final String _sourceFileTemplate; | 10 final String _sourceFileTemplate; |
| 11 final String _tempDartFileTemplate; | 11 final String _tempDartFileTemplate; |
| 12 | 12 |
| 13 DartWrapTask(this._sourceFileTemplate, this._tempDartFileTemplate); | 13 DartWrapTask(this._sourceFileTemplate, this._tempDartFileTemplate); |
| 14 | 14 |
| 15 void execute(Path testfile, List stdout, List stderr, bool logging, | 15 void execute(Path testfile, List stdout, List stderr, bool logging, |
| 16 Function exitHandler) { | 16 Function exitHandler) { |
| 17 // Get the source test file and canonicalize the path. | 17 // Get the source test file and canonicalize the path. |
| 18 var sourceName = makePathAbsolute( | 18 var sourceName = makePathAbsolute( |
| 19 expandMacros(_sourceFileTemplate, testfile)); | 19 expandMacros(_sourceFileTemplate, testfile)); |
| 20 // Get the destination file. | 20 // Get the destination file. |
| 21 var destFile = expandMacros(_tempDartFileTemplate, testfile); | 21 var destFile = expandMacros(_tempDartFileTemplate, testfile); |
| 22 | 22 |
| 23 var p = new Path(sourceName); | 23 // Get the directory that testrunner lives in; we need it to import |
| 24 if (isLayoutRenderTest(sourceName) || config.generateRenders) { | 24 // support files into the generated scripts. |
| 25 makeLayoutTestWrapper(sourceName, destFile, p.filenameWithoutExtension); | 25 var libDirectory = runnerDirectory; |
|
Siggi Cherem (dart-lang)
2012/09/20 19:56:27
nit: seems you don't need the local variable anymo
gram
2012/09/20 20:08:17
Done.
| |
| 26 exitHandler(0); | 26 |
| 27 return; | 27 if (config.layoutText || config.layoutPixel) { |
| 28 makeLayoutTestWrappers(sourceName, destFile, libDirectory); | |
| 29 } else { | |
| 30 makeNonLayoutTestWrapper(sourceName, destFile, libDirectory); | |
| 28 } | 31 } |
| 32 exitHandler(0); | |
| 33 } | |
| 29 | 34 |
| 30 // Working buffer for the Dart wrapper. | 35 void makeLayoutTestWrappers(String sourceName, |
| 31 StringBuffer sbuf = new StringBuffer(); | 36 String destFile, |
| 37 String libDirectory) { | |
| 32 | 38 |
| 33 // Add the common header stuff. | 39 // Get the name of the directory that has the expectation files |
| 34 sbuf.add(directives(p.filenameWithoutExtension, | 40 // (by stripping .dart suffix from test file path). |
| 35 config.unittestPath, | 41 // Create it if it does not exist. |
| 36 sourceName)); | 42 var expectedDirectory = sourceName.substring(0, sourceName.length - 5); |
| 37 | 43 if (config.regenerate) { |
| 38 // Add the test configuration and determine the action function. | 44 var d = new Directory(expectedDirectory); |
| 39 var action; | 45 if (!d.existsSync()) { |
| 40 if (config.listTests) { | 46 d.createSync(); |
| 41 action = 'listTests'; | |
| 42 sbuf.add(barebonesConfig()); | |
| 43 sbuf.add(listTestsFunction); | |
| 44 sbuf.add(formatListMessageFunction(config.listFormat)); | |
| 45 } else if (config.listGroups) { | |
| 46 sbuf.add(barebonesConfig()); | |
| 47 sbuf.add(listGroupsFunction); | |
| 48 sbuf.add(formatListMessageFunction(config.listFormat)); | |
| 49 action = 'listGroups'; | |
| 50 } else { | |
| 51 | |
| 52 if (config.runInBrowser) { | |
| 53 sbuf.add(browserTestPrintFunction); | |
| 54 sbuf.add(unblockDRTFunction); | |
| 55 } else { | |
| 56 sbuf.add(nonBrowserTestPrintFunction); | |
| 57 sbuf.add(stubUnblockDRTFunction); | |
| 58 } | |
| 59 | |
| 60 if (config.runIsolated) { | |
| 61 sbuf.add(runIsolateTestsFunction); | |
| 62 action = 'runIsolateTests'; | |
| 63 } else { | |
| 64 sbuf.add(runTestsFunction); | |
| 65 action = 'runTests'; | |
| 66 } | |
| 67 | |
| 68 sbuf.add(config.includeTime ? elapsedFunction : stubElapsedFunction); | |
| 69 sbuf.add(config.produceSummary ? | |
| 70 printSummaryFunction : stubPrintSummaryFunction); | |
| 71 | |
| 72 if (config.immediateOutput) { | |
| 73 sbuf.add(printTestResultFunction); | |
| 74 sbuf.add(stubPrintAllTestResultsFunction); | |
| 75 } else { | |
| 76 sbuf.add(stubPrintTestResultFunction); | |
| 77 sbuf.add(printAllTestResultsFunction); | |
| 78 } | |
| 79 | |
| 80 sbuf.add(dumpTestResultFunction); | |
| 81 sbuf.add(formatMessageFunction(config.passFormat, | |
| 82 config.failFormat, | |
| 83 config.errorFormat)); | |
| 84 sbuf.add(testConfig()); | |
| 85 } | |
| 86 | |
| 87 // Add the filter, if applicable. | |
| 88 if (config.filtering) { | |
| 89 if (config.includeFilter.length > 0) { | |
| 90 sbuf.add(filterTestFunction(config.includeFilter, 'true')); | |
| 91 } else { | |
| 92 sbuf.add(filterTestFunction(config.excludeFilter, 'false')); | |
| 93 } | 47 } |
| 94 } | 48 } |
| 95 | 49 |
| 96 // Add the common trailer stuff. | 50 // Create the child file that runs single tests in DRT. |
| 97 sbuf.add(dartMain(sourceName, action, config.filtering)); | 51 var childFile = |
| 52 '${destFile.substring(0, destFile.length - 5)}-child.dart'; | |
| 53 createFile(childFile, layoutTestWrapper(sourceName, libDirectory)); | |
| 98 | 54 |
| 55 // Create the controller file that invokes DRT for each test. | |
| 56 createFile(destFile, | |
| 57 layoutTestControllerWrapper(sourceName, childFile, | |
| 58 expectedDirectory, libDirectory)); | |
| 59 } | |
| 60 | |
| 61 void makeNonLayoutTestWrapper(String sourceName, | |
| 62 String destFile, | |
| 63 String libDirectory) { | |
| 64 var extraImports; | |
| 65 var onDone; | |
| 66 var tprint; | |
| 67 var action; | |
| 68 if (config.runInBrowser) { | |
| 69 extraImports = "#import('dart:html');"; | |
| 70 onDone = "window.postMessage('done', '*')"; | |
| 71 tprint = "query('#console').addText('###\$msg\\n')"; | |
| 72 } else { | |
| 73 extraImports = "#import('dart:io');"; | |
| 74 onDone = "exit(e)"; | |
| 75 tprint = "print('###\$msg')"; | |
| 76 } | |
| 77 if (config.listTests) { | |
| 78 action = 'listTests'; | |
| 79 } else if (config.listGroups) { | |
| 80 action = 'listGroups'; | |
| 81 } else if (config.runIsolated) { | |
| 82 action = 'runIsolateTests'; | |
| 83 } else { | |
| 84 action = 'null'; | |
| 85 } | |
| 86 var wrapper = """ | |
| 87 #library('layout_test'); | |
| 88 $extraImports | |
| 89 #import('${config.unittestPath}', prefix:'unittest'); | |
| 90 #import('$sourceName', prefix: 'test'); | |
| 91 #source('$libDirectory/standard_test_runner.dart'); | |
| 92 | |
| 93 main() { | |
| 94 action = null; | |
| 95 immediate = ${config.immediateOutput}; | |
| 96 includeTime = ${config.includeTime}; | |
| 97 passFormat = '${config.passFormat}'; | |
| 98 failFormat = '${config.failFormat}'; | |
| 99 errorFormat = '${config.errorFormat}'; | |
| 100 listFormat = '${config.listFormat}'; | |
| 101 includeFilters = ${config.includeFilter}; | |
| 102 excludeFilters = ${config.excludeFilter}; | |
| 103 regenerate = ${config.regenerate}; | |
| 104 testfile = '$sourceName'; | |
| 105 summarize = ${config.produceSummary}; | |
| 106 notifyDone = (e) => $onDone; | |
| 107 tprint = (msg) => $tprint; | |
| 108 action = $action; | |
| 109 runTests(test.main); | |
| 110 } | |
| 111 """; | |
| 99 // Save the Dart file. | 112 // Save the Dart file. |
| 100 createFile(destFile, sbuf.toString()); | 113 createFile(destFile, wrapper); |
| 101 exitHandler(0); | |
| 102 } | 114 } |
| 103 | 115 |
| 104 void cleanup(Path testfile, List stdout, List stderr, | 116 void cleanup(Path testfile, List stdout, List stderr, |
| 105 bool logging, bool keepFiles) { | 117 bool logging, bool keepFiles) { |
| 106 deleteFiles([_tempDartFileTemplate], testfile, logging, keepFiles, stdout); | 118 deleteFiles([_tempDartFileTemplate], testfile, logging, keepFiles, stdout); |
| 107 } | 119 } |
| 108 | 120 |
| 109 void makeLayoutTestWrapper(String sourceName, String destFile, | 121 String layoutTestWrapper(String sourceName, String libDirectory) => |
| 110 String libraryName) { | 122 """ |
|
Siggi Cherem (dart-lang)
2012/09/20 19:56:27
nit: I prefer putting this on the previous line.
gram
2012/09/20 20:08:17
Done.
| |
| 111 StringBuffer sbuf = new StringBuffer(); | 123 #library('layout_test'); |
| 112 var cfg = config.unittestPath. | |
| 113 replaceAll('unittest.dart', 'html_layout_config.dart'); | |
| 114 sbuf.add(""" | |
| 115 #library('$libraryName'); | |
| 116 #import('dart:math'); | 124 #import('dart:math'); |
| 117 #import('dart:isolate'); | 125 #import('dart:isolate'); |
| 118 #import('dart:html'); | 126 #import('dart:html'); |
| 127 #import('dart:uri'); | |
| 119 #import('${config.unittestPath}', prefix:'unittest'); | 128 #import('${config.unittestPath}', prefix:'unittest'); |
| 120 #import('$cfg', prefix:'unittest'); | |
| 121 #import('$sourceName', prefix: 'test'); | 129 #import('$sourceName', prefix: 'test'); |
| 122 """); | 130 #source('$libDirectory/layout_test_runner.dart'); |
| 123 // Add the filter, if applicable. | 131 |
| 124 if (config.filtering) { | |
| 125 if (config.includeFilter.length > 0) { | |
| 126 sbuf.add(filterTestFunction(config.includeFilter, 'true')); | |
| 127 } else { | |
| 128 sbuf.add(filterTestFunction(config.excludeFilter, 'false')); | |
| 129 } | |
| 130 } | |
| 131 sbuf.add(""" | |
| 132 main() { | 132 main() { |
| 133 unittest.groupSep = '###'; | 133 includeFilters = ${config.includeFilter}; |
| 134 unittest.useHtmlLayoutConfiguration(); | 134 excludeFilters = ${config.excludeFilter}; |
| 135 unittest.group('', test.main); | 135 runTests(test.main); |
| 136 ${config.filtering ? 'unittest.filterTests(filterTest);' : ''} | 136 } |
| 137 if (window.location.search == '') unittest.runTests(); | 137 """; |
| 138 } | |
| 139 """); | |
| 140 // Save the Dart file. | |
| 141 createFile(destFile, sbuf.toString()); | |
| 142 } | |
| 143 | 138 |
| 144 String directives(String library, String unittest, String sourceName) { | 139 |
| 140 String layoutTestControllerWrapper(String sourceName, String childName, | |
| 141 String expectedDirectory, | |
| 142 String libDirectory) { | |
| 143 StringBuffer sbuf = new StringBuffer(); | |
| 144 var htmlFile = childName.replaceFirst('-child.dart', '.html'); | |
| 145 // Add common prefix. | |
| 145 return """ | 146 return """ |
| 146 #library('$library'); | 147 #library('layout_controller'); |
| 148 #import('dart:uri'); | |
| 149 #import('dart:io'); | |
| 147 #import('dart:math'); | 150 #import('dart:math'); |
| 148 #import('dart:isolate'); | 151 #source('$libDirectory/layout_test_controller.dart'); |
| 149 #import('$unittest', prefix:'unittest'); | |
| 150 #import('$sourceName', prefix: 'test'); | |
| 151 """; | |
| 152 } | |
| 153 | 152 |
| 154 // The core skeleton for a config. Most of the guts is in the | 153 main() { |
| 155 // parameter [body]. | 154 includeTime = ${config.includeTime}; |
| 156 String configuration([String body = '']) { | 155 passFormat = '${config.passFormat}'; |
| 157 return """ | 156 failFormat = '${config.failFormat}'; |
| 158 class TestRunnerConfiguration extends unittest.Configuration { | 157 errorFormat = '${config.errorFormat}'; |
| 159 get name => 'Test runner configuration'; | 158 listFormat = '${config.listFormat}'; |
| 160 get autoStart => false; | 159 drt = '${makePathAbsolute(config.drtPath)}'; |
| 161 $body | 160 regenerate = ${config.regenerate}; |
| 161 sourceDir = '$expectedDirectory'; | |
| 162 testfile = '$sourceName'; | |
| 163 summarize = ${config.produceSummary}; | |
| 164 baseUrl = 'file://$htmlFile'; | |
| 165 run${config.layoutText?'Text':'Pixel'}LayoutTest(0); | |
| 162 } | 166 } |
| 163 """; | 167 """; |
| 164 } | 168 } |
| 165 | |
| 166 // A barebones config, used for listing tests, not running them. | |
| 167 String barebonesConfig() { | |
| 168 return configuration(); | |
| 169 } | |
| 170 | |
| 171 // A more complex config, used for running tests. | |
| 172 String testConfig() { | |
| 173 return configuration(""" | |
| 174 void onTestResult(unittest.TestCase testCase) { | |
| 175 printResult('\$testFile ', testCase); | |
| 176 } | |
| 177 | |
| 178 void onDone(int passed, int failed, int errors, | |
| 179 List<unittest.TestCase> results, | |
| 180 String uncaughtError) { | |
| 181 var success = (passed > 0 && failed == 0 && errors == 0 && | |
| 182 uncaughtError == null); | |
| 183 printResults(testFile, results); | |
| 184 printSummary(testFile, passed, failed, errors, uncaughtError); | |
| 185 unblockDRT(); | |
| 186 } | |
| 187 """); | |
| 188 } | |
| 189 | |
| 190 // The main function, that creates the config, filters the tests if | |
| 191 // necessary, then performs the action (list/run/run-isolated). | |
| 192 String dartMain(String sourceName, String action, bool filter) { | |
| 193 return """ | |
| 194 var testFile = '$sourceName'; | |
| 195 main() { | |
| 196 unittest.groupSep = '###'; | |
| 197 unittest.configure(new TestRunnerConfiguration()); | |
| 198 unittest.group('', test.main); | |
| 199 ${filter ? 'unittest.filterTests(filterTest);' : ''} | |
| 200 $action(); | |
| 201 } | 169 } |
| 202 """; | |
| 203 } | |
| 204 | |
| 205 // For 'printing' when we are in the browser, we add text elements | |
| 206 // to a DOM element with id 'console'. | |
| 207 final String browserTestPrintFunction = """ | |
| 208 #import('dart:html'); | |
| 209 void tprint(msg) { | |
| 210 var pre = query('#console'); | |
| 211 pre.addText('###\$msg\\n'); | |
| 212 } | |
| 213 """; | |
| 214 | |
| 215 // For printing when not in the browser we can just use Dart's print(). | |
| 216 final String nonBrowserTestPrintFunction = """ | |
| 217 void tprint(msg) { | |
| 218 print('###\$msg'); | |
| 219 } | |
| 220 """; | |
| 221 | |
| 222 // A function to give us the elapsed time for a test. | |
| 223 final String elapsedFunction = """ | |
| 224 String elapsed(unittest.TestCase t) { | |
| 225 double duration = t.runningTime.inMilliseconds.toDouble(); | |
| 226 duration /= 1000; | |
| 227 return '\${duration.toStringAsFixed(3)}s '; | |
| 228 } | |
| 229 """; | |
| 230 | |
| 231 // A dummy version of the elapsed function for when the user | |
| 232 // doesn't want test times included. | |
| 233 final String stubElapsedFunction = """ | |
| 234 String elapsed(unittest.TestCase t) { | |
| 235 return ''; | |
| 236 } | |
| 237 """; | |
| 238 | |
| 239 // A function to print the results of a test. | |
| 240 final String dumpTestResultFunction = """ | |
| 241 void dumpTestResult(source, unittest.TestCase t) { | |
| 242 var groupName = '', testName = ''; | |
| 243 var idx = t.description.lastIndexOf('###'); | |
| 244 if (idx >= 0) { | |
| 245 groupName = t.description.substring(0, idx).replaceAll('###', ' '); | |
| 246 testName = t.description.substring(idx+3); | |
| 247 } else { | |
| 248 testName = t.description; | |
| 249 } | |
| 250 var stack = (t.stackTrace == null) ? '' : '\${t.stackTrace} '; | |
| 251 var message = (t.message.length > 0) ? '\$t.message ' : ''; | |
| 252 var duration = elapsed(t); | |
| 253 tprint(formatMessage(source, '\$groupName ', '\$testName ', | |
| 254 duration, t.result, message, stack)); | |
| 255 } | |
| 256 """; | |
| 257 | |
| 258 // A function to print the test summary. | |
| 259 final String printSummaryFunction = """ | |
| 260 void printSummary(String testFile, int passed, int failed, int errors, | |
| 261 String uncaughtError) { | |
| 262 tprint(''); | |
| 263 if (passed == 0 && failed == 0 && errors == 0) { | |
| 264 tprint('\$testFile: No tests found.'); | |
| 265 } else if (failed == 0 && errors == 0 && uncaughtError == null) { | |
| 266 tprint('\$testFile: All \$passed tests passed.'); | |
| 267 } else { | |
| 268 if (uncaughtError != null) { | |
| 269 tprint('\$testFile: Top-level uncaught error: \$uncaughtError'); | |
| 270 } | |
| 271 tprint('\$testFile: \$passed PASSED, \$failed FAILED, \$errors ERRORS'); | |
| 272 } | |
| 273 } | |
| 274 """; | |
| 275 | |
| 276 final String stubPrintSummaryFunction = """ | |
| 277 void printSummary(String testFile, int passed, int failed, int errors, | |
| 278 String uncaughtError) { | |
| 279 } | |
| 280 """; | |
| 281 | |
| 282 // A function to print all test results. | |
| 283 final String printAllTestResultsFunction = """ | |
| 284 void printResults(testfile, List<unittest.TestCase> results) { | |
| 285 for (final testCase in results) { | |
| 286 dumpTestResult('\$testfile ', testCase); | |
| 287 } | |
| 288 } | |
| 289 """; | |
| 290 | |
| 291 final String stubPrintAllTestResultsFunction = """ | |
| 292 void printResults(testfile, List<unittest.TestCase> results) { | |
| 293 } | |
| 294 """; | |
| 295 | |
| 296 // A function to print a single test result. | |
| 297 final String printTestResultFunction = """ | |
| 298 void printResult(testfile, unittest.TestCase testCase) { | |
| 299 dumpTestResult('\$testfile ', testCase); | |
| 300 } | |
| 301 """; | |
| 302 | |
| 303 final String stubPrintTestResultFunction = """ | |
| 304 void printResult(testfile, unittest.TestCase testCase) { | |
| 305 } | |
| 306 """; | |
| 307 | |
| 308 final String unblockDRTFunction = """ | |
| 309 void unblockDRT() { | |
| 310 window.postMessage('done', '*'); | |
| 311 } | |
| 312 """; | |
| 313 | |
| 314 final String stubUnblockDRTFunction = """ | |
| 315 void unblockDRT() { | |
| 316 } | |
| 317 """; | |
| 318 | |
| 319 // A simple format function for listing tests. | |
| 320 String formatListMessageFunction(String format) { | |
| 321 return """ | |
| 322 String formatMessage(filename, groupname, [ testname = '']) { | |
| 323 return '${format}'. | |
| 324 replaceAll('${Macros.testfile}', filename). | |
| 325 replaceAll('${Macros.testGroup}', groupname). | |
| 326 replaceAll('${Macros.testDescription}', testname); | |
| 327 } | |
| 328 """; | |
| 329 } | |
| 330 | |
| 331 // A richer format function for test results. | |
| 332 String formatMessageFunction( | |
| 333 String passFormat, String failFormat, String errorFormat) { | |
| 334 return """ | |
| 335 String formatMessage(filename, groupname, | |
| 336 [ testname = '', testTime = '', result = '', | |
| 337 message = '', stack = '' ]) { | |
| 338 var format = '$errorFormat'; | |
| 339 if (result == 'pass') format = '$passFormat'; | |
| 340 else if (result == 'fail') format = '$failFormat'; | |
| 341 return format. | |
| 342 replaceAll('${Macros.testTime}', testTime). | |
| 343 replaceAll('${Macros.testfile}', filename). | |
| 344 replaceAll('${Macros.testGroup}', groupname). | |
| 345 replaceAll('${Macros.testDescription}', testname). | |
| 346 replaceAll('${Macros.testMessage}', message). | |
| 347 replaceAll('${Macros.testStacktrace}', stack); | |
| 348 } | |
| 349 """; | |
| 350 } | |
| 351 | |
| 352 // A function to list the test groups. | |
| 353 final String listGroupsFunction = """ | |
| 354 listGroups() { | |
| 355 List tests = unittest.testCases; | |
| 356 Map groups = {}; | |
| 357 for (var t in tests) { | |
| 358 var groupName, testName = ''; | |
| 359 var idx = t.description.lastIndexOf('###'); | |
| 360 if (idx >= 0) { | |
| 361 groupName = t.description.substring(0, idx).replaceAll('###', ' '); | |
| 362 if (!groups.containsKey(groupName)) { | |
| 363 groups[groupName] = ''; | |
| 364 } | |
| 365 } | |
| 366 } | |
| 367 for (var g in groups.getKeys()) { | |
| 368 var msg = formatMessage('\$testfile ', '\$g '); | |
| 369 print('###\$msg'); | |
| 370 } | |
| 371 } | |
| 372 """; | |
| 373 | |
| 374 // A function to list the tests. | |
| 375 final String listTestsFunction = """ | |
| 376 listTests() { | |
| 377 List tests = unittest.testCases; | |
| 378 for (var t in tests) { | |
| 379 var groupName, testName = ''; | |
| 380 var idx = t.description.lastIndexOf('###'); | |
| 381 if (idx >= 0) { | |
| 382 groupName = t.description.substring(0, idx).replaceAll('###', ' '); | |
| 383 testName = t.description.substring(idx+3); | |
| 384 } else { | |
| 385 groupName = ''; | |
| 386 testName = t.description; | |
| 387 } | |
| 388 var msg = formatMessage('\$testfile ', '\$groupName ', '\$testName '); | |
| 389 print('###\$msg'); | |
| 390 } | |
| 391 } | |
| 392 """; | |
| 393 | |
| 394 // A function to filter the tests. | |
| 395 String filterTestFunction(List filters, String filterReturnValue) { | |
| 396 StringBuffer sbuf = new StringBuffer(); | |
| 397 sbuf.add('filterTest(t) {\n'); | |
| 398 if (filters != null) { | |
| 399 sbuf.add(' var name = t.description.replaceAll("###", " ");\n'); | |
| 400 for (var f in filters) { | |
| 401 sbuf.add(' if (name.indexOf("$f")>=0) return $filterReturnValue;\n'); | |
| 402 } | |
| 403 sbuf.add(' return !$filterReturnValue;\n'); | |
| 404 } else { | |
| 405 sbuf.add(' return true;\n'); | |
| 406 } | |
| 407 sbuf.add('}\n'); | |
| 408 return sbuf.toString(); | |
| 409 } | |
| 410 | |
| 411 // Code to support running single tests in isolates. | |
| 412 final String runIsolateTestsFunction = """ | |
| 413 class TestRunnerChildConfiguration extends unittest.Configuration { | |
| 414 get name => 'Test runner child configuration'; | |
| 415 get autoStart => false; | |
| 416 | |
| 417 void onDone(int passed, int failed, int errors, | |
| 418 List<unittest.TestCase> results, String uncaughtError) { | |
| 419 unittest.TestCase test = results[0]; | |
| 420 parentPort.send([test.result, test.runningTime.inMilliseconds, | |
| 421 test.message, test.stackTrace]); | |
| 422 } | |
| 423 } | |
| 424 | |
| 425 var parentPort; | |
| 426 runChildTest() { | |
| 427 port.receive((testName, sendport) { | |
| 428 parentPort = sendport; | |
| 429 unittest.configure(new TestRunnerChildConfiguration()); | |
| 430 unittest.groupSep = '###'; | |
| 431 unittest.group('', test.main); | |
| 432 unittest.filterTests(testName); | |
| 433 unittest.runTests(); | |
| 434 }); | |
| 435 } | |
| 436 | |
| 437 var testNum; | |
| 438 var failed; | |
| 439 var errors; | |
| 440 var passed; | |
| 441 | |
| 442 runParentTest() { | |
| 443 var tests = unittest.testCases; | |
| 444 tests[testNum].startTime = new Date.now(); | |
| 445 SendPort childPort = spawnFunction(runChildTest); | |
| 446 childPort.call(tests[testNum].description).then((results) { | |
| 447 var result = results[0]; | |
| 448 var duration = new Duration(milliseconds: results[1]); | |
| 449 var message = results[2]; | |
| 450 var stack = results[3]; | |
| 451 if (result == 'pass') { | |
| 452 tests[testNum].pass(); | |
| 453 ++passed; | |
| 454 } else if (result == 'fail') { | |
| 455 tests[testNum].fail(message, stack); | |
| 456 ++failed; | |
| 457 } else { | |
| 458 tests[testNum].error(message, stack); | |
| 459 ++errors; | |
| 460 } | |
| 461 tests[testNum].runningTime = duration; | |
| 462 ++testNum; | |
| 463 if (testNum < tests.length) { | |
| 464 runParentTest(); | |
| 465 } else { | |
| 466 unittest.config.onDone(passed, failed, errors, | |
| 467 unittest.testCases, null); | |
| 468 } | |
| 469 }); | |
| 470 } | |
| 471 | |
| 472 runIsolateTests() { | |
| 473 testNum = 0; | |
| 474 passed = failed = errors = 0; | |
| 475 runParentTest(); | |
| 476 } | |
| 477 """; | |
| 478 | |
| 479 // Code for running all tests in the normal (non-isolate) way. | |
| 480 final String runTestsFunction = """ | |
| 481 runTests() { | |
| 482 unittest.runTests(); | |
| 483 } | |
| 484 """; | |
| 485 | |
| 486 } | |
| OLD | NEW |