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 import 'dart:async'; | 15 import 'dart:async'; |
16 import 'dart:io'; | 16 import 'dart:io'; |
17 import 'dart:math'; | |
18 | 17 |
19 import 'browser_test.dart'; | 18 import 'browser_test.dart'; |
20 import 'compiler_configuration.dart'; | 19 import 'compiler_configuration.dart'; |
21 import 'configuration.dart'; | 20 import 'configuration.dart'; |
22 import 'drt_updater.dart'; | 21 import 'drt_updater.dart'; |
23 import 'expectation.dart'; | 22 import 'expectation.dart'; |
24 import 'expectation_set.dart'; | 23 import 'expectation_set.dart'; |
25 import 'html_test.dart' as html_test; | 24 import 'html_test.dart' as html_test; |
26 import 'http_server.dart'; | 25 import 'http_server.dart'; |
27 import 'multitest.dart'; | 26 import 'multitest.dart'; |
(...skipping 717 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 createTestCase( | 744 createTestCase( |
746 filePath, | 745 filePath, |
747 filePath, | 746 filePath, |
748 optionsFromFile['hasCompileError'] as bool, | 747 optionsFromFile['hasCompileError'] as bool, |
749 optionsFromFile['hasRuntimeError'] as bool, | 748 optionsFromFile['hasRuntimeError'] as bool, |
750 hasStaticWarning: optionsFromFile['hasStaticWarning'] as bool); | 749 hasStaticWarning: optionsFromFile['hasStaticWarning'] as bool); |
751 } | 750 } |
752 } | 751 } |
753 | 752 |
754 static Path _findPubspecYamlFile(Path filePath) { | 753 static Path _findPubspecYamlFile(Path filePath) { |
755 final existsCache = TestUtils.existsCache; | 754 var root = TestUtils.dartDir; |
756 | |
757 Path root = TestUtils.dartDir; | |
758 assert("$filePath".startsWith("$root")); | 755 assert("$filePath".startsWith("$root")); |
759 | 756 |
760 // We start with the parent directory of [filePath] and go up until | 757 // We start with the parent directory of [filePath] and go up until |
761 // the root directory (excluding the root). | 758 // the root directory (excluding the root). |
762 List<String> segments = filePath.directoryPath.relativeTo(root).segments(); | 759 List<String> segments = filePath.directoryPath.relativeTo(root).segments(); |
763 while (segments.length > 0) { | 760 while (segments.length > 0) { |
764 var pubspecYamlPath = new Path(segments.join('/')).append('pubspec.yaml'); | 761 var pubspecYamlPath = new Path(segments.join('/')).append('pubspec.yaml'); |
765 if (existsCache.doesFileExist(pubspecYamlPath.toNativePath())) { | 762 if (TestUtils.existsCache.doesFileExist(pubspecYamlPath.toNativePath())) { |
766 return root.join(pubspecYamlPath); | 763 return root.join(pubspecYamlPath); |
767 } | 764 } |
768 segments.removeLast(); | 765 segments.removeLast(); |
769 } | 766 } |
| 767 |
770 return null; | 768 return null; |
771 } | 769 } |
772 | 770 |
773 void enqueueTestCaseFromTestInformation(TestInformation info) { | 771 void enqueueTestCaseFromTestInformation(TestInformation info) { |
774 String testName = buildTestCaseDisplayName(suiteDir, info.originTestPath, | 772 String testName = buildTestCaseDisplayName(suiteDir, info.originTestPath, |
775 multitestName: info.optionsFromFile['isMultitest'] as bool | 773 multitestName: info.optionsFromFile['isMultitest'] as bool |
776 ? info.multitestKey | 774 ? info.multitestKey |
777 : ""); | 775 : ""); |
778 Set<Expectation> expectations = testExpectations.expectations(testName); | 776 Set<Expectation> expectations = testExpectations.expectations(testName); |
779 if (info is HtmlTestInformation) { | 777 if (info is HtmlTestInformation) { |
780 enqueueHtmlTest(info, testName, expectations); | 778 enqueueHtmlTest(info, testName, expectations); |
781 return; | 779 return; |
782 } | 780 } |
| 781 |
783 var optionsFromFile = info.optionsFromFile; | 782 var optionsFromFile = info.optionsFromFile; |
784 | 783 |
785 // If this test is inside a package, we will check if there is a | 784 // If this test is inside a package, we will check if there is a |
786 // pubspec.yaml file and if so, create a custom package root for it. | 785 // pubspec.yaml file and if so, create a custom package root for it. |
787 List<Command> baseCommands = <Command>[]; | |
788 Path packageRoot; | 786 Path packageRoot; |
789 Path packages; | 787 Path packages; |
790 | 788 |
791 if (optionsFromFile['packageRoot'] == null && | 789 if (optionsFromFile['packageRoot'] == null && |
792 optionsFromFile['packages'] == null) { | 790 optionsFromFile['packages'] == null) { |
793 if (configuration.packageRoot != null) { | 791 if (configuration.packageRoot != null) { |
794 packageRoot = new Path(configuration.packageRoot); | 792 packageRoot = new Path(configuration.packageRoot); |
795 optionsFromFile['packageRoot'] = packageRoot.toNativePath(); | 793 optionsFromFile['packageRoot'] = packageRoot.toNativePath(); |
796 } | 794 } |
797 if (configuration.packages != null) { | 795 if (configuration.packages != null) { |
798 Path packages = new Path(configuration.packages); | 796 Path packages = new Path(configuration.packages); |
799 optionsFromFile['packages'] = packages.toNativePath(); | 797 optionsFromFile['packages'] = packages.toNativePath(); |
800 } | 798 } |
801 } | 799 } |
802 if (configuration.compilerConfiguration.hasCompiler && | 800 if (configuration.compilerConfiguration.hasCompiler && |
803 expectCompileError(info)) { | 801 expectCompileError(info)) { |
804 // If a compile-time error is expected, and we're testing a | 802 // If a compile-time error is expected, and we're testing a |
805 // compiler, we never need to attempt to run the program (in a | 803 // compiler, we never need to attempt to run the program (in a |
806 // browser or otherwise). | 804 // browser or otherwise). |
807 enqueueStandardTest(baseCommands, info, testName, expectations); | 805 enqueueStandardTest(info, testName, expectations); |
808 } else if (configuration.runtime.isBrowser) { | 806 } else if (configuration.runtime.isBrowser) { |
809 if (info.optionsFromFile['isMultiHtmlTest'] as bool) { | 807 if (info.optionsFromFile['isMultiHtmlTest'] as bool) { |
810 // A browser multi-test has multiple expectations for one test file. | 808 // A browser multi-test has multiple expectations for one test file. |
811 // Find all the different sub-test expecations for one entire test file. | 809 // Find all the different sub-test expecations for one entire test file. |
812 var subtestNames = info.optionsFromFile['subtestNames'] as List<String>; | 810 var subtestNames = info.optionsFromFile['subtestNames'] as List<String>; |
813 var multiHtmlTestExpectations = <String, Set<Expectation>>{}; | 811 var multiHtmlTestExpectations = <String, Set<Expectation>>{}; |
814 for (var name in subtestNames) { | 812 for (var name in subtestNames) { |
815 var fullTestName = '$testName/$name'; | 813 var fullTestName = '$testName/$name'; |
816 multiHtmlTestExpectations[fullTestName] = | 814 multiHtmlTestExpectations[fullTestName] = |
817 testExpectations.expectations(fullTestName); | 815 testExpectations.expectations(fullTestName); |
818 } | 816 } |
819 enqueueBrowserTest(baseCommands, packageRoot, packages, info, testName, | 817 enqueueBrowserTest( |
820 multiHtmlTestExpectations); | 818 packageRoot, packages, info, testName, multiHtmlTestExpectations); |
821 } else { | 819 } else { |
822 enqueueBrowserTest( | 820 enqueueBrowserTest(packageRoot, packages, info, testName, expectations); |
823 baseCommands, packageRoot, packages, info, testName, expectations); | |
824 } | 821 } |
825 } else { | 822 } else { |
826 enqueueStandardTest(baseCommands, info, testName, expectations); | 823 enqueueStandardTest(info, testName, expectations); |
827 } | 824 } |
828 } | 825 } |
829 | 826 |
830 void enqueueStandardTest(List<Command> baseCommands, TestInformation info, | 827 void enqueueStandardTest( |
831 String testName, Set<Expectation> expectations) { | 828 TestInformation info, String testName, Set<Expectation> expectations) { |
832 var commonArguments = | 829 var commonArguments = |
833 commonArgumentsFromFile(info.filePath, info.optionsFromFile); | 830 commonArgumentsFromFile(info.filePath, info.optionsFromFile); |
834 | 831 |
835 var vmOptionsList = getVmOptions(info.optionsFromFile); | 832 var vmOptionsList = getVmOptions(info.optionsFromFile); |
836 assert(!vmOptionsList.isEmpty); | 833 assert(!vmOptionsList.isEmpty); |
837 | 834 |
838 for (var vmOptionsVariant = 0; | 835 for (var vmOptionsVariant = 0; |
839 vmOptionsVariant < vmOptionsList.length; | 836 vmOptionsVariant < vmOptionsList.length; |
840 vmOptionsVariant++) { | 837 vmOptionsVariant++) { |
841 var vmOptions = vmOptionsList[vmOptionsVariant]; | 838 var vmOptions = vmOptionsList[vmOptionsVariant]; |
842 var allVmOptions = vmOptions; | 839 var allVmOptions = vmOptions; |
843 if (!extraVmOptions.isEmpty) { | 840 if (!extraVmOptions.isEmpty) { |
844 allVmOptions = vmOptions.toList()..addAll(extraVmOptions); | 841 allVmOptions = vmOptions.toList()..addAll(extraVmOptions); |
845 } | 842 } |
846 | 843 |
847 var commands = baseCommands.toList(); | 844 var commands = |
848 commands.addAll( | 845 makeCommands(info, vmOptionsVariant, allVmOptions, commonArguments); |
849 makeCommands(info, vmOptionsVariant, allVmOptions, commonArguments)); | |
850 enqueueNewTestCase(new TestCase( | 846 enqueueNewTestCase(new TestCase( |
851 '$suiteName/$testName', commands, configuration, expectations, | 847 '$suiteName/$testName', commands, configuration, expectations, |
852 isNegative: isNegative(info), info: info)); | 848 isNegative: isNegative(info), info: info)); |
853 } | 849 } |
854 } | 850 } |
855 | 851 |
856 bool expectCompileError(TestInformation info) { | 852 bool expectCompileError(TestInformation info) { |
857 return info.hasCompileError || | 853 return info.hasCompileError || |
858 (configuration.isChecked && info.hasCompileErrorIfChecked); | 854 (configuration.isChecked && info.hasCompileErrorIfChecked); |
859 } | 855 } |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1023 * JavaScript version of the test, and copies the appropriate framework | 1019 * JavaScript version of the test, and copies the appropriate framework |
1024 * files to that directory. It creates a [BrowserTestCase], which has | 1020 * files to that directory. It creates a [BrowserTestCase], which has |
1025 * two sequential steps to be run by the [ProcessQueue] when the test is | 1021 * two sequential steps to be run by the [ProcessQueue] when the test is |
1026 * executed: a compilation step and an execution step, both with the | 1022 * executed: a compilation step and an execution step, both with the |
1027 * appropriate executable and arguments. The [expectations] object can be | 1023 * appropriate executable and arguments. The [expectations] object can be |
1028 * either a Set<String> if the test is a regular test, or a Map<String | 1024 * either a Set<String> if the test is a regular test, or a Map<String |
1029 * subTestName, Set<String>> if we are running a browser multi-test (one | 1025 * subTestName, Set<String>> if we are running a browser multi-test (one |
1030 * compilation and many browser runs). | 1026 * compilation and many browser runs). |
1031 */ | 1027 */ |
1032 void enqueueBrowserTest( | 1028 void enqueueBrowserTest( |
1033 List<Command> baseCommands, | |
1034 Path packageRoot, | 1029 Path packageRoot, |
1035 Path packages, | 1030 Path packages, |
1036 TestInformation info, | 1031 TestInformation info, |
1037 String testName, | 1032 String testName, |
1038 /* Set<Expectation> | Map<String, Set<Expectation>> */ dynamic | 1033 /* Set<Expectation> | Map<String, Set<Expectation>> */ dynamic |
1039 expectations) { | 1034 expectations) { |
1040 var badChars = new RegExp('[-=/]'); | 1035 var badChars = new RegExp('[-=/]'); |
1041 var vmOptionsList = getVmOptions(info.optionsFromFile); | 1036 var vmOptionsList = getVmOptions(info.optionsFromFile); |
1042 var multipleOptions = vmOptionsList.length > 1; | 1037 var multipleOptions = vmOptionsList.length > 1; |
1043 for (var vmOptions in vmOptionsList) { | 1038 for (var vmOptions in vmOptionsList) { |
1044 var optionsName = | 1039 var optionsName = |
1045 multipleOptions ? vmOptions.join('-').replaceAll(badChars, '') : ''; | 1040 multipleOptions ? vmOptions.join('-').replaceAll(badChars, '') : ''; |
1046 var tempDir = createOutputDirectory(info.filePath, optionsName); | 1041 var tempDir = createOutputDirectory(info.filePath, optionsName); |
1047 enqueueBrowserTestWithOptions(baseCommands, packageRoot, packages, info, | 1042 enqueueBrowserTestWithOptions(packageRoot, packages, info, testName, |
1048 testName, expectations, vmOptions, tempDir); | 1043 expectations, vmOptions, tempDir); |
1049 } | 1044 } |
1050 } | 1045 } |
1051 | 1046 |
1052 void enqueueBrowserTestWithOptions( | 1047 void enqueueBrowserTestWithOptions( |
1053 List<Command> baseCommands, | |
1054 Path packageRoot, | 1048 Path packageRoot, |
1055 Path packages, | 1049 Path packages, |
1056 TestInformation info, | 1050 TestInformation info, |
1057 String testName, | 1051 String testName, |
1058 /* Set<Expectation> | Map<String, Set<Expectation>> */ expectations, | 1052 /* Set<Expectation> | Map<String, Set<Expectation>> */ expectations, |
1059 List<String> vmOptions, | 1053 List<String> vmOptions, |
1060 String tempDir) { | 1054 String tempDir) { |
1061 // TODO(Issue 14651): If we're on dartium, we need to pass [packageRoot] | 1055 // TODO(Issue 14651): If we're on dartium, we need to pass [packageRoot] |
1062 // on to the browser (it may be test specific). | 1056 // on to the browser (it may be test specific). |
1063 | 1057 |
1064 var filePath = info.filePath; | 1058 var filePath = info.filePath; |
1065 var fileName = filePath.toString(); | 1059 var fileName = filePath.toString(); |
1066 | 1060 |
1067 var optionsFromFile = info.optionsFromFile; | 1061 var optionsFromFile = info.optionsFromFile; |
1068 | 1062 |
1069 var compilationTempDir = createCompilationOutputDirectory(info.filePath); | 1063 var compilationTempDir = createCompilationOutputDirectory(info.filePath); |
1070 | 1064 |
1071 var dartWrapperFilename = '$tempDir/test.dart'; | 1065 var dartWrapperFilename = '$tempDir/test.dart'; |
1072 var compiledDartWrapperFilename = '$compilationTempDir/test.js'; | 1066 var compiledDartWrapperFilename = '$compilationTempDir/test.js'; |
1073 | 1067 |
1074 String content = null; | 1068 String content = null; |
1075 var dir = filePath.directoryPath; | 1069 var dir = filePath.directoryPath; |
1076 var nameNoExt = filePath.filenameWithoutExtension; | 1070 var nameNoExt = filePath.filenameWithoutExtension; |
1077 | 1071 |
1078 var customHtmlPath = dir.append('$nameNoExt.html').toNativePath(); | 1072 var customHtmlPath = dir.append('$nameNoExt.html').toNativePath(); |
1079 var customHtml = new File(customHtmlPath); | 1073 var customHtml = new File(customHtmlPath); |
1080 | 1074 |
1081 // Construct the command(s) that compile all the inputs needed by the | 1075 // Construct the command(s) that compile all the inputs needed by the |
1082 // browser test. For running Dart in DRT, this will be noop commands. | 1076 // browser test. For running Dart in DRT, this will be noop commands. |
1083 var commands = baseCommands.toList(); | 1077 var commands = <Command>[]; |
1084 | 1078 |
1085 // Use existing HTML document if available. | 1079 // Use existing HTML document if available. |
1086 String htmlPath; | 1080 String htmlPath; |
1087 if (customHtml.existsSync()) { | 1081 if (customHtml.existsSync()) { |
1088 // If necessary, run the Polymer deploy steps. | 1082 // If necessary, run the Polymer deploy steps. |
1089 // TODO(jmesserly): this should be generalized for any tests that | 1083 // TODO(jmesserly): this should be generalized for any tests that |
1090 // require Pub deploy, not just polymer. | 1084 // require Pub deploy, not just polymer. |
1091 if (customHtml.readAsStringSync().contains('<!--polymer-test')) { | 1085 if (customHtml.readAsStringSync().contains('<!--polymer-test')) { |
1092 if (configuration.compiler != Compiler.none) { | 1086 if (configuration.compiler != Compiler.none) { |
1093 commands.add( | 1087 commands.add( |
(...skipping 622 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1716 /// Used for testing packages in on off settings, i.e., we pass in the actual | 1710 /// Used for testing packages in on off settings, i.e., we pass in the actual |
1717 /// directory that we want to test. | 1711 /// directory that we want to test. |
1718 class PKGTestSuite extends StandardTestSuite { | 1712 class PKGTestSuite extends StandardTestSuite { |
1719 PKGTestSuite(Configuration configuration, Path directoryPath) | 1713 PKGTestSuite(Configuration configuration, Path directoryPath) |
1720 : super(configuration, directoryPath.filename, directoryPath, | 1714 : super(configuration, directoryPath.filename, directoryPath, |
1721 ["$directoryPath/.status"], | 1715 ["$directoryPath/.status"], |
1722 isTestFilePredicate: (f) => f.endsWith('_test.dart'), | 1716 isTestFilePredicate: (f) => f.endsWith('_test.dart'), |
1723 recursive: true); | 1717 recursive: true); |
1724 | 1718 |
1725 void enqueueBrowserTest( | 1719 void enqueueBrowserTest( |
1726 List<Command> baseCommands, | |
1727 Path packageRoot, | 1720 Path packageRoot, |
1728 packages, | 1721 packages, |
1729 TestInformation info, | 1722 TestInformation info, |
1730 String testName, | 1723 String testName, |
1731 /* Set<Expectation> | Map<String, Set<Expectation>> */ dynamic | 1724 /* Set<Expectation> | Map<String, Set<Expectation>> */ dynamic |
1732 expectations) { | 1725 expectations) { |
1733 var filePath = info.filePath; | 1726 var filePath = info.filePath; |
1734 var dir = filePath.directoryPath; | 1727 var dir = filePath.directoryPath; |
1735 var nameNoExt = filePath.filenameWithoutExtension; | 1728 var nameNoExt = filePath.filenameWithoutExtension; |
1736 var customHtmlPath = dir.append('$nameNoExt.html'); | 1729 var customHtmlPath = dir.append('$nameNoExt.html'); |
1737 var customHtml = new File(customHtmlPath.toNativePath()); | 1730 var customHtml = new File(customHtmlPath.toNativePath()); |
1738 if (!customHtml.existsSync()) { | 1731 if (!customHtml.existsSync()) { |
1739 super.enqueueBrowserTest( | 1732 super.enqueueBrowserTest( |
1740 baseCommands, packageRoot, packages, info, testName, expectations); | 1733 packageRoot, packages, info, testName, expectations); |
1741 } else { | 1734 } else { |
1742 var relativeHtml = customHtmlPath.relativeTo(TestUtils.dartDir); | 1735 var relativeHtml = customHtmlPath.relativeTo(TestUtils.dartDir); |
1743 var commands = baseCommands.toList(); | |
1744 var fullPath = _createUrlPathFromFile(customHtmlPath); | 1736 var fullPath = _createUrlPathFromFile(customHtmlPath); |
1745 | 1737 |
1746 commands.add(CommandBuilder.instance | 1738 var commands = [ |
1747 .getBrowserTestCommand(fullPath, configuration, !isNegative(info))); | 1739 CommandBuilder.instance |
| 1740 .getBrowserTestCommand(fullPath, configuration, !isNegative(info)) |
| 1741 ]; |
1748 var testDisplayName = '$suiteName/$testName'; | 1742 var testDisplayName = '$suiteName/$testName'; |
1749 enqueueNewTestCase(new BrowserTestCase( | 1743 enqueueNewTestCase(new BrowserTestCase( |
1750 testDisplayName, | 1744 testDisplayName, |
1751 commands, | 1745 commands, |
1752 configuration, | 1746 configuration, |
1753 expectations as Set<Expectation>, | 1747 expectations as Set<Expectation>, |
1754 info, | 1748 info, |
1755 isNegative(info), | 1749 isNegative(info), |
1756 relativeHtml.toNativePath())); | 1750 relativeHtml.toNativePath())); |
1757 } | 1751 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1807 | 1801 |
1808 bool isTestFile(String filename) { | 1802 bool isTestFile(String filename) { |
1809 // NOTE: We exclude tests and patch files for now. | 1803 // NOTE: We exclude tests and patch files for now. |
1810 return filename.endsWith(".dart") && | 1804 return filename.endsWith(".dart") && |
1811 !filename.endsWith("_test.dart") && | 1805 !filename.endsWith("_test.dart") && |
1812 !filename.contains("_internal/js_runtime/lib"); | 1806 !filename.contains("_internal/js_runtime/lib"); |
1813 } | 1807 } |
1814 | 1808 |
1815 bool get listRecursively => true; | 1809 bool get listRecursively => true; |
1816 } | 1810 } |
1817 | |
1818 class LastModifiedCache { | |
1819 Map<String, DateTime> _cache = <String, DateTime>{}; | |
1820 | |
1821 /** | |
1822 * Returns the last modified date of the given [uri]. | |
1823 * | |
1824 * The return value will be cached for future queries. If [uri] is a local | |
1825 * file, it's last modified [Date] will be returned. If the file does not | |
1826 * exist, null will be returned instead. | |
1827 * In case [uri] is not a local file, this method will always return | |
1828 * the current date. | |
1829 */ | |
1830 DateTime getLastModified(Uri uri) { | |
1831 if (uri.scheme == "file") { | |
1832 if (_cache.containsKey(uri.path)) { | |
1833 return _cache[uri.path]; | |
1834 } | |
1835 var file = new File(new Path(uri.path).toNativePath()); | |
1836 _cache[uri.path] = file.existsSync() ? file.lastModifiedSync() : null; | |
1837 return _cache[uri.path]; | |
1838 } | |
1839 return new DateTime.now(); | |
1840 } | |
1841 } | |
1842 | |
1843 class ExistsCache { | |
1844 Map<String, bool> _cache = <String, bool>{}; | |
1845 | |
1846 /** | |
1847 * Returns true if the file in [path] exists, false otherwise. | |
1848 * | |
1849 * The information will be cached. | |
1850 */ | |
1851 bool doesFileExist(String path) { | |
1852 if (!_cache.containsKey(path)) { | |
1853 _cache[path] = new File(path).existsSync(); | |
1854 } | |
1855 return _cache[path]; | |
1856 } | |
1857 } | |
1858 | |
1859 class TestUtils { | |
1860 /** | |
1861 * Any script using TestUtils must set dartDirUri to a file:// URI | |
1862 * pointing to the root of the Dart checkout. | |
1863 */ | |
1864 static void setDartDirUri(Uri uri) { | |
1865 dartDirUri = uri; | |
1866 dartDir = new Path(uri.toFilePath()); | |
1867 } | |
1868 | |
1869 static Random rand = new Random.secure(); | |
1870 static Uri dartDirUri; | |
1871 static Path dartDir; | |
1872 static LastModifiedCache lastModifiedCache = new LastModifiedCache(); | |
1873 static ExistsCache existsCache = new ExistsCache(); | |
1874 static Path currentWorkingDirectory = new Path(Directory.current.path); | |
1875 | |
1876 /** | |
1877 * Generates a random number. | |
1878 */ | |
1879 static int getRandomNumber() { | |
1880 return rand.nextInt(0xffffffff); | |
1881 } | |
1882 | |
1883 /** | |
1884 * Creates a directory using a [relativePath] to an existing | |
1885 * [base] directory if that [relativePath] does not already exist. | |
1886 */ | |
1887 static Directory mkdirRecursive(Path base, Path relativePath) { | |
1888 if (relativePath.isAbsolute) { | |
1889 base = new Path('/'); | |
1890 } | |
1891 Directory dir = new Directory(base.toNativePath()); | |
1892 assert(dir.existsSync()); | |
1893 var segments = relativePath.segments(); | |
1894 for (String segment in segments) { | |
1895 base = base.append(segment); | |
1896 if (base.toString() == "/$segment" && | |
1897 segment.length == 2 && | |
1898 segment.endsWith(':')) { | |
1899 // Skip the directory creation for a path like "/E:". | |
1900 continue; | |
1901 } | |
1902 dir = new Directory(base.toNativePath()); | |
1903 if (!dir.existsSync()) { | |
1904 dir.createSync(); | |
1905 } | |
1906 assert(dir.existsSync()); | |
1907 } | |
1908 return dir; | |
1909 } | |
1910 | |
1911 /** | |
1912 * Copy a [source] file to a new place. | |
1913 * Assumes that the directory for [dest] already exists. | |
1914 */ | |
1915 static Future copyFile(Path source, Path dest) { | |
1916 return new File(source.toNativePath()) | |
1917 .openRead() | |
1918 .pipe(new File(dest.toNativePath()).openWrite()); | |
1919 } | |
1920 | |
1921 static Future copyDirectory(String source, String dest) { | |
1922 source = new Path(source).toNativePath(); | |
1923 dest = new Path(dest).toNativePath(); | |
1924 | |
1925 var executable = 'cp'; | |
1926 var args = ['-Rp', source, dest]; | |
1927 if (Platform.operatingSystem == 'windows') { | |
1928 executable = 'xcopy'; | |
1929 args = [source, dest, '/e', '/i']; | |
1930 } | |
1931 return Process.run(executable, args).then((ProcessResult result) { | |
1932 if (result.exitCode != 0) { | |
1933 throw new Exception("Failed to execute '$executable " | |
1934 "${args.join(' ')}'."); | |
1935 } | |
1936 }); | |
1937 } | |
1938 | |
1939 static Future deleteDirectory(String path) { | |
1940 // We are seeing issues with long path names on windows when | |
1941 // deleting them. Use the system tools to delete our long paths. | |
1942 // See issue 16264. | |
1943 if (Platform.operatingSystem == 'windows') { | |
1944 var native_path = new Path(path).toNativePath(); | |
1945 // Running this in a shell sucks, but rmdir is not part of the standard | |
1946 // path. | |
1947 return Process | |
1948 .run('rmdir', ['/s', '/q', native_path], runInShell: true) | |
1949 .then((ProcessResult result) { | |
1950 if (result.exitCode != 0) { | |
1951 throw new Exception('Can\'t delete path $native_path. ' | |
1952 'This path might be too long'); | |
1953 } | |
1954 }); | |
1955 } else { | |
1956 var dir = new Directory(path); | |
1957 return dir.delete(recursive: true); | |
1958 } | |
1959 } | |
1960 | |
1961 static void deleteTempSnapshotDirectory(Configuration configuration) { | |
1962 if (configuration.compiler == Compiler.appJit || | |
1963 configuration.compiler == Compiler.precompiler) { | |
1964 var checked = configuration.isChecked ? '-checked' : ''; | |
1965 var strong = configuration.isStrong ? '-strong' : ''; | |
1966 var minified = configuration.isMinified ? '-minified' : ''; | |
1967 var csp = configuration.isCsp ? '-csp' : ''; | |
1968 var sdk = configuration.useSdk ? '-sdk' : ''; | |
1969 var dirName = "${configuration.compiler.name}" | |
1970 "$checked$strong$minified$csp$sdk"; | |
1971 var generatedPath = | |
1972 configuration.buildDirectory + "/generated_compilations/$dirName"; | |
1973 TestUtils.deleteDirectory(generatedPath); | |
1974 } | |
1975 } | |
1976 | |
1977 static final debugLogFilePath = new Path(".debug.log"); | |
1978 | |
1979 /// If a flaky test did fail, infos about it (i.e. test name, stdin, stdout) | |
1980 /// will be written to this file. | |
1981 /// | |
1982 /// This is useful for debugging flaky tests. When running on a buildbot, the | |
1983 /// file can be made visible in the waterfall UI. | |
1984 static const flakyFileName = ".flaky.log"; | |
1985 | |
1986 /// If test.py was invoked with '--write-test-outcome-log it will write | |
1987 /// test outcomes to this file. | |
1988 static const testOutcomeFileName = ".test-outcome.log"; | |
1989 | |
1990 static void ensureExists(String filename, Configuration configuration) { | |
1991 if (!configuration.listTests && !existsCache.doesFileExist(filename)) { | |
1992 throw "'$filename' does not exist"; | |
1993 } | |
1994 } | |
1995 | |
1996 static Path absolutePath(Path path) { | |
1997 if (!path.isAbsolute) { | |
1998 return currentWorkingDirectory.join(path); | |
1999 } | |
2000 return path; | |
2001 } | |
2002 | |
2003 static int shortNameCounter = 0; // Make unique short file names on Windows. | |
2004 | |
2005 static String getShortName(String path) { | |
2006 final PATH_REPLACEMENTS = const { | |
2007 "pkg_polymer_e2e_test_bad_import_test": "polymer_bi", | |
2008 "pkg_polymer_e2e_test_canonicalization_test": "polymer_c16n", | |
2009 "pkg_polymer_e2e_test_experimental_boot_test": "polymer_boot", | |
2010 "pkg_polymer_e2e_test_good_import_test": "polymer_gi", | |
2011 "tests_co19_src_Language_12_Expressions_14_Function_Invocation_": | |
2012 "co19_fn_invoke_", | |
2013 "tests_co19_src_LayoutTests_fast_css_getComputedStyle_getComputedStyle-": | |
2014 "co19_css_getComputedStyle_", | |
2015 "tests_co19_src_LayoutTests_fast_dom_Document_CaretRangeFromPoint_" | |
2016 "caretRangeFromPoint-": "co19_caretrangefrompoint_", | |
2017 "tests_co19_src_LayoutTests_fast_dom_Document_CaretRangeFromPoint_" | |
2018 "hittest-relative-to-viewport_": "co19_caretrange_hittest_", | |
2019 "tests_co19_src_LayoutTests_fast_dom_HTMLLinkElement_link-onerror-" | |
2020 "stylesheet-with-": "co19_dom_link-", | |
2021 "tests_co19_src_LayoutTests_fast_dom_": "co19_dom", | |
2022 "tests_co19_src_LayoutTests_fast_canvas_webgl": "co19_canvas_webgl", | |
2023 "tests_co19_src_LibTest_core_AbstractClassInstantiationError_" | |
2024 "AbstractClassInstantiationError_": "co19_abstract_class_", | |
2025 "tests_co19_src_LibTest_core_IntegerDivisionByZeroException_" | |
2026 "IntegerDivisionByZeroException_": "co19_division_by_zero", | |
2027 "tests_co19_src_WebPlatformTest_html_dom_documents_dom-tree-accessors_": | |
2028 "co19_dom_accessors_", | |
2029 "tests_co19_src_WebPlatformTest_html_semantics_embedded-content_" | |
2030 "media-elements_": "co19_media_elements", | |
2031 "tests_co19_src_WebPlatformTest_html_semantics_": "co19_semantics_", | |
2032 "tests_co19_src_WebPlatformTest_html-templates_additions-to-" | |
2033 "the-steps-to-clone-a-node_": "co19_htmltemplates_clone_", | |
2034 "tests_co19_src_WebPlatformTest_html-templates_definitions_" | |
2035 "template-contents-owner": "co19_htmltemplates_contents", | |
2036 "tests_co19_src_WebPlatformTest_html-templates_parsing-html-" | |
2037 "templates_additions-to-": "co19_htmltemplates_add_", | |
2038 "tests_co19_src_WebPlatformTest_html-templates_parsing-html-" | |
2039 "templates_appending-to-a-template_": "co19_htmltemplates_append_", | |
2040 "tests_co19_src_WebPlatformTest_html-templates_parsing-html-" | |
2041 "templates_clearing-the-stack-back-to-a-given-context_": | |
2042 "co19_htmltemplates_clearstack_", | |
2043 "tests_co19_src_WebPlatformTest_html-templates_parsing-html-" | |
2044 "templates_creating-an-element-for-the-token_": | |
2045 "co19_htmltemplates_create_", | |
2046 "tests_co19_src_WebPlatformTest_html-templates_template-element" | |
2047 "_template-": "co19_htmltemplates_element-", | |
2048 "tests_co19_src_WebPlatformTest_html-templates_": "co19_htmltemplate_", | |
2049 "tests_co19_src_WebPlatformTest_shadow-dom_shadow-trees_": | |
2050 "co19_shadow-trees_", | |
2051 "tests_co19_src_WebPlatformTest_shadow-dom_elements-and-dom-objects_": | |
2052 "co19_shadowdom_", | |
2053 "tests_co19_src_WebPlatformTest_shadow-dom_html-elements-in-" | |
2054 "shadow-trees_": "co19_shadow_html_", | |
2055 "tests_co19_src_WebPlatformTest_html_webappapis_system-state-and-" | |
2056 "capabilities_the-navigator-object": "co19_webappapis_navigator_", | |
2057 "tests_co19_src_WebPlatformTest_DOMEvents_approved_": "co19_dom_approved_" | |
2058 }; | |
2059 | |
2060 // Some tests are already in [build_dir]/generated_tests. | |
2061 String GEN_TESTS = 'generated_tests/'; | |
2062 if (path.contains(GEN_TESTS)) { | |
2063 int index = path.indexOf(GEN_TESTS) + GEN_TESTS.length; | |
2064 path = 'multitest/${path.substring(index)}'; | |
2065 } | |
2066 path = path.replaceAll('/', '_'); | |
2067 final int WINDOWS_SHORTEN_PATH_LIMIT = 58; | |
2068 final int WINDOWS_PATH_END_LENGTH = 30; | |
2069 if (Platform.operatingSystem == 'windows' && | |
2070 path.length > WINDOWS_SHORTEN_PATH_LIMIT) { | |
2071 for (var key in PATH_REPLACEMENTS.keys) { | |
2072 if (path.startsWith(key)) { | |
2073 path = path.replaceFirst(key, PATH_REPLACEMENTS[key]); | |
2074 break; | |
2075 } | |
2076 } | |
2077 if (path.length > WINDOWS_SHORTEN_PATH_LIMIT) { | |
2078 ++shortNameCounter; | |
2079 var pathEnd = path.substring(path.length - WINDOWS_PATH_END_LENGTH); | |
2080 path = "short${shortNameCounter}_$pathEnd"; | |
2081 } | |
2082 } | |
2083 return path; | |
2084 } | |
2085 } | |
OLD | NEW |