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 562 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
573 'Pub returned exit code ${result.exitCode}, expected $exitCode.'); | 573 'Pub returned exit code ${result.exitCode}, expected $exitCode.'); |
574 } | 574 } |
575 | 575 |
576 if (failures.length > 0) { | 576 if (failures.length > 0) { |
577 if (error == null) { | 577 if (error == null) { |
578 // If we aren't validating the error, still show it on failure. | 578 // If we aren't validating the error, still show it on failure. |
579 failures.add('Pub stderr:'); | 579 failures.add('Pub stderr:'); |
580 failures.addAll(result.stderr.map((line) => '| $line')); | 580 failures.addAll(result.stderr.map((line) => '| $line')); |
581 } | 581 } |
582 | 582 |
583 throw new ExpectException(Strings.join(failures, '\n')); | 583 throw new ExpectException(failures.join('\n')); |
584 } | 584 } |
585 | 585 |
586 return null; | 586 return null; |
587 }); | 587 }); |
588 }); | 588 }); |
589 } | 589 } |
590 | 590 |
591 /// Starts a Pub process and returns a [ScheduledProcess] that supports | 591 /// Starts a Pub process and returns a [ScheduledProcess] that supports |
592 /// interaction with that process. | 592 /// interaction with that process. |
593 /// | 593 /// |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
736 | 736 |
737 if (expected is RegExp) { | 737 if (expected is RegExp) { |
738 _validateOutputRegex(failures, pipe, expected, actual); | 738 _validateOutputRegex(failures, pipe, expected, actual); |
739 } else { | 739 } else { |
740 _validateOutputString(failures, pipe, expected, actual); | 740 _validateOutputString(failures, pipe, expected, actual); |
741 } | 741 } |
742 } | 742 } |
743 | 743 |
744 void _validateOutputRegex(List<String> failures, String pipe, | 744 void _validateOutputRegex(List<String> failures, String pipe, |
745 RegExp expected, List<String> actual) { | 745 RegExp expected, List<String> actual) { |
746 var actualText = Strings.join(actual, '\n'); | 746 var actualText = actual.join('\n'); |
747 if (actualText.contains(expected)) return; | 747 if (actualText.contains(expected)) return; |
748 | 748 |
749 if (actual.length == 0) { | 749 if (actual.length == 0) { |
750 failures.add('Expected $pipe to match "${expected.pattern}" but got none.'); | 750 failures.add('Expected $pipe to match "${expected.pattern}" but got none.'); |
751 } else { | 751 } else { |
752 failures.add('Expected $pipe to match "${expected.pattern}" but got:'); | 752 failures.add('Expected $pipe to match "${expected.pattern}" but got:'); |
753 failures.addAll(actual.map((line) => '| $line')); | 753 failures.addAll(actual.map((line) => '| $line')); |
754 } | 754 } |
755 } | 755 } |
756 | 756 |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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'); |
949 }); | 949 }); |
950 } | 950 } |
951 | 951 |
952 /// Loads the contents of the file. | 952 /// Loads the contents of the file. |
953 ByteStream load(List<String> path) { | 953 ByteStream load(List<String> path) { |
954 if (!path.isEmpty) { | 954 if (!path.isEmpty) { |
955 var joinedPath = Strings.join(path, '/'); | 955 throw "Can't load ${path.join('/')} from within $name: not a directory."; |
956 throw "Can't load $joinedPath from within $name: not a directory."; | |
957 } | 956 } |
958 | 957 |
959 return new ByteStream.fromBytes(contents); | 958 return new ByteStream.fromBytes(contents); |
960 } | 959 } |
961 } | 960 } |
962 | 961 |
963 /// Describes a directory and its contents. These are used both for setting up | 962 /// Describes a directory and its contents. These are used both for setting up |
964 /// an expected directory tree before running a test, and for validating that | 963 /// an expected directory tree before running a test, and for validating that |
965 /// the file system matches some expectations after running it. | 964 /// the file system matches some expectations after running it. |
966 class DirectoryDescriptor extends Descriptor { | 965 class DirectoryDescriptor extends Descriptor { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1012 if (path.isEmpty) { | 1011 if (path.isEmpty) { |
1013 throw "Can't load the contents of $name: is a directory."; | 1012 throw "Can't load the contents of $name: is a directory."; |
1014 } | 1013 } |
1015 | 1014 |
1016 for (var descriptor in contents) { | 1015 for (var descriptor in contents) { |
1017 if (descriptor.name == path[0]) { | 1016 if (descriptor.name == path[0]) { |
1018 return descriptor.load(path.getRange(1, path.length - 1)); | 1017 return descriptor.load(path.getRange(1, path.length - 1)); |
1019 } | 1018 } |
1020 } | 1019 } |
1021 | 1020 |
1022 throw "Directory $name doesn't contain ${Strings.join(path, '/')}."; | 1021 throw "Directory $name doesn't contain ${path.join('/')}."; |
1023 } | 1022 } |
1024 } | 1023 } |
1025 | 1024 |
1026 /// Wraps a [Future] that will complete to a [Descriptor] and makes it behave | 1025 /// Wraps a [Future] that will complete to a [Descriptor] and makes it behave |
1027 /// like a concrete [Descriptor]. This is necessary when the contents of the | 1026 /// like a concrete [Descriptor]. This is necessary when the contents of the |
1028 /// descriptor depends on information that's not available until part of the | 1027 /// descriptor depends on information that's not available until part of the |
1029 /// test run is completed. | 1028 /// test run is completed. |
1030 class FutureDescriptor extends Descriptor { | 1029 class FutureDescriptor extends Descriptor { |
1031 Future<Descriptor> _future; | 1030 Future<Descriptor> _future; |
1032 | 1031 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1096 var command = commands.removeAt(0); | 1095 var command = commands.removeAt(0); |
1097 return _runGit(command, workingDir).then(runGitStep); | 1096 return _runGit(command, workingDir).then(runGitStep); |
1098 } | 1097 } |
1099 | 1098 |
1100 return super.create(parentDir).then((rootDir) { | 1099 return super.create(parentDir).then((rootDir) { |
1101 workingDir = rootDir; | 1100 workingDir = rootDir; |
1102 return runGitStep(null); | 1101 return runGitStep(null); |
1103 }); | 1102 }); |
1104 } | 1103 } |
1105 | 1104 |
1106 Future<String> _runGit(List<String> args, Directory workingDir) { | 1105 Future<List<String>> _runGit(List<String> args, Directory workingDir) { |
1107 // Explicitly specify the committer information. Git needs this to commit | 1106 // Explicitly specify the committer information. Git needs this to commit |
1108 // and we don't want to rely on the buildbots having this already set up. | 1107 // and we don't want to rely on the buildbots having this already set up. |
1109 var environment = { | 1108 var environment = { |
1110 'GIT_AUTHOR_NAME': 'Pub Test', | 1109 'GIT_AUTHOR_NAME': 'Pub Test', |
1111 'GIT_AUTHOR_EMAIL': 'pub@dartlang.org', | 1110 'GIT_AUTHOR_EMAIL': 'pub@dartlang.org', |
1112 'GIT_COMMITTER_NAME': 'Pub Test', | 1111 'GIT_COMMITTER_NAME': 'Pub Test', |
1113 'GIT_COMMITTER_EMAIL': 'pub@dartlang.org' | 1112 'GIT_COMMITTER_EMAIL': 'pub@dartlang.org' |
1114 }; | 1113 }; |
1115 | 1114 |
1116 return gitlib.run(args, workingDir: workingDir.path, | 1115 return gitlib.run(args, workingDir: workingDir.path, |
(...skipping 27 matching lines...) Expand all Loading... |
1144 throw "TODO(nweiz): implement this"; | 1143 throw "TODO(nweiz): implement this"; |
1145 } | 1144 } |
1146 | 1145 |
1147 Future delete(dir) { | 1146 Future delete(dir) { |
1148 throw new UnsupportedError(''); | 1147 throw new UnsupportedError(''); |
1149 } | 1148 } |
1150 | 1149 |
1151 /// Loads the contents of this tar file. | 1150 /// Loads the contents of this tar file. |
1152 ByteStream load(List<String> path) { | 1151 ByteStream load(List<String> path) { |
1153 if (!path.isEmpty) { | 1152 if (!path.isEmpty) { |
1154 var joinedPath = Strings.join(path, '/'); | 1153 throw "Can't load ${path.join('/')} from within $name: not a directory."; |
1155 throw "Can't load $joinedPath from within $name: not a directory."; | |
1156 } | 1154 } |
1157 | 1155 |
1158 var controller = new StreamController<List<int>>(); | 1156 var controller = new StreamController<List<int>>(); |
1159 // TODO(nweiz): propagate any errors to the return value. See issue 3657. | 1157 // TODO(nweiz): propagate any errors to the return value. See issue 3657. |
1160 withTempDir((tempDir) { | 1158 withTempDir((tempDir) { |
1161 return create(tempDir).then((tar) { | 1159 return create(tempDir).then((tar) { |
1162 var sourceStream = tar.openInputStream(); | 1160 var sourceStream = tar.openInputStream(); |
1163 return store(wrapInputStream(sourceStream), controller); | 1161 return store(wrapInputStream(sourceStream), controller); |
1164 }); | 1162 }); |
1165 }); | 1163 }); |
(...skipping 13 matching lines...) Expand all Loading... |
1179 if (entryExists(join(dir, name))) { | 1177 if (entryExists(join(dir, name))) { |
1180 throw new ExpectException('File $name in $dir should not exist.'); | 1178 throw new ExpectException('File $name in $dir should not exist.'); |
1181 } | 1179 } |
1182 }); | 1180 }); |
1183 } | 1181 } |
1184 | 1182 |
1185 ByteStream load(List<String> path) { | 1183 ByteStream load(List<String> path) { |
1186 if (path.isEmpty) { | 1184 if (path.isEmpty) { |
1187 throw "Can't load the contents of $name: it doesn't exist."; | 1185 throw "Can't load the contents of $name: it doesn't exist."; |
1188 } else { | 1186 } else { |
1189 throw "Can't load ${Strings.join(path, '/')} from within $name: $name " | 1187 throw "Can't load ${path.join('/')} from within $name: $name doesn't " |
1190 "doesn't exist."; | 1188 "exist."; |
1191 } | 1189 } |
1192 } | 1190 } |
1193 } | 1191 } |
1194 | 1192 |
1195 /// A function that creates a [Validator] subclass. | 1193 /// A function that creates a [Validator] subclass. |
1196 typedef Validator ValidatorCreator(Entrypoint entrypoint); | 1194 typedef Validator ValidatorCreator(Entrypoint entrypoint); |
1197 | 1195 |
1198 /// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled | 1196 /// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled |
1199 /// Future that contains the errors and warnings produced by that validator. | 1197 /// Future that contains the errors and warnings produced by that validator. |
1200 Future<Pair<List<String>, List<String>>> schedulePackageValidation( | 1198 Future<Pair<List<String>, List<String>>> schedulePackageValidation( |
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1628 /// calling [completion] is unnecessary. | 1626 /// calling [completion] is unnecessary. |
1629 void expectLater(Future actual, matcher, {String reason, | 1627 void expectLater(Future actual, matcher, {String reason, |
1630 FailureHandler failureHandler, bool verbose: false}) { | 1628 FailureHandler failureHandler, bool verbose: false}) { |
1631 _schedule((_) { | 1629 _schedule((_) { |
1632 return actual.then((value) { | 1630 return actual.then((value) { |
1633 expect(value, matcher, reason: reason, failureHandler: failureHandler, | 1631 expect(value, matcher, reason: reason, failureHandler: failureHandler, |
1634 verbose: false); | 1632 verbose: false); |
1635 }); | 1633 }); |
1636 }); | 1634 }); |
1637 } | 1635 } |
OLD | NEW |