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 535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 var dir = new Options().script; | 546 var dir = new Options().script; |
547 while (path.basename(dir) != 'pub') dir = path.dirname(dir); | 547 while (path.basename(dir) != 'pub') dir = path.dirname(dir); |
548 | 548 |
549 return path.absolute(dir); | 549 return path.absolute(dir); |
550 } | 550 } |
551 | 551 |
552 /// Schedules renaming (moving) the directory at [from] to [to], both of which | 552 /// Schedules renaming (moving) the directory at [from] to [to], both of which |
553 /// are assumed to be relative to [sandboxDir]. | 553 /// are assumed to be relative to [sandboxDir]. |
554 void scheduleRename(String from, String to) { | 554 void scheduleRename(String from, String to) { |
555 _schedule((sandboxDir) { | 555 _schedule((sandboxDir) { |
556 return renameDir(join(sandboxDir, from), join(sandboxDir, to)); | 556 return renameDir(path.join(sandboxDir, from), path.join(sandboxDir, to)); |
557 }); | 557 }); |
558 } | 558 } |
559 | 559 |
560 /// Schedules a call to the Pub command-line utility. Runs Pub with [args] and | 560 /// Schedules a call to the Pub command-line utility. Runs Pub with [args] and |
561 /// validates that its results match [output], [error], and [exitCode]. | 561 /// validates that its results match [output], [error], and [exitCode]. |
562 void schedulePub({List args, Pattern output, Pattern error, | 562 void schedulePub({List args, Pattern output, Pattern error, |
563 Future<Uri> tokenEndpoint, int exitCode: 0}) { | 563 Future<Uri> tokenEndpoint, int exitCode: 0}) { |
564 _schedule((sandboxDir) { | 564 _schedule((sandboxDir) { |
565 return _doPub(runProcess, sandboxDir, args, tokenEndpoint).then((result) { | 565 return _doPub(runProcess, sandboxDir, args, tokenEndpoint).then((result) { |
566 var failures = []; | 566 var failures = []; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 expectLater(pub.nextLine(), equals("")); | 625 expectLater(pub.nextLine(), equals("")); |
626 | 626 |
627 pub.writeLine("y"); | 627 pub.writeLine("y"); |
628 } | 628 } |
629 | 629 |
630 /// Calls [fn] with appropriately modified arguments to run a pub process. [fn] | 630 /// Calls [fn] with appropriately modified arguments to run a pub process. [fn] |
631 /// should have the same signature as [startProcess], except that the returned | 631 /// should have the same signature as [startProcess], except that the returned |
632 /// [Future] may have a type other than [Process]. | 632 /// [Future] may have a type other than [Process]. |
633 Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) { | 633 Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) { |
634 String pathInSandbox(String relPath) { | 634 String pathInSandbox(String relPath) { |
635 return join(path.absolute(sandboxDir), relPath); | 635 return path.join(path.absolute(sandboxDir), relPath); |
636 } | 636 } |
637 | 637 |
638 return defer(() { | 638 return defer(() { |
639 ensureDir(pathInSandbox(appPath)); | 639 ensureDir(pathInSandbox(appPath)); |
640 return Future.wait([ | 640 return Future.wait([ |
641 _awaitObject(args), | 641 _awaitObject(args), |
642 tokenEndpoint == null ? new Future.immediate(null) : tokenEndpoint | 642 tokenEndpoint == null ? new Future.immediate(null) : tokenEndpoint |
643 ]); | 643 ]); |
644 }).then((results) { | 644 }).then((results) { |
645 var args = results[0]; | 645 var args = results[0]; |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
846 | 846 |
847 /// Asserts that the name of the descriptor is a [String] and returns it. | 847 /// Asserts that the name of the descriptor is a [String] and returns it. |
848 String get _stringName { | 848 String get _stringName { |
849 if (name is String) return name; | 849 if (name is String) return name; |
850 throw 'Pattern $name must be a string.'; | 850 throw 'Pattern $name must be a string.'; |
851 } | 851 } |
852 | 852 |
853 /// Validates that at least one file in [dir] matching [name] is valid | 853 /// Validates that at least one file in [dir] matching [name] is valid |
854 /// according to [validate]. [validate] should throw or complete to an | 854 /// according to [validate]. [validate] should throw or complete to an |
855 /// exception if the input path is invalid. | 855 /// exception if the input path is invalid. |
856 Future _validateOneMatch(String dir, Future validate(String path)) { | 856 Future _validateOneMatch(String dir, Future validate(String entry)) { |
857 // Special-case strings to support multi-level names like "myapp/packages". | 857 // Special-case strings to support multi-level names like "myapp/packages". |
858 if (name is String) { | 858 if (name is String) { |
859 var path = join(dir, name); | 859 var entry = path.join(dir, name); |
860 return defer(() { | 860 return defer(() { |
861 if (!entryExists(path)) { | 861 if (!entryExists(entry)) { |
862 throw new ExpectException('Entry $path not found.'); | 862 throw new ExpectException('Entry $entry not found.'); |
863 } | 863 } |
864 return validate(path); | 864 return validate(entry); |
865 }); | 865 }); |
866 } | 866 } |
867 | 867 |
868 // TODO(nweiz): remove this when issue 4061 is fixed. | 868 // TODO(nweiz): remove this when issue 4061 is fixed. |
869 var stackTrace; | 869 var stackTrace; |
870 try { | 870 try { |
871 throw ""; | 871 throw ""; |
872 } catch (_, localStackTrace) { | 872 } catch (_, localStackTrace) { |
873 stackTrace = localStackTrace; | 873 stackTrace = localStackTrace; |
874 } | 874 } |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
922 | 922 |
923 String get textContents => new String.fromCharCodes(contents); | 923 String get textContents => new String.fromCharCodes(contents); |
924 | 924 |
925 FileDescriptor.bytes(Pattern name, this.contents) : super(name); | 925 FileDescriptor.bytes(Pattern name, this.contents) : super(name); |
926 | 926 |
927 FileDescriptor(Pattern name, String contents) : | 927 FileDescriptor(Pattern name, String contents) : |
928 this.bytes(name, encodeUtf8(contents)); | 928 this.bytes(name, encodeUtf8(contents)); |
929 | 929 |
930 /// Creates the file within [dir]. Returns a [Future] that is completed after | 930 /// Creates the file within [dir]. Returns a [Future] that is completed after |
931 /// the creation is done. | 931 /// the creation is done. |
932 Future<File> create(dir) => | 932 Future<String> create(dir) => |
933 defer(() => writeBinaryFile(join(dir, _stringName), contents)); | 933 defer(() => writeBinaryFile(path.join(dir, _stringName), contents)); |
934 | 934 |
935 /// Deletes the file within [dir]. Returns a [Future] that is completed after | 935 /// Deletes the file within [dir]. Returns a [Future] that is completed after |
936 /// the deletion is done. | 936 /// the deletion is done. |
937 Future delete(dir) => | 937 Future delete(dir) => |
938 defer(() => deleteFile(join(dir, _stringName))); | 938 defer(() => deleteFile(path.join(dir, _stringName))); |
939 | 939 |
940 /// Validates that this file correctly matches the actual file at [path]. | 940 /// Validates that this file correctly matches the actual file at [path]. |
941 Future validate(String path) { | 941 Future validate(String path) { |
942 return _validateOneMatch(path, (file) { | 942 return _validateOneMatch(path, (file) { |
943 var text = readTextFile(file); | 943 var text = readTextFile(file); |
944 if (text == textContents) return null; | 944 if (text == textContents) return null; |
945 | 945 |
946 throw new ExpectException( | 946 throw new ExpectException( |
947 'File $file should contain:\n\n$textContents\n\n' | 947 'File $file should contain:\n\n$textContents\n\n' |
948 'but contained:\n\n$text'); | 948 'but contained:\n\n$text'); |
(...skipping 16 matching lines...) Expand all Loading... |
965 class DirectoryDescriptor extends Descriptor { | 965 class DirectoryDescriptor extends Descriptor { |
966 /// The files and directories contained in this directory. | 966 /// The files and directories contained in this directory. |
967 final List<Descriptor> contents; | 967 final List<Descriptor> contents; |
968 | 968 |
969 DirectoryDescriptor(Pattern name, List<Descriptor> contents) | 969 DirectoryDescriptor(Pattern name, List<Descriptor> contents) |
970 : this.contents = contents == null ? <Descriptor>[] : contents, | 970 : this.contents = contents == null ? <Descriptor>[] : contents, |
971 super(name); | 971 super(name); |
972 | 972 |
973 /// Creates the file within [dir]. Returns a [Future] that is completed after | 973 /// Creates the file within [dir]. Returns a [Future] that is completed after |
974 /// the creation is done. | 974 /// the creation is done. |
975 Future<Directory> create(parentDir) { | 975 Future<String> create(parentDir) { |
976 return defer(() { | 976 return defer(() { |
977 // Create the directory. | 977 // Create the directory. |
978 var dir = ensureDir(join(parentDir, _stringName)); | 978 var dir = ensureDir(path.join(parentDir, _stringName)); |
979 if (contents == null) return dir; | 979 if (contents == null) return dir; |
980 | 980 |
981 // Recursively create all of its children. | 981 // Recursively create all of its children. |
982 var childFutures = contents.map((child) => child.create(dir)).toList(); | 982 var childFutures = contents.map((child) => child.create(dir)).toList(); |
983 // Only complete once all of the children have been created too. | 983 // Only complete once all of the children have been created too. |
984 return Future.wait(childFutures).then((_) => dir); | 984 return Future.wait(childFutures).then((_) => dir); |
985 }); | 985 }); |
986 } | 986 } |
987 | 987 |
988 /// Deletes the directory within [dir]. Returns a [Future] that is completed | 988 /// Deletes the directory within [dir]. Returns a [Future] that is completed |
989 /// after the deletion is done. | 989 /// after the deletion is done. |
990 Future delete(dir) { | 990 Future delete(dir) { |
991 return deleteDir(join(dir, _stringName)); | 991 return deleteDir(path.join(dir, _stringName)); |
992 } | 992 } |
993 | 993 |
994 /// Validates that the directory at [path] contains all of the expected | 994 /// Validates that the directory at [path] contains all of the expected |
995 /// contents in this descriptor. Note that this does *not* check that the | 995 /// contents in this descriptor. Note that this does *not* check that the |
996 /// directory doesn't contain other unexpected stuff, just that it *does* | 996 /// directory doesn't contain other unexpected stuff, just that it *does* |
997 /// contain the stuff we do expect. | 997 /// contain the stuff we do expect. |
998 Future validate(String path) { | 998 Future validate(String path) { |
999 return _validateOneMatch(path, (dir) { | 999 return _validateOneMatch(path, (dir) { |
1000 // Validate each of the items in this directory. | 1000 // Validate each of the items in this directory. |
1001 final entryFutures = | 1001 final entryFutures = |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1043 return new ByteStream(controller.stream); | 1043 return new ByteStream(controller.stream); |
1044 } | 1044 } |
1045 } | 1045 } |
1046 | 1046 |
1047 /// Describes a Git repository and its contents. | 1047 /// Describes a Git repository and its contents. |
1048 class GitRepoDescriptor extends DirectoryDescriptor { | 1048 class GitRepoDescriptor extends DirectoryDescriptor { |
1049 GitRepoDescriptor(Pattern name, List<Descriptor> contents) | 1049 GitRepoDescriptor(Pattern name, List<Descriptor> contents) |
1050 : super(name, contents); | 1050 : super(name, contents); |
1051 | 1051 |
1052 /// Creates the Git repository and commits the contents. | 1052 /// Creates the Git repository and commits the contents. |
1053 Future<Directory> create(parentDir) { | 1053 Future create(parentDir) { |
1054 return _runGitCommands(parentDir, [ | 1054 return _runGitCommands(parentDir, [ |
1055 ['init'], | 1055 ['init'], |
1056 ['add', '.'], | 1056 ['add', '.'], |
1057 ['commit', '-m', 'initial commit'] | 1057 ['commit', '-m', 'initial commit'] |
1058 ]); | 1058 ]); |
1059 } | 1059 } |
1060 | 1060 |
1061 /// Commits any changes to the Git repository. | 1061 /// Commits any changes to the Git repository. |
1062 Future commit(parentDir) { | 1062 Future commit(parentDir) { |
1063 return _runGitCommands(parentDir, [ | 1063 return _runGitCommands(parentDir, [ |
(...skipping 10 matching lines...) Expand all Loading... |
1074 Future<String> revParse(String ref) { | 1074 Future<String> revParse(String ref) { |
1075 return _scheduleValue((parentDir) { | 1075 return _scheduleValue((parentDir) { |
1076 return super.create(parentDir).then((rootDir) { | 1076 return super.create(parentDir).then((rootDir) { |
1077 return _runGit(['rev-parse', ref], rootDir); | 1077 return _runGit(['rev-parse', ref], rootDir); |
1078 }).then((output) => output[0]); | 1078 }).then((output) => output[0]); |
1079 }); | 1079 }); |
1080 } | 1080 } |
1081 | 1081 |
1082 /// Schedule a Git command to run in this repository. | 1082 /// Schedule a Git command to run in this repository. |
1083 void scheduleGit(List<String> args) { | 1083 void scheduleGit(List<String> args) { |
1084 _schedule((parentDir) { | 1084 _schedule((parentDir) => _runGit(args, path.join(parentDir, name))); |
1085 var gitDir = new Directory(join(parentDir, name)); | |
1086 return _runGit(args, gitDir); | |
1087 }); | |
1088 } | 1085 } |
1089 | 1086 |
1090 Future _runGitCommands(parentDir, List<List<String>> commands) { | 1087 Future _runGitCommands(parentDir, List<List<String>> commands) { |
1091 var workingDir; | 1088 var workingDir; |
1092 | 1089 |
1093 Future runGitStep(_) { | 1090 Future runGitStep(_) { |
1094 if (commands.isEmpty) return new Future.immediate(workingDir); | 1091 if (commands.isEmpty) return new Future.immediate(workingDir); |
1095 var command = commands.removeAt(0); | 1092 var command = commands.removeAt(0); |
1096 return _runGit(command, workingDir).then(runGitStep); | 1093 return _runGit(command, workingDir).then(runGitStep); |
1097 } | 1094 } |
1098 | 1095 |
1099 return super.create(parentDir).then((rootDir) { | 1096 return super.create(parentDir).then((rootDir) { |
1100 workingDir = rootDir; | 1097 workingDir = rootDir; |
1101 return runGitStep(null); | 1098 return runGitStep(null); |
1102 }); | 1099 }); |
1103 } | 1100 } |
1104 | 1101 |
1105 Future<List<String>> _runGit(List<String> args, Directory workingDir) { | 1102 Future<List<String>> _runGit(List<String> args, String workingDir) { |
1106 // Explicitly specify the committer information. Git needs this to commit | 1103 // Explicitly specify the committer information. Git needs this to commit |
1107 // and we don't want to rely on the buildbots having this already set up. | 1104 // and we don't want to rely on the buildbots having this already set up. |
1108 var environment = { | 1105 var environment = { |
1109 'GIT_AUTHOR_NAME': 'Pub Test', | 1106 'GIT_AUTHOR_NAME': 'Pub Test', |
1110 'GIT_AUTHOR_EMAIL': 'pub@dartlang.org', | 1107 'GIT_AUTHOR_EMAIL': 'pub@dartlang.org', |
1111 'GIT_COMMITTER_NAME': 'Pub Test', | 1108 'GIT_COMMITTER_NAME': 'Pub Test', |
1112 'GIT_COMMITTER_EMAIL': 'pub@dartlang.org' | 1109 'GIT_COMMITTER_EMAIL': 'pub@dartlang.org' |
1113 }; | 1110 }; |
1114 | 1111 |
1115 return gitlib.run(args, workingDir: workingDir.path, | 1112 return gitlib.run(args, workingDir: workingDir, environment: environment); |
1116 environment: environment); | |
1117 } | 1113 } |
1118 } | 1114 } |
1119 | 1115 |
1120 /// Describes a gzipped tar file and its contents. | 1116 /// Describes a gzipped tar file and its contents. |
1121 class TarFileDescriptor extends Descriptor { | 1117 class TarFileDescriptor extends Descriptor { |
1122 final List<Descriptor> contents; | 1118 final List<Descriptor> contents; |
1123 | 1119 |
1124 TarFileDescriptor(Pattern name, this.contents) | 1120 TarFileDescriptor(Pattern name, this.contents) |
1125 : super(name); | 1121 : super(name); |
1126 | 1122 |
1127 /// Creates the files and directories within this tar file, then archives | 1123 /// Creates the files and directories within this tar file, then archives |
1128 /// them, compresses them, and saves the result to [parentDir]. | 1124 /// them, compresses them, and saves the result to [parentDir]. |
1129 Future<File> create(parentDir) { | 1125 Future<String> create(parentDir) { |
1130 return withTempDir((tempDir) { | 1126 return withTempDir((tempDir) { |
1131 return Future.wait(contents.map((child) => child.create(tempDir))) | 1127 return Future.wait(contents.map((child) => child.create(tempDir))) |
1132 .then((createdContents) { | 1128 .then((createdContents) { |
1133 return createTarGz(createdContents, baseDir: tempDir).toBytes(); | 1129 return createTarGz(createdContents, baseDir: tempDir).toBytes(); |
1134 }).then((bytes) { | 1130 }).then((bytes) { |
1135 return new File(join(parentDir, _stringName)).writeAsBytes(bytes); | 1131 var file = path.join(parentDir, _stringName); |
| 1132 writeBinaryFile(file, bytes); |
| 1133 return file; |
1136 }); | 1134 }); |
1137 }); | 1135 }); |
1138 } | 1136 } |
1139 | 1137 |
1140 /// Validates that the `.tar.gz` file at [path] contains the expected | 1138 /// Validates that the `.tar.gz` file at [path] contains the expected |
1141 /// contents. | 1139 /// contents. |
1142 Future validate(String path) { | 1140 Future validate(String path) { |
1143 throw "TODO(nweiz): implement this"; | 1141 throw "TODO(nweiz): implement this"; |
1144 } | 1142 } |
1145 | 1143 |
1146 Future delete(dir) { | 1144 Future delete(dir) { |
1147 throw new UnsupportedError(''); | 1145 throw new UnsupportedError(''); |
1148 } | 1146 } |
1149 | 1147 |
1150 /// Loads the contents of this tar file. | 1148 /// Loads the contents of this tar file. |
1151 ByteStream load(List<String> path) { | 1149 ByteStream load(List<String> path) { |
1152 if (!path.isEmpty) { | 1150 if (!path.isEmpty) { |
1153 throw "Can't load ${path.join('/')} from within $name: not a directory."; | 1151 throw "Can't load ${path.join('/')} from within $name: not a directory."; |
1154 } | 1152 } |
1155 | 1153 |
1156 var controller = new StreamController<List<int>>(); | 1154 var controller = new StreamController<List<int>>(); |
1157 // TODO(nweiz): propagate any errors to the return value. See issue 3657. | 1155 // TODO(nweiz): propagate any errors to the return value. See issue 3657. |
1158 withTempDir((tempDir) { | 1156 withTempDir((tempDir) { |
1159 return create(tempDir).then((tar) { | 1157 return create(tempDir).then((tar) { |
1160 var sourceStream = tar.openInputStream(); | 1158 var sourceStream = new File(tar).openInputStream(); |
1161 return store(wrapInputStream(sourceStream), controller); | 1159 return store(wrapInputStream(sourceStream), controller); |
1162 }); | 1160 }); |
1163 }); | 1161 }); |
1164 return new ByteStream(controller.stream); | 1162 return new ByteStream(controller.stream); |
1165 } | 1163 } |
1166 } | 1164 } |
1167 | 1165 |
1168 /// A descriptor that validates that no file exists with the given name. | 1166 /// A descriptor that validates that no file exists with the given name. |
1169 class NothingDescriptor extends Descriptor { | 1167 class NothingDescriptor extends Descriptor { |
1170 NothingDescriptor(String name) : super(name); | 1168 NothingDescriptor(String name) : super(name); |
1171 | 1169 |
1172 Future create(dir) => new Future.immediate(null); | 1170 Future create(dir) => new Future.immediate(null); |
1173 Future delete(dir) => new Future.immediate(null); | 1171 Future delete(dir) => new Future.immediate(null); |
1174 | 1172 |
1175 Future validate(String dir) { | 1173 Future validate(String dir) { |
1176 return defer(() { | 1174 return defer(() { |
1177 if (entryExists(join(dir, name))) { | 1175 if (entryExists(path.join(dir, name))) { |
1178 throw new ExpectException('File $name in $dir should not exist.'); | 1176 throw new ExpectException('File $name in $dir should not exist.'); |
1179 } | 1177 } |
1180 }); | 1178 }); |
1181 } | 1179 } |
1182 | 1180 |
1183 ByteStream load(List<String> path) { | 1181 ByteStream load(List<String> path) { |
1184 if (path.isEmpty) { | 1182 if (path.isEmpty) { |
1185 throw "Can't load the contents of $name: it doesn't exist."; | 1183 throw "Can't load the contents of $name: it doesn't exist."; |
1186 } else { | 1184 } else { |
1187 throw "Can't load ${path.join('/')} from within $name: $name doesn't " | 1185 throw "Can't load ${path.join('/')} from within $name: $name doesn't " |
1188 "exist."; | 1186 "exist."; |
1189 } | 1187 } |
1190 } | 1188 } |
1191 } | 1189 } |
1192 | 1190 |
1193 /// A function that creates a [Validator] subclass. | 1191 /// A function that creates a [Validator] subclass. |
1194 typedef Validator ValidatorCreator(Entrypoint entrypoint); | 1192 typedef Validator ValidatorCreator(Entrypoint entrypoint); |
1195 | 1193 |
1196 /// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled | 1194 /// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled |
1197 /// Future that contains the errors and warnings produced by that validator. | 1195 /// Future that contains the errors and warnings produced by that validator. |
1198 Future<Pair<List<String>, List<String>>> schedulePackageValidation( | 1196 Future<Pair<List<String>, List<String>>> schedulePackageValidation( |
1199 ValidatorCreator fn) { | 1197 ValidatorCreator fn) { |
1200 return _scheduleValue((sandboxDir) { | 1198 return _scheduleValue((sandboxDir) { |
1201 var cache = new SystemCache.withSources(join(sandboxDir, cachePath)); | 1199 var cache = new SystemCache.withSources(path.join(sandboxDir, cachePath)); |
1202 | 1200 |
1203 return defer(() { | 1201 return defer(() { |
1204 var validator = fn(new Entrypoint(join(sandboxDir, appPath), cache)); | 1202 var validator = fn(new Entrypoint(path.join(sandboxDir, appPath), cache)); |
1205 return validator.validate().then((_) { | 1203 return validator.validate().then((_) { |
1206 return new Pair(validator.errors, validator.warnings); | 1204 return new Pair(validator.errors, validator.warnings); |
1207 }); | 1205 }); |
1208 }); | 1206 }); |
1209 }); | 1207 }); |
1210 } | 1208 } |
1211 | 1209 |
1212 /// A matcher that matches a Pair. | 1210 /// A matcher that matches a Pair. |
1213 Matcher pairOf(Matcher firstMatcher, Matcher lastMatcher) => | 1211 Matcher pairOf(Matcher firstMatcher, Matcher lastMatcher) => |
1214 new _PairMatcher(firstMatcher, lastMatcher); | 1212 new _PairMatcher(firstMatcher, lastMatcher); |
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1626 /// calling [completion] is unnecessary. | 1624 /// calling [completion] is unnecessary. |
1627 void expectLater(Future actual, matcher, {String reason, | 1625 void expectLater(Future actual, matcher, {String reason, |
1628 FailureHandler failureHandler, bool verbose: false}) { | 1626 FailureHandler failureHandler, bool verbose: false}) { |
1629 _schedule((_) { | 1627 _schedule((_) { |
1630 return actual.then((value) { | 1628 return actual.then((value) { |
1631 expect(value, matcher, reason: reason, failureHandler: failureHandler, | 1629 expect(value, matcher, reason: reason, failureHandler: failureHandler, |
1632 verbose: false); | 1630 verbose: false); |
1633 }); | 1631 }); |
1634 }); | 1632 }); |
1635 } | 1633 } |
OLD | NEW |