| 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 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 183 versions[version] = yaml(spec); | 183 versions[version] = yaml(spec); |
| 184 } | 184 } |
| 185 | 185 |
| 186 _servedPackageDir.contents.clear(); | 186 _servedPackageDir.contents.clear(); |
| 187 for (var name in _servedPackages.keys) { | 187 for (var name in _servedPackages.keys) { |
| 188 var versions = _servedPackages[name].keys.toList(); | 188 var versions = _servedPackages[name].keys.toList(); |
| 189 _servedPackageDir.contents.addAll([ | 189 _servedPackageDir.contents.addAll([ |
| 190 file('$name.json', | 190 file('$name.json', |
| 191 json.stringify({'versions': versions})), | 191 json.stringify({'versions': versions})), |
| 192 dir(name, [ | 192 dir(name, [ |
| 193 dir('versions', flatten(versions.mappedBy((version) { | 193 dir('versions', flatten(versions.map((version) { |
| 194 return [ | 194 return [ |
| 195 file('$version.yaml', _servedPackages[name][version]), | 195 file('$version.yaml', _servedPackages[name][version]), |
| 196 tar('$version.tar.gz', [ | 196 tar('$version.tar.gz', [ |
| 197 file('pubspec.yaml', _servedPackages[name][version]), | 197 file('pubspec.yaml', _servedPackages[name][version]), |
| 198 libDir(name, '$name $version') | 198 libDir(name, '$name $version') |
| 199 ]) | 199 ]) |
| 200 ]; | 200 ]; |
| 201 }))) | 201 }))) |
| 202 ]) | 202 ]) |
| 203 ]); | 203 ]); |
| (...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 | 522 |
| 523 if (result.exitCode != exitCode) { | 523 if (result.exitCode != exitCode) { |
| 524 failures.add( | 524 failures.add( |
| 525 'Pub returned exit code ${result.exitCode}, expected $exitCode.'); | 525 'Pub returned exit code ${result.exitCode}, expected $exitCode.'); |
| 526 } | 526 } |
| 527 | 527 |
| 528 if (failures.length > 0) { | 528 if (failures.length > 0) { |
| 529 if (error == null) { | 529 if (error == null) { |
| 530 // If we aren't validating the error, still show it on failure. | 530 // If we aren't validating the error, still show it on failure. |
| 531 failures.add('Pub stderr:'); | 531 failures.add('Pub stderr:'); |
| 532 failures.addAll(result.stderr.mappedBy((line) => '| $line')); | 532 failures.addAll(result.stderr.map((line) => '| $line')); |
| 533 } | 533 } |
| 534 | 534 |
| 535 throw new ExpectException(Strings.join(failures, '\n')); | 535 throw new ExpectException(Strings.join(failures, '\n')); |
| 536 } | 536 } |
| 537 | 537 |
| 538 return null; | 538 return null; |
| 539 }); | 539 }); |
| 540 }); | 540 }); |
| 541 } | 541 } |
| 542 | 542 |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 694 | 694 |
| 695 void _validateOutputRegex(List<String> failures, String pipe, | 695 void _validateOutputRegex(List<String> failures, String pipe, |
| 696 RegExp expected, List<String> actual) { | 696 RegExp expected, List<String> actual) { |
| 697 var actualText = Strings.join(actual, '\n'); | 697 var actualText = Strings.join(actual, '\n'); |
| 698 if (actualText.contains(expected)) return; | 698 if (actualText.contains(expected)) return; |
| 699 | 699 |
| 700 if (actual.length == 0) { | 700 if (actual.length == 0) { |
| 701 failures.add('Expected $pipe to match "${expected.pattern}" but got none.'); | 701 failures.add('Expected $pipe to match "${expected.pattern}" but got none.'); |
| 702 } else { | 702 } else { |
| 703 failures.add('Expected $pipe to match "${expected.pattern}" but got:'); | 703 failures.add('Expected $pipe to match "${expected.pattern}" but got:'); |
| 704 failures.addAll(actual.mappedBy((line) => '| $line')); | 704 failures.addAll(actual.map((line) => '| $line')); |
| 705 } | 705 } |
| 706 } | 706 } |
| 707 | 707 |
| 708 void _validateOutputString(List<String> failures, String pipe, | 708 void _validateOutputString(List<String> failures, String pipe, |
| 709 String expectedText, List<String> actual) { | 709 String expectedText, List<String> actual) { |
| 710 final expected = expectedText.split('\n'); | 710 final expected = expectedText.split('\n'); |
| 711 | 711 |
| 712 // Strip off the last line. This lets us have expected multiline strings | 712 // Strip off the last line. This lets us have expected multiline strings |
| 713 // where the closing ''' is on its own line. It also fixes '' expected output | 713 // where the closing ''' is on its own line. It also fixes '' expected output |
| 714 // to expect zero lines of output, not a single empty line. | 714 // to expect zero lines of output, not a single empty line. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 739 } else { | 739 } else { |
| 740 // Output is OK, but include it in case other lines are wrong. | 740 // Output is OK, but include it in case other lines are wrong. |
| 741 results.add('| ${actual[i]}'); | 741 results.add('| ${actual[i]}'); |
| 742 } | 742 } |
| 743 } | 743 } |
| 744 } | 744 } |
| 745 | 745 |
| 746 // If any lines mismatched, show the expected and actual. | 746 // If any lines mismatched, show the expected and actual. |
| 747 if (failed) { | 747 if (failed) { |
| 748 failures.add('Expected $pipe:'); | 748 failures.add('Expected $pipe:'); |
| 749 failures.addAll(expected.mappedBy((line) => '| $line')); | 749 failures.addAll(expected.map((line) => '| $line')); |
| 750 failures.add('Got:'); | 750 failures.add('Got:'); |
| 751 failures.addAll(results); | 751 failures.addAll(results); |
| 752 } | 752 } |
| 753 } | 753 } |
| 754 | 754 |
| 755 /// Base class for [FileDescriptor] and [DirectoryDescriptor] so that a | 755 /// Base class for [FileDescriptor] and [DirectoryDescriptor] so that a |
| 756 /// directory can contain a heterogeneous collection of files and | 756 /// directory can contain a heterogeneous collection of files and |
| 757 /// subdirectories. | 757 /// subdirectories. |
| 758 abstract class Descriptor { | 758 abstract class Descriptor { |
| 759 /// The name of this file or directory. This must be a [String] if the file | 759 /// The name of this file or directory. This must be a [String] if the file |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 // Create the directory. |
| 928 return ensureDir(join(parentDir, _stringName)).then((dir) { | 928 return ensureDir(join(parentDir, _stringName)).then((dir) { |
| 929 if (contents == null) return new Future<Directory>.immediate(dir); | 929 if (contents == null) return new Future<Directory>.immediate(dir); |
| 930 | 930 |
| 931 // Recursively create all of its children. | 931 // Recursively create all of its children. |
| 932 final childFutures = | 932 final childFutures = |
| 933 contents.mappedBy((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. | 934 // Only complete once all of the children have been created too. |
| 935 return Future.wait(childFutures).then((_) => dir); | 935 return Future.wait(childFutures).then((_) => dir); |
| 936 }); | 936 }); |
| 937 } | 937 } |
| 938 | 938 |
| 939 /// Deletes the directory within [dir]. Returns a [Future] that is completed | 939 /// Deletes the directory within [dir]. Returns a [Future] that is completed |
| 940 /// after the deletion is done. | 940 /// after the deletion is done. |
| 941 Future delete(dir) { | 941 Future delete(dir) { |
| 942 return deleteDir(join(dir, _stringName)); | 942 return deleteDir(join(dir, _stringName)); |
| 943 } | 943 } |
| 944 | 944 |
| 945 /// Validates that the directory at [path] contains all of the expected | 945 /// Validates that the directory at [path] contains all of the expected |
| 946 /// contents in this descriptor. Note that this does *not* check that the | 946 /// contents in this descriptor. Note that this does *not* check that the |
| 947 /// directory doesn't contain other unexpected stuff, just that it *does* | 947 /// directory doesn't contain other unexpected stuff, just that it *does* |
| 948 /// contain the stuff we do expect. | 948 /// contain the stuff we do expect. |
| 949 Future validate(String path) { | 949 Future validate(String path) { |
| 950 return _validateOneMatch(path, (dir) { | 950 return _validateOneMatch(path, (dir) { |
| 951 // Validate each of the items in this directory. | 951 // Validate each of the items in this directory. |
| 952 final entryFutures = | 952 final entryFutures = |
| 953 contents.mappedBy((entry) => entry.validate(dir)).toList(); | 953 contents.map((entry) => entry.validate(dir)).toList(); |
| 954 | 954 |
| 955 // If they are all valid, the directory is valid. | 955 // If they are all valid, the directory is valid. |
| 956 return Future.wait(entryFutures).then((entries) => null); | 956 return Future.wait(entryFutures).then((entries) => null); |
| 957 }); | 957 }); |
| 958 } | 958 } |
| 959 | 959 |
| 960 /// Loads [path] from within this directory. | 960 /// Loads [path] from within this directory. |
| 961 InputStream load(List<String> path) { | 961 InputStream load(List<String> path) { |
| 962 if (path.isEmpty) { | 962 if (path.isEmpty) { |
| 963 throw "Can't load the contents of $name: is a directory."; | 963 throw "Can't load the contents of $name: is a directory."; |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1075 TarFileDescriptor(Pattern name, this.contents) | 1075 TarFileDescriptor(Pattern name, this.contents) |
| 1076 : super(name); | 1076 : super(name); |
| 1077 | 1077 |
| 1078 /// Creates the files and directories within this tar file, then archives | 1078 /// Creates the files and directories within this tar file, then archives |
| 1079 /// them, compresses them, and saves the result to [parentDir]. | 1079 /// them, compresses them, and saves the result to [parentDir]. |
| 1080 Future<File> create(parentDir) { | 1080 Future<File> create(parentDir) { |
| 1081 // TODO(rnystrom): Use withTempDir(). | 1081 // TODO(rnystrom): Use withTempDir(). |
| 1082 var tempDir; | 1082 var tempDir; |
| 1083 return createTempDir().then((_tempDir) { | 1083 return createTempDir().then((_tempDir) { |
| 1084 tempDir = _tempDir; | 1084 tempDir = _tempDir; |
| 1085 return Future.wait(contents.mappedBy((child) => child.create(tempDir))); | 1085 return Future.wait(contents.map((child) => child.create(tempDir))); |
| 1086 }).then((createdContents) { | 1086 }).then((createdContents) { |
| 1087 return consumeInputStream(createTarGz(createdContents, baseDir: tempDir)); | 1087 return consumeInputStream(createTarGz(createdContents, baseDir: tempDir)); |
| 1088 }).then((bytes) { | 1088 }).then((bytes) { |
| 1089 return new File(join(parentDir, _stringName)).writeAsBytes(bytes); | 1089 return new File(join(parentDir, _stringName)).writeAsBytes(bytes); |
| 1090 }).then((file) { | 1090 }).then((file) { |
| 1091 return deleteDir(tempDir).then((_) => file); | 1091 return deleteDir(tempDir).then((_) => file); |
| 1092 }); | 1092 }); |
| 1093 } | 1093 } |
| 1094 | 1094 |
| 1095 /// Validates that the `.tar.gz` file at [path] contains the expected | 1095 /// Validates that the `.tar.gz` file at [path] contains the expected |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1486 } | 1486 } |
| 1487 } | 1487 } |
| 1488 | 1488 |
| 1489 /// Takes a simple data structure (composed of [Map]s, [List]s, scalar objects, | 1489 /// Takes a simple data structure (composed of [Map]s, [List]s, scalar objects, |
| 1490 /// and [Future]s) and recursively resolves all the [Future]s contained within. | 1490 /// and [Future]s) and recursively resolves all the [Future]s contained within. |
| 1491 /// Completes with the fully resolved structure. | 1491 /// Completes with the fully resolved structure. |
| 1492 Future _awaitObject(object) { | 1492 Future _awaitObject(object) { |
| 1493 // Unroll nested futures. | 1493 // Unroll nested futures. |
| 1494 if (object is Future) return object.then(_awaitObject); | 1494 if (object is Future) return object.then(_awaitObject); |
| 1495 if (object is Collection) { | 1495 if (object is Collection) { |
| 1496 return Future.wait(object.mappedBy(_awaitObject).toList()); | 1496 return Future.wait(object.map(_awaitObject).toList()); |
| 1497 } | 1497 } |
| 1498 if (object is! Map) return new Future.immediate(object); | 1498 if (object is! Map) return new Future.immediate(object); |
| 1499 | 1499 |
| 1500 var pairs = <Future<Pair>>[]; | 1500 var pairs = <Future<Pair>>[]; |
| 1501 object.forEach((key, value) { | 1501 object.forEach((key, value) { |
| 1502 pairs.add(_awaitObject(value) | 1502 pairs.add(_awaitObject(value) |
| 1503 .then((resolved) => new Pair(key, resolved))); | 1503 .then((resolved) => new Pair(key, resolved))); |
| 1504 }); | 1504 }); |
| 1505 return Future.wait(pairs).then((resolvedPairs) { | 1505 return Future.wait(pairs).then((resolvedPairs) { |
| 1506 var map = {}; | 1506 var map = {}; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1550 /// calling [completion] is unnecessary. | 1550 /// calling [completion] is unnecessary. |
| 1551 void expectLater(Future actual, matcher, {String reason, | 1551 void expectLater(Future actual, matcher, {String reason, |
| 1552 FailureHandler failureHandler, bool verbose: false}) { | 1552 FailureHandler failureHandler, bool verbose: false}) { |
| 1553 _schedule((_) { | 1553 _schedule((_) { |
| 1554 return actual.then((value) { | 1554 return actual.then((value) { |
| 1555 expect(value, matcher, reason: reason, failureHandler: failureHandler, | 1555 expect(value, matcher, reason: reason, failureHandler: failureHandler, |
| 1556 verbose: false); | 1556 verbose: false); |
| 1557 }); | 1557 }); |
| 1558 }); | 1558 }); |
| 1559 } | 1559 } |
| OLD | NEW |