@@ -140,6 +140,34 @@ def test_resolve_conservative
140140 assert_resolves_to [ a2_spec , b2_spec , c1_spec , d2_spec , e1_spec ] , res
141141 end
142142
143+ def test_conservative_upgrades_when_installed_blocked
144+ # Conservative mode floats the installed (skip) version to the front but
145+ # keeps newer versions selectable. When the installed version cannot be
146+ # used because its own dependency is unsatisfiable, the solver backtracks
147+ # to a newer version instead of failing. This intentionally diverges from
148+ # Molinillo (which hard-restricted to skip versions and raised) and reaches
149+ # Bundler's upgrade-over-raise outcome. See the comment in
150+ # Gem::Resolver#all_versions_for.
151+ a1_spec = util_spec "a" , 1 do |s |
152+ s . add_dependency "b" , ">= 2"
153+ end
154+ a2_spec = util_spec "a" , 2 do |s |
155+ s . add_dependency "b" , ">= 1"
156+ end
157+ b1_spec = util_spec "b" , 1
158+
159+ # b-2 is intentionally absent, so a-1's `b >= 2` cannot be satisfied.
160+ deps = [ make_dep ( "a" , ">= 1" ) ]
161+ s = set a1_spec , a2_spec , b1_spec
162+
163+ res = Gem ::Resolver . new deps , s
164+ # a-1 is already installed and satisfies `a >= 1`, so conservative mode
165+ # prefers it - but it is blocked by the missing b-2, forcing an upgrade.
166+ res . skip_gems = { "a" => [ a1_spec ] }
167+
168+ assert_resolves_to [ a2_spec , b1_spec ] , res
169+ end
170+
143171 def test_resolve_development
144172 a_spec = util_spec "a" , 1 do |s |
145173 s . add_development_dependency "b"
@@ -516,7 +544,7 @@ def test_raises_and_reports_an_implicit_request_properly
516544 r . resolve
517545 end
518546
519- assert_match ( /depends on unknown package b / , e . message )
547+ assert_match ( /depends on b = 2 which could not be found in any repository / , e . message )
520548 end
521549
522550 def test_raises_when_possibles_are_exhausted
@@ -945,6 +973,28 @@ def test_error_includes_ruby_version_hint_when_filtered
945973 assert_match ( /you have/ , e . message )
946974 end
947975
976+ def test_root_gem_incompatible_ruby_version_names_ruby_requirement
977+ # A requested (root) gem available only for an incompatible Ruby version
978+ # flows through the solver to a DependencyResolutionError whose message
979+ # names the Ruby requirement. This matches Bundler (which models Ruby as a
980+ # synthetic dependency and reports a solve failure) and is clearer than the
981+ # platform-oriented UnsatisfiableDependencyError. Contrast the foreign-
982+ # *platform* case (test_raises_and_explains_when_platform_prevents_install),
983+ # which is genuinely "not found" and does raise UnsatisfiableDependencyError.
984+ a = util_spec "a" , "1.0" do |s |
985+ s . required_ruby_version = ">= 999.0"
986+ end
987+
988+ ad = make_dep "a" , "= 1.0"
989+ r = Gem ::Resolver . new ( [ ad ] , set ( a ) )
990+
991+ e = assert_raise Gem ::DependencyResolutionError do
992+ r . resolve
993+ end
994+
995+ assert_match ( /requires Ruby >= 999.0/ , e . message )
996+ end
997+
948998 def test_self_dependency_does_not_crash
949999 a = util_spec "a" , "1.0" do |s |
9501000 s . add_dependency "a"
@@ -1090,7 +1140,7 @@ def test_fails_when_every_version_depends_on_missing_package
10901140 r . resolve
10911141 end
10921142
1093- assert_match ( /every version of a depends on unknown package zzz / , e . message )
1143+ assert_match ( /every version of a depends on zzz >= 1 which could not be found in any repository / , e . message )
10941144 end
10951145
10961146 def test_resolves_when_only_lowest_version_has_missing_dep
0 commit comments