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

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

Issue 10690032: Make VersionSolver source- and description-aware. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes Created 8 years, 5 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
« no previous file with comments | « utils/tests/pub/pubspec_test.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/package.dart'); 10 #import('../../pub/package.dart');
11 #import('../../pub/pubspec.dart'); 11 #import('../../pub/pubspec.dart');
12 #import('../../pub/source.dart'); 12 #import('../../pub/source.dart');
13 #import('../../pub/source_registry.dart'); 13 #import('../../pub/source_registry.dart');
14 #import('../../pub/utils.dart');
14 #import('../../pub/version.dart'); 15 #import('../../pub/version.dart');
15 #import('../../pub/version_solver.dart'); 16 #import('../../pub/version_solver.dart');
16 #import('../../../lib/unittest/unittest.dart'); 17 #import('../../../lib/unittest/unittest.dart');
17 18
18 final noVersion = 'no version'; 19 final noVersion = 'no version';
19 final disjointConstraint = 'disjoint'; 20 final disjointConstraint = 'disjoint';
21 final sourceMismatch = 'source mismatch';
22 final descriptionMismatch = 'description mismatch';
20 final couldNotSolve = 'unsolved'; 23 final couldNotSolve = 'unsolved';
21 24
25 Source source1;
26 Source source2;
27
22 main() { 28 main() {
23 testResolve('no dependencies', { 29 testResolve('no dependencies', {
24 'myapp 0.0.0': {} 30 'myapp 0.0.0': {}
25 }, result: { 31 }, result: {
26 'myapp': '0.0.0' 32 'myapp': '0.0.0'
27 }); 33 });
28 34
29 testResolve('simple dependency tree', { 35 testResolve('simple dependency tree', {
30 'myapp 0.0.0': { 36 'myapp 0.0.0': {
31 'a': '1.0.0', 37 'a': '1.0.0',
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 'bang': '1.0.0' 103 'bang': '1.0.0'
98 }); 104 });
99 105
100 testResolve('dependency back onto root package', { 106 testResolve('dependency back onto root package', {
101 'myapp 1.0.0': { 107 'myapp 1.0.0': {
102 'foo': '1.0.0' 108 'foo': '1.0.0'
103 }, 109 },
104 'foo 1.0.0': { 110 'foo 1.0.0': {
105 'myapp': '>=1.0.0' 111 'myapp': '>=1.0.0'
106 } 112 }
107 }, result: { 113 }, error: sourceMismatch);
108 'myapp': '1.0.0',
109 'foo': '1.0.0'
110 });
111
112 testResolve("dependency back onto root package that doesn't contain root's "
113 "version", {
114 'myapp 1.0.0': {
115 'foo': '1.0.0'
116 },
117 'foo 1.0.0': {
118 'myapp': '>=2.0.0'
119 }
120 }, error: disjointConstraint);
121 114
122 testResolve('no version that matches requirement', { 115 testResolve('no version that matches requirement', {
123 'myapp 0.0.0': { 116 'myapp 0.0.0': {
124 'foo': '>=1.0.0 <2.0.0' 117 'foo': '>=1.0.0 <2.0.0'
125 }, 118 },
126 'foo 2.0.0': {}, 119 'foo 2.0.0': {},
127 'foo 2.1.3': {} 120 'foo 2.1.3': {}
128 }, error: noVersion); 121 }, error: noVersion);
129 122
130 testResolve('no version that matches combined constraint', { 123 testResolve('no version that matches combined constraint', {
(...skipping 19 matching lines...) Expand all
150 'foo 1.0.0': { 143 'foo 1.0.0': {
151 'shared': '<=2.0.0' 144 'shared': '<=2.0.0'
152 }, 145 },
153 'bar 1.0.0': { 146 'bar 1.0.0': {
154 'shared': '>3.0.0' 147 'shared': '>3.0.0'
155 }, 148 },
156 'shared 2.0.0': {}, 149 'shared 2.0.0': {},
157 'shared 4.0.0': {} 150 'shared 4.0.0': {}
158 }, error: disjointConstraint); 151 }, error: disjointConstraint);
159 152
153 testResolve('mismatched descriptions', {
154 'myapp 0.0.0': {
155 'foo': '1.0.0',
156 'bar': '1.0.0'
157 },
158 'foo 1.0.0': {
159 'shared-x': '1.0.0'
160 },
161 'bar 1.0.0': {
162 'shared-y': '1.0.0'
163 },
164 'shared-x 1.0.0': {},
165 'shared-y 1.0.0': {}
166 }, error: descriptionMismatch);
167
168 testResolve('mismatched sources', {
169 'myapp 0.0.0': {
170 'foo': '1.0.0',
171 'bar': '1.0.0'
172 },
173 'foo 1.0.0': {
174 'shared': '1.0.0'
175 },
176 'bar 1.0.0': {
177 'shared from mock2': '1.0.0'
178 },
179 'shared 1.0.0': {},
180 'shared 1.0.0 from mock2': {}
181 }, error: sourceMismatch);
182
160 testResolve('unstable dependency graph', { 183 testResolve('unstable dependency graph', {
161 'myapp 0.0.0': { 184 'myapp 0.0.0': {
162 'a': '>=1.0.0' 185 'a': '>=1.0.0'
163 }, 186 },
164 'a 1.0.0': {}, 187 'a 1.0.0': {},
165 'a 2.0.0': { 188 'a 2.0.0': {
166 'b': '1.0.0' 189 'b': '1.0.0'
167 }, 190 },
168 'b 1.0.0': { 191 'b 1.0.0': {
169 'a': '1.0.0' 192 'a': '1.0.0'
170 } 193 }
171 }, error: couldNotSolve); 194 }, error: couldNotSolve);
172 195
173 // TODO(rnystrom): More stuff to test: 196 // TODO(rnystrom): More stuff to test:
174 // - Two packages depend on the same package, but from different sources. Should 197 // - Two packages depend on the same package, but from different sources. Should
175 // fail. 198 // fail.
176 // - Depending on a non-existent package. 199 // - Depending on a non-existent package.
177 // - Test that only a certain number requests are sent to the mock source so we 200 // - Test that only a certain number requests are sent to the mock source so we
178 // can keep track of server traffic. 201 // can keep track of server traffic.
179 } 202 }
180 203
181 testResolve(description, packages, [result, error]) { 204 testResolve(description, packages, [result, error]) {
182 test(description, () { 205 test(description, () {
183 var sources = new SourceRegistry(); 206 var sources = new SourceRegistry();
184 var source = new MockSource(); 207 source1 = new MockSource('mock1');
185 sources.register(source); 208 source2 = new MockSource('mock2');
186 sources.setDefault(source.name); 209 sources.register(source1);
210 sources.register(source2);
211 sources.setDefault(source1.name);
187 212
188 // Build the test package graph. 213 // Build the test package graph.
189 var root; 214 var root;
190 packages.forEach((nameVersion, dependencies) { 215 packages.forEach((nameVersion, dependencies) {
216 var parsed = parseSource(nameVersion);
217 nameVersion = parsed.first;
218 var source = parsed.last;
219
191 var parts = nameVersion.split(' '); 220 var parts = nameVersion.split(' ');
192 var name = parts[0]; 221 var name = parts[0];
193 var version = parts[1]; 222 var version = parts[1];
223
194 var package = source.mockPackage(name, version, dependencies); 224 var package = source.mockPackage(name, version, dependencies);
195 if (name == 'myapp') { 225 if (name == 'myapp') {
196 // Don't add the root package to the server, so we can verify that Pub 226 // Don't add the root package to the server, so we can verify that Pub
197 // doesn't try to look up information about the local package on the 227 // doesn't try to look up information about the local package on the
198 // remote server. 228 // remote server.
199 root = package; 229 root = package;
200 } else { 230 } else {
201 source.addPackage(package); 231 source.addPackage(package);
202 } 232 }
203 }); 233 });
204 234
205 // Clean up the expectation. 235 // Clean up the expectation.
206 if (result != null) { 236 if (result != null) {
207 result.forEach((name, version) { 237 result.forEach((name, version) {
208 result[name] = new Version.parse(version); 238 result[name] = new Version.parse(version);
209 }); 239 });
210 } 240 }
211 241
212 // Resolve the versions. 242 // Resolve the versions.
213 var future = resolveVersions(sources, root); 243 var future = resolveVersions(sources, root);
214 244
215 if (result != null) { 245 if (result != null) {
216 expect(future, completion(equals(result))); 246 expect(future, completion(equals(result)));
217 } else if (error == noVersion) { 247 } else if (error == noVersion) {
218 expect(future, throwsA(new isInstanceOf<NoVersionException>())); 248 expect(future, throwsA(new isInstanceOf<NoVersionException>()));
219 } else if (error == disjointConstraint) { 249 } else if (error == disjointConstraint) {
220 expect(future, throwsA(new isInstanceOf<DisjointConstraintException>())); 250 expect(future, throwsA(new isInstanceOf<DisjointConstraintException>()));
251 } else if (error == sourceMismatch) {
252 expect(future, throwsA(new isInstanceOf<SourceMismatchException>()));
253 } else if (error == descriptionMismatch) {
254 expect(future, throwsA(new isInstanceOf<DescriptionMismatchException>()));
221 } else if (error == couldNotSolve) { 255 } else if (error == couldNotSolve) {
222 expect(future, throwsA(new isInstanceOf<CouldNotSolveException>())); 256 expect(future, throwsA(new isInstanceOf<CouldNotSolveException>()));
223 } else { 257 } else {
224 expect(future, throwsA(error)); 258 expect(future, throwsA(error));
225 } 259 }
226 260
227 // If we aren't expecting an error, print some debugging info if we get one. 261 // If we aren't expecting an error, print some debugging info if we get one.
228 if (error == null) { 262 if (error == null) {
229 future.handleException((ex) { 263 future.handleException((ex) {
230 print(ex); 264 print(ex);
231 print(future.stackTrace); 265 print(future.stackTrace);
232 return true; 266 return true;
233 }); 267 });
234 } 268 }
235 }); 269 });
236 } 270 }
237 271
272 /**
273 * A source used for testing. This both creates mock package objects and acts as
274 * a source for them.
275 *
276 * In order to support testing packages that have the same name but different
277 * descriptions, a package's name is calculated by taking the description string
278 * and stripping off any trailing hyphen followed by non-hyphen characters.
279 */
238 class MockSource extends Source { 280 class MockSource extends Source {
239 final Map<String, Map<Version, Package>> _packages; 281 final Map<String, Map<Version, Package>> _packages;
240 282
241 String get name() => 'mock'; 283 final String name;
242 bool get shouldCache() => true; 284 bool get shouldCache() => true;
243 285
244 MockSource() 286 MockSource(this.name)
245 : _packages = <Map<Version, Package>>{}; 287 : _packages = <Map<Version, Package>>{};
246 288
247 Future<List<Version>> getVersions(String name) { 289 Future<List<Version>> getVersions(String name) {
248 return fakeAsync(() => _packages[name].getKeys()); 290 return fakeAsync(() => _packages[name].getKeys());
249 } 291 }
250 292
251 Future<Pubspec> describe(String package, Version version) { 293 Future<Pubspec> describe(PackageId id) {
252 return fakeAsync(() { 294 return fakeAsync(() {
253 return _packages[package][version].pubspec; 295 return _packages[id.name][id.version].pubspec;
254 }); 296 });
255 } 297 }
256 298
257 Future<bool> install(PackageId id, String path) { 299 Future<bool> install(PackageId id, String path) {
258 throw 'no'; 300 throw 'no';
259 } 301 }
260 302
261 Package mockPackage(String name, String version, Map dependencyStrings) { 303 Package mockPackage(String description, String version,
304 Map dependencyStrings) {
262 // Build the pubspec dependencies. 305 // Build the pubspec dependencies.
263 var dependencies = <PackageRef>[]; 306 var dependencies = <PackageRef>[];
264 dependencyStrings.forEach((name, constraint) { 307 dependencyStrings.forEach((name, constraint) {
265 dependencies.add(new PackageRef(name, this, 308 var parsed = parseSource(name);
266 new VersionConstraint.parse(constraint), name)); 309 dependencies.add(new PackageRef(
310 parsed.last, new VersionConstraint.parse(constraint), parsed.first));
267 }); 311 });
268 312
269 var pubspec = new Pubspec(new Version.parse(version), dependencies); 313 var pubspec = new Pubspec(new Version.parse(version), dependencies);
270 return new Package.inMemory(name, pubspec); 314 return new Package.inMemory(description, pubspec);
271 } 315 }
272 316
273 void addPackage(Package package) { 317 void addPackage(Package package) {
274 _packages.putIfAbsent(package.name, () => new Map<Version, Package>()); 318 _packages.putIfAbsent(package.name, () => new Map<Version, Package>());
275 _packages[package.name][package.version] = package; 319 _packages[package.name][package.version] = package;
276 return package; 320 return package;
277 } 321 }
322
323 String packageName(String description) =>
324 description.replaceFirst(new RegExp(@"-[^-]+$"), "");
278 } 325 }
279 326
280 Future fakeAsync(callback()) { 327 Future fakeAsync(callback()) {
281 var completer = new Completer(); 328 var completer = new Completer();
282 new Timer(0, (_) { 329 new Timer(0, (_) {
283 completer.complete(callback()); 330 completer.complete(callback());
284 }); 331 });
285 332
286 return completer.future; 333 return completer.future;
287 } 334 }
335
336 Pair<String, Source> parseSource(String name) {
337 var match = new RegExp(@"(.*) from (.*)").firstMatch(name);
338 if (match == null) return new Pair<String, Source>(name, source1);
339 switch (match[2]) {
340 case 'mock1': return new Pair<String, Source>(match[1], source1);
341 case 'mock2': return new Pair<String, Source>(match[1], source2);
342 }
343 }
OLDNEW
« no previous file with comments | « utils/tests/pub/pubspec_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698