1# $Id: test_fileutils.rb 41946 2013-07-13 14:32:56Z nagachika $
2
3require 'fileutils'
4require_relative 'fileasserts'
5require 'pathname'
6require 'tmpdir'
7require 'test/unit'
8
9class TestFileUtils < Test::Unit::TestCase
10  TMPROOT = "#{Dir.tmpdir}/fileutils.rb.#{$$}"
11  include Test::Unit::FileAssertions
12end
13
14prevdir = Dir.pwd
15tmproot = TestFileUtils::TMPROOT
16Dir.mkdir tmproot unless File.directory?(tmproot)
17Dir.chdir tmproot
18
19def have_drive_letter?
20  /mswin(?!ce)|mingw|bcc|emx/ =~ RUBY_PLATFORM
21end
22
23def have_file_perm?
24  /mswin|mingw|bcc|emx/ !~ RUBY_PLATFORM
25end
26
27$fileutils_rb_have_symlink = nil
28
29def have_symlink?
30  if $fileutils_rb_have_symlink == nil
31    $fileutils_rb_have_symlink = check_have_symlink?
32  end
33  $fileutils_rb_have_symlink
34end
35
36def check_have_symlink?
37  File.symlink nil, nil
38rescue NotImplementedError
39  return false
40rescue
41  return true
42end
43
44$fileutils_rb_have_hardlink = nil
45
46def have_hardlink?
47  if $fileutils_rb_have_hardlink == nil
48    $fileutils_rb_have_hardlink = check_have_hardlink?
49  end
50  $fileutils_rb_have_hardlink
51end
52
53def check_have_hardlink?
54  File.link nil, nil
55rescue NotImplementedError
56  return false
57rescue
58  return true
59end
60
61begin
62  Dir.mkdir("\n")
63  Dir.rmdir("\n")
64  def lf_in_path_allowed?
65    true
66  end
67rescue
68  def lf_in_path_allowed?
69    false
70  end
71end
72
73Dir.chdir prevdir
74Dir.rmdir tmproot
75
76class TestFileUtils
77
78  include FileUtils
79
80  def check_singleton(name)
81    assert_respond_to ::FileUtils, name
82  end
83
84  def my_rm_rf(path)
85    if File.exist?('/bin/rm')
86      system %Q[/bin/rm -rf "#{path}"]
87    else
88      FileUtils.rm_rf path
89    end
90  end
91
92  def mymkdir(path)
93    Dir.mkdir path
94    File.chown nil, Process.gid, path if have_file_perm?
95  end
96
97  def setup
98    @prevdir = Dir.pwd
99    tmproot = TMPROOT
100    mymkdir tmproot unless File.directory?(tmproot)
101    Dir.chdir tmproot
102    my_rm_rf 'data'; mymkdir 'data'
103    my_rm_rf 'tmp';  mymkdir 'tmp'
104    prepare_data_file
105  end
106
107  def teardown
108    Dir.chdir @prevdir
109    my_rm_rf TMPROOT
110  end
111
112
113  TARGETS = %w( data/a data/all data/random data/zero )
114
115  def prepare_data_file
116    File.open('data/a', 'w') {|f|
117      32.times do
118        f.puts 'a' * 50
119      end
120    }
121
122    all_chars = (0..255).map {|n| n.chr }.join('')
123    File.open('data/all', 'w') {|f|
124      32.times do
125        f.puts all_chars
126      end
127    }
128
129    random_chars = (0...50).map { rand(256).chr }.join('')
130    File.open('data/random', 'w') {|f|
131      32.times do
132        f.puts random_chars
133      end
134    }
135
136    File.open('data/zero', 'w') {|f|
137      ;
138    }
139  end
140
141  BIGFILE = 'data/big'
142
143  def prepare_big_file
144    File.open('data/big', 'w') {|f|
145      (4 * 1024 * 1024 / 256).times do   # 4MB
146        f.print "aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa aaaa\n"
147      end
148    }
149  end
150
151  def prepare_time_data
152    File.open('data/old',    'w') {|f| f.puts 'dummy' }
153    File.open('data/newer',  'w') {|f| f.puts 'dummy' }
154    File.open('data/newest', 'w') {|f| f.puts 'dummy' }
155    t = Time.now
156    File.utime t-8, t-8, 'data/old'
157    File.utime t-4, t-4, 'data/newer'
158  end
159
160  def each_srcdest
161    TARGETS.each do |path|
162      yield path, "tmp/#{File.basename(path)}"
163    end
164  end
165
166  #
167  # Test Cases
168  #
169
170  def test_pwd
171    check_singleton :pwd
172
173    assert_equal Dir.pwd, pwd()
174
175    cwd = Dir.pwd
176    root = have_drive_letter? ? 'C:/' : '/'
177    cd(root) {
178      assert_equal root, pwd()
179    }
180    assert_equal cwd, pwd()
181  end
182
183  def test_cmp
184    check_singleton :cmp
185
186    TARGETS.each do |fname|
187      assert cmp(fname, fname), 'not same?'
188    end
189    assert_raise(ArgumentError) {
190      cmp TARGETS[0], TARGETS[0], :undefinedoption => true
191    }
192
193    # pathname
194    touch 'tmp/cmptmp'
195    assert_nothing_raised {
196      cmp Pathname.new('tmp/cmptmp'), 'tmp/cmptmp'
197      cmp 'tmp/cmptmp', Pathname.new('tmp/cmptmp')
198      cmp Pathname.new('tmp/cmptmp'), Pathname.new('tmp/cmptmp')
199    }
200  end
201
202  def test_cp
203    check_singleton :cp
204
205    each_srcdest do |srcpath, destpath|
206      cp srcpath, destpath
207      assert_same_file srcpath, destpath
208
209      cp srcpath, File.dirname(destpath)
210      assert_same_file srcpath, destpath
211
212      cp srcpath, File.dirname(destpath) + '/'
213      assert_same_file srcpath, destpath
214
215      cp srcpath, destpath, :preserve => true
216      assert_same_file srcpath, destpath
217      assert_same_entry srcpath, destpath
218    end
219
220    assert_raise(Errno::ENOENT) {
221      cp 'tmp/cptmp', 'tmp/cptmp_new'
222    }
223    assert_file_not_exist('tmp/cptmp_new')
224
225    # src==dest (1) same path
226    touch 'tmp/cptmp'
227    assert_raise(ArgumentError) {
228      cp 'tmp/cptmp', 'tmp/cptmp'
229    }
230  end
231
232  def test_cp_preserve_permissions
233    bug4507 = '[ruby-core:35518]'
234    touch 'tmp/cptmp'
235    chmod 0755, 'tmp/cptmp'
236    cp 'tmp/cptmp', 'tmp/cptmp2'
237    assert_equal(File.stat('tmp/cptmp').mode,
238                 File.stat('tmp/cptmp2').mode,
239                 bug4507)
240  end
241
242  def test_cp_preserve_permissions_dir
243    bug7246 = '[ruby-core:48603]'
244    mkdir 'tmp/cptmp'
245    mkdir 'tmp/cptmp/d1'
246    chmod 0745, 'tmp/cptmp/d1'
247    mkdir 'tmp/cptmp/d2'
248    chmod 0700, 'tmp/cptmp/d2'
249    cp_r 'tmp/cptmp', 'tmp/cptmp2', :preserve => true
250    assert_equal(File.stat('tmp/cptmp/d1').mode,
251                 File.stat('tmp/cptmp2/d1').mode,
252                 bug7246)
253    assert_equal(File.stat('tmp/cptmp/d2').mode,
254                 File.stat('tmp/cptmp2/d2').mode,
255                 bug7246)
256  end
257
258  def test_cp_symlink
259    touch 'tmp/cptmp'
260    # src==dest (2) symlink and its target
261    File.symlink 'cptmp', 'tmp/cptmp_symlink'
262    assert_raise(ArgumentError) {
263      cp 'tmp/cptmp', 'tmp/cptmp_symlink'
264    }
265    assert_raise(ArgumentError) {
266      cp 'tmp/cptmp_symlink', 'tmp/cptmp'
267    }
268    # src==dest (3) looped symlink
269    File.symlink 'symlink', 'tmp/symlink'
270    assert_raise(Errno::ELOOP) {
271      cp 'tmp/symlink', 'tmp/symlink'
272    }
273  end if have_symlink?
274
275  def test_cp_pathname
276    # pathname
277    touch 'tmp/cptmp'
278    assert_nothing_raised {
279      cp 'tmp/cptmp', Pathname.new('tmp/tmpdest')
280      cp Pathname.new('tmp/cptmp'), 'tmp/tmpdest'
281      cp Pathname.new('tmp/cptmp'), Pathname.new('tmp/tmpdest')
282      mkdir 'tmp/tmpdir'
283      cp ['tmp/cptmp', 'tmp/tmpdest'], Pathname.new('tmp/tmpdir')
284    }
285  end
286
287  def test_cp_r
288    check_singleton :cp_r
289
290    cp_r 'data', 'tmp'
291    TARGETS.each do |fname|
292      assert_same_file fname, "tmp/#{fname}"
293    end
294
295    cp_r 'data', 'tmp2', :preserve => true
296    TARGETS.each do |fname|
297      assert_same_entry fname, "tmp2/#{File.basename(fname)}"
298      assert_same_file fname, "tmp2/#{File.basename(fname)}"
299    end
300
301    # a/* -> b/*
302    mkdir 'tmp/cpr_src'
303    mkdir 'tmp/cpr_dest'
304    File.open('tmp/cpr_src/a', 'w') {|f| f.puts 'a' }
305    File.open('tmp/cpr_src/b', 'w') {|f| f.puts 'b' }
306    File.open('tmp/cpr_src/c', 'w') {|f| f.puts 'c' }
307    mkdir 'tmp/cpr_src/d'
308    cp_r 'tmp/cpr_src/.', 'tmp/cpr_dest'
309    assert_same_file 'tmp/cpr_src/a', 'tmp/cpr_dest/a'
310    assert_same_file 'tmp/cpr_src/b', 'tmp/cpr_dest/b'
311    assert_same_file 'tmp/cpr_src/c', 'tmp/cpr_dest/c'
312    assert_directory 'tmp/cpr_dest/d'
313    my_rm_rf 'tmp/cpr_src'
314    my_rm_rf 'tmp/cpr_dest'
315
316    bug3588 = '[ruby-core:31360]'
317    assert_nothing_raised(ArgumentError, bug3588) do
318      cp_r 'tmp', 'tmp2'
319    end
320    assert_directory 'tmp2/tmp'
321    assert_raise(ArgumentError, bug3588) do
322      cp_r 'tmp2', 'tmp2/new_tmp2'
323    end
324  end
325
326  def test_cp_r_symlink
327    # symlink in a directory
328    mkdir 'tmp/cpr_src'
329    ln_s 'SLdest', 'tmp/cpr_src/symlink'
330    cp_r 'tmp/cpr_src', 'tmp/cpr_dest'
331    assert_symlink 'tmp/cpr_dest/symlink'
332    assert_equal 'SLdest', File.readlink('tmp/cpr_dest/symlink')
333
334    # root is a symlink
335    ln_s 'cpr_src', 'tmp/cpr_src2'
336    cp_r 'tmp/cpr_src2', 'tmp/cpr_dest2'
337    assert_directory 'tmp/cpr_dest2'
338    assert_not_symlink 'tmp/cpr_dest2'
339    assert_symlink 'tmp/cpr_dest2/symlink'
340    assert_equal 'SLdest', File.readlink('tmp/cpr_dest2/symlink')
341  end if have_symlink?
342
343  def test_cp_r_symlink_preserve
344    mkdir 'tmp/cross'
345    mkdir 'tmp/cross/a'
346    mkdir 'tmp/cross/b'
347    touch 'tmp/cross/a/f'
348    touch 'tmp/cross/b/f'
349    ln_s '../a/f', 'tmp/cross/b/l'
350    ln_s '../b/f', 'tmp/cross/a/l'
351    assert_nothing_raised {
352      cp_r 'tmp/cross', 'tmp/cross2', :preserve => true
353    }
354  end if have_symlink?
355
356  def test_cp_r_pathname
357    # pathname
358    touch 'tmp/cprtmp'
359    assert_nothing_raised {
360      cp_r Pathname.new('tmp/cprtmp'), 'tmp/tmpdest'
361      cp_r 'tmp/cprtmp', Pathname.new('tmp/tmpdest')
362      cp_r Pathname.new('tmp/cprtmp'), Pathname.new('tmp/tmpdest')
363    }
364  end
365
366  def test_mv
367    check_singleton :mv
368
369    mkdir 'tmp/dest'
370    TARGETS.each do |fname|
371      cp fname, 'tmp/mvsrc'
372      mv 'tmp/mvsrc', 'tmp/mvdest'
373      assert_same_file fname, 'tmp/mvdest'
374
375      mv 'tmp/mvdest', 'tmp/dest/'
376      assert_same_file fname, 'tmp/dest/mvdest'
377
378      mv 'tmp/dest/mvdest', 'tmp'
379      assert_same_file fname, 'tmp/mvdest'
380    end
381
382    mkdir 'tmp/tmpdir'
383    mkdir_p 'tmp/dest2/tmpdir'
384    assert_raise(Errno::EEXIST) {
385      mv 'tmp/tmpdir', 'tmp/dest2'
386    }
387    mkdir 'tmp/dest2/tmpdir/junk'
388    assert_raise(Errno::EEXIST, "[ruby-talk:124368]") {
389      mv 'tmp/tmpdir', 'tmp/dest2'
390    }
391
392    # src==dest (1) same path
393    touch 'tmp/cptmp'
394    assert_raise(ArgumentError) {
395      mv 'tmp/cptmp', 'tmp/cptmp'
396    }
397  end
398
399  def test_mv_symlink
400    touch 'tmp/cptmp'
401    # src==dest (2) symlink and its target
402    File.symlink 'cptmp', 'tmp/cptmp_symlink'
403    assert_raise(ArgumentError) {
404      mv 'tmp/cptmp', 'tmp/cptmp_symlink'
405    }
406    assert_raise(ArgumentError) {
407      mv 'tmp/cptmp_symlink', 'tmp/cptmp'
408    }
409    # src==dest (3) looped symlink
410    File.symlink 'symlink', 'tmp/symlink'
411    assert_raise(Errno::ELOOP) {
412      mv 'tmp/symlink', 'tmp/symlink'
413    }
414  end if have_symlink?
415
416  def test_mv_pathname
417    # pathname
418    assert_nothing_raised {
419      touch 'tmp/mvtmpsrc'
420      mv Pathname.new('tmp/mvtmpsrc'), 'tmp/mvtmpdest'
421      touch 'tmp/mvtmpsrc'
422      mv 'tmp/mvtmpsrc', Pathname.new('tmp/mvtmpdest')
423      touch 'tmp/mvtmpsrc'
424      mv Pathname.new('tmp/mvtmpsrc'), Pathname.new('tmp/mvtmpdest')
425    }
426  end
427
428  def test_rm
429    check_singleton :rm
430
431    TARGETS.each do |fname|
432      cp fname, 'tmp/rmsrc'
433      rm 'tmp/rmsrc'
434      assert_file_not_exist 'tmp/rmsrc'
435    end
436
437    # pathname
438    touch 'tmp/rmtmp1'
439    touch 'tmp/rmtmp2'
440    touch 'tmp/rmtmp3'
441    assert_nothing_raised {
442      rm Pathname.new('tmp/rmtmp1')
443      rm [Pathname.new('tmp/rmtmp2'), Pathname.new('tmp/rmtmp3')]
444    }
445    assert_file_not_exist 'tmp/rmtmp1'
446    assert_file_not_exist 'tmp/rmtmp2'
447    assert_file_not_exist 'tmp/rmtmp3'
448  end
449
450  def test_rm_f
451    check_singleton :rm_f
452
453    TARGETS.each do |fname|
454      cp fname, 'tmp/rmsrc'
455      rm_f 'tmp/rmsrc'
456      assert_file_not_exist 'tmp/rmsrc'
457    end
458  end
459
460  def test_rm_symlink
461    File.open('tmp/lnf_symlink_src', 'w') {|f| f.puts 'dummy' }
462    File.symlink 'tmp/lnf_symlink_src', 'tmp/lnf_symlink_dest'
463    rm_f 'tmp/lnf_symlink_dest'
464    assert_file_not_exist 'tmp/lnf_symlink_dest'
465    assert_file_exist     'tmp/lnf_symlink_src'
466
467    rm_f 'notexistdatafile'
468    rm_f 'tmp/notexistdatafile'
469    my_rm_rf 'tmpdatadir'
470    Dir.mkdir 'tmpdatadir'
471    # rm_f 'tmpdatadir'
472    Dir.rmdir 'tmpdatadir'
473  end if have_symlink?
474
475  def test_rm_f_2
476    Dir.mkdir 'tmp/tmpdir'
477    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' }
478    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' }
479    rm_f ['tmp/tmpdir/a', 'tmp/tmpdir/b', 'tmp/tmpdir/c']
480    assert_file_not_exist 'tmp/tmpdir/a'
481    assert_file_not_exist 'tmp/tmpdir/c'
482    Dir.rmdir 'tmp/tmpdir'
483  end
484
485  def test_rm_pathname
486    # pathname
487    touch 'tmp/rmtmp1'
488    touch 'tmp/rmtmp2'
489    touch 'tmp/rmtmp3'
490    touch 'tmp/rmtmp4'
491    assert_nothing_raised {
492      rm_f Pathname.new('tmp/rmtmp1')
493      rm_f [Pathname.new('tmp/rmtmp2'), Pathname.new('tmp/rmtmp3')]
494    }
495    assert_file_not_exist 'tmp/rmtmp1'
496    assert_file_not_exist 'tmp/rmtmp2'
497    assert_file_not_exist 'tmp/rmtmp3'
498    assert_file_exist 'tmp/rmtmp4'
499
500    # [ruby-dev:39345]
501    touch 'tmp/[rmtmp]'
502    FileUtils.rm_f 'tmp/[rmtmp]'
503    assert_file_not_exist 'tmp/[rmtmp]'
504  end
505
506  def test_rm_r
507    check_singleton :rm_r
508
509    my_rm_rf 'tmpdatadir'
510
511    Dir.mkdir 'tmpdatadir'
512    rm_r 'tmpdatadir'
513    assert_file_not_exist 'tmpdatadir'
514
515    Dir.mkdir 'tmpdatadir'
516    rm_r 'tmpdatadir/'
517    assert_file_not_exist 'tmpdatadir'
518
519    Dir.mkdir 'tmp/tmpdir'
520    rm_r 'tmp/tmpdir/'
521    assert_file_not_exist 'tmp/tmpdir'
522    assert_file_exist     'tmp'
523
524    Dir.mkdir 'tmp/tmpdir'
525    rm_r 'tmp/tmpdir'
526    assert_file_not_exist 'tmp/tmpdir'
527    assert_file_exist     'tmp'
528
529    Dir.mkdir 'tmp/tmpdir'
530    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' }
531    File.open('tmp/tmpdir/b', 'w') {|f| f.puts 'dummy' }
532    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' }
533    rm_r 'tmp/tmpdir'
534    assert_file_not_exist 'tmp/tmpdir'
535    assert_file_exist     'tmp'
536
537    Dir.mkdir 'tmp/tmpdir'
538    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' }
539    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' }
540    rm_r ['tmp/tmpdir/a', 'tmp/tmpdir/b', 'tmp/tmpdir/c'], :force => true
541    assert_file_not_exist 'tmp/tmpdir/a'
542    assert_file_not_exist 'tmp/tmpdir/c'
543    Dir.rmdir 'tmp/tmpdir'
544  end
545
546  def test_rm_r_symlink
547    # [ruby-talk:94635] a symlink to the directory
548    Dir.mkdir 'tmp/tmpdir'
549    File.symlink '..', 'tmp/tmpdir/symlink_to_dir'
550    rm_r 'tmp/tmpdir'
551    assert_file_not_exist 'tmp/tmpdir'
552    assert_file_exist     'tmp'
553  end if have_symlink?
554
555  def test_rm_r_pathname
556    # pathname
557    Dir.mkdir 'tmp/tmpdir1'; touch 'tmp/tmpdir1/tmp'
558    Dir.mkdir 'tmp/tmpdir2'; touch 'tmp/tmpdir2/tmp'
559    Dir.mkdir 'tmp/tmpdir3'; touch 'tmp/tmpdir3/tmp'
560    assert_nothing_raised {
561      rm_r Pathname.new('tmp/tmpdir1')
562      rm_r [Pathname.new('tmp/tmpdir2'), Pathname.new('tmp/tmpdir3')]
563    }
564    assert_file_not_exist 'tmp/tmpdir1'
565    assert_file_not_exist 'tmp/tmpdir2'
566    assert_file_not_exist 'tmp/tmpdir3'
567  end
568
569  def test_remove_entry_secure
570    check_singleton :remove_entry_secure
571
572    my_rm_rf 'tmpdatadir'
573
574    Dir.mkdir 'tmpdatadir'
575    remove_entry_secure 'tmpdatadir'
576    assert_file_not_exist 'tmpdatadir'
577
578    Dir.mkdir 'tmpdatadir'
579    remove_entry_secure 'tmpdatadir/'
580    assert_file_not_exist 'tmpdatadir'
581
582    Dir.mkdir 'tmp/tmpdir'
583    remove_entry_secure 'tmp/tmpdir/'
584    assert_file_not_exist 'tmp/tmpdir'
585    assert_file_exist     'tmp'
586
587    Dir.mkdir 'tmp/tmpdir'
588    remove_entry_secure 'tmp/tmpdir'
589    assert_file_not_exist 'tmp/tmpdir'
590    assert_file_exist     'tmp'
591
592    Dir.mkdir 'tmp/tmpdir'
593    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' }
594    File.open('tmp/tmpdir/b', 'w') {|f| f.puts 'dummy' }
595    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' }
596    remove_entry_secure 'tmp/tmpdir'
597    assert_file_not_exist 'tmp/tmpdir'
598    assert_file_exist     'tmp'
599
600    Dir.mkdir 'tmp/tmpdir'
601    File.open('tmp/tmpdir/a', 'w') {|f| f.puts 'dummy' }
602    File.open('tmp/tmpdir/c', 'w') {|f| f.puts 'dummy' }
603    remove_entry_secure 'tmp/tmpdir/a', true
604    remove_entry_secure 'tmp/tmpdir/b', true
605    remove_entry_secure 'tmp/tmpdir/c', true
606    assert_file_not_exist 'tmp/tmpdir/a'
607    assert_file_not_exist 'tmp/tmpdir/c'
608    Dir.rmdir 'tmp/tmpdir'
609  end
610
611  def test_remove_entry_secure_symlink
612    # [ruby-talk:94635] a symlink to the directory
613    Dir.mkdir 'tmp/tmpdir'
614    File.symlink '..', 'tmp/tmpdir/symlink_to_dir'
615    remove_entry_secure 'tmp/tmpdir'
616    assert_file_not_exist 'tmp/tmpdir'
617    assert_file_exist     'tmp'
618  end if have_symlink?
619
620  def test_remove_entry_secure_pathname
621    # pathname
622    Dir.mkdir 'tmp/tmpdir1'; touch 'tmp/tmpdir1/tmp'
623    assert_nothing_raised {
624      remove_entry_secure Pathname.new('tmp/tmpdir1')
625    }
626    assert_file_not_exist 'tmp/tmpdir1'
627  end
628
629  def test_with_big_file
630    prepare_big_file
631
632    cp BIGFILE, 'tmp/cpdest'
633    assert_same_file BIGFILE, 'tmp/cpdest'
634    assert cmp(BIGFILE, 'tmp/cpdest'), 'orig != copied'
635
636    mv 'tmp/cpdest', 'tmp/mvdest'
637    assert_same_file BIGFILE, 'tmp/mvdest'
638    assert_file_not_exist 'tmp/cpdest'
639
640    rm 'tmp/mvdest'
641    assert_file_not_exist 'tmp/mvdest'
642  end
643
644  def test_ln
645    TARGETS.each do |fname|
646      ln fname, 'tmp/lndest'
647      assert_same_file fname, 'tmp/lndest'
648      File.unlink 'tmp/lndest'
649    end
650
651    ln TARGETS, 'tmp'
652    TARGETS.each do |fname|
653      assert_same_file fname, 'tmp/' + File.basename(fname)
654    end
655    TARGETS.each do |fname|
656      File.unlink 'tmp/' + File.basename(fname)
657    end
658
659    # src==dest (1) same path
660    touch 'tmp/cptmp'
661    assert_raise(Errno::EEXIST) {
662      ln 'tmp/cptmp', 'tmp/cptmp'
663    }
664  end if have_hardlink?
665
666  def test_ln_symlink
667    touch 'tmp/cptmp'
668    # src==dest (2) symlink and its target
669    File.symlink 'cptmp', 'tmp/symlink'
670    assert_raise(Errno::EEXIST) {
671      ln 'tmp/cptmp', 'tmp/symlink'   # normal file -> symlink
672    }
673    assert_raise(Errno::EEXIST) {
674      ln 'tmp/symlink', 'tmp/cptmp'   # symlink -> normal file
675    }
676    # src==dest (3) looped symlink
677    File.symlink 'cptmp_symlink', 'tmp/cptmp_symlink'
678    begin
679      ln 'tmp/cptmp_symlink', 'tmp/cptmp_symlink'
680    rescue => err
681      assert_kind_of SystemCallError, err
682    end
683  end if have_symlink?
684
685  def test_ln_pathname
686    # pathname
687    touch 'tmp/lntmp'
688    assert_nothing_raised {
689      ln Pathname.new('tmp/lntmp'), 'tmp/lndesttmp1'
690      ln 'tmp/lntmp', Pathname.new('tmp/lndesttmp2')
691      ln Pathname.new('tmp/lntmp'), Pathname.new('tmp/lndesttmp3')
692    }
693  end if have_hardlink?
694
695  def test_ln_s
696    check_singleton :ln_s
697
698    TARGETS.each do |fname|
699      ln_s fname, 'tmp/lnsdest'
700      assert FileTest.symlink?('tmp/lnsdest'), 'not symlink'
701      assert_equal fname, File.readlink('tmp/lnsdest')
702      rm_f 'tmp/lnsdest'
703    end
704    assert_nothing_raised {
705      ln_s 'symlink', 'tmp/symlink'
706    }
707    assert_symlink 'tmp/symlink'
708
709    # pathname
710    touch 'tmp/lnsdest'
711    assert_nothing_raised {
712      ln_s Pathname.new('lnsdest'), 'tmp/symlink_tmp1'
713      ln_s 'lnsdest', Pathname.new('tmp/symlink_tmp2')
714      ln_s Pathname.new('lnsdest'), Pathname.new('tmp/symlink_tmp3')
715    }
716  end if have_symlink?
717
718  def test_ln_sf
719    check_singleton :ln_sf
720
721    TARGETS.each do |fname|
722      ln_sf fname, 'tmp/lnsdest'
723      assert FileTest.symlink?('tmp/lnsdest'), 'not symlink'
724      assert_equal fname, File.readlink('tmp/lnsdest')
725      ln_sf fname, 'tmp/lnsdest'
726      ln_sf fname, 'tmp/lnsdest'
727    end
728    assert_nothing_raised {
729      ln_sf 'symlink', 'tmp/symlink'
730    }
731
732    # pathname
733    touch 'tmp/lns_dest'
734    assert_nothing_raised {
735      ln_sf Pathname.new('lns_dest'), 'tmp/symlink_tmp1'
736      ln_sf 'lns_dest', Pathname.new('tmp/symlink_tmp2')
737      ln_sf Pathname.new('lns_dest'), Pathname.new('tmp/symlink_tmp3')
738    }
739  end if have_symlink?
740
741  def test_mkdir
742    check_singleton :mkdir
743
744    my_rm_rf 'tmpdatadir'
745    mkdir 'tmpdatadir'
746    assert_directory 'tmpdatadir'
747    Dir.rmdir 'tmpdatadir'
748
749    mkdir 'tmpdatadir/'
750    assert_directory 'tmpdatadir'
751    Dir.rmdir 'tmpdatadir'
752
753    mkdir 'tmp/mkdirdest'
754    assert_directory 'tmp/mkdirdest'
755    Dir.rmdir 'tmp/mkdirdest'
756
757    mkdir 'tmp/tmp', :mode => 0700
758    assert_directory 'tmp/tmp'
759    assert_equal 0700, (File.stat('tmp/tmp').mode & 0777) if have_file_perm?
760    Dir.rmdir 'tmp/tmp'
761  end
762
763  def test_mkdir_file_perm
764    mkdir 'tmp/tmp', :mode => 07777
765    assert_directory 'tmp/tmp'
766    assert_equal 07777, (File.stat('tmp/tmp').mode & 07777)
767    Dir.rmdir 'tmp/tmp'
768  end if have_file_perm?
769
770  def test_mkdir_lf_in_path
771    mkdir "tmp-first-line\ntmp-second-line"
772    assert_directory "tmp-first-line\ntmp-second-line"
773    Dir.rmdir "tmp-first-line\ntmp-second-line"
774  end if lf_in_path_allowed?
775
776  def test_mkdir_pathname
777    # pathname
778    assert_nothing_raised {
779      mkdir Pathname.new('tmp/tmpdirtmp')
780      mkdir [Pathname.new('tmp/tmpdirtmp2'), Pathname.new('tmp/tmpdirtmp3')]
781    }
782  end
783
784  def test_mkdir_p
785    check_singleton :mkdir_p
786
787    dirs = %w(
788      tmpdir/dir/
789      tmpdir/dir/./
790      tmpdir/dir/./.././dir/
791      tmpdir/a
792      tmpdir/a/
793      tmpdir/a/b
794      tmpdir/a/b/
795      tmpdir/a/b/c/
796      tmpdir/a/b/c
797      tmpdir/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a/a
798      tmpdir/a/a
799    )
800    my_rm_rf 'tmpdir'
801    dirs.each do |d|
802      mkdir_p d
803      assert_directory d
804      assert_file_not_exist "#{d}/a"
805      assert_file_not_exist "#{d}/b"
806      assert_file_not_exist "#{d}/c"
807      my_rm_rf 'tmpdir'
808    end
809    dirs.each do |d|
810      mkdir_p d
811      assert_directory d
812    end
813    rm_rf 'tmpdir'
814    dirs.each do |d|
815      mkdir_p "#{Dir.pwd}/#{d}"
816      assert_directory d
817    end
818    rm_rf 'tmpdir'
819
820    mkdir_p 'tmp/tmp/tmp', :mode => 0700
821    assert_directory 'tmp/tmp'
822    assert_directory 'tmp/tmp/tmp'
823    assert_equal 0700, (File.stat('tmp/tmp').mode & 0777) if have_file_perm?
824    assert_equal 0700, (File.stat('tmp/tmp/tmp').mode & 0777) if have_file_perm?
825    rm_rf 'tmp/tmp'
826
827    mkdir_p 'tmp/tmp', :mode => 0
828    assert_directory 'tmp/tmp'
829    assert_equal 0, (File.stat('tmp/tmp').mode & 0777) if have_file_perm?
830    # DO NOT USE rm_rf here.
831    # (rm(1) try to chdir to parent directory, it fails to remove directory.)
832    Dir.rmdir 'tmp/tmp'
833    Dir.rmdir 'tmp'
834  end
835
836  def test_mkdir_p_file_perm
837    mkdir_p 'tmp/tmp/tmp', :mode => 07777
838    assert_directory 'tmp/tmp/tmp'
839    assert_equal 07777, (File.stat('tmp/tmp/tmp').mode & 07777)
840    Dir.rmdir 'tmp/tmp/tmp'
841    Dir.rmdir 'tmp/tmp'
842  end if have_file_perm?
843
844  def test_mkdir_p_pathname
845    # pathname
846    assert_nothing_raised {
847      mkdir_p Pathname.new('tmp/tmp/tmp')
848    }
849  end
850
851  def test_install
852    check_singleton :install
853
854    File.open('tmp/aaa', 'w') {|f| f.puts 'aaa' }
855    File.open('tmp/bbb', 'w') {|f| f.puts 'bbb' }
856    install 'tmp/aaa', 'tmp/bbb', :mode => 0600
857    assert_equal "aaa\n", File.read('tmp/bbb')
858    assert_equal 0600, (File.stat('tmp/bbb').mode & 0777) if have_file_perm?
859
860    t = File.mtime('tmp/bbb')
861    install 'tmp/aaa', 'tmp/bbb'
862    assert_equal "aaa\n", File.read('tmp/bbb')
863    assert_equal 0600, (File.stat('tmp/bbb').mode & 0777) if have_file_perm?
864    assert_equal_time t, File.mtime('tmp/bbb')
865
866    File.unlink 'tmp/aaa'
867    File.unlink 'tmp/bbb'
868
869    # src==dest (1) same path
870    touch 'tmp/cptmp'
871    assert_raise(ArgumentError) {
872      install 'tmp/cptmp', 'tmp/cptmp'
873    }
874  end
875
876  def test_install_symlink
877    touch 'tmp/cptmp'
878    # src==dest (2) symlink and its target
879    File.symlink 'cptmp', 'tmp/cptmp_symlink'
880    assert_raise(ArgumentError) {
881      install 'tmp/cptmp', 'tmp/cptmp_symlink'
882    }
883    assert_raise(ArgumentError) {
884      install 'tmp/cptmp_symlink', 'tmp/cptmp'
885    }
886    # src==dest (3) looped symlink
887    File.symlink 'symlink', 'tmp/symlink'
888    assert_raise(Errno::ELOOP) {
889      # File#install invokes open(2), always ELOOP must be raised
890      install 'tmp/symlink', 'tmp/symlink'
891    }
892  end if have_symlink?
893
894  def test_install_pathname
895    # pathname
896    assert_nothing_raised {
897      rm_f 'tmp/a'; touch 'tmp/a'
898      install 'tmp/a', Pathname.new('tmp/b')
899      rm_f 'tmp/a'; touch 'tmp/a'
900      install Pathname.new('tmp/a'), 'tmp/b'
901      rm_f 'tmp/a'; touch 'tmp/a'
902      install Pathname.new('tmp/a'), Pathname.new('tmp/b')
903      rm_f 'tmp/a'
904      touch 'tmp/a'
905      touch 'tmp/b'
906      mkdir 'tmp/dest'
907      install [Pathname.new('tmp/a'), Pathname.new('tmp/b')], 'tmp/dest'
908      my_rm_rf 'tmp/dest'
909      mkdir 'tmp/dest'
910      install [Pathname.new('tmp/a'), Pathname.new('tmp/b')], Pathname.new('tmp/dest')
911    }
912  end
913
914  def test_chmod
915    check_singleton :chmod
916
917    touch 'tmp/a'
918    chmod 0700, 'tmp/a'
919    assert_equal 0700, File.stat('tmp/a').mode & 0777
920    chmod 0500, 'tmp/a'
921    assert_equal 0500, File.stat('tmp/a').mode & 0777
922  end if have_file_perm?
923
924  def test_chmod_symbol_mode
925    check_singleton :chmod
926
927    touch 'tmp/a'
928    chmod "u=wrx,g=,o=", 'tmp/a'
929    assert_equal 0700, File.stat('tmp/a').mode & 0777
930    chmod "u=rx,go=", 'tmp/a'
931    assert_equal 0500, File.stat('tmp/a').mode & 0777
932    chmod "+wrx", 'tmp/a'
933    assert_equal 0777, File.stat('tmp/a').mode & 0777
934    chmod "u+s,o=s", 'tmp/a'
935    assert_equal 04770, File.stat('tmp/a').mode & 07777
936    chmod "u-w,go-wrx", 'tmp/a'
937    assert_equal 04500, File.stat('tmp/a').mode & 07777
938    chmod "+s", 'tmp/a'
939    assert_equal 06500, File.stat('tmp/a').mode & 07777
940
941    # FreeBSD ufs and tmpfs don't allow to change sticky bit against
942    # regular file. It's slightly strange. Anyway it's no effect bit.
943    # see /usr/src/sys/ufs/ufs/ufs_chmod()
944    # NetBSD, OpenBSD and Solaris also denies it.
945    if /freebsd|netbsd|openbsd|solaris/ !~ RUBY_PLATFORM
946      chmod "u+t,o+t", 'tmp/a'
947      assert_equal 07500, File.stat('tmp/a').mode & 07777
948      chmod "a-t,a-s", 'tmp/a'
949      assert_equal 0500, File.stat('tmp/a').mode & 07777
950    end
951
952  end if have_file_perm?
953
954
955  def test_chmod_R
956    check_singleton :chmod_R
957
958    mkdir_p 'tmp/dir/dir'
959    touch %w( tmp/dir/file tmp/dir/dir/file )
960    chmod_R 0700, 'tmp/dir'
961    assert_equal 0700, File.stat('tmp/dir').mode & 0777
962    assert_equal 0700, File.stat('tmp/dir/file').mode & 0777
963    assert_equal 0700, File.stat('tmp/dir/dir').mode & 0777
964    assert_equal 0700, File.stat('tmp/dir/dir/file').mode & 0777
965    chmod_R 0500, 'tmp/dir'
966    assert_equal 0500, File.stat('tmp/dir').mode & 0777
967    assert_equal 0500, File.stat('tmp/dir/file').mode & 0777
968    assert_equal 0500, File.stat('tmp/dir/dir').mode & 0777
969    assert_equal 0500, File.stat('tmp/dir/dir/file').mode & 0777
970    chmod_R 0700, 'tmp/dir'   # to remove
971  end if have_file_perm?
972
973  def test_chmod_symbol_mode_R
974    check_singleton :chmod_R
975
976    mkdir_p 'tmp/dir/dir'
977    touch %w( tmp/dir/file tmp/dir/dir/file )
978    chmod_R "u=wrx,g=,o=", 'tmp/dir'
979    assert_equal 0700, File.stat('tmp/dir').mode & 0777
980    assert_equal 0700, File.stat('tmp/dir/file').mode & 0777
981    assert_equal 0700, File.stat('tmp/dir/dir').mode & 0777
982    assert_equal 0700, File.stat('tmp/dir/dir/file').mode & 0777
983    chmod_R "u=xr,g+X,o=", 'tmp/dir'
984    assert_equal 0510, File.stat('tmp/dir').mode & 0777
985    assert_equal 0500, File.stat('tmp/dir/file').mode & 0777
986    assert_equal 0510, File.stat('tmp/dir/dir').mode & 0777
987    assert_equal 0500, File.stat('tmp/dir/dir/file').mode & 0777
988    chmod_R 0700, 'tmp/dir'   # to remove
989  end if have_file_perm?
990
991  def test_chmod_verbose
992    check_singleton :chmod
993
994    stderr_back = $stderr
995    read, $stderr = IO.pipe
996    th = Thread.new { read.read }
997
998    touch 'tmp/a'
999    chmod 0700, 'tmp/a', verbose: true
1000    assert_equal 0700, File.stat('tmp/a').mode & 0777
1001    chmod 0500, 'tmp/a', verbose: true
1002    assert_equal 0500, File.stat('tmp/a').mode & 0777
1003
1004    $stderr.close
1005    lines = th.value.lines.map {|l| l.chomp }
1006    assert_equal(["chmod 700 tmp/a", "chmod 500 tmp/a"], lines)
1007  ensure
1008    $stderr = stderr_back if stderr_back
1009  end if have_file_perm?
1010
1011  def test_s_chmod_verbose
1012    output_back = FileUtils.instance_variable_get(:@fileutils_output)
1013    read, write = IO.pipe
1014    FileUtils.instance_variable_set(:@fileutils_output, write)
1015    th = Thread.new { read.read }
1016
1017    touch 'tmp/a'
1018    FileUtils.chmod 0700, 'tmp/a', verbose: true
1019    assert_equal 0700, File.stat('tmp/a').mode & 0777
1020
1021    write.close
1022    lines = th.value.lines.map {|l| l.chomp }
1023    assert_equal(["chmod 700 tmp/a"], lines)
1024  ensure
1025    FileUtils.instance_variable_set(:@fileutils_output, output_back) if output_back
1026  end if have_file_perm?
1027
1028  # FIXME: How can I test this method?
1029  def test_chown
1030    check_singleton :chown
1031  end if have_file_perm?
1032
1033  # FIXME: How can I test this method?
1034  def test_chown_R
1035    check_singleton :chown_R
1036  end if have_file_perm?
1037
1038  def test_copy_entry
1039    check_singleton :copy_entry
1040
1041    each_srcdest do |srcpath, destpath|
1042      copy_entry srcpath, destpath
1043      assert_same_file srcpath, destpath
1044      assert_equal File.stat(srcpath).ftype, File.stat(destpath).ftype
1045    end
1046  end
1047
1048  def test_copy_entry_symlink
1049    # root is a symlink
1050    File.symlink 'somewhere', 'tmp/symsrc'
1051    copy_entry 'tmp/symsrc', 'tmp/symdest'
1052    assert_symlink 'tmp/symdest'
1053    assert_equal 'somewhere', File.readlink('tmp/symdest')
1054
1055    # content is a symlink
1056    mkdir 'tmp/dir'
1057    File.symlink 'somewhere', 'tmp/dir/sym'
1058    copy_entry 'tmp/dir', 'tmp/dirdest'
1059    assert_directory 'tmp/dirdest'
1060    assert_not_symlink 'tmp/dirdest'
1061    assert_symlink 'tmp/dirdest/sym'
1062    assert_equal 'somewhere', File.readlink('tmp/dirdest/sym')
1063  end if have_symlink?
1064
1065  def test_copy_file
1066    check_singleton :copy_file
1067
1068    each_srcdest do |srcpath, destpath|
1069      copy_file srcpath, destpath
1070      assert_same_file srcpath, destpath
1071    end
1072  end
1073
1074  def test_copy_stream
1075    check_singleton :copy_stream
1076    # IO
1077    each_srcdest do |srcpath, destpath|
1078      File.open(srcpath, 'rb') {|src|
1079        File.open(destpath, 'wb') {|dest|
1080          copy_stream src, dest
1081        }
1082      }
1083      assert_same_file srcpath, destpath
1084    end
1085  end
1086
1087  def test_copy_stream_duck
1088    check_singleton :copy_stream
1089    # duck typing test  [ruby-dev:25369]
1090    each_srcdest do |srcpath, destpath|
1091      File.open(srcpath, 'rb') {|src|
1092        File.open(destpath, 'wb') {|dest|
1093          copy_stream Stream.new(src), Stream.new(dest)
1094        }
1095      }
1096      assert_same_file srcpath, destpath
1097    end
1098  end
1099
1100  def test_remove_file
1101    check_singleton :remove_file
1102    File.open('data/tmp', 'w') {|f| f.puts 'dummy' }
1103    remove_file 'data/tmp'
1104    assert_file_not_exist 'data/tmp'
1105  end
1106
1107  def test_remove_file_file_perm
1108    File.open('data/tmp', 'w') {|f| f.puts 'dummy' }
1109    File.chmod 0, 'data/tmp'
1110    remove_file 'data/tmp'
1111    assert_file_not_exist 'data/tmp'
1112  end if have_file_perm?
1113
1114  def test_remove_dir
1115    check_singleton :remove_dir
1116    Dir.mkdir 'data/tmpdir'
1117    File.open('data/tmpdir/a', 'w') {|f| f.puts 'dummy' }
1118    remove_dir 'data/tmpdir'
1119    assert_file_not_exist 'data/tmpdir'
1120  end
1121
1122  def test_remove_dir_file_perm
1123    Dir.mkdir 'data/tmpdir'
1124    File.chmod 0555, 'data/tmpdir'
1125    remove_dir 'data/tmpdir'
1126    assert_file_not_exist 'data/tmpdir'
1127  end if have_file_perm?
1128
1129  def test_compare_file
1130    check_singleton :compare_file
1131    # FIXME
1132  end
1133
1134  def test_compare_stream
1135    check_singleton :compare_stream
1136    # FIXME
1137  end
1138
1139  class Stream
1140    def initialize(f)
1141      @f = f
1142    end
1143
1144    def read(*args)
1145      @f.read(*args)
1146    end
1147
1148    def write(str)
1149      @f.write str
1150    end
1151  end
1152
1153  def test_uptodate?
1154    check_singleton :uptodate?
1155    prepare_time_data
1156    Dir.chdir('data') {
1157      assert(   uptodate?('newest', %w(old newer notexist)) )
1158      assert( ! uptodate?('newer', %w(old newest notexist)) )
1159      assert( ! uptodate?('notexist', %w(old newest newer)) )
1160    }
1161
1162    # pathname
1163    touch 'tmp/a'
1164    touch 'tmp/b'
1165    touch 'tmp/c'
1166    assert_nothing_raised {
1167      uptodate? Pathname.new('tmp/a'), ['tmp/b', 'tmp/c']
1168      uptodate? 'tmp/a', [Pathname.new('tmp/b'), 'tmp/c']
1169      uptodate? 'tmp/a', ['tmp/b', Pathname.new('tmp/c')]
1170      uptodate? Pathname.new('tmp/a'), [Pathname.new('tmp/b'), Pathname.new('tmp/c')]
1171    }
1172    # [Bug #6708] [ruby-core:46256]
1173    assert_raises_with_message(ArgumentError, "wrong number of arguments (3 for 2)") {
1174      uptodate?('new',['old', 'oldest'], {})
1175    }
1176  end
1177
1178  def assert_raises_with_message(klass, message)
1179    begin
1180      yield
1181      flunk("Expected Exception #{klass} didn't raise")
1182    rescue klass => ex
1183      if message.kind_of? String
1184        flag = !!(ex.message == message)
1185        assert(flag, "Expected Exception(#{klass}) was raised, but the message doesn't match")
1186      elsif message.kind_of? Regexp
1187        flag = !!(ex.message =~ message)
1188        assert(flag, "Expected Exception(#{klass}) was raised, but the message doesn't match")
1189      else
1190        raise
1191      end
1192    end
1193  end
1194  private :assert_raises_with_message
1195
1196  def test_cd
1197    check_singleton :cd
1198  end
1199
1200  def test_chdir
1201    check_singleton :chdir
1202  end
1203
1204  def test_getwd
1205    check_singleton :getwd
1206  end
1207
1208  def test_identical?
1209    check_singleton :identical?
1210  end
1211
1212  def test_link
1213    check_singleton :link
1214  end
1215
1216  def test_makedirs
1217    check_singleton :makedirs
1218  end
1219
1220  def test_mkpath
1221    check_singleton :mkpath
1222  end
1223
1224  def test_move
1225    check_singleton :move
1226  end
1227
1228  def test_rm_rf
1229    check_singleton :rm_rf
1230  end
1231
1232  def test_rmdir
1233    check_singleton :rmdir
1234  end
1235
1236  def test_rmtree
1237    check_singleton :rmtree
1238  end
1239
1240  def test_safe_unlink
1241    check_singleton :safe_unlink
1242  end
1243
1244  def test_symlink
1245    check_singleton :symlink
1246  end
1247
1248  def test_touch
1249    check_singleton :touch
1250  end
1251
1252  def test_collect_methods
1253  end
1254
1255  def test_commands
1256  end
1257
1258  def test_have_option?
1259  end
1260
1261  def test_options
1262  end
1263
1264  def test_options_of
1265  end
1266
1267end
1268