diff options
Diffstat (limited to 'jni/ruby/test/fileutils/test_fileutils.rb')
| -rw-r--r-- | jni/ruby/test/fileutils/test_fileutils.rb | 1570 | 
1 files changed, 1570 insertions, 0 deletions
diff --git a/jni/ruby/test/fileutils/test_fileutils.rb b/jni/ruby/test/fileutils/test_fileutils.rb new file mode 100644 index 0000000..27c80d7 --- /dev/null +++ b/jni/ruby/test/fileutils/test_fileutils.rb @@ -0,0 +1,1570 @@ +# $Id: test_fileutils.rb 50485 2015-05-13 15:32:22Z nagachika $ + +require 'fileutils' +require 'etc' +require_relative 'fileasserts' +require 'pathname' +require 'tmpdir' +require 'test/unit' + +class TestFileUtils < Test::Unit::TestCase +  TMPROOT = "#{Dir.tmpdir}/fileutils.rb.#{$$}" +  include Test::Unit::FileAssertions + +  def assert_output_lines(expected, fu = self, message=nil) +    old = fu.instance_variable_get(:@fileutils_output) +    IO.pipe {|read, write| +      fu.instance_variable_set(:@fileutils_output, write) +      th = Thread.new { read.read } +      th2 = Thread.new { +        yield +        write.close +      } +      th_value, _ = assert_join_threads([th, th2]) +      lines = th_value.lines.map {|l| l.chomp } +      assert_equal(expected, lines) +    } +  ensure +    fu.instance_variable_set(:@fileutils_output, old) if old +  end + +  m = Module.new do +    def have_drive_letter? +      /mswin(?!ce)|mingw|bcc|emx/ =~ RUBY_PLATFORM +    end + +    def have_file_perm? +      /mswin|mingw|bcc|emx/ !~ RUBY_PLATFORM +    end + +    @@have_symlink = nil + +    def have_symlink? +      if @@have_symlink == nil +        @@have_symlink = check_have_symlink? +      end +      @@have_symlink +    end + +    def check_have_symlink? +      File.symlink nil, nil +    rescue NotImplementedError +      return false +    rescue +      return true +    end + +    @@have_hardlink = nil + +    def have_hardlink? +      if @@have_hardlink == nil +        @@have_hardlink = check_have_hardlink? +      end +      @@have_hardlink +    end + +    def check_have_hardlink? +      File.link nil, nil +    rescue NotImplementedError +      return false +    rescue +      return true +    end + +    def root_in_posix? +      if Process.respond_to?('uid') +        return Process.uid == 0 +      else +        return false +      end +    end + +    def distinct_uids(n = 2) +      return unless user = Etc.getpwent +      uids = [user.uid] +      while user = Etc.getpwent +        uid = user.uid +        unless uids.include?(uid) +          uids << uid +          break if uids.size >= n +        end +      end +      uids +    ensure +      Etc.endpwent +    end + +    begin +      tmproot = TMPROOT +      Dir.mkdir tmproot unless File.directory?(tmproot) +      Dir.chdir tmproot do +        Dir.mkdir("\n") +        Dir.rmdir("\n") +      end +      def lf_in_path_allowed? +        true +      end +    rescue +      def lf_in_path_allowed? +        false +      end +    ensure +      Dir.rmdir tmproot +    end +  end +  include m +  extend m + +  include FileUtils + +  def check_singleton(name) +    assert_respond_to ::FileUtils, name +  end + +  def my_rm_rf(path) +    if File.exist?('/bin/rm') +      system %Q[/bin/rm -rf "#{path}"] +    else +      FileUtils.rm_rf path +    end +  end + +  def mymkdir(path) +    Dir.mkdir path +    File.chown nil, Process.gid, path if have_file_perm? +  end + +  def setup +    @prevdir = Dir.pwd +    @groups = Process.groups if have_file_perm? +    tmproot = TMPROOT +    mymkdir tmproot unless File.directory?(tmproot) +    Dir.chdir tmproot +    my_rm_rf 'data'; mymkdir 'data' +    my_rm_rf 'tmp';  mymkdir 'tmp' +    prepare_data_file +  end + +  def teardown +    Dir.chdir @prevdir +    my_rm_rf TMPROOT +  end + + +  TARGETS = %w( data/a data/all data/random data/zero ) + +  def prepare_data_file +    File.open('data/a', 'w') {|f| +      32.times do +        f.puts 'a' * 50 +      end +    } + +    all_chars = (0..255).map {|n| n.chr }.join('') +    File.open('data/all', 'w') {|f| +      32.times do +        f.puts all_chars +      end +    } + +    random_chars = (0...50).map { rand(256).chr }.join('') +    File.open('data/random', 'w') {|f| +      32.times do +        f.puts random_chars +      end +    } + +    File.open('data/zero', 'w') {|f| +      ; +    } +  end + +  BIGFILE = 'data/big' + +  def prepare_big_file +    File.open('data/big', 'w') {|f| +      (4 * 1024 * 1024 / 256).times do   # 4MB +        f.print "aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa\n" +      end +    } +  end + +  def prepare_time_data +    File.open('data/old',    'w') {|f| f.puts 'dummy' } +    File.open('data/newer',  'w') {|f| f.puts 'dummy' } +    File.open('data/newest', 'w') {|f| f.puts 'dummy' } +    t = Time.now +    File.utime t-8, t-8, 'data/old' +    File.utime t-4, t-4, 'data/newer' +  end + +  def each_srcdest +    TARGETS.each do |path| +      yield path, "tmp/#{File.basename(path)}" +    end +  end + +  # +  # Test Cases +  # + +  def test_pwd +    check_singleton :pwd + +    assert_equal Dir.pwd, pwd() + +    cwd = Dir.pwd +    root = have_drive_letter? ? 'C:/' : '/' +    cd(root) { +      assert_equal root, pwd() +    } +    assert_equal cwd, pwd() +  end + +  def test_cmp +    check_singleton :cmp + +    TARGETS.each do |fname| +      assert cmp(fname, fname), 'not same?' +    end +    assert_raise(ArgumentError) { +      cmp TARGETS[0], TARGETS[0], :undefinedoption => true +    } + +    # pathname +    touch 'tmp/cmptmp' +    assert_nothing_raised { +      cmp Pathname.new('tmp/cmptmp'), 'tmp/cmptmp' +      cmp 'tmp/cmptmp', Pathname.new('tmp/cmptmp') +      cmp Pathname.new('tmp/cmptmp'), Pathname.new('tmp/cmptmp') +    } +  end + +  def test_cp +    check_singleton :cp + +    each_srcdest do |srcpath, destpath| +      cp srcpath, destpath +      assert_same_file srcpath, destpath + +      cp srcpath, File.dirname(destpath) +      assert_same_file srcpath, destpath + +      cp srcpath, File.dirname(destpath) + '/' +      assert_same_file srcpath, destpath + +      cp srcpath, destpath, :preserve => true +      assert_same_file srcpath, destpath +      assert_same_entry srcpath, destpath +    end + +    assert_raise(Errno::ENOENT) { +      cp 'tmp/cptmp', 'tmp/cptmp_new' +    } +    assert_file_not_exist('tmp/cptmp_new') + +    # src==dest (1) same path +    touch 'tmp/cptmp' +    assert_raise(ArgumentError) { +      cp 'tmp/cptmp', 'tmp/cptmp' +    } +  end + +  def test_cp_preserve_permissions +    bug4507 = '[ruby-core:35518]' +    touch 'tmp/cptmp' +    chmod 0755, 'tmp/cptmp' +    cp 'tmp/cptmp', 'tmp/cptmp2' +    assert_equal_filemode('tmp/cptmp', 'tmp/cptmp2', bug4507) +  end + +  def test_cp_preserve_permissions_dir +    bug7246 = '[ruby-core:48603]' +    mkdir 'tmp/cptmp' +    mkdir 'tmp/cptmp/d1' +    chmod 0745, 'tmp/cptmp/d1' +    mkdir 'tmp/cptmp/d2' +    chmod 0700, 'tmp/cptmp/d2' +    cp_r 'tmp/cptmp', 'tmp/cptmp2', :preserve => true +    assert_equal_filemode('tmp/cptmp/d1', 'tmp/cptmp2/d1', bug7246) +    assert_equal_filemode('tmp/cptmp/d2', 'tmp/cptmp2/d2', bug7246) +  end + +  def test_cp_symlink +    touch 'tmp/cptmp' +    # src==dest (2) symlink and its target +    File.symlink 'cptmp', 'tmp/cptmp_symlink' +    assert_raise(ArgumentError) { +      cp 'tmp/cptmp', 'tmp/cptmp_symlink' +    } +    assert_raise(ArgumentError) { +      cp 'tmp/cptmp_symlink', 'tmp/cptmp' +    } +    # src==dest (3) looped symlink +    File.symlink 'symlink', 'tmp/symlink' +    assert_raise(Errno::ELOOP) { +      cp 'tmp/symlink', 'tmp/symlink' +    } +  end if have_symlink? + +  def test_cp_pathname +    # pathname +    touch 'tmp/cptmp' +    assert_nothing_raised { +      cp 'tmp/cptmp', Pathname.new('tmp/tmpdest') +      cp Pathname.new('tmp/cptmp'), 'tmp/tmpdest' +      cp Pathname.new('tmp/cptmp'), Pathname.new('tmp/tmpdest') +      mkdir 'tmp/tmpdir' +      cp ['tmp/cptmp', 'tmp/tmpdest'], Pathname.new('tmp/tmpdir') +    } +  end + +  def test_cp_r +    check_singleton :cp_r + +    cp_r 'data', 'tmp' +    TARGETS.each do |fname| +      assert_same_file fname, "tmp/#{fname}" +    end + +    cp_r 'data', 'tmp2', :preserve => true +    TARGETS.each do |fname| +      assert_same_entry fname, "tmp2/#{File.basename(fname)}" +      assert_same_file fname, "tmp2/#{File.basename(fname)}" +    end + +    # a/* -> b/* +    mkdir 'tmp/cpr_src' +    mkdir 'tmp/cpr_dest' +    File.open('tmp/cpr_src/a', 'w') {|f| f.puts 'a' } +    File.open('tmp/cpr_src/b', 'w') {|f| f.puts 'b' } +    File.open('tmp/cpr_src/c', 'w') {|f| f.puts 'c' } +    mkdir 'tmp/cpr_src/d' +    cp_r 'tmp/cpr_src/.', 'tmp/cpr_dest' +    assert_same_file 'tmp/cpr_src/a', 'tmp/cpr_dest/a' +    assert_same_file 'tmp/cpr_src/b', 'tmp/cpr_dest/b' +    assert_same_file 'tmp/cpr_src/c', 'tmp/cpr_dest/c' +    assert_directory 'tmp/cpr_dest/d' +    my_rm_rf 'tmp/cpr_src' +    my_rm_rf 'tmp/cpr_dest' + +    bug3588 = '[ruby-core:31360]' +    assert_nothing_raised(ArgumentError, bug3588) do +      cp_r 'tmp', 'tmp2' +    end +    assert_directory 'tmp2/tmp' +    assert_raise(ArgumentError, bug3588) do +      cp_r 'tmp2', 'tmp2/new_tmp2' +    end +  end + +  def test_cp_r_symlink +    # symlink in a directory +    mkdir 'tmp/cpr_src' +    ln_s 'SLdest', 'tmp/cpr_src/symlink' +    cp_r 'tmp/cpr_src', 'tmp/cpr_dest' +    assert_symlink 'tmp/cpr_dest/symlink' +    assert_equal 'SLdest', File.readlink('tmp/cpr_dest/symlink') + +    # root is a symlink +    ln_s 'cpr_src', 'tmp/cpr_src2' +    cp_r 'tmp/cpr_src2', 'tmp/cpr_dest2' +    assert_directory 'tmp/cpr_dest2' +    assert_not_symlink 'tmp/cpr_dest2' +    assert_symlink 'tmp/cpr_dest2/symlink' +    assert_equal 'SLdest', File.readlink('tmp/cpr_dest2/symlink') +  end if have_symlink? + +  def test_cp_r_symlink_preserve +    mkdir 'tmp/cross' +    mkdir 'tmp/cross/a' +    mkdir 'tmp/cross/b' +    touch 'tmp/cross/a/f' +    touch 'tmp/cross/b/f' +    ln_s '../a/f', 'tmp/cross/b/l' +    ln_s '../b/f', 'tmp/cross/a/l' +    assert_nothing_raised { +      cp_r 'tmp/cross', 'tmp/cross2', :preserve => true +    } +  end if have_symlink? + +  def test_cp_r_pathname +    # pathname +    touch 'tmp/cprtmp' +    assert_nothing_raised { +      cp_r Pathname.new('tmp/cprtmp'), 'tmp/tmpdest' +      cp_r 'tmp/cprtmp', Pathname.new('tmp/tmpdest') +      cp_r Pathname.new('tmp/cprtmp'), Pathname.new('tmp/tmpdest') +    } +  end + +  def test_mv +    check_singleton :mv + +    mkdir 'tmp/dest' +    TARGETS.each do |fname| +      cp fname, 'tmp/mvsrc' +      mv 'tmp/mvsrc', 'tmp/mvdest' +      assert_same_file fname, 'tmp/mvdest' + +      mv 'tmp/mvdest', 'tmp/dest/' +      assert_same_file fname, 'tmp/dest/mvdest' + +      mv 'tmp/dest/mvdest', 'tmp' +      assert_same_file fname, 'tmp/mvdest' +    end + +    mkdir 'tmp/tmpdir' +    mkdir_p 'tmp/dest2/tmpdir' +    assert_raise_with_message(Errno::EEXIST, %r' - tmp/dest2/tmpdir\z', +                              '[ruby-core:68706] [Bug #11021]') { +      mv 'tmp/tmpdir', 'tmp/dest2' +    } +    mkdir 'tmp/dest2/tmpdir/junk' +    assert_raise(Errno::EEXIST, "[ruby-talk:124368]") { +      mv 'tmp/tmpdir', 'tmp/dest2' +    } + +    # src==dest (1) same path +    touch 'tmp/cptmp' +    assert_raise(ArgumentError) { +      mv 'tmp/cptmp', 'tmp/cptmp' +    } +  end + +  def test_mv_symlink +    touch 'tmp/cptmp' +    # src==dest (2) symlink and its target +    File.symlink 'cptmp', 'tmp/cptmp_symlink' +    assert_raise(ArgumentError) { +      mv 'tmp/cptmp', 'tmp/cptmp_symlink' +    } +    assert_raise(ArgumentError) { +      mv 'tmp/cptmp_symlink', 'tmp/cptmp' +    } +    # src==dest (3) looped symlink +    File.symlink 'symlink', 'tmp/symlink' +    assert_raise(Errno::ELOOP) { +      mv 'tmp/symlink', 'tmp/symlink' +    } +    # unexist symlink +    File.symlink 'xxx', 'tmp/src' +    assert_nothing_raised { +      mv 'tmp/src', 'tmp/dest' +    } +    assert_equal true, File.symlink?('tmp/dest') +  end if have_symlink? + +  def test_mv_pathname +    # pathname +    assert_nothing_raised { +      touch 'tmp/mvtmpsrc' +      mv Pathname.new('tmp/mvtmpsrc'), 'tmp/mvtmpdest' +      touch 'tmp/mvtmpsrc' +      mv 'tmp/mvtmpsrc', Pathname.new('tmp/mvtmpdest') +      touch 'tmp/mvtmpsrc' +      mv Pathname.new('tmp/mvtmpsrc'), Pathname.new('tmp/mvtmpdest') +    } +  end + +  def test_rm +    check_singleton :rm + +    TARGETS.each do |fname| +      cp fname, 'tmp/rmsrc' +      rm 'tmp/rmsrc' +      assert_file_not_exist 'tmp/rmsrc' +    end + +    # pathname +    touch 'tmp/rmtmp1' +    touch 'tmp/rmtmp2' +    touch 'tmp/rmtmp3' +    assert_nothing_raised { +      rm Pathname.new('tmp/rmtmp1') +      rm [Pathname.new('tmp/rmtmp2'), Pathname.new('tmp/rmtmp3')] +    } +    assert_file_not_exist 'tmp/rmtmp1' +    assert_file_not_exist 'tmp/rmtmp2' +    assert_file_not_exist 'tmp/rmtmp3' +  end + +  def test_rm_f +    check_singleton :rm_f + +    TARGETS.each do |fname| +      cp fname, 'tmp/rmsrc' +      rm_f 'tmp/rmsrc' +      assert_file_not_exist 'tmp/rmsrc' +    end +  end + +  def test_rm_symlink +    File.open('tmp/lnf_symlink_src', 'w') {|f| f.puts 'dummy' } +    File.symlink 'tmp/lnf_symlink_src', 'tmp/lnf_symlink_dest' +    rm_f 'tmp/lnf_symlink_dest' +    assert_file_not_exist 'tmp/lnf_symlink_dest' +    assert_file_exist     'tmp/lnf_symlink_src' + +    rm_f 'notexistdatafile' +    rm_f 'tmp/notexistdatafile' +    my_rm_rf 'tmpdatadir' +    Dir.mkdir 'tmpdatadir' +    # rm_f 'tmpdatadir' +    Dir.rmdir 'tmpdatadir' +  end if have_symlink? + +  def test_rm_f_2 +    Dir.mkdir 'tmp/tmpdir' +    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } +    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } +    rm_f ['tmp/tmpdir/a', 'tmp/tmpdir/b', 'tmp/tmpdir/c'] +    assert_file_not_exist 'tmp/tmpdir/a' +    assert_file_not_exist 'tmp/tmpdir/c' +    Dir.rmdir 'tmp/tmpdir' +  end + +  def test_rm_pathname +    # pathname +    touch 'tmp/rmtmp1' +    touch 'tmp/rmtmp2' +    touch 'tmp/rmtmp3' +    touch 'tmp/rmtmp4' +    assert_nothing_raised { +      rm_f Pathname.new('tmp/rmtmp1') +      rm_f [Pathname.new('tmp/rmtmp2'), Pathname.new('tmp/rmtmp3')] +    } +    assert_file_not_exist 'tmp/rmtmp1' +    assert_file_not_exist 'tmp/rmtmp2' +    assert_file_not_exist 'tmp/rmtmp3' +    assert_file_exist 'tmp/rmtmp4' + +    # [ruby-dev:39345] +    touch 'tmp/[rmtmp]' +    FileUtils.rm_f 'tmp/[rmtmp]' +    assert_file_not_exist 'tmp/[rmtmp]' +  end + +  def test_rm_r +    check_singleton :rm_r + +    my_rm_rf 'tmpdatadir' + +    Dir.mkdir 'tmpdatadir' +    rm_r 'tmpdatadir' +    assert_file_not_exist 'tmpdatadir' + +    Dir.mkdir 'tmpdatadir' +    rm_r 'tmpdatadir/' +    assert_file_not_exist 'tmpdatadir' + +    Dir.mkdir 'tmp/tmpdir' +    rm_r 'tmp/tmpdir/' +    assert_file_not_exist 'tmp/tmpdir' +    assert_file_exist     'tmp' + +    Dir.mkdir 'tmp/tmpdir' +    rm_r 'tmp/tmpdir' +    assert_file_not_exist 'tmp/tmpdir' +    assert_file_exist     'tmp' + +    Dir.mkdir 'tmp/tmpdir' +    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } +    File.open('tmp/tmpdir/b', 'w') {|f| f.puts 'dummy' } +    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } +    rm_r 'tmp/tmpdir' +    assert_file_not_exist 'tmp/tmpdir' +    assert_file_exist     'tmp' + +    Dir.mkdir 'tmp/tmpdir' +    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } +    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } +    rm_r ['tmp/tmpdir/a', 'tmp/tmpdir/b', 'tmp/tmpdir/c'], :force => true +    assert_file_not_exist 'tmp/tmpdir/a' +    assert_file_not_exist 'tmp/tmpdir/c' +    Dir.rmdir 'tmp/tmpdir' +  end + +  def test_rm_r_symlink +    # [ruby-talk:94635] a symlink to the directory +    Dir.mkdir 'tmp/tmpdir' +    File.symlink '..', 'tmp/tmpdir/symlink_to_dir' +    rm_r 'tmp/tmpdir' +    assert_file_not_exist 'tmp/tmpdir' +    assert_file_exist     'tmp' +  end if have_symlink? + +  def test_rm_r_pathname +    # pathname +    Dir.mkdir 'tmp/tmpdir1'; touch 'tmp/tmpdir1/tmp' +    Dir.mkdir 'tmp/tmpdir2'; touch 'tmp/tmpdir2/tmp' +    Dir.mkdir 'tmp/tmpdir3'; touch 'tmp/tmpdir3/tmp' +    assert_nothing_raised { +      rm_r Pathname.new('tmp/tmpdir1') +      rm_r [Pathname.new('tmp/tmpdir2'), Pathname.new('tmp/tmpdir3')] +    } +    assert_file_not_exist 'tmp/tmpdir1' +    assert_file_not_exist 'tmp/tmpdir2' +    assert_file_not_exist 'tmp/tmpdir3' +  end + +  def test_remove_entry_secure +    check_singleton :remove_entry_secure + +    my_rm_rf 'tmpdatadir' + +    Dir.mkdir 'tmpdatadir' +    remove_entry_secure 'tmpdatadir' +    assert_file_not_exist 'tmpdatadir' + +    Dir.mkdir 'tmpdatadir' +    remove_entry_secure 'tmpdatadir/' +    assert_file_not_exist 'tmpdatadir' + +    Dir.mkdir 'tmp/tmpdir' +    remove_entry_secure 'tmp/tmpdir/' +    assert_file_not_exist 'tmp/tmpdir' +    assert_file_exist     'tmp' + +    Dir.mkdir 'tmp/tmpdir' +    remove_entry_secure 'tmp/tmpdir' +    assert_file_not_exist 'tmp/tmpdir' +    assert_file_exist     'tmp' + +    Dir.mkdir 'tmp/tmpdir' +    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } +    File.open('tmp/tmpdir/b', 'w') {|f| f.puts 'dummy' } +    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } +    remove_entry_secure 'tmp/tmpdir' +    assert_file_not_exist 'tmp/tmpdir' +    assert_file_exist     'tmp' + +    Dir.mkdir 'tmp/tmpdir' +    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' } +    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' } +    remove_entry_secure 'tmp/tmpdir/a', true +    remove_entry_secure 'tmp/tmpdir/b', true +    remove_entry_secure 'tmp/tmpdir/c', true +    assert_file_not_exist 'tmp/tmpdir/a' +    assert_file_not_exist 'tmp/tmpdir/c' +    Dir.rmdir 'tmp/tmpdir' +  end + +  def test_remove_entry_secure_symlink +    # [ruby-talk:94635] a symlink to the directory +    Dir.mkdir 'tmp/tmpdir' +    File.symlink '..', 'tmp/tmpdir/symlink_to_dir' +    remove_entry_secure 'tmp/tmpdir' +    assert_file_not_exist 'tmp/tmpdir' +    assert_file_exist     'tmp' +  end if have_symlink? + +  def test_remove_entry_secure_pathname +    # pathname +    Dir.mkdir 'tmp/tmpdir1'; touch 'tmp/tmpdir1/tmp' +    assert_nothing_raised { +      remove_entry_secure Pathname.new('tmp/tmpdir1') +    } +    assert_file_not_exist 'tmp/tmpdir1' +  end + +  def test_with_big_file +    prepare_big_file + +    cp BIGFILE, 'tmp/cpdest' +    assert_same_file BIGFILE, 'tmp/cpdest' +    assert cmp(BIGFILE, 'tmp/cpdest'), 'orig != copied' + +    mv 'tmp/cpdest', 'tmp/mvdest' +    assert_same_file BIGFILE, 'tmp/mvdest' +    assert_file_not_exist 'tmp/cpdest' + +    rm 'tmp/mvdest' +    assert_file_not_exist 'tmp/mvdest' +  end + +  def test_ln +    TARGETS.each do |fname| +      ln fname, 'tmp/lndest' +      assert_same_file fname, 'tmp/lndest' +      File.unlink 'tmp/lndest' +    end + +    ln TARGETS, 'tmp' +    TARGETS.each do |fname| +      assert_same_file fname, 'tmp/' + File.basename(fname) +    end +    TARGETS.each do |fname| +      File.unlink 'tmp/' + File.basename(fname) +    end + +    # src==dest (1) same path +    touch 'tmp/cptmp' +    assert_raise(Errno::EEXIST) { +      ln 'tmp/cptmp', 'tmp/cptmp' +    } +  end if have_hardlink? + +  def test_ln_symlink +    touch 'tmp/cptmp' +    # src==dest (2) symlink and its target +    File.symlink 'cptmp', 'tmp/symlink' +    assert_raise(Errno::EEXIST) { +      ln 'tmp/cptmp', 'tmp/symlink'   # normal file -> symlink +    } +    assert_raise(Errno::EEXIST) { +      ln 'tmp/symlink', 'tmp/cptmp'   # symlink -> normal file +    } +    # src==dest (3) looped symlink +    File.symlink 'cptmp_symlink', 'tmp/cptmp_symlink' +    begin +      ln 'tmp/cptmp_symlink', 'tmp/cptmp_symlink' +    rescue => err +      assert_kind_of SystemCallError, err +    end +  end if have_symlink? + +  def test_ln_pathname +    # pathname +    touch 'tmp/lntmp' +    assert_nothing_raised { +      ln Pathname.new('tmp/lntmp'), 'tmp/lndesttmp1' +      ln 'tmp/lntmp', Pathname.new('tmp/lndesttmp2') +      ln Pathname.new('tmp/lntmp'), Pathname.new('tmp/lndesttmp3') +    } +  end if have_hardlink? + +  def test_ln_s +    check_singleton :ln_s + +    TARGETS.each do |fname| +      ln_s fname, 'tmp/lnsdest' +      assert FileTest.symlink?('tmp/lnsdest'), 'not symlink' +      assert_equal fname, File.readlink('tmp/lnsdest') +      rm_f 'tmp/lnsdest' +    end +    assert_nothing_raised { +      ln_s 'symlink', 'tmp/symlink' +    } +    assert_symlink 'tmp/symlink' + +    # pathname +    touch 'tmp/lnsdest' +    assert_nothing_raised { +      ln_s Pathname.new('lnsdest'), 'tmp/symlink_tmp1' +      ln_s 'lnsdest', Pathname.new('tmp/symlink_tmp2') +      ln_s Pathname.new('lnsdest'), Pathname.new('tmp/symlink_tmp3') +    } +  end if have_symlink? + +  def test_ln_sf +    check_singleton :ln_sf + +    TARGETS.each do |fname| +      ln_sf fname, 'tmp/lnsdest' +      assert FileTest.symlink?('tmp/lnsdest'), 'not symlink' +      assert_equal fname, File.readlink('tmp/lnsdest') +      ln_sf fname, 'tmp/lnsdest' +      ln_sf fname, 'tmp/lnsdest' +    end +    assert_nothing_raised { +      ln_sf 'symlink', 'tmp/symlink' +    } + +    # pathname +    touch 'tmp/lns_dest' +    assert_nothing_raised { +      ln_sf Pathname.new('lns_dest'), 'tmp/symlink_tmp1' +      ln_sf 'lns_dest', Pathname.new('tmp/symlink_tmp2') +      ln_sf Pathname.new('lns_dest'), Pathname.new('tmp/symlink_tmp3') +    } +  end if have_symlink? + +  def test_mkdir +    check_singleton :mkdir + +    my_rm_rf 'tmpdatadir' +    mkdir 'tmpdatadir' +    assert_directory 'tmpdatadir' +    Dir.rmdir 'tmpdatadir' + +    mkdir 'tmpdatadir/' +    assert_directory 'tmpdatadir' +    Dir.rmdir 'tmpdatadir' + +    mkdir 'tmp/mkdirdest' +    assert_directory 'tmp/mkdirdest' +    Dir.rmdir 'tmp/mkdirdest' + +    mkdir 'tmp/tmp', :mode => 0700 +    assert_directory 'tmp/tmp' +    assert_filemode 0700, 'tmp/tmp', mask: 0777 if have_file_perm? +    Dir.rmdir 'tmp/tmp' + +    # EISDIR on OS X, FreeBSD; EEXIST on Linux; Errno::EACCES on Windows +    assert_raise(Errno::EISDIR, Errno::EEXIST, Errno::EACCES) { +      mkdir '/' +    } +  end + +  def test_mkdir_file_perm +    mkdir 'tmp/tmp', :mode => 07777 +    assert_directory 'tmp/tmp' +    assert_filemode 07777, 'tmp/tmp' +    Dir.rmdir 'tmp/tmp' +  end if have_file_perm? + +  def test_mkdir_lf_in_path +    mkdir "tmp-first-line\ntmp-second-line" +    assert_directory "tmp-first-line\ntmp-second-line" +    Dir.rmdir "tmp-first-line\ntmp-second-line" +  end if lf_in_path_allowed? + +  def test_mkdir_pathname +    # pathname +    assert_nothing_raised { +      mkdir Pathname.new('tmp/tmpdirtmp') +      mkdir [Pathname.new('tmp/tmpdirtmp2'), Pathname.new('tmp/tmpdirtmp3')] +    } +  end + +  def test_mkdir_p +    check_singleton :mkdir_p + +    dirs = %w( +      tmpdir/dir/ +      tmpdir/dir/./ +      tmpdir/dir/./.././dir/ +      tmpdir/a +      tmpdir/a/ +      tmpdir/a/b +      tmpdir/a/b/ +      tmpdir/a/b/c/ +      tmpdir/a/b/c +      tmpdir/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a +      tmpdir/a/a +    ) +    my_rm_rf 'tmpdir' +    dirs.each do |d| +      mkdir_p d +      assert_directory d +      assert_file_not_exist "#{d}/a" +      assert_file_not_exist "#{d}/b" +      assert_file_not_exist "#{d}/c" +      my_rm_rf 'tmpdir' +    end +    dirs.each do |d| +      mkdir_p d +      assert_directory d +    end +    rm_rf 'tmpdir' +    dirs.each do |d| +      mkdir_p "#{Dir.pwd}/#{d}" +      assert_directory d +    end +    rm_rf 'tmpdir' + +    mkdir_p 'tmp/tmp/tmp', :mode => 0700 +    assert_directory 'tmp/tmp' +    assert_directory 'tmp/tmp/tmp' +    assert_filemode 0700, 'tmp/tmp', mask: 0777 if have_file_perm? +    assert_filemode 0700, 'tmp/tmp/tmp', mask: 0777 if have_file_perm? +    rm_rf 'tmp/tmp' + +    mkdir_p 'tmp/tmp', :mode => 0 +    assert_directory 'tmp/tmp' +    assert_filemode 0, 'tmp/tmp', mask: 0777 if have_file_perm? +    # DO NOT USE rm_rf here. +    # (rm(1) try to chdir to parent directory, it fails to remove directory.) +    Dir.rmdir 'tmp/tmp' +    Dir.rmdir 'tmp' + +    mkdir_p '/' +  end + +  def test_mkdir_p_file_perm +    mkdir_p 'tmp/tmp/tmp', :mode => 07777 +    assert_directory 'tmp/tmp/tmp' +    assert_filemode 07777, 'tmp/tmp/tmp' +    Dir.rmdir 'tmp/tmp/tmp' +    Dir.rmdir 'tmp/tmp' +  end if have_file_perm? + +  def test_mkdir_p_pathname +    # pathname +    assert_nothing_raised { +      mkdir_p Pathname.new('tmp/tmp/tmp') +    } +  end + +  def test_install +    check_singleton :install + +    File.open('tmp/aaa', 'w') {|f| f.puts 'aaa' } +    File.open('tmp/bbb', 'w') {|f| f.puts 'bbb' } +    install 'tmp/aaa', 'tmp/bbb', :mode => 0600 +    assert_equal "aaa\n", File.read('tmp/bbb') +    assert_filemode 0600, 'tmp/bbb', mask: 0777 if have_file_perm? + +    t = File.mtime('tmp/bbb') +    install 'tmp/aaa', 'tmp/bbb' +    assert_equal "aaa\n", File.read('tmp/bbb') +    assert_filemode 0600, 'tmp/bbb', mask: 0777 if have_file_perm? +    assert_equal_time t, File.mtime('tmp/bbb') + +    File.unlink 'tmp/aaa' +    File.unlink 'tmp/bbb' + +    # src==dest (1) same path +    touch 'tmp/cptmp' +    assert_raise(ArgumentError) { +      install 'tmp/cptmp', 'tmp/cptmp' +    } +  end + +  def test_install_symlink +    touch 'tmp/cptmp' +    # src==dest (2) symlink and its target +    File.symlink 'cptmp', 'tmp/cptmp_symlink' +    assert_raise(ArgumentError) { +      install 'tmp/cptmp', 'tmp/cptmp_symlink' +    } +    assert_raise(ArgumentError) { +      install 'tmp/cptmp_symlink', 'tmp/cptmp' +    } +    # src==dest (3) looped symlink +    File.symlink 'symlink', 'tmp/symlink' +    assert_raise(Errno::ELOOP) { +      # File#install invokes open(2), always ELOOP must be raised +      install 'tmp/symlink', 'tmp/symlink' +    } +  end if have_symlink? + +  def test_install_pathname +    # pathname +    assert_nothing_raised { +      rm_f 'tmp/a'; touch 'tmp/a' +      install 'tmp/a', Pathname.new('tmp/b') +      rm_f 'tmp/a'; touch 'tmp/a' +      install Pathname.new('tmp/a'), 'tmp/b' +      rm_f 'tmp/a'; touch 'tmp/a' +      install Pathname.new('tmp/a'), Pathname.new('tmp/b') +      rm_f 'tmp/a' +      touch 'tmp/a' +      touch 'tmp/b' +      mkdir 'tmp/dest' +      install [Pathname.new('tmp/a'), Pathname.new('tmp/b')], 'tmp/dest' +      my_rm_rf 'tmp/dest' +      mkdir 'tmp/dest' +      install [Pathname.new('tmp/a'), Pathname.new('tmp/b')], Pathname.new('tmp/dest') +    } +  end + +  def test_chmod +    check_singleton :chmod + +    touch 'tmp/a' +    chmod 0700, 'tmp/a' +    assert_filemode 0700, 'tmp/a' +    chmod 0500, 'tmp/a' +    assert_filemode 0500, 'tmp/a' +  end if have_file_perm? + +  def test_chmod_symbol_mode +    check_singleton :chmod + +    touch 'tmp/a' +    chmod "u=wrx,g=rx,o=x", 'tmp/a' +    assert_filemode 0751, 'tmp/a' +    chmod "g+w-x", 'tmp/a' +    assert_filemode 0761, 'tmp/a' +    chmod "o+r,g=o+w,o-r,u-o", 'tmp/a' # 761 => 763 => 773 => 771 => 671 +    assert_filemode 0671, 'tmp/a' +    chmod "go=u", 'tmp/a' +    assert_filemode 0666, 'tmp/a' +    chmod "u=wrx,g=,o=", 'tmp/a' +    assert_filemode 0700, 'tmp/a' +    chmod "u=rx,go=", 'tmp/a' +    assert_filemode 0500, 'tmp/a' +    chmod "+wrx", 'tmp/a' +    assert_filemode 0777, 'tmp/a' +    chmod "u+s,o=s", 'tmp/a' +    assert_filemode 04770, 'tmp/a' +    chmod "u-w,go-wrx", 'tmp/a' +    assert_filemode 04500, 'tmp/a' +    chmod "+s", 'tmp/a' +    assert_filemode 06500, 'tmp/a' + +    # FreeBSD ufs and tmpfs don't allow to change sticky bit against +    # regular file. It's slightly strange. Anyway it's no effect bit. +    # see /usr/src/sys/ufs/ufs/ufs_chmod() +    # NetBSD, OpenBSD, Solaris, and AIX also deny it. +    if /freebsd|netbsd|openbsd|solaris|aix/ !~ RUBY_PLATFORM +      chmod "u+t,o+t", 'tmp/a' +      assert_filemode 07500, 'tmp/a' +      chmod "a-t,a-s", 'tmp/a' +      assert_filemode 0500, 'tmp/a' +    end + +    assert_raise_with_message(ArgumentError, /invalid\b.*\bfile mode/) { +      chmod "a", 'tmp/a' +    } + +    assert_raise_with_message(ArgumentError, /invalid\b.*\bfile mode/) { +      chmod "x+a", 'tmp/a' +    } + +    assert_raise_with_message(ArgumentError, /invalid\b.*\bfile mode/) { +      chmod "u+z", 'tmp/a' +    } + +    assert_raise_with_message(ArgumentError, /invalid\b.*\bfile mode/) { +      chmod ",+x", 'tmp/a' +    } + +    assert_raise_with_message(ArgumentError, /invalid\b.*\bfile mode/) { +      chmod "755", 'tmp/a' +    } + +  end if have_file_perm? + + +  def test_chmod_R +    check_singleton :chmod_R + +    mkdir_p 'tmp/dir/dir' +    touch %w( tmp/dir/file tmp/dir/dir/file ) +    chmod_R 0700, 'tmp/dir' +    assert_filemode 0700, 'tmp/dir', mask: 0777 +    assert_filemode 0700, 'tmp/dir/file', mask: 0777 +    assert_filemode 0700, 'tmp/dir/dir', mask: 0777 +    assert_filemode 0700, 'tmp/dir/dir/file', mask: 0777 +    chmod_R 0500, 'tmp/dir' +    assert_filemode 0500, 'tmp/dir', mask: 0777 +    assert_filemode 0500, 'tmp/dir/file', mask: 0777 +    assert_filemode 0500, 'tmp/dir/dir', mask: 0777 +    assert_filemode 0500, 'tmp/dir/dir/file', mask: 0777 +    chmod_R 0700, 'tmp/dir'   # to remove +  end if have_file_perm? + +  def test_chmod_symbol_mode_R +    check_singleton :chmod_R + +    mkdir_p 'tmp/dir/dir' +    touch %w( tmp/dir/file tmp/dir/dir/file ) +    chmod_R "u=wrx,g=,o=", 'tmp/dir' +    assert_filemode 0700, 'tmp/dir', mask: 0777 +    assert_filemode 0700, 'tmp/dir/file', mask: 0777 +    assert_filemode 0700, 'tmp/dir/dir', mask: 0777 +    assert_filemode 0700, 'tmp/dir/dir/file', mask: 0777 +    chmod_R "u=xr,g+X,o=", 'tmp/dir' +    assert_filemode 0510, 'tmp/dir', mask: 0777 +    assert_filemode 0500, 'tmp/dir/file', mask: 0777 +    assert_filemode 0510, 'tmp/dir/dir', mask: 0777 +    assert_filemode 0500, 'tmp/dir/dir/file', mask: 0777 +    chmod_R 0700, 'tmp/dir'   # to remove +  end if have_file_perm? + +  def test_chmod_verbose +    check_singleton :chmod + +    assert_output_lines(["chmod 700 tmp/a", "chmod 500 tmp/a"]) { +      touch 'tmp/a' +      chmod 0700, 'tmp/a', verbose: true +      assert_filemode 0700, 'tmp/a', mask: 0777 +      chmod 0500, 'tmp/a', verbose: true +      assert_filemode 0500, 'tmp/a', mask: 0777 +    } +  end if have_file_perm? + +  def test_s_chmod_verbose +    assert_output_lines(["chmod 700 tmp/a"], FileUtils) { +      touch 'tmp/a' +      FileUtils.chmod 0700, 'tmp/a', verbose: true +      assert_filemode 0700, 'tmp/a', mask: 0777 +    } +  end if have_file_perm? + +  def test_chown +    check_singleton :chown + +    return unless @groups[1] + +    input_group_1 = @groups[0] +    assert_output_lines([]) { +      touch 'tmp/a' +      # integer input for group, nil for user +      chown nil, input_group_1, 'tmp/a' +      assert_ownership_group @groups[0], 'tmp/a' +    } + +    input_group_2 = Etc.getgrgid(@groups[1]).name +    assert_output_lines([]) { +      touch 'tmp/b' +      # string input for group, -1 for user +      chown(-1, input_group_2, 'tmp/b') +      assert_ownership_group @groups[1], 'tmp/b' +    } +  end if have_file_perm? + +  def test_chown_verbose +    assert_output_lines(["chown :#{@groups[0]} tmp/a1 tmp/a2"]) { +      touch 'tmp/a1' +      touch 'tmp/a2' +      chown nil, @groups[0], ['tmp/a1', 'tmp/a2'], verbose: true +      assert_ownership_group @groups[0], 'tmp/a1' +      assert_ownership_group @groups[0], 'tmp/a2' +    } +  end if have_file_perm? + +  def test_chown_noop +    return unless @groups[1] +    assert_output_lines([]) { +      touch 'tmp/a' +      chown nil, @groups[0], 'tmp/a', :noop => false +      assert_ownership_group @groups[0], 'tmp/a' +      chown nil, @groups[1], 'tmp/a', :noop => true +      assert_ownership_group @groups[0], 'tmp/a' +      chown nil, @groups[1], 'tmp/a' +      assert_ownership_group @groups[1], 'tmp/a' +    } +  end if have_file_perm? + +  if have_file_perm? +    def test_chown_error +      uid, = distinct_uids(1) +      return unless uid + +      touch 'tmp/a' + +      # getpwnam("") on Mac OS X doesn't err. +      # passwd & group databases format is colon-separated, so user & +      # group name can't contain a colon. + +      assert_raise_with_message(ArgumentError, "can't find user for :::") { +        chown ":::", @groups[0], 'tmp/a' +      } + +      assert_raise_with_message(ArgumentError, "can't find group for :::") { +        chown uid, ":::", 'tmp/a' +      } + +      assert_raise_with_message(Errno::ENOENT, /No such file or directory/) { +        chown nil, @groups[0], '' +      } +    end + +    def test_chown_dir_group_ownership_not_recursive +      return unless @groups[1] + +      input_group_1 = @groups[0] +      input_group_2 = @groups[1] +      assert_output_lines([]) { +        mkdir 'tmp/dir' +        touch 'tmp/dir/a' +        chown nil, input_group_1, ['tmp/dir', 'tmp/dir/a'] +        assert_ownership_group @groups[0], 'tmp/dir' +        assert_ownership_group @groups[0], 'tmp/dir/a' +        chown nil, input_group_2, 'tmp/dir' +        assert_ownership_group @groups[1], 'tmp/dir' +        # Make sure FileUtils.chown does not chown recursively +        assert_ownership_group @groups[0], 'tmp/dir/a' +      } +    end + +    def test_chown_R +      check_singleton :chown_R + +      return unless @groups[1] + +      input_group_1 = @groups[0] +      input_group_2 = @groups[1] +      assert_output_lines([]) { +        list = ['tmp/dir', 'tmp/dir/a', 'tmp/dir/a/b', 'tmp/dir/a/b/c'] +        mkdir_p 'tmp/dir/a/b/c' +        touch 'tmp/d' +        # string input +        chown_R nil, input_group_1, 'tmp/dir' +        list.each {|dir| +          assert_ownership_group @groups[0], dir +        } +        chown_R nil, input_group_1, 'tmp/d' +        assert_ownership_group @groups[0], 'tmp/d' +        # list input +        chown_R nil, input_group_2, ['tmp/dir', 'tmp/d'] +        list += ['tmp/d'] +        list.each {|dir| +          assert_ownership_group @groups[1], dir +        } +      } +    end + +    def test_chown_R_verbose +      assert_output_lines(["chown -R :#{@groups[0]} tmp/dir tmp/d"]) { +        list = ['tmp/dir', 'tmp/dir/a', 'tmp/dir/a/b', 'tmp/dir/a/b/c'] +        mkdir_p 'tmp/dir/a/b/c' +        touch 'tmp/d' +        chown_R nil, @groups[0], ['tmp/dir', 'tmp/d'], :verbose => true +        list.each {|dir| +          assert_ownership_group @groups[0], dir +        } +      } +    end + +    def test_chown_R_noop +      return unless @groups[1] + +      assert_output_lines([]) { +        list = ['tmp/dir', 'tmp/dir/a', 'tmp/dir/a/b', 'tmp/dir/a/b/c'] +        mkdir_p 'tmp/dir/a/b/c' +        chown_R nil, @groups[0], 'tmp/dir', :noop => false +        list.each {|dir| +          assert_ownership_group @groups[0], dir +        } +        chown_R nil, @groups[1], 'tmp/dir', :noop => true +        list.each {|dir| +          assert_ownership_group @groups[0], dir +        } +      } +    end + +    def test_chown_R_force +      assert_output_lines([]) { +        list = ['tmp/dir', 'tmp/dir/a', 'tmp/dir/a/b', 'tmp/dir/a/b/c'] +        mkdir_p 'tmp/dir/a/b/c' +        assert_raise_with_message(Errno::ENOENT, /No such file or directory/) { +            chown_R nil, @groups[0], ['tmp/dir', 'invalid'], :force => false +        } +        chown_R nil, @groups[0], ['tmp/dir', 'invalid'], :force => true +        list.each {|dir| +          assert_ownership_group @groups[0], dir +        } +      } +    end + +    if root_in_posix? +      def test_chown_with_root +        uid_1, uid_2 = distinct_uids(2) +        return unless uid_1 and uid_2 + +        gid = @groups[0] # Most of the time, root only has one group + +        files = ['tmp/a1', 'tmp/a2'] +        files.each {|file| touch file} +        [uid_1, uid_2].each {|uid| +          assert_output_lines(["chown #{uid}:#{gid} tmp/a1 tmp/a2"]) { +            chown uid, gid, files, verbose: true +            files.each {|file| +              assert_ownership_group gid, file +              assert_ownership_user uid, file +            } +          } +        } +      end + +      def test_chown_dir_user_ownership_not_recursive_with_root +        uid_1, uid_2 = distinct_uids(2) +        return unless uid_1 and uid_2 + +        assert_output_lines([]) { +          mkdir 'tmp/dir' +          touch 'tmp/dir/a' +          chown uid_1, nil, ['tmp/dir', 'tmp/dir/a'] +          assert_ownership_user uid_1, 'tmp/dir' +          assert_ownership_user uid_1, 'tmp/dir/a' +          chown uid_2, nil, 'tmp/dir' +          assert_ownership_user uid_2, 'tmp/dir' +          # Make sure FileUtils.chown does not chown recursively +          assert_ownership_user uid_1, 'tmp/dir/a' +        } +      end + +      def test_chown_R_with_root +        uid_1, uid_2 = distinct_uids(2) +        return unless uid_1 and uid_2 + +        assert_output_lines([]) { +          list = ['tmp/dir', 'tmp/dir/a', 'tmp/dir/a/b', 'tmp/dir/a/b/c'] +          mkdir_p 'tmp/dir/a/b/c' +          touch 'tmp/d' +          # string input +          chown_R uid_1, nil, 'tmp/dir' +          list.each {|dir| +            assert_ownership_user uid_1, dir +          } +          chown_R uid_1, nil, 'tmp/d' +          assert_ownership_user uid_1, 'tmp/d' +          # list input +          chown_R uid_2, nil, ['tmp/dir', 'tmp/d'] +          list += ['tmp/d'] +          list.each {|dir| +            assert_ownership_user uid_2, dir +          } +        } +      end +    else +      def test_chown_without_permission +        uid_1, uid_2 = distinct_uids(2) +        return unless uid_1 and uid_2 + +        touch 'tmp/a' +        assert_raise(Errno::EPERM) { +          chown uid_1, nil, 'tmp/a' +          chown uid_2, nil, 'tmp/a' +        } +      end + +      def test_chown_R_without_permission +        uid_1, uid_2 = distinct_uids(2) +        return unless uid_1 and uid_2 + +        touch 'tmp/a' +        exception = assert_raise(Errno::EPERM) { +          chown_R uid_1, nil, 'tmp/a' +          chown_R uid_2, nil, 'tmp/a' +        } +      end +    end +  end + +  def test_copy_entry +    check_singleton :copy_entry + +    each_srcdest do |srcpath, destpath| +      copy_entry srcpath, destpath +      assert_same_file srcpath, destpath +      assert_equal File.stat(srcpath).ftype, File.stat(destpath).ftype +    end +  end + +  def test_copy_entry_symlink +    # root is a symlink +    File.symlink 'somewhere', 'tmp/symsrc' +    copy_entry 'tmp/symsrc', 'tmp/symdest' +    assert_symlink 'tmp/symdest' +    assert_equal 'somewhere', File.readlink('tmp/symdest') + +    # content is a symlink +    mkdir 'tmp/dir' +    File.symlink 'somewhere', 'tmp/dir/sym' +    copy_entry 'tmp/dir', 'tmp/dirdest' +    assert_directory 'tmp/dirdest' +    assert_not_symlink 'tmp/dirdest' +    assert_symlink 'tmp/dirdest/sym' +    assert_equal 'somewhere', File.readlink('tmp/dirdest/sym') +  end if have_symlink? + +  def test_copy_file +    check_singleton :copy_file + +    each_srcdest do |srcpath, destpath| +      copy_file srcpath, destpath +      assert_same_file srcpath, destpath +    end +  end + +  def test_copy_stream +    check_singleton :copy_stream +    # IO +    each_srcdest do |srcpath, destpath| +      File.open(srcpath, 'rb') {|src| +        File.open(destpath, 'wb') {|dest| +          copy_stream src, dest +        } +      } +      assert_same_file srcpath, destpath +    end +  end + +  def test_copy_stream_duck +    check_singleton :copy_stream +    # duck typing test  [ruby-dev:25369] +    each_srcdest do |srcpath, destpath| +      File.open(srcpath, 'rb') {|src| +        File.open(destpath, 'wb') {|dest| +          copy_stream Stream.new(src), Stream.new(dest) +        } +      } +      assert_same_file srcpath, destpath +    end +  end + +  def test_remove_file +    check_singleton :remove_file +    File.open('data/tmp', 'w') {|f| f.puts 'dummy' } +    remove_file 'data/tmp' +    assert_file_not_exist 'data/tmp' +  end + +  def test_remove_file_file_perm +    File.open('data/tmp', 'w') {|f| f.puts 'dummy' } +    File.chmod 0, 'data/tmp' +    remove_file 'data/tmp' +    assert_file_not_exist 'data/tmp' +  end if have_file_perm? + +  def test_remove_dir +    check_singleton :remove_dir +    Dir.mkdir 'data/tmpdir' +    File.open('data/tmpdir/a', 'w') {|f| f.puts 'dummy' } +    remove_dir 'data/tmpdir' +    assert_file_not_exist 'data/tmpdir' +  end + +  def test_remove_dir_file_perm +    Dir.mkdir 'data/tmpdir' +    File.chmod 0555, 'data/tmpdir' +    remove_dir 'data/tmpdir' +    assert_file_not_exist 'data/tmpdir' +  end if have_file_perm? + +  def test_compare_file +    check_singleton :compare_file +    # FIXME +  end + +  def test_compare_stream +    check_singleton :compare_stream +    # FIXME +  end + +  class Stream +    def initialize(f) +      @f = f +    end + +    def read(*args) +      @f.read(*args) +    end + +    def write(str) +      @f.write str +    end +  end + +  def test_uptodate? +    check_singleton :uptodate? +    prepare_time_data +    Dir.chdir('data') { +      assert(   uptodate?('newest', %w(old newer notexist)) ) +      assert( ! uptodate?('newer', %w(old newest notexist)) ) +      assert( ! uptodate?('notexist', %w(old newest newer)) ) +    } + +    # pathname +    touch 'tmp/a' +    touch 'tmp/b' +    touch 'tmp/c' +    assert_nothing_raised { +      uptodate? Pathname.new('tmp/a'), ['tmp/b', 'tmp/c'] +      uptodate? 'tmp/a', [Pathname.new('tmp/b'), 'tmp/c'] +      uptodate? 'tmp/a', ['tmp/b', Pathname.new('tmp/c')] +      uptodate? Pathname.new('tmp/a'), [Pathname.new('tmp/b'), Pathname.new('tmp/c')] +    } +    # [Bug #6708] [ruby-core:46256] +    assert_raise_with_message(ArgumentError, "wrong number of arguments (3 for 2)") { +      uptodate?('new',['old', 'oldest'], {}) +    } +  end + +  def test_cd +    check_singleton :cd +  end + +  def test_chdir +    check_singleton :chdir +  end + +  def test_getwd +    check_singleton :getwd +  end + +  def test_identical? +    check_singleton :identical? +  end + +  def test_link +    check_singleton :link +  end + +  def test_makedirs +    check_singleton :makedirs +  end + +  def test_mkpath +    check_singleton :mkpath +  end + +  def test_move +    check_singleton :move +  end + +  def test_rm_rf +    check_singleton :rm_rf + +    return if /mswin|mingw/ =~ RUBY_PLATFORM + +    mkdir 'tmpdatadir' +    chmod 700, 'tmpdatadir' +    rm_rf 'tmpdatadir' + +    assert_file_not_exist 'tmpdatadir' +  end + +  def test_rmdir +    check_singleton :rmdir + +    begin +      Dir.rmdir '/' +    rescue Errno::ENOTEMPTY +    rescue => e +      assert_raise(e.class) { +        # Dir.rmdir('') raises Errno::ENOENT. +        # FileUtils#rmdir ignores it. +        # And this test failed as expected. +        rmdir '/' +      } +    end + +    subdir = 'data/sub/dir' +    mkdir_p(subdir) +    assert_nothing_raised(Errno::ENOENT) { +      rmdir(subdir, parents: true) +    } +    assert_file_not_exist(subdir) +    assert_file_not_exist('data/sub') +    assert_directory('data') +  end + +  def test_rmtree +    check_singleton :rmtree +  end + +  def test_safe_unlink +    check_singleton :safe_unlink +  end + +  def test_symlink +    check_singleton :symlink +  end + +  def test_touch +    check_singleton :touch +  end + +  def test_collect_methods +  end + +  def test_commands +  end + +  def test_have_option? +  end + +  def test_options +  end + +  def test_options_of +  end + +end  | 
