Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1430)

Side by Side Diff: utils/tests/pub/version_solver_test.dart

Issue 10949026: Allow circular dependencies on the root source in Pub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« utils/pub/version_solver.dart ('K') | « utils/pub/version_solver.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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:io'); 7 #import('dart:io');
8 #import('dart:isolate'); 8 #import('dart:isolate');
9 9
10 #import('../../pub/lock_file.dart'); 10 #import('../../pub/lock_file.dart');
11 #import('../../pub/package.dart'); 11 #import('../../pub/package.dart');
12 #import('../../pub/pubspec.dart'); 12 #import('../../pub/pubspec.dart');
13 #import('../../pub/root_source.dart');
13 #import('../../pub/source.dart'); 14 #import('../../pub/source.dart');
14 #import('../../pub/source_registry.dart'); 15 #import('../../pub/source_registry.dart');
15 #import('../../pub/utils.dart'); 16 #import('../../pub/utils.dart');
16 #import('../../pub/version.dart'); 17 #import('../../pub/version.dart');
17 #import('../../pub/version_solver.dart'); 18 #import('../../pub/version_solver.dart');
18 #import('../../../pkg/unittest/unittest.dart'); 19 #import('../../../pkg/unittest/unittest.dart');
19 20
20 final noVersion = 'no version'; 21 final noVersion = 'no version';
21 final disjointConstraint = 'disjoint'; 22 final disjointConstraint = 'disjoint';
22 final sourceMismatch = 'source mismatch'; 23 final sourceMismatch = 'source mismatch';
23 final descriptionMismatch = 'description mismatch'; 24 final descriptionMismatch = 'description mismatch';
24 final couldNotSolve = 'unsolved'; 25 final couldNotSolve = 'unsolved';
25 26
26 Source source1; 27 Source source1;
27 Source source2; 28 Source source2;
28 Source versionlessSource; 29 Source versionlessSource;
30 Source rootSource;
29 31
30 main() { 32 main() {
31 testResolve('no dependencies', { 33 testResolve('no dependencies', {
32 'myapp 0.0.0': {} 34 'myapp 0.0.0': {}
33 }, result: { 35 }, result: {
34 'myapp': '0.0.0' 36 'myapp from root': '0.0.0'
35 }); 37 });
36 38
37 testResolve('simple dependency tree', { 39 testResolve('simple dependency tree', {
38 'myapp 0.0.0': { 40 'myapp 0.0.0': {
39 'a': '1.0.0', 41 'a': '1.0.0',
40 'b': '1.0.0' 42 'b': '1.0.0'
41 }, 43 },
42 'a 1.0.0': { 44 'a 1.0.0': {
43 'aa': '1.0.0', 45 'aa': '1.0.0',
44 'ab': '1.0.0' 46 'ab': '1.0.0'
45 }, 47 },
46 'aa 1.0.0': {}, 48 'aa 1.0.0': {},
47 'ab 1.0.0': {}, 49 'ab 1.0.0': {},
48 'b 1.0.0': { 50 'b 1.0.0': {
49 'ba': '1.0.0', 51 'ba': '1.0.0',
50 'bb': '1.0.0' 52 'bb': '1.0.0'
51 }, 53 },
52 'ba 1.0.0': {}, 54 'ba 1.0.0': {},
53 'bb 1.0.0': {} 55 'bb 1.0.0': {}
54 }, result: { 56 }, result: {
55 'myapp': '0.0.0', 57 'myapp from root': '0.0.0',
56 'a': '1.0.0', 58 'a': '1.0.0',
57 'aa': '1.0.0', 59 'aa': '1.0.0',
58 'ab': '1.0.0', 60 'ab': '1.0.0',
59 'b': '1.0.0', 61 'b': '1.0.0',
60 'ba': '1.0.0', 62 'ba': '1.0.0',
61 'bb': '1.0.0' 63 'bb': '1.0.0'
62 }); 64 });
63 65
64 testResolve('shared dependency with overlapping constraints', { 66 testResolve('shared dependency with overlapping constraints', {
65 'myapp 0.0.0': { 67 'myapp 0.0.0': {
66 'a': '1.0.0', 68 'a': '1.0.0',
67 'b': '1.0.0' 69 'b': '1.0.0'
68 }, 70 },
69 'a 1.0.0': { 71 'a 1.0.0': {
70 'shared': '>=2.0.0 <4.0.0' 72 'shared': '>=2.0.0 <4.0.0'
71 }, 73 },
72 'b 1.0.0': { 74 'b 1.0.0': {
73 'shared': '>=3.0.0 <5.0.0' 75 'shared': '>=3.0.0 <5.0.0'
74 }, 76 },
75 'shared 2.0.0': {}, 77 'shared 2.0.0': {},
76 'shared 3.0.0': {}, 78 'shared 3.0.0': {},
77 'shared 3.6.9': {}, 79 'shared 3.6.9': {},
78 'shared 4.0.0': {}, 80 'shared 4.0.0': {},
79 'shared 5.0.0': {}, 81 'shared 5.0.0': {},
80 }, result: { 82 }, result: {
81 'myapp': '0.0.0', 83 'myapp from root': '0.0.0',
82 'a': '1.0.0', 84 'a': '1.0.0',
83 'b': '1.0.0', 85 'b': '1.0.0',
84 'shared': '3.6.9' 86 'shared': '3.6.9'
85 }); 87 });
86 88
87 testResolve('shared dependency where dependent version in turn affects ' 89 testResolve('shared dependency where dependent version in turn affects '
88 'other dependencies', { 90 'other dependencies', {
89 'myapp 0.0.0': { 91 'myapp 0.0.0': {
90 'foo': '<=1.0.2', 92 'foo': '<=1.0.2',
91 'bar': '1.0.0' 93 'bar': '1.0.0'
92 }, 94 },
93 'foo 1.0.0': {}, 95 'foo 1.0.0': {},
94 'foo 1.0.1': { 'bang': '1.0.0' }, 96 'foo 1.0.1': { 'bang': '1.0.0' },
95 'foo 1.0.2': { 'whoop': '1.0.0' }, 97 'foo 1.0.2': { 'whoop': '1.0.0' },
96 'foo 1.0.3': { 'zoop': '1.0.0' }, 98 'foo 1.0.3': { 'zoop': '1.0.0' },
97 'bar 1.0.0': { 'foo': '<=1.0.1' }, 99 'bar 1.0.0': { 'foo': '<=1.0.1' },
98 'bang 1.0.0': {}, 100 'bang 1.0.0': {},
99 'whoop 1.0.0': {}, 101 'whoop 1.0.0': {},
100 'zoop 1.0.0': {} 102 'zoop 1.0.0': {}
101 }, result: { 103 }, result: {
102 'myapp': '0.0.0', 104 'myapp from root': '0.0.0',
103 'foo': '1.0.1', 105 'foo': '1.0.1',
104 'bar': '1.0.0', 106 'bar': '1.0.0',
105 'bang': '1.0.0' 107 'bang': '1.0.0'
106 }); 108 });
107 109
108 testResolve('from versionless source', { 110 testResolve('from versionless source', {
109 'myapp 0.0.0': { 111 'myapp 0.0.0': {
110 'foo from versionless': 'any' 112 'foo from versionless': 'any'
111 }, 113 },
112 'foo 1.2.3 from versionless': {} 114 'foo 1.2.3 from versionless': {}
113 }, result: { 115 }, result: {
114 'myapp': '0.0.0', 116 'myapp from root': '0.0.0',
115 'foo': '1.2.3' 117 'foo from versionless': '1.2.3'
116 }); 118 });
117 119
118 testResolve('transitively through versionless source', { 120 testResolve('transitively through versionless source', {
119 'myapp 0.0.0': { 121 'myapp 0.0.0': {
120 'foo from versionless': 'any' 122 'foo from versionless': 'any'
121 }, 123 },
122 'foo 1.2.3 from versionless': { 124 'foo 1.2.3 from versionless': {
123 'bar': '>=1.0.0' 125 'bar': '>=1.0.0'
124 }, 126 },
125 'bar 1.1.0': {} 127 'bar 1.1.0': {}
126 }, result: { 128 }, result: {
127 'myapp': '0.0.0', 129 'myapp from root': '0.0.0',
128 'foo': '1.2.3', 130 'foo from versionless': '1.2.3',
129 'bar': '1.1.0' 131 'bar': '1.1.0'
130 }); 132 });
131 133
132 testResolve('with compatible locked dependency', { 134 testResolve('with compatible locked dependency', {
133 'myapp 0.0.0': { 135 'myapp 0.0.0': {
134 'foo': 'any' 136 'foo': 'any'
135 }, 137 },
136 'foo 1.0.0': { 'bar': '1.0.0' }, 138 'foo 1.0.0': { 'bar': '1.0.0' },
137 'foo 1.0.1': { 'bar': '1.0.1' }, 139 'foo 1.0.1': { 'bar': '1.0.1' },
138 'foo 1.0.2': { 'bar': '1.0.2' }, 140 'foo 1.0.2': { 'bar': '1.0.2' },
139 'bar 1.0.0': {}, 141 'bar 1.0.0': {},
140 'bar 1.0.1': {}, 142 'bar 1.0.1': {},
141 'bar 1.0.2': {} 143 'bar 1.0.2': {}
142 }, lockfile: { 144 }, lockfile: {
143 'foo': '1.0.1' 145 'foo': '1.0.1'
144 }, result: { 146 }, result: {
145 'myapp': '0.0.0', 147 'myapp from root': '0.0.0',
146 'foo': '1.0.1', 148 'foo': '1.0.1',
147 'bar': '1.0.1' 149 'bar': '1.0.1'
148 }); 150 });
149 151
150 testResolve('with incompatible locked dependency', { 152 testResolve('with incompatible locked dependency', {
151 'myapp 0.0.0': { 153 'myapp 0.0.0': {
152 'foo': '>1.0.1' 154 'foo': '>1.0.1'
153 }, 155 },
154 'foo 1.0.0': { 'bar': '1.0.0' }, 156 'foo 1.0.0': { 'bar': '1.0.0' },
155 'foo 1.0.1': { 'bar': '1.0.1' }, 157 'foo 1.0.1': { 'bar': '1.0.1' },
156 'foo 1.0.2': { 'bar': '1.0.2' }, 158 'foo 1.0.2': { 'bar': '1.0.2' },
157 'bar 1.0.0': {}, 159 'bar 1.0.0': {},
158 'bar 1.0.1': {}, 160 'bar 1.0.1': {},
159 'bar 1.0.2': {} 161 'bar 1.0.2': {}
160 }, lockfile: { 162 }, lockfile: {
161 'foo': '1.0.1' 163 'foo': '1.0.1'
162 }, result: { 164 }, result: {
163 'myapp': '0.0.0', 165 'myapp from root': '0.0.0',
164 'foo': '1.0.2', 166 'foo': '1.0.2',
165 'bar': '1.0.2' 167 'bar': '1.0.2'
166 }); 168 });
167 169
168 testResolve('with unrelated locked dependency', { 170 testResolve('with unrelated locked dependency', {
169 'myapp 0.0.0': { 171 'myapp 0.0.0': {
170 'foo': 'any' 172 'foo': 'any'
171 }, 173 },
172 'foo 1.0.0': { 'bar': '1.0.0' }, 174 'foo 1.0.0': { 'bar': '1.0.0' },
173 'foo 1.0.1': { 'bar': '1.0.1' }, 175 'foo 1.0.1': { 'bar': '1.0.1' },
174 'foo 1.0.2': { 'bar': '1.0.2' }, 176 'foo 1.0.2': { 'bar': '1.0.2' },
175 'bar 1.0.0': {}, 177 'bar 1.0.0': {},
176 'bar 1.0.1': {}, 178 'bar 1.0.1': {},
177 'bar 1.0.2': {}, 179 'bar 1.0.2': {},
178 'baz 1.0.0': {} 180 'baz 1.0.0': {}
179 }, lockfile: { 181 }, lockfile: {
180 'baz': '1.0.0' 182 'baz': '1.0.0'
181 }, result: { 183 }, result: {
182 'myapp': '0.0.0', 184 'myapp from root': '0.0.0',
183 'foo': '1.0.2', 185 'foo': '1.0.2',
184 'bar': '1.0.2' 186 'bar': '1.0.2'
185 }); 187 });
186 188
189 testResolve('circular dependency', {
190 'myapp 1.0.0': {
191 'foo': '1.0.0'
192 },
193 'foo 1.0.0': {
194 'bar': '1.0.0'
195 },
196 'bar 1.0.0': {
197 'foo': '1.0.0'
198 }
199 }, result: {
200 'myapp from root': '1.0.0',
201 'foo': '1.0.0',
202 'bar': '1.0.0'
203 });
204
187 testResolve('dependency back onto root package', { 205 testResolve('dependency back onto root package', {
188 'myapp 1.0.0': { 206 'myapp 1.0.0': {
189 'foo': '1.0.0' 207 'foo': '1.0.0'
190 }, 208 },
191 'foo 1.0.0': { 209 'foo 1.0.0': {
210 'myapp from root': '>=1.0.0'
211 }
212 }, result: {
213 'myapp from root': '1.0.0',
214 'foo': '1.0.0'
215 });
216
217 testResolve('dependency back onto root package with different source', {
218 'myapp 1.0.0': {
219 'foo': '1.0.0'
220 },
221 'foo 1.0.0': {
192 'myapp': '>=1.0.0' 222 'myapp': '>=1.0.0'
193 } 223 }
224 }, result: {
225 'myapp from root': '1.0.0',
226 'foo': '1.0.0'
227 });
228
229 testResolve('mismatched dependencies back onto root package', {
230 'myapp 1.0.0': {
231 'foo': '1.0.0',
232 'bar': '1.0.0'
233 },
234 'foo 1.0.0': {
235 'myapp': '>=1.0.0'
236 },
237 'bar 1.0.0': {
238 'myapp from mock2': '>=1.0.0'
239 }
194 }, error: sourceMismatch); 240 }, error: sourceMismatch);
195 241
242 testResolve('dependency back onto root package with wrong version', {
243 'myapp 1.0.0': {
244 'foo': '1.0.0'
245 },
246 'foo 1.0.0': {
247 'myapp': '<1.0.0'
248 }
249 }, error: disjointConstraint);
250
196 testResolve('no version that matches requirement', { 251 testResolve('no version that matches requirement', {
197 'myapp 0.0.0': { 252 'myapp 0.0.0': {
198 'foo': '>=1.0.0 <2.0.0' 253 'foo': '>=1.0.0 <2.0.0'
199 }, 254 },
200 'foo 2.0.0': {}, 255 'foo 2.0.0': {},
201 'foo 2.1.3': {} 256 'foo 2.1.3': {}
202 }, error: noVersion); 257 }, error: noVersion);
203 258
204 testResolve('no version that matches combined constraint', { 259 testResolve('no version that matches combined constraint', {
205 'myapp 0.0.0': { 260 'myapp 0.0.0': {
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 var parts = nameVersion.split(' '); 358 var parts = nameVersion.split(' ');
304 var name = parts[0]; 359 var name = parts[0];
305 var version = parts[1]; 360 var version = parts[1];
306 361
307 var package = source1.mockPackage(name, version, dependencies); 362 var package = source1.mockPackage(name, version, dependencies);
308 if (name == 'myapp') { 363 if (name == 'myapp') {
309 // Don't add the root package to the server, so we can verify that Pub 364 // Don't add the root package to the server, so we can verify that Pub
310 // doesn't try to look up information about the local package on the 365 // doesn't try to look up information about the local package on the
311 // remote server. 366 // remote server.
312 root = package; 367 root = package;
368 rootSource = new RootSource(root);
369 sources.register(rootSource);
313 } else { 370 } else {
314 source.addPackage(package); 371 source.addPackage(package);
315 } 372 }
316 }); 373 });
317 374
318 // Clean up the expectation. 375 // Clean up the expectation.
319 if (result != null) { 376 if (result != null) {
377 var newResult = {};
320 result.forEach((name, version) { 378 result.forEach((name, version) {
321 result[name] = new Version.parse(version); 379 var parsed = parseSource(name);
380 name = parsed.first;
381 var source = parsed.last;
382 version = new Version.parse(version);
383 newResult[name] = new PackageId(name, source, version, name);
322 }); 384 });
385 result = newResult;
323 } 386 }
324 387
325 var realLockFile = new LockFile.empty(); 388 var realLockFile = new LockFile.empty();
326 if (lockfile != null) { 389 if (lockfile != null) {
327 lockfile.forEach((name, version) { 390 lockfile.forEach((name, version) {
328 version = new Version.parse(version); 391 version = new Version.parse(version);
329 realLockFile.packages[name] = 392 realLockFile.packages[name] =
330 new PackageId(name, source1, version, name); 393 new PackageId(name, source1, version, name);
331 }); 394 });
332 } 395 }
333 396
334 // Resolve the versions. 397 // Resolve the versions.
335 var future = resolveVersions(sources, root, realLockFile); 398 var future = resolveVersions(sources, root, realLockFile);
336 399
337 if (result != null) { 400 if (result != null) {
338 expect(future, completion(predicate((actualResult) { 401 expect(future, completion(predicate((actualResult) {
339 for (var id in actualResult) { 402 for (var actualId in actualResult) {
340 if (!result.containsKey(id.description)) return false; 403 if (!result.containsKey(actualId.name)) return false;
341 if (id.version != result.remove(id.description)) return false; 404 var expectedId = result.remove(actualId.name);
405 if (actualId != expectedId) return false;
342 } 406 }
343 return result.isEmpty(); 407 return result.isEmpty();
344 }, description: 'packages to match $result'))); 408 }, description: 'packages to match $result')));
345 } else if (error == noVersion) { 409 } else if (error == noVersion) {
346 expect(future, throwsA(new isInstanceOf<NoVersionException>())); 410 expect(future, throwsA(new isInstanceOf<NoVersionException>()));
347 } else if (error == disjointConstraint) { 411 } else if (error == disjointConstraint) {
348 expect(future, throwsA(new isInstanceOf<DisjointConstraintException>())); 412 expect(future, throwsA(new isInstanceOf<DisjointConstraintException>()));
349 } else if (error == sourceMismatch) { 413 } else if (error == sourceMismatch) {
350 expect(future, throwsA(new isInstanceOf<SourceMismatchException>())); 414 expect(future, throwsA(new isInstanceOf<SourceMismatchException>()));
351 } else if (error == descriptionMismatch) { 415 } else if (error == descriptionMismatch) {
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 519
456 return completer.future; 520 return completer.future;
457 } 521 }
458 522
459 Pair<String, Source> parseSource(String name) { 523 Pair<String, Source> parseSource(String name) {
460 var match = new RegExp(@"(.*) from (.*)").firstMatch(name); 524 var match = new RegExp(@"(.*) from (.*)").firstMatch(name);
461 if (match == null) return new Pair<String, Source>(name, source1); 525 if (match == null) return new Pair<String, Source>(name, source1);
462 switch (match[2]) { 526 switch (match[2]) {
463 case 'mock1': return new Pair<String, Source>(match[1], source1); 527 case 'mock1': return new Pair<String, Source>(match[1], source1);
464 case 'mock2': return new Pair<String, Source>(match[1], source2); 528 case 'mock2': return new Pair<String, Source>(match[1], source2);
529 case 'root': return new Pair<String, Source>(match[1], rootSource);
465 case 'versionless': 530 case 'versionless':
466 return new Pair<String, Source>(match[1], versionlessSource); 531 return new Pair<String, Source>(match[1], versionlessSource);
467 } 532 }
468 } 533 }
OLDNEW
« utils/pub/version_solver.dart ('K') | « utils/pub/version_solver.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698