From c3546c76c8f1c9d61e65d08e8b2dfca2e2098736 Mon Sep 17 00:00:00 2001 From: hsbt Date: Thu, 5 Feb 2015 13:42:45 +0000 Subject: * lib/rubygems: Update to RubyGems HEAD(5c3b6f3). Fixed #1156, #1142, #1115, #1142, #1139 on rubygems/rubygems * test/rubygems: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49511 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 + lib/rubygems/basic_specification.rb | 2 +- lib/rubygems/commands/open_command.rb | 4 +- lib/rubygems/installer.rb | 2 +- lib/rubygems/request_set.rb | 12 +- lib/rubygems/request_set/lockfile.rb | 445 +---------- lib/rubygems/request_set/lockfile/parser.rb | 334 +++++++++ lib/rubygems/request_set/lockfile/tokenizer.rb | 108 +++ lib/rubygems/requirement.rb | 2 +- lib/rubygems/specification.rb | 18 +- lib/rubygems/test_case.rb | 4 +- lib/rubygems/user_interaction.rb | 8 - test/rubygems/test_gem_commands_open_command.rb | 12 +- .../test_gem_request_set_gem_dependency_api.rb | 19 + test/rubygems/test_gem_request_set_lockfile.rb | 810 +-------------------- .../test_gem_request_set_lockfile_parser.rb | 543 ++++++++++++++ .../test_gem_request_set_lockfile_tokenizer.rb | 305 ++++++++ test/rubygems/test_gem_requirement.rb | 10 + test/rubygems/test_gem_specification.rb | 8 +- test/rubygems/test_gem_stub_specification.rb | 2 +- 20 files changed, 1391 insertions(+), 1263 deletions(-) create mode 100644 lib/rubygems/request_set/lockfile/parser.rb create mode 100644 lib/rubygems/request_set/lockfile/tokenizer.rb create mode 100644 test/rubygems/test_gem_request_set_lockfile_parser.rb create mode 100644 test/rubygems/test_gem_request_set_lockfile_tokenizer.rb diff --git a/ChangeLog b/ChangeLog index 181000d4e7..590f16cfec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Thu Feb 5 22:42:34 2015 SHIBATA Hiroshi + + * lib/rubygems: Update to RubyGems HEAD(5c3b6f3). + Fixed #1156, #1142, #1115, #1142, #1139 on rubygems/rubygems + * test/rubygems: ditto. + Thu Feb 5 13:41:01 2015 Nobuyoshi Nakada * vm_eval.c (send_internal), vm_insnhelper.c (vm_call_opt_send): diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb index d1cee4f36d..e27b261d7e 100644 --- a/lib/rubygems/basic_specification.rb +++ b/lib/rubygems/basic_specification.rb @@ -144,7 +144,7 @@ class Gem::BasicSpecification File.join full_gem_path, path end - full_paths.unshift extension_dir unless @extensions.nil? || @extensions.empty? + full_paths << extension_dir unless @extensions.nil? || @extensions.empty? full_paths end diff --git a/lib/rubygems/commands/open_command.rb b/lib/rubygems/commands/open_command.rb index 91963bba73..254a74275e 100644 --- a/lib/rubygems/commands/open_command.rb +++ b/lib/rubygems/commands/open_command.rb @@ -61,7 +61,9 @@ class Gem::Commands::OpenCommand < Gem::Command end def open_editor path - system(*@editor.split(/\s+/) + [path]) + Dir.chdir(path) do + system(*@editor.split(/\s+/) + [path]) + end end def spec_for name diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 877cb21b7c..10fc1a34a5 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -681,7 +681,7 @@ TEXT # return the stub script text used to launch the true Ruby script def windows_stub_script(bindir, bin_file_name) - ruby = Gem.ruby.chomp('"').tr(File::SEPARATOR, "\\") + ruby = Gem.ruby.gsub(/^\"|\"$/, "").tr(File::SEPARATOR, "\\") return <<-TEXT @ECHO OFF IF NOT "%~f0" == "~f0" GOTO :WinNT diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index 05bfcbee2c..819a1d8e2d 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -116,7 +116,7 @@ class Gem::RequestSet if dep = @dependency_names[name] then dep.requirement.concat reqs else - dep = Gem::Dependency.new name, reqs + dep = Gem::Dependency.new name, *reqs @dependency_names[name] = dep @dependencies << dep end @@ -275,8 +275,13 @@ class Gem::RequestSet @git_set.root_dir = @install_dir - lockfile = Gem::RequestSet::Lockfile.new self, path - lockfile.parse + lock_file = "#{File.expand_path(path)}.lock" + begin + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file lock_file + parser = tokenizer.make_parser self, [] + parser.parse + rescue Errno::ENOENT + end gf = Gem::RequestSet::GemDependencyAPI.new self, path gf.installing = installing @@ -411,3 +416,4 @@ end require 'rubygems/request_set/gem_dependency_api' require 'rubygems/request_set/lockfile' +require 'rubygems/request_set/lockfile/tokenizer' diff --git a/lib/rubygems/request_set/lockfile.rb b/lib/rubygems/request_set/lockfile.rb index 4f2fa0933f..2c788fb703 100644 --- a/lib/rubygems/request_set/lockfile.rb +++ b/lib/rubygems/request_set/lockfile.rb @@ -1,12 +1,9 @@ -require 'strscan' - ## # Parses a gem.deps.rb.lock file and constructs a LockSet containing the # dependencies found inside. If the lock file is missing no LockSet is # constructed. class Gem::RequestSet::Lockfile - ## # Raised when a lockfile cannot be parsed @@ -37,7 +34,6 @@ class Gem::RequestSet::Lockfile @path = path super "#{message} (at line #{line} column #{column})" end - end ## @@ -57,11 +53,7 @@ class Gem::RequestSet::Lockfile @gem_deps_file.untaint unless gem_deps_file.tainted? - @current_token = nil - @line = 0 - @line_pos = 0 @platforms = [] - @tokens = [] end def add_DEPENDENCIES out # :nodoc: @@ -80,7 +72,7 @@ class Gem::RequestSet::Lockfile [name, requirement_string] end else - @requests.sort_by { |r| r.name }.map do |request| + requests.sort_by { |r| r.name }.map do |request| spec = request.spec name = request.name requirement = request.request.dependency.requirement @@ -106,10 +98,10 @@ class Gem::RequestSet::Lockfile out << nil end - def add_GEM out # :nodoc: - return if @spec_groups.empty? + def add_GEM out, spec_groups # :nodoc: + return if spec_groups.empty? - source_groups = @spec_groups.values.flatten.group_by do |request| + source_groups = spec_groups.values.flatten.group_by do |request| request.spec.source.uri end @@ -136,9 +128,8 @@ class Gem::RequestSet::Lockfile end end - def add_GIT out - return unless git_requests = - @spec_groups.delete(Gem::Resolver::GitSpecification) + def add_GIT out, git_requests + return if git_requests.empty? by_repository_revision = git_requests.group_by do |request| source = request.spec.source @@ -179,9 +170,8 @@ class Gem::RequestSet::Lockfile end end - def add_PATH out # :nodoc: - return unless path_requests = - @spec_groups.delete(Gem::Resolver::VendorSpecification) + def add_PATH out, path_requests # :nodoc: + return if path_requests.empty? out << "PATH" path_requests.each do |request| @@ -198,7 +188,7 @@ class Gem::RequestSet::Lockfile def add_PLATFORMS out # :nodoc: out << "PLATFORMS" - platforms = @requests.map { |request| request.spec.platform }.uniq + platforms = requests.map { |request| request.spec.platform }.uniq platforms = platforms.sort_by { |platform| platform.to_s } @@ -209,319 +199,8 @@ class Gem::RequestSet::Lockfile out << nil end - ## - # Gets the next token for a Lockfile - - def get expected_types = nil, expected_value = nil # :nodoc: - @current_token = @tokens.shift - - type, value, column, line = @current_token - - if expected_types and not Array(expected_types).include? type then - unget - - message = "unexpected token [#{type.inspect}, #{value.inspect}], " + - "expected #{expected_types.inspect}" - - raise ParseError.new message, column, line, "#{@gem_deps_file}.lock" - end - - if expected_value and expected_value != value then - unget - - message = "unexpected token [#{type.inspect}, #{value.inspect}], " + - "expected [#{expected_types.inspect}, " + - "#{expected_value.inspect}]" - - raise ParseError.new message, column, line, "#{@gem_deps_file}.lock" - end - - @current_token - end - - def parse # :nodoc: - tokenize - - until @tokens.empty? do - type, data, column, line = get - - case type - when :section then - skip :newline - - case data - when 'DEPENDENCIES' then - parse_DEPENDENCIES - when 'GIT' then - parse_GIT - when 'GEM' then - parse_GEM - when 'PATH' then - parse_PATH - when 'PLATFORMS' then - parse_PLATFORMS - else - type, = get until @tokens.empty? or peek.first == :section - end - else - raise "BUG: unhandled token #{type} (#{data.inspect}) at line #{line} column #{column}" - end - end - end - - def parse_DEPENDENCIES # :nodoc: - while not @tokens.empty? and :text == peek.first do - _, name, = get :text - - requirements = [] - - case peek[0] - when :bang then - get :bang - - requirements << pinned_requirement(name) - when :l_paren then - get :l_paren - - loop do - _, op, = get :requirement - _, version, = get :text - - requirements << "#{op} #{version}" - - break unless peek[0] == :comma - - get :comma - end - - get :r_paren - - if peek[0] == :bang then - requirements.clear - requirements << pinned_requirement(name) - - get :bang - end - end - - @set.gem name, *requirements - - skip :newline - end - end - - def parse_GEM # :nodoc: - sources = [] - - while [:entry, 'remote'] == peek.first(2) do - get :entry, 'remote' - _, data, = get :text - skip :newline - - sources << Gem::Source.new(data) - end - - sources << Gem::Source.new(Gem::DEFAULT_HOST) if sources.empty? - - get :entry, 'specs' - - skip :newline - - set = Gem::Resolver::LockSet.new sources - last_specs = nil - - while not @tokens.empty? and :text == peek.first do - _, name, column, = get :text - - case peek[0] - when :newline then - last_specs.each do |spec| - spec.add_dependency Gem::Dependency.new name if column == 6 - end - when :l_paren then - get :l_paren - - type, data, = get [:text, :requirement] - - if type == :text and column == 4 then - version, platform = data.split '-', 2 - - platform = - platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY - - last_specs = set.add name, version, platform - else - dependency = parse_dependency name, data - - last_specs.each do |spec| - spec.add_dependency dependency - end - end - - get :r_paren - else - raise "BUG: unknown token #{peek}" - end - - skip :newline - end - - @set.sets << set - end - - def parse_GIT # :nodoc: - get :entry, 'remote' - _, repository, = get :text - - skip :newline - - get :entry, 'revision' - _, revision, = get :text - - skip :newline - - type, value = peek.first 2 - if type == :entry and %w[branch ref tag].include? value then - get - get :text - - skip :newline - end - - get :entry, 'specs' - - skip :newline - - set = Gem::Resolver::GitSet.new - set.root_dir = @set.install_dir - - last_spec = nil - - while not @tokens.empty? and :text == peek.first do - _, name, column, = get :text - - case peek[0] - when :newline then - last_spec.add_dependency Gem::Dependency.new name if column == 6 - when :l_paren then - get :l_paren - - type, data, = get [:text, :requirement] - - if type == :text and column == 4 then - last_spec = set.add_git_spec name, data, repository, revision, true - else - dependency = parse_dependency name, data - - last_spec.add_dependency dependency - end - - get :r_paren - else - raise "BUG: unknown token #{peek}" - end - - skip :newline - end - - @set.sets << set - end - - def parse_PATH # :nodoc: - get :entry, 'remote' - _, directory, = get :text - - skip :newline - - get :entry, 'specs' - - skip :newline - - set = Gem::Resolver::VendorSet.new - last_spec = nil - - while not @tokens.empty? and :text == peek.first do - _, name, column, = get :text - - case peek[0] - when :newline then - last_spec.add_dependency Gem::Dependency.new name if column == 6 - when :l_paren then - get :l_paren - - type, data, = get [:text, :requirement] - - if type == :text and column == 4 then - last_spec = set.add_vendor_gem name, directory - else - dependency = parse_dependency name, data - - last_spec.dependencies << dependency - end - - get :r_paren - else - raise "BUG: unknown token #{peek}" - end - - skip :newline - end - - @set.sets << set - end - - def parse_PLATFORMS # :nodoc: - while not @tokens.empty? and :text == peek.first do - _, name, = get :text - - @platforms << name - - skip :newline - end - end - - ## - # Parses the requirements following the dependency +name+ and the +op+ for - # the first token of the requirements and returns a Gem::Dependency object. - - def parse_dependency name, op # :nodoc: - return Gem::Dependency.new name, op unless peek[0] == :text - - _, version, = get :text - - requirements = ["#{op} #{version}"] - - while peek[0] == :comma do - get :comma - _, op, = get :requirement - _, version, = get :text - - requirements << "#{op} #{version}" - end - - Gem::Dependency.new name, requirements - end - - ## - # Peeks at the next token for Lockfile - - def peek # :nodoc: - @tokens.first || [:EOF] - end - - def pinned_requirement name # :nodoc: - spec = @set.sets.select { |set| - Gem::Resolver::GitSet === set or - Gem::Resolver::VendorSet === set - }.map { |set| - set.specs[name] - }.compact.first - - spec.version - end - - def skip type # :nodoc: - get while not @tokens.empty? and peek.first == type + def spec_groups + requests.group_by { |request| request.spec.class } end ## @@ -532,17 +211,13 @@ class Gem::RequestSet::Lockfile out = [] - @requests = @set.sorted_requests - - @spec_groups = @requests.group_by do |request| - request.spec.class - end + groups = spec_groups - add_PATH out + add_PATH out, groups.delete(Gem::Resolver::VendorSpecification) { [] } - add_GIT out + add_GIT out, groups.delete(Gem::Resolver::GitSpecification) { [] } - add_GEM out + add_GEM out, groups add_PLATFORMS out @@ -551,90 +226,6 @@ class Gem::RequestSet::Lockfile out.join "\n" end - ## - # Calculates the column (by byte) and the line of the current token based on - # +byte_offset+. - - def token_pos byte_offset # :nodoc: - [byte_offset - @line_pos, @line] - end - - ## - # Converts a lock file into an Array of tokens. If the lock file is missing - # an empty Array is returned. - - def tokenize # :nodoc: - @line = 0 - @line_pos = 0 - - @platforms = [] - @tokens = [] - @current_token = nil - - lock_file = "#{@gem_deps_file}.lock" - - @input = File.read lock_file - s = StringScanner.new @input - - until s.eos? do - pos = s.pos - - pos = s.pos if leading_whitespace = s.scan(/ +/) - - if s.scan(/[<|=>]{7}/) then - message = "your #{lock_file} contains merge conflict markers" - column, line = token_pos pos - - raise ParseError.new message, column, line, lock_file - end - - @tokens << - case - when s.scan(/\r?\n/) then - token = [:newline, nil, *token_pos(pos)] - @line_pos = s.pos - @line += 1 - token - when s.scan(/[A-Z]+/) then - if leading_whitespace then - text = s.matched - text += s.scan(/[^\s)]*/).to_s # in case of no match - [:text, text, *token_pos(pos)] - else - [:section, s.matched, *token_pos(pos)] - end - when s.scan(/([a-z]+):\s/) then - s.pos -= 1 # rewind for possible newline - [:entry, s[1], *token_pos(pos)] - when s.scan(/\(/) then - [:l_paren, nil, *token_pos(pos)] - when s.scan(/\)/) then - [:r_paren, nil, *token_pos(pos)] - when s.scan(/<=|>=|=|~>|<|>|!=/) then - [:requirement, s.matched, *token_pos(pos)] - when s.scan(/,/) then - [:comma, nil, *token_pos(pos)] - when s.scan(/!/) then - [:bang, nil, *token_pos(pos)] - when s.scan(/[^\s),!]*/) then - [:text, s.matched, *token_pos(pos)] - else - raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}" - end - end - - @tokens - rescue Errno::ENOENT - @tokens - end - - ## - # Ungets the last token retrieved by #get - - def unget # :nodoc: - @tokens.unshift @current_token - end - ## # Writes the lock file alongside the gem dependencies file @@ -646,5 +237,11 @@ class Gem::RequestSet::Lockfile end end + private + + def requests + @set.sorted_requests + end end +require 'rubygems/request_set/lockfile/tokenizer' diff --git a/lib/rubygems/request_set/lockfile/parser.rb b/lib/rubygems/request_set/lockfile/parser.rb new file mode 100644 index 0000000000..7778b7ae17 --- /dev/null +++ b/lib/rubygems/request_set/lockfile/parser.rb @@ -0,0 +1,334 @@ +class Gem::RequestSet::Lockfile::Parser + ### + # Parses lockfiles + + def initialize tokenizer, set, platforms, filename = nil + @tokens = tokenizer + @filename = filename + @set = set + @platforms = platforms + end + + def parse + until @tokens.empty? do + type, data, column, line = get + + case type + when :section then + @tokens.skip :newline + + case data + when 'DEPENDENCIES' then + parse_DEPENDENCIES + when 'GIT' then + parse_GIT + when 'GEM' then + parse_GEM + when 'PATH' then + parse_PATH + when 'PLATFORMS' then + parse_PLATFORMS + else + type, = get until @tokens.empty? or peek.first == :section + end + else + raise "BUG: unhandled token #{type} (#{data.inspect}) at line #{line} column #{column}" + end + end + end + + ## + # Gets the next token for a Lockfile + + def get expected_types = nil, expected_value = nil # :nodoc: + current_token = @tokens.shift + + type, value, column, line = current_token + + if expected_types and not Array(expected_types).include? type then + unget current_token + + message = "unexpected token [#{type.inspect}, #{value.inspect}], " + + "expected #{expected_types.inspect}" + + raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename + end + + if expected_value and expected_value != value then + unget current_token + + message = "unexpected token [#{type.inspect}, #{value.inspect}], " + + "expected [#{expected_types.inspect}, " + + "#{expected_value.inspect}]" + + raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename + end + + current_token + end + + def parse_DEPENDENCIES # :nodoc: + while not @tokens.empty? and :text == peek.first do + _, name, = get :text + + requirements = [] + + case peek[0] + when :bang then + get :bang + + requirements << pinned_requirement(name) + when :l_paren then + get :l_paren + + loop do + _, op, = get :requirement + _, version, = get :text + + requirements << "#{op} #{version}" + + break unless peek[0] == :comma + + get :comma + end + + get :r_paren + + if peek[0] == :bang then + requirements.clear + requirements << pinned_requirement(name) + + get :bang + end + end + + @set.gem name, *requirements + + skip :newline + end + end + + def parse_GEM # :nodoc: + sources = [] + + while [:entry, 'remote'] == peek.first(2) do + get :entry, 'remote' + _, data, = get :text + skip :newline + + sources << Gem::Source.new(data) + end + + sources << Gem::Source.new(Gem::DEFAULT_HOST) if sources.empty? + + get :entry, 'specs' + + skip :newline + + set = Gem::Resolver::LockSet.new sources + last_specs = nil + + while not @tokens.empty? and :text == peek.first do + _, name, column, = get :text + + case peek[0] + when :newline then + last_specs.each do |spec| + spec.add_dependency Gem::Dependency.new name if column == 6 + end + when :l_paren then + get :l_paren + + type, data, = get [:text, :requirement] + + if type == :text and column == 4 then + version, platform = data.split '-', 2 + + platform = + platform ? Gem::Platform.new(platform) : Gem::Platform::RUBY + + last_specs = set.add name, version, platform + else + dependency = parse_dependency name, data + + last_specs.each do |spec| + spec.add_dependency dependency + end + end + + get :r_paren + else + raise "BUG: unknown token #{peek}" + end + + skip :newline + end + + @set.sets << set + end + + def parse_GIT # :nodoc: + get :entry, 'remote' + _, repository, = get :text + + skip :newline + + get :entry, 'revision' + _, revision, = get :text + + skip :newline + + type, value = peek.first 2 + if type == :entry and %w[branch ref tag].include? value then + get + get :text + + skip :newline + end + + get :entry, 'specs' + + skip :newline + + set = Gem::Resolver::GitSet.new + set.root_dir = @set.install_dir + + last_spec = nil + + while not @tokens.empty? and :text == peek.first do + _, name, column, = get :text + + case peek[0] + when :newline then + last_spec.add_dependency Gem::Dependency.new name if column == 6 + when :l_paren then + get :l_paren + + type, data, = get [:text, :requirement] + + if type == :text and column == 4 then + last_spec = set.add_git_spec name, data, repository, revision, true + else + dependency = parse_dependency name, data + + last_spec.add_dependency dependency + end + + get :r_paren + else + raise "BUG: unknown token #{peek}" + end + + skip :newline + end + + @set.sets << set + end + + def parse_PATH # :nodoc: + get :entry, 'remote' + _, directory, = get :text + + skip :newline + + get :entry, 'specs' + + skip :newline + + set = Gem::Resolver::VendorSet.new + last_spec = nil + + while not @tokens.empty? and :text == peek.first do + _, name, column, = get :text + + case peek[0] + when :newline then + last_spec.add_dependency Gem::Dependency.new name if column == 6 + when :l_paren then + get :l_paren + + type, data, = get [:text, :requirement] + + if type == :text and column == 4 then + last_spec = set.add_vendor_gem name, directory + else + dependency = parse_dependency name, data + + last_spec.dependencies << dependency + end + + get :r_paren + else + raise "BUG: unknown token #{peek}" + end + + skip :newline + end + + @set.sets << set + end + + def parse_PLATFORMS # :nodoc: + while not @tokens.empty? and :text == peek.first do + _, name, = get :text + + @platforms << name + + skip :newline + end + end + + ## + # Parses the requirements following the dependency +name+ and the +op+ for + # the first token of the requirements and returns a Gem::Dependency object. + + def parse_dependency name, op # :nodoc: + return Gem::Dependency.new name, op unless peek[0] == :text + + _, version, = get :text + + requirements = ["#{op} #{version}"] + + while peek[0] == :comma do + get :comma + _, op, = get :requirement + _, version, = get :text + + requirements << "#{op} #{version}" + end + + Gem::Dependency.new name, requirements + end + + private + + def skip type # :nodoc: + @tokens.skip type + end + + ## + # Peeks at the next token for Lockfile + + def peek # :nodoc: + @tokens.peek + end + + def pinned_requirement name # :nodoc: + spec = @set.sets.select { |set| + Gem::Resolver::GitSet === set or + Gem::Resolver::VendorSet === set + }.map { |set| + set.specs[name] + }.compact.first + + spec.version + end + + ## + # Ungets the last token retrieved by #get + + def unget token # :nodoc: + @tokens.unshift token + end +end + diff --git a/lib/rubygems/request_set/lockfile/tokenizer.rb b/lib/rubygems/request_set/lockfile/tokenizer.rb new file mode 100644 index 0000000000..73c9a834bb --- /dev/null +++ b/lib/rubygems/request_set/lockfile/tokenizer.rb @@ -0,0 +1,108 @@ +require 'strscan' +require 'rubygems/request_set/lockfile/parser' + +class Gem::RequestSet::Lockfile::Tokenizer + def self.from_file file + new File.read(file), file + end + + def initialize input, filename = nil, line = 0, pos = 0 + @line = line + @line_pos = pos + @tokens = [] + @filename = filename + tokenize input + end + + def make_parser set, platforms + Gem::RequestSet::Lockfile::Parser.new self, set, platforms, @filename + end + + def to_a + @tokens + end + + def skip type + @tokens.shift while not @tokens.empty? and peek.first == type + end + + ## + # Calculates the column (by byte) and the line of the current token based on + # +byte_offset+. + + def token_pos byte_offset # :nodoc: + [byte_offset - @line_pos, @line] + end + + def empty? + @tokens.empty? + end + + def unshift token + @tokens.unshift token + end + + def next_token + @tokens.shift + end + alias :shift :next_token + + def peek + @tokens.first || [:EOF] + end + + private + + def tokenize input + s = StringScanner.new input + + until s.eos? do + pos = s.pos + + pos = s.pos if leading_whitespace = s.scan(/ +/) + + if s.scan(/[<|=>]{7}/) then + message = "your #{@filename} contains merge conflict markers" + column, line = token_pos pos + + raise Gem::RequestSet::Lockfile::ParseError.new message, column, line, @filename + end + + @tokens << + case + when s.scan(/\r?\n/) then + token = [:newline, nil, *token_pos(pos)] + @line_pos = s.pos + @line += 1 + token + when s.scan(/[A-Z]+/) then + if leading_whitespace then + text = s.matched + text += s.scan(/[^\s)]*/).to_s # in case of no match + [:text, text, *token_pos(pos)] + else + [:section, s.matched, *token_pos(pos)] + end + when s.scan(/([a-z]+):\s/) then + s.pos -= 1 # rewind for possible newline + [:entry, s[1], *token_pos(pos)] + when s.scan(/\(/) then + [:l_paren, nil, *token_pos(pos)] + when s.scan(/\)/) then + [:r_paren, nil, *token_pos(pos)] + when s.scan(/<=|>=|=|~>|<|>|!=/) then + [:requirement, s.matched, *token_pos(pos)] + when s.scan(/,/) then + [:comma, nil, *token_pos(pos)] + when s.scan(/!/) then + [:bang, nil, *token_pos(pos)] + when s.scan(/[^\s),!]*/) then + [:text, s.matched, *token_pos(pos)] + else + raise "BUG: can't create token for: #{s.string[s.pos..-1].inspect}" + end + end + + @tokens + end +end diff --git a/lib/rubygems/requirement.rb b/lib/rubygems/requirement.rb index 8b6a81612c..bcf5fb967e 100644 --- a/lib/rubygems/requirement.rb +++ b/lib/rubygems/requirement.rb @@ -171,7 +171,7 @@ class Gem::Requirement end def hash # :nodoc: - requirements.hash + requirements.sort.hash end def marshal_dump # :nodoc: diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 631bb7a0d3..eb89c4c97b 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -1028,8 +1028,8 @@ class Gem::Specification < Gem::BasicSpecification file = file.dup.untaint return unless File.file?(file) - spec = LOAD_CACHE[file] - return spec if spec + _spec = LOAD_CACHE[file] + return _spec if _spec code = if defined? Encoding File.read file, :mode => 'r:UTF-8:-' @@ -1040,15 +1040,15 @@ class Gem::Specification < Gem::BasicSpecification code.untaint begin - spec = eval code, binding, file + _spec = eval code, binding, file - if Gem::Specification === spec - spec.loaded_from = File.expand_path file.to_s - LOAD_CACHE[file] = spec - return spec + if Gem::Specification === _spec + _spec.loaded_from = File.expand_path file.to_s + LOAD_CACHE[file] = _spec + return _spec end - warn "[#{file}] isn't a Gem::Specification (#{spec.class} instead)." + warn "[#{file}] isn't a Gem::Specification (#{_spec.class} instead)." rescue SignalException, SystemExit raise rescue SyntaxError, Exception => e @@ -1350,7 +1350,7 @@ class Gem::Specification < Gem::BasicSpecification end unless dependency.respond_to?(:name) && - dependency.respond_to?(:version_requirements) + dependency.respond_to?(:requirement) dependency = Gem::Dependency.new(dependency.to_s, requirements, type) end diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index 5dc7a1b67c..cb2e2b8be7 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -1427,4 +1427,6 @@ Also, a list: end require 'rubygems/test_utilities' - +ENV['GEM_HOME'] = Dir.mktmpdir "home" +ENV['GEM_PATH'] = Dir.mktmpdir "path" +Gem.clear_paths diff --git a/lib/rubygems/user_interaction.rb b/lib/rubygems/user_interaction.rb index 44ff2d33ff..78d37906c9 100644 --- a/lib/rubygems/user_interaction.rb +++ b/lib/rubygems/user_interaction.rb @@ -396,10 +396,6 @@ class Gem::StreamUI # Return a progress reporter object chosen from the current verbosity. def progress_reporter(*args) - if self.kind_of?(Gem::SilentUI) - return SilentProgressReporter.new(@outs, *args) - end - case Gem.configuration.verbose when nil, false SilentProgressReporter.new(@outs, *args) @@ -533,10 +529,6 @@ class Gem::StreamUI # Return a download reporter object chosen from the current verbosity def download_reporter(*args) - if self.kind_of?(Gem::SilentUI) - return SilentDownloadReporter.new(@outs, *args) - end - case Gem.configuration.verbose when nil, false SilentDownloadReporter.new(@outs, *args) diff --git a/test/rubygems/test_gem_commands_open_command.rb b/test/rubygems/test_gem_commands_open_command.rb index 25f22c81b3..c1c76f95c9 100644 --- a/test/rubygems/test_gem_commands_open_command.rb +++ b/test/rubygems/test_gem_commands_open_command.rb @@ -15,18 +15,24 @@ class TestGemCommandsOpenCommand < Gem::TestCase end write_file File.join(*%W[gems #{spec.full_name} lib #{name}.rb]) write_file File.join(*%W[gems #{spec.full_name} Rakefile]) + spec end def test_execute @cmd.options[:args] = %w[foo] @cmd.options[:editor] = "#{Gem.ruby} -e0 --" - gem 'foo' + spec = gem 'foo' + mock = MiniTest::Mock.new + mock.expect(:call, true, [spec.full_gem_path]) - use_ui @ui do - @cmd.execute + Dir.stub(:chdir, mock) do + use_ui @ui do + @cmd.execute + end end + assert mock.verify assert_equal "", @ui.error end diff --git a/test/rubygems/test_gem_request_set_gem_dependency_api.rb b/test/rubygems/test_gem_request_set_gem_dependency_api.rb index 65b30f83bf..32c03bacf6 100644 --- a/test/rubygems/test_gem_request_set_gem_dependency_api.rb +++ b/test/rubygems/test_gem_request_set_gem_dependency_api.rb @@ -50,6 +50,25 @@ class TestGemRequestSetGemDependencyAPI < Gem::TestCase Gem.instance_variables.include? :@ruby_version end + def test_gempspec_with_multiple_runtime_deps + gda = Class.new(@GDA) do + # implement find_gemspec so we don't need one on the FS + def find_gemspec name, path + Gem::Specification.new do |s| + s.name = 'foo' + s.version = '1.0' + s.add_runtime_dependency 'bar', '>= 1.6.0', '< 1.6.4' + end + end + end + instance = gda.new @set, __FILE__ + instance.gemspec + assert_equal %w{ foo bar }.sort, @set.dependencies.map(&:name).sort + bar = @set.dependencies.find { |d| d.name == 'bar' } + assert_equal [[">=", Gem::Version.create('1.6.0')], + ["<", Gem::Version.create('1.6.4')]], bar.requirement.requirements + end + def test_gemspec_without_group @gda.send :add_dependencies, [:development], [dep('a', '= 1')] diff --git a/test/rubygems/test_gem_request_set_lockfile.rb b/test/rubygems/test_gem_request_set_lockfile.rb index 7c5cd5a295..f825a8b359 100644 --- a/test/rubygems/test_gem_request_set_lockfile.rb +++ b/test/rubygems/test_gem_request_set_lockfile.rb @@ -24,12 +24,6 @@ class TestGemRequestSetLockfile < Gem::TestCase @lockfile = Gem::RequestSet::Lockfile.new @set, @gem_deps_file end - def write_gem_deps gem_deps - open @gem_deps_file, 'w' do |io| - io.write gem_deps - end - end - def write_lockfile lockfile @lock_file = File.expand_path "#{@gem_deps_file}.lock" @@ -47,7 +41,6 @@ class TestGemRequestSetLockfile < Gem::TestCase @set.gem 'a' @set.resolve - @lockfile.instance_variable_set :@requests, @set.sorted_requests out = [] @@ -75,7 +68,6 @@ class TestGemRequestSetLockfile < Gem::TestCase @set.resolve @lockfile = Gem::RequestSet::Lockfile.new @set, @gem_deps_file, dependencies - @lockfile.instance_variable_set :@requests, @set.sorted_requests out = [] @@ -105,17 +97,10 @@ class TestGemRequestSetLockfile < Gem::TestCase @set.gem 'a' @set.gem 'bundler' @set.resolve - @lockfile.instance_variable_set :@requests, @set.sorted_requests - - spec_groups = @set.sorted_requests.group_by do |request| - request.spec.class - end - @lockfile.instance_variable_set :@spec_groups, spec_groups - out = [] - @lockfile.add_GEM out + @lockfile.add_GEM out, @lockfile.spec_groups expected = [ 'GEM', @@ -143,7 +128,6 @@ class TestGemRequestSetLockfile < Gem::TestCase @set.gem 'a' @set.resolve - @lockfile.instance_variable_set :@requests, @set.sorted_requests out = [] @@ -159,518 +143,6 @@ class TestGemRequestSetLockfile < Gem::TestCase assert_equal expected, out end - def test_get - @lockfile.instance_variable_set :@tokens, [:token] - - assert_equal :token, @lockfile.get - end - - def test_get_type_mismatch - @lockfile.instance_variable_set :@tokens, [[:section, 'x', 5, 1]] - - e = assert_raises Gem::RequestSet::Lockfile::ParseError do - @lockfile.get :text - end - - expected = - 'unexpected token [:section, "x"], expected :text (at line 1 column 5)' - - assert_equal expected, e.message - - assert_equal 1, e.line - assert_equal 5, e.column - assert_equal File.expand_path("#{@gem_deps_file}.lock"), e.path - end - - def test_get_type_multiple - @lockfile.instance_variable_set :@tokens, [[:section, 'x', 5, 1]] - - assert @lockfile.get [:text, :section] - end - - def test_get_type_value_mismatch - @lockfile.instance_variable_set :@tokens, [[:section, 'x', 5, 1]] - - e = assert_raises Gem::RequestSet::Lockfile::ParseError do - @lockfile.get :section, 'y' - end - - expected = - 'unexpected token [:section, "x"], expected [:section, "y"] (at line 1 column 5)' - - assert_equal expected, e.message - - assert_equal 1, e.line - assert_equal 5, e.column - assert_equal File.expand_path("#{@gem_deps_file}.lock"), e.path - end - - def test_parse - write_lockfile <<-LOCKFILE.strip -GEM - remote: #{@gem_repo} - specs: - a (2) - -PLATFORMS - #{Gem::Platform::RUBY} - -DEPENDENCIES - a - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a')], @set.dependencies - - assert_equal [Gem::Platform::RUBY], @lockfile.platforms - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - assert lockfile_set, 'could not find a LockSet' - - assert_equal %w[a-2], lockfile_set.specs.map { |tuple| tuple.full_name } - end - - def test_parse_dependencies - write_lockfile <<-LOCKFILE -GEM - remote: #{@gem_repo} - specs: - a (2) - -PLATFORMS - #{Gem::Platform::RUBY} - -DEPENDENCIES - a (>= 1, <= 2) - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a', '>= 1', '<= 2')], @set.dependencies - - assert_equal [Gem::Platform::RUBY], @lockfile.platforms - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - assert lockfile_set, 'could not find a LockSet' - - assert_equal %w[a-2], lockfile_set.specs.map { |tuple| tuple.full_name } - end - - def test_parse_DEPENDENCIES_git - write_lockfile <<-LOCKFILE -GIT - remote: git://git.example/josevalim/rails-footnotes.git - revision: 3a6ac1971e91d822f057650cc5916ebfcbd6ee37 - specs: - rails-footnotes (3.7.9) - rails (>= 3.0.0) - -GIT - remote: git://git.example/svenfuchs/i18n-active_record.git - revision: 55507cf59f8f2173d38e07e18df0e90d25b1f0f6 - specs: - i18n-active_record (0.0.2) - i18n (>= 0.5.0) - -GEM - remote: http://gems.example/ - specs: - i18n (0.6.9) - rails (4.0.0) - -PLATFORMS - ruby - -DEPENDENCIES - i18n-active_record! - rails-footnotes! - LOCKFILE - - @lockfile.parse - - expected = [ - dep('i18n-active_record', '= 0.0.2'), - dep('rails-footnotes', '= 3.7.9'), - ] - - assert_equal expected, @set.dependencies - end - - def test_parse_DEPENDENCIES_git_version - write_lockfile <<-LOCKFILE -GIT - remote: git://github.com/progrium/ruby-jwt.git - revision: 8d74770c6cd92ea234b428b5d0c1f18306a4f41c - specs: - jwt (1.1) - -GEM - remote: http://gems.example/ - specs: - -PLATFORMS - ruby - -DEPENDENCIES - jwt (= 1.1)! - LOCKFILE - - @lockfile.parse - - expected = [ - dep('jwt', '= 1.1'), - ] - - assert_equal expected, @set.dependencies - end - - def test_parse_GEM - write_lockfile <<-LOCKFILE -GEM - specs: - a (2) - -PLATFORMS - ruby - -DEPENDENCIES - a - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a', '>= 0')], @set.dependencies - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - assert lockfile_set, 'found a LockSet' - - assert_equal %w[a-2], lockfile_set.specs.map { |s| s.full_name } - end - - def test_parse_GEM_remote_multiple - write_lockfile <<-LOCKFILE -GEM - remote: https://gems.example/ - remote: https://other.example/ - specs: - a (2) - -PLATFORMS - ruby - -DEPENDENCIES - a - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a', '>= 0')], @set.dependencies - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - assert lockfile_set, 'found a LockSet' - - assert_equal %w[a-2 a-2], lockfile_set.specs.map { |s| s.full_name } - - assert_equal %w[https://gems.example/ https://other.example/], - lockfile_set.specs.map { |s| s.source.uri.to_s } - end - - def test_parse_GIT - @set.instance_variable_set :@install_dir, 'install_dir' - - write_lockfile <<-LOCKFILE -GIT - remote: git://example/a.git - revision: master - specs: - a (2) - b (>= 3) - c - -DEPENDENCIES - a! - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a', '= 2')], @set.dependencies - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - refute lockfile_set, 'fount a LockSet' - - git_set = @set.sets.find do |set| - Gem::Resolver::GitSet === set - end - - assert git_set, 'could not find a GitSet' - - assert_equal %w[a-2], git_set.specs.values.map { |s| s.full_name } - - assert_equal [dep('b', '>= 3'), dep('c')], - git_set.specs.values.first.dependencies - - expected = { - 'a' => %w[git://example/a.git master], - } - - assert_equal expected, git_set.repositories - assert_equal 'install_dir', git_set.root_dir - end - - def test_parse_GIT_branch - write_lockfile <<-LOCKFILE -GIT - remote: git://example/a.git - revision: 1234abc - branch: 0-9-12-stable - specs: - a (2) - b (>= 3) - -DEPENDENCIES - a! - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a', '= 2')], @set.dependencies - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - refute lockfile_set, 'fount a LockSet' - - git_set = @set.sets.find do |set| - Gem::Resolver::GitSet === set - end - - assert git_set, 'could not find a GitSet' - - expected = { - 'a' => %w[git://example/a.git 1234abc], - } - - assert_equal expected, git_set.repositories - end - - def test_parse_GIT_ref - write_lockfile <<-LOCKFILE -GIT - remote: git://example/a.git - revision: 1234abc - ref: 1234abc - specs: - a (2) - b (>= 3) - -DEPENDENCIES - a! - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a', '= 2')], @set.dependencies - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - refute lockfile_set, 'fount a LockSet' - - git_set = @set.sets.find do |set| - Gem::Resolver::GitSet === set - end - - assert git_set, 'could not find a GitSet' - - expected = { - 'a' => %w[git://example/a.git 1234abc], - } - - assert_equal expected, git_set.repositories - end - - def test_parse_GIT_tag - write_lockfile <<-LOCKFILE -GIT - remote: git://example/a.git - revision: 1234abc - tag: v0.9.12 - specs: - a (2) - b (>= 3) - -DEPENDENCIES - a! - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a', '= 2')], @set.dependencies - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - refute lockfile_set, 'fount a LockSet' - - git_set = @set.sets.find do |set| - Gem::Resolver::GitSet === set - end - - assert git_set, 'could not find a GitSet' - - expected = { - 'a' => %w[git://example/a.git 1234abc], - } - - assert_equal expected, git_set.repositories - end - - def test_parse_PATH - _, _, directory = vendor_gem - - write_lockfile <<-LOCKFILE -PATH - remote: #{directory} - specs: - a (1) - b (2) - -DEPENDENCIES - a! - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a', '= 1')], @set.dependencies - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - refute lockfile_set, 'found a LockSet' - - vendor_set = @set.sets.find do |set| - Gem::Resolver::VendorSet === set - end - - assert vendor_set, 'could not find a VendorSet' - - assert_equal %w[a-1], vendor_set.specs.values.map { |s| s.full_name } - - spec = vendor_set.load_spec 'a', nil, nil, nil - - assert_equal [dep('b', '= 2')], spec.dependencies - end - - def test_parse_dependency - write_lockfile ' 1)' - - @lockfile.tokenize - - parsed = @lockfile.parse_dependency 'a', '=' - - assert_equal dep('a', '= 1'), parsed - - write_lockfile ')' - - @lockfile.tokenize - - parsed = @lockfile.parse_dependency 'a', '2' - - assert_equal dep('a', '= 2'), parsed - end - - def test_parse_gem_specs_dependency - write_lockfile <<-LOCKFILE -GEM - remote: #{@gem_repo} - specs: - a (2) - b (= 3) - c (~> 4) - d - e (~> 5.0, >= 5.0.1) - b (3-x86_64-linux) - -PLATFORMS - #{Gem::Platform::RUBY} - -DEPENDENCIES - a - LOCKFILE - - @lockfile.parse - - assert_equal [dep('a')], @set.dependencies - - assert_equal [Gem::Platform::RUBY], @lockfile.platforms - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - assert lockfile_set, 'could not find a LockSet' - - assert_equal %w[a-2 b-3], lockfile_set.specs.map { |tuple| tuple.full_name } - - expected = [ - Gem::Platform::RUBY, - Gem::Platform.new('x86_64-linux'), - ] - - assert_equal expected, lockfile_set.specs.map { |tuple| tuple.platform } - - spec = lockfile_set.specs.first - - expected = [ - dep('b', '= 3'), - dep('c', '~> 4'), - dep('d'), - dep('e', '~> 5.0', '>= 5.0.1'), - ] - - assert_equal expected, spec.dependencies - end - - def test_parse_missing - @lockfile.parse - - lockfile_set = @set.sets.find do |set| - Gem::Resolver::LockSet === set - end - - refute lockfile_set - end - - def test_peek - @lockfile.instance_variable_set :@tokens, [:token] - - assert_equal :token, @lockfile.peek - - assert_equal :token, @lockfile.get - - assert_equal [:EOF], @lockfile.peek - end - def test_relative_path_from path = @lockfile.relative_path_from '/foo', '/foo/bar' @@ -681,276 +153,6 @@ DEPENDENCIES assert_equal '.', path end - def test_skip - tokens = [[:token]] - - @lockfile.instance_variable_set :@tokens, tokens - - @lockfile.skip :token - - assert_empty tokens - end - - def test_token_pos - assert_equal [5, 0], @lockfile.token_pos(5) - - @lockfile.instance_variable_set :@line_pos, 2 - @lockfile.instance_variable_set :@line, 1 - - assert_equal [3, 1], @lockfile.token_pos(5) - end - - def test_tokenize - write_lockfile <<-LOCKFILE -GEM - remote: #{@gem_repo} - specs: - a (2) - b (= 2) - c (!= 3) - d (> 4) - e (< 5) - f (>= 6) - g (<= 7) - h (~> 8) - -PLATFORMS - #{Gem::Platform::RUBY} - -DEPENDENCIES - a - LOCKFILE - - expected = [ - [:section, 'GEM', 0, 0], - [:newline, nil, 3, 0], - - [:entry, 'remote', 2, 1], - [:text, @gem_repo, 10, 1], - [:newline, nil, 34, 1], - - [:entry, 'specs', 2, 2], - [:newline, nil, 8, 2], - - [:text, 'a', 4, 3], - [:l_paren, nil, 6, 3], - [:text, '2', 7, 3], - [:r_paren, nil, 8, 3], - [:newline, nil, 9, 3], - - [:text, 'b', 6, 4], - [:l_paren, nil, 8, 4], - [:requirement, '=', 9, 4], - [:text, '2', 11, 4], - [:r_paren, nil, 12, 4], - [:newline, nil, 13, 4], - - [:text, 'c', 6, 5], - [:l_paren, nil, 8, 5], - [:requirement, '!=', 9, 5], - [:text, '3', 12, 5], - [:r_paren, nil, 13, 5], - [:newline, nil, 14, 5], - - [:text, 'd', 6, 6], - [:l_paren, nil, 8, 6], - [:requirement, '>', 9, 6], - [:text, '4', 11, 6], - [:r_paren, nil, 12, 6], - [:newline, nil, 13, 6], - - [:text, 'e', 6, 7], - [:l_paren, nil, 8, 7], - [:requirement, '<', 9, 7], - [:text, '5', 11, 7], - [:r_paren, nil, 12, 7], - [:newline, nil, 13, 7], - - [:text, 'f', 6, 8], - [:l_paren, nil, 8, 8], - [:requirement, '>=', 9, 8], - [:text, '6', 12, 8], - [:r_paren, nil, 13, 8], - [:newline, nil, 14, 8], - - [:text, 'g', 6, 9], - [:l_paren, nil, 8, 9], - [:requirement, '<=', 9, 9], - [:text, '7', 12, 9], - [:r_paren, nil, 13, 9], - [:newline, nil, 14, 9], - - [:text, 'h', 6, 10], - [:l_paren, nil, 8, 10], - [:requirement, '~>', 9, 10], - [:text, '8', 12, 10], - [:r_paren, nil, 13, 10], - [:newline, nil, 14, 10], - - [:newline, nil, 0, 11], - - [:section, 'PLATFORMS', 0, 12], - [:newline, nil, 9, 12], - - [:text, Gem::Platform::RUBY, 2, 13], - [:newline, nil, 6, 13], - - [:newline, nil, 0, 14], - - [:section, 'DEPENDENCIES', 0, 15], - [:newline, nil, 12, 15], - - [:text, 'a', 2, 16], - [:newline, nil, 3, 16], - ] - - assert_equal expected, @lockfile.tokenize - end - - def test_tokenize_capitals - write_lockfile <<-LOCKFILE -GEM - remote: #{@gem_repo} - specs: - Ab (2) - -PLATFORMS - #{Gem::Platform::RUBY} - -DEPENDENCIES - Ab - LOCKFILE - - expected = [ - [:section, 'GEM', 0, 0], - [:newline, nil, 3, 0], - [:entry, 'remote', 2, 1], - [:text, @gem_repo, 10, 1], - [:newline, nil, 34, 1], - [:entry, 'specs', 2, 2], - [:newline, nil, 8, 2], - [:text, 'Ab', 4, 3], - [:l_paren, nil, 7, 3], - [:text, '2', 8, 3], - [:r_paren, nil, 9, 3], - [:newline, nil, 10, 3], - [:newline, nil, 0, 4], - [:section, 'PLATFORMS', 0, 5], - [:newline, nil, 9, 5], - [:text, Gem::Platform::RUBY, 2, 6], - [:newline, nil, 6, 6], - [:newline, nil, 0, 7], - [:section, 'DEPENDENCIES', 0, 8], - [:newline, nil, 12, 8], - [:text, 'Ab', 2, 9], - [:newline, nil, 4, 9], - ] - - assert_equal expected, @lockfile.tokenize - end - - def test_tokenize_conflict_markers - write_lockfile '<<<<<<<' - - e = assert_raises Gem::RequestSet::Lockfile::ParseError do - @lockfile.tokenize - end - - assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)", - e.message - - write_lockfile '|||||||' - - e = assert_raises Gem::RequestSet::Lockfile::ParseError do - @lockfile.tokenize - end - - assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)", - e.message - - write_lockfile '=======' - - e = assert_raises Gem::RequestSet::Lockfile::ParseError do - @lockfile.tokenize - end - - assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)", - e.message - - write_lockfile '>>>>>>>' - - e = assert_raises Gem::RequestSet::Lockfile::ParseError do - @lockfile.tokenize - end - - assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)", - e.message - end - - def test_tokenize_git - write_lockfile <<-LOCKFILE -DEPENDENCIES - a! - LOCKFILE - - expected = [ - [:section, 'DEPENDENCIES', 0, 0], - [:newline, nil, 12, 0], - - [:text, 'a', 2, 1], - [:bang, nil, 3, 1], - [:newline, nil, 4, 1], - ] - - assert_equal expected, @lockfile.tokenize - end - - def test_tokenize_missing - tokens = @lockfile.tokenize - - assert_empty tokens - end - - def test_tokenize_multiple - write_lockfile <<-LOCKFILE -GEM - remote: #{@gem_repo} - specs: - a (2) - b (~> 3.0, >= 3.0.1) - LOCKFILE - - expected = [ - [:section, 'GEM', 0, 0], - [:newline, nil, 3, 0], - - [:entry, 'remote', 2, 1], - [:text, @gem_repo, 10, 1], - [:newline, nil, 34, 1], - - [:entry, 'specs', 2, 2], - [:newline, nil, 8, 2], - - [:text, 'a', 4, 3], - [:l_paren, nil, 6, 3], - [:text, '2', 7, 3], - [:r_paren, nil, 8, 3], - [:newline, nil, 9, 3], - - [:text, 'b', 6, 4], - [:l_paren, nil, 8, 4], - [:requirement, '~>', 9, 4], - [:text, '3.0', 12, 4], - [:comma, nil, 15, 4], - [:requirement, '>=', 17, 4], - [:text, '3.0.1', 20, 4], - [:r_paren, nil, 25, 4], - [:newline, nil, 26, 4], - ] - - assert_equal expected, @lockfile.tokenize - end - def test_to_s_gem spec_fetcher do |fetcher| fetcher.spec 'a', 2 @@ -1236,14 +438,6 @@ DEPENDENCIES assert_equal expected, @lockfile.to_s end - def test_unget - @lockfile.instance_variable_set :@current_token, :token - - @lockfile.unget - - assert_equal :token, @lockfile.get - end - def test_write @lockfile.write @@ -1271,6 +465,4 @@ DEPENDENCIES assert_equal 'hello', File.read(gem_deps_lock_file) end - end - diff --git a/test/rubygems/test_gem_request_set_lockfile_parser.rb b/test/rubygems/test_gem_request_set_lockfile_parser.rb new file mode 100644 index 0000000000..c5b2b19c0e --- /dev/null +++ b/test/rubygems/test_gem_request_set_lockfile_parser.rb @@ -0,0 +1,543 @@ +require 'rubygems/test_case' +require 'rubygems/request_set' +require 'rubygems/request_set/lockfile' +require 'rubygems/request_set/lockfile/tokenizer' +require 'rubygems/request_set/lockfile/parser' + +class TestGemRequestSetLockfileParser < Gem::TestCase + def setup + super + @gem_deps_file = 'gem.deps.rb' + @lock_file = File.expand_path "#{@gem_deps_file}.lock" + @set = Gem::RequestSet.new + end + + def test_get + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n" + parser = tokenizer.make_parser nil, nil + + assert_equal :newline, parser.get.first + end + + def test_get_type_mismatch + filename = File.expand_path("#{@gem_deps_file}.lock") + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "foo", filename, 1, 0 + parser = tokenizer.make_parser nil, nil + + e = assert_raises Gem::RequestSet::Lockfile::ParseError do + parser.get :section + end + + expected = + 'unexpected token [:text, "foo"], expected :section (at line 1 column 0)' + + assert_equal expected, e.message + + assert_equal 1, e.line + assert_equal 0, e.column + assert_equal filename, e.path + end + + def test_get_type_multiple + filename = File.expand_path("#{@gem_deps_file}.lock") + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "x", filename, 1 + parser = tokenizer.make_parser nil, nil + + assert parser.get [:text, :section] + end + + def test_get_type_value_mismatch + filename = File.expand_path("#{@gem_deps_file}.lock") + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "x", filename, 1 + parser = tokenizer.make_parser nil, nil + + e = assert_raises Gem::RequestSet::Lockfile::ParseError do + parser.get :text, 'y' + end + + expected = + 'unexpected token [:text, "x"], expected [:text, "y"] (at line 1 column 0)' + + assert_equal expected, e.message + + assert_equal 1, e.line + assert_equal 0, e.column + assert_equal File.expand_path("#{@gem_deps_file}.lock"), e.path + end + + + def test_parse + write_lockfile <<-LOCKFILE.strip +GEM + remote: #{@gem_repo} + specs: + a (2) + +PLATFORMS + #{Gem::Platform::RUBY} + +DEPENDENCIES + a + LOCKFILE + + platforms = [] + parse_lockfile @set, platforms + + assert_equal [dep('a')], @set.dependencies + + assert_equal [Gem::Platform::RUBY], platforms + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + assert lockfile_set, 'could not find a LockSet' + + assert_equal %w[a-2], lockfile_set.specs.map { |tuple| tuple.full_name } + end + + def test_parse_dependencies + write_lockfile <<-LOCKFILE +GEM + remote: #{@gem_repo} + specs: + a (2) + +PLATFORMS + #{Gem::Platform::RUBY} + +DEPENDENCIES + a (>= 1, <= 2) + LOCKFILE + + platforms = [] + parse_lockfile @set, platforms + + assert_equal [dep('a', '>= 1', '<= 2')], @set.dependencies + + assert_equal [Gem::Platform::RUBY], platforms + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + assert lockfile_set, 'could not find a LockSet' + + assert_equal %w[a-2], lockfile_set.specs.map { |tuple| tuple.full_name } + end + + def test_parse_DEPENDENCIES_git + write_lockfile <<-LOCKFILE +GIT + remote: git://git.example/josevalim/rails-footnotes.git + revision: 3a6ac1971e91d822f057650cc5916ebfcbd6ee37 + specs: + rails-footnotes (3.7.9) + rails (>= 3.0.0) + +GIT + remote: git://git.example/svenfuchs/i18n-active_record.git + revision: 55507cf59f8f2173d38e07e18df0e90d25b1f0f6 + specs: + i18n-active_record (0.0.2) + i18n (>= 0.5.0) + +GEM + remote: http://gems.example/ + specs: + i18n (0.6.9) + rails (4.0.0) + +PLATFORMS + ruby + +DEPENDENCIES + i18n-active_record! + rails-footnotes! + LOCKFILE + + parse_lockfile @set, [] + + expected = [ + dep('i18n-active_record', '= 0.0.2'), + dep('rails-footnotes', '= 3.7.9'), + ] + + assert_equal expected, @set.dependencies + end + + def test_parse_DEPENDENCIES_git_version + write_lockfile <<-LOCKFILE +GIT + remote: git://github.com/progrium/ruby-jwt.git + revision: 8d74770c6cd92ea234b428b5d0c1f18306a4f41c + specs: + jwt (1.1) + +GEM + remote: http://gems.example/ + specs: + +PLATFORMS + ruby + +DEPENDENCIES + jwt (= 1.1)! + LOCKFILE + + parse_lockfile @set, [] + + expected = [ + dep('jwt', '= 1.1'), + ] + + assert_equal expected, @set.dependencies + end + + def test_parse_GEM + write_lockfile <<-LOCKFILE +GEM + specs: + a (2) + +PLATFORMS + ruby + +DEPENDENCIES + a + LOCKFILE + + parse_lockfile @set, [] + + assert_equal [dep('a', '>= 0')], @set.dependencies + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + assert lockfile_set, 'found a LockSet' + + assert_equal %w[a-2], lockfile_set.specs.map { |s| s.full_name } + end + + def test_parse_GEM_remote_multiple + write_lockfile <<-LOCKFILE +GEM + remote: https://gems.example/ + remote: https://other.example/ + specs: + a (2) + +PLATFORMS + ruby + +DEPENDENCIES + a + LOCKFILE + + parse_lockfile @set, [] + + assert_equal [dep('a', '>= 0')], @set.dependencies + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + assert lockfile_set, 'found a LockSet' + + assert_equal %w[a-2 a-2], lockfile_set.specs.map { |s| s.full_name } + + assert_equal %w[https://gems.example/ https://other.example/], + lockfile_set.specs.map { |s| s.source.uri.to_s } + end + + def test_parse_GIT + @set.instance_variable_set :@install_dir, 'install_dir' + + write_lockfile <<-LOCKFILE +GIT + remote: git://example/a.git + revision: master + specs: + a (2) + b (>= 3) + c + +DEPENDENCIES + a! + LOCKFILE + + parse_lockfile @set, [] + + assert_equal [dep('a', '= 2')], @set.dependencies + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + refute lockfile_set, 'fount a LockSet' + + git_set = @set.sets.find do |set| + Gem::Resolver::GitSet === set + end + + assert git_set, 'could not find a GitSet' + + assert_equal %w[a-2], git_set.specs.values.map { |s| s.full_name } + + assert_equal [dep('b', '>= 3'), dep('c')], + git_set.specs.values.first.dependencies + + expected = { + 'a' => %w[git://example/a.git master], + } + + assert_equal expected, git_set.repositories + assert_equal 'install_dir', git_set.root_dir + end + + def test_parse_GIT_branch + write_lockfile <<-LOCKFILE +GIT + remote: git://example/a.git + revision: 1234abc + branch: 0-9-12-stable + specs: + a (2) + b (>= 3) + +DEPENDENCIES + a! + LOCKFILE + + parse_lockfile @set, [] + + assert_equal [dep('a', '= 2')], @set.dependencies + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + refute lockfile_set, 'fount a LockSet' + + git_set = @set.sets.find do |set| + Gem::Resolver::GitSet === set + end + + assert git_set, 'could not find a GitSet' + + expected = { + 'a' => %w[git://example/a.git 1234abc], + } + + assert_equal expected, git_set.repositories + end + + def test_parse_GIT_ref + write_lockfile <<-LOCKFILE +GIT + remote: git://example/a.git + revision: 1234abc + ref: 1234abc + specs: + a (2) + b (>= 3) + +DEPENDENCIES + a! + LOCKFILE + + parse_lockfile @set, [] + + assert_equal [dep('a', '= 2')], @set.dependencies + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + refute lockfile_set, 'fount a LockSet' + + git_set = @set.sets.find do |set| + Gem::Resolver::GitSet === set + end + + assert git_set, 'could not find a GitSet' + + expected = { + 'a' => %w[git://example/a.git 1234abc], + } + + assert_equal expected, git_set.repositories + end + + def test_parse_GIT_tag + write_lockfile <<-LOCKFILE +GIT + remote: git://example/a.git + revision: 1234abc + tag: v0.9.12 + specs: + a (2) + b (>= 3) + +DEPENDENCIES + a! + LOCKFILE + + parse_lockfile @set, [] + + assert_equal [dep('a', '= 2')], @set.dependencies + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + refute lockfile_set, 'fount a LockSet' + + git_set = @set.sets.find do |set| + Gem::Resolver::GitSet === set + end + + assert git_set, 'could not find a GitSet' + + expected = { + 'a' => %w[git://example/a.git 1234abc], + } + + assert_equal expected, git_set.repositories + end + + def test_parse_PATH + _, _, directory = vendor_gem + + write_lockfile <<-LOCKFILE +PATH + remote: #{directory} + specs: + a (1) + b (2) + +DEPENDENCIES + a! + LOCKFILE + + parse_lockfile @set, [] + + assert_equal [dep('a', '= 1')], @set.dependencies + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + refute lockfile_set, 'found a LockSet' + + vendor_set = @set.sets.find do |set| + Gem::Resolver::VendorSet === set + end + + assert vendor_set, 'could not find a VendorSet' + + assert_equal %w[a-1], vendor_set.specs.values.map { |s| s.full_name } + + spec = vendor_set.load_spec 'a', nil, nil, nil + + assert_equal [dep('b', '= 2')], spec.dependencies + end + + def test_parse_dependency + write_lockfile ' 1)' + + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file @lock_file + parser = tokenizer.make_parser nil, nil + + parsed = parser.parse_dependency 'a', '=' + + assert_equal dep('a', '= 1'), parsed + + write_lockfile ')' + + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file @lock_file + parser = tokenizer.make_parser nil, nil + + parsed = parser.parse_dependency 'a', '2' + + assert_equal dep('a', '= 2'), parsed + end + + def test_parse_gem_specs_dependency + write_lockfile <<-LOCKFILE +GEM + remote: #{@gem_repo} + specs: + a (2) + b (= 3) + c (~> 4) + d + e (~> 5.0, >= 5.0.1) + b (3-x86_64-linux) + +PLATFORMS + #{Gem::Platform::RUBY} + +DEPENDENCIES + a + LOCKFILE + + platforms = [] + parse_lockfile @set, platforms + + assert_equal [dep('a')], @set.dependencies + + assert_equal [Gem::Platform::RUBY], platforms + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + assert lockfile_set, 'could not find a LockSet' + + assert_equal %w[a-2 b-3], lockfile_set.specs.map { |tuple| tuple.full_name } + + expected = [ + Gem::Platform::RUBY, + Gem::Platform.new('x86_64-linux'), + ] + + assert_equal expected, lockfile_set.specs.map { |tuple| tuple.platform } + + spec = lockfile_set.specs.first + + expected = [ + dep('b', '= 3'), + dep('c', '~> 4'), + dep('d'), + dep('e', '~> 5.0', '>= 5.0.1'), + ] + + assert_equal expected, spec.dependencies + end + + def test_parse_missing + assert_raises(Errno::ENOENT) do + parse_lockfile @set, [] + end + + lockfile_set = @set.sets.find do |set| + Gem::Resolver::LockSet === set + end + + refute lockfile_set + end + + def write_lockfile lockfile + open @lock_file, 'w' do |io| + io.write lockfile + end + end + + def parse_lockfile set, platforms + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file @lock_file + parser = tokenizer.make_parser set, platforms + parser.parse + end +end diff --git a/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb b/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb new file mode 100644 index 0000000000..bf56f5019b --- /dev/null +++ b/test/rubygems/test_gem_request_set_lockfile_tokenizer.rb @@ -0,0 +1,305 @@ +require 'rubygems/test_case' +require 'rubygems/request_set' +require 'rubygems/request_set/lockfile' +require 'rubygems/request_set/lockfile/tokenizer' +require 'rubygems/request_set/lockfile/parser' + +class TestGemRequestSetLockfileTokenizer < Gem::TestCase + def setup + super + + @gem_deps_file = 'gem.deps.rb' + @lock_file = File.expand_path "#{@gem_deps_file}.lock" + end + + def test_peek + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n" + + assert_equal :newline, tokenizer.peek.first + + assert_equal :newline, tokenizer.next_token.first + + assert_equal [:EOF], tokenizer.peek + end + + def test_skip + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n" + + refute_predicate tokenizer, :empty? + + tokenizer.skip :newline + + assert_empty tokenizer + end + + def test_token_pos + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new '' + assert_equal [5, 0], tokenizer.token_pos(5) + + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new '', nil, 1, 2 + assert_equal [3, 1], tokenizer.token_pos(5) + end + + def test_tokenize + write_lockfile <<-LOCKFILE +GEM + remote: #{@gem_repo} + specs: + a (2) + b (= 2) + c (!= 3) + d (> 4) + e (< 5) + f (>= 6) + g (<= 7) + h (~> 8) + +PLATFORMS + #{Gem::Platform::RUBY} + +DEPENDENCIES + a + LOCKFILE + + expected = [ + [:section, 'GEM', 0, 0], + [:newline, nil, 3, 0], + + [:entry, 'remote', 2, 1], + [:text, @gem_repo, 10, 1], + [:newline, nil, 34, 1], + + [:entry, 'specs', 2, 2], + [:newline, nil, 8, 2], + + [:text, 'a', 4, 3], + [:l_paren, nil, 6, 3], + [:text, '2', 7, 3], + [:r_paren, nil, 8, 3], + [:newline, nil, 9, 3], + + [:text, 'b', 6, 4], + [:l_paren, nil, 8, 4], + [:requirement, '=', 9, 4], + [:text, '2', 11, 4], + [:r_paren, nil, 12, 4], + [:newline, nil, 13, 4], + + [:text, 'c', 6, 5], + [:l_paren, nil, 8, 5], + [:requirement, '!=', 9, 5], + [:text, '3', 12, 5], + [:r_paren, nil, 13, 5], + [:newline, nil, 14, 5], + + [:text, 'd', 6, 6], + [:l_paren, nil, 8, 6], + [:requirement, '>', 9, 6], + [:text, '4', 11, 6], + [:r_paren, nil, 12, 6], + [:newline, nil, 13, 6], + + [:text, 'e', 6, 7], + [:l_paren, nil, 8, 7], + [:requirement, '<', 9, 7], + [:text, '5', 11, 7], + [:r_paren, nil, 12, 7], + [:newline, nil, 13, 7], + + [:text, 'f', 6, 8], + [:l_paren, nil, 8, 8], + [:requirement, '>=', 9, 8], + [:text, '6', 12, 8], + [:r_paren, nil, 13, 8], + [:newline, nil, 14, 8], + + [:text, 'g', 6, 9], + [:l_paren, nil, 8, 9], + [:requirement, '<=', 9, 9], + [:text, '7', 12, 9], + [:r_paren, nil, 13, 9], + [:newline, nil, 14, 9], + + [:text, 'h', 6, 10], + [:l_paren, nil, 8, 10], + [:requirement, '~>', 9, 10], + [:text, '8', 12, 10], + [:r_paren, nil, 13, 10], + [:newline, nil, 14, 10], + + [:newline, nil, 0, 11], + + [:section, 'PLATFORMS', 0, 12], + [:newline, nil, 9, 12], + + [:text, Gem::Platform::RUBY, 2, 13], + [:newline, nil, 6, 13], + + [:newline, nil, 0, 14], + + [:section, 'DEPENDENCIES', 0, 15], + [:newline, nil, 12, 15], + + [:text, 'a', 2, 16], + [:newline, nil, 3, 16], + ] + + assert_equal expected, tokenize_lockfile + end + + def test_tokenize_capitals + write_lockfile <<-LOCKFILE +GEM + remote: #{@gem_repo} + specs: + Ab (2) + +PLATFORMS + #{Gem::Platform::RUBY} + +DEPENDENCIES + Ab + LOCKFILE + + expected = [ + [:section, 'GEM', 0, 0], + [:newline, nil, 3, 0], + [:entry, 'remote', 2, 1], + [:text, @gem_repo, 10, 1], + [:newline, nil, 34, 1], + [:entry, 'specs', 2, 2], + [:newline, nil, 8, 2], + [:text, 'Ab', 4, 3], + [:l_paren, nil, 7, 3], + [:text, '2', 8, 3], + [:r_paren, nil, 9, 3], + [:newline, nil, 10, 3], + [:newline, nil, 0, 4], + [:section, 'PLATFORMS', 0, 5], + [:newline, nil, 9, 5], + [:text, Gem::Platform::RUBY, 2, 6], + [:newline, nil, 6, 6], + [:newline, nil, 0, 7], + [:section, 'DEPENDENCIES', 0, 8], + [:newline, nil, 12, 8], + [:text, 'Ab', 2, 9], + [:newline, nil, 4, 9], + ] + + assert_equal expected, tokenize_lockfile + end + + def test_tokenize_conflict_markers + write_lockfile '<<<<<<<' + + e = assert_raises Gem::RequestSet::Lockfile::ParseError do + tokenize_lockfile + end + + assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)", + e.message + + write_lockfile '|||||||' + + e = assert_raises Gem::RequestSet::Lockfile::ParseError do + tokenize_lockfile + end + + assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)", + e.message + + write_lockfile '=======' + + e = assert_raises Gem::RequestSet::Lockfile::ParseError do + tokenize_lockfile + end + + assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)", + e.message + + write_lockfile '>>>>>>>' + + e = assert_raises Gem::RequestSet::Lockfile::ParseError do + tokenize_lockfile + end + + assert_equal "your #{@lock_file} contains merge conflict markers (at line 0 column 0)", + e.message + end + + def test_tokenize_git + write_lockfile <<-LOCKFILE +DEPENDENCIES + a! + LOCKFILE + + expected = [ + [:section, 'DEPENDENCIES', 0, 0], + [:newline, nil, 12, 0], + + [:text, 'a', 2, 1], + [:bang, nil, 3, 1], + [:newline, nil, 4, 1], + ] + + assert_equal expected, tokenize_lockfile + end + + def test_tokenize_multiple + write_lockfile <<-LOCKFILE +GEM + remote: #{@gem_repo} + specs: + a (2) + b (~> 3.0, >= 3.0.1) + LOCKFILE + + expected = [ + [:section, 'GEM', 0, 0], + [:newline, nil, 3, 0], + + [:entry, 'remote', 2, 1], + [:text, @gem_repo, 10, 1], + [:newline, nil, 34, 1], + + [:entry, 'specs', 2, 2], + [:newline, nil, 8, 2], + + [:text, 'a', 4, 3], + [:l_paren, nil, 6, 3], + [:text, '2', 7, 3], + [:r_paren, nil, 8, 3], + [:newline, nil, 9, 3], + + [:text, 'b', 6, 4], + [:l_paren, nil, 8, 4], + [:requirement, '~>', 9, 4], + [:text, '3.0', 12, 4], + [:comma, nil, 15, 4], + [:requirement, '>=', 17, 4], + [:text, '3.0.1', 20, 4], + [:r_paren, nil, 25, 4], + [:newline, nil, 26, 4], + ] + + assert_equal expected, tokenize_lockfile + end + + def test_unget + tokenizer = Gem::RequestSet::Lockfile::Tokenizer.new "\n" + tokenizer.unshift :token + parser = tokenizer.make_parser nil, nil + + assert_equal :token, parser.get + end + + def write_lockfile lockfile + open @lock_file, 'w' do |io| + io.write lockfile + end + end + + def tokenize_lockfile + Gem::RequestSet::Lockfile::Tokenizer.from_file(@lock_file).to_a + end +end diff --git a/test/rubygems/test_gem_requirement.rb b/test/rubygems/test_gem_requirement.rb index 6974ff0810..234edb4ec3 100644 --- a/test/rubygems/test_gem_requirement.rb +++ b/test/rubygems/test_gem_requirement.rb @@ -347,6 +347,16 @@ class TestGemRequirement < Gem::TestCase refute_satisfied_by "1.0.0.1", "= 1.0" end + def test_hash_with_multiple_versions + r1 = req('1.0', '2.0') + r2 = req('2.0', '1.0') + assert_equal r1.hash, r2.hash + + r1 = req('1.0', '2.0').tap { |r| r.concat(['3.0']) } + r2 = req('3.0', '1.0').tap { |r| r.concat(['2.0']) } + assert_equal r1.hash, r2.hash + end + # Assert that two requirements are equal. Handles Gem::Requirements, # strings, arrays, numbers, and versions. diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 3cadc55d5d..020cfb2ae6 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -1080,6 +1080,12 @@ dependencies: [] assert_equal %w[true gem_name], gem.dependencies.map { |dep| dep.name } end + def test_add_dependency_from_existing_dependency + dep = Gem::Dependency.new("existing_dep", Gem::Requirement.new('> 1'), :runtime) + spec = Gem::Specification.new { |s| s.add_dependency dep } + assert_equal dep, spec.dependencies.first + end + def test_add_dependency_with_type_explicit gem = util_spec "awesome", "1.0" do |awesome| awesome.add_development_dependency "monkey" @@ -1856,8 +1862,8 @@ dependencies: [] @ext.require_paths = 'lib' expected = [ - @ext.extension_dir, File.join(@gemhome, 'gems', @ext.original_name, 'lib'), + @ext.extension_dir, ] assert_equal expected, @ext.full_require_paths diff --git a/test/rubygems/test_gem_stub_specification.rb b/test/rubygems/test_gem_stub_specification.rb index 914b06a27a..9d273125a5 100644 --- a/test/rubygems/test_gem_stub_specification.rb +++ b/test/rubygems/test_gem_stub_specification.rb @@ -65,8 +65,8 @@ class TestStubSpecification < Gem::TestCase stub = stub_with_extension expected = [ - stub.extension_dir, File.join(stub.full_gem_path, 'lib'), + stub.extension_dir, ] assert_equal expected, stub.full_require_paths -- cgit v1.2.3