# frozen_string_literal: true 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], lockfile_set.specs.map { |s| s.full_name } if [].respond_to? :flat_map assert_equal %w[https://gems.example/ https://other.example/], lockfile_set.specs.flat_map { |s| s.sources.map{ |src| src.uri.to_s } } else # FIXME: remove when 1.8 is dropped assert_equal %w[https://gems.example/ https://other.example/], lockfile_set.specs.map { |s| s.sources.map{ |src| src.uri.to_s } }.flatten(1) end 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