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