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 * 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, |
| 11 * and creating [TestCase]s for those files that meet the relevant criteria. | 11 * and creating [TestCase]s for those files that meet the relevant criteria. |
| 12 * - Preparing tests, including copying files and frameworks to temporary | 12 * - Preparing tests, including copying files and frameworks to temporary |
| 13 * directories, and computing the command line and arguments to be run. | 13 * directories, and computing the command line and arguments to be run. |
| 14 */ | 14 */ |
| 15 library test_suite; | 15 library test_suite; |
| 16 | 16 |
| 17 import "dart:async"; | |
| 17 import "dart:io"; | 18 import "dart:io"; |
| 18 import "dart:isolate"; | 19 import "dart:isolate"; |
| 19 import "status_file_parser.dart"; | 20 import "status_file_parser.dart"; |
| 20 import "test_runner.dart"; | 21 import "test_runner.dart"; |
| 21 import "multitest.dart"; | 22 import "multitest.dart"; |
| 22 import "drt_updater.dart"; | 23 import "drt_updater.dart"; |
| 23 import "dart:uri"; | 24 import "dart:uri"; |
| 24 | 25 |
| 25 part "browser_test.dart"; | 26 part "browser_test.dart"; |
| 26 | 27 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 Completer<List> _completer = new Completer<List>(); | 66 Completer<List> _completer = new Completer<List>(); |
| 66 final List<Future> futures = <Future>[]; | 67 final List<Future> futures = <Future>[]; |
| 67 | 68 |
| 68 /** | 69 /** |
| 69 * Wait for [task] to complete (assuming this barrier has not already been | 70 * Wait for [task] to complete (assuming this barrier has not already been |
| 70 * marked as completed, otherwise you'll get an exception indicating that a | 71 * marked as completed, otherwise you'll get an exception indicating that a |
| 71 * future has already been completed). | 72 * future has already been completed). |
| 72 */ | 73 */ |
| 73 void add(Future task) { | 74 void add(Future task) { |
| 74 if (_pending == _FINISHED) { | 75 if (_pending == _FINISHED) { |
| 75 throw new FutureAlreadyCompleteException(); | 76 throw new Exception("FutureFutureAlreadyCompleteException"); |
| 76 } | 77 } |
| 77 _pending++; | 78 _pending++; |
| 78 futures.add(task); | 79 futures.add(task); |
|
Bill Hesse
2013/01/09 17:06:33
Add the return value of task.catchError(...).then(
kustermann
2013/01/09 18:02:25
Done.
| |
| 79 task.handleException( | 80 task.catchError( |
| 80 (e) => _completer.completeException(e, task.stackTrace)); | 81 (e) => _completer.completeError(e.error, task.stackTrace)); |
| 81 task.then((_) { | 82 task.then((_) { |
| 82 _pending--; | 83 _pending--; |
| 83 if (_pending == 0) { | 84 if (_pending == 0) { |
| 84 _pending = _FINISHED; | 85 _pending = _FINISHED; |
| 85 _completer.complete(futures); | 86 _completer.complete(futures); |
| 86 } | 87 } |
| 87 }); | 88 }); |
| 88 } | 89 } |
| 89 | 90 |
| 90 Future<List> get future => _completer.future; | 91 Future<List> get future => _completer.future; |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 266 if (code < 0) { | 267 if (code < 0) { |
| 267 print("Failed to list tests: $runnerPath --list"); | 268 print("Failed to list tests: $runnerPath --list"); |
| 268 replyTo.send(""); | 269 replyTo.send(""); |
| 269 } else { | 270 } else { |
| 270 processExited = true; | 271 processExited = true; |
| 271 checkDone(); | 272 checkDone(); |
| 272 } | 273 } |
| 273 }; | 274 }; |
| 274 port.close(); | 275 port.close(); |
| 275 }); | 276 }); |
| 276 processFuture.handleException((e) { | 277 processFuture.catchError((e) { |
|
Bill Hesse
2013/01/09 17:06:33
another
kustermann
2013/01/09 18:02:25
Done.
| |
| 277 print("Failed to list tests: $runnerPath --list"); | 278 print("Failed to list tests: $runnerPath --list"); |
| 278 replyTo.send(""); | 279 replyTo.send(""); |
| 279 return true; | 280 return true; |
| 280 }); | 281 }); |
| 281 }); | 282 }); |
| 282 } | 283 } |
| 283 | 284 |
| 284 | 285 |
| 285 /** | 286 /** |
| 286 * A specialized [TestSuite] that runs tests written in C to unit test | 287 * A specialized [TestSuite] that runs tests written in C to unit test |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 467 bool isTestFile(String filename) { | 468 bool isTestFile(String filename) { |
| 468 // Use the specified predicate, if provided. | 469 // Use the specified predicate, if provided. |
| 469 if (isTestFilePredicate != null) return isTestFilePredicate(filename); | 470 if (isTestFilePredicate != null) return isTestFilePredicate(filename); |
| 470 | 471 |
| 471 return filename.endsWith("Test.dart"); | 472 return filename.endsWith("Test.dart"); |
| 472 } | 473 } |
| 473 | 474 |
| 474 List<String> additionalOptions(Path filePath) => []; | 475 List<String> additionalOptions(Path filePath) => []; |
| 475 | 476 |
| 476 void forEachTest(TestCaseEvent onTest, Map testCache, [VoidFunction onDone]) { | 477 void forEachTest(TestCaseEvent onTest, Map testCache, [VoidFunction onDone]) { |
| 477 updateDartium().chain((_) { | 478 updateDartium().then((_) { |
| 478 doTest = onTest; | 479 doTest = onTest; |
| 479 | 480 |
| 480 return readExpectations(); | 481 return readExpectations(); |
| 481 }).chain((expectations) { | 482 }).then((expectations) { |
| 482 testExpectations = expectations; | 483 testExpectations = expectations; |
| 483 | 484 |
| 484 // Checked if we have already found and generated the tests for | 485 // Checked if we have already found and generated the tests for |
| 485 // this suite. | 486 // this suite. |
| 486 if (!testCache.containsKey(suiteName)) { | 487 if (!testCache.containsKey(suiteName)) { |
| 487 cachedTests = testCache[suiteName] = []; | 488 cachedTests = testCache[suiteName] = []; |
| 488 return enqueueTests(); | 489 return enqueueTests(); |
| 489 } else { | 490 } else { |
| 490 // We rely on enqueueing completing asynchronously. | 491 // We rely on enqueueing completing asynchronously. |
| 491 return asynchronously(() { | 492 return asynchronously(() { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 545 ReadTestExpectationsInto(expectations, | 546 ReadTestExpectationsInto(expectations, |
| 546 dartDir.append(statusFilePath).toNativePath(), | 547 dartDir.append(statusFilePath).toNativePath(), |
| 547 configuration, statusFileRead); | 548 configuration, statusFileRead); |
| 548 } | 549 } |
| 549 | 550 |
| 550 return completer.future; | 551 return completer.future; |
| 551 } | 552 } |
| 552 | 553 |
| 553 Future enqueueTests() { | 554 Future enqueueTests() { |
| 554 Directory dir = new Directory.fromPath(suiteDir); | 555 Directory dir = new Directory.fromPath(suiteDir); |
| 555 return dir.exists().chain((exists) { | 556 return dir.exists().then((exists) { |
| 556 if (!exists) { | 557 if (!exists) { |
| 557 print('Directory containing tests missing: ${suiteDir.toNativePath()}'); | 558 print('Directory containing tests missing: ${suiteDir.toNativePath()}'); |
| 558 return new Future.immediate(null); | 559 return new Future.immediate(null); |
| 559 } else { | 560 } else { |
| 560 var group = new FutureGroup(); | 561 var group = new FutureGroup(); |
| 561 enqueueDirectory(dir, group); | 562 enqueueDirectory(dir, group); |
| 562 return group.future; | 563 return group.future; |
| 563 } | 564 } |
| 564 }); | 565 }); |
| 565 } | 566 } |
| (...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1313 // Find the options in the file. | 1314 // Find the options in the file. |
| 1314 List<List> result = new List<List>(); | 1315 List<List> result = new List<List>(); |
| 1315 List<String> dartOptions; | 1316 List<String> dartOptions; |
| 1316 String packageRoot; | 1317 String packageRoot; |
| 1317 bool hasCompileError = contents.contains("@compile-error"); | 1318 bool hasCompileError = contents.contains("@compile-error"); |
| 1318 bool hasRuntimeError = contents.contains("@runtime-error"); | 1319 bool hasRuntimeError = contents.contains("@runtime-error"); |
| 1319 bool isStaticClean = false; | 1320 bool isStaticClean = false; |
| 1320 | 1321 |
| 1321 Iterable<Match> matches = testOptionsRegExp.allMatches(contents); | 1322 Iterable<Match> matches = testOptionsRegExp.allMatches(contents); |
| 1322 for (var match in matches) { | 1323 for (var match in matches) { |
| 1323 result.add(match[1].split(' ').filter((e) => e != '')); | 1324 result.add(match[1].split(' ').where((e) => e != '').toList()); |
| 1324 } | 1325 } |
| 1325 if (result.isEmpty) result.add([]); | 1326 if (result.isEmpty) result.add([]); |
| 1326 | 1327 |
| 1327 matches = dartOptionsRegExp.allMatches(contents); | 1328 matches = dartOptionsRegExp.allMatches(contents); |
| 1328 for (var match in matches) { | 1329 for (var match in matches) { |
| 1329 if (dartOptions != null) { | 1330 if (dartOptions != null) { |
| 1330 throw new Exception( | 1331 throw new Exception( |
| 1331 'More than one "// DartOptions=" line in test $filePath'); | 1332 'More than one "// DartOptions=" line in test $filePath'); |
| 1332 } | 1333 } |
| 1333 dartOptions = match[1].split(' ').filter((e) => e != ''); | 1334 dartOptions = match[1].split(' ').where((e) => e != '').toList(); |
| 1334 } | 1335 } |
| 1335 | 1336 |
| 1336 matches = packageRootRegExp.allMatches(contents); | 1337 matches = packageRootRegExp.allMatches(contents); |
| 1337 for (var match in matches) { | 1338 for (var match in matches) { |
| 1338 if (packageRoot != null) { | 1339 if (packageRoot != null) { |
| 1339 throw new Exception( | 1340 throw new Exception( |
| 1340 'More than one "// PackageRoot=" line in test $filePath'); | 1341 'More than one "// PackageRoot=" line in test $filePath'); |
| 1341 } | 1342 } |
| 1342 packageRoot = match[1]; | 1343 packageRoot = match[1]; |
| 1343 if (packageRoot != 'none') { | 1344 if (packageRoot != 'none') { |
| 1344 // PackageRoot=none means that no package-root option should be given. | 1345 // PackageRoot=none means that no package-root option should be given. |
| 1345 packageRoot = '${filePath.directoryPath.join(new Path(packageRoot))}'; | 1346 packageRoot = '${filePath.directoryPath.join(new Path(packageRoot))}'; |
| 1346 } | 1347 } |
| 1347 } | 1348 } |
| 1348 | 1349 |
| 1349 matches = staticCleanRegExp.allMatches(contents); | 1350 matches = staticCleanRegExp.allMatches(contents); |
| 1350 for (var match in matches) { | 1351 for (var match in matches) { |
| 1351 if (isStaticClean) { | 1352 if (isStaticClean) { |
| 1352 throw new Exception( | 1353 throw new Exception( |
| 1353 'More than one "// @static-clean=" line in test $filePath'); | 1354 'More than one "// @static-clean=" line in test $filePath'); |
| 1354 } | 1355 } |
| 1355 isStaticClean = true; | 1356 isStaticClean = true; |
| 1356 } | 1357 } |
| 1357 | 1358 |
| 1358 List<String> otherScripts = new List<String>(); | 1359 List<String> otherScripts = new List<String>(); |
| 1359 matches = otherScriptsRegExp.allMatches(contents); | 1360 matches = otherScriptsRegExp.allMatches(contents); |
| 1360 for (var match in matches) { | 1361 for (var match in matches) { |
| 1361 otherScripts.addAll(match[1].split(' ').filter((e) => e != '')); | 1362 otherScripts.addAll(match[1].split(' ').where((e) => e != '').toList()); |
| 1362 } | 1363 } |
| 1363 | 1364 |
| 1364 bool isMultitest = multiTestRegExp.hasMatch(contents); | 1365 bool isMultitest = multiTestRegExp.hasMatch(contents); |
| 1365 bool isMultiHtmlTest = multiHtmlTestRegExp.hasMatch(contents); | 1366 bool isMultiHtmlTest = multiHtmlTestRegExp.hasMatch(contents); |
| 1366 bool containsLeadingHash = leadingHashRegExp.hasMatch(contents); | 1367 bool containsLeadingHash = leadingHashRegExp.hasMatch(contents); |
| 1367 Match isolateMatch = isolateStubsRegExp.firstMatch(contents); | 1368 Match isolateMatch = isolateStubsRegExp.firstMatch(contents); |
| 1368 String isolateStubs = isolateMatch != null ? isolateMatch[1] : ''; | 1369 String isolateStubs = isolateMatch != null ? isolateMatch[1] : ''; |
| 1369 bool containsDomImport = domImportRegExp.hasMatch(contents); | 1370 bool containsDomImport = domImportRegExp.hasMatch(contents); |
| 1370 bool isLibraryDefinition = libraryDefinitionRegExp.hasMatch(contents); | 1371 bool isLibraryDefinition = libraryDefinitionRegExp.hasMatch(contents); |
| 1371 bool containsSourceOrImport = sourceOrImportRegExp.hasMatch(contents); | 1372 bool containsSourceOrImport = sourceOrImportRegExp.hasMatch(contents); |
| 1372 int numStaticTypeAnnotations = 0; | 1373 int numStaticTypeAnnotations = 0; |
| 1373 for (var i in staticTypeRegExp.allMatches(contents)) { | 1374 for (var i in staticTypeRegExp.allMatches(contents)) { |
| 1374 numStaticTypeAnnotations++; | 1375 numStaticTypeAnnotations++; |
| 1375 } | 1376 } |
| 1376 int numCompileTimeAnnotations = 0; | 1377 int numCompileTimeAnnotations = 0; |
| 1377 for (var i in compileTimeRegExp.allMatches(contents)) { | 1378 for (var i in compileTimeRegExp.allMatches(contents)) { |
| 1378 numCompileTimeAnnotations++; | 1379 numCompileTimeAnnotations++; |
| 1379 } | 1380 } |
| 1380 | 1381 |
| 1381 // Note: This is brittle. It's the age-old problem of having a context free | 1382 // Note: This is brittle. It's the age-old problem of having a context free |
| 1382 // language but the means to easily identify the construct is a regular | 1383 // language but the means to easily identify the construct is a regular |
| 1383 // expression, aka impossible. Therefore we just make an approximation of | 1384 // expression, aka impossible. Therefore we just make an approximation of |
| 1384 // the number of top-level "group(...)" occurrences. This assumes you import | 1385 // the number of top-level "group(...)" occurrences. This assumes you import |
| 1385 // unittest with no prefix and always directly call "group(". It only uses | 1386 // unittest with no prefix and always directly call "group(". It only uses |
| 1386 // top-level "groups" so tests running nested groups will be no-ops. | 1387 // top-level "groups" so tests running nested groups will be no-ops. |
| 1387 RegExp numTests = new RegExp(r"\s*[^/]\s*group\('[^,']*"); | 1388 RegExp numTests = new RegExp(r"\s*[^/]\s*group\('[^,']*"); |
| 1388 List<String> subtestNames = []; | 1389 List<String> subtestNames = []; |
| 1389 Iterator matchesIter = numTests.allMatches(contents).iterator(); | 1390 Iterator matchesIter = numTests.allMatches(contents).iterator; |
| 1390 while(matchesIter.hasNext && isMultiHtmlTest) { | 1391 while(matchesIter.moveNext() && isMultiHtmlTest) { |
| 1391 String fullMatch = matchesIter.next().group(0); | 1392 String fullMatch = matchesIter.current.group(0); |
| 1392 subtestNames.add(fullMatch.substring(fullMatch.indexOf("'") + 1)); | 1393 subtestNames.add(fullMatch.substring(fullMatch.indexOf("'") + 1)); |
| 1393 } | 1394 } |
| 1394 | 1395 |
| 1395 return { "vmOptions": result, | 1396 return { "vmOptions": result, |
| 1396 "dartOptions": dartOptions, | 1397 "dartOptions": dartOptions, |
| 1397 "packageRoot": packageRoot, | 1398 "packageRoot": packageRoot, |
| 1398 "hasCompileError": hasCompileError, | 1399 "hasCompileError": hasCompileError, |
| 1399 "hasRuntimeError": hasRuntimeError, | 1400 "hasRuntimeError": hasRuntimeError, |
| 1400 "isStaticClean" : isStaticClean, | 1401 "isStaticClean" : isStaticClean, |
| 1401 "otherScripts": otherScripts, | 1402 "otherScripts": otherScripts, |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1806 * $pass tests are expected to pass | 1807 * $pass tests are expected to pass |
| 1807 * $failOk tests are expected to fail that we won't fix | 1808 * $failOk tests are expected to fail that we won't fix |
| 1808 * $fail tests are expected to fail that we should fix | 1809 * $fail tests are expected to fail that we should fix |
| 1809 * $crash tests are expected to crash that we should fix | 1810 * $crash tests are expected to crash that we should fix |
| 1810 * $timeout tests are allowed to timeout | 1811 * $timeout tests are allowed to timeout |
| 1811 * $compileErrorSkip tests are skipped on browsers due to compile-time error | 1812 * $compileErrorSkip tests are skipped on browsers due to compile-time error |
| 1812 """; | 1813 """; |
| 1813 print(report); | 1814 print(report); |
| 1814 } | 1815 } |
| 1815 } | 1816 } |
| OLD | NEW |