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, |
| (...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 415 } | 415 } |
| 416 if (expectations.contains(SKIP)) return; | 416 if (expectations.contains(SKIP)) return; |
| 417 | 417 |
| 418 if (configuration['compiler'] != 'none' && info.hasCompileError) { | 418 if (configuration['compiler'] != 'none' && info.hasCompileError) { |
| 419 // If a compile-time error is expected, and we're testing a | 419 // If a compile-time error is expected, and we're testing a |
| 420 // compiler, we never need to attempt to run the program (in a | 420 // compiler, we never need to attempt to run the program (in a |
| 421 // browser or otherwise). | 421 // browser or otherwise). |
| 422 enqueueStandardTest(info, testName, expectations); | 422 enqueueStandardTest(info, testName, expectations); |
| 423 } else if (TestUtils.isBrowserRuntime(configuration['runtime'])) { | 423 } else if (TestUtils.isBrowserRuntime(configuration['runtime'])) { |
| 424 bool isWrappingRequired = configuration['compiler'] != 'dart2js'; | 424 bool isWrappingRequired = configuration['compiler'] != 'dart2js'; |
| 425 enqueueBrowserTest(info, testName, expectations, isWrappingRequired); | 425 if (info.optionsFromFile['isMultiHtmlTest']) { |
| 426 // A browser multi-test has multiple expectations for one test file. | |
| 427 // Find all the different sub-test expecations for one entire test file. | |
| 428 List<String> subtestNames = info.optionsFromFile['subtestNames']; | |
| 429 Map<String, Set<String>> multiHtmlTestExpectations = {}; | |
| 430 for (String name in subtestNames) { | |
| 431 String fullTestName = '$testName/$name'; | |
| 432 multiHtmlTestExpectations[fullTestName] = | |
| 433 testExpectations.expectations(fullTestName); | |
| 434 } | |
| 435 enqueueBrowserTest(info, testName, multiHtmlTestExpectations, | |
| 436 isWrappingRequired); | |
| 437 } else { | |
| 438 enqueueBrowserTest(info, testName, expectations, isWrappingRequired); | |
| 439 } | |
| 426 } else { | 440 } else { |
| 427 enqueueStandardTest(info, testName, expectations); | 441 enqueueStandardTest(info, testName, expectations); |
| 428 } | 442 } |
| 429 } | 443 } |
| 430 | 444 |
| 431 void enqueueStandardTest(TestInformation info, | 445 void enqueueStandardTest(TestInformation info, |
| 432 String testName, | 446 String testName, |
| 433 Set<String> expectations) { | 447 Set<String> expectations) { |
| 434 bool isNegative = info.hasCompileError || | 448 bool isNegative = info.hasCompileError || |
| 435 (configuration['checked'] && info.isNegativeIfChecked); | 449 (configuration['checked'] && info.isNegativeIfChecked); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 567 } | 581 } |
| 568 } | 582 } |
| 569 | 583 |
| 570 /** | 584 /** |
| 571 * The [StandardTestSuite] has support for tests that | 585 * The [StandardTestSuite] has support for tests that |
| 572 * compile a test from Dart to JavaScript, and then run the resulting | 586 * compile a test from Dart to JavaScript, and then run the resulting |
| 573 * JavaScript. This function creates a working directory to hold the | 587 * JavaScript. This function creates a working directory to hold the |
| 574 * JavaScript version of the test, and copies the appropriate framework | 588 * JavaScript version of the test, and copies the appropriate framework |
| 575 * files to that directory. It creates a [BrowserTestCase], which has | 589 * files to that directory. It creates a [BrowserTestCase], which has |
| 576 * two sequential steps to be run by the [ProcessQueue] when the test is | 590 * two sequential steps to be run by the [ProcessQueue] when the test is |
| 577 * executed: a compilation | 591 * executed: a compilation step and an execution step, both with the |
| 578 * step and an execution step, both with the appropriate executable and | 592 * appropriate executable and arguments. The [expectations] object can be |
| 579 * arguments. | 593 * either a Set<String> if the test is a regular test, or a Map<String |
| 594 * subTestName, Set<String>> if we are running a browser multi-test (one | |
| 595 * compilation and many browser runs). | |
| 580 */ | 596 */ |
| 581 void enqueueBrowserTest(TestInformation info, | 597 void enqueueBrowserTest(TestInformation info, |
| 582 String testName, | 598 String testName, |
| 583 Set<String> expectations, | 599 Object expectations, |
| 584 bool isWrappingRequired) { | 600 bool isWrappingRequired) { |
| 585 Map optionsFromFile = info.optionsFromFile; | 601 Map optionsFromFile = info.optionsFromFile; |
| 586 Path filePath = info.filePath; | 602 Path filePath = info.filePath; |
| 587 String filename = filePath.toString(); | 603 String filename = filePath.toString(); |
| 588 bool isWebTest = optionsFromFile['containsDomImport']; | 604 bool isWebTest = optionsFromFile['containsDomImport']; |
| 589 bool isLibraryDefinition = optionsFromFile['isLibraryDefinition']; | 605 bool isLibraryDefinition = optionsFromFile['isLibraryDefinition']; |
| 590 if (isWrappingRequired | 606 if (isWrappingRequired |
| 591 && !isLibraryDefinition && optionsFromFile['containsSourceOrImport']) { | 607 && !isLibraryDefinition && optionsFromFile['containsSourceOrImport']) { |
| 592 print('Warning for $filename: Browser tests require #library ' | 608 print('Warning for $filename: Browser tests require #library ' |
| 593 'in any file that uses #import, #source, or #resource'); | 609 'in any file that uses #import, #source, or #resource'); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 695 Expect.equals(namePath.extension, 'dart'); | 711 Expect.equals(namePath.extension, 'dart'); |
| 696 String baseName = namePath.filenameWithoutExtension; | 712 String baseName = namePath.filenameWithoutExtension; |
| 697 Path fromPath = filePath.directoryPath.join(namePath); | 713 Path fromPath = filePath.directoryPath.join(namePath); |
| 698 commands.add(_compileCommand( | 714 commands.add(_compileCommand( |
| 699 fromPath.toNativePath(), '$tempDir/$baseName.js', | 715 fromPath.toNativePath(), '$tempDir/$baseName.js', |
| 700 compiler, tempDir, vmOptions)); | 716 compiler, tempDir, vmOptions)); |
| 701 } | 717 } |
| 702 } | 718 } |
| 703 | 719 |
| 704 // Construct the command that executes the browser test | 720 // Construct the command that executes the browser test |
| 705 List<String> args; | 721 List<String> subtestNames = info.optionsFromFile['subtestNames']; |
| 706 if (TestUtils.usesWebDriver(runtime)) { | 722 TestCase parentTest; |
| 707 args = [dartDir.append('tools/testing/run_selenium.py').toNativePath(), | 723 int subtestIndex = 0; |
| 708 '--browser=$runtime', | 724 do { |
| 709 '--timeout=${configuration["timeout"] - 2}', | 725 List<String> args = <String>[]; |
| 710 '--out=$htmlPath']; | 726 String fullHtmlPath = htmlPath; |
| 711 if (runtime == 'dartium') { | 727 if (subtestNames.length > 0) { |
| 712 args.add('--executable=$dartiumFilename'); | 728 fullHtmlPath = '${htmlPath}#${subtestNames[subtestIndex]}'; |
| 713 } | 729 } |
| 714 } else { | 730 if (TestUtils.usesWebDriver(runtime)) { |
| 715 args = [ | 731 args = [ |
| 716 dartDir.append('tools/testing/drt-trampoline.py').toNativePath(), | 732 dartDir.append('tools/testing/run_selenium.py').toNativePath(), |
| 717 dumpRenderTreeFilename, | 733 '--browser=$runtime', |
| 718 '--no-timeout' | 734 '--timeout=${configuration["timeout"] - 2}', |
| 719 ]; | 735 '--out="$fullHtmlPath"']; |
| 720 if (runtime == 'drt' && | 736 if (runtime == 'dartium') { |
| 721 (compiler == 'none' || compiler == 'dart2dart')) { | 737 args.add('--executable=$dartiumFilename'); |
| 722 var dartFlags = ['--ignore-unrecognized-flags']; | |
| 723 if (configuration["checked"]) { | |
| 724 dartFlags.add('--enable_asserts'); | |
| 725 dartFlags.add("--enable_type_checks"); | |
| 726 } | 738 } |
| 727 dartFlags.addAll(vmOptions); | 739 } else { |
| 728 args.add('--dart-flags=${Strings.join(dartFlags, " ")}'); | 740 args = [ |
| 741 dartDir.append('tools/testing/drt-trampoline.py').toNativePath(), | |
| 742 dumpRenderTreeFilename, | |
| 743 '--no-timeout' | |
| 744 ]; | |
| 745 if (runtime == 'drt' && | |
| 746 (compiler == 'none' || compiler == 'dart2dart')) { | |
| 747 var dartFlags = ['--ignore-unrecognized-flags']; | |
| 748 if (configuration["checked"]) { | |
| 749 dartFlags.add('--enable_asserts'); | |
| 750 dartFlags.add("--enable_type_checks"); | |
| 751 } | |
| 752 dartFlags.addAll(vmOptions); | |
| 753 args.add('--dart-flags=${Strings.join(dartFlags, " ")}'); | |
| 754 } | |
| 755 args.add(fullHtmlPath); | |
| 756 if (expectedOutput != null) { | |
| 757 args.add('--out-expectation=${expectedOutput.toNativePath()}'); | |
| 758 } | |
| 729 } | 759 } |
| 730 args.add(htmlPath); | 760 List<String> commandSet = new List<String>.from(commands); |
| 731 if (expectedOutput != null) { | 761 if (subtestIndex != 0) { |
|
Bill Hesse
2012/11/05 11:51:49
Nit: It would be better if the sense of this test
Emily Fortuna
2012/11/05 18:27:49
Fixed!
| |
| 732 args.add('--out-expectation=${expectedOutput.toNativePath()}'); | 762 commandSet = []; |
| 733 } | 763 } |
| 734 } | 764 commandSet.add(new Command('python', args)); |
| 735 commands.add(new Command('python', args)); | |
| 736 | 765 |
| 737 // Create BrowserTestCase and queue it. | 766 // Create BrowserTestCase and queue it. |
| 738 var testCase = new BrowserTestCase('$suiteName/$testName', | 767 String testDisplayName = '$suiteName/$testName'; |
| 739 commands, configuration, completeHandler, expectations, | 768 var testCase; |
| 740 info, info.hasCompileError || info.hasRuntimeError); | 769 if (info.optionsFromFile['isMultiHtmlTest']) { |
| 741 doTest(testCase); | 770 testDisplayName = '$testDisplayName/${subtestNames[subtestIndex]}'; |
| 771 testCase = new BrowserTestCase(testDisplayName, | |
| 772 commandSet, configuration, completeHandler, | |
| 773 expectations['$testName/${subtestNames[subtestIndex]}'], | |
| 774 info, info.hasCompileError || info.hasRuntimeError, | |
| 775 subtestIndex != 0); | |
| 776 } else { | |
| 777 testCase = new BrowserTestCase(testDisplayName, | |
| 778 commandSet, configuration, completeHandler, expectations, | |
| 779 info, info.hasCompileError || info.hasRuntimeError, false); | |
| 780 } | |
| 781 if (subtestIndex == 0) { | |
| 782 parentTest = testCase; | |
| 783 } else { | |
| 784 parentTest.addObserver(testCase); | |
| 785 } | |
| 786 doTest(testCase); // TODO in doTest, check if the hasCompiled is set for | |
| 787 // the shared tests variable. the first process can notify the other | |
| 788 // processes its ready to go. | |
| 789 subtestIndex++; | |
| 790 } while(subtestIndex < subtestNames.length); | |
| 742 } | 791 } |
| 743 } | 792 } |
| 744 | 793 |
| 745 /** Helper to create a compilation command for a single input file. */ | 794 /** Helper to create a compilation command for a single input file. */ |
| 746 Command _compileCommand(String inputFile, String outputFile, | 795 Command _compileCommand(String inputFile, String outputFile, |
| 747 String compiler, String dir, var vmOptions) { | 796 String compiler, String dir, var vmOptions) { |
| 748 String executable = TestUtils.compilerPath(configuration); | 797 String executable = TestUtils.compilerPath(configuration); |
| 749 List<String> args = TestUtils.standardOptions(configuration); | 798 List<String> args = TestUtils.standardOptions(configuration); |
| 750 switch (compiler) { | 799 switch (compiler) { |
| 751 case 'dart2js': | 800 case 'dart2js': |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 957 * executing the copy command printed by the test script. | 1006 * executing the copy command printed by the test script. |
| 958 * | 1007 * |
| 959 * This method is static as the map is cached and shared amongst | 1008 * This method is static as the map is cached and shared amongst |
| 960 * configurations, so it may not use [configuration]. | 1009 * configurations, so it may not use [configuration]. |
| 961 */ | 1010 */ |
| 962 static Map readOptionsFromFile(Path filePath) { | 1011 static Map readOptionsFromFile(Path filePath) { |
| 963 RegExp testOptionsRegExp = const RegExp(r"// VMOptions=(.*)"); | 1012 RegExp testOptionsRegExp = const RegExp(r"// VMOptions=(.*)"); |
| 964 RegExp dartOptionsRegExp = const RegExp(r"// DartOptions=(.*)"); | 1013 RegExp dartOptionsRegExp = const RegExp(r"// DartOptions=(.*)"); |
| 965 RegExp otherScriptsRegExp = const RegExp(r"// OtherScripts=(.*)"); | 1014 RegExp otherScriptsRegExp = const RegExp(r"// OtherScripts=(.*)"); |
| 966 RegExp multiTestRegExp = const RegExp(r"/// [0-9][0-9]:(.*)"); | 1015 RegExp multiTestRegExp = const RegExp(r"/// [0-9][0-9]:(.*)"); |
| 1016 RegExp multiHtmlTestRegExp = | |
| 1017 const RegExp(r"useHtmlIndividualConfiguration()"); | |
| 967 RegExp staticTypeRegExp = | 1018 RegExp staticTypeRegExp = |
| 968 const RegExp(r"/// ([0-9][0-9]:){0,1}\s*static type warning"); | 1019 const RegExp(r"/// ([0-9][0-9]:){0,1}\s*static type warning"); |
| 969 RegExp compileTimeRegExp = | 1020 RegExp compileTimeRegExp = |
| 970 const RegExp(r"/// ([0-9][0-9]:){0,1}\s*compile-time error"); | 1021 const RegExp(r"/// ([0-9][0-9]:){0,1}\s*compile-time error"); |
| 971 RegExp staticCleanRegExp = const RegExp(r"// @static-clean"); | 1022 RegExp staticCleanRegExp = const RegExp(r"// @static-clean"); |
| 972 RegExp leadingHashRegExp = const RegExp(r"^#", multiLine: true); | 1023 RegExp leadingHashRegExp = const RegExp(r"^#", multiLine: true); |
| 973 RegExp isolateStubsRegExp = const RegExp(r"// IsolateStubs=(.*)"); | 1024 RegExp isolateStubsRegExp = const RegExp(r"// IsolateStubs=(.*)"); |
| 974 // TODO(gram) Clean these up once the old directives are not supported. | 1025 // TODO(gram) Clean these up once the old directives are not supported. |
| 975 RegExp domImportRegExp = | 1026 RegExp domImportRegExp = |
| 976 const RegExp(r"^[#]?import.*dart:html", multiLine: true); | 1027 const RegExp(r"^[#]?import.*dart:html", multiLine: true); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1023 isStaticClean = true; | 1074 isStaticClean = true; |
| 1024 } | 1075 } |
| 1025 | 1076 |
| 1026 List<String> otherScripts = new List<String>(); | 1077 List<String> otherScripts = new List<String>(); |
| 1027 matches = otherScriptsRegExp.allMatches(contents); | 1078 matches = otherScriptsRegExp.allMatches(contents); |
| 1028 for (var match in matches) { | 1079 for (var match in matches) { |
| 1029 otherScripts.addAll(match[1].split(' ').filter((e) => e != '')); | 1080 otherScripts.addAll(match[1].split(' ').filter((e) => e != '')); |
| 1030 } | 1081 } |
| 1031 | 1082 |
| 1032 bool isMultitest = multiTestRegExp.hasMatch(contents); | 1083 bool isMultitest = multiTestRegExp.hasMatch(contents); |
| 1084 bool isMultiHtmlTest = multiHtmlTestRegExp.hasMatch(contents); | |
| 1033 bool containsLeadingHash = leadingHashRegExp.hasMatch(contents); | 1085 bool containsLeadingHash = leadingHashRegExp.hasMatch(contents); |
| 1034 Match isolateMatch = isolateStubsRegExp.firstMatch(contents); | 1086 Match isolateMatch = isolateStubsRegExp.firstMatch(contents); |
| 1035 String isolateStubs = isolateMatch != null ? isolateMatch[1] : ''; | 1087 String isolateStubs = isolateMatch != null ? isolateMatch[1] : ''; |
| 1036 bool containsDomImport = domImportRegExp.hasMatch(contents); | 1088 bool containsDomImport = domImportRegExp.hasMatch(contents); |
| 1037 bool isLibraryDefinition = libraryDefinitionRegExp.hasMatch(contents); | 1089 bool isLibraryDefinition = libraryDefinitionRegExp.hasMatch(contents); |
| 1038 bool containsSourceOrImport = sourceOrImportRegExp.hasMatch(contents); | 1090 bool containsSourceOrImport = sourceOrImportRegExp.hasMatch(contents); |
| 1039 int numStaticTypeAnnotations = 0; | 1091 int numStaticTypeAnnotations = 0; |
| 1040 for (var i in staticTypeRegExp.allMatches(contents)) { | 1092 for (var i in staticTypeRegExp.allMatches(contents)) { |
| 1041 numStaticTypeAnnotations++; | 1093 numStaticTypeAnnotations++; |
| 1042 } | 1094 } |
| 1043 int numCompileTimeAnnotations = 0; | 1095 int numCompileTimeAnnotations = 0; |
| 1044 for (var i in compileTimeRegExp.allMatches(contents)) { | 1096 for (var i in compileTimeRegExp.allMatches(contents)) { |
| 1045 numCompileTimeAnnotations++; | 1097 numCompileTimeAnnotations++; |
| 1046 } | 1098 } |
| 1047 | 1099 |
| 1100 // Note: This is brittle. It assumes you import unittest with no prefix and | |
| 1101 // always directly call "group(". | |
| 1102 RegExp numTests = new RegExp(r"\s*[^/]\s*group\('[^,']*"); | |
| 1103 List<String> subtestNames = []; | |
| 1104 Iterator matchesIter = numTests.allMatches(contents).iterator(); | |
| 1105 while(matchesIter.hasNext && isMultiHtmlTest) { | |
| 1106 String fullMatch = matchesIter.next().group(0); | |
| 1107 subtestNames.add(fullMatch.substring(fullMatch.indexOf("'") + 1)); | |
| 1108 } | |
| 1109 | |
| 1048 return { "vmOptions": result, | 1110 return { "vmOptions": result, |
| 1049 "dartOptions": dartOptions, | 1111 "dartOptions": dartOptions, |
| 1050 "hasCompileError": hasCompileError, | 1112 "hasCompileError": hasCompileError, |
| 1051 "hasRuntimeError": hasRuntimeError, | 1113 "hasRuntimeError": hasRuntimeError, |
| 1052 "isStaticClean" : isStaticClean, | 1114 "isStaticClean" : isStaticClean, |
| 1053 "otherScripts": otherScripts, | 1115 "otherScripts": otherScripts, |
| 1054 "isMultitest": isMultitest, | 1116 "isMultitest": isMultitest, |
| 1117 "isMultiHtmlTest": isMultiHtmlTest, | |
| 1118 "subtestNames": subtestNames, | |
| 1055 "containsLeadingHash": containsLeadingHash, | 1119 "containsLeadingHash": containsLeadingHash, |
| 1056 "isolateStubs": isolateStubs, | 1120 "isolateStubs": isolateStubs, |
| 1057 "containsDomImport": containsDomImport, | 1121 "containsDomImport": containsDomImport, |
| 1058 "isLibraryDefinition": isLibraryDefinition, | 1122 "isLibraryDefinition": isLibraryDefinition, |
| 1059 "containsSourceOrImport": containsSourceOrImport, | 1123 "containsSourceOrImport": containsSourceOrImport, |
| 1060 "numStaticTypeAnnotations": numStaticTypeAnnotations, | 1124 "numStaticTypeAnnotations": numStaticTypeAnnotations, |
| 1061 "numCompileTimeAnnotations": numCompileTimeAnnotations }; | 1125 "numCompileTimeAnnotations": numCompileTimeAnnotations }; |
| 1062 } | 1126 } |
| 1063 | 1127 |
| 1064 List<List<String>> getVmOptions(Map optionsFromFile) { | 1128 List<List<String>> getVmOptions(Map optionsFromFile) { |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1481 * $noCrash tests are expected to be flaky but not crash | 1545 * $noCrash tests are expected to be flaky but not crash |
| 1482 * $pass tests are expected to pass | 1546 * $pass tests are expected to pass |
| 1483 * $failOk tests are expected to fail that we won't fix | 1547 * $failOk tests are expected to fail that we won't fix |
| 1484 * $fail tests are expected to fail that we should fix | 1548 * $fail tests are expected to fail that we should fix |
| 1485 * $crash tests are expected to crash that we should fix | 1549 * $crash tests are expected to crash that we should fix |
| 1486 * $timeout tests are allowed to timeout | 1550 * $timeout tests are allowed to timeout |
| 1487 """; | 1551 """; |
| 1488 print(report); | 1552 print(report); |
| 1489 } | 1553 } |
| 1490 } | 1554 } |
| OLD | NEW |