Elaborate on test configuration, add a new test
authorAidan Hobson Sayers <aidanhs@cantab.net>
Sat, 3 Feb 2018 21:49:42 +0000 (21:49 +0000)
committerAidan Hobson Sayers <aidanhs@cantab.net>
Sat, 3 Feb 2018 23:19:21 +0000 (23:19 +0000)
tests/resolve.rs

index 411c39300689438211ff2141c27ad813dbc5d437..6e43528fa3f680b91d3efc5e6540d9aa67b66d17 100644 (file)
@@ -375,8 +375,10 @@ fn resolving_with_deep_backtracking() {
 fn resolving_with_constrained_sibling_backtrack_parent() {
     // There is no point in considering all of the backtrack_trap{1,2}
     // candidates since they can't change the result of failing to
-    // resolve 'constrained'. Cargo should skip past them and resume
+    // resolve 'constrained'. Cargo should (ideally) skip past them and resume
     // resolution once the activation of the parent, 'bar', is rolled back.
+    // Note that the traps are slightly more constrained to make sure they
+    // get picked first.
     let mut reglist = vec![
         pkg!(("foo", "1.0.0") => [dep_req("bar", "1.0"),
                                   dep_req("constrained", "=1.0.0")]),
@@ -388,7 +390,10 @@ fn resolving_with_constrained_sibling_backtrack_parent() {
         pkg!(("backtrack_trap1", "1.0.0")),
         pkg!(("backtrack_trap2", "1.0.0")),
     ];
-    for i in 1..50 {
+    // Bump this to make the test harder - it adds more versions of bar that will
+    // fail to resolve, and more versions of the traps to consider.
+    const NUM_BARS_AND_TRAPS: usize = 50; // minimum 2
+    for i in 1..NUM_BARS_AND_TRAPS {
         let vsn = format!("1.0.{}", i);
         reglist.push(pkg!(("bar", vsn.clone()) => [dep_req("backtrack_trap1", "1.0.2"),
                                                    dep_req("backtrack_trap2", "1.0.2"),
@@ -423,12 +428,19 @@ fn resolving_with_constrained_sibling_backtrack_activation() {
                                   dep_req("constrained", "<=1.0.60")]),
         pkg!(("bar", "1.0.0") => [dep_req("constrained", ">=1.0.60")]),
     ];
-    for i in 0..45 {
+    // Bump these to make the test harder, but you'll also need to
+    // change the version constraints on `constrained` above. To correctly
+    // exercise Cargo, the relationship between the values is:
+    // NUM_CONSTRAINED - vsn < NUM_TRAPS < vsn
+    // to make sure the traps are resolved between `constrained`.
+    const NUM_TRAPS: usize = 45; // min 1
+    const NUM_CONSTRAINED: usize = 100; // min 1
+    for i in 0..NUM_TRAPS {
         let vsn = format!("1.0.{}", i);
         reglist.push(pkg!(("backtrack_trap1", vsn.clone())));
         reglist.push(pkg!(("backtrack_trap2", vsn.clone())));
     }
-    for i in 0..100 {
+    for i in 0..NUM_CONSTRAINED {
         let vsn = format!("1.0.{}", i);
         reglist.push(pkg!(("constrained", vsn.clone())));
     }
@@ -444,6 +456,52 @@ fn resolving_with_constrained_sibling_backtrack_activation() {
                                        ("constrained", "1.0.60")])));
 }
 
+#[test]
+fn resolving_with_constrained_sibling_transitive_dep_effects() {
+    // When backtracking due to a failed dependency, if Cargo is
+    // trying to be clever and skip irrelevant dependencies, care must
+    // be taken to not miss the transitive effects of alternatives. E.g.
+    // in the right-to-left resolution of the graph below, B may
+    // affect whether D is successfully resolved.
+    //
+    //    A
+    //  / | \
+    // B  C  D
+    // |  |
+    // C  D
+    let reg = registry(vec![
+        pkg!(("A", "1.0.0") => [dep_req("B", "1.0"),
+                                dep_req("C", "1.0"),
+                                dep_req("D", "1.0.100")]),
+
+        pkg!(("B", "1.0.0") => [dep_req("C", ">=1.0.0")]),
+        pkg!(("B", "1.0.1") => [dep_req("C", ">=1.0.1")]),
+
+        pkg!(("C", "1.0.0") => [dep_req("D", "1.0.0")]),
+        pkg!(("C", "1.0.1") => [dep_req("D", ">=1.0.1,<1.0.100")]),
+        pkg!(("C", "1.0.2") => [dep_req("D", ">=1.0.2,<1.0.100")]),
+
+        pkg!(("D", "1.0.0")),
+        pkg!(("D", "1.0.1")),
+        pkg!(("D", "1.0.2")),
+        pkg!(("D", "1.0.100")),
+        pkg!(("D", "1.0.101")),
+        pkg!(("D", "1.0.102")),
+        pkg!(("D", "1.0.103")),
+        pkg!(("D", "1.0.104")),
+        pkg!(("D", "1.0.105")),
+    ]);
+
+    let res = resolve(&pkg_id("root"), vec![
+        dep_req("A", "1"),
+    ], &reg).unwrap();
+
+    assert_that(&res, contains(names(&[("A", "1.0.0"),
+                                       ("B", "1.0.0"),
+                                       ("C", "1.0.0"),
+                                       ("D", "1.0.105")])));
+}
+
 #[test]
 fn resolving_but_no_exists() {
     let reg = registry(vec![