1require 'test/unit'
2require 'find'
3require 'tmpdir'
4
5class TestFind < Test::Unit::TestCase
6  def test_empty
7    Dir.mktmpdir {|d|
8      a = []
9      Find.find(d) {|f| a << f }
10      assert_equal([d], a)
11    }
12  end
13
14  def test_rec
15    Dir.mktmpdir {|d|
16      File.open("#{d}/a", "w"){}
17      Dir.mkdir("#{d}/b")
18      File.open("#{d}/b/a", "w"){}
19      File.open("#{d}/b/b", "w"){}
20      Dir.mkdir("#{d}/c")
21      a = []
22      Find.find(d) {|f| a << f }
23      assert_equal([d, "#{d}/a", "#{d}/b", "#{d}/b/a", "#{d}/b/b", "#{d}/c"], a)
24    }
25  end
26
27  def test_relative
28    Dir.mktmpdir {|d|
29      File.open("#{d}/a", "w"){}
30      Dir.mkdir("#{d}/b")
31      File.open("#{d}/b/a", "w"){}
32      File.open("#{d}/b/b", "w"){}
33      Dir.mkdir("#{d}/c")
34      a = []
35      Dir.chdir(d) {
36        Find.find(".") {|f| a << f }
37      }
38      assert_equal([".", "./a", "./b", "./b/a", "./b/b", "./c"], a)
39    }
40  end
41
42  def test_dont_follow_symlink
43    Dir.mktmpdir {|d|
44      File.open("#{d}/a", "w"){}
45      Dir.mkdir("#{d}/b")
46      File.open("#{d}/b/a", "w"){}
47      File.open("#{d}/b/b", "w"){}
48      begin
49        File.symlink("#{d}/b", "#{d}/c")
50      rescue NotImplementedError
51        skip "symlink is not supported."
52      end
53      a = []
54      Find.find(d) {|f| a << f }
55      assert_equal([d, "#{d}/a", "#{d}/b", "#{d}/b/a", "#{d}/b/b", "#{d}/c"], a)
56    }
57  end
58
59  def test_prune
60    Dir.mktmpdir {|d|
61      File.open("#{d}/a", "w"){}
62      Dir.mkdir("#{d}/b")
63      File.open("#{d}/b/a", "w"){}
64      File.open("#{d}/b/b", "w"){}
65      Dir.mkdir("#{d}/c")
66      a = []
67      Find.find(d) {|f|
68        a << f
69        Find.prune if f == "#{d}/b"
70      }
71      assert_equal([d, "#{d}/a", "#{d}/b", "#{d}/c"], a)
72    }
73  end
74
75  def test_countup3
76    Dir.mktmpdir {|d|
77      1.upto(3) {|n| File.open("#{d}/#{n}", "w"){} }
78      a = []
79      Find.find(d) {|f| a << f }
80      assert_equal([d, "#{d}/1", "#{d}/2", "#{d}/3"], a)
81    }
82  end
83
84  def test_countdown3
85    Dir.mktmpdir {|d|
86      3.downto(1) {|n| File.open("#{d}/#{n}", "w"){} }
87      a = []
88      Find.find(d) {|f| a << f }
89      assert_equal([d, "#{d}/1", "#{d}/2", "#{d}/3"], a)
90    }
91  end
92
93  def test_unreadable_dir
94    skip "no meaning test on Windows" if /mswin|mingw/ =~ RUBY_PLATFORM
95    Dir.mktmpdir {|d|
96      Dir.mkdir(dir = "#{d}/dir")
97      File.open(file = "#{dir}/foo", "w"){}
98      begin
99        File.chmod(0300, dir)
100        a = []
101        Find.find(d) {|f| a << f }
102        assert_equal([d, dir], a)
103      ensure
104        File.chmod(0700, dir)
105      end
106    }
107  end
108
109  def test_unsearchable_dir
110    Dir.mktmpdir {|d|
111      Dir.mkdir(dir = "#{d}/dir")
112      File.open(file = "#{dir}/foo", "w"){}
113      begin
114        File.chmod(0600, dir)
115        a = []
116        Find.find(d) {|f| a << f }
117        assert_equal([d, dir, file], a)
118        skip "no meaning test on Windows" if /mswin|mingw/ =~ RUBY_PLATFORM
119        assert_raise(Errno::EACCES) { File.lstat(file) }
120      ensure
121        File.chmod(0700, dir)
122      end
123    }
124  end
125
126  def test_dangling_symlink
127    Dir.mktmpdir {|d|
128      begin
129        File.symlink("foo", "#{d}/bar")
130      rescue NotImplementedError
131        skip "symlink is not supported."
132      end
133      a = []
134      Find.find(d) {|f| a << f }
135      assert_equal([d, "#{d}/bar"], a)
136      assert_raise(Errno::ENOENT) { File.stat("#{d}/bar") }
137    }
138  end
139
140  def test_dangling_symlink_stat_error
141    Dir.mktmpdir {|d|
142      begin
143        File.symlink("foo", "#{d}/bar")
144      rescue NotImplementedError
145        skip "symlink is not supported."
146      end
147      assert_raise(Errno::ENOENT) {
148        Find.find(d) {|f| File.stat(f) }
149      }
150    }
151  end
152
153  def test_change_dir_to_file
154    Dir.mktmpdir {|d|
155      Dir.mkdir(dir_1 = "#{d}/d1")
156      File.open(file_a = "#{dir_1}/a", "w"){}
157      File.open(file_b = "#{dir_1}/b", "w"){}
158      File.open(file_c = "#{dir_1}/c", "w"){}
159      Dir.mkdir(dir_d = "#{dir_1}/d")
160      File.open(file_de = "#{dir_d}/e", "w"){}
161      dir_2 = "#{d}/d2"
162      a = []
163      Find.find(d) {|f|
164        a << f
165        if f == file_b
166          File.rename(dir_1, dir_2)
167          File.open(dir_1, "w") {}
168        end
169      }
170      assert_equal([d, dir_1, file_a, file_b, file_c, dir_d], a)
171    }
172  end
173
174  def test_change_dir_to_symlink_loop
175    Dir.mktmpdir {|d|
176      Dir.mkdir(dir_1 = "#{d}/d1")
177      File.open(file_a = "#{dir_1}/a", "w"){}
178      File.open(file_b = "#{dir_1}/b", "w"){}
179      File.open(file_c = "#{dir_1}/c", "w"){}
180      Dir.mkdir(dir_d = "#{dir_1}/d")
181      File.open(file_de = "#{dir_d}/e", "w"){}
182      dir_2 = "#{d}/d2"
183      a = []
184      Find.find(d) {|f|
185        a << f
186        if f == file_b
187          File.rename(dir_1, dir_2)
188          begin
189            File.symlink("d1", dir_1)
190          rescue NotImplementedError
191            skip "symlink is not supported."
192          end
193        end
194      }
195      assert_equal([d, dir_1, file_a, file_b, file_c, dir_d], a)
196    }
197  end
198
199  def test_enumerator
200    Dir.mktmpdir {|d|
201      File.open("#{d}/a", "w"){}
202      Dir.mkdir("#{d}/b")
203      File.open("#{d}/b/a", "w"){}
204      File.open("#{d}/b/b", "w"){}
205      Dir.mkdir("#{d}/c")
206      e = Find.find(d)
207      a = []
208      e.each {|f| a << f }
209      assert_equal([d, "#{d}/a", "#{d}/b", "#{d}/b/a", "#{d}/b/b", "#{d}/c"], a)
210    }
211  end
212
213  class TestInclude < Test::Unit::TestCase
214    include Find
215
216    def test_functional_call
217      Dir.mktmpdir {|d|
218        File.open("#{d}/a", "w"){}
219        a = []
220        find(d) {|f| a << f }
221        assert_equal([d, "#{d}/a"], a)
222      }
223    end
224  end
225
226end
227