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'; |
11 | 11 |
12 import '../../pub/lock_file.dart'; | 12 import '../../pub/lock_file.dart'; |
13 import '../../pub/package.dart'; | 13 import '../../pub/package.dart'; |
14 import '../../pub/pubspec.dart'; | 14 import '../../pub/pubspec.dart'; |
| 15 import '../../pub/sdk.dart' as sdk; |
15 import '../../pub/source.dart'; | 16 import '../../pub/source.dart'; |
16 import '../../pub/source_registry.dart'; | 17 import '../../pub/source_registry.dart'; |
17 import '../../pub/system_cache.dart'; | 18 import '../../pub/system_cache.dart'; |
18 import '../../pub/utils.dart'; | 19 import '../../pub/utils.dart'; |
19 import '../../pub/version.dart'; | 20 import '../../pub/version.dart'; |
20 import '../../pub/solver/version_solver.dart'; | 21 import '../../pub/solver/version_solver.dart'; |
21 import 'test_pub.dart'; | 22 import 'test_pub.dart'; |
22 | 23 |
23 MockSource source1; | 24 MockSource source1; |
24 MockSource source2; | 25 MockSource source2; |
25 | 26 |
26 bool allowBacktracking; | 27 bool allowBacktracking; |
27 | 28 |
28 main() { | 29 main() { |
29 initConfig(); | 30 initConfig(); |
30 | 31 |
| 32 // Since this test isn't run from the SDK, it can't find the "version" file |
| 33 // to load. Instead, just manually inject a version. |
| 34 sdk.version = new Version(1, 2, 3); |
| 35 |
31 for (allowBacktracking in [false, true]) { | 36 for (allowBacktracking in [false, true]) { |
32 group(allowBacktracking ? 'BackTrackingSolver' : 'GreedySolver', () { | 37 group(allowBacktracking ? 'BackTrackingSolver' : 'GreedySolver', () { |
33 group('basic graph', basicGraph); | 38 group('basic graph', basicGraph); |
34 group('with lockfile', withLockFile); | 39 group('with lockfile', withLockFile); |
35 group('root dependency', rootDependency); | 40 group('root dependency', rootDependency); |
36 group('dev dependency', devDependency); | 41 group('dev dependency', devDependency); |
37 group('unsolvable', unsolvable); | 42 group('unsolvable', unsolvable); |
38 group('backtracking', backtracking); | 43 group('backtracking', backtracking); |
39 }); | 44 }); |
40 } | 45 } |
| 46 |
| 47 // These tests are only valid with the backtracking solver. |
| 48 allowBacktracking = true; |
| 49 group('SDK constraint', sdkConstraint); |
41 } | 50 } |
42 | 51 |
43 void basicGraph() { | 52 void basicGraph() { |
44 testResolve('no dependencies', { | 53 testResolve('no dependencies', { |
45 'myapp 0.0.0': {} | 54 'myapp 0.0.0': {} |
46 }, result: { | 55 }, result: { |
47 'myapp from root': '0.0.0' | 56 'myapp from root': '0.0.0' |
48 }); | 57 }); |
49 | 58 |
50 testResolve('simple dependency tree', { | 59 testResolve('simple dependency tree', { |
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 'baz': '0.0.0' | 548 'baz': '0.0.0' |
540 }, maxTries: 100); | 549 }, maxTries: 100); |
541 | 550 |
542 // TODO(rnystrom): More tests. In particular: | 551 // TODO(rnystrom): More tests. In particular: |
543 // - Tests that demonstrate backtracking for every case that can cause a | 552 // - Tests that demonstrate backtracking for every case that can cause a |
544 // solution to fail (no versions, disjoint, etc.) | 553 // solution to fail (no versions, disjoint, etc.) |
545 // - Tests where there are multiple valid solutions and "best" is possibly | 554 // - Tests where there are multiple valid solutions and "best" is possibly |
546 // ambiguous to nail down which order the backtracker tries solutions. | 555 // ambiguous to nail down which order the backtracker tries solutions. |
547 } | 556 } |
548 | 557 |
| 558 sdkConstraint() { |
| 559 var badVersion = '0.0.0-nope'; |
| 560 var goodVersion = sdk.version.toString(); |
| 561 |
| 562 testResolve('root matches SDK', { |
| 563 'myapp 0.0.0': {'sdk': goodVersion } |
| 564 }, result: { |
| 565 'myapp from root': '0.0.0' |
| 566 }); |
| 567 |
| 568 testResolve('root does not match SDK', { |
| 569 'myapp 0.0.0': {'sdk': badVersion } |
| 570 }, error: couldNotSolve); |
| 571 |
| 572 testResolve('dependency does not match SDK', { |
| 573 'myapp 0.0.0': {'foo': 'any'}, |
| 574 'foo 0.0.0': {'sdk': badVersion } |
| 575 }, error: couldNotSolve); |
| 576 |
| 577 testResolve('transitive dependency does not match SDK', { |
| 578 'myapp 0.0.0': {'foo': 'any'}, |
| 579 'foo 0.0.0': {'bar': 'any'}, |
| 580 'bar 0.0.0': {'sdk': badVersion } |
| 581 }, error: couldNotSolve); |
| 582 |
| 583 testResolve('selects a dependency version that allows the SDK', { |
| 584 'myapp 0.0.0': {'foo': 'any'}, |
| 585 'foo 1.0.0': {'sdk': goodVersion }, |
| 586 'foo 2.0.0': {'sdk': goodVersion }, |
| 587 'foo 3.0.0': {'sdk': badVersion }, |
| 588 'foo 4.0.0': {'sdk': badVersion } |
| 589 }, result: { |
| 590 'myapp from root': '0.0.0', |
| 591 'foo': '2.0.0' |
| 592 }, maxTries: 3); |
| 593 |
| 594 testResolve('selects a transitive dependency version that allows the SDK', { |
| 595 'myapp 0.0.0': {'foo': 'any'}, |
| 596 'foo 1.0.0': {'bar': 'any'}, |
| 597 'bar 1.0.0': {'sdk': goodVersion }, |
| 598 'bar 2.0.0': {'sdk': goodVersion }, |
| 599 'bar 3.0.0': {'sdk': badVersion }, |
| 600 'bar 4.0.0': {'sdk': badVersion } |
| 601 }, result: { |
| 602 'myapp from root': '0.0.0', |
| 603 'foo': '1.0.0', |
| 604 'bar': '2.0.0' |
| 605 }, maxTries: 3); |
| 606 |
| 607 testResolve('selects a dependency version that allows a transitive ' |
| 608 'dependency that allows the SDK', { |
| 609 'myapp 0.0.0': {'foo': 'any'}, |
| 610 'foo 1.0.0': {'bar': '1.0.0'}, |
| 611 'foo 2.0.0': {'bar': '2.0.0'}, |
| 612 'foo 3.0.0': {'bar': '3.0.0'}, |
| 613 'foo 4.0.0': {'bar': '4.0.0'}, |
| 614 'bar 1.0.0': {'sdk': goodVersion }, |
| 615 'bar 2.0.0': {'sdk': goodVersion }, |
| 616 'bar 3.0.0': {'sdk': badVersion }, |
| 617 'bar 4.0.0': {'sdk': badVersion } |
| 618 }, result: { |
| 619 'myapp from root': '0.0.0', |
| 620 'foo': '2.0.0', |
| 621 'bar': '2.0.0' |
| 622 }, maxTries: 3); |
| 623 } |
| 624 |
549 testResolve(description, packages, | 625 testResolve(description, packages, |
550 {lockfile, result, FailMatcherBuilder error, int maxTries, | 626 {lockfile, result, FailMatcherBuilder error, int maxTries, |
551 bool hasGreedySolution}) { | 627 bool hasGreedySolution}) { |
552 // Close over the top-level variable since it will be mutated. | 628 // Close over the top-level variable since it will be mutated. |
553 var allowBacktracking_ = allowBacktracking; | 629 var allowBacktracking_ = allowBacktracking; |
554 | 630 |
555 if (maxTries == null) maxTries = 1; | 631 if (maxTries == null) maxTries = 1; |
556 if (hasGreedySolution == null) hasGreedySolution = maxTries == 1; | 632 if (hasGreedySolution == null) hasGreedySolution = maxTries == 1; |
557 | 633 |
558 if (!allowBacktracking_) { | 634 if (!allowBacktracking_) { |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
851 } | 927 } |
852 | 928 |
853 void addPackage(String description, Package package) { | 929 void addPackage(String description, Package package) { |
854 _packages.putIfAbsent(description, () => new Map<Version, Package>()); | 930 _packages.putIfAbsent(description, () => new Map<Version, Package>()); |
855 _packages[description][package.version] = package; | 931 _packages[description][package.version] = package; |
856 } | 932 } |
857 } | 933 } |
858 | 934 |
859 Package mockPackage(String description, String version, | 935 Package mockPackage(String description, String version, |
860 Map dependencyStrings) { | 936 Map dependencyStrings) { |
| 937 var sdkConstraint = null; |
| 938 |
861 // Build the pubspec dependencies. | 939 // Build the pubspec dependencies. |
862 var dependencies = <PackageRef>[]; | 940 var dependencies = <PackageRef>[]; |
863 var devDependencies = <PackageRef>[]; | 941 var devDependencies = <PackageRef>[]; |
864 | 942 |
865 dependencyStrings.forEach((name, constraint) { | 943 dependencyStrings.forEach((name, constraint) { |
866 parseSource(name, (isDev, name, source) { | 944 parseSource(name, (isDev, name, source) { |
867 var packageName = name.replaceFirst(new RegExp(r"-[^-]+$"), ""); | 945 var packageName = name.replaceFirst(new RegExp(r"-[^-]+$"), ""); |
868 var ref = new PackageRef(packageName, source, | 946 constraint = new VersionConstraint.parse(constraint); |
869 new VersionConstraint.parse(constraint), name); | 947 |
| 948 if (name == 'sdk') { |
| 949 sdkConstraint = constraint; |
| 950 return; |
| 951 } |
| 952 |
| 953 var ref = new PackageRef(packageName, source, constraint, name); |
870 | 954 |
871 if (isDev) { | 955 if (isDev) { |
872 devDependencies.add(ref); | 956 devDependencies.add(ref); |
873 } else { | 957 } else { |
874 dependencies.add(ref); | 958 dependencies.add(ref); |
875 } | 959 } |
876 }); | 960 }); |
877 }); | 961 }); |
878 | 962 |
879 var name = description.replaceFirst(new RegExp(r"-[^-]+$"), ""); | 963 var name = description.replaceFirst(new RegExp(r"-[^-]+$"), ""); |
880 var pubspec = new Pubspec( | 964 var pubspec = new Pubspec( |
881 name, new Version.parse(version), dependencies, devDependencies, | 965 name, new Version.parse(version), dependencies, devDependencies, |
882 new PubspecEnvironment()); | 966 new PubspecEnvironment(sdkConstraint)); |
883 return new Package.inMemory(pubspec); | 967 return new Package.inMemory(pubspec); |
884 } | 968 } |
885 | 969 |
886 void parseSource(String description, | 970 void parseSource(String description, |
887 callback(bool isDev, String name, Source source)) { | 971 callback(bool isDev, String name, Source source)) { |
888 var isDev = false; | 972 var isDev = false; |
889 | 973 |
890 if (description.startsWith("(dev) ")) { | 974 if (description.startsWith("(dev) ")) { |
891 description = description.substring("(dev) ".length); | 975 description = description.substring("(dev) ".length); |
892 isDev = true; | 976 isDev = true; |
893 } | 977 } |
894 | 978 |
895 var name = description; | 979 var name = description; |
896 var source = source1; | 980 var source = source1; |
897 | 981 |
898 var sourceNames = { | 982 var sourceNames = { |
899 'mock1': source1, | 983 'mock1': source1, |
900 'mock2': source2, | 984 'mock2': source2, |
901 'root': null | 985 'root': null |
902 }; | 986 }; |
903 | 987 |
904 var match = new RegExp(r"(.*) from (.*)").firstMatch(description); | 988 var match = new RegExp(r"(.*) from (.*)").firstMatch(description); |
905 if (match != null) { | 989 if (match != null) { |
906 name = match[1]; | 990 name = match[1]; |
907 source = sourceNames[match[2]]; | 991 source = sourceNames[match[2]]; |
908 } | 992 } |
909 | 993 |
910 callback(isDev, name, source); | 994 callback(isDev, name, source); |
911 } | 995 } |
OLD | NEW |