| 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: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 Loading... |
| 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 Loading... |
| 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 } |
| OLD | NEW |