From fcbf63e62c627deae76c1b8cb8c0876c536ed811 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Mon, 16 Mar 2020 18:49:26 +0900 Subject: Fresh start --- jni/ruby/test/rubygems/test_gem_resolver.rb | 733 ++++++++++++++++++++++++++++ 1 file changed, 733 insertions(+) create mode 100644 jni/ruby/test/rubygems/test_gem_resolver.rb (limited to 'jni/ruby/test/rubygems/test_gem_resolver.rb') diff --git a/jni/ruby/test/rubygems/test_gem_resolver.rb b/jni/ruby/test/rubygems/test_gem_resolver.rb new file mode 100644 index 0000000..2b9e9fe --- /dev/null +++ b/jni/ruby/test/rubygems/test_gem_resolver.rb @@ -0,0 +1,733 @@ +require 'rubygems/test_case' + +class TestGemResolver < Gem::TestCase + + def setup + super + + @DR = Gem::Resolver + end + + def make_dep(name, *req) + Gem::Dependency.new(name, *req) + end + + def set(*specs) + source = Gem::Source.new URI @gem_repo + + specs = specs.map do |spec| + Gem::Resolver::SpecSpecification.new nil, spec, source + end + + StaticSet.new(specs) + end + + def assert_resolves_to expected, resolver + actual = resolver.resolve + + exp = expected.sort_by { |s| s.full_name } + act = actual.map { |a| a.spec.spec }.sort_by { |s| s.full_name } + + msg = "Set of gems was not the same: #{exp.map { |x| x.full_name}.inspect} != #{act.map { |x| x.full_name}.inspect}" + + assert_equal exp, act, msg + rescue Gem::DependencyResolutionError => e + flunk e.message + end + + def test_self_compatibility + assert_same Gem::Resolver, Gem::DependencyResolver + end + + def test_self_compose_sets_best_set + best_set = @DR::BestSet.new + + composed = @DR.compose_sets best_set + + assert_equal best_set, composed + end + + def test_self_compose_sets_multiple + index_set = @DR::IndexSet.new + vendor_set = @DR::VendorSet.new + + composed = @DR.compose_sets index_set, vendor_set + + assert_kind_of Gem::Resolver::ComposedSet, composed + + assert_equal [index_set, vendor_set], composed.sets + end + + def test_self_compose_sets_nest + index_set = @DR::IndexSet.new + vendor_set = @DR::VendorSet.new + + inner = @DR.compose_sets index_set, vendor_set + + current_set = @DR::CurrentSet.new + + composed = @DR.compose_sets inner, current_set + + assert_kind_of Gem::Resolver::ComposedSet, composed + + assert_equal [index_set, vendor_set, current_set], composed.sets + end + + def test_self_compose_sets_nil + index_set = @DR::IndexSet.new + + composed = @DR.compose_sets index_set, nil + + assert_same index_set, composed + + e = assert_raises ArgumentError do + @DR.compose_sets nil + end + + assert_equal 'one set in the composition must be non-nil', e.message + end + + def test_self_compose_sets_single + index_set = @DR::IndexSet.new + + composed = @DR.compose_sets index_set + + assert_same index_set, composed + end + + def test_handle_conflict + a1 = util_spec 'a', 1 + + r1 = Gem::Resolver::DependencyRequest.new dep('a', '= 1'), nil + r2 = Gem::Resolver::DependencyRequest.new dep('a', '= 2'), nil + r3 = Gem::Resolver::DependencyRequest.new dep('a', '= 3'), nil + + existing = Gem::Resolver::ActivationRequest.new a1, r1, false + + res = Gem::Resolver.new [a1] + + res.handle_conflict r2, existing + res.handle_conflict r2, existing + res.handle_conflict r3, existing + + assert_equal 2, res.conflicts.length + end + + def test_requests + a1 = util_spec 'a', 1, 'b' => 2 + + r1 = Gem::Resolver::DependencyRequest.new dep('a', '= 1'), nil + + act = Gem::Resolver::ActivationRequest.new a1, r1, false + + res = Gem::Resolver.new [a1] + + reqs = Gem::Resolver::RequirementList.new + + res.requests a1, act, reqs + + assert_equal ['b (= 2)'], reqs.to_a.map { |req| req.to_s } + end + + def test_requests_development + a1 = util_spec 'a', 1, 'b' => 2 + + spec = Gem::Resolver::SpecSpecification.new nil, a1 + def spec.fetch_development_dependencies + @called = true + end + + r1 = Gem::Resolver::DependencyRequest.new dep('a', '= 1'), nil + + act = Gem::Resolver::ActivationRequest.new spec, r1, false + + res = Gem::Resolver.new [act] + res.development = true + + reqs = Gem::Resolver::RequirementList.new + + res.requests spec, act, reqs + + assert_equal ['b (= 2)'], reqs.to_a.map { |req| req.to_s } + + assert spec.instance_variable_defined? :@called + end + + def test_requests_ignore_dependencies + a1 = util_spec 'a', 1, 'b' => 2 + + r1 = Gem::Resolver::DependencyRequest.new dep('a', '= 1'), nil + + act = Gem::Resolver::ActivationRequest.new a1, r1, false + + res = Gem::Resolver.new [a1] + res.ignore_dependencies = true + + reqs = Gem::Resolver::RequirementList.new + + res.requests a1, act, reqs + + assert_empty reqs + end + + def test_resolve_conservative + a1_spec = util_spec 'a', 1 + a2_spec = util_spec 'a', 2 do |s| + s.add_dependency 'b', 2 + s.add_dependency 'c' + end + b1_spec = util_spec 'b', 1 + b2_spec = util_spec 'b', 2 + c1_spec = util_spec 'c', 1 do |s| s.add_dependency 'd', 2 end + c2_spec = util_spec 'c', 2 do |s| s.add_dependency 'd', 2 end + d1_spec = util_spec 'd', 1 do |s| s.add_dependency 'e' end + d2_spec = util_spec 'd', 2 do |s| s.add_dependency 'e' end + e1_spec = util_spec 'e', 1 + e2_spec = util_spec 'e', 2 + + a_dep = make_dep 'a', '= 2' + e_dep = make_dep 'e' + + # When requesting to install: + # a-2, e + deps = [a_dep, e_dep] + + s = set a1_spec, a2_spec, b1_spec, b2_spec, c1_spec, c2_spec, d1_spec, d2_spec, e1_spec, e2_spec + + res = Gem::Resolver.new deps, s + + # With the following gems already installed: + # a-1, b-1, c-1, e-1 + res.skip_gems = {'a'=>[a1_spec], 'b'=>[b1_spec], 'c'=>[c1_spec], 'e'=>[e1_spec]} + + # Make sure the following gems end up getting used/installed/upgraded: + # a-2 (upgraded) + # b-2 (upgraded), specific dependency from a-2 + # c-1 (used, not upgraded), open dependency from a-2 + # d-2 (installed), specific dependency from c-2 + # e-1 (used, not upgraded), open dependency from request + assert_resolves_to [a2_spec, b2_spec, c1_spec, d2_spec, e1_spec], res + end + + def test_resolve_development + a_spec = util_spec 'a', 1 do |s| s.add_development_dependency 'b' end + b_spec = util_spec 'b', 1 do |s| s.add_development_dependency 'c' end + c_spec = util_spec 'c', 1 + + a_dep = make_dep 'a', '= 1' + + deps = [a_dep] + + s = set a_spec, b_spec, c_spec + + res = Gem::Resolver.new deps, s + + res.development = true + + assert_resolves_to [a_spec, b_spec, c_spec], res + end + + def test_resolve_development_shallow + a_spec = util_spec 'a', 1 do |s| + s.add_development_dependency 'b' + s.add_runtime_dependency 'd' + end + + b_spec = util_spec 'b', 1 do |s| s.add_development_dependency 'c' end + c_spec = util_spec 'c', 1 + + d_spec = util_spec 'd', 1 do |s| s.add_development_dependency 'e' end + e_spec = util_spec 'e', 1 + + a_dep = make_dep 'a', '= 1' + + deps = [a_dep] + + s = set a_spec, b_spec, c_spec, d_spec, e_spec + + res = Gem::Resolver.new deps, s + + res.development = true + res.development_shallow = true + + assert_resolves_to [a_spec, b_spec, d_spec], res + end + + def test_resolve_remote_missing_dependency + @fetcher = Gem::FakeFetcher.new + Gem::RemoteFetcher.fetcher = @fetcher + + a_dep = make_dep 'a', '= 1' + + res = Gem::Resolver.new [a_dep], Gem::Resolver::IndexSet.new + + e = assert_raises Gem::UnsatisfiableDepedencyError do + res.resolve + end + + refute_empty e.errors + end + + def test_no_overlap_specificly + a = util_spec "a", '1' + b = util_spec "b", "1" + + ad = make_dep "a", "= 1" + bd = make_dep "b", "= 1" + + deps = [ad, bd] + + s = set(a, b) + + res = Gem::Resolver.new(deps, s) + + assert_resolves_to [a, b], res + end + + def test_pulls_in_dependencies + a = util_spec "a", '1' + b = util_spec "b", "1", "c" => "= 1" + c = util_spec "c", "1" + + ad = make_dep "a", "= 1" + bd = make_dep "b", "= 1" + + deps = [ad, bd] + + s = set(a, b, c) + + res = Gem::Resolver.new(deps, s) + + assert_resolves_to [a, b, c], res + end + + def test_picks_highest_version + a1 = util_spec "a", '1' + a2 = util_spec "a", '2' + + s = set(a1, a2) + + ad = make_dep "a" + + res = Gem::Resolver.new([ad], s) + + assert_resolves_to [a2], res + end + + def test_picks_best_platform + is = Gem::Resolver::IndexSpecification + unknown = Gem::Platform.new 'unknown' + a2_p1 = a3_p2 = nil + + spec_fetcher do |fetcher| + fetcher.spec 'a', 2 + a2_p1 = fetcher.spec 'a', 2 do |s| s.platform = Gem::Platform.local end + a3_p2 = fetcher.spec 'a', 3 do |s| s.platform = unknown end + end + + v2 = v(2) + v3 = v(3) + source = Gem::Source.new @gem_repo + + s = set + + a2 = is.new s, 'a', v2, source, Gem::Platform::RUBY + a2_p1 = is.new s, 'a', v2, source, Gem::Platform.local.to_s + a3_p2 = is.new s, 'a', v3, source, unknown + + s.add a3_p2 + s.add a2_p1 + s.add a2 + + ad = make_dep "a" + + res = Gem::Resolver.new([ad], s) + + assert_resolves_to [a2_p1.spec], res + end + + def test_only_returns_spec_once + a1 = util_spec "a", "1", "c" => "= 1" + b1 = util_spec "b", "1", "c" => "= 1" + + c1 = util_spec "c", "1" + + ad = make_dep "a" + bd = make_dep "b" + + s = set(a1, b1, c1) + + res = Gem::Resolver.new([ad, bd], s) + + assert_resolves_to [a1, b1, c1], res + end + + def test_picks_lower_version_when_needed + a1 = util_spec "a", "1", "c" => ">= 1" + b1 = util_spec "b", "1", "c" => "= 1" + + c1 = util_spec "c", "1" + c2 = util_spec "c", "2" + + ad = make_dep "a" + bd = make_dep "b" + + s = set(a1, b1, c1, c2) + + res = Gem::Resolver.new([ad, bd], s) + + assert_resolves_to [a1, b1, c1], res + end + + def test_conflict_resolution_only_effects_correct_spec + a1 = util_spec "a", "1", "c" => ">= 1" + b1 = util_spec "b", "1", "d" => ">= 1" + + d3 = util_spec "d", "3", "c" => "= 1" + d4 = util_spec "d", "4", "c" => "= 1" + + c1 = util_spec "c", "1" + c2 = util_spec "c", "2" + + ad = make_dep "a" + bd = make_dep "b" + + s = set(a1, b1, d3, d4, c1, c2) + + res = Gem::Resolver.new([ad, bd], s) + + assert_resolves_to [a1, b1, c1, d4], res + end + + def test_backoff_higher_version_to_satisfy_dep + t3 = util_spec "railties", "3.2" + t4 = util_spec "railties", "4.0" + + r3 = util_spec "rails", "3.2", "railties" => "= 3.2" + r4 = util_spec "rails", "4.0", "railties" => "= 4.0" + + rd = make_dep "rails", "3.2" + + c3 = util_spec "coffee", "3.0", "railties" => "~> 3.0" + c4 = util_spec "coffee", "4.0", "railties" => "~> 4.0" + + cd = make_dep "coffee" + + s = set(t3, t4, r3, r4, c3, c4) + + res = Gem::Resolver.new([rd, cd], s) + + assert_resolves_to [r3, t3, c3], res + end + + def test_raises_dependency_error + a1 = util_spec "a", "1", "c" => "= 1" + b1 = util_spec "b", "1", "c" => "= 2" + + c1 = util_spec "c", "1" + c2 = util_spec "c", "2" + + ad = make_dep "a" + bd = make_dep "b" + + s = set(a1, b1, c1, c2) + + r = Gem::Resolver.new([ad, bd], s) + + e = assert_raises Gem::DependencyResolutionError do + r.resolve + end + + deps = [make_dep("c", "= 1"), make_dep("c", "= 2")] + assert_equal deps, e.conflicting_dependencies + + con = e.conflict + + act = con.activated + assert_equal "c-2", act.spec.full_name + + parent = act.parent + assert_equal "b-1", parent.spec.full_name + + act = con.requester + assert_equal "a-1", act.spec.full_name + end + + def test_raises_when_a_gem_is_missing + ad = make_dep "a" + + r = Gem::Resolver.new([ad], set) + + e = assert_raises Gem::UnsatisfiableDepedencyError do + r.resolve + end + + assert_equal "Unable to resolve dependency: user requested 'a (>= 0)'", + e.message + + assert_equal "a (>= 0)", e.dependency.to_s + end + + def test_raises_when_a_gem_version_is_missing + a1 = util_spec "a", "1" + + ad = make_dep "a", "= 3" + + r = Gem::Resolver.new([ad], set(a1)) + + e = assert_raises Gem::UnsatisfiableDepedencyError do + r.resolve + end + + assert_equal "a (= 3)", e.dependency.to_s + end + + def test_raises_and_reports_a_toplevel_request_properly + a1 = util_spec "a", "1" + ad = make_dep "a", "= 3" + + r = Gem::Resolver.new([ad], set(a1)) + + e = assert_raises Gem::UnsatisfiableDepedencyError do + r.resolve + end + + assert_equal "Unable to resolve dependency: user requested 'a (= 3)'", + e.message + end + + def test_raises_and_reports_an_implicit_request_properly + a1 = util_spec "a", "1" do |s| + s.add_runtime_dependency 'b', '= 2' + end + + ad = make_dep "a", "= 1" + + r = Gem::Resolver.new([ad], set(a1)) + + e = assert_raises Gem::UnsatisfiableDepedencyError do + r.resolve + end + + assert_equal "Unable to resolve dependency: 'a (= 1)' requires 'b (= 2)'", + e.message + end + + def test_raises_when_possibles_are_exhausted + a1 = util_spec "a", "1", "c" => ">= 2" + b1 = util_spec "b", "1", "c" => "= 1" + + c1 = util_spec "c", "1" + c2 = util_spec "c", "2" + c3 = util_spec "c", "3" + + s = set(a1, b1, c1, c2, c3) + + ad = make_dep "a" + bd = make_dep "b" + + r = Gem::Resolver.new([ad, bd], s) + + e = assert_raises Gem::DependencyResolutionError do + r.resolve + end + + dependency = e.conflict.dependency + + assert_equal 'a', dependency.name + assert_equal req('>= 0'), dependency.requirement + + activated = e.conflict.activated + assert_equal 'c-1', activated.full_name + + assert_equal dep('c', '= 1'), activated.request.dependency + + assert_equal [dep('c', '>= 2'), dep('c', '= 1')], + e.conflict.conflicting_dependencies + end + + def test_keeps_resolving_after_seeing_satisfied_dep + a1 = util_spec "a", "1", "b" => "= 1", "c" => "= 1" + b1 = util_spec "b", "1" + c1 = util_spec "c", "1" + + ad = make_dep "a" + bd = make_dep "b" + + s = set(a1, b1, c1) + + r = Gem::Resolver.new([ad, bd], s) + + assert_resolves_to [a1, b1, c1], r + end + + def test_common_rack_activation_scenario + rack100 = util_spec "rack", "1.0.0" + rack101 = util_spec "rack", "1.0.1" + + lib1 = util_spec "lib", "1", "rack" => ">= 1.0.1" + + rails = util_spec "rails", "3", "actionpack" => "= 3" + ap = util_spec "actionpack", "3", "rack" => ">= 1.0.0" + + d1 = make_dep "rails" + d2 = make_dep "lib" + + s = set(lib1, rails, ap, rack100, rack101) + + r = Gem::Resolver.new([d1, d2], s) + + assert_resolves_to [rails, ap, rack101, lib1], r + + # check it with the deps reverse too + + r = Gem::Resolver.new([d2, d1], s) + + assert_resolves_to [lib1, rack101, rails, ap], r + end + + def test_backtracks_to_the_first_conflict + a1 = util_spec "a", "1" + a2 = util_spec "a", "2" + a3 = util_spec "a", "3" + a4 = util_spec "a", "4" + + d1 = make_dep "a" + d2 = make_dep "a", ">= 2" + d3 = make_dep "a", "= 1" + + s = set(a1, a2, a3, a4) + + r = Gem::Resolver.new([d1, d2, d3], s) + + assert_raises Gem::DependencyResolutionError do + r.resolve + end + end + + def test_resolve_conflict + a1 = util_spec 'a', 1 + a2 = util_spec 'a', 2 + + b2 = util_spec 'b', 2, 'a' => '~> 2.0' + + s = set a1, a2, b2 + + a_dep = dep 'a', '~> 1.0' + b_dep = dep 'b' + + r = Gem::Resolver.new [a_dep, b_dep], s + + assert_raises Gem::DependencyResolutionError do + r.resolve + end + end + + def test_resolve_bug_699 + a1 = util_spec 'a', '1', 'b' => '= 2', + 'c' => '~> 1.0.3' + + b1 = util_spec 'b', '2', 'c' => '~> 1.0' + + c1 = util_spec 'c', '1.0.9' + c2 = util_spec 'c', '1.1.0' + c3 = util_spec 'c', '1.2.0' + + s = set a1, b1, c1, c2, c3 + + a_dep = dep 'a', '= 1' + + r = Gem::Resolver.new [a_dep], s + + assert_resolves_to [a1, b1, c1], r + end + + def test_resolve_rollback + a1 = util_spec 'a', 1 + a2 = util_spec 'a', 2 + + b1 = util_spec 'b', 1, 'a' => '~> 1.0' + b2 = util_spec 'b', 2, 'a' => '~> 2.0' + + s = set a1, a2, b1, b2 + + a_dep = dep 'a', '~> 1.0' + b_dep = dep 'b' + + r = Gem::Resolver.new [a_dep, b_dep], s + + assert_resolves_to [a1, b1], r + end + + # actionmailer 2.3.4 + # activemerchant 1.5.0 + # activesupport 2.3.5, 2.3.4 + # 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. + + + def test_simple_activesupport_problem + sup1 = util_spec "activesupport", "2.3.4" + sup2 = util_spec "activesupport", "2.3.5" + + merch = util_spec "activemerchant", "1.5.0", "activesupport" => ">= 2.3.2" + mail = util_spec "actionmailer", "2.3.4", "activesupport" => "= 2.3.4" + + s = set(mail, merch, sup1, sup2) + + d1 = make_dep "activemerchant" + d2 = make_dep "actionmailer" + + r = Gem::Resolver.new([d1, d2], s) + + assert_resolves_to [merch, mail, sup1], r + end + + def test_second_level_backout + b1 = new_spec "b", "1", { "c" => ">= 1" }, "lib/b.rb" + b2 = new_spec "b", "2", { "c" => ">= 2" }, "lib/b.rb" + c1 = new_spec "c", "1" + c2 = new_spec "c", "2" + d1 = new_spec "d", "1", { "c" => "< 2" }, "lib/d.rb" + d2 = new_spec "d", "2", { "c" => "< 2" }, "lib/d.rb" + + s = set(b1, b2, c1, c2, d1, d2) + + p1 = make_dep "b", "> 0" + p2 = make_dep "d", "> 0" + + r = Gem::Resolver.new([p1, p2], s) + + assert_resolves_to [b1, c1, d2], r + end + + def test_select_local_platforms + r = Gem::Resolver.new nil, nil + + a1 = util_spec 'a', 1 + a1_p1 = util_spec 'a', 1 do |s| s.platform = Gem::Platform.local end + a1_p2 = util_spec 'a', 1 do |s| s.platform = 'unknown' end + + selected = r.select_local_platforms [a1, a1_p1, a1_p2] + + assert_equal [a1, a1_p1], selected + end + + def test_raises_and_explains_when_platform_prevents_install + a1 = util_spec "a", "1" do |s| + s.platform = Gem::Platform.new %w[c p 1] + end + + ad = make_dep "a", "= 1" + + r = Gem::Resolver.new([ad], set(a1)) + + e = assert_raises Gem::UnsatisfiableDepedencyError do + r.resolve + end + + assert_match "No match for 'a (= 1)' on this platform. Found: c-p-1", + e.message + end + +end + -- cgit v1.2.3