| 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 * Classes and methods for enumerating and preparing tests. | 6 * Classes and methods for enumerating and preparing tests. |
| 7 * | 7 * |
| 8 * This library includes: | 8 * This library includes: |
| 9 * | 9 * |
| 10 * - Creating tests by listing all the Dart files in certain directories, | 10 * - Creating tests by listing all the Dart files in certain directories, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 typedef void CreateTest(Path filePath, | 33 typedef void CreateTest(Path filePath, |
| 34 bool hasCompileError, | 34 bool hasCompileError, |
| 35 bool hasRuntimeError, | 35 bool hasRuntimeError, |
| 36 {bool isNegativeIfChecked, | 36 {bool isNegativeIfChecked, |
| 37 bool hasFatalTypeErrors, | 37 bool hasFatalTypeErrors, |
| 38 Set<String> multitestOutcome}); | 38 Set<String> multitestOutcome}); |
| 39 | 39 |
| 40 typedef void VoidFunction(); | 40 typedef void VoidFunction(); |
| 41 | 41 |
| 42 /** | 42 /** |
| 43 * Calls [function] asynchronously. Returns a future that completes with the |
| 44 * result of the function. If the function is `null`, returns a future that |
| 45 * completes immediately with `null`. |
| 46 */ |
| 47 Future asynchronously(function()) { |
| 48 if (function == null) return new Future.immediate(null); |
| 49 |
| 50 var completer = new Completer(); |
| 51 new Timer(0, (_) { |
| 52 completer.complete(function()); |
| 53 }); |
| 54 |
| 55 return completer.future; |
| 56 } |
| 57 |
| 58 /** A completer that waits until all added [Future]s complete. */ |
| 59 // TODO(rnystrom): Copied from web_components. Remove from here when it gets |
| 60 // added to dart:core. (See #6626.) |
| 61 class FutureGroup { |
| 62 const _FINISHED = -1; |
| 63 int _pending = 0; |
| 64 Completer<List> _completer = new Completer<List>(); |
| 65 final List<Future> futures = <Future>[]; |
| 66 |
| 67 /** |
| 68 * Wait for [task] to complete (assuming this barrier has not already been |
| 69 * marked as completed, otherwise you'll get an exception indicating that a |
| 70 * future has already been completed). |
| 71 */ |
| 72 void add(Future task) { |
| 73 if (_pending == _FINISHED) { |
| 74 throw new FutureAlreadyCompleteException(); |
| 75 } |
| 76 _pending++; |
| 77 futures.add(task); |
| 78 task.handleException( |
| 79 (e) => _completer.completeException(e, task.stackTrace)); |
| 80 task.then((_) { |
| 81 _pending--; |
| 82 if (_pending == 0) { |
| 83 _pending = _FINISHED; |
| 84 _completer.complete(futures); |
| 85 } |
| 86 }); |
| 87 } |
| 88 |
| 89 Future<List> get future => _completer.future; |
| 90 } |
| 91 |
| 92 /** |
| 43 * A TestSuite represents a collection of tests. It creates a [TestCase] | 93 * A TestSuite represents a collection of tests. It creates a [TestCase] |
| 44 * object for each test to be run, and passes the test cases to a callback. | 94 * object for each test to be run, and passes the test cases to a callback. |
| 45 * | 95 * |
| 46 * Most TestSuites represent a directory or directory tree containing tests, | 96 * Most TestSuites represent a directory or directory tree containing tests, |
| 47 * and a status file containing the expected results when these tests are run. | 97 * and a status file containing the expected results when these tests are run. |
| 48 */ | 98 */ |
| 49 abstract class TestSuite { | 99 abstract class TestSuite { |
| 100 final Map configuration; |
| 101 final String suiteName; |
| 102 |
| 103 TestSuite(this.configuration, this.suiteName); |
| 104 |
| 105 /** |
| 106 * The output directory for this suite's configuration. |
| 107 */ |
| 108 String get buildDir { |
| 109 var mode = (configuration['mode'] == 'debug') ? 'Debug' : 'Release'; |
| 110 var arch = configuration['arch'].toUpperCase(); |
| 111 return "${TestUtils.outputDir(configuration)}$mode$arch"; |
| 112 } |
| 113 |
| 114 /** |
| 115 * The path to the compiler for this suite's configuration. Returns `null` if |
| 116 * no compiler should be used. |
| 117 */ |
| 118 String get compilerPath { |
| 119 if (configuration['compiler'] == 'none') { |
| 120 return null; // No separate compiler for dartium tests. |
| 121 } |
| 122 var name = '$buildDir/${compilerName}'; |
| 123 if (!(new File(name)).existsSync() && !configuration['list']) { |
| 124 throw "Executable '$name' does not exist"; |
| 125 } |
| 126 return name; |
| 127 } |
| 128 |
| 129 /** |
| 130 * The name of the compiler for this suite's configuration. Throws an error |
| 131 * if the configuration does not use a compiler. |
| 132 */ |
| 133 String get compilerName { |
| 134 switch (configuration['compiler']) { |
| 135 case 'dartc': |
| 136 case 'dart2js': |
| 137 case 'dart2dart': |
| 138 return executableName; |
| 139 default: |
| 140 throw "Unknown compiler for: ${configuration['compiler']}"; |
| 141 } |
| 142 } |
| 143 |
| 144 /** |
| 145 * The file name of the executable used to run this suite's tests. |
| 146 */ |
| 147 String get executableName { |
| 148 String suffix = getExecutableSuffix(configuration['compiler']); |
| 149 switch (configuration['compiler']) { |
| 150 case 'none': |
| 151 return 'dart$suffix'; |
| 152 case 'dartc': |
| 153 return 'analyzer/bin/dart_analyzer$suffix'; |
| 154 case 'dart2js': |
| 155 case 'dart2dart': |
| 156 var prefix = ''; |
| 157 if (configuration['use_sdk']) { |
| 158 prefix = 'dart-sdk/bin/'; |
| 159 } |
| 160 if (configuration['host_checked']) { |
| 161 // The script dart2js_developer is not in the SDK. |
| 162 return 'dart2js_developer$suffix'; |
| 163 } else { |
| 164 return '${prefix}dart2js$suffix'; |
| 165 } |
| 166 break; |
| 167 default: |
| 168 throw "Unknown executable for: ${configuration['compiler']}"; |
| 169 } |
| 170 } |
| 171 |
| 172 /** |
| 173 * The file name of the d8 executable. |
| 174 */ |
| 175 String get d8FileName { |
| 176 var suffix = getExecutableSuffix('d8'); |
| 177 var d8 = '$buildDir/d8$suffix'; |
| 178 TestUtils.ensureExists(d8, configuration); |
| 179 return d8; |
| 180 } |
| 181 |
| 182 String get dartShellFileName { |
| 183 var name = configuration['dart']; |
| 184 if (name == '') { |
| 185 name = '$buildDir/$executableName'; |
| 186 } |
| 187 TestUtils.ensureExists(name, configuration); |
| 188 return name; |
| 189 } |
| 190 |
| 191 String get jsShellFileName { |
| 192 var executableSuffix = getExecutableSuffix('jsshell'); |
| 193 var executable = 'jsshell$executableSuffix'; |
| 194 var jsshellDir = '${TestUtils.dartDir()}/tools/testing/bin'; |
| 195 return '$jsshellDir/$executable'; |
| 196 } |
| 197 |
| 198 /** |
| 199 * The file name of the Dart VM executable. |
| 200 */ |
| 201 String get vmFileName { |
| 202 var suffix = getExecutableSuffix('vm'); |
| 203 var vm = '$buildDir/dart$suffix'; |
| 204 TestUtils.ensureExists(vm, configuration); |
| 205 return vm; |
| 206 } |
| 207 |
| 208 /** |
| 209 * The file extension (if any) that should be added to the given executable |
| 210 * name for the current platform. |
| 211 */ |
| 212 String getExecutableSuffix(String executable) { |
| 213 if (Platform.operatingSystem == 'windows') { |
| 214 if (executable == 'd8' || executable == 'vm' || executable == 'none') { |
| 215 return '.exe'; |
| 216 } else { |
| 217 return '.bat'; |
| 218 } |
| 219 } |
| 220 return ''; |
| 221 } |
| 222 |
| 50 /** | 223 /** |
| 51 * Call the callback function onTest with a [TestCase] argument for each | 224 * Call the callback function onTest with a [TestCase] argument for each |
| 52 * test in the suite. When all tests have been processed, call [onDone]. | 225 * test in the suite. When all tests have been processed, call [onDone]. |
| 53 * | 226 * |
| 54 * The [testCache] argument provides a persistent store that can be used to | 227 * The [testCache] argument provides a persistent store that can be used to |
| 55 * cache information about the test suite, so that directories do not need | 228 * cache information about the test suite, so that directories do not need |
| 56 * to be listed each time. | 229 * to be listed each time. |
| 57 */ | 230 */ |
| 58 void forEachTest(TestCaseEvent onTest, Map testCache, [VoidFunction onDone]); | 231 void forEachTest(TestCaseEvent onTest, Map testCache, [VoidFunction onDone]); |
| 59 } | 232 } |
| 60 | 233 |
| 61 | 234 |
| 62 // TODO(1030): remove once in the corelib. | |
| 63 bool Contains(element, collection) => collection.indexOf(element) >= 0; | |
| 64 | |
| 65 | |
| 66 void ccTestLister() { | 235 void ccTestLister() { |
| 67 port.receive((String runnerPath, SendPort replyTo) { | 236 port.receive((String runnerPath, SendPort replyTo) { |
| 68 Future processFuture = Process.start(runnerPath, ["--list"]); | 237 Future processFuture = Process.start(runnerPath, ["--list"]); |
| 69 processFuture.then((p) { | 238 processFuture.then((p) { |
| 70 // Drain stderr to not leak resources. | 239 // Drain stderr to not leak resources. |
| 71 p.stderr.onData = p.stderr.read; | 240 p.stderr.onData = p.stderr.read; |
| 72 StringInputStream stdoutStream = new StringInputStream(p.stdout); | 241 StringInputStream stdoutStream = new StringInputStream(p.stdout); |
| 73 var streamDone = false; | 242 var streamDone = false; |
| 74 var processExited = false; | 243 var processExited = false; |
| 75 checkDone() { | 244 checkDone() { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 106 | 275 |
| 107 | 276 |
| 108 /** | 277 /** |
| 109 * A specialized [TestSuite] that runs tests written in C to unit test | 278 * A specialized [TestSuite] that runs tests written in C to unit test |
| 110 * the Dart virtual machine and its API. | 279 * the Dart virtual machine and its API. |
| 111 * | 280 * |
| 112 * The tests are compiled into a monolithic executable by the build step. | 281 * The tests are compiled into a monolithic executable by the build step. |
| 113 * The executable lists its tests when run with the --list command line flag. | 282 * The executable lists its tests when run with the --list command line flag. |
| 114 * Individual tests are run by specifying them on the command line. | 283 * Individual tests are run by specifying them on the command line. |
| 115 */ | 284 */ |
| 116 class CCTestSuite implements TestSuite { | 285 class CCTestSuite extends TestSuite { |
| 117 Map configuration; | |
| 118 final String suiteName; | |
| 119 final String testPrefix; | 286 final String testPrefix; |
| 120 String runnerPath; | 287 String runnerPath; |
| 121 final String dartDir; | 288 final String dartDir; |
| 122 List<String> statusFilePaths; | 289 List<String> statusFilePaths; |
| 123 TestCaseEvent doTest; | 290 TestCaseEvent doTest; |
| 124 VoidFunction doDone; | 291 VoidFunction doDone; |
| 125 ReceivePort receiveTestName; | 292 ReceivePort receiveTestName; |
| 126 TestExpectations testExpectations; | 293 TestExpectations testExpectations; |
| 127 | 294 |
| 128 CCTestSuite(Map this.configuration, | 295 CCTestSuite(Map configuration, |
| 129 String this.suiteName, | 296 String suiteName, |
| 130 String runnerName, | 297 String runnerName, |
| 131 List<String> this.statusFilePaths, | 298 List<String> this.statusFilePaths, |
| 132 {this.testPrefix: ''}) | 299 {this.testPrefix: ''}) |
| 133 : dartDir = TestUtils.dartDir().toNativePath() { | 300 : super(configuration, suiteName), |
| 134 runnerPath = '${TestUtils.buildDir(configuration)}/$runnerName'; | 301 dartDir = TestUtils.dartDir().toNativePath() { |
| 302 runnerPath = '$buildDir/$runnerName'; |
| 135 } | 303 } |
| 136 | 304 |
| 137 void testNameHandler(String testName, ignore) { | 305 void testNameHandler(String testName, ignore) { |
| 138 if (testName == "") { | 306 if (testName == "") { |
| 139 receiveTestName.close(); | 307 receiveTestName.close(); |
| 140 doDone(); | 308 |
| 309 if (doDone != null) doDone(); |
| 141 } else { | 310 } else { |
| 142 // Only run the tests that match the pattern. Use the name | 311 // Only run the tests that match the pattern. Use the name |
| 143 // "suiteName/testName" for cc tests. | 312 // "suiteName/testName" for cc tests. |
| 144 RegExp pattern = configuration['selectors'][suiteName]; | 313 RegExp pattern = configuration['selectors'][suiteName]; |
| 145 String constructedName = '$suiteName/$testPrefix$testName'; | 314 String constructedName = '$suiteName/$testPrefix$testName'; |
| 146 if (!pattern.hasMatch(constructedName)) return; | 315 if (!pattern.hasMatch(constructedName)) return; |
| 147 | 316 |
| 148 var expectations = testExpectations.expectations( | 317 var expectations = testExpectations.expectations( |
| 149 '$testPrefix$testName'); | 318 '$testPrefix$testName'); |
| 150 | 319 |
| 151 if (configuration["report"]) { | 320 if (configuration["report"]) { |
| 152 SummaryReport.add(expectations); | 321 SummaryReport.add(expectations); |
| 153 } | 322 } |
| 154 | 323 |
| 155 if (expectations.contains(SKIP)) return; | 324 if (expectations.contains(SKIP)) return; |
| 156 | 325 |
| 157 var args = TestUtils.standardOptions(configuration); | 326 var args = TestUtils.standardOptions(configuration); |
| 158 args.add(testName); | 327 args.add(testName); |
| 159 | 328 |
| 160 doTest(new TestCase(constructedName, | 329 doTest(new TestCase(constructedName, |
| 161 [new Command(runnerPath, args)], | 330 [new Command(runnerPath, args)], |
| 162 configuration, | 331 configuration, |
| 163 completeHandler, | 332 completeHandler, |
| 164 expectations)); | 333 expectations)); |
| 165 } | 334 } |
| 166 } | 335 } |
| 167 | 336 |
| 168 void forEachTest(TestCaseEvent onTest, Map testCache, [VoidFunction onDone]) { | 337 void forEachTest(TestCaseEvent onTest, Map testCache, [VoidFunction onDone]) { |
| 169 doTest = onTest; | 338 doTest = onTest; |
| 170 doDone = () => (onDone != null) ? onDone() : null; | 339 doDone = onDone; |
| 171 | 340 |
| 172 var filesRead = 0; | 341 var filesRead = 0; |
| 173 void statusFileRead() { | 342 void statusFileRead() { |
| 174 filesRead++; | 343 filesRead++; |
| 175 if (filesRead == statusFilePaths.length) { | 344 if (filesRead == statusFilePaths.length) { |
| 176 receiveTestName = new ReceivePort(); | 345 receiveTestName = new ReceivePort(); |
| 177 var port = spawnFunction(ccTestLister); | 346 var port = spawnFunction(ccTestLister); |
| 178 port.send(runnerPath, receiveTestName.toSendPort()); | 347 port.send(runnerPath, receiveTestName.toSendPort()); |
| 179 receiveTestName.receive(testNameHandler); | 348 receiveTestName.receive(testNameHandler); |
| 180 } | 349 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 204 Set<String> multitestOutcome; | 373 Set<String> multitestOutcome; |
| 205 | 374 |
| 206 TestInformation(this.filePath, this.optionsFromFile, | 375 TestInformation(this.filePath, this.optionsFromFile, |
| 207 this.hasCompileError, this.hasRuntimeError, | 376 this.hasCompileError, this.hasRuntimeError, |
| 208 this.isNegativeIfChecked, this.hasFatalTypeErrors, | 377 this.isNegativeIfChecked, this.hasFatalTypeErrors, |
| 209 this.multitestOutcome) { | 378 this.multitestOutcome) { |
| 210 Expect.isTrue(filePath.isAbsolute); | 379 Expect.isTrue(filePath.isAbsolute); |
| 211 } | 380 } |
| 212 } | 381 } |
| 213 | 382 |
| 214 | |
| 215 /** | 383 /** |
| 216 * A standard [TestSuite] implementation that searches for tests in a | 384 * A standard [TestSuite] implementation that searches for tests in a |
| 217 * directory, and creates [TestCase]s that compile and/or run them. | 385 * directory, and creates [TestCase]s that compile and/or run them. |
| 218 */ | 386 */ |
| 219 class StandardTestSuite implements TestSuite { | 387 class StandardTestSuite extends TestSuite { |
| 220 Map configuration; | 388 final Path suiteDir; |
| 221 String suiteName; | 389 final List<String> statusFilePaths; |
| 222 Path suiteDir; | |
| 223 List<String> statusFilePaths; | |
| 224 TestCaseEvent doTest; | 390 TestCaseEvent doTest; |
| 225 VoidFunction doDone; | |
| 226 int activeTestGenerators = 0; | |
| 227 bool listingDone = false; | |
| 228 TestExpectations testExpectations; | 391 TestExpectations testExpectations; |
| 229 List<TestInformation> cachedTests; | 392 List<TestInformation> cachedTests; |
| 230 final Path dartDir; | 393 final Path dartDir; |
| 231 Predicate<String> isTestFilePredicate; | 394 Predicate<String> isTestFilePredicate; |
| 232 bool _listRecursive; | 395 final bool listRecursively; |
| 233 | 396 |
| 234 StandardTestSuite(this.configuration, | 397 StandardTestSuite(Map configuration, |
| 235 this.suiteName, | 398 String suiteName, |
| 236 Path suiteDirectory, | 399 Path suiteDirectory, |
| 237 this.statusFilePaths, | 400 this.statusFilePaths, |
| 238 {this.isTestFilePredicate, | 401 {this.isTestFilePredicate, |
| 239 bool recursive: false}) | 402 bool recursive: false}) |
| 240 : dartDir = TestUtils.dartDir(), _listRecursive = recursive, | 403 : super(configuration, suiteName), |
| 404 dartDir = TestUtils.dartDir(), |
| 405 listRecursively = recursive, |
| 241 suiteDir = TestUtils.dartDir().join(suiteDirectory); | 406 suiteDir = TestUtils.dartDir().join(suiteDirectory); |
| 242 | 407 |
| 243 /** | 408 /** |
| 244 * Creates a test suite whose file organization matches an expected structure. | 409 * Creates a test suite whose file organization matches an expected structure. |
| 245 * To use this, your suite should look like: | 410 * To use this, your suite should look like: |
| 246 * | 411 * |
| 247 * dart/ | 412 * dart/ |
| 248 * path/ | 413 * path/ |
| 249 * to/ | 414 * to/ |
| 250 * mytestsuite/ | 415 * mytestsuite/ |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 * The default implementation assumes a file is a test if | 447 * The default implementation assumes a file is a test if |
| 283 * it ends in "Test.dart". | 448 * it ends in "Test.dart". |
| 284 */ | 449 */ |
| 285 bool isTestFile(String filename) { | 450 bool isTestFile(String filename) { |
| 286 // Use the specified predicate, if provided. | 451 // Use the specified predicate, if provided. |
| 287 if (isTestFilePredicate != null) return isTestFilePredicate(filename); | 452 if (isTestFilePredicate != null) return isTestFilePredicate(filename); |
| 288 | 453 |
| 289 return filename.endsWith("Test.dart"); | 454 return filename.endsWith("Test.dart"); |
| 290 } | 455 } |
| 291 | 456 |
| 292 bool listRecursively() => _listRecursive; | |
| 293 | |
| 294 String shellPath() => TestUtils.dartShellFileName(configuration); | |
| 295 | |
| 296 List<String> additionalOptions(Path filePath) => []; | 457 List<String> additionalOptions(Path filePath) => []; |
| 297 | 458 |
| 298 void forEachTest(TestCaseEvent onTest, Map testCache, [VoidFunction onDone]) { | 459 void forEachTest(TestCaseEvent onTest, Map testCache, [VoidFunction onDone]) { |
| 299 // If DumpRenderTree/Dartium is required, and not yet updated, | 460 updateDartium().chain((_) { |
| 300 // wait for update. | 461 doTest = onTest; |
| 462 |
| 463 return readExpectations(); |
| 464 }).chain((expectations) { |
| 465 testExpectations = expectations; |
| 466 |
| 467 // Checked if we have already found and generated the tests for |
| 468 // this suite. |
| 469 if (!testCache.containsKey(suiteName)) { |
| 470 cachedTests = testCache[suiteName] = []; |
| 471 return enqueueTests(); |
| 472 } else { |
| 473 // We rely on enqueueing completing asynchronously. |
| 474 return asynchronously(() { |
| 475 for (var info in testCache[suiteName]) { |
| 476 enqueueTestCaseFromTestInformation(info); |
| 477 } |
| 478 }); |
| 479 } |
| 480 }).then((_) { |
| 481 if (onDone != null) onDone(); |
| 482 }); |
| 483 } |
| 484 |
| 485 /** |
| 486 * If DumpRenderTree/Dartium is required, and not yet updated, waits for |
| 487 * the update then completes. Otherwise completes immediately. |
| 488 */ |
| 489 Future updateDartium() { |
| 490 var completer = new Completer(); |
| 301 var updater = runtimeUpdater(configuration); | 491 var updater = runtimeUpdater(configuration); |
| 302 if (updater !== null && !updater.updated) { | 492 if (updater == null || updater.updated) { |
| 303 Expect.isTrue(updater.isActive); | 493 return new Future.immediate(null); |
| 304 updater.onUpdated.add(() { | |
| 305 forEachTest(onTest, testCache, onDone); | |
| 306 }); | |
| 307 return; | |
| 308 } | 494 } |
| 309 | 495 |
| 310 doTest = onTest; | 496 Expect.isTrue(updater.isActive); |
| 311 doDone = (onDone != null) ? onDone : (() => null); | 497 updater.onUpdated.add(() => completer.complete(null)); |
| 498 |
| 499 return completer.future; |
| 500 } |
| 501 |
| 502 /** |
| 503 * Reads the status files and completes with the parsed expectations. |
| 504 */ |
| 505 Future<TestExpectations> readExpectations() { |
| 506 var completer = new Completer(); |
| 507 var expectations = new TestExpectations(); |
| 312 | 508 |
| 313 var filesRead = 0; | 509 var filesRead = 0; |
| 314 void statusFileRead() { | 510 void statusFileRead() { |
| 315 filesRead++; | 511 filesRead++; |
| 316 if (filesRead == statusFilePaths.length) { | 512 if (filesRead == statusFilePaths.length) { |
| 317 // Checked if we have already found and generated the tests for | 513 completer.complete(expectations); |
| 318 // this suite. | |
| 319 if (!testCache.containsKey(suiteName)) { | |
| 320 cachedTests = testCache[suiteName] = []; | |
| 321 processDirectory(); | |
| 322 } else { | |
| 323 // We rely on enqueueing completing asynchronously so use a | |
| 324 // timer to make it so. | |
| 325 void enqueueCachedTests(Timer ignore) { | |
| 326 for (var info in testCache[suiteName]) { | |
| 327 enqueueTestCaseFromTestInformation(info); | |
| 328 } | |
| 329 doDone(); | |
| 330 } | |
| 331 new Timer(0, enqueueCachedTests); | |
| 332 } | |
| 333 } | 514 } |
| 334 } | 515 } |
| 335 | 516 |
| 336 // Read test expectations from status files. | |
| 337 testExpectations = new TestExpectations(); | |
| 338 for (var statusFilePath in statusFilePaths) { | 517 for (var statusFilePath in statusFilePaths) { |
| 339 // [forDirectory] adds name_dart2js.status for all tests suites, use it if | 518 // [forDirectory] adds name_dart2js.status for all tests suites. Use it |
| 340 // it exists, but otherwise skip it and don't fail. | 519 // if it exists, but otherwise skip it and don't fail. |
| 341 if (statusFilePath.endsWith('_dart2js.status')) { | 520 if (statusFilePath.endsWith('_dart2js.status')) { |
| 342 File file = new File.fromPath(dartDir.append(statusFilePath)); | 521 var file = new File.fromPath(dartDir.append(statusFilePath)); |
| 343 if (!file.existsSync()) { | 522 if (!file.existsSync()) { |
| 344 filesRead++; | 523 filesRead++; |
| 345 continue; | 524 continue; |
| 346 } | 525 } |
| 347 } | 526 } |
| 348 ReadTestExpectationsInto(testExpectations, | 527 |
| 528 ReadTestExpectationsInto(expectations, |
| 349 dartDir.append(statusFilePath).toNativePath(), | 529 dartDir.append(statusFilePath).toNativePath(), |
| 350 configuration, | 530 configuration, statusFileRead); |
| 351 statusFileRead); | |
| 352 } | 531 } |
| 532 |
| 533 return completer.future; |
| 353 } | 534 } |
| 354 | 535 |
| 355 void processDirectory() { | 536 Future enqueueTests() { |
| 356 Directory dir = new Directory.fromPath(suiteDir); | 537 Directory dir = new Directory.fromPath(suiteDir); |
| 357 dir.exists().then((exists) { | 538 return dir.exists().chain((exists) { |
| 358 if (!exists) { | 539 if (!exists) { |
| 359 print('Directory containing tests not found: $suiteDir'); | 540 print('Directory containing tests not found: $suiteDir'); |
| 360 directoryListingDone(false); | 541 return new Future.immediate(null); |
| 361 } else { | 542 } else { |
| 362 var lister = dir.list(recursive: listRecursively()); | 543 var group = new FutureGroup(); |
| 363 lister.onFile = processFile; | 544 enqueueDirectory(dir, group); |
| 364 lister.onDone = directoryListingDone; | 545 return group.future; |
| 365 } | 546 } |
| 366 }); | 547 }); |
| 367 } | 548 } |
| 368 | 549 |
| 550 void enqueueDirectory(Directory dir, FutureGroup group) { |
| 551 var listCompleter = new Completer(); |
| 552 group.add(listCompleter.future); |
| 553 |
| 554 var lister = dir.list(recursive: listRecursively); |
| 555 lister.onFile = (file) => enqueueFile(file, group); |
| 556 lister.onDone = listCompleter.complete; |
| 557 } |
| 558 |
| 559 void enqueueFile(String filename, FutureGroup group) { |
| 560 if (!isTestFile(filename)) return; |
| 561 Path filePath = new Path.fromNative(filename); |
| 562 |
| 563 // Only run the tests that match the pattern. |
| 564 RegExp pattern = configuration['selectors'][suiteName]; |
| 565 if (!pattern.hasMatch('$filePath')) return; |
| 566 if (filePath.filename.endsWith('test_config.dart')) return; |
| 567 |
| 568 var optionsFromFile = readOptionsFromFile(filePath); |
| 569 CreateTest createTestCase = makeTestCaseCreator(optionsFromFile); |
| 570 |
| 571 if (optionsFromFile['isMultitest']) { |
| 572 group.add(doMultitest(filePath, buildDir, suiteDir, createTestCase)); |
| 573 } else { |
| 574 createTestCase(filePath, |
| 575 optionsFromFile['hasCompileError'], |
| 576 optionsFromFile['hasRuntimeError']); |
| 577 } |
| 578 } |
| 579 |
| 369 void enqueueTestCaseFromTestInformation(TestInformation info) { | 580 void enqueueTestCaseFromTestInformation(TestInformation info) { |
| 370 var filePath = info.filePath; | 581 var filePath = info.filePath; |
| 371 var optionsFromFile = info.optionsFromFile; | 582 var optionsFromFile = info.optionsFromFile; |
| 372 var isNegative = info.hasCompileError; | 583 var isNegative = info.hasCompileError; |
| 373 if (info.hasRuntimeError && hasRuntime) { | 584 if (info.hasRuntimeError && hasRuntime) { |
| 374 isNegative = true; | 585 isNegative = true; |
| 375 } | 586 } |
| 376 | 587 |
| 377 // Look up expectations in status files using a test name generated | 588 // Look up expectations in status files using a test name generated |
| 378 // from the test file's path. | 589 // from the test file's path. |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 info: info)); | 691 info: info)); |
| 481 } | 692 } |
| 482 } | 693 } |
| 483 | 694 |
| 484 List<Command> makeCommands(TestInformation info, var vmOptions, var args) { | 695 List<Command> makeCommands(TestInformation info, var vmOptions, var args) { |
| 485 switch (configuration['compiler']) { | 696 switch (configuration['compiler']) { |
| 486 case 'dart2js': | 697 case 'dart2js': |
| 487 args = new List.from(args); | 698 args = new List.from(args); |
| 488 String tempDir = createOutputDirectory(info.filePath, ''); | 699 String tempDir = createOutputDirectory(info.filePath, ''); |
| 489 args.add('--out=$tempDir/out.js'); | 700 args.add('--out=$tempDir/out.js'); |
| 490 List<Command> commands = <Command>[new Command(shellPath(), args)]; | 701 List<Command> commands = <Command>[new Command(dartShellFileName, args)]; |
| 491 if (info.hasCompileError) { | 702 if (info.hasCompileError) { |
| 492 // Do not attempt to run the compiled result. A compilation | 703 // Do not attempt to run the compiled result. A compilation |
| 493 // error should be reported by the compilation command. | 704 // error should be reported by the compilation command. |
| 494 } else if (configuration['runtime'] == 'd8') { | 705 } else if (configuration['runtime'] == 'd8') { |
| 495 var d8 = TestUtils.d8FileName(configuration); | 706 commands.add(new Command(d8FileName, ['$tempDir/out.js'])); |
| 496 commands.add(new Command(d8, ['$tempDir/out.js'])); | |
| 497 } else if (configuration['runtime'] == 'jsshell') { | 707 } else if (configuration['runtime'] == 'jsshell') { |
| 498 var jsshell = TestUtils.jsshellFileName(configuration); | 708 commands.add(new Command(jsShellFileName, ['$tempDir/out.js'])); |
| 499 commands.add(new Command(jsshell, ['$tempDir/out.js'])); | |
| 500 } | 709 } |
| 501 return commands; | 710 return commands; |
| 502 | 711 |
| 503 case 'dart2dart': | 712 case 'dart2dart': |
| 504 var compilerArguments = new List.from(args); | 713 var compilerArguments = new List.from(args); |
| 505 var additionalFlags = | 714 var additionalFlags = |
| 506 configuration['additional-compiler-flags'].split(' '); | 715 configuration['additional-compiler-flags'].split(' '); |
| 507 for (final flag in additionalFlags) { | 716 for (final flag in additionalFlags) { |
| 508 if (flag.isEmpty) continue; | 717 if (flag.isEmpty) continue; |
| 509 compilerArguments.add(flag); | 718 compilerArguments.add(flag); |
| 510 } | 719 } |
| 511 compilerArguments.add('--output-type=dart'); | 720 compilerArguments.add('--output-type=dart'); |
| 512 String tempDir = createOutputDirectory(info.filePath, ''); | 721 String tempDir = createOutputDirectory(info.filePath, ''); |
| 513 compilerArguments.add('--out=$tempDir/out.dart'); | 722 compilerArguments.add('--out=$tempDir/out.dart'); |
| 514 List<Command> commands = | 723 List<Command> commands = |
| 515 <Command>[new Command(shellPath(), compilerArguments)]; | 724 <Command>[new Command(dartShellFileName, compilerArguments)]; |
| 516 if (info.hasCompileError) { | 725 if (info.hasCompileError) { |
| 517 // Do not attempt to run the compiled result. A compilation | 726 // Do not attempt to run the compiled result. A compilation |
| 518 // error should be reported by the compilation command. | 727 // error should be reported by the compilation command. |
| 519 } else if (configuration['runtime'] == 'vm') { | 728 } else if (configuration['runtime'] == 'vm') { |
| 520 // TODO(antonm): support checked. | 729 // TODO(antonm): support checked. |
| 521 var vmArguments = new List.from(vmOptions); | 730 var vmArguments = new List.from(vmOptions); |
| 522 vmArguments.addAll([ | 731 vmArguments.addAll([ |
| 523 '--ignore-unrecognized-flags', '$tempDir/out.dart']); | 732 '--ignore-unrecognized-flags', '$tempDir/out.dart']); |
| 524 commands.add(new Command( | 733 commands.add(new Command(vmFileName, vmArguments)); |
| 525 TestUtils.vmFileName(configuration), | |
| 526 vmArguments)); | |
| 527 } else { | 734 } else { |
| 528 throw 'Unsupported runtime ${configuration["runtime"]} for dart2dart'; | 735 throw 'Unsupported runtime ${configuration["runtime"]} for dart2dart'; |
| 529 } | 736 } |
| 530 return commands; | 737 return commands; |
| 531 | 738 |
| 532 case 'none': | 739 case 'none': |
| 533 case 'dartc': | 740 case 'dartc': |
| 534 var arguments = new List.from(vmOptions); | 741 var arguments = new List.from(vmOptions); |
| 535 arguments.addAll(args); | 742 arguments.addAll(args); |
| 536 return <Command>[new Command(shellPath(), arguments)]; | 743 return <Command>[new Command(dartShellFileName, arguments)]; |
| 537 | 744 |
| 538 default: | 745 default: |
| 539 throw 'Unknown compiler ${configuration["compiler"]}'; | 746 throw 'Unknown compiler ${configuration["compiler"]}'; |
| 540 } | 747 } |
| 541 } | 748 } |
| 542 | 749 |
| 543 CreateTest makeTestCaseCreator(Map optionsFromFile) { | 750 CreateTest makeTestCaseCreator(Map optionsFromFile) { |
| 544 return (Path filePath, | 751 return (Path filePath, |
| 545 bool hasCompileError, | 752 bool hasCompileError, |
| 546 bool hasRuntimeError, | 753 bool hasRuntimeError, |
| 547 {bool isNegativeIfChecked: false, | 754 {bool isNegativeIfChecked: false, |
| 548 bool hasFatalTypeErrors: false, | 755 bool hasFatalTypeErrors: false, |
| 549 Set<String> multitestOutcome: null}) { | 756 Set<String> multitestOutcome: null}) { |
| 550 // Cache the test information for each test case. | 757 // Cache the test information for each test case. |
| 551 var info = new TestInformation(filePath, | 758 var info = new TestInformation(filePath, |
| 552 optionsFromFile, | 759 optionsFromFile, |
| 553 hasCompileError, | 760 hasCompileError, |
| 554 hasRuntimeError, | 761 hasRuntimeError, |
| 555 isNegativeIfChecked, | 762 isNegativeIfChecked, |
| 556 hasFatalTypeErrors, | 763 hasFatalTypeErrors, |
| 557 multitestOutcome); | 764 multitestOutcome); |
| 558 cachedTests.add(info); | 765 cachedTests.add(info); |
| 559 enqueueTestCaseFromTestInformation(info); | 766 enqueueTestCaseFromTestInformation(info); |
| 560 }; | 767 }; |
| 561 } | 768 } |
| 562 | 769 |
| 563 void processFile(String filename) { | |
| 564 if (!isTestFile(filename)) return; | |
| 565 Path filePath = new Path.fromNative(filename); | |
| 566 | |
| 567 // Only run the tests that match the pattern. | |
| 568 RegExp pattern = configuration['selectors'][suiteName]; | |
| 569 if (!pattern.hasMatch('$filePath')) return; | |
| 570 if (filePath.filename.endsWith('test_config.dart')) return; | |
| 571 | |
| 572 var optionsFromFile = readOptionsFromFile(filePath); | |
| 573 CreateTest createTestCase = makeTestCaseCreator(optionsFromFile); | |
| 574 | |
| 575 if (optionsFromFile['isMultitest']) { | |
| 576 testGeneratorStarted(); | |
| 577 DoMultitest(filePath, | |
| 578 TestUtils.buildDir(configuration), | |
| 579 suiteDir, | |
| 580 createTestCase, | |
| 581 testGeneratorDone); | |
| 582 } else { | |
| 583 createTestCase(filePath, | |
| 584 optionsFromFile['hasCompileError'], | |
| 585 optionsFromFile['hasRuntimeError']); | |
| 586 } | |
| 587 } | |
| 588 | |
| 589 /** | 770 /** |
| 590 * The [StandardTestSuite] has support for tests that | 771 * The [StandardTestSuite] has support for tests that |
| 591 * compile a test from Dart to JavaScript, and then run the resulting | 772 * compile a test from Dart to JavaScript, and then run the resulting |
| 592 * JavaScript. This function creates a working directory to hold the | 773 * JavaScript. This function creates a working directory to hold the |
| 593 * JavaScript version of the test, and copies the appropriate framework | 774 * JavaScript version of the test, and copies the appropriate framework |
| 594 * files to that directory. It creates a [BrowserTestCase], which has | 775 * files to that directory. It creates a [BrowserTestCase], which has |
| 595 * two sequential steps to be run by the [ProcessQueue] when the test is | 776 * two sequential steps to be run by the [ProcessQueue] when the test is |
| 596 * executed: a compilation step and an execution step, both with the | 777 * executed: a compilation step and an execution step, both with the |
| 597 * appropriate executable and arguments. The [expectations] object can be | 778 * appropriate executable and arguments. The [expectations] object can be |
| 598 * either a Set<String> if the test is a regular test, or a Map<String | 779 * either a Set<String> if the test is a regular test, or a Map<String |
| 599 * subTestName, Set<String>> if we are running a browser multi-test (one | 780 * subTestName, Set<String>> if we are running a browser multi-test (one |
| 600 * compilation and many browser runs). | 781 * compilation and many browser runs). |
| 601 */ | 782 */ |
| 602 void enqueueBrowserTest(TestInformation info, | 783 void enqueueBrowserTest(TestInformation info, |
| 603 String testName, | 784 String testName, |
| 604 Object expectations, | 785 Object expectations, |
| 605 bool isWrappingRequired) { | 786 bool isWrappingRequired) { |
| 606 Map optionsFromFile = info.optionsFromFile; | 787 Map optionsFromFile = info.optionsFromFile; |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 794 } | 975 } |
| 795 doTest(testCase); | 976 doTest(testCase); |
| 796 subtestIndex++; | 977 subtestIndex++; |
| 797 } while(subtestIndex < subtestNames.length); | 978 } while(subtestIndex < subtestNames.length); |
| 798 } | 979 } |
| 799 } | 980 } |
| 800 | 981 |
| 801 /** Helper to create a compilation command for a single input file. */ | 982 /** Helper to create a compilation command for a single input file. */ |
| 802 Command _compileCommand(String inputFile, String outputFile, | 983 Command _compileCommand(String inputFile, String outputFile, |
| 803 String compiler, String dir, var vmOptions) { | 984 String compiler, String dir, var vmOptions) { |
| 804 String executable = TestUtils.compilerPath(configuration); | 985 String executable = compilerPath; |
| 805 List<String> args = TestUtils.standardOptions(configuration); | 986 List<String> args = TestUtils.standardOptions(configuration); |
| 806 switch (compiler) { | 987 switch (compiler) { |
| 807 case 'dart2js': | 988 case 'dart2js': |
| 808 case 'dart2dart': | 989 case 'dart2dart': |
| 809 if (compiler == 'dart2dart') args.add('--out=$outputFile'); | 990 if (compiler == 'dart2dart') args.add('--out=$outputFile'); |
| 810 args.add('--out=$outputFile'); | 991 args.add('--out=$outputFile'); |
| 811 args.add(inputFile); | 992 args.add(inputFile); |
| 812 break; | 993 break; |
| 813 default: | 994 default: |
| 814 Expect.fail('unimplemented compiler $compiler'); | 995 Expect.fail('unimplemented compiler $compiler'); |
| 815 } | 996 } |
| 816 if (executable.endsWith('.dart')) { | 997 if (executable.endsWith('.dart')) { |
| 817 // Run the compiler script via the Dart VM. | 998 // Run the compiler script via the Dart VM. |
| 818 args.insertRange(0, 1, executable); | 999 args.insertRange(0, 1, executable); |
| 819 executable = TestUtils.dartShellFileName(configuration); | 1000 executable = dartShellFileName; |
| 820 } | 1001 } |
| 821 return new Command(executable, args); | 1002 return new Command(executable, args); |
| 822 } | 1003 } |
| 823 | 1004 |
| 824 /** | 1005 /** |
| 825 * Create a directory for the generated test. If a Dart language test | 1006 * Create a directory for the generated test. If a Dart language test |
| 826 * needs to be run in a browser, the Dart test needs to be embedded in | 1007 * needs to be run in a browser, the Dart test needs to be embedded in |
| 827 * an HTML page, with a testing framework based on scripting and DOM events. | 1008 * an HTML page, with a testing framework based on scripting and DOM events. |
| 828 * These scripts and pages are written to a generated_test directory | 1009 * These scripts and pages are written to a generated_test directory |
| 829 * inside the build directory of the checkout. | 1010 * inside the build directory of the checkout. |
| 830 * | 1011 * |
| 831 * Those tests which are already HTML web applications (web tests), with | 1012 * Those tests which are already HTML web applications (web tests), with |
| 832 * resources including CSS files and HTML files, need to be compiled into | 1013 * resources including CSS files and HTML files, need to be compiled into |
| 833 * a work directory where the relative URLS to the resources work. | 1014 * a work directory where the relative URLS to the resources work. |
| 834 * We use a subdirectory of the build directory that is the same number | 1015 * We use a subdirectory of the build directory that is the same number |
| 835 * of levels down in the checkout as the original path of the web test. | 1016 * of levels down in the checkout as the original path of the web test. |
| 836 */ | 1017 */ |
| 837 String createOutputDirectory(Path testPath, String optionsName) { | 1018 String createOutputDirectory(Path testPath, String optionsName) { |
| 838 Path relative = testPath.relativeTo(TestUtils.dartDir()); | 1019 Path relative = testPath.relativeTo(TestUtils.dartDir()); |
| 839 relative = relative.directoryPath.append(relative.filenameWithoutExtension); | 1020 relative = relative.directoryPath.append(relative.filenameWithoutExtension); |
| 840 String testUniqueName = relative.toString().replaceAll('/', '_'); | 1021 String testUniqueName = relative.toString().replaceAll('/', '_'); |
| 841 if (!optionsName.isEmpty) { | 1022 if (!optionsName.isEmpty) { |
| 842 testUniqueName = '$testUniqueName-$optionsName'; | 1023 testUniqueName = '$testUniqueName-$optionsName'; |
| 843 } | 1024 } |
| 844 | 1025 |
| 845 // Create '[build dir]/generated_tests/$compiler-$runtime/$testUniqueName', | 1026 // Create '[build dir]/generated_tests/$compiler-$runtime/$testUniqueName', |
| 846 // including any intermediate directories that don't exist. | 1027 // including any intermediate directories that don't exist. |
| 847 var generatedTestPath = Strings.join( | 1028 var generatedTestPath = Strings.join([ |
| 848 [TestUtils.buildDir(configuration), | 1029 buildDir, |
| 849 'generated_tests', | 1030 'generated_tests', |
| 850 "${configuration['compiler']}-${configuration['runtime']}", | 1031 "${configuration['compiler']}-${configuration['runtime']}", |
| 851 testUniqueName], '/'); | 1032 testUniqueName |
| 1033 ], '/'); |
| 852 | 1034 |
| 853 TestUtils.mkdirRecursive(new Path('.'), new Path(generatedTestPath)); | 1035 TestUtils.mkdirRecursive(new Path('.'), new Path(generatedTestPath)); |
| 854 return new File(generatedTestPath).fullPathSync().replaceAll('\\', '/'); | 1036 return new File(generatedTestPath).fullPathSync().replaceAll('\\', '/'); |
| 855 } | 1037 } |
| 856 | 1038 |
| 857 String get scriptType { | 1039 String get scriptType { |
| 858 switch (configuration['compiler']) { | 1040 switch (configuration['compiler']) { |
| 859 case 'none': | 1041 case 'none': |
| 860 case 'dart2dart': | 1042 case 'dart2dart': |
| 861 return 'application/dart'; | 1043 return 'application/dart'; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 902 if (configuration['dartium'] != '') { | 1084 if (configuration['dartium'] != '') { |
| 903 return configuration['dartium']; | 1085 return configuration['dartium']; |
| 904 } | 1086 } |
| 905 if (Platform.operatingSystem == 'macos') { | 1087 if (Platform.operatingSystem == 'macos') { |
| 906 return dartDir.append('client/tests/dartium/Chromium.app/Contents/' | 1088 return dartDir.append('client/tests/dartium/Chromium.app/Contents/' |
| 907 'MacOS/Chromium').toNativePath(); | 1089 'MacOS/Chromium').toNativePath(); |
| 908 } | 1090 } |
| 909 return dartDir.append('client/tests/dartium/chrome').toNativePath(); | 1091 return dartDir.append('client/tests/dartium/chrome').toNativePath(); |
| 910 } | 1092 } |
| 911 | 1093 |
| 912 void testGeneratorStarted() { | |
| 913 ++activeTestGenerators; | |
| 914 } | |
| 915 | |
| 916 void testGeneratorDone() { | |
| 917 --activeTestGenerators; | |
| 918 if (activeTestGenerators == 0 && listingDone) { | |
| 919 doDone(); | |
| 920 } | |
| 921 } | |
| 922 | |
| 923 void directoryListingDone(ignore) { | |
| 924 listingDone = true; | |
| 925 if (activeTestGenerators == 0) { | |
| 926 doDone(); | |
| 927 } | |
| 928 } | |
| 929 | |
| 930 void completeHandler(TestCase testCase) { | 1094 void completeHandler(TestCase testCase) { |
| 931 } | 1095 } |
| 932 | 1096 |
| 933 List<String> commonArgumentsFromFile(Path filePath, Map optionsFromFile) { | 1097 List<String> commonArgumentsFromFile(Path filePath, Map optionsFromFile) { |
| 934 List args = TestUtils.standardOptions(configuration); | 1098 List args = TestUtils.standardOptions(configuration); |
| 935 args.addAll(additionalOptions(filePath)); | 1099 args.addAll(additionalOptions(filePath)); |
| 936 if (configuration['compiler'] == 'dartc') { | 1100 if (configuration['compiler'] == 'dartc') { |
| 937 args.add('--error_format'); | 1101 args.add('--error_format'); |
| 938 args.add('machine'); | 1102 args.add('machine'); |
| 939 } | 1103 } |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1130 "containsLeadingHash": containsLeadingHash, | 1294 "containsLeadingHash": containsLeadingHash, |
| 1131 "isolateStubs": isolateStubs, | 1295 "isolateStubs": isolateStubs, |
| 1132 "containsDomImport": containsDomImport, | 1296 "containsDomImport": containsDomImport, |
| 1133 "isLibraryDefinition": isLibraryDefinition, | 1297 "isLibraryDefinition": isLibraryDefinition, |
| 1134 "containsSourceOrImport": containsSourceOrImport, | 1298 "containsSourceOrImport": containsSourceOrImport, |
| 1135 "numStaticTypeAnnotations": numStaticTypeAnnotations, | 1299 "numStaticTypeAnnotations": numStaticTypeAnnotations, |
| 1136 "numCompileTimeAnnotations": numCompileTimeAnnotations }; | 1300 "numCompileTimeAnnotations": numCompileTimeAnnotations }; |
| 1137 } | 1301 } |
| 1138 | 1302 |
| 1139 List<List<String>> getVmOptions(Map optionsFromFile) { | 1303 List<List<String>> getVmOptions(Map optionsFromFile) { |
| 1140 bool needsVmOptions = Contains(configuration['compiler'], | 1304 var COMPILERS = const ['none', 'dart2dart', 'dartc']; |
| 1141 const ['none', 'dart2dart', 'dartc']) && | 1305 var RUNTIMES = const ['none', 'vm', 'drt', 'dartium']; |
| 1142 Contains(configuration['runtime'], | 1306 var needsVmOptions = COMPILERS.contains(configuration['compiler']) && |
| 1143 const ['none', 'vm', 'drt', 'dartium']); | 1307 RUNTIMES.contains(configuration['runtime']); |
| 1144 if (!needsVmOptions) return [[]]; | 1308 if (!needsVmOptions) return [[]]; |
| 1145 return optionsFromFile['vmOptions']; | 1309 return optionsFromFile['vmOptions']; |
| 1146 } | 1310 } |
| 1147 } | 1311 } |
| 1148 | 1312 |
| 1149 | 1313 |
| 1150 class DartcCompilationTestSuite extends StandardTestSuite { | 1314 class DartcCompilationTestSuite extends StandardTestSuite { |
| 1151 List<String> _testDirs; | 1315 List<String> _testDirs; |
| 1152 int activityCount = 0; | |
| 1153 | 1316 |
| 1154 DartcCompilationTestSuite(Map configuration, | 1317 DartcCompilationTestSuite(Map configuration, |
| 1155 String suiteName, | 1318 String suiteName, |
| 1156 String directoryPath, | 1319 String directoryPath, |
| 1157 List<String> this._testDirs, | 1320 List<String> this._testDirs, |
| 1158 List<String> expectations) | 1321 List<String> expectations) |
| 1159 : super(configuration, | 1322 : super(configuration, |
| 1160 suiteName, | 1323 suiteName, |
| 1161 new Path.fromNative(directoryPath), | 1324 new Path.fromNative(directoryPath), |
| 1162 expectations); | 1325 expectations); |
| 1163 | 1326 |
| 1164 void activityStarted() { ++activityCount; } | |
| 1165 | |
| 1166 void activityCompleted() { | |
| 1167 if (--activityCount == 0) { | |
| 1168 directoryListingDone(true); | |
| 1169 } | |
| 1170 } | |
| 1171 | |
| 1172 String shellPath() => TestUtils.compilerPath(configuration); | |
| 1173 | |
| 1174 List<String> additionalOptions(Path filePath) { | 1327 List<String> additionalOptions(Path filePath) { |
| 1175 return ['--fatal-warnings', '--fatal-type-errors']; | 1328 return ['--fatal-warnings', '--fatal-type-errors']; |
| 1176 } | 1329 } |
| 1177 | 1330 |
| 1178 void processDirectory() { | 1331 Future enqueueTests() { |
| 1179 // Enqueueing the directory listers is an activity. | 1332 var group = new FutureGroup(); |
| 1180 activityStarted(); | 1333 |
| 1181 for (String testDir in _testDirs) { | 1334 for (String testDir in _testDirs) { |
| 1182 Directory dir = new Directory.fromPath(suiteDir.append(testDir)); | 1335 Directory dir = new Directory.fromPath(suiteDir.append(testDir)); |
| 1183 if (dir.existsSync()) { | 1336 if (dir.existsSync()) { |
| 1184 activityStarted(); | 1337 enqueueDirectory(dir, group); |
| 1185 var lister = dir.list(recursive: listRecursively()); | |
| 1186 lister.onFile = processFile; | |
| 1187 lister.onDone = (ignore) => activityCompleted(); | |
| 1188 } | 1338 } |
| 1189 } | 1339 } |
| 1190 // Completed the enqueueing of listers. | 1340 |
| 1191 activityCompleted(); | 1341 return group.future; |
| 1192 } | 1342 } |
| 1193 } | 1343 } |
| 1194 | 1344 |
| 1195 | 1345 |
| 1196 class JUnitTestSuite implements TestSuite { | 1346 class JUnitTestSuite extends TestSuite { |
| 1197 Map configuration; | |
| 1198 String suiteName; | |
| 1199 String directoryPath; | 1347 String directoryPath; |
| 1200 String statusFilePath; | 1348 String statusFilePath; |
| 1201 final String dartDir; | 1349 final String dartDir; |
| 1202 String buildDir; | |
| 1203 String classPath; | 1350 String classPath; |
| 1204 List<String> testClasses; | 1351 List<String> testClasses; |
| 1205 TestCaseEvent doTest; | 1352 TestCaseEvent doTest; |
| 1206 VoidFunction doDone; | 1353 VoidFunction doDone; |
| 1207 TestExpectations testExpectations; | 1354 TestExpectations testExpectations; |
| 1208 | 1355 |
| 1209 JUnitTestSuite(Map this.configuration, | 1356 JUnitTestSuite(Map configuration, |
| 1210 String this.suiteName, | 1357 String suiteName, |
| 1211 String this.directoryPath, | 1358 String this.directoryPath, |
| 1212 String this.statusFilePath) | 1359 String this.statusFilePath) |
| 1213 : dartDir = TestUtils.dartDir().toNativePath(); | 1360 : super(configuration, suiteName), |
| 1361 dartDir = TestUtils.dartDir().toNativePath(); |
| 1214 | 1362 |
| 1215 bool isTestFile(String filename) => filename.endsWith("Tests.java") && | 1363 bool isTestFile(String filename) => filename.endsWith("Tests.java") && |
| 1216 !filename.contains('com/google/dart/compiler/vm') && | 1364 !filename.contains('com/google/dart/compiler/vm') && |
| 1217 !filename.contains('com/google/dart/corelib/SharedTests.java'); | 1365 !filename.contains('com/google/dart/corelib/SharedTests.java'); |
| 1218 | 1366 |
| 1219 void forEachTest(TestCaseEvent onTest, | 1367 void forEachTest(TestCaseEvent onTest, |
| 1220 Map testCacheIgnored, | 1368 Map testCacheIgnored, |
| 1221 [VoidFunction onDone]) { | 1369 [VoidFunction onDone]) { |
| 1222 doTest = onTest; | 1370 doTest = onTest; |
| 1223 doDone = (onDone != null) ? onDone : (() => null); | 1371 doDone = onDone; |
| 1224 | 1372 |
| 1225 if (configuration['compiler'] != 'dartc') { | 1373 if (configuration['compiler'] != 'dartc') { |
| 1226 // Do nothing. Asynchronously report that the suite is enqueued. | 1374 // Do nothing. Asynchronously report that the suite is enqueued. |
| 1227 new Timer(0, (timerUnused){ doDone(); }); | 1375 asynchronously(doDone); |
| 1228 return; | 1376 return; |
| 1229 } | 1377 } |
| 1230 RegExp pattern = configuration['selectors']['dartc']; | 1378 RegExp pattern = configuration['selectors']['dartc']; |
| 1231 if (!pattern.hasMatch('junit_tests')) { | 1379 if (!pattern.hasMatch('junit_tests')) { |
| 1232 new Timer(0, (timerUnused){ doDone(); }); | 1380 asynchronously(doDone); |
| 1233 return; | 1381 return; |
| 1234 } | 1382 } |
| 1235 | 1383 |
| 1236 buildDir = TestUtils.buildDir(configuration); | |
| 1237 computeClassPath(); | 1384 computeClassPath(); |
| 1238 testClasses = <String>[]; | 1385 testClasses = <String>[]; |
| 1239 // Do not read the status file. | 1386 // Do not read the status file. |
| 1240 // All exclusions are hardcoded in this script, as they are in testcfg.py. | 1387 // All exclusions are hardcoded in this script, as they are in testcfg.py. |
| 1241 processDirectory(); | 1388 processDirectory(); |
| 1242 } | 1389 } |
| 1243 | 1390 |
| 1244 void processDirectory() { | 1391 void processDirectory() { |
| 1245 directoryPath = '$dartDir/$directoryPath'; | 1392 directoryPath = '$dartDir/$directoryPath'; |
| 1246 Directory dir = new Directory(directoryPath); | 1393 Directory dir = new Directory(directoryPath); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1301 '$dartDir/third_party/rhino/1_7R3/js.jar', | 1448 '$dartDir/third_party/rhino/1_7R3/js.jar', |
| 1302 '$dartDir/third_party/hamcrest/v1_3/hamcrest-core-1.3.0RC2.jar', | 1449 '$dartDir/third_party/hamcrest/v1_3/hamcrest-core-1.3.0RC2.jar', |
| 1303 '$dartDir/third_party/hamcrest/v1_3/hamcrest-generator-1.3.0RC2.jar', | 1450 '$dartDir/third_party/hamcrest/v1_3/hamcrest-generator-1.3.0RC2.jar', |
| 1304 '$dartDir/third_party/hamcrest/v1_3/hamcrest-integration-1.3.0RC2.jar', | 1451 '$dartDir/third_party/hamcrest/v1_3/hamcrest-integration-1.3.0RC2.jar', |
| 1305 '$dartDir/third_party/hamcrest/v1_3/hamcrest-library-1.3.0RC2.jar', | 1452 '$dartDir/third_party/hamcrest/v1_3/hamcrest-library-1.3.0RC2.jar', |
| 1306 '$dartDir/third_party/junit/v4_8_2/junit.jar'], | 1453 '$dartDir/third_party/junit/v4_8_2/junit.jar'], |
| 1307 Platform.operatingSystem == 'windows'? ';': ':'); // Path separator. | 1454 Platform.operatingSystem == 'windows'? ';': ':'); // Path separator. |
| 1308 } | 1455 } |
| 1309 } | 1456 } |
| 1310 | 1457 |
| 1311 | |
| 1312 class TestUtils { | 1458 class TestUtils { |
| 1313 /** | 1459 /** |
| 1314 * The libraries in this directory relies on finding various files | 1460 * The libraries in this directory relies on finding various files |
| 1315 * relative to the 'test.dart' script in '.../dart/tools/test.dart'. If | 1461 * relative to the 'test.dart' script in '.../dart/tools/test.dart'. If |
| 1316 * the main script using 'test_suite.dart' is not there, the main | 1462 * the main script using 'test_suite.dart' is not there, the main |
| 1317 * script must set this to '.../dart/tools/test.dart'. | 1463 * script must set this to '.../dart/tools/test.dart'. |
| 1318 */ | 1464 */ |
| 1319 static String testScriptPath = new Options().script; | 1465 static String testScriptPath = new Options().script; |
| 1320 | 1466 |
| 1321 /** | 1467 /** |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1343 * Assumes that the directory for [dest] already exists. | 1489 * Assumes that the directory for [dest] already exists. |
| 1344 */ | 1490 */ |
| 1345 static Future copyFile(Path source, Path dest) { | 1491 static Future copyFile(Path source, Path dest) { |
| 1346 var output = new File.fromPath(dest).openOutputStream(); | 1492 var output = new File.fromPath(dest).openOutputStream(); |
| 1347 new File.fromPath(source).openInputStream().pipe(output); | 1493 new File.fromPath(source).openInputStream().pipe(output); |
| 1348 var completer = new Completer(); | 1494 var completer = new Completer(); |
| 1349 output.onClosed = (){ completer.complete(null); }; | 1495 output.onClosed = (){ completer.complete(null); }; |
| 1350 return completer.future; | 1496 return completer.future; |
| 1351 } | 1497 } |
| 1352 | 1498 |
| 1353 static String executableSuffix(String executable) { | |
| 1354 if (Platform.operatingSystem == 'windows') { | |
| 1355 if (executable == 'd8' || executable == 'vm' || executable == 'none') { | |
| 1356 return '.exe'; | |
| 1357 } else { | |
| 1358 return '.bat'; | |
| 1359 } | |
| 1360 } | |
| 1361 return ''; | |
| 1362 } | |
| 1363 | |
| 1364 static String executableName(Map configuration) { | |
| 1365 String suffix = executableSuffix(configuration['compiler']); | |
| 1366 switch (configuration['compiler']) { | |
| 1367 case 'none': | |
| 1368 return 'dart$suffix'; | |
| 1369 case 'dartc': | |
| 1370 return 'analyzer/bin/dart_analyzer$suffix'; | |
| 1371 case 'dart2js': | |
| 1372 case 'dart2dart': | |
| 1373 var prefix = ''; | |
| 1374 if (configuration['use_sdk']) { | |
| 1375 prefix = 'dart-sdk/bin/'; | |
| 1376 } | |
| 1377 if (configuration['host_checked']) { | |
| 1378 // The script dart2js_developer is not in the SDK. | |
| 1379 return 'dart2js_developer$suffix'; | |
| 1380 } else { | |
| 1381 return '${prefix}dart2js$suffix'; | |
| 1382 } | |
| 1383 break; | |
| 1384 default: | |
| 1385 throw "Unknown executable for: ${configuration['compiler']}"; | |
| 1386 } | |
| 1387 } | |
| 1388 | |
| 1389 static String compilerName(Map configuration) { | |
| 1390 String suffix = executableSuffix(configuration['compiler']); | |
| 1391 switch (configuration['compiler']) { | |
| 1392 case 'dartc': | |
| 1393 case 'dart2js': | |
| 1394 case 'dart2dart': | |
| 1395 return executableName(configuration); | |
| 1396 default: | |
| 1397 throw "Unknown compiler for: ${configuration['compiler']}"; | |
| 1398 } | |
| 1399 } | |
| 1400 | |
| 1401 static String dartShellFileName(Map configuration) { | |
| 1402 var name = configuration['dart']; | |
| 1403 if (name == '') { | |
| 1404 name = '${buildDir(configuration)}/${executableName(configuration)}'; | |
| 1405 } | |
| 1406 ensureExists(name, configuration); | |
| 1407 return name; | |
| 1408 } | |
| 1409 | |
| 1410 static String d8FileName(Map configuration) { | |
| 1411 var suffix = executableSuffix('d8'); | |
| 1412 var d8 = '${buildDir(configuration)}/d8$suffix'; | |
| 1413 ensureExists(d8, configuration); | |
| 1414 return d8; | |
| 1415 } | |
| 1416 | |
| 1417 static String vmFileName(Map configuration) { | |
| 1418 var suffix = executableSuffix('vm'); | |
| 1419 var vm = '${buildDir(configuration)}/dart$suffix'; | |
| 1420 ensureExists(vm, configuration); | |
| 1421 return vm; | |
| 1422 } | |
| 1423 | |
| 1424 static String flakyFileName() { | 1499 static String flakyFileName() { |
| 1425 // If a flaky test did fail, infos about it (i.e. test name, stdin, stdout) | 1500 // If a flaky test did fail, infos about it (i.e. test name, stdin, stdout) |
| 1426 // will be written to this file. This is useful for the debugging of | 1501 // will be written to this file. This is useful for the debugging of |
| 1427 // flaky tests. | 1502 // flaky tests. |
| 1428 // When running on a built bot, the file can be made visible in the waterfal
l UI. | 1503 // When running on a built bot, the file can be made visible in the waterfal
l UI. |
| 1429 return ".flaky.log"; | 1504 return ".flaky.log"; |
| 1430 } | 1505 } |
| 1431 | 1506 |
| 1432 static void ensureExists(String filename, Map configuration) { | 1507 static void ensureExists(String filename, Map configuration) { |
| 1433 if (!configuration['list'] && !(new File(filename).existsSync())) { | 1508 if (!configuration['list'] && !(new File(filename).existsSync())) { |
| 1434 throw "Executable '$filename' does not exist"; | 1509 throw "Executable '$filename' does not exist"; |
| 1435 } | 1510 } |
| 1436 } | 1511 } |
| 1437 | 1512 |
| 1438 static String compilerPath(Map configuration) { | |
| 1439 if (configuration['compiler'] == 'none') { | |
| 1440 return null; // No separate compiler for dartium tests. | |
| 1441 } | |
| 1442 var name = '${buildDir(configuration)}/${compilerName(configuration)}'; | |
| 1443 if (!(new File(name)).existsSync() && !configuration['list']) { | |
| 1444 throw "Executable '$name' does not exist"; | |
| 1445 } | |
| 1446 return name; | |
| 1447 } | |
| 1448 | |
| 1449 static String outputDir(Map configuration) { | 1513 static String outputDir(Map configuration) { |
| 1450 var result = ''; | 1514 var result = ''; |
| 1451 var system = configuration['system']; | 1515 var system = configuration['system']; |
| 1452 if (system == 'linux') { | 1516 if (system == 'linux') { |
| 1453 result = 'out/'; | 1517 result = 'out/'; |
| 1454 } else if (system == 'macos') { | 1518 } else if (system == 'macos') { |
| 1455 result = 'xcodebuild/'; | 1519 result = 'xcodebuild/'; |
| 1456 } else if (system == 'windows') { | 1520 } else if (system == 'windows') { |
| 1457 result = 'build/'; | 1521 result = 'build/'; |
| 1458 } | 1522 } |
| 1459 return result; | 1523 return result; |
| 1460 } | 1524 } |
| 1461 | 1525 |
| 1462 static String buildDir(Map configuration) { | |
| 1463 String mode = (configuration['mode'] == 'debug') ? 'Debug' : 'Release'; | |
| 1464 String arch = configuration['arch'].toUpperCase(); | |
| 1465 return "${outputDir(configuration)}$mode$arch"; | |
| 1466 } | |
| 1467 | |
| 1468 static Path dartDir() { | 1526 static Path dartDir() { |
| 1469 File scriptFile = new File(testScriptPath); | 1527 File scriptFile = new File(testScriptPath); |
| 1470 Path scriptPath = new Path.fromNative(scriptFile.fullPathSync()); | 1528 Path scriptPath = new Path.fromNative(scriptFile.fullPathSync()); |
| 1471 return scriptPath.directoryPath.directoryPath; | 1529 return scriptPath.directoryPath.directoryPath; |
| 1472 } | 1530 } |
| 1473 | 1531 |
| 1474 static List<String> standardOptions(Map configuration) { | 1532 static List<String> standardOptions(Map configuration) { |
| 1475 List args = ["--ignore-unrecognized-flags"]; | 1533 List args = ["--ignore-unrecognized-flags"]; |
| 1476 if (configuration["checked"]) { | 1534 if (configuration["checked"]) { |
| 1477 args.add('--enable_asserts'); | 1535 args.add('--enable_asserts'); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1489 } | 1547 } |
| 1490 } | 1548 } |
| 1491 // TODO(riocw): Unify our minification calling convention between dart2js | 1549 // TODO(riocw): Unify our minification calling convention between dart2js |
| 1492 // and dart2dart. | 1550 // and dart2dart. |
| 1493 if (compiler == "dart2js" && configuration["minified"]) { | 1551 if (compiler == "dart2js" && configuration["minified"]) { |
| 1494 args.add("--minify"); | 1552 args.add("--minify"); |
| 1495 } | 1553 } |
| 1496 return args; | 1554 return args; |
| 1497 } | 1555 } |
| 1498 | 1556 |
| 1499 static String jsshellFileName(Map configuration) { | 1557 static bool usesWebDriver(String runtime) { |
| 1500 var executableSuffix = executableSuffix('jsshell'); | 1558 const BROWSERS = const [ |
| 1501 var executable = 'jsshell$executableSuffix'; | 1559 'dartium', |
| 1502 var jsshellDir = '${dartDir()}/tools/testing/bin'; | 1560 'ie9', |
| 1503 return '$jsshellDir/$executable'; | 1561 'ie10', |
| 1562 'safari', |
| 1563 'opera', |
| 1564 'chrome', |
| 1565 'ff' |
| 1566 ]; |
| 1567 return BROWSERS.contains(runtime); |
| 1504 } | 1568 } |
| 1505 | 1569 |
| 1506 static bool usesWebDriver(String runtime) => Contains( | |
| 1507 runtime, const <String>['dartium', | |
| 1508 'ie9', | |
| 1509 'ie10', | |
| 1510 'safari', | |
| 1511 'opera', | |
| 1512 'chrome', | |
| 1513 'ff']); | |
| 1514 | |
| 1515 static bool isBrowserRuntime(String runtime) => | 1570 static bool isBrowserRuntime(String runtime) => |
| 1516 runtime == 'drt' || TestUtils.usesWebDriver(runtime); | 1571 runtime == 'drt' || TestUtils.usesWebDriver(runtime); |
| 1517 | 1572 |
| 1518 static bool isJsCommandLineRuntime(String runtime) => | 1573 static bool isJsCommandLineRuntime(String runtime) => |
| 1519 Contains(runtime, const <String>['d8', 'jsshell']); | 1574 const ['d8', 'jsshell'].contains(runtime); |
| 1520 | 1575 |
| 1521 } | 1576 } |
| 1522 | 1577 |
| 1523 class SummaryReport { | 1578 class SummaryReport { |
| 1524 static int total = 0; | 1579 static int total = 0; |
| 1525 static int skipped = 0; | 1580 static int skipped = 0; |
| 1526 static int noCrash = 0; | 1581 static int noCrash = 0; |
| 1527 static int pass = 0; | 1582 static int pass = 0; |
| 1528 static int failOk = 0; | 1583 static int failOk = 0; |
| 1529 static int fail = 0; | 1584 static int fail = 0; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1571 * $pass tests are expected to pass | 1626 * $pass tests are expected to pass |
| 1572 * $failOk tests are expected to fail that we won't fix | 1627 * $failOk tests are expected to fail that we won't fix |
| 1573 * $fail tests are expected to fail that we should fix | 1628 * $fail tests are expected to fail that we should fix |
| 1574 * $crash tests are expected to crash that we should fix | 1629 * $crash tests are expected to crash that we should fix |
| 1575 * $timeout tests are allowed to timeout | 1630 * $timeout tests are allowed to timeout |
| 1576 * $compileErrorSkip tests are skipped on browsers due to compile-time error | 1631 * $compileErrorSkip tests are skipped on browsers due to compile-time error |
| 1577 """; | 1632 """; |
| 1578 print(report); | 1633 print(report); |
| 1579 } | 1634 } |
| 1580 } | 1635 } |
| OLD | NEW |