| 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 library pub_update_test; | 5 library pub_update_test; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 import 'dart:io'; | 8 import 'dart:io'; |
| 9 | 9 |
| 10 import 'package:unittest/unittest.dart'; | 10 import 'package:unittest/unittest.dart'; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 33 | 33 |
| 34 // Since this test isn't run from the SDK, it can't find the "version" file | 34 // Since this test isn't run from the SDK, it can't find the "version" file |
| 35 // to load. Instead, just manually inject a version. | 35 // to load. Instead, just manually inject a version. |
| 36 sdk.version = new Version(1, 2, 3); | 36 sdk.version = new Version(1, 2, 3); |
| 37 | 37 |
| 38 group('basic graph', basicGraph); | 38 group('basic graph', basicGraph); |
| 39 group('with lockfile', withLockFile); | 39 group('with lockfile', withLockFile); |
| 40 group('root dependency', rootDependency); | 40 group('root dependency', rootDependency); |
| 41 group('dev dependency', devDependency); | 41 group('dev dependency', devDependency); |
| 42 group('unsolvable', unsolvable); | 42 group('unsolvable', unsolvable); |
| 43 group('bad source', badSource); |
| 43 group('backtracking', backtracking); | 44 group('backtracking', backtracking); |
| 44 group('SDK constraint', sdkConstraint); | 45 group('SDK constraint', sdkConstraint); |
| 45 } | 46 } |
| 46 | 47 |
| 47 void basicGraph() { | 48 void basicGraph() { |
| 48 testResolve('no dependencies', { | 49 testResolve('no dependencies', { |
| 49 'myapp 0.0.0': {} | 50 'myapp 0.0.0': {} |
| 50 }, result: { | 51 }, result: { |
| 51 'myapp from root': '0.0.0' | 52 'myapp from root': '0.0.0' |
| 52 }); | 53 }); |
| (...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 }, | 398 }, |
| 398 'b 1.0.0': { | 399 'b 1.0.0': { |
| 399 'a': '2.0.0' | 400 'a': '2.0.0' |
| 400 }, | 401 }, |
| 401 'b 2.0.0': { | 402 'b 2.0.0': { |
| 402 'a': '1.0.0' | 403 'a': '1.0.0' |
| 403 } | 404 } |
| 404 }, error: couldNotSolve, maxTries: 4); | 405 }, error: couldNotSolve, maxTries: 4); |
| 405 } | 406 } |
| 406 | 407 |
| 408 badSource() { |
| 409 testResolve('fail if the root package has a bad source in dep', { |
| 410 'myapp 0.0.0': { |
| 411 'foo from bad': 'any' |
| 412 }, |
| 413 }, error: unknownSource('myapp', 'foo', 'bad')); |
| 414 |
| 415 testResolve('fail if the root package has a bad source in dev dep', { |
| 416 'myapp 0.0.0': { |
| 417 '(dev) foo from bad': 'any' |
| 418 }, |
| 419 }, error: unknownSource('myapp', 'foo', 'bad')); |
| 420 |
| 421 testResolve('fail if all versions have bad source in dep', { |
| 422 'myapp 0.0.0': { |
| 423 'foo': 'any' |
| 424 }, |
| 425 'foo 1.0.0': { |
| 426 'bar from bad': 'any' |
| 427 }, |
| 428 'foo 1.0.1': { |
| 429 'baz from bad': 'any' |
| 430 }, |
| 431 'foo 1.0.3': { |
| 432 'bang from bad': 'any' |
| 433 }, |
| 434 }, error: unknownSource('foo', 'bar', 'bad'), maxTries: 3); |
| 435 |
| 436 testResolve('ignore versions with bad source in dep', { |
| 437 'myapp 1.0.0': { |
| 438 'foo': 'any' |
| 439 }, |
| 440 'foo 1.0.0': { |
| 441 'bar': 'any' |
| 442 }, |
| 443 'foo 1.0.1': { |
| 444 'bar from bad': 'any' |
| 445 }, |
| 446 'foo 1.0.3': { |
| 447 'bar from bad': 'any' |
| 448 }, |
| 449 'bar 1.0.0': {} |
| 450 }, result: { |
| 451 'myapp from root': '1.0.0', |
| 452 'foo': '1.0.0', |
| 453 'bar': '1.0.0' |
| 454 }, maxTries: 3); |
| 455 } |
| 456 |
| 407 backtracking() { | 457 backtracking() { |
| 408 testResolve('circular dependency on older version', { | 458 testResolve('circular dependency on older version', { |
| 409 'myapp 0.0.0': { | 459 'myapp 0.0.0': { |
| 410 'a': '>=1.0.0' | 460 'a': '>=1.0.0' |
| 411 }, | 461 }, |
| 412 'a 1.0.0': {}, | 462 'a 1.0.0': {}, |
| 413 'a 2.0.0': { | 463 'a 2.0.0': { |
| 414 'b': '1.0.0' | 464 'b': '1.0.0' |
| 415 }, | 465 }, |
| 416 'b 1.0.0': { | 466 'b 1.0.0': { |
| (...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 768 var name = parts[0]; | 818 var name = parts[0]; |
| 769 var version = parts[1]; | 819 var version = parts[1]; |
| 770 | 820 |
| 771 var package = mockPackage(name, version, dependencies); | 821 var package = mockPackage(name, version, dependencies); |
| 772 if (name == 'myapp') { | 822 if (name == 'myapp') { |
| 773 // Don't add the root package to the server, so we can verify that Pub | 823 // Don't add the root package to the server, so we can verify that Pub |
| 774 // doesn't try to look up information about the local package on the | 824 // doesn't try to look up information about the local package on the |
| 775 // remote server. | 825 // remote server. |
| 776 root = package; | 826 root = package; |
| 777 } else { | 827 } else { |
| 778 source.addPackage(name, package); | 828 cache.sources[source].addPackage(name, package); |
| 779 } | 829 } |
| 780 }); | 830 }); |
| 781 }); | 831 }); |
| 782 | 832 |
| 783 // Clean up the expectation. | 833 // Clean up the expectation. |
| 784 if (result != null) { | 834 if (result != null) { |
| 785 var newResult = {}; | 835 var newResult = {}; |
| 786 result.forEach((name, version) { | 836 result.forEach((name, version) { |
| 787 parseSource(name, (isDev, name, source) { | 837 parseSource(name, (isDev, name, source) { |
| 788 version = new Version.parse(version); | 838 version = new Version.parse(version); |
| 789 newResult[name] = new PackageId(name, source, version, name); | 839 newResult[name] = new PackageId(name, source, version, name); |
| 790 }); | 840 }); |
| 791 }); | 841 }); |
| 792 result = newResult; | 842 result = newResult; |
| 793 } | 843 } |
| 794 | 844 |
| 795 var realLockFile = new LockFile.empty(); | 845 var realLockFile = new LockFile.empty(); |
| 796 if (lockfile != null) { | 846 if (lockfile != null) { |
| 797 lockfile.forEach((name, version) { | 847 lockfile.forEach((name, version) { |
| 798 version = new Version.parse(version); | 848 version = new Version.parse(version); |
| 799 realLockFile.packages[name] = | 849 realLockFile.packages[name] = |
| 800 new PackageId(name, source1, version, name); | 850 new PackageId(name, source1.name, version, name); |
| 801 }); | 851 }); |
| 802 } | 852 } |
| 803 | 853 |
| 804 // Make a version number like the continuous build's version. | 854 // Make a version number like the continuous build's version. |
| 805 var previousVersion = sdk.version; | 855 var previousVersion = sdk.version; |
| 806 if (useBleedingEdgeSdkVersion) { | 856 if (useBleedingEdgeSdkVersion) { |
| 807 sdk.version = new Version(0, 1, 2, build: '0_r12345_juser'); | 857 sdk.version = new Version(0, 1, 2, build: '0_r12345_juser'); |
| 808 } | 858 } |
| 809 | 859 |
| 810 // Resolve the versions. | 860 // Resolve the versions. |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 849 // happened during propagation. Since we don't specify the order that solutions | 899 // happened during propagation. Since we don't specify the order that solutions |
| 850 // are tried, this just validates that *some* failure occurred, but not which. | 900 // are tried, this just validates that *some* failure occurred, but not which. |
| 851 SolveFailMatcher couldNotSolve(maxTries) => | 901 SolveFailMatcher couldNotSolve(maxTries) => |
| 852 new SolveFailMatcher([], maxTries, null); | 902 new SolveFailMatcher([], maxTries, null); |
| 853 | 903 |
| 854 FailMatcherBuilder sourceMismatch(String package1, String package2) { | 904 FailMatcherBuilder sourceMismatch(String package1, String package2) { |
| 855 return (maxTries) => new SolveFailMatcher([package1, package2], maxTries, | 905 return (maxTries) => new SolveFailMatcher([package1, package2], maxTries, |
| 856 SourceMismatchException); | 906 SourceMismatchException); |
| 857 } | 907 } |
| 858 | 908 |
| 909 unknownSource(String depender, String dependency, String source) { |
| 910 return (maxTries) => new SolveFailMatcher([depender, dependency, source], |
| 911 maxTries, UnknownSourceException); |
| 912 } |
| 913 |
| 859 class SolveSuccessMatcher implements Matcher { | 914 class SolveSuccessMatcher implements Matcher { |
| 860 /// The expected concrete package selections. | 915 /// The expected concrete package selections. |
| 861 final Map<String, PackageId> _expected; | 916 final Map<String, PackageId> _expected; |
| 862 | 917 |
| 863 /// The maximum number of attempts that should have been tried before finding | 918 /// The maximum number of attempts that should have been tried before finding |
| 864 /// the solution. | 919 /// the solution. |
| 865 final int _maxTries; | 920 final int _maxTries; |
| 866 | 921 |
| 867 SolveSuccessMatcher(this._expected, this._maxTries); | 922 SolveSuccessMatcher(this._expected, this._maxTries); |
| 868 | 923 |
| 869 Description describe(Description description) { | 924 Description describe(Description description) { |
| 870 return description.add( | 925 return description.add( |
| 871 'Solver to use at most $_maxTries attempts to find:\n' | 926 'Solver to use at most $_maxTries attempts to find:\n' |
| 872 '${_listPackages(_expected.values)}'); | 927 '${_listPackages(_expected.values)}'); |
| 873 } | 928 } |
| 874 | 929 |
| 875 Description describeMismatch(SolveResult result, | 930 Description describeMismatch(SolveResult result, |
| 876 Description description, | 931 Description description, |
| 877 MatchState state, bool verbose) { | 932 MatchState state, bool verbose) { |
| 878 if (!result.succeeded) { | 933 if (!result.succeeded) { |
| 879 description.add('Solver failed with:\n${result.error}'); | 934 description.add('Solver failed with:\n${result.error}'); |
| 880 return; | 935 return null; |
| 881 } | 936 } |
| 882 | 937 |
| 883 description.add('Resolved:\n${_listPackages(result.packages)}\n'); | 938 description.add('Resolved:\n${_listPackages(result.packages)}\n'); |
| 884 description.add(state.state); | 939 description.add(state.state); |
| 885 return description; | 940 return description; |
| 886 } | 941 } |
| 887 | 942 |
| 888 bool matches(SolveResult result, MatchState state) { | 943 bool matches(SolveResult result, MatchState state) { |
| 889 if (!result.succeeded) return false; | 944 if (!result.succeeded) return false; |
| 890 | 945 |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1026 throw new Exception('Version list for $description was already ' | 1081 throw new Exception('Version list for $description was already ' |
| 1027 'requested.'); | 1082 'requested.'); |
| 1028 } | 1083 } |
| 1029 | 1084 |
| 1030 _requestedVersions.add(description); | 1085 _requestedVersions.add(description); |
| 1031 | 1086 |
| 1032 if (!_packages.containsKey(description)){ | 1087 if (!_packages.containsKey(description)){ |
| 1033 throw new Exception('MockSource does not have a package matching ' | 1088 throw new Exception('MockSource does not have a package matching ' |
| 1034 '"$description".'); | 1089 '"$description".'); |
| 1035 } | 1090 } |
| 1091 |
| 1036 return _packages[description].keys.toList(); | 1092 return _packages[description].keys.toList(); |
| 1037 }); | 1093 }); |
| 1038 } | 1094 } |
| 1039 | 1095 |
| 1040 Future<Pubspec> describe(PackageId id) { | 1096 Future<Pubspec> describe(PackageId id) { |
| 1041 return new Future.sync(() { | 1097 return new Future.sync(() { |
| 1042 // Make sure the solver doesn't request the same thing twice. | 1098 // Make sure the solver doesn't request the same thing twice. |
| 1043 if (_requestedPubspecs.containsKey(id.description) && | 1099 if (_requestedPubspecs.containsKey(id.description) && |
| 1044 _requestedPubspecs[id.description].contains(id.version)) { | 1100 _requestedPubspecs[id.description].contains(id.version)) { |
| 1045 throw new Exception('Pubspec for $id was already requested.'); | 1101 throw new Exception('Pubspec for $id was already requested.'); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1091 }); | 1147 }); |
| 1092 | 1148 |
| 1093 var name = description.replaceFirst(new RegExp(r"-[^-]+$"), ""); | 1149 var name = description.replaceFirst(new RegExp(r"-[^-]+$"), ""); |
| 1094 var pubspec = new Pubspec( | 1150 var pubspec = new Pubspec( |
| 1095 name, new Version.parse(version), dependencies, devDependencies, | 1151 name, new Version.parse(version), dependencies, devDependencies, |
| 1096 new PubspecEnvironment(sdkConstraint)); | 1152 new PubspecEnvironment(sdkConstraint)); |
| 1097 return new Package.inMemory(pubspec); | 1153 return new Package.inMemory(pubspec); |
| 1098 } | 1154 } |
| 1099 | 1155 |
| 1100 void parseSource(String description, | 1156 void parseSource(String description, |
| 1101 callback(bool isDev, String name, Source source)) { | 1157 callback(bool isDev, String name, String source)) { |
| 1102 var isDev = false; | 1158 var isDev = false; |
| 1103 | 1159 |
| 1104 if (description.startsWith("(dev) ")) { | 1160 if (description.startsWith("(dev) ")) { |
| 1105 description = description.substring("(dev) ".length); | 1161 description = description.substring("(dev) ".length); |
| 1106 isDev = true; | 1162 isDev = true; |
| 1107 } | 1163 } |
| 1108 | 1164 |
| 1109 var name = description; | 1165 var name = description; |
| 1110 var source = source1; | 1166 var source = "mock1"; |
| 1111 | |
| 1112 var sourceNames = { | |
| 1113 'mock1': source1, | |
| 1114 'mock2': source2, | |
| 1115 'root': null | |
| 1116 }; | |
| 1117 | |
| 1118 var match = new RegExp(r"(.*) from (.*)").firstMatch(description); | 1167 var match = new RegExp(r"(.*) from (.*)").firstMatch(description); |
| 1119 if (match != null) { | 1168 if (match != null) { |
| 1120 name = match[1]; | 1169 name = match[1]; |
| 1121 source = sourceNames[match[2]]; | 1170 source = match[2]; |
| 1171 if (source == "root") source = null; |
| 1122 } | 1172 } |
| 1123 | 1173 |
| 1124 callback(isDev, name, source); | 1174 callback(isDev, name, source); |
| 1125 } | 1175 } |
| OLD | NEW |