1# Licensed to the Apache Software Foundation (ASF) under one
2# or more contributor license agreements.  See the NOTICE file
3# distributed with this work for additional information
4# regarding copyright ownership.  The ASF licenses this file
5# to you under the Apache License, Version 2.0 (the
6# "License"); you may not use this file except in compliance
7# with the License.  You may obtain a copy of the License at
8#
9#   http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing,
12# software distributed under the License is distributed on an
13# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14# KIND, either express or implied.  See the License for the
15# specific language governing permissions and limitations
16# under the License.
17
18module FileSystemTests
19  private def all_entries
20    selector = Arrow::FileSelector.new
21    selector.base_dir = ""
22    selector.recursive = true
23    infos = @fs.get_file_infos_selector(selector)
24    infos.map {|info| [info.path, info.type.nick.to_sym]}.to_h
25  end
26
27  private def mkpath(path)
28    @fs.create_dir(path, true)
29  end
30
31  private def create_file(path, content=nil)
32    stream = @fs.open_output_stream(path)
33    stream.write(content) if content
34    stream.close
35  end
36
37  private def read_file(path)
38    stream = @fs.open_input_stream(path)
39    size = @fs.get_file_info(path).size
40    bytes = stream.read_bytes(size)
41    stream.close
42    bytes.to_s
43  end
44
45  private def file?(path)
46    info = @fs.get_file_info(path)
47    info.file?
48  rescue Arrow::Error::Io
49    false
50  end
51
52  private def directory?(path)
53    info = @fs.get_file_info(path)
54    info.dir?
55  rescue Arrow::Error::Io
56    false
57  end
58
59  def test_empty
60    assert { all_entries.empty? }
61  end
62
63  def test_create_dir
64    @fs.create_dir("AB/CD/EF", true) # recursive
65    @fs.create_dir("AB/GH", false) # non-recursive
66    assert_equal({
67                   "AB" => :dir,
68                   "AB/CD" => :dir,
69                   "AB/CD/EF" => :dir,
70                   "AB/GH" => :dir
71                 },
72                 all_entries)
73  end
74
75  def test_create_dir_with_nonexistent_parent
76    assert_raise(Arrow::Error::Io) do
77      @fs.create_dir("AB/GH/IJ", false) # non-recursive, parent doesn't exist
78    end
79    assert_equal({},
80                 all_entries)
81  end
82
83  def test_create_dir_under_file
84    create_file("empty_file")
85    assert_raise(Arrow::Error::Io) do
86      @fs.create_dir(File.join("empty_file", "XY"), true)
87    end
88    assert_equal({"empty_file" => :file},
89                 all_entries)
90  end
91
92  def test_delete_dir
93    mkpath("AB/CD/EF")
94    mkpath("AB/GH/IJ")
95    create_file("AB/abc")
96    create_file("AB/CD/def")
97    create_file("AB/CD/EF/ghi")
98
99    @fs.delete_dir("AB/CD")
100    @fs.delete_dir("AB/GH/IJ")
101
102    assert_equal({
103                   "AB" => :dir,
104                   "AB/GH" => :dir,
105                   "AB/abc" => :file
106                 },
107                 all_entries)
108  end
109
110  def test_delete_dir_contents
111    mkpath("AB/CD/EF")
112    mkpath("AB/GH/IJ")
113    create_file("AB/abc")
114    create_file("AB/CD/def")
115    create_file("AB/CD/EF/ghi")
116
117    @fs.delete_dir_contents("AB/CD")
118    @fs.delete_dir_contents("AB/GH/IJ")
119
120    assert_equal({
121                   "AB" => :dir,
122                   "AB/CD" => :dir,
123                   "AB/GH" => :dir,
124                   "AB/GH/IJ" => :dir,
125                   "AB/abc" => :file
126                 },
127                 all_entries)
128  end
129
130  def test_delete_file
131    mkpath("AB")
132    create_file("AB/def")
133    assert { file?("AB/def") }
134
135    @fs.delete_file("AB/def")
136    assert { not file?("AB/def") }
137  end
138
139  def test_delete_files
140    mkpath("AB")
141    create_file("abc")
142    {
143      def: 123,
144      ghi: 456,
145      jkl: 789,
146      mno: 789
147    }.each do |name, content|
148      create_file(File.join("AB", name.to_s), content.to_s)
149    end
150
151    assert_equal({
152                   "AB" => :dir,
153                   "AB/def" => :file,
154                   "AB/ghi" => :file,
155                   "AB/jkl" => :file,
156                   "AB/mno" => :file,
157                   "abc" => :file
158                 },
159                 all_entries)
160
161    @fs.delete_files(["abc", "AB/def"])
162    assert_equal({
163                   "AB" => :dir,
164                   "AB/ghi" => :file,
165                   "AB/jkl" => :file,
166                   "AB/mno" => :file
167                 },
168                 all_entries)
169  end
170
171  def test_move_file
172    mkpath("AB/CD")
173    mkpath("EF")
174    create_file("abc")
175    assert_equal({
176                   "AB" => :dir,
177                   "AB/CD" => :dir,
178                   "EF" => :dir,
179                   "abc" => :file
180                 },
181                 all_entries)
182
183    @fs.move("abc", "AB/CD/ghi")
184    assert_equal({
185                   "AB" => :dir,
186                   "AB/CD" => :dir,
187                   "EF" => :dir,
188                   "AB/CD/ghi" => :file
189                 },
190                 all_entries)
191  end
192
193  def move_dir_is_supported?
194    true
195  end
196
197  def test_move_dir
198    omit("move_dir is not allowed") unless move_dir_is_supported?
199
200    mkpath("AB/CD")
201    mkpath("EF")
202    assert_equal({
203                   "AB" => :dir,
204                   "AB/CD" => :dir,
205                   "EF" => :dir
206                 },
207                 all_entries)
208
209    @fs.move("AB", "GH")
210    assert_equal({
211                   "EF" => :dir,
212                   "GH" => :dir,
213                   "GH/CD" => :dir
214                 },
215                 all_entries)
216  end
217
218  def test_copy_file
219    mkpath("AB/CD")
220    mkpath("EF")
221    create_file("AB/abc", "data")
222    assert_equal({
223                   "AB" => :dir,
224                   "AB/CD" => :dir,
225                   "EF" => :dir,
226                   "AB/abc" => :file
227                 },
228                 all_entries)
229
230    @fs.copy_file("AB/abc", "def")
231    assert_equal({
232                   "AB" => :dir,
233                   "AB/CD" => :dir,
234                   "EF" => :dir,
235                   "AB/abc" => :file,
236                   "def" => :file
237                 },
238                 all_entries)
239    assert_equal("data",
240                 read_file("def"))
241  end
242
243  def test_get_file_info
244    mkpath("AB/CD")
245    create_file("AB/CD/ghi", "some data")
246
247    info = @fs.get_file_info("AB")
248    assert_equal(Arrow::FileType::DIR,
249                 info.type)
250    assert_equal("AB",
251                 info.base_name)
252    assert_equal(-1,
253                 info.size)
254    assert do
255      info.mtime > 0
256    end
257
258    info = @fs.get_file_info("AB/CD/ghi")
259    assert_equal(Arrow::FileType::FILE,
260                 info.type)
261    assert_equal("ghi",
262                 info.base_name)
263    assert_equal(9,
264                 info.size)
265    assert do
266      info.mtime > 0
267    end
268  end
269
270  def test_get_file_infos_paths
271    mkpath("AB/CD")
272    create_file("AB/CD/ghi", "some data")
273
274    infos = @fs.get_file_infos_paths(["AB", "AB/CD/ghi"])
275    assert_equal({
276                   "AB" => -1,
277                   "AB/CD/ghi" => 9
278                 },
279                 infos.map {|info| [info.path, info.size]}.to_h)
280  end
281
282  def test_get_file_infos_selector
283    mkpath("AB/CD")
284    create_file("abc", "data")
285    create_file("AB/def", "some data")
286    create_file("AB/CD/ghi", "some other data")
287
288    selector = Arrow::FileSelector.new
289    infos = @fs.get_file_infos_selector(selector)
290    assert_equal({
291                   "AB" => -1,
292                   "abc" => 4
293                 },
294                 infos.map {|info| [info.path, info.size]}.to_h)
295
296    selector.base_dir = "AB"
297    infos = @fs.get_file_infos_selector(selector)
298    assert_equal({
299                   "AB/CD" => -1,
300                   "AB/def" => 9
301                 },
302                 infos.map {|info| [info.path, info.size]}.to_h)
303  end
304
305  def test_get_file_infos_selector_with_recursion
306    mkpath("AB/CD")
307    create_file("abc", "data")
308    create_file("AB/def", "some data")
309    create_file("AB/CD/ghi", "some other data")
310
311    selector = Arrow::FileSelector.new
312    selector.recursive = true
313    infos = @fs.get_file_infos_selector(selector)
314    assert_equal({
315                   "AB" => -1,
316                   "AB/CD" => -1,
317                   "AB/CD/ghi" => 15,
318                   "AB/def" => 9,
319                   "abc" => 4
320                 },
321                 infos.map {|info| [info.path, info.size]}.to_h)
322  end
323
324  def test_open_output_stream
325    assert { not file?("abc") }
326    stream = @fs.open_output_stream("abc")
327    assert_equal(0, stream.tell)
328    stream.write("some ")
329    stream.write("data")
330    stream.close
331    assert { file?("abc") }
332    assert_equal("some data",
333                 read_file("abc"))
334
335    stream = @fs.open_output_stream("abc")
336    assert_equal(0, stream.tell)
337    stream.write("other data")
338    stream.close
339    assert { file?("abc") }
340    assert_equal("other data",
341                 read_file("abc"))
342  end
343
344  def test_open_append_stream
345    assert { not file?("abc") }
346    stream = @fs.open_append_stream("abc")
347    assert_equal(0, stream.tell)
348    stream.write("some ")
349    stream.close
350    assert { file?("abc") }
351    assert_equal("some ",
352                 read_file("abc"))
353
354    stream = @fs.open_append_stream("abc")
355    assert_equal(5, stream.tell)
356    stream.write("data")
357    stream.close
358    assert { file?("abc") }
359    assert_equal("some data",
360                 read_file("abc"))
361  end
362
363  def test_open_input_stream
364    mkpath("AB")
365    create_file("AB/abc", "some data")
366
367    stream = @fs.open_input_stream("AB/abc")
368    bytes = stream.read_bytes(4)
369    assert_equal("some",
370                 bytes.to_s)
371    stream.close
372  end
373
374  def test_open_input_file
375    create_file("ab", "some data")
376
377    stream = @fs.open_input_file("ab")
378    bytes = stream.read_at_bytes(5, 4)
379    assert_equal("data",
380                 bytes.to_s)
381    stream.close
382  end
383end
384