diff options
Diffstat (limited to 'test/rubygems/test_gem_specification.rb')
-rw-r--r-- | test/rubygems/test_gem_specification.rb | 596 |
1 files changed, 442 insertions, 154 deletions
diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 24a7261466..0a009cbd7b 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require "benchmark" + require_relative "helper" require "date" require "pathname" @@ -10,7 +10,7 @@ require "rubygems/installer" require "rubygems/platform" class TestGemSpecification < Gem::TestCase - LEGACY_YAML_SPEC = <<-EOF.freeze + LEGACY_YAML_SPEC = <<-EOF --- !ruby/object:Gem::Specification rubygems_version: "1.0" name: keyedlist @@ -29,7 +29,7 @@ email: flgr@ccan.de has_rdoc: true EOF - LEGACY_RUBY_SPEC = <<-EOF.freeze + LEGACY_RUBY_SPEC = <<-EOF Gem::Specification.new do |s| s.name = %q{keyedlist} s.version = %q{0.4.0} @@ -55,7 +55,6 @@ end s.add_dependency "jabber4r", "> 0.0.0" s.add_dependency "pqa", ["> 0.4", "<= 0.6"] - s.mark_version s.files = %w[lib/code.rb] end end @@ -68,7 +67,6 @@ end s.license = "MIT" s.platform = platform - s.mark_version s.files = %w[lib/code.rb] s.installed_by_version = v("2.2") end @@ -89,12 +87,12 @@ end Gem.instance_variable_set(:'@default_source_date_epoch', nil) @a1 = util_spec "a", "1" do |s| + s.required_ruby_version = ">= 2.3.0" s.executable = "exec" s.test_file = "test/suite.rb" s.requirements << "A working computer" s.license = "MIT" - s.mark_version s.files = %w[lib/code.rb] end @@ -147,6 +145,12 @@ end end def test_find_in_unresolved_tree_is_not_exponentiental + begin + require "benchmark" + rescue LoadError + pend "Benchmark is not available in this environment. Please install it with `gem install benchmark`." + end + pend "currently slower in CI on TruffleRuby" if RUBY_ENGINE == "truffleruby" num_of_pkg = 7 num_of_version_per_pkg = 3 @@ -691,7 +695,7 @@ end version ] - actual_value = Gem::Specification.attribute_names.map {|a| a.to_s }.sort + actual_value = Gem::Specification.attribute_names.map(&:to_s).sort assert_equal expected_value, actual_value end @@ -796,26 +800,6 @@ dependencies: [] assert_equal File.join(@tempdir, "a-2.gemspec"), spec.loaded_from end - if RUBY_ENGINE == "ruby" && RUBY_VERSION < "2.7" - def test_self_load_tainted - full_path = @a2.spec_file - write_file full_path do |io| - io.write @a2.to_ruby_for_cache - end - - full_path.taint - loader = Thread.new { $SAFE = 1; Gem::Specification.load full_path } - spec = loader.value - - @a2.files.clear - - assert_equal @a2, spec - - ensure - $SAFE = 0 - end - end - def test_self_load_escape_curly @a2.name = 'a};raise "improper escaping";%q{' @@ -962,13 +946,13 @@ dependencies: [] install_specs @a1 assert_includes Gem::Specification.all_names, "a-1" - assert_includes Gem::Specification.stubs.map {|s| s.full_name }, "a-1" + assert_includes Gem::Specification.stubs.map(&:full_name), "a-1" uninstall_gem @a1 Gem::Specification.reset refute_includes Gem::Specification.all_names, "a-1" - refute_includes Gem::Specification.stubs.map {|s| s.full_name }, "a-1" + refute_includes Gem::Specification.stubs.map(&:full_name), "a-1" end def test_self_remove_spec_removed @@ -983,31 +967,34 @@ dependencies: [] Gem::Specification.reset refute_includes Gem::Specification.all_names, "a-1" - refute_includes Gem::Specification.stubs.map {|s| s.full_name }, "a-1" + refute_includes Gem::Specification.stubs.map(&:full_name), "a-1" end def test_self_stubs_for_lazy_loading Gem.loaded_specs.clear - Gem::Specification.class_variable_set(:@@stubs, nil) + + specification_record = Gem::Specification.specification_record + + specification_record.instance_variable_set(:@stubs, nil) dir_standard_specs = File.join Gem.dir, "specifications" save_gemspec("a-1", "1", dir_standard_specs) {|s| s.name = "a" } save_gemspec("b-1", "1", dir_standard_specs) {|s| s.name = "b" } - assert_equal ["a-1"], Gem::Specification.stubs_for("a").map {|s| s.full_name } - assert_equal 1, Gem::Specification.class_variable_get(:@@stubs_by_name).length - assert_equal ["b-1"], Gem::Specification.stubs_for("b").map {|s| s.full_name } - assert_equal 2, Gem::Specification.class_variable_get(:@@stubs_by_name).length + assert_equal ["a-1"], Gem::Specification.stubs_for("a").map(&:full_name) + assert_equal 1, specification_record.instance_variable_get(:@stubs_by_name).length + assert_equal ["b-1"], Gem::Specification.stubs_for("b").map(&:full_name) + assert_equal 2, specification_record.instance_variable_get(:@stubs_by_name).length assert_equal( - Gem::Specification.stubs_for("a").map {|s| s.object_id }, - Gem::Specification.stubs_for("a").map {|s| s.object_id } + Gem::Specification.stubs_for("a").map(&:object_id), + Gem::Specification.stubs_for("a").map(&:object_id) ) Gem.loaded_specs.delete "a" Gem.loaded_specs.delete "b" - Gem::Specification.class_variable_set(:@@stubs, nil) + specification_record.instance_variable_set(:@stubs, nil) end def test_self_stubs_for_no_lazy_loading_after_all_specs_setup @@ -1015,7 +1002,7 @@ dependencies: [] save_gemspec("b-1", "1", File.join(Gem.dir, "specifications")) {|s| s.name = "b" } - assert_equal [], Gem::Specification.stubs_for("b").map {|s| s.full_name } + assert_equal [], Gem::Specification.stubs_for("b").map(&:full_name) end def test_self_stubs_for_mult_platforms @@ -1034,7 +1021,7 @@ dependencies: [] v = "1.1.1" platforms = ["x86-mingw32", "x64-mingw32"] - #create specs + # create specs platforms.each do |plat| spec = Gem::Specification.new(gem, v) {|s| s.platform = plat } File.open File.join(user_spec_dir, "#{gem}-#{v}-#{plat}.gemspec"), "w" do |io| @@ -1068,19 +1055,46 @@ dependencies: [] end def test_handles_private_null_type + yaml_defined = Object.const_defined?("YAML") + path = File.expand_path "data/pry-0.4.7.gemspec.rz", __dir__ data = Marshal.load Gem::Util.inflate(Gem.read_binary(path)) assert_instance_of Gem::Specification, data + + assert_equal(yaml_defined, Object.const_defined?("YAML")) end def test_handles_dependencies_with_syck_requirements_bug + yaml_defined = Object.const_defined?("YAML") + path = File.expand_path "data/excon-0.7.7.gemspec.rz", __dir__ data = Marshal.load Gem::Util.inflate(Gem.read_binary(path)) assert_instance_of Gem::Specification, data + + assert_equal(yaml_defined, Object.const_defined?("YAML")) + end + + def test_handles_dependencies_with_other_syck_requirements_argument_error + yaml_defined = Object.const_defined?("YAML") + + data = Marshal.dump(Gem::Specification.new do |s| + v = Gem::Version.allocate + v.instance_variable_set :@version, "YAML::Syck::DefaultKey" + s.instance_variable_set :@version, v + end) + + assert_raise(ArgumentError) { Marshal.load(data) } + out, err = capture_output do + assert_raise(ArgumentError) { Marshal.load(data) } + end + assert_empty out + assert_empty err + + assert_equal(yaml_defined, Object.const_defined?("YAML")) end def test_initialize @@ -1186,10 +1200,13 @@ dependencies: [] assert_same spec.bindir, dup_spec.bindir assert_equal ">= 0", spec.required_ruby_version.to_s - assert_same spec.required_ruby_version, dup_spec.required_ruby_version + assert_equal spec.required_ruby_version, dup_spec.required_ruby_version + refute_same spec.required_ruby_version, dup_spec.required_ruby_version assert_equal ">= 0", spec.required_rubygems_version.to_s - assert_same spec.required_rubygems_version, + assert_equal spec.required_rubygems_version, + dup_spec.required_rubygems_version + refute_same spec.required_rubygems_version, dup_spec.required_rubygems_version end @@ -1199,7 +1216,7 @@ dependencies: [] s.version = "1" end - spec.instance_variable_set :@licenses, (class << (Object.new);self;end) + spec.instance_variable_set :@licenses, (class << Object.new;self;end) spec.loaded_from = "/path/to/file" e = assert_raise Gem::FormatException do @@ -1252,7 +1269,7 @@ dependencies: [] awesome.add_dependency :gem_name end - assert_equal %w[true gem_name], gem.dependencies.map {|dep| dep.name } + assert_equal %w[true gem_name], gem.dependencies.map(&:name) end def test_add_dependency_from_existing_dependency @@ -1322,9 +1339,7 @@ dependencies: [] assert_empty @ext.build_args - File.open @ext.build_info_file, "w" do |io| - io.puts - end + File.open @ext.build_info_file, "w", &:puts assert_empty @ext.build_args @@ -1444,15 +1459,15 @@ dependencies: [] end FileUtils.mkdir_p File.join @ext.base_dir, "extensions" - FileUtils.chmod 0555, @ext.base_dir - FileUtils.chmod 0555, File.join(@ext.base_dir, "extensions") + FileUtils.chmod 0o555, @ext.base_dir + FileUtils.chmod 0o555, File.join(@ext.base_dir, "extensions") @ext.build_extensions assert_path_not_exist @ext.extension_dir ensure - unless ($DEBUG || win_platform? || Process.uid.zero? || Gem.java_platform?) - FileUtils.chmod 0755, File.join(@ext.base_dir, "extensions") - FileUtils.chmod 0755, @ext.base_dir + unless $DEBUG || Gem.win_platform? || Process.uid.zero? || Gem.java_platform? + FileUtils.chmod 0o755, File.join(@ext.base_dir, "extensions") + FileUtils.chmod 0o755, @ext.base_dir end end @@ -1477,14 +1492,14 @@ dependencies: [] end FileUtils.rm_r File.join @gemhome, "extensions" - FileUtils.chmod 0555, @gemhome + FileUtils.chmod 0o555, @gemhome @ext.build_extensions gem_make_out = File.join @ext.extension_dir, "gem_make.out" assert_path_not_exist gem_make_out ensure - FileUtils.chmod 0755, @gemhome + FileUtils.chmod 0o755, @gemhome end def test_build_extensions_none @@ -1539,7 +1554,7 @@ dependencies: [] refute @ext.contains_requirable_file? "nonexistent" end - expected = "Ignoring ext-1 because its extensions are not built. " + + expected = "Ignoring ext-1 because its extensions are not built. " \ "Try: gem pristine ext --version 1\n" assert_equal expected, err @@ -1555,6 +1570,17 @@ dependencies: [] assert_empty err end + def test_contains_requirable_file_extension_soext + ext_spec + dlext = RbConfig::CONFIG["DLEXT"] + @ext.files += ["lib/ext.#{dlext}"] + + FileUtils.mkdir_p @ext.extension_dir + FileUtils.touch File.join(@ext.extension_dir, "ext.#{dlext}") + FileUtils.touch File.join(@ext.extension_dir, "gem.build_complete") + assert @ext.contains_requirable_file? "ext.so" + end + def test_date assert_date @a1.date end @@ -1592,12 +1618,12 @@ dependencies: [] def test_date_tolerates_hour_sec_zulu @a1.date = "2012-01-12 11:22:33.4444444 Z" - assert_equal Time.utc(2012,01,12,0,0,0), @a1.date + assert_equal Time.utc(2012,1,12,0,0,0), @a1.date end def test_date_tolerates_hour_sec_and_timezone @a1.date = "2012-01-12 11:22:33.4444444 +02:33" - assert_equal Time.utc(2012,01,12,0,0,0), @a1.date + assert_equal Time.utc(2012,1,12,0,0,0), @a1.date end def test_date_use_env_source_date_epoch @@ -1684,8 +1710,8 @@ dependencies: [] end def test_extension_dir - enable_shared, RbConfig::CONFIG["ENABLE_SHARED"] = - RbConfig::CONFIG["ENABLE_SHARED"], "no" + enable_shared = RbConfig::CONFIG["ENABLE_SHARED"] + RbConfig::CONFIG["ENABLE_SHARED"] = "no" ext_spec @@ -1701,11 +1727,11 @@ dependencies: [] end def test_extension_dir_override - enable_shared, RbConfig::CONFIG["ENABLE_SHARED"] = - RbConfig::CONFIG["ENABLE_SHARED"], "no" + enable_shared = RbConfig::CONFIG["ENABLE_SHARED"] + RbConfig::CONFIG["ENABLE_SHARED"] = "no" class << Gem - alias orig_default_ext_dir_for default_ext_dir_for + alias_method :orig_default_ext_dir_for, :default_ext_dir_for remove_method :default_ext_dir_for @@ -1727,7 +1753,7 @@ dependencies: [] class << Gem remove_method :default_ext_dir_for - alias default_ext_dir_for orig_default_ext_dir_for + alias_method :default_ext_dir_for, :orig_default_ext_dir_for end end @@ -1812,7 +1838,7 @@ dependencies: [] end def test_for_cache - @a2.add_runtime_dependency "b", "1" + @a2.add_dependency "b", "1" @a2.dependencies.first.instance_variable_set :@type, nil @a2.required_rubygems_version = Gem::Requirement.new "> 0" @a2.test_files = %w[test/test_b.rb] @@ -1839,7 +1865,7 @@ dependencies: [] end def test_full_gem_path_double_slash - gemhome = @gemhome.to_s.sub(/\w\//, '\&/') + gemhome = @gemhome.to_s.sub(%r{\w/}, '\&/') @a1.loaded_from = File.join gemhome, "specifications", @a1.spec_name expected = File.join @gemhome, "gems", @a1.full_name @@ -1857,7 +1883,7 @@ dependencies: [] @a1.instance_variable_set :@new_platform, "mswin32" assert_equal "a-1-mswin32", @a1.full_name, "legacy" - return if win_platform? + return if Gem.win_platform? @a1 = Gem::Specification.new "a", 1 @a1.platform = "current" @@ -1971,8 +1997,8 @@ dependencies: [] test_cases = { "i386-mswin32" => ["x86", "mswin32", "60"], "i386-mswin32_80" => ["x86", "mswin32", "80"], - "i386-mingw32" => ["x86", "mingw32", nil ], - "x86-darwin8" => ["x86", "darwin", "8" ], + "i386-mingw32" => ["x86", "mingw32", nil], + "x86-darwin8" => ["x86", "darwin", "8"], } test_cases.each do |arch, expected| @@ -1999,12 +2025,6 @@ dependencies: [] assert_equal Gem::Platform.new("ppc-darwin"), @a1.platform end - def test_prerelease_spec_adds_required_rubygems_version - @prerelease = util_spec("tardis", "2.2.0.a") - refute @prerelease.required_rubygems_version.satisfied_by?(Gem::Version.new("1.3.1")) - assert @prerelease.required_rubygems_version.satisfied_by?(Gem::Version.new("1.4.0")) - end - def test_require_paths enable_shared "no" do ext_spec @@ -2186,7 +2206,7 @@ dependencies: [] expected = %w[rake jabber4r pqa] - assert_equal expected, @c1.runtime_dependencies.map {|d| d.name } + assert_equal expected, @c1.runtime_dependencies.map(&:name) end def test_spaceship_name @@ -2194,7 +2214,7 @@ dependencies: [] s2 = util_spec "b", "1" assert_equal(-1, (s1 <=> s2)) - assert_equal(0, (s1 <=> s1)) + assert_equal(0, (s1 <=> s1)) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands assert_equal(1, (s2 <=> s1)) end @@ -2205,7 +2225,7 @@ dependencies: [] end assert_equal(-1, (s1 <=> s2)) - assert_equal(0, (s1 <=> s1)) + assert_equal(0, (s1 <=> s1)) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands assert_equal(1, (s2 <=> s1)) end @@ -2214,7 +2234,7 @@ dependencies: [] s2 = util_spec "a", "2" assert_equal(-1, (s1 <=> s2)) - assert_equal(0, (s1 <=> s1)) + assert_equal(0, (s1 <=> s1)) # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands assert_equal(1, (s2 <=> s1)) end @@ -2250,7 +2270,7 @@ dependencies: [] end def test_to_ruby - @a2.add_runtime_dependency "b", "1" + @a2.add_dependency "b", "1" @a2.dependencies.first.instance_variable_set :@type, nil @a2.required_rubygems_version = Gem::Requirement.new "> 0" @a2.require_paths << "other" @@ -2263,7 +2283,7 @@ dependencies: [] Gem::Specification.new do |s| s.name = "a".freeze - s.version = "2" + s.version = "2".freeze s.required_rubygems_version = Gem::Requirement.new(\"> 0\".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze, "other".freeze] @@ -2278,7 +2298,7 @@ Gem::Specification.new do |s| s.specification_version = #{Gem::Specification::CURRENT_SPECIFICATION_VERSION} - s.add_runtime_dependency(%q<b>.freeze, [\"= 1\"]) + s.add_runtime_dependency(%q<b>.freeze, [\"= 1\".freeze]) end SPEC @@ -2303,7 +2323,7 @@ end Gem::Specification.new do |s| s.name = "a".freeze - s.version = "2" + s.version = "2".freeze s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] @@ -2322,7 +2342,7 @@ end end def test_to_ruby_for_cache - @a2.add_runtime_dependency "b", "1" + @a2.add_dependency "b", "1" @a2.dependencies.first.instance_variable_set :@type, nil @a2.required_rubygems_version = Gem::Requirement.new "> 0" @a2.installed_by_version = Gem.rubygems_version @@ -2336,7 +2356,7 @@ end Gem::Specification.new do |s| s.name = "a".freeze - s.version = "2" + s.version = "2".freeze s.required_rubygems_version = Gem::Requirement.new(\"> 0\".freeze) if s.respond_to? :required_rubygems_version= s.require_paths = ["lib".freeze] @@ -2348,11 +2368,11 @@ Gem::Specification.new do |s| s.rubygems_version = "#{Gem::VERSION}".freeze s.summary = "this is a summary".freeze - s.installed_by_version = "#{Gem::VERSION}" if s.respond_to? :installed_by_version + s.installed_by_version = "#{Gem::VERSION}".freeze s.specification_version = #{Gem::Specification::CURRENT_SPECIFICATION_VERSION} - s.add_runtime_dependency(%q<b>.freeze, [\"= 1\"]) + s.add_runtime_dependency(%q<b>.freeze, ["= 1".freeze]) end SPEC @@ -2372,19 +2392,19 @@ end ruby_code = @c1.to_ruby local = Gem::Platform.local - expected_platform = "[#{local.cpu.inspect}, #{local.os.inspect}, #{local.version.inspect}]" + expected_platform = "[#{local.cpu.inspect}.freeze, #{local.os.inspect}.freeze, #{local.version.inspect}.freeze]" stub_require_paths = @c1.instance_variable_get(:@require_paths).join "\u0000" extensions = @c1.extensions.join "\u0000" expected = <<-SPEC # -*- encoding: utf-8 -*- -# stub: a 1 #{win_platform? ? "x86-mswin32-60" : "x86-darwin-8"} #{stub_require_paths} +# stub: a 1 #{Gem.win_platform? ? "x86-mswin32-60" : "x86-darwin-8"} #{stub_require_paths} # stub: #{extensions} Gem::Specification.new do |s| s.name = "a".freeze - s.version = "1" + s.version = "1".freeze s.platform = Gem::Platform.new(#{expected_platform}) s.required_rubygems_version = Gem::Requirement.new(\">= 0\".freeze) if s.respond_to? :required_rubygems_version= @@ -2405,9 +2425,9 @@ Gem::Specification.new do |s| s.specification_version = 4 - s.add_runtime_dependency(%q<rake>.freeze, [\"> 0.4\"]) - s.add_runtime_dependency(%q<jabber4r>.freeze, [\"> 0.0.0\"]) - s.add_runtime_dependency(%q<pqa>.freeze, [\"> 0.4\", \"<= 0.6\"]) + s.add_runtime_dependency(%q<rake>.freeze, [\"> 0.4\".freeze]) + s.add_runtime_dependency(%q<jabber4r>.freeze, [\"> 0.0.0\".freeze]) + s.add_runtime_dependency(%q<pqa>.freeze, [\"> 0.4\".freeze, \"<= 0.6\".freeze]) end SPEC @@ -2423,7 +2443,7 @@ end s.add_dependency "b", ["~> 1.0", ">= 1.0.0"] end - assert_includes spec.to_ruby, '"~> 1.0", ">= 1.0.0"' + assert_includes spec.to_ruby, '"~> 1.0".freeze, ">= 1.0.0".freeze' end def test_to_ruby_legacy @@ -2438,13 +2458,13 @@ end def test_to_ruby_nested_hash metadata = {} - metadata[metadata] = metadata + metadata[:metadata] = {} @a2.metadata = metadata ruby = @a2.to_ruby - assert_match %r%^ s\.metadata = \{ "%, ruby + assert_match(/^ s\.metadata = \{ "/, ruby) end def test_to_ruby_platform @@ -2461,7 +2481,7 @@ end def test_to_yaml yaml_str = @a1.to_yaml - refute_match %r{!!null}, yaml_str + refute_match(/!!null/, yaml_str) same_spec = Gem::Specification.from_yaml(yaml_str) @@ -2482,7 +2502,7 @@ end def test_to_yaml_platform_empty_string @a1.instance_variable_set :@original_platform, "" - assert_match %r{^platform: ruby$}, @a1.to_yaml + assert_match(/^platform: ruby$/, @a1.to_yaml) end def test_to_yaml_platform_legacy @@ -2500,7 +2520,27 @@ end def test_to_yaml_platform_nil @a1.instance_variable_set :@original_platform, nil - assert_match %r{^platform: ruby$}, @a1.to_yaml + assert_match(/^platform: ruby$/, @a1.to_yaml) + end + + def test_to_yaml_no_autorequire + yaml_str = @a1.to_yaml + + refute_match(/^autorequire:/, yaml_str) + end + + def test_to_yaml_no_signing_key + @a1.signing_key = nil + yaml_str = @a1.to_yaml + + refute_match(/^signing_key:/, yaml_str) + end + + def test_to_yaml_no_post_install_message + @a1.post_install_message = nil + yaml_str = @a1.to_yaml + + refute_match(/^post_install_message:/, yaml_str) end def test_validate @@ -2511,10 +2551,21 @@ end end end - def x(s); s.gsub(/xxx/, ""); end - def w; x "WARxxxNING"; end - def t; x "TOxxxDO"; end - def f; x "FxxxIXME"; end + def x(s) + s.gsub(/xxx/, "") + end + + def w + x "WARxxxNING" + end + + def t + x "TOxxxDO" + end + + def f + x "FxxxIXME" + end def test_validate_authors util_setup_validate @@ -2598,18 +2649,18 @@ end #{w}: prerelease dependency on c (>= 2.0.rc2, development) is not recommended #{w}: open-ended dependency on i (>= 1.2) is not recommended if i is semantically versioned, use: - add_runtime_dependency 'i', '~> 1.2' + add_runtime_dependency "i", "~> 1.2" #{w}: open-ended dependency on j (>= 1.2.3) is not recommended if j is semantically versioned, use: - add_runtime_dependency 'j', '~> 1.2', '>= 1.2.3' + add_runtime_dependency "j", "~> 1.2", ">= 1.2.3" #{w}: open-ended dependency on k (> 1.2) is not recommended if k is semantically versioned, use: - add_runtime_dependency 'k', '~> 1.2', '> 1.2' + add_runtime_dependency "k", "~> 1.2", "> 1.2" #{w}: open-ended dependency on l (> 1.2.3) is not recommended if l is semantically versioned, use: - add_runtime_dependency 'l', '~> 1.2', '> 1.2.3' + add_runtime_dependency "l", "~> 1.2", "> 1.2.3" #{w}: open-ended dependency on o (>= 0) is not recommended - use a bounded requirement, such as '~> x.y' + use a bounded requirement, such as "~> x.y" #{w}: See https://guides.rubygems.org/specification-reference/ for help EXPECTED @@ -2633,9 +2684,9 @@ end expected = <<-EXPECTED duplicate dependency on b (>= 1.2.3), (~> 1.2) use: - add_runtime_dependency 'b', '>= 1.2.3', '~> 1.2' + add_runtime_dependency "b", ">= 1.2.3", "~> 1.2" duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: - add_development_dependency 'c', '>= 1.2.3', '~> 1.2' + add_development_dependency "c", ">= 1.2.3", "~> 1.2" EXPECTED assert_equal expected, e.message @@ -2662,12 +2713,59 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: end end + def test_validate_no_required_ruby_versions + util_setup_validate + + Dir.chdir @tempdir do + use_ui @ui do + @a1.required_ruby_version = nil # reset + @a1.validate + end + + assert_equal <<-EXPECTED, @ui.error +#{w}: make sure you specify the oldest ruby version constraint (like \">= 3.0\") that you want your gem to support by setting the `required_ruby_version` gemspec attribute +#{w}: See https://guides.rubygems.org/specification-reference/ for help + EXPECTED + end + end + + def test_validate_open_required_ruby_versions + util_setup_validate + + Dir.chdir @tempdir do + @a1.required_ruby_version = ">= 0" + + use_ui @ui do + @a1.validate + end + + assert_equal <<-EXPECTED, @ui.error +#{w}: make sure you specify the oldest ruby version constraint (like \">= 3.0\") that you want your gem to support by setting the `required_ruby_version` gemspec attribute +#{w}: See https://guides.rubygems.org/specification-reference/ for help + EXPECTED + end + end + + def test_validate_valid_required_ruby_versions + util_setup_validate + + Dir.chdir @tempdir do + @a1.required_ruby_version = ">= 2.3.0" + + use_ui @ui do + @a1.validate + end + + assert_equal "", @ui.error, "warning" + end + end + def test_validate_prerelease_dependencies_with_prerelease_version util_setup_validate Dir.chdir @tempdir do @a1.version = "1.0.0.beta.1" - @a1.add_runtime_dependency "b", "~> 1.2.0.beta.1" + @a1.add_dependency "b", "~> 1.2.0.beta.1" use_ui @ui do @a1.validate @@ -2677,6 +2775,23 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: end end + def test_validate_self_referencing_dependencies + util_setup_validate + + Dir.chdir @tempdir do + @a1.add_dependency @a1.name, "1" + + use_ui @ui do + @a1.validate + end + + assert_equal <<-EXPECTED, @ui.error +#{w}: Self referencing dependency is unnecessary and strongly discouraged. +#{w}: See https://guides.rubygems.org/specification-reference/ for help + EXPECTED + end + end + def test_validate_rake_extension_have_rake_dependency_warning util_setup_validate @@ -2688,7 +2803,7 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: @a1.validate end - assert_match(/add rake as a dependency/, @ui.error) + assert_match(/add rake as a runtime dependency/, @ui.error) end end @@ -2697,14 +2812,47 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: Dir.chdir @tempdir do @a1.extensions = ["Rakefile"] - @a1.add_runtime_dependency "rake" + @a1.add_dependency "rake" File.write File.join(@tempdir, "Rakefile"), "" use_ui @ui do @a1.validate end - refute_match(/add rake as a dependency/, @ui.error) + refute_match(/add rake as a runtime dependency/, @ui.error) + end + end + + def test_validate_rust_extension_have_missing_cargo_toml_error + util_setup_validate + + Dir.chdir @tempdir do + @a1.extensions = ["Cargo.toml"] + File.write File.join(@tempdir, "Cargo.toml"), "" + + e = assert_raise Gem::InvalidSpecificationException do + use_ui @ui do + @a1.validate + end + end + + assert_match(/but Cargo.lock is not part of the gem files/, e.message) + end + end + + def test_validate_rust_extension_have_no_missing_cargo_toml_error + util_setup_validate + + Dir.chdir @tempdir do + @a1.extensions = ["Cargo.toml"] + @a1.files << "Cargo.toml" + @a1.files << "Cargo.lock" + File.write File.join(@tempdir, "Cargo.toml"), "" + File.write File.join(@tempdir, "Cargo.lock"), "" + + use_ui @ui do + @a1.validate + end end end @@ -2835,23 +2983,31 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: end def test_validate_empty_require_paths - if win_platform? - pend "test_validate_empty_require_paths skipped on MS Windows (symlink)" - else - util_setup_validate + util_setup_validate - @a1.require_paths = [] - e = assert_raise Gem::InvalidSpecificationException do - @a1.validate - end + @a1.require_paths = [] + e = assert_raise Gem::InvalidSpecificationException do + @a1.validate + end - assert_equal "specification must have at least one require_path", - e.message + assert_equal "specification must have at least one require_path", + e.message + end + + def test_validate_require_paths_with_invalid_types + util_setup_validate + + @a1.require_paths = [1, 2] + e = assert_raise Gem::InvalidSpecificationException do + @a1.validate end + + assert_equal "require_paths must be an Array of String", + e.message end def test_validate_files - pend "test_validate_files skipped on MS Windows (symlink)" if win_platform? + pend "test_validate_files skipped on MS Windows (symlink)" if Gem.win_platform? util_setup_validate @a1.files += ["lib", "lib2"] @@ -2880,7 +3036,7 @@ duplicate dependency on c (>= 1.2.3, development), (~> 1.2) use: { b: Gem::Dependency.new("x","1") } end - specification.define_singleton_method(:find_all_by_name) do |dep_name| + specification.define_singleton_method(:find_all_by_name) do |_dep_name| [] end @@ -2907,7 +3063,7 @@ Please report a bug if this causes problems. { b: Gem::Dependency.new("x","1") } end - specification.define_singleton_method(:find_all_by_name) do |dep_name| + specification.define_singleton_method(:find_all_by_name) do |_dep_name| [ specification.new {|s| s.name = "z", s.version = Gem::Version.new("1") }, specification.new {|s| s.name = "z", s.version = Gem::Version.new("2") }, @@ -2934,7 +3090,7 @@ Please report a bug if this causes problems. def test_duplicate_runtime_dependency expected = "WARNING: duplicated b dependency [\"~> 3.0\", \"~> 3.0\"]\n" out, err = capture_output do - @a1.add_runtime_dependency "b", "~> 3.0", "~> 3.0" + @a1.add_dependency "b", "~> 3.0", "~> 3.0" end assert_empty out assert_equal(expected, err) @@ -2942,7 +3098,7 @@ Please report a bug if this causes problems. def set_orig(cls) s_cls = cls.singleton_class - s_cls.send :alias_method, :orig_unresolved_deps , :unresolved_deps + s_cls.send :alias_method, :orig_unresolved_deps, :unresolved_deps s_cls.send :alias_method, :orig_find_all_by_name, :find_all_by_name end @@ -3015,11 +3171,23 @@ Please report a bug if this causes problems. end assert_match <<-WARNING, @ui.error -WARNING: licenses is empty, but is recommended. Use a license identifier from -http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. +WARNING: licenses is empty, but is recommended. Use an license identifier from +https://spdx.org/licenses or 'Nonstandard' for a nonstandard license, +or set it to nil if you don't want to specify a license. WARNING end + def test_validate_nil_license + util_setup_validate + + use_ui @ui do + @a1.license = nil + @a1.validate + end + + assert_empty @ui.error + end + def test_validate_license_in_a_non_packaging_context util_setup_validate @@ -3032,7 +3200,7 @@ http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. end def test_removed_methods - assert_equal Gem::Specification::REMOVED_METHODS, [:rubyforge_project=] + assert_equal Gem::Specification::REMOVED_METHODS, [:rubyforge_project=, :mark_version] end def test_validate_removed_rubyforge_project @@ -3055,8 +3223,9 @@ http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. end assert_match <<-WARNING, @ui.error -WARNING: license value 'BSD' is invalid. Use a license identifier from -http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. +WARNING: License identifier 'BSD' is invalid. Use an identifier from +https://spdx.org/licenses or 'Nonstandard' for a nonstandard license, +or set it to nil if you don't want to specify a license. WARNING end @@ -3071,7 +3240,7 @@ http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. assert_empty @ui.error end - def test_validate_license_values_plus + def test_validate_deprecated_license_values_plus util_setup_validate use_ui @ui do @@ -3079,7 +3248,11 @@ http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. @a1.validate end - assert_empty @ui.error + assert_match <<-WARNING, @ui.error +WARNING: License identifier 'GPL-2.0+' is deprecated. Use an identifier from +https://spdx.org/licenses or 'Nonstandard' for a nonstandard license, +or set it to nil if you don't want to specify a license. + WARNING end def test_validate_license_values_or_later @@ -3097,7 +3270,7 @@ http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. util_setup_validate use_ui @ui do - @a1.licenses = ["GPL-2.0+ WITH Autoconf-exception-2.0"] + @a1.licenses = ["GPL-2.0-or-later WITH Autoconf-exception-2.0"] @a1.validate end @@ -3113,12 +3286,14 @@ http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. end assert_match <<-WARNING, @ui.error -WARNING: license value 'GPL-2.0+ FOO' is invalid. Use a license identifier from -http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. +WARNING: License identifier 'GPL-2.0+ FOO' is invalid. Use an identifier from +https://spdx.org/licenses or 'Nonstandard' for a nonstandard license, +or set it to nil if you don't want to specify a license. WARNING assert_match <<-WARNING, @ui.error -WARNING: license value 'GPL-2.0 FOO' is invalid. Use a license identifier from -http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. +WARNING: License identifier 'GPL-2.0+ FOO' is invalid. Use an identifier from +https://spdx.org/licenses or 'Nonstandard' for a nonstandard license, +or set it to nil if you don't want to specify a license. WARNING end @@ -3126,13 +3301,29 @@ http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. util_setup_validate use_ui @ui do - @a1.licenses = ["GPL-2.0+ WITH Autocofn-exception-2.0"] + @a1.licenses = ["GPL-2.0-only WITH Autocofn-exception-2.0"] + @a1.validate + end + + assert_match <<-WARNING, @ui.error +WARNING: License identifier 'GPL-2.0-only WITH Autocofn-exception-2.0' is invalid. Use an identifier from +https://spdx.org/licenses or 'Nonstandard' for a nonstandard license, +or set it to nil if you don't want to specify a license. + WARNING + end + + def test_validate_license_with_deprecated_exception + util_setup_validate + + use_ui @ui do + @a1.licenses = ["GPL-2.0-only WITH Nokia-Qt-exception-1.1"] @a1.validate end assert_match <<-WARNING, @ui.error -WARNING: license value 'GPL-2.0+ WITH Autocofn-exception-2.0' is invalid. Use a license identifier from -http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. +WARNING: Exception identifier at 'GPL-2.0-only WITH Nokia-Qt-exception-1.1' is deprecated. Use an identifier from +https://spdx.org/licenses or 'Nonstandard' for a nonstandard license, +or set it to nil if you don't want to specify a license. WARNING end @@ -3145,8 +3336,9 @@ http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. end assert_match <<-WARNING, @ui.error -WARNING: license value 'ruby' is invalid. Use a license identifier from -http://spdx.org/licenses or 'Nonstandard' for a nonstandard license. +WARNING: License identifier 'ruby' is invalid. Use an identifier from +https://spdx.org/licenses or 'Nonstandard' for a nonstandard license, +or set it to nil if you don't want to specify a license. Did you mean 'Ruby'? WARNING end @@ -3244,7 +3436,7 @@ Did you mean 'Ruby'? spec.validate end - assert_match %r{^#{name}}, e.message + assert_match(/^#{name}/, e.message) end end end @@ -3255,8 +3447,8 @@ Did you mean 'Ruby'? util_setup_validate Dir.chdir @tempdir do - File.chmod 0640, File.join("lib", "code.rb") - File.chmod 0640, File.join("bin", "exec") + File.chmod 0o640, File.join("lib", "code.rb") + File.chmod 0o640, File.join("bin", "exec") use_ui @ui do @a1.validate @@ -3301,12 +3493,17 @@ Did you mean 'Ruby'? util_setup_validate @a1.rubygems_version = "3" - e = assert_raise Gem::InvalidSpecificationException do + + use_ui @ui do @a1.validate end - assert_equal "expected RubyGems version #{Gem::VERSION}, was 3", - e.message + expected = <<~EXPECTED + #{w}: expected RubyGems version #{Gem::VERSION}, was 3 + #{w}: See https://guides.rubygems.org/specification-reference/ for help + EXPECTED + + assert_equal expected, @ui.error end def test_validate_specification_version @@ -3404,7 +3601,7 @@ Did you mean 'Ruby'? capture_output do Gem::Specification.load(specfile.path) end - rescue => e + rescue StandardError => e name_rexp = Regexp.new(Regexp.escape(specfile.path)) assert e.backtrace.grep(name_rexp).any? end @@ -3547,6 +3744,39 @@ Did you mean 'Ruby'? end end + def test_metadata_link_validation_warns_for_duplicates + util_setup_validate + + Dir.chdir @tempdir do + @m2 = quick_gem "m", "2" do |s| + s.required_ruby_version = ">= 2.3.0" + s.files = %w[lib/code.rb] + s.licenses = "BSD-2-Clause" + s.metadata = { + "source_code_uri" => "http://example.com", + "homepage_uri" => "http://example.com", + "changelog_uri" => "http://example.com/changelog", + } + end + + use_ui @ui do + @m2.validate + end + + expected = <<~EXPECTED + #{w}: You have specified the uri: + http://example.com + for all of the following keys: + homepage_uri + source_code_uri + Only the first one will be shown on rubygems.org + #{w}: See https://guides.rubygems.org/specification-reference/ for help + EXPECTED + + assert_equal expected, @ui.error, "warning" + end + end + def test_metadata_specs @m1 = quick_gem "m", "1" do |s| s.files = %w[lib/code.rb] @@ -3559,7 +3789,7 @@ Did you mean 'Ruby'? Gem::Specification.new do |s| s.name = "m".freeze - s.version = "1" + s.version = "1".freeze s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version= s.metadata = { "one" => "two", "two" => "three" } if s.respond_to? :metadata= @@ -3658,6 +3888,13 @@ end assert Gem::Specification.find_by_name "q" end + def test_find_by_name_with_only_prereleases_with_requirements + q = util_spec "q", "2.a" + install_specs q + + assert Gem::Specification.find_by_name "q", ">= 1" + end + def test_find_by_name_prerelease b = util_spec "b", "2.a" @@ -3676,6 +3913,23 @@ end assert Gem::Specification.find_by_name "b", ">1" end + def test_find_by_full_name + pl = Gem::Platform.new "x86_64-linux" + + a = util_spec "a", "1" + install_specs a + + a_pl = util_spec("a", "1") {|s| s.platform = pl } + install_specs a_pl + + assert_equal a, Gem::Specification.find_by_full_name("a-1") + assert_equal a_pl, Gem::Specification.find_by_full_name("a-1-x86_64-linux") + + assert_nil Gem::Specification.find_by_full_name("a-2") + assert_nil Gem::Specification.find_by_full_name("b-1") + assert_nil Gem::Specification.find_by_full_name("a-1-arm64-linux") + end + def test_find_by_path a = util_spec "foo", "1", nil, "lib/foo.rb" @@ -3710,6 +3964,40 @@ end assert_equal ["default-2.0.0.0"], Gem::Specification.map(&:full_name) end + def test_validate_for_resolution_validates_required_attributes + e = assert_raise Gem::InvalidSpecificationException do + @a1.name = nil + @a1.validate_for_resolution + end + + assert_equal "missing value for attribute name", e.message + end + + def test_validate_for_resolution_validates_name + e = assert_raise Gem::InvalidSpecificationException do + @a1.name = 123 + @a1.validate_for_resolution + end + + assert_equal 'invalid value for attribute name: "123" must be a string', e.message + end + + def test_validate_for_resolution_validates_duplicate_dependencies + e = assert_raise Gem::InvalidSpecificationException do + @a1.add_dependency "foo", "1.2.3" + @a1.add_dependency "foo", "3.4.5" + @a1.validate_for_resolution + end + + assert_match "duplicate dependency on foo", e.message + end + + def test_validate_for_resolution_ignores_metadata + @a1.summary = "TODO: Invalid summary" + @a1.metadata["homepage_uri"] = "TODO: Invalid homepage URI" + @a1.validate_for_resolution + end + def util_setup_deps @gem = util_spec "awesome", "1.0" do |awesome| awesome.add_runtime_dependency "bonobo", [] @@ -3733,7 +4021,7 @@ end FileUtils.touch File.join("lib", "code.rb") FileUtils.touch File.join("test", "suite.rb") - File.open "bin/exec", "w", 0755 do |fp| + File.open "bin/exec", "w", 0o755 do |fp| fp.puts "#!#{Gem.ruby}" end ensure |