| 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 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 } | 420 } |
| 421 if (expectations.contains(SKIP)) return; | 421 if (expectations.contains(SKIP)) return; |
| 422 | 422 |
| 423 if (configuration['compiler'] != 'none' && info.hasCompileError) { | 423 if (configuration['compiler'] != 'none' && info.hasCompileError) { |
| 424 // If a compile-time error is expected, and we're testing a | 424 // If a compile-time error is expected, and we're testing a |
| 425 // compiler, we never need to attempt to run the program (in a | 425 // compiler, we never need to attempt to run the program (in a |
| 426 // browser or otherwise). | 426 // browser or otherwise). |
| 427 enqueueStandardTest(info, testName, expectations); | 427 enqueueStandardTest(info, testName, expectations); |
| 428 } else if (TestUtils.isBrowserRuntime(configuration['runtime'])) { | 428 } else if (TestUtils.isBrowserRuntime(configuration['runtime'])) { |
| 429 bool isWrappingRequired = configuration['compiler'] != 'dart2js'; | 429 bool isWrappingRequired = configuration['compiler'] != 'dart2js'; |
| 430 enqueueBrowserTest(info, testName, expectations, isWrappingRequired); | 430 if (info.optionsFromFile['isMultiHtmlTest']) { |
| 431 // A browser multi-test has multiple expectations for one test file. |
| 432 // Find all the different sub-test expecations for one entire test file. |
| 433 List<String> subtestNames = info.optionsFromFile['subtestNames']; |
| 434 Map<String, Set<String>> multiHtmlTestExpectations = {}; |
| 435 for (String name in subtestNames) { |
| 436 String fullTestName = '$testName/$name'; |
| 437 multiHtmlTestExpectations[fullTestName] = |
| 438 testExpectations.expectations(fullTestName); |
| 439 } |
| 440 enqueueBrowserTest(info, testName, multiHtmlTestExpectations, |
| 441 isWrappingRequired); |
| 442 } else { |
| 443 enqueueBrowserTest(info, testName, expectations, isWrappingRequired); |
| 444 } |
| 431 } else { | 445 } else { |
| 432 enqueueStandardTest(info, testName, expectations); | 446 enqueueStandardTest(info, testName, expectations); |
| 433 } | 447 } |
| 434 } | 448 } |
| 435 | 449 |
| 436 void enqueueStandardTest(TestInformation info, | 450 void enqueueStandardTest(TestInformation info, |
| 437 String testName, | 451 String testName, |
| 438 Set<String> expectations) { | 452 Set<String> expectations) { |
| 439 bool isNegative = info.hasCompileError || | 453 bool isNegative = info.hasCompileError || |
| 440 (configuration['checked'] && info.isNegativeIfChecked); | 454 (configuration['checked'] && info.isNegativeIfChecked); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 } | 586 } |
| 573 } | 587 } |
| 574 | 588 |
| 575 /** | 589 /** |
| 576 * The [StandardTestSuite] has support for tests that | 590 * The [StandardTestSuite] has support for tests that |
| 577 * compile a test from Dart to JavaScript, and then run the resulting | 591 * compile a test from Dart to JavaScript, and then run the resulting |
| 578 * JavaScript. This function creates a working directory to hold the | 592 * JavaScript. This function creates a working directory to hold the |
| 579 * JavaScript version of the test, and copies the appropriate framework | 593 * JavaScript version of the test, and copies the appropriate framework |
| 580 * files to that directory. It creates a [BrowserTestCase], which has | 594 * files to that directory. It creates a [BrowserTestCase], which has |
| 581 * two sequential steps to be run by the [ProcessQueue] when the test is | 595 * two sequential steps to be run by the [ProcessQueue] when the test is |
| 582 * executed: a compilation | 596 * executed: a compilation step and an execution step, both with the |
| 583 * step and an execution step, both with the appropriate executable and | 597 * appropriate executable and arguments. The [expectations] object can be |
| 584 * arguments. | 598 * 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 |
| 600 * compilation and many browser runs). |
| 585 */ | 601 */ |
| 586 void enqueueBrowserTest(TestInformation info, | 602 void enqueueBrowserTest(TestInformation info, |
| 587 String testName, | 603 String testName, |
| 588 Set<String> expectations, | 604 Object expectations, |
| 589 bool isWrappingRequired) { | 605 bool isWrappingRequired) { |
| 590 Map optionsFromFile = info.optionsFromFile; | 606 Map optionsFromFile = info.optionsFromFile; |
| 591 Path filePath = info.filePath; | 607 Path filePath = info.filePath; |
| 592 String filename = filePath.toString(); | 608 String filename = filePath.toString(); |
| 593 bool isWebTest = optionsFromFile['containsDomImport']; | 609 bool isWebTest = optionsFromFile['containsDomImport']; |
| 594 bool isLibraryDefinition = optionsFromFile['isLibraryDefinition']; | 610 bool isLibraryDefinition = optionsFromFile['isLibraryDefinition']; |
| 595 if (isWrappingRequired | 611 if (isWrappingRequired |
| 596 && !isLibraryDefinition && optionsFromFile['containsSourceOrImport']) { | 612 && !isLibraryDefinition && optionsFromFile['containsSourceOrImport']) { |
| 597 print('Warning for $filename: Browser tests require #library ' | 613 print('Warning for $filename: Browser tests require #library ' |
| 598 'in any file that uses #import, #source, or #resource'); | 614 'in any file that uses #import, #source, or #resource'); |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 Path namePath = new Path(name); | 715 Path namePath = new Path(name); |
| 700 Expect.equals(namePath.extension, 'dart'); | 716 Expect.equals(namePath.extension, 'dart'); |
| 701 String baseName = namePath.filenameWithoutExtension; | 717 String baseName = namePath.filenameWithoutExtension; |
| 702 Path fromPath = filePath.directoryPath.join(namePath); | 718 Path fromPath = filePath.directoryPath.join(namePath); |
| 703 commands.add(_compileCommand( | 719 commands.add(_compileCommand( |
| 704 fromPath.toNativePath(), '$tempDir/$baseName.js', | 720 fromPath.toNativePath(), '$tempDir/$baseName.js', |
| 705 compiler, tempDir, vmOptions)); | 721 compiler, tempDir, vmOptions)); |
| 706 } | 722 } |
| 707 } | 723 } |
| 708 | 724 |
| 725 // Variables for browser multi-tests. |
| 726 List<String> subtestNames = info.optionsFromFile['subtestNames']; |
| 727 TestCase multitestParentTest; |
| 728 int subtestIndex = 0; |
| 709 // Construct the command that executes the browser test | 729 // Construct the command that executes the browser test |
| 710 List<String> args; | 730 constructBrowserTestCommands(); |
| 711 if (TestUtils.usesWebDriver(runtime)) { | 731 do { |
| 712 args = [dartDir.append('tools/testing/run_selenium.py').toNativePath(), | 732 List<String> args = <String>[]; |
| 713 '--browser=$runtime', | 733 String fullHtmlPath = htmlPath; |
| 714 '--timeout=${configuration["timeout"] - 2}', | 734 if (info.optionsFromFile['isMultiHtmlTest'] |
| 715 '--out=$htmlPath']; | 735 && subtestNames.length > 0) { |
| 716 if (runtime == 'dartium') { | 736 fullHtmlPath = '${htmlPath}#${subtestNames[subtestIndex]}'; |
| 717 args.add('--executable=$dartiumFilename'); | |
| 718 } | 737 } |
| 719 } else { | 738 if (TestUtils.usesWebDriver(runtime)) { |
| 720 args = [ | 739 args = [ |
| 721 dartDir.append('tools/testing/drt-trampoline.py').toNativePath(), | 740 dartDir.append('tools/testing/run_selenium.py').toNativePath(), |
| 722 dumpRenderTreeFilename, | 741 '--browser=$runtime', |
| 723 '--no-timeout' | 742 '--timeout=${configuration["timeout"] - 2}', |
| 724 ]; | 743 '--out="$fullHtmlPath"']; |
| 725 if (runtime == 'drt' && | 744 if (runtime == 'dartium') { |
| 726 (compiler == 'none' || compiler == 'dart2dart')) { | 745 args.add('--executable=$dartiumFilename'); |
| 727 var dartFlags = ['--ignore-unrecognized-flags']; | |
| 728 if (configuration["checked"]) { | |
| 729 dartFlags.add('--enable_asserts'); | |
| 730 dartFlags.add("--enable_type_checks"); | |
| 731 } | 746 } |
| 732 dartFlags.addAll(vmOptions); | 747 } else { |
| 733 args.add('--dart-flags=${Strings.join(dartFlags, " ")}'); | 748 args = [ |
| 749 dartDir.append('tools/testing/drt-trampoline.py').toNativePath(), |
| 750 dumpRenderTreeFilename, |
| 751 '--no-timeout' |
| 752 ]; |
| 753 if (runtime == 'drt' && |
| 754 (compiler == 'none' || compiler == 'dart2dart')) { |
| 755 var dartFlags = ['--ignore-unrecognized-flags']; |
| 756 if (configuration["checked"]) { |
| 757 dartFlags.add('--enable_asserts'); |
| 758 dartFlags.add("--enable_type_checks"); |
| 759 } |
| 760 dartFlags.addAll(vmOptions); |
| 761 args.add('--dart-flags=${Strings.join(dartFlags, " ")}'); |
| 762 } |
| 763 args.add(fullHtmlPath); |
| 764 if (expectedOutput != null) { |
| 765 args.add('--out-expectation=${expectedOutput.toNativePath()}'); |
| 766 } |
| 734 } | 767 } |
| 735 args.add(htmlPath); | 768 List<String> commandSet = new List<String>.from(commands); |
| 736 if (expectedOutput != null) { | 769 if (subtestIndex != 0) { |
| 737 args.add('--out-expectation=${expectedOutput.toNativePath()}'); | 770 commandSet = []; |
| 771 args.add('--force-refresh'); |
| 738 } | 772 } |
| 739 } | 773 commandSet.add(new Command('python', args)); |
| 740 commands.add(new Command('python', args)); | |
| 741 | 774 |
| 742 // Create BrowserTestCase and queue it. | 775 // Create BrowserTestCase and queue it. |
| 743 var testCase = new BrowserTestCase('$suiteName/$testName', | 776 String testDisplayName = '$suiteName/$testName'; |
| 744 commands, configuration, completeHandler, expectations, | 777 var testCase; |
| 745 info, info.hasCompileError || info.hasRuntimeError); | 778 if (info.optionsFromFile['isMultiHtmlTest']) { |
| 746 doTest(testCase); | 779 testDisplayName = '$testDisplayName/${subtestNames[subtestIndex]}'; |
| 780 testCase = new BrowserTestCase(testDisplayName, |
| 781 commandSet, configuration, completeHandler, |
| 782 expectations['$testName/${subtestNames[subtestIndex]}'], |
| 783 info, info.hasCompileError || info.hasRuntimeError, |
| 784 subtestIndex != 0); |
| 785 } else { |
| 786 testCase = new BrowserTestCase(testDisplayName, |
| 787 commandSet, configuration, completeHandler, expectations, |
| 788 info, info.hasCompileError || info.hasRuntimeError, false); |
| 789 } |
| 790 if (subtestIndex == 0) { |
| 791 multitestParentTest = testCase; |
| 792 } else { |
| 793 multitestParentTest.addObserver(testCase); |
| 794 } |
| 795 doTest(testCase); |
| 796 subtestIndex++; |
| 797 } while(subtestIndex < subtestNames.length); |
| 747 } | 798 } |
| 748 } | 799 } |
| 749 | 800 |
| 801 void constructBrowserTestCommands() { |
| 802 |
| 803 } |
| 804 |
| 750 /** Helper to create a compilation command for a single input file. */ | 805 /** Helper to create a compilation command for a single input file. */ |
| 751 Command _compileCommand(String inputFile, String outputFile, | 806 Command _compileCommand(String inputFile, String outputFile, |
| 752 String compiler, String dir, var vmOptions) { | 807 String compiler, String dir, var vmOptions) { |
| 753 String executable = TestUtils.compilerPath(configuration); | 808 String executable = TestUtils.compilerPath(configuration); |
| 754 List<String> args = TestUtils.standardOptions(configuration); | 809 List<String> args = TestUtils.standardOptions(configuration); |
| 755 switch (compiler) { | 810 switch (compiler) { |
| 756 case 'dart2js': | 811 case 'dart2js': |
| 757 case 'dart2dart': | 812 case 'dart2dart': |
| 758 if (compiler == 'dart2dart') args.add('--out=$outputFile'); | 813 if (compiler == 'dart2dart') args.add('--out=$outputFile'); |
| 759 args.add('--out=$outputFile'); | 814 args.add('--out=$outputFile'); |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 962 * executing the copy command printed by the test script. | 1017 * executing the copy command printed by the test script. |
| 963 * | 1018 * |
| 964 * This method is static as the map is cached and shared amongst | 1019 * This method is static as the map is cached and shared amongst |
| 965 * configurations, so it may not use [configuration]. | 1020 * configurations, so it may not use [configuration]. |
| 966 */ | 1021 */ |
| 967 static Map readOptionsFromFile(Path filePath) { | 1022 static Map readOptionsFromFile(Path filePath) { |
| 968 RegExp testOptionsRegExp = const RegExp(r"// VMOptions=(.*)"); | 1023 RegExp testOptionsRegExp = const RegExp(r"// VMOptions=(.*)"); |
| 969 RegExp dartOptionsRegExp = const RegExp(r"// DartOptions=(.*)"); | 1024 RegExp dartOptionsRegExp = const RegExp(r"// DartOptions=(.*)"); |
| 970 RegExp otherScriptsRegExp = const RegExp(r"// OtherScripts=(.*)"); | 1025 RegExp otherScriptsRegExp = const RegExp(r"// OtherScripts=(.*)"); |
| 971 RegExp multiTestRegExp = const RegExp(r"/// [0-9][0-9]:(.*)"); | 1026 RegExp multiTestRegExp = const RegExp(r"/// [0-9][0-9]:(.*)"); |
| 1027 RegExp multiHtmlTestRegExp = |
| 1028 const RegExp(r"useHtmlIndividualConfiguration()"); |
| 972 RegExp staticTypeRegExp = | 1029 RegExp staticTypeRegExp = |
| 973 const RegExp(r"/// ([0-9][0-9]:){0,1}\s*static type warning"); | 1030 const RegExp(r"/// ([0-9][0-9]:){0,1}\s*static type warning"); |
| 974 RegExp compileTimeRegExp = | 1031 RegExp compileTimeRegExp = |
| 975 const RegExp(r"/// ([0-9][0-9]:){0,1}\s*compile-time error"); | 1032 const RegExp(r"/// ([0-9][0-9]:){0,1}\s*compile-time error"); |
| 976 RegExp staticCleanRegExp = const RegExp(r"// @static-clean"); | 1033 RegExp staticCleanRegExp = const RegExp(r"// @static-clean"); |
| 977 RegExp leadingHashRegExp = const RegExp(r"^#", multiLine: true); | 1034 RegExp leadingHashRegExp = const RegExp(r"^#", multiLine: true); |
| 978 RegExp isolateStubsRegExp = const RegExp(r"// IsolateStubs=(.*)"); | 1035 RegExp isolateStubsRegExp = const RegExp(r"// IsolateStubs=(.*)"); |
| 979 // TODO(gram) Clean these up once the old directives are not supported. | 1036 // TODO(gram) Clean these up once the old directives are not supported. |
| 980 RegExp domImportRegExp = | 1037 RegExp domImportRegExp = |
| 981 const RegExp(r"^[#]?import.*dart:html", multiLine: true); | 1038 const RegExp(r"^[#]?import.*dart:html", multiLine: true); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1028 isStaticClean = true; | 1085 isStaticClean = true; |
| 1029 } | 1086 } |
| 1030 | 1087 |
| 1031 List<String> otherScripts = new List<String>(); | 1088 List<String> otherScripts = new List<String>(); |
| 1032 matches = otherScriptsRegExp.allMatches(contents); | 1089 matches = otherScriptsRegExp.allMatches(contents); |
| 1033 for (var match in matches) { | 1090 for (var match in matches) { |
| 1034 otherScripts.addAll(match[1].split(' ').filter((e) => e != '')); | 1091 otherScripts.addAll(match[1].split(' ').filter((e) => e != '')); |
| 1035 } | 1092 } |
| 1036 | 1093 |
| 1037 bool isMultitest = multiTestRegExp.hasMatch(contents); | 1094 bool isMultitest = multiTestRegExp.hasMatch(contents); |
| 1095 bool isMultiHtmlTest = multiHtmlTestRegExp.hasMatch(contents); |
| 1038 bool containsLeadingHash = leadingHashRegExp.hasMatch(contents); | 1096 bool containsLeadingHash = leadingHashRegExp.hasMatch(contents); |
| 1039 Match isolateMatch = isolateStubsRegExp.firstMatch(contents); | 1097 Match isolateMatch = isolateStubsRegExp.firstMatch(contents); |
| 1040 String isolateStubs = isolateMatch != null ? isolateMatch[1] : ''; | 1098 String isolateStubs = isolateMatch != null ? isolateMatch[1] : ''; |
| 1041 bool containsDomImport = domImportRegExp.hasMatch(contents); | 1099 bool containsDomImport = domImportRegExp.hasMatch(contents); |
| 1042 bool isLibraryDefinition = libraryDefinitionRegExp.hasMatch(contents); | 1100 bool isLibraryDefinition = libraryDefinitionRegExp.hasMatch(contents); |
| 1043 bool containsSourceOrImport = sourceOrImportRegExp.hasMatch(contents); | 1101 bool containsSourceOrImport = sourceOrImportRegExp.hasMatch(contents); |
| 1044 int numStaticTypeAnnotations = 0; | 1102 int numStaticTypeAnnotations = 0; |
| 1045 for (var i in staticTypeRegExp.allMatches(contents)) { | 1103 for (var i in staticTypeRegExp.allMatches(contents)) { |
| 1046 numStaticTypeAnnotations++; | 1104 numStaticTypeAnnotations++; |
| 1047 } | 1105 } |
| 1048 int numCompileTimeAnnotations = 0; | 1106 int numCompileTimeAnnotations = 0; |
| 1049 for (var i in compileTimeRegExp.allMatches(contents)) { | 1107 for (var i in compileTimeRegExp.allMatches(contents)) { |
| 1050 numCompileTimeAnnotations++; | 1108 numCompileTimeAnnotations++; |
| 1051 } | 1109 } |
| 1052 | 1110 |
| 1111 // Note: This is brittle. It's the age-old problem of having a context free |
| 1112 // language but the means to easily identify the construct is a regular |
| 1113 // expression, aka impossible. Therefore we just make an approximation of |
| 1114 // the number of top-level "group(...)" occurrences. This assumes you import |
| 1115 // unittest with no prefix and always directly call "group(". It only uses |
| 1116 // top-level "groups" so tests running nested groups will be no-ops. |
| 1117 RegExp numTests = new RegExp(r"\s*[^/]\s*group\('[^,']*"); |
| 1118 List<String> subtestNames = []; |
| 1119 Iterator matchesIter = numTests.allMatches(contents).iterator(); |
| 1120 while(matchesIter.hasNext && isMultiHtmlTest) { |
| 1121 String fullMatch = matchesIter.next().group(0); |
| 1122 subtestNames.add(fullMatch.substring(fullMatch.indexOf("'") + 1)); |
| 1123 } |
| 1124 |
| 1053 return { "vmOptions": result, | 1125 return { "vmOptions": result, |
| 1054 "dartOptions": dartOptions, | 1126 "dartOptions": dartOptions, |
| 1055 "hasCompileError": hasCompileError, | 1127 "hasCompileError": hasCompileError, |
| 1056 "hasRuntimeError": hasRuntimeError, | 1128 "hasRuntimeError": hasRuntimeError, |
| 1057 "isStaticClean" : isStaticClean, | 1129 "isStaticClean" : isStaticClean, |
| 1058 "otherScripts": otherScripts, | 1130 "otherScripts": otherScripts, |
| 1059 "isMultitest": isMultitest, | 1131 "isMultitest": isMultitest, |
| 1132 "isMultiHtmlTest": isMultiHtmlTest, |
| 1133 "subtestNames": subtestNames, |
| 1060 "containsLeadingHash": containsLeadingHash, | 1134 "containsLeadingHash": containsLeadingHash, |
| 1061 "isolateStubs": isolateStubs, | 1135 "isolateStubs": isolateStubs, |
| 1062 "containsDomImport": containsDomImport, | 1136 "containsDomImport": containsDomImport, |
| 1063 "isLibraryDefinition": isLibraryDefinition, | 1137 "isLibraryDefinition": isLibraryDefinition, |
| 1064 "containsSourceOrImport": containsSourceOrImport, | 1138 "containsSourceOrImport": containsSourceOrImport, |
| 1065 "numStaticTypeAnnotations": numStaticTypeAnnotations, | 1139 "numStaticTypeAnnotations": numStaticTypeAnnotations, |
| 1066 "numCompileTimeAnnotations": numCompileTimeAnnotations }; | 1140 "numCompileTimeAnnotations": numCompileTimeAnnotations }; |
| 1067 } | 1141 } |
| 1068 | 1142 |
| 1069 List<List<String>> getVmOptions(Map optionsFromFile) { | 1143 List<List<String>> getVmOptions(Map optionsFromFile) { |
| (...skipping 423 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1493 * $pass tests are expected to pass | 1567 * $pass tests are expected to pass |
| 1494 * $failOk tests are expected to fail that we won't fix | 1568 * $failOk tests are expected to fail that we won't fix |
| 1495 * $fail tests are expected to fail that we should fix | 1569 * $fail tests are expected to fail that we should fix |
| 1496 * $crash tests are expected to crash that we should fix | 1570 * $crash tests are expected to crash that we should fix |
| 1497 * $timeout tests are allowed to timeout | 1571 * $timeout tests are allowed to timeout |
| 1498 * $compileErrorSkip tests are skipped on browsers due to compile-time error | 1572 * $compileErrorSkip tests are skipped on browsers due to compile-time error |
| 1499 """; | 1573 """; |
| 1500 print(report); | 1574 print(report); |
| 1501 } | 1575 } |
| 1502 } | 1576 } |
| OLD | NEW |