1require 'rubygems/test_case' 2require 'rubygems/dependency_resolver' 3 4class TestGemDependencyResolver < Gem::TestCase 5 6 def make_dep(name, *req) 7 Gem::Dependency.new(name, *req) 8 end 9 10 def set(*specs) 11 StaticSet.new(specs) 12 end 13 14 def assert_set(expected, actual) 15 exp = expected.sort_by { |s| s.full_name } 16 act = actual.map { |a| a.spec }.sort_by { |s| s.full_name } 17 18 assert_equal exp, act 19 end 20 21 def test_no_overlap_specificly 22 a = util_spec "a", '1' 23 b = util_spec "b", "1" 24 25 ad = make_dep "a", "= 1" 26 bd = make_dep "b", "= 1" 27 28 deps = [ad, bd] 29 30 s = set(a, b) 31 32 res = Gem::DependencyResolver.new(deps, s) 33 34 assert_set [a, b], res.resolve 35 end 36 37 def test_pulls_in_dependencies 38 a = util_spec "a", '1' 39 b = util_spec "b", "1", "c" => "= 1" 40 c = util_spec "c", "1" 41 42 ad = make_dep "a", "= 1" 43 bd = make_dep "b", "= 1" 44 45 deps = [ad, bd] 46 47 s = set(a, b, c) 48 49 res = Gem::DependencyResolver.new(deps, s) 50 51 assert_set [a, b, c], res.resolve 52 end 53 54 def test_picks_highest_version 55 a1 = util_spec "a", '1' 56 a2 = util_spec "a", '2' 57 58 s = set(a1, a2) 59 60 ad = make_dep "a" 61 62 res = Gem::DependencyResolver.new([ad], s) 63 64 assert_set [a2], res.resolve 65 end 66 67 def test_only_returns_spec_once 68 a1 = util_spec "a", "1", "c" => "= 1" 69 b1 = util_spec "b", "1", "c" => "= 1" 70 71 c1 = util_spec "c", "1" 72 73 ad = make_dep "a" 74 bd = make_dep "b" 75 76 s = set(a1, b1, c1) 77 78 res = Gem::DependencyResolver.new([ad, bd], s) 79 80 assert_set [a1, b1, c1], res.resolve 81 end 82 83 def test_picks_lower_version_when_needed 84 a1 = util_spec "a", "1", "c" => ">= 1" 85 b1 = util_spec "b", "1", "c" => "= 1" 86 87 c1 = util_spec "c", "1" 88 c2 = util_spec "c", "2" 89 90 ad = make_dep "a" 91 bd = make_dep "b" 92 93 s = set(a1, b1, c1, c2) 94 95 res = Gem::DependencyResolver.new([ad, bd], s) 96 97 assert_set [a1, b1, c1], res.resolve 98 99 cons = res.conflicts 100 101 assert_equal 1, cons.size 102 con = cons.first 103 104 assert_equal "c (= 1)", con.dependency.to_s 105 assert_equal "c-2", con.activated.full_name 106 end 107 108 def test_conflict_resolution_only_effects_correct_spec 109 a1 = util_spec "a", "1", "c" => ">= 1" 110 b1 = util_spec "b", "1", "d" => ">= 1" 111 112 d3 = util_spec "d", "3", "c" => "= 1" 113 d4 = util_spec "d", "4", "c" => "= 1" 114 115 c1 = util_spec "c", "1" 116 c2 = util_spec "c", "2" 117 118 ad = make_dep "a" 119 bd = make_dep "b" 120 121 s = set(a1, b1, d3, d4, c1, c2) 122 123 res = Gem::DependencyResolver.new([ad, bd], s) 124 125 assert_set [a1, b1, c1, d4], res.resolve 126 127 cons = res.conflicts 128 129 assert_equal 1, cons.size 130 con = cons.first 131 132 assert_equal "c (= 1)", con.dependency.to_s 133 assert_equal "c-2", con.activated.full_name 134 end 135 136 def test_raises_dependency_error 137 a1 = util_spec "a", "1", "c" => "= 1" 138 b1 = util_spec "b", "1", "c" => "= 2" 139 140 c1 = util_spec "c", "1" 141 c2 = util_spec "c", "2" 142 143 ad = make_dep "a" 144 bd = make_dep "b" 145 146 s = set(a1, b1, c1, c2) 147 148 r = Gem::DependencyResolver.new([ad, bd], s) 149 150 e = assert_raises Gem::DependencyResolutionError do 151 r.resolve 152 end 153 154 assert_equal "unable to resolve conflicting dependencies 'c (= 2)' and 'c (= 1)'", e.message 155 156 deps = [make_dep("c", "= 2"), make_dep("c", "= 1")] 157 assert_equal deps, e.conflicting_dependencies 158 159 con = e.conflict 160 161 act = con.activated 162 assert_equal "c-1", act.spec.full_name 163 164 parent = act.parent 165 assert_equal "a-1", parent.spec.full_name 166 167 act = con.requester 168 assert_equal "b-1", act.spec.full_name 169 end 170 171 def test_raises_when_a_gem_is_missing 172 ad = make_dep "a" 173 174 r = Gem::DependencyResolver.new([ad], set) 175 176 e = assert_raises Gem::UnsatisfiableDepedencyError do 177 r.resolve 178 end 179 180 assert_equal "unable to find any gem matching dependency 'a (>= 0)'", e.message 181 182 assert_equal "a (>= 0)", e.dependency.to_s 183 end 184 185 def test_raises_when_a_gem_version_is_missing 186 a1 = util_spec "a", "1" 187 188 ad = make_dep "a", "= 3" 189 190 r = Gem::DependencyResolver.new([ad], set(a1)) 191 192 e = assert_raises Gem::UnsatisfiableDepedencyError do 193 r.resolve 194 end 195 196 assert_equal "a (= 3)", e.dependency.to_s 197 end 198 199 def test_raises_when_possibles_are_exhausted 200 a1 = util_spec "a", "1", "c" => ">= 2" 201 b1 = util_spec "b", "1", "c" => "= 1" 202 203 c1 = util_spec "c", "1" 204 c2 = util_spec "c", "2" 205 c3 = util_spec "c", "3" 206 207 s = set(a1, b1, c1, c2, c3) 208 209 ad = make_dep "a" 210 bd = make_dep "b" 211 212 r = Gem::DependencyResolver.new([ad, bd], s) 213 214 e = assert_raises Gem::ImpossibleDependenciesError do 215 r.resolve 216 end 217 218 assert_equal "detected 1 conflict with dependency 'c (>= 2)'", e.message 219 220 assert_equal "c (>= 2)", e.dependency.to_s 221 222 s, con = e.conflicts[0] 223 assert_equal "c-3", s.full_name 224 assert_equal "c (= 1)", con.dependency.to_s 225 assert_equal "b-1", con.requester.full_name 226 end 227 228 def test_keeps_resolving_after_seeing_satisfied_dep 229 a1 = util_spec "a", "1", "b" => "= 1", "c" => "= 1" 230 b1 = util_spec "b", "1" 231 c1 = util_spec "c", "1" 232 233 ad = make_dep "a" 234 bd = make_dep "b" 235 236 s = set(a1, b1, c1) 237 238 r = Gem::DependencyResolver.new([ad, bd], s) 239 240 assert_set [a1, b1, c1], r.resolve 241 end 242 243 def test_common_rack_activation_scenario 244 rack100 = util_spec "rack", "1.0.0" 245 rack101 = util_spec "rack", "1.0.1" 246 247 lib1 = util_spec "lib", "1", "rack" => ">= 1.0.1" 248 249 rails = util_spec "rails", "3", "actionpack" => "= 3" 250 ap = util_spec "actionpack", "3", "rack" => ">= 1.0.0" 251 252 d1 = make_dep "rails" 253 d2 = make_dep "lib" 254 255 s = set(lib1, rails, ap, rack100, rack101) 256 257 r = Gem::DependencyResolver.new([d1, d2], s) 258 259 assert_set [rails, ap, rack101, lib1], r.resolve 260 261 # check it with the deps reverse too 262 263 r = Gem::DependencyResolver.new([d2, d1], s) 264 265 assert_set [lib1, rack101, rails, ap], r.resolve 266 end 267 268 def test_backtracks_to_the_first_conflict 269 a1 = util_spec "a", "1" 270 a2 = util_spec "a", "2" 271 a3 = util_spec "a", "3" 272 a4 = util_spec "a", "4" 273 274 d1 = make_dep "a" 275 d2 = make_dep "a", ">= 2" 276 d3 = make_dep "a", "= 1" 277 278 s = set(a1, a2, a3, a4) 279 280 r = Gem::DependencyResolver.new([d1, d2, d3], s) 281 282 assert_raises Gem::ImpossibleDependenciesError do 283 r.resolve 284 end 285 end 286 287 # actionmailer 2.3.4 288 # activemerchant 1.5.0 289 # activesupport 2.3.5, 2.3.4 290 # Activemerchant needs activesupport >= 2.3.2. When you require activemerchant, it will activate the latest version that meets that requirement which is 2.3.5. Actionmailer on the other hand needs activesupport = 2.3.4. When rubygems tries to activate activesupport 2.3.4, it will raise an error. 291 292 293 def test_simple_activesupport_problem 294 sup1 = util_spec "activesupport", "2.3.4" 295 sup2 = util_spec "activesupport", "2.3.5" 296 297 merch = util_spec "activemerchant", "1.5.0", "activesupport" => ">= 2.3.2" 298 mail = util_spec "actionmailer", "2.3.4", "activesupport" => "= 2.3.4" 299 300 s = set(mail, merch, sup1, sup2) 301 302 d1 = make_dep "activemerchant" 303 d2 = make_dep "actionmailer" 304 305 r = Gem::DependencyResolver.new([d1, d2], s) 306 307 assert_set [merch, mail, sup1], r.resolve 308 end 309 310 def test_second_level_backout 311 b1 = new_spec "b", "1", { "c" => ">= 1" }, "lib/b.rb" 312 b2 = new_spec "b", "2", { "c" => ">= 2" }, "lib/b.rb" 313 c1 = new_spec "c", "1" 314 c2 = new_spec "c", "2" 315 d1 = new_spec "d", "1", { "c" => "< 2" }, "lib/d.rb" 316 d2 = new_spec "d", "2", { "c" => "< 2" }, "lib/d.rb" 317 318 s = set(b1, b2, c1, c2, d1, d2) 319 320 p1 = make_dep "b", "> 0" 321 p2 = make_dep "d", "> 0" 322 323 r = Gem::DependencyResolver.new([p1, p2], s) 324 325 assert_set [b1, c1, d2], r.resolve 326 end 327end 328