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 |