| 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 /// Test infrastructure for testing pub. Unlike typical unit tests, most pub | 5 /// Test infrastructure for testing pub. Unlike typical unit tests, most pub |
| 6 /// tests are integration tests that stage some stuff on the file system, run | 6 /// tests are integration tests that stage some stuff on the file system, run |
| 7 /// pub, and then validate the results. This library provides an API to build | 7 /// pub, and then validate the results. This library provides an API to build |
| 8 /// tests like that. | 8 /// tests like that. |
| 9 library test_pub; | 9 library test_pub; |
| 10 | 10 |
| (...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 | 578 |
| 579 pub.writeLine("y"); | 579 pub.writeLine("y"); |
| 580 } | 580 } |
| 581 | 581 |
| 582 | 582 |
| 583 /// Calls [fn] with appropriately modified arguments to run a pub process. [fn] | 583 /// Calls [fn] with appropriately modified arguments to run a pub process. [fn] |
| 584 /// should have the same signature as [startProcess], except that the returned | 584 /// should have the same signature as [startProcess], except that the returned |
| 585 /// [Future] may have a type other than [Process]. | 585 /// [Future] may have a type other than [Process]. |
| 586 Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) { | 586 Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) { |
| 587 String pathInSandbox(path) => join(getFullPath(sandboxDir), path); | 587 String pathInSandbox(path) => join(getFullPath(sandboxDir), path); |
| 588 | 588 // Make sure all errors propagate through future. |
| 589 return Future.wait([ | 589 return defer(() { |
| 590 ensureDir(pathInSandbox(appPath)), | 590 ensureDir(pathInSandbox(appPath)); |
| 591 _awaitObject(args), | 591 return Future.wait([ |
| 592 tokenEndpoint == null ? new Future.immediate(null) : tokenEndpoint | 592 _awaitObject(args), |
| 593 ]).then((results) { | 593 tokenEndpoint == null ? new Future.immediate(null) : tokenEndpoint |
| 594 var args = results[1]; | 594 ]); |
| 595 var tokenEndpoint = results[2]; | 595 }).then((results) { |
| 596 var args = results[0]; |
| 597 var tokenEndpoint = results[1]; |
| 596 // Find a Dart executable we can use to spawn. Use the same one that was | 598 // Find a Dart executable we can use to spawn. Use the same one that was |
| 597 // used to run this script itself. | 599 // used to run this script itself. |
| 598 var dartBin = new Options().executable; | 600 var dartBin = new Options().executable; |
| 599 | 601 |
| 600 // If the executable looks like a path, get its full path. That way we | 602 // If the executable looks like a path, get its full path. That way we |
| 601 // can still find it when we spawn it with a different working directory. | 603 // can still find it when we spawn it with a different working directory. |
| 602 if (dartBin.contains(Platform.pathSeparator)) { | 604 if (dartBin.contains(Platform.pathSeparator)) { |
| 603 dartBin = new File(dartBin).fullPathSync(); | 605 dartBin = new File(dartBin).fullPathSync(); |
| 604 } | 606 } |
| 605 | 607 |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 793 /// directory. | 795 /// directory. |
| 794 void scheduleValidate() => _schedule((parentDir) => validate(parentDir.path)); | 796 void scheduleValidate() => _schedule((parentDir) => validate(parentDir.path)); |
| 795 | 797 |
| 796 /// Asserts that the name of the descriptor is a [String] and returns it. | 798 /// Asserts that the name of the descriptor is a [String] and returns it. |
| 797 String get _stringName { | 799 String get _stringName { |
| 798 if (name is String) return name; | 800 if (name is String) return name; |
| 799 throw 'Pattern $name must be a string.'; | 801 throw 'Pattern $name must be a string.'; |
| 800 } | 802 } |
| 801 | 803 |
| 802 /// Validates that at least one file in [dir] matching [name] is valid | 804 /// Validates that at least one file in [dir] matching [name] is valid |
| 803 /// according to [validate]. [validate] should complete to an exception if | 805 /// according to [validate]. [validate] should throw or complete to an |
| 804 /// the input path is invalid. | 806 /// exception if the input path is invalid. |
| 805 Future _validateOneMatch(String dir, Future validate(String path)) { | 807 Future _validateOneMatch(String dir, Future validate(String path)) { |
| 806 // Special-case strings to support multi-level names like "myapp/packages". | 808 // Special-case strings to support multi-level names like "myapp/packages". |
| 807 if (name is String) { | 809 if (name is String) { |
| 808 var path = join(dir, name); | 810 var path = join(dir, name); |
| 809 return exists(path).then((exists) { | 811 // Make sure errors propagate through future. |
| 810 if (!exists) { | 812 return defer(() { |
| 813 if (!entryExists(path)) { |
| 811 throw new ExpectException('File $name in $dir not found.'); | 814 throw new ExpectException('File $name in $dir not found.'); |
| 812 } | 815 } |
| 813 return validate(path); | 816 return validate(path); |
| 814 }); | 817 }); |
| 815 } | 818 } |
| 816 | 819 |
| 817 // TODO(nweiz): remove this when issue 4061 is fixed. | 820 // TODO(nweiz): remove this when issue 4061 is fixed. |
| 818 var stackTrace; | 821 var stackTrace; |
| 819 try { | 822 try { |
| 820 throw ""; | 823 throw ""; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 /// tree before running a test, and for validating that the file system matches | 869 /// tree before running a test, and for validating that the file system matches |
| 867 /// some expectations after running it. | 870 /// some expectations after running it. |
| 868 class FileDescriptor extends Descriptor { | 871 class FileDescriptor extends Descriptor { |
| 869 /// The text contents of the file. | 872 /// The text contents of the file. |
| 870 final String contents; | 873 final String contents; |
| 871 | 874 |
| 872 FileDescriptor(Pattern name, this.contents) : super(name); | 875 FileDescriptor(Pattern name, this.contents) : super(name); |
| 873 | 876 |
| 874 /// Creates the file within [dir]. Returns a [Future] that is completed after | 877 /// Creates the file within [dir]. Returns a [Future] that is completed after |
| 875 /// the creation is done. | 878 /// the creation is done. |
| 876 Future<File> create(dir) { | 879 Future<File> create(dir) => |
| 877 return writeTextFile(join(dir, _stringName), contents); | 880 defer(() => writeTextFile(join(dir, _stringName), contents)); |
| 878 } | |
| 879 | 881 |
| 880 /// Deletes the file within [dir]. Returns a [Future] that is completed after | 882 /// Deletes the file within [dir]. Returns a [Future] that is completed after |
| 881 /// the deletion is done. | 883 /// the deletion is done. |
| 882 Future delete(dir) { | 884 Future delete(dir) => |
| 883 return deleteFile(join(dir, _stringName)); | 885 defer(() => deleteFile(join(dir, _stringName))); |
| 884 } | |
| 885 | 886 |
| 886 /// Validates that this file correctly matches the actual file at [path]. | 887 /// Validates that this file correctly matches the actual file at [path]. |
| 887 Future validate(String path) { | 888 Future validate(String path) { |
| 888 return _validateOneMatch(path, (file) { | 889 return _validateOneMatch(path, (file) { |
| 889 return readTextFile(file).then((text) { | 890 var text = readTextFile(file); |
| 890 if (text == contents) return null; | 891 if (text == contents) return null; |
| 891 | 892 |
| 892 throw new ExpectException( | 893 throw new ExpectException( |
| 893 'File $file should contain:\n\n$contents\n\n' | 894 'File $file should contain:\n\n$contents\n\n' |
| 894 'but contained:\n\n$text'); | 895 'but contained:\n\n$text'); |
| 895 }); | |
| 896 }); | 896 }); |
| 897 } | 897 } |
| 898 | 898 |
| 899 /// Loads the contents of the file. | 899 /// Loads the contents of the file. |
| 900 InputStream load(List<String> path) { | 900 InputStream load(List<String> path) { |
| 901 if (!path.isEmpty) { | 901 if (!path.isEmpty) { |
| 902 var joinedPath = Strings.join(path, '/'); | 902 var joinedPath = Strings.join(path, '/'); |
| 903 throw "Can't load $joinedPath from within $name: not a directory."; | 903 throw "Can't load $joinedPath from within $name: not a directory."; |
| 904 } | 904 } |
| 905 | 905 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 917 /// The files and directories contained in this directory. | 917 /// The files and directories contained in this directory. |
| 918 final List<Descriptor> contents; | 918 final List<Descriptor> contents; |
| 919 | 919 |
| 920 DirectoryDescriptor(Pattern name, List<Descriptor> contents) | 920 DirectoryDescriptor(Pattern name, List<Descriptor> contents) |
| 921 : this.contents = contents == null ? <Descriptor>[] : contents, | 921 : this.contents = contents == null ? <Descriptor>[] : contents, |
| 922 super(name); | 922 super(name); |
| 923 | 923 |
| 924 /// Creates the file within [dir]. Returns a [Future] that is completed after | 924 /// Creates the file within [dir]. Returns a [Future] that is completed after |
| 925 /// the creation is done. | 925 /// the creation is done. |
| 926 Future<Directory> create(parentDir) { | 926 Future<Directory> create(parentDir) { |
| 927 // Create the directory. | 927 // Make sure all errors propagate through the future. |
| 928 return ensureDir(join(parentDir, _stringName)).then((dir) { | 928 return defer(() { |
| 929 if (contents == null) return new Future<Directory>.immediate(dir); | 929 // Create the directory. |
| 930 var dir = ensureDir(join(parentDir, _stringName)); |
| 931 if (contents == null) return dir; |
| 930 | 932 |
| 931 // Recursively create all of its children. | 933 // Recursively create all of its children. |
| 932 final childFutures = | 934 var childFutures = contents.map((child) => child.create(dir)).toList(); |
| 933 contents.map((child) => child.create(dir)).toList(); | |
| 934 // Only complete once all of the children have been created too. | 935 // Only complete once all of the children have been created too. |
| 935 return Future.wait(childFutures).then((_) => dir); | 936 return Future.wait(childFutures).then((_) => dir); |
| 936 }); | 937 }); |
| 937 } | 938 } |
| 938 | 939 |
| 939 /// Deletes the directory within [dir]. Returns a [Future] that is completed | 940 /// Deletes the directory within [dir]. Returns a [Future] that is completed |
| 940 /// after the deletion is done. | 941 /// after the deletion is done. |
| 941 Future delete(dir) { | 942 Future delete(dir) { |
| 942 return deleteDir(join(dir, _stringName)); | 943 return deleteDir(join(dir, _stringName)); |
| 943 } | 944 } |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1127 } | 1128 } |
| 1128 | 1129 |
| 1129 /// A descriptor that validates that no file exists with the given name. | 1130 /// A descriptor that validates that no file exists with the given name. |
| 1130 class NothingDescriptor extends Descriptor { | 1131 class NothingDescriptor extends Descriptor { |
| 1131 NothingDescriptor(String name) : super(name); | 1132 NothingDescriptor(String name) : super(name); |
| 1132 | 1133 |
| 1133 Future create(dir) => new Future.immediate(null); | 1134 Future create(dir) => new Future.immediate(null); |
| 1134 Future delete(dir) => new Future.immediate(null); | 1135 Future delete(dir) => new Future.immediate(null); |
| 1135 | 1136 |
| 1136 Future validate(String dir) { | 1137 Future validate(String dir) { |
| 1137 return exists(join(dir, name)).then((exists) { | 1138 // Make sure errors propagate through future. |
| 1138 if (exists) { | 1139 return defer(() { |
| 1140 if (entryExists(join(dir, name))) { |
| 1139 throw new ExpectException('File $name in $dir should not exist.'); | 1141 throw new ExpectException('File $name in $dir should not exist.'); |
| 1140 } | 1142 } |
| 1141 }); | 1143 }); |
| 1142 } | 1144 } |
| 1143 | 1145 |
| 1144 InputStream load(List<String> path) { | 1146 InputStream load(List<String> path) { |
| 1145 if (path.isEmpty) { | 1147 if (path.isEmpty) { |
| 1146 throw "Can't load the contents of $name: it doesn't exist."; | 1148 throw "Can't load the contents of $name: it doesn't exist."; |
| 1147 } else { | 1149 } else { |
| 1148 throw "Can't load ${Strings.join(path, '/')} from within $name: $name " | 1150 throw "Can't load ${Strings.join(path, '/')} from within $name: $name " |
| 1149 "doesn't exist."; | 1151 "doesn't exist."; |
| 1150 } | 1152 } |
| 1151 } | 1153 } |
| 1152 } | 1154 } |
| 1153 | 1155 |
| 1154 /// A function that creates a [Validator] subclass. | 1156 /// A function that creates a [Validator] subclass. |
| 1155 typedef Validator ValidatorCreator(Entrypoint entrypoint); | 1157 typedef Validator ValidatorCreator(Entrypoint entrypoint); |
| 1156 | 1158 |
| 1157 /// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled | 1159 /// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled |
| 1158 /// Future that contains the erros and warnings produced by that validator. | 1160 /// Future that contains the erros and warnings produced by that validator. |
| 1159 Future<Pair<List<String>, List<String>>> schedulePackageValidation( | 1161 Future<Pair<List<String>, List<String>>> schedulePackageValidation( |
| 1160 ValidatorCreator fn) { | 1162 ValidatorCreator fn) { |
| 1161 return _scheduleValue((sandboxDir) { | 1163 return _scheduleValue((sandboxDir) { |
| 1162 var cache = new SystemCache.withSources( | 1164 var cache = new SystemCache.withSources(join(sandboxDir, cachePath)); |
| 1163 join(sandboxDir, cachePath)); | |
| 1164 | 1165 |
| 1165 return Entrypoint.load(join(sandboxDir, appPath), cache) | 1166 return defer(() { |
| 1166 .then((entrypoint) { | 1167 var validator = fn(new Entrypoint(join(sandboxDir, appPath), cache)); |
| 1167 var validator = fn(entrypoint); | |
| 1168 return validator.validate().then((_) { | 1168 return validator.validate().then((_) { |
| 1169 return new Pair(validator.errors, validator.warnings); | 1169 return new Pair(validator.errors, validator.warnings); |
| 1170 }); | 1170 }); |
| 1171 }); | 1171 }); |
| 1172 }); | 1172 }); |
| 1173 } | 1173 } |
| 1174 | 1174 |
| 1175 /// A matcher that matches a Pair. | 1175 /// A matcher that matches a Pair. |
| 1176 Matcher pairOf(Matcher firstMatcher, Matcher lastMatcher) => | 1176 Matcher pairOf(Matcher firstMatcher, Matcher lastMatcher) => |
| 1177 new _PairMatcher(firstMatcher, lastMatcher); | 1177 new _PairMatcher(firstMatcher, lastMatcher); |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1466 } | 1466 } |
| 1467 | 1467 |
| 1468 /// Ignore all requests with the given [method] and [path]. If one is | 1468 /// Ignore all requests with the given [method] and [path]. If one is |
| 1469 /// received, don't respond to it. | 1469 /// received, don't respond to it. |
| 1470 void ignore(String method, String path) => | 1470 void ignore(String method, String path) => |
| 1471 _ignored.add(new Pair(method, path)); | 1471 _ignored.add(new Pair(method, path)); |
| 1472 | 1472 |
| 1473 /// Raises an error complaining of an unexpected request. | 1473 /// Raises an error complaining of an unexpected request. |
| 1474 void _awaitHandle(HttpRequest request, HttpResponse response) { | 1474 void _awaitHandle(HttpRequest request, HttpResponse response) { |
| 1475 if (_ignored.contains(new Pair(request.method, request.path))) return; | 1475 if (_ignored.contains(new Pair(request.method, request.path))) return; |
| 1476 var future = timeout(new Future.immediate(null).then((_) { | 1476 // Make sure all errors propagate through future. |
| 1477 var future = timeout(defer(() { |
| 1477 if (_handlers.isEmpty) { | 1478 if (_handlers.isEmpty) { |
| 1478 fail('Unexpected ${request.method} request to ${request.path}.'); | 1479 fail('Unexpected ${request.method} request to ${request.path}.'); |
| 1479 } | 1480 } |
| 1480 return _handlers.removeFirst(); | 1481 return _handlers.removeFirst(); |
| 1481 }).then((handler) { | 1482 }).then((handler) { |
| 1482 handler(request, response); | 1483 handler(request, response); |
| 1483 }), _SCHEDULE_TIMEOUT, "waiting for a handler for ${request.method} " | 1484 }), _SCHEDULE_TIMEOUT, "waiting for a handler for ${request.method} " |
| 1484 "${request.path}"); | 1485 "${request.path}"); |
| 1485 expect(future, completes); | 1486 expect(future, completes); |
| 1486 } | 1487 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1550 /// calling [completion] is unnecessary. | 1551 /// calling [completion] is unnecessary. |
| 1551 void expectLater(Future actual, matcher, {String reason, | 1552 void expectLater(Future actual, matcher, {String reason, |
| 1552 FailureHandler failureHandler, bool verbose: false}) { | 1553 FailureHandler failureHandler, bool verbose: false}) { |
| 1553 _schedule((_) { | 1554 _schedule((_) { |
| 1554 return actual.then((value) { | 1555 return actual.then((value) { |
| 1555 expect(value, matcher, reason: reason, failureHandler: failureHandler, | 1556 expect(value, matcher, reason: reason, failureHandler: failureHandler, |
| 1556 verbose: false); | 1557 verbose: false); |
| 1557 }); | 1558 }); |
| 1558 }); | 1559 }); |
| 1559 } | 1560 } |
| OLD | NEW |