| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Classes and methods for enumerating and preparing tests. | 6 * Classes and methods for enumerating and preparing tests. |
| 7 * | 7 * |
| 8 * This library includes: | 8 * This library includes: |
| 9 * | 9 * |
| 10 * - Creating tests by listing all the Dart files in certain directories, | 10 * - Creating tests by listing all the Dart files in certain directories, |
| 11 * and creating [TestCase]s for those files that meet the relevant criteria. | 11 * and creating [TestCase]s for those files that meet the relevant criteria. |
| 12 * - Preparing tests, including copying files and frameworks to temporary | 12 * - Preparing tests, including copying files and frameworks to temporary |
| 13 * directories, and computing the command line and arguments to be run. | 13 * directories, and computing the command line and arguments to be run. |
| 14 */ | 14 */ |
| 15 library test_suite; | 15 library test_suite; |
| 16 | 16 |
| 17 import "dart:io"; | 17 import "dart:io"; |
| 18 import "dart:isolate"; | 18 import "dart:isolate"; |
| 19 import "status_file_parser.dart"; | 19 import "status_file_parser.dart"; |
| 20 import "test_runner.dart"; | 20 import "test_runner.dart"; |
| 21 import "multitest.dart"; | 21 import "multitest.dart"; |
| 22 import "drt_updater.dart"; | 22 import "drt_updater.dart"; |
| 23 import "dart:uri"; | 23 import "dart:uri"; |
| 24 import '../../../pkg/path/lib/path.dart' as pathLib; |
| 24 | 25 |
| 25 part "browser_test.dart"; | 26 part "browser_test.dart"; |
| 26 | 27 |
| 27 | 28 |
| 28 // TODO(rnystrom): Add to dart:core? | 29 // TODO(rnystrom): Add to dart:core? |
| 29 /** | 30 /** |
| 30 * A simple function that tests [arg] and returns `true` or `false`. | 31 * A simple function that tests [arg] and returns `true` or `false`. |
| 31 */ | 32 */ |
| 32 typedef bool Predicate<T>(T arg); | 33 typedef bool Predicate<T>(T arg); |
| 33 | 34 |
| (...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 377 */ | 378 */ |
| 378 class StandardTestSuite extends TestSuite { | 379 class StandardTestSuite extends TestSuite { |
| 379 final Path suiteDir; | 380 final Path suiteDir; |
| 380 final List<String> statusFilePaths; | 381 final List<String> statusFilePaths; |
| 381 TestCaseEvent doTest; | 382 TestCaseEvent doTest; |
| 382 TestExpectations testExpectations; | 383 TestExpectations testExpectations; |
| 383 List<TestInformation> cachedTests; | 384 List<TestInformation> cachedTests; |
| 384 final Path dartDir; | 385 final Path dartDir; |
| 385 Predicate<String> isTestFilePredicate; | 386 Predicate<String> isTestFilePredicate; |
| 386 final bool listRecursively; | 387 final bool listRecursively; |
| 388 /** |
| 389 * The set of servers that have been started to run these tests (Could be |
| 390 * none). |
| 391 */ |
| 392 List serverList; |
| 387 | 393 |
| 388 StandardTestSuite(Map configuration, | 394 StandardTestSuite(Map configuration, |
| 389 String suiteName, | 395 String suiteName, |
| 390 Path suiteDirectory, | 396 Path suiteDirectory, |
| 391 this.statusFilePaths, | 397 this.statusFilePaths, |
| 398 this.serverList, |
| 392 {this.isTestFilePredicate, | 399 {this.isTestFilePredicate, |
| 393 bool recursive: false}) | 400 bool recursive: false}) |
| 394 : super(configuration, suiteName), | 401 : super(configuration, suiteName), |
| 395 dartDir = TestUtils.dartDir(), | 402 dartDir = TestUtils.dartDir(), |
| 396 listRecursively = recursive, | 403 listRecursively = recursive, |
| 397 suiteDir = TestUtils.dartDir().join(suiteDirectory); | 404 suiteDir = TestUtils.dartDir().join(suiteDirectory); |
| 398 | 405 |
| 399 /** | 406 /** |
| 400 * Creates a test suite whose file organization matches an expected structure. | 407 * Creates a test suite whose file organization matches an expected structure. |
| 401 * To use this, your suite should look like: | 408 * To use this, your suite should look like: |
| (...skipping 13 matching lines...) Expand all Loading... |
| 415 * * The status file uses the same name. | 422 * * The status file uses the same name. |
| 416 * * Test files are directly in that directory and end in "_test.dart". | 423 * * Test files are directly in that directory and end in "_test.dart". |
| 417 * | 424 * |
| 418 * If you follow that convention, then you can construct one of these like: | 425 * If you follow that convention, then you can construct one of these like: |
| 419 * | 426 * |
| 420 * new StandardTestSuite.forDirectory(configuration, 'path/to/mytestsuite'); | 427 * new StandardTestSuite.forDirectory(configuration, 'path/to/mytestsuite'); |
| 421 * | 428 * |
| 422 * instead of having to create a custom [StandardTestSuite] subclass. In | 429 * instead of having to create a custom [StandardTestSuite] subclass. In |
| 423 * particular, if you add 'path/to/mytestsuite' to [TEST_SUITE_DIRECTORIES] | 430 * particular, if you add 'path/to/mytestsuite' to [TEST_SUITE_DIRECTORIES] |
| 424 * in test.dart, this will all be set up for you. | 431 * in test.dart, this will all be set up for you. |
| 432 * |
| 433 * The [StandardTestSuite] also optionally takes a list of servers that have |
| 434 * been started up by the test harness, to be used by browser tests. |
| 425 */ | 435 */ |
| 426 factory StandardTestSuite.forDirectory( | 436 factory StandardTestSuite.forDirectory( |
| 427 Map configuration, Path directory) { | 437 Map configuration, Path directory, [List serverList = const []]) { |
| 428 final name = directory.filename; | 438 final name = directory.filename; |
| 429 | 439 |
| 430 return new StandardTestSuite(configuration, | 440 return new StandardTestSuite(configuration, |
| 431 name, directory, | 441 name, directory, |
| 432 ['$directory/$name.status', '$directory/${name}_dart2js.status'], | 442 ['$directory/$name.status', '$directory/${name}_dart2js.status'], |
| 443 serverList, |
| 433 isTestFilePredicate: (filename) => filename.endsWith('_test.dart'), | 444 isTestFilePredicate: (filename) => filename.endsWith('_test.dart'), |
| 434 recursive: true); | 445 recursive: true); |
| 435 } | 446 } |
| 436 | 447 |
| 437 Collection<Uri> get dart2JsBootstrapDependencies { | 448 Collection<Uri> get dart2JsBootstrapDependencies { |
| 438 if (!useDart2JsFromSdk) return []; | 449 if (!useDart2JsFromSdk) return []; |
| 439 | 450 |
| 440 var snapshotPath = TestUtils.absolutePath(new Path(buildDir).join( | 451 var snapshotPath = TestUtils.absolutePath(new Path(buildDir).join( |
| 441 new Path('dart-sdk/lib/_internal/compiler/' | 452 new Path('dart-sdk/lib/_internal/compiler/' |
| 442 'implementation/dart2js.dart.snapshot'))).toString(); | 453 'implementation/dart2js.dart.snapshot'))).toString(); |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 697 } | 708 } |
| 698 } | 709 } |
| 699 | 710 |
| 700 List<Command> makeCommands(TestInformation info, var vmOptions, var args) { | 711 List<Command> makeCommands(TestInformation info, var vmOptions, var args) { |
| 701 switch (configuration['compiler']) { | 712 switch (configuration['compiler']) { |
| 702 case 'dart2js': | 713 case 'dart2js': |
| 703 args = new List.from(args); | 714 args = new List.from(args); |
| 704 String tempDir = createOutputDirectory(info.filePath, ''); | 715 String tempDir = createOutputDirectory(info.filePath, ''); |
| 705 args.add('--out=$tempDir/out.js'); | 716 args.add('--out=$tempDir/out.js'); |
| 706 | 717 |
| 707 List<Command> commands = | 718 List<Command> commands = |
| 708 <Command>[new CompilationCommand("$tempDir/out.js", | 719 <Command>[new CompilationCommand("$tempDir/out.js", |
| 709 !useDart2JsFromSdk, | 720 !useDart2JsFromSdk, |
| 710 dart2JsBootstrapDependencies, | 721 dart2JsBootstrapDependencies, |
| 711 compilerPath, | 722 compilerPath, |
| 712 args)]; | 723 args)]; |
| 713 if (info.hasCompileError) { | 724 if (info.hasCompileError) { |
| 714 // Do not attempt to run the compiled result. A compilation | 725 // Do not attempt to run the compiled result. A compilation |
| 715 // error should be reported by the compilation command. | 726 // error should be reported by the compilation command. |
| 716 } else if (configuration['runtime'] == 'd8') { | 727 } else if (configuration['runtime'] == 'd8') { |
| 717 commands.add(new Command(d8FileName, ['$tempDir/out.js'])); | 728 commands.add(new Command(d8FileName, ['$tempDir/out.js'])); |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 833 dartLibraryFilename = new Path('test_as_library.dart'); | 844 dartLibraryFilename = new Path('test_as_library.dart'); |
| 834 File file = new File('$tempDir/$dartLibraryFilename'); | 845 File file = new File('$tempDir/$dartLibraryFilename'); |
| 835 RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE); | 846 RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE); |
| 836 dartLibrary.writeStringSync(wrapDartTestInLibrary(filePath)); | 847 dartLibrary.writeStringSync(wrapDartTestInLibrary(filePath)); |
| 837 dartLibrary.closeSync(); | 848 dartLibrary.closeSync(); |
| 838 } | 849 } |
| 839 | 850 |
| 840 File file = new File(dartWrapperFilename); | 851 File file = new File(dartWrapperFilename); |
| 841 RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE); | 852 RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE); |
| 842 dartWrapper.writeStringSync( | 853 dartWrapper.writeStringSync( |
| 843 dartTestWrapper(dartDir, dartLibraryFilename)); | 854 dartTestWrapper(dartDir, file.name, dartLibraryFilename)); |
| 844 dartWrapper.closeSync(); | 855 dartWrapper.closeSync(); |
| 845 } else { | 856 } else { |
| 846 dartWrapperFilename = filename; | 857 dartWrapperFilename = filename; |
| 847 // TODO(whesse): Once test.py is retired, adjust the relative path in | 858 // TODO(whesse): Once test.py is retired, adjust the relative path in |
| 848 // the client/samples/dartcombat test to its css file, remove the | 859 // the client/samples/dartcombat test to its css file, remove the |
| 849 // "../../" from this path, and move this out of the isWebTest guard. | 860 // "../../" from this path, and move this out of the isWebTest guard. |
| 850 // Also remove getHtmlName, and just use test.html. | 861 // Also remove getHtmlName, and just use test.html. |
| 851 // TODO(efortuna): this shortening of htmlFilename is a band-aid until | 862 // TODO(efortuna): this shortening of htmlFilename is a band-aid until |
| 852 // the above TODO gets fixed. Windows cannot have paths that are longer | 863 // the above TODO gets fixed. Windows cannot have paths that are longer |
| 853 // than 260 characters, and without this hack, we were running past the | 864 // than 260 characters, and without this hack, we were running past the |
| 854 // the limit. | 865 // the limit. |
| 855 String htmlFilename = getHtmlName(filename); | 866 String htmlFilename = getHtmlName(filename); |
| 856 while ('$tempDir/../$htmlFilename'.length >= 260) { | 867 while ('$tempDir/../$htmlFilename'.length >= 260) { |
| 857 htmlFilename = htmlFilename.substring(htmlFilename.length~/2); | 868 htmlFilename = htmlFilename.substring(htmlFilename.length~/2); |
| 858 } | 869 } |
| 859 htmlPath = '$tempDir/../$htmlFilename'; | 870 htmlPath = '$tempDir/../$htmlFilename'; |
| 860 } | 871 } |
| 861 final String scriptPath = (compiler == 'none') ? | 872 final String scriptPath = (compiler == 'none') ? |
| 862 dartWrapperFilename : compiledDartWrapperFilename; | 873 dartWrapperFilename : compiledDartWrapperFilename; |
| 863 // Create the HTML file for the test. | 874 // Create the HTML file for the test. |
| 864 RandomAccessFile htmlTest = new File(htmlPath).openSync(FileMode.WRITE); | 875 RandomAccessFile htmlTest = new File(htmlPath).openSync(FileMode.WRITE); |
| 865 String filePrefix = ''; | |
| 866 if (Platform.operatingSystem == 'windows') { | |
| 867 // Firefox on Windows does not like absolute file path names that start | |
| 868 // with 'C:' adding 'file:///' solves the problem. | |
| 869 filePrefix = 'file:///'; | |
| 870 } | |
| 871 String content = null; | 876 String content = null; |
| 872 Path dir = filePath.directoryPath; | 877 Path dir = filePath.directoryPath; |
| 873 String nameNoExt = filePath.filenameWithoutExtension; | 878 String nameNoExt = filePath.filenameWithoutExtension; |
| 874 Path pngPath = dir.append('$nameNoExt.png'); | 879 Path pngPath = dir.append('$nameNoExt.png'); |
| 875 Path txtPath = dir.append('$nameNoExt.txt'); | 880 Path txtPath = dir.append('$nameNoExt.txt'); |
| 876 Path expectedOutput = null; | 881 Path expectedOutput = null; |
| 877 if (new File.fromPath(pngPath).existsSync()) { | 882 if (new File.fromPath(pngPath).existsSync()) { |
| 878 expectedOutput = pngPath; | 883 expectedOutput = pngPath; |
| 879 content = getHtmlLayoutContents(scriptType, '$filePrefix$scriptPath'); | 884 content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath, |
| 885 from: pathLib.dirname(htmlPath))); |
| 880 } else if (new File.fromPath(txtPath).existsSync()) { | 886 } else if (new File.fromPath(txtPath).existsSync()) { |
| 881 expectedOutput = txtPath; | 887 expectedOutput = txtPath; |
| 882 content = getHtmlLayoutContents(scriptType, '$filePrefix$scriptPath'); | 888 content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath, |
| 889 from: pathLib.dirname(htmlPath))); |
| 883 } else { | 890 } else { |
| 884 final htmlLocation = new Path.fromNative(htmlPath); | 891 final htmlLocation = new Path.fromNative(htmlPath); |
| 885 content = getHtmlContents( | 892 content = getHtmlContents( |
| 886 filename, | 893 filename, |
| 887 dartDir.append('pkg/unittest/test_controller.js') | 894 dartDir.append('pkg/unittest/test_controller.js') |
| 888 .relativeTo(htmlLocation), | 895 .relativeTo(htmlLocation), |
| 889 dartDir.append('client/dart.js').relativeTo(htmlLocation), | 896 dartDir.append('client/dart.js').relativeTo(htmlLocation), |
| 890 scriptType, | 897 scriptType, |
| 891 new Path.fromNative(scriptPath).relativeTo(htmlLocation)); | 898 new Path.fromNative(scriptPath).relativeTo(htmlLocation)); |
| 892 } | 899 } |
| (...skipping 22 matching lines...) Expand all Loading... |
| 915 } | 922 } |
| 916 | 923 |
| 917 // Variables for browser multi-tests. | 924 // Variables for browser multi-tests. |
| 918 List<String> subtestNames = info.optionsFromFile['subtestNames']; | 925 List<String> subtestNames = info.optionsFromFile['subtestNames']; |
| 919 TestCase multitestParentTest; | 926 TestCase multitestParentTest; |
| 920 int subtestIndex = 0; | 927 int subtestIndex = 0; |
| 921 // Construct the command that executes the browser test | 928 // Construct the command that executes the browser test |
| 922 do { | 929 do { |
| 923 List<Command> commandSet = new List<Command>.from(commands); | 930 List<Command> commandSet = new List<Command>.from(commands); |
| 924 if (subtestIndex != 0) { | 931 if (subtestIndex != 0) { |
| 925 // NOTE: The first time we enter this loop, all the compilation | 932 // NOTE: The first time we enter this loop, all the compilation |
| 926 // commands will be executed. On subsequent loop iterations, we | 933 // commands will be executed. On subsequent loop iterations, we |
| 927 // don't need to do any compilations. Thus we set "commandSet = []". | 934 // don't need to do any compilations. Thus we set "commandSet = []". |
| 928 commandSet = []; | 935 commandSet = []; |
| 929 } | 936 } |
| 930 | 937 |
| 931 List<String> args = <String>[]; | 938 List<String> args = <String>[]; |
| 932 String fullHtmlPath = htmlPath.startsWith('http:') ? htmlPath : | 939 var basePath = TestUtils.dartDir().toString(); |
| 933 (htmlPath.startsWith('/') ? | 940 htmlPath = htmlPath.startsWith(basePath) ? |
| 934 'file://$htmlPath' : | 941 htmlPath.substring(basePath.length) : htmlPath; |
| 935 'file:///$htmlPath'); | 942 String fullHtmlPath = htmlPath; |
| 943 if (!htmlPath.startsWith('http')) { |
| 944 if (!htmlPath.startsWith('/')) htmlPath = '/$htmlPath'; |
| 945 fullHtmlPath = 'http://127.0.0.1:${serverList[0].port}$htmlPath?' |
| 946 'crossOriginPort=${serverList[1].port}'; |
| 947 } |
| 936 if (info.optionsFromFile['isMultiHtmlTest'] | 948 if (info.optionsFromFile['isMultiHtmlTest'] |
| 937 && subtestNames.length > 0) { | 949 && subtestNames.length > 0) { |
| 938 fullHtmlPath = '${fullHtmlPath}#${subtestNames[subtestIndex]}'; | 950 fullHtmlPath = '${fullHtmlPath}#${subtestNames[subtestIndex]}'; |
| 939 } | 951 } |
| 940 | 952 |
| 941 if (TestUtils.usesWebDriver(runtime)) { | 953 if (TestUtils.usesWebDriver(runtime)) { |
| 942 args = [ | 954 args = [ |
| 943 dartDir.append('tools/testing/run_selenium.py').toNativePath(), | 955 dartDir.append('tools/testing/run_selenium.py').toNativePath(), |
| 944 '--browser=$runtime', | 956 '--browser=$runtime', |
| 945 '--timeout=${configuration["timeout"] - 2}', | 957 '--timeout=${configuration["timeout"] - 2}', |
| (...skipping 18 matching lines...) Expand all Loading... |
| 964 dartFlags.add('--ignore-unrecognized-flags'); | 976 dartFlags.add('--ignore-unrecognized-flags'); |
| 965 if (configuration["checked"]) { | 977 if (configuration["checked"]) { |
| 966 dartFlags.add('--enable_asserts'); | 978 dartFlags.add('--enable_asserts'); |
| 967 dartFlags.add("--enable_type_checks"); | 979 dartFlags.add("--enable_type_checks"); |
| 968 } | 980 } |
| 969 dartFlags.addAll(vmOptions); | 981 dartFlags.addAll(vmOptions); |
| 970 } | 982 } |
| 971 if (compiler == 'none') { | 983 if (compiler == 'none') { |
| 972 var packageRootPath = packageRoot(optionsFromFile['packageRoot']); | 984 var packageRootPath = packageRoot(optionsFromFile['packageRoot']); |
| 973 if (packageRootPath != null) { | 985 if (packageRootPath != null) { |
| 974 var absolutePath = | 986 var absolutePath = |
| 975 TestUtils.absolutePath(new Path(packageRootPath)); | 987 TestUtils.absolutePath(new Path(packageRootPath)); |
| 976 packageRootUri = new Uri.fromComponents( | 988 packageRootUri = new Uri.fromComponents( |
| 977 scheme: 'file', | 989 scheme: 'http', |
| 978 path: absolutePath.toString()); | 990 path: '127.0.0.1:${serverList[0].port}/' |
| 991 '${pathLib.relative(absolutePath.toString(), from: |
| 992 TestUtils.dartDir().toString())}'); |
| 979 } | 993 } |
| 980 } | 994 } |
| 981 | 995 |
| 982 if (expectedOutput != null) { | 996 if (expectedOutput != null) { |
| 983 if (expectedOutput.toNativePath().endsWith('.png')) { | 997 if (expectedOutput.toNativePath().endsWith('.png')) { |
| 984 // pixel tests are specified by running DRT "foo.html'-p" | 998 // pixel tests are specified by running DRT "foo.html'-p" |
| 985 dumpRenderTreeOptions.add('--notree'); | 999 dumpRenderTreeOptions.add('--notree'); |
| 986 fullHtmlPath = "${fullHtmlPath}'-p"; | 1000 fullHtmlPath = "${fullHtmlPath}'-p"; |
| 987 } | 1001 } |
| 988 } | 1002 } |
| (...skipping 804 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1793 * $pass tests are expected to pass | 1807 * $pass tests are expected to pass |
| 1794 * $failOk tests are expected to fail that we won't fix | 1808 * $failOk tests are expected to fail that we won't fix |
| 1795 * $fail tests are expected to fail that we should fix | 1809 * $fail tests are expected to fail that we should fix |
| 1796 * $crash tests are expected to crash that we should fix | 1810 * $crash tests are expected to crash that we should fix |
| 1797 * $timeout tests are allowed to timeout | 1811 * $timeout tests are allowed to timeout |
| 1798 * $compileErrorSkip tests are skipped on browsers due to compile-time error | 1812 * $compileErrorSkip tests are skipped on browsers due to compile-time error |
| 1799 """; | 1813 """; |
| 1800 print(report); | 1814 print(report); |
| 1801 } | 1815 } |
| 1802 } | 1816 } |
| OLD | NEW |