| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 376 path.join(sandboxDir, target), | 376 path.join(sandboxDir, target), |
| 377 path.join(sandboxDir, symlink)), | 377 path.join(sandboxDir, symlink)), |
| 378 'symlinking $target to $symlink'); | 378 'symlinking $target to $symlink'); |
| 379 } | 379 } |
| 380 | 380 |
| 381 /// Schedules a call to the Pub command-line utility. | 381 /// Schedules a call to the Pub command-line utility. |
| 382 /// | 382 /// |
| 383 /// Runs Pub with [args] and validates that its results match [output] (or | 383 /// Runs Pub with [args] and validates that its results match [output] (or |
| 384 /// [outputJson]), [error], and [exitCode]. | 384 /// [outputJson]), [error], and [exitCode]. |
| 385 /// | 385 /// |
| 386 /// [output] and [error] can be [String]s, [RegExp]s, or [Matcher]s. |
| 387 /// |
| 386 /// If [outputJson] is given, validates that pub outputs stringified JSON | 388 /// If [outputJson] is given, validates that pub outputs stringified JSON |
| 387 /// matching that object, which can be a literal JSON object or any other | 389 /// matching that object, which can be a literal JSON object or any other |
| 388 /// [Matcher]. | 390 /// [Matcher]. |
| 389 void schedulePub({List args, Pattern output, Pattern error, outputJson, | 391 void schedulePub({List args, output, error, outputJson, |
| 390 Future<Uri> tokenEndpoint, int exitCode: exit_codes.SUCCESS}) { | 392 Future<Uri> tokenEndpoint, int exitCode: exit_codes.SUCCESS}) { |
| 391 // Cannot pass both output and outputJson. | 393 // Cannot pass both output and outputJson. |
| 392 assert(output == null || outputJson == null); | 394 assert(output == null || outputJson == null); |
| 393 | 395 |
| 394 var pub = startPub(args: args, tokenEndpoint: tokenEndpoint); | 396 var pub = startPub(args: args, tokenEndpoint: tokenEndpoint); |
| 395 pub.shouldExit(exitCode); | 397 pub.shouldExit(exitCode); |
| 396 | 398 |
| 397 var failures = []; | 399 var failures = []; |
| 398 var stderr; | 400 var stderr; |
| 399 | 401 |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 730 'downloads': 0, | 732 'downloads': 0, |
| 731 'created': '2012-09-25T18:38:28.685260', | 733 'created': '2012-09-25T18:38:28.685260', |
| 732 'libraries': ['$name.dart'], | 734 'libraries': ['$name.dart'], |
| 733 'uploader': ['nweiz@google.com'] | 735 'uploader': ['nweiz@google.com'] |
| 734 }); | 736 }); |
| 735 } | 737 } |
| 736 | 738 |
| 737 return map; | 739 return map; |
| 738 } | 740 } |
| 739 | 741 |
| 740 /// Compares the [actual] output from running pub with [expected]. For [String] | 742 /// Compares the [actual] output from running pub with [expected]. |
| 741 /// patterns, ignores leading and trailing whitespace differences and tries to | 743 /// |
| 742 /// report the offending difference in a nice way. For other [Pattern]s, just | 744 /// If [expected] is a [String], ignores leading and trailing whitespace |
| 743 /// reports whether the output contained the pattern. | 745 /// differences and tries to report the offending difference in a nice way. |
| 744 void _validateOutput(List<String> failures, String pipe, Pattern expected, | 746 /// |
| 747 /// If it's a [RegExp] or [Matcher], just reports whether the output matches. |
| 748 void _validateOutput(List<String> failures, String pipe, expected, |
| 745 String actual) { | 749 String actual) { |
| 746 if (expected == null) return; | 750 if (expected == null) return; |
| 747 | 751 |
| 748 var actualLines = actual.split("\n"); | 752 if (expected is String) { |
| 749 if (expected is RegExp) { | 753 _validateOutputString(failures, pipe, expected, actual); |
| 750 _validateOutputRegex(failures, pipe, expected, actualLines); | |
| 751 } else { | 754 } else { |
| 752 _validateOutputString(failures, pipe, expected, actualLines); | 755 if (expected is RegExp) expected = matches(expected); |
| 753 } | 756 expect(actual, expected); |
| 754 } | |
| 755 | |
| 756 void _validateOutputRegex(List<String> failures, String pipe, | |
| 757 RegExp expected, List<String> actual) { | |
| 758 var actualText = actual.join('\n'); | |
| 759 if (actualText.contains(expected)) return; | |
| 760 | |
| 761 if (actual.length == 0) { | |
| 762 failures.add('Expected $pipe to match "${expected.pattern}" but got none.'); | |
| 763 } else { | |
| 764 failures.add('Expected $pipe to match "${expected.pattern}" but got:'); | |
| 765 failures.addAll(actual.map((line) => '| $line')); | |
| 766 } | 757 } |
| 767 } | 758 } |
| 768 | 759 |
| 769 void _validateOutputString(List<String> failures, String pipe, | 760 void _validateOutputString(List<String> failures, String pipe, |
| 770 String expectedText, List<String> actual) { | 761 String expected, String actual) { |
| 771 final expected = expectedText.split('\n'); | 762 var actualLines = actual.split("\n"); |
| 763 var expectedLines = expected.split("\n"); |
| 772 | 764 |
| 773 // Strip off the last line. This lets us have expected multiline strings | 765 // Strip off the last line. This lets us have expected multiline strings |
| 774 // where the closing ''' is on its own line. It also fixes '' expected output | 766 // where the closing ''' is on its own line. It also fixes '' expected output |
| 775 // to expect zero lines of output, not a single empty line. | 767 // to expect zero lines of output, not a single empty line. |
| 776 if (expected.last.trim() == '') { | 768 if (expectedLines.last.trim() == '') { |
| 777 expected.removeLast(); | 769 expectedLines.removeLast(); |
| 778 } | 770 } |
| 779 | 771 |
| 780 var results = []; | 772 var results = []; |
| 781 var failed = false; | 773 var failed = false; |
| 782 | 774 |
| 783 // Compare them line by line to see which ones match. | 775 // Compare them line by line to see which ones match. |
| 784 var length = max(expected.length, actual.length); | 776 var length = max(expectedLines.length, actualLines.length); |
| 785 for (var i = 0; i < length; i++) { | 777 for (var i = 0; i < length; i++) { |
| 786 if (i >= actual.length) { | 778 if (i >= actualLines.length) { |
| 787 // Missing output. | 779 // Missing output. |
| 788 failed = true; | 780 failed = true; |
| 789 results.add('? ${expected[i]}'); | 781 results.add('? ${expectedLines[i]}'); |
| 790 } else if (i >= expected.length) { | 782 } else if (i >= expectedLines.length) { |
| 791 // Unexpected extra output. | 783 // Unexpected extra output. |
| 792 failed = true; | 784 failed = true; |
| 793 results.add('X ${actual[i]}'); | 785 results.add('X ${actualLines[i]}'); |
| 794 } else { | 786 } else { |
| 795 var expectedLine = expected[i].trim(); | 787 var expectedLine = expectedLines[i].trim(); |
| 796 var actualLine = actual[i].trim(); | 788 var actualLine = actualLines[i].trim(); |
| 797 | 789 |
| 798 if (expectedLine != actualLine) { | 790 if (expectedLine != actualLine) { |
| 799 // Mismatched lines. | 791 // Mismatched lines. |
| 800 failed = true; | 792 failed = true; |
| 801 results.add('X ${actual[i]}'); | 793 results.add('X ${actualLines[i]}'); |
| 802 } else { | 794 } else { |
| 803 // Output is OK, but include it in case other lines are wrong. | 795 // Output is OK, but include it in case other lines are wrong. |
| 804 results.add('| ${actual[i]}'); | 796 results.add('| ${actualLines[i]}'); |
| 805 } | 797 } |
| 806 } | 798 } |
| 807 } | 799 } |
| 808 | 800 |
| 809 // If any lines mismatched, show the expected and actual. | 801 // If any lines mismatched, show the expected and actual. |
| 810 if (failed) { | 802 if (failed) { |
| 811 failures.add('Expected $pipe:'); | 803 failures.add('Expected $pipe:'); |
| 812 failures.addAll(expected.map((line) => '| $line')); | 804 failures.addAll(expectedLines.map((line) => '| $line')); |
| 813 failures.add('Got:'); | 805 failures.add('Got:'); |
| 814 failures.addAll(results); | 806 failures.addAll(results); |
| 815 } | 807 } |
| 816 } | 808 } |
| 817 | 809 |
| 818 /// Validates that [actualText] is a string of JSON that matches [expected], | 810 /// Validates that [actualText] is a string of JSON that matches [expected], |
| 819 /// which may be a literal JSON object, or any other [Matcher]. | 811 /// which may be a literal JSON object, or any other [Matcher]. |
| 820 void _validateOutputJson(List<String> failures, String pipe, | 812 void _validateOutputJson(List<String> failures, String pipe, |
| 821 expected, String actualText) { | 813 expected, String actualText) { |
| 822 var actual; | 814 var actual; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 868 _lastMatcher.matches(item.last, matchState); | 860 _lastMatcher.matches(item.last, matchState); |
| 869 } | 861 } |
| 870 | 862 |
| 871 Description describe(Description description) { | 863 Description describe(Description description) { |
| 872 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); | 864 return description.addAll("(", ", ", ")", [_firstMatcher, _lastMatcher]); |
| 873 } | 865 } |
| 874 } | 866 } |
| 875 | 867 |
| 876 /// A [StreamMatcher] that matches multiple lines of output. | 868 /// A [StreamMatcher] that matches multiple lines of output. |
| 877 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); | 869 StreamMatcher emitsLines(String output) => inOrder(output.split("\n")); |
| OLD | NEW |