[rubygems/rubygems] Use a constant empty tar header to avoid extra allocations
[ruby.git] / test / test_tempfile.rb
blobeddbac5d754df4b161f6c4c9e5ff924a2ea4fe25
1 # frozen_string_literal: true
2 require 'test/unit'
3 require 'tempfile'
5 class TestTempfile < Test::Unit::TestCase
6   def initialize(*)
7     super
8     @tempfile = nil
9   end
11   def tempfile(*args, **kw, &block)
12     t = Tempfile.new(*args, **kw, &block)
13     @tempfile = (t unless block)
14   end
16   def teardown
17     if @tempfile
18       @tempfile.close!
19     end
20   end
22   def test_leackchecker
23     assert_instance_of(Tempfile, Tempfile.allocate)
24   end
26   def test_basic
27     t = tempfile("foo")
28     path = t.path
29     t.write("hello world")
30     t.close
31     assert_equal "hello world", File.read(path)
32   end
34   def test_saves_in_given_directory
35     subdir = File.join(Dir.tmpdir, "tempfile-test-#{rand}")
36     Dir.mkdir(subdir)
37     begin
38       tempfile = Tempfile.new("foo", subdir)
39       tempfile.close
40       begin
41         assert_equal subdir, File.dirname(tempfile.path)
42       ensure
43         tempfile.unlink
44       end
45     ensure
46       Dir.rmdir(subdir)
47     end
48   end
50   def test_basename
51     t = tempfile("foo")
52     assert_match(/^foo/, File.basename(t.path))
53   end
55   def test_default_basename
56     t = tempfile
57     assert_file.exist?(t.path)
58   end
60   def test_basename_with_suffix
61     t = tempfile(["foo", ".txt"])
62     assert_match(/^foo/, File.basename(t.path))
63     assert_match(/\.txt$/, File.basename(t.path))
64   end
66   def test_dup
67     t = tempfile
68     t2 = t.dup
69     t2.close
70     assert_equal true, t2.closed?
71     assert_equal false, t.closed?
72   end
74   def test_clone
75     t = tempfile
76     t2 = t.clone
77     t2.close
78     assert_equal true, t2.closed?
79     assert_equal false, t.closed?
80   end
82   def test_unlink
83     t = tempfile("foo")
84     path = t.path
86     t.close
87     assert_file.exist?(path)
89     t.unlink
90     assert_file.not_exist?(path)
92     assert_nil t.path
93   end
95   def test_unlink_silently_fails_on_windows
96     tempfile = tempfile("foo")
97     path = tempfile.path
98     begin
99       assert_nothing_raised do
100         tempfile.unlink
101       end
102     ensure
103       tempfile.close
104       File.unlink(path) if File.exist?(path)
105     end
106   end
108   def test_unlink_before_close_works_on_posix_systems
109     tempfile = tempfile("foo")
110     begin
111       path = tempfile.path
112       tempfile.unlink
113       assert_file.not_exist?(path)
114       tempfile.write("hello ")
115       tempfile.write("world\n")
116       tempfile.rewind
117       assert_equal "hello world\n", tempfile.read
118     ensure
119       tempfile.close
120       tempfile.unlink
121     end
122   end unless /mswin|mingw/ =~ RUBY_PLATFORM
124   def test_close_and_close_p
125     t = tempfile("foo")
126     assert_not_predicate(t, :closed?)
127     t.close
128     assert_predicate(t, :closed?)
129   end
131   def test_close_with_unlink_now_true_works
132     t = tempfile("foo")
133     path = t.path
134     t.close(true)
135     assert_predicate(t, :closed?)
136     assert_nil t.path
137     assert_file.not_exist?(path)
138   end
140   def test_close_with_unlink_now_true_does_not_unlink_if_already_unlinked
141     t = tempfile("foo")
142     path = t.path
143     t.unlink
144     File.open(path, "w").close
145     begin
146       t.close(true)
147       assert_file.exist?(path)
148     ensure
149       File.unlink(path) rescue nil
150     end
151   end unless /mswin|mingw/ =~ RUBY_PLATFORM
153   def test_close_bang_works
154     t = tempfile("foo")
155     path = t.path
156     t.close!
157     assert_predicate(t, :closed?)
158     assert_nil t.path
159     assert_file.not_exist?(path)
160   end
162   def test_close_bang_does_not_unlink_if_already_unlinked
163     t = tempfile("foo")
164     path = t.path
165     t.unlink
166     File.open(path, "w").close
167     begin
168       t.close!
169       assert_file.exist?(path)
170     ensure
171       File.unlink(path) rescue nil
172     end
173   end unless /mswin|mingw/ =~ RUBY_PLATFORM
175   def test_finalizer_does_not_unlink_if_already_unlinked
176     assert_in_out_err('-rtempfile', <<-'EOS') do |(filename,*), (error,*)|
177 file = Tempfile.new('foo')
178 path = file.path
179 puts path
180 file.close!
181 File.open(path, "w").close
182     EOS
183       assert_file.exist?(filename)
184       File.unlink(filename)
185       assert_nil error
186     end
188     assert_in_out_err('-rtempfile', <<-'EOS') do |(filename,*), (error,*)|
189 file = Tempfile.new('foo')
190 path = file.path
191 file.unlink
192 puts path
193 File.open(path, "w").close
194     EOS
195       if !filename.empty?
196         # POSIX unlink semantics supported, continue with test
197         assert_file.exist?(filename)
198         File.unlink(filename)
199       end
200       assert_nil error
201     end
202   end unless /mswin|mingw/ =~ RUBY_PLATFORM
204   def test_close_does_not_make_path_nil
205     t = tempfile("foo")
206     t.close
207     assert_not_nil t.path
208   end
210   def test_close_flushes_buffer
211     t = tempfile("foo")
212     t.write("hello")
213     t.close
214     assert_equal 5, File.size(t.path)
215   end
217   def test_tempfile_is_unlinked_when_ruby_exits
218     assert_in_out_err('-rtempfile', <<-'EOS') do |(filename), (error)|
219 puts Tempfile.new('foo').path
220     EOS
221       assert_file.for("tempfile must not be exist after GC.").not_exist?(filename)
222       assert_nil(error)
223     end
224   end
226   def test_tempfile_finalizer_does_not_run_if_unlinked
227     bug8768 = '[ruby-core:56521] [Bug #8768]'
228     assert_in_out_err(%w(-rtempfile), <<-'EOS') do |(filename), (error)|
229       tmp = Tempfile.new('foo')
230       puts tmp.path
231       tmp.close
232       tmp.unlink
233       $DEBUG = true
234       EOS
235       assert_file.not_exist?(filename)
236       assert_nil(error, "#{bug8768} we used to get a confusing 'removing ...done' here")
237     end
238   end
240   def test_size_flushes_buffer_before_determining_file_size
241     t = tempfile("foo")
242     t.write("hello")
243     assert_equal 0, File.size(t.path)
244     assert_equal 5, t.size
245     assert_equal 5, File.size(t.path)
246   end
248   def test_size_works_if_file_is_closed
249     t = tempfile("foo")
250     t.write("hello")
251     t.close
252     assert_equal 5, t.size
253   end
255   def test_size_on_empty_file
256     t = tempfile("foo")
257     t.write("")
258     t.close
259     assert_equal 0, t.size
260   end
262   def test_concurrency
263     threads = []
264     tempfiles = []
265     lock = Thread::Mutex.new
266     cond = Thread::ConditionVariable.new
267     start = false
269     4.times do
270       threads << Thread.new do
271         lock.synchronize do
272           while !start
273             cond.wait(lock)
274           end
275         end
276         result = []
277         30.times do
278           result << Tempfile.new('foo')
279         end
280         Thread.current[:result] = result
281       end
282     end
284     lock.synchronize do
285       start = true
286       cond.broadcast
287     end
288     threads.each do |thread|
289       thread.join
290       tempfiles |= thread[:result]
291     end
292     filenames = tempfiles.map { |f| f.path }
293     begin
294       assert_equal filenames.size, filenames.uniq.size
295     ensure
296       tempfiles.each do |tempfile|
297         tempfile.close!
298       end
299     end
300   end
302   module M
303   end
305   def test_extend
306     o = tempfile("foo")
307     o.extend M
308     assert(M === o, "[ruby-dev:32932]")
309   end
311   def test_tempfile_encoding_nooption
312     default_external=Encoding.default_external
313     t = tempfile("TEST")
314     t.write("\xE6\x9D\xBE\xE6\xB1\x9F")
315     t.rewind
316     assert_equal(default_external,t.read.encoding)
317   end
319   def test_tempfile_encoding_ascii8bit
320     t = tempfile("TEST",:encoding=>"ascii-8bit")
321     t.write("\xE6\x9D\xBE\xE6\xB1\x9F")
322     t.rewind
323     assert_equal(Encoding::ASCII_8BIT,t.read.encoding)
324   end
326   def test_tempfile_encoding_ascii8bit2
327     t = tempfile("TEST",Dir::tmpdir,:encoding=>"ascii-8bit")
328     t.write("\xE6\x9D\xBE\xE6\xB1\x9F")
329     t.rewind
330     assert_equal(Encoding::ASCII_8BIT,t.read.encoding)
331   end
333   def test_binmode
334     t = tempfile("TEST", mode: IO::BINARY)
335     if IO::BINARY.nonzero?
336       assert(t.binmode?)
337       t.open
338       assert(t.binmode?, 'binmode after reopen')
339     else
340       assert_equal(0600, t.stat.mode & 0777)
341     end
342   end
344   def test_create_with_block
345     path = nil
346     Tempfile.create("tempfile-create") {|f|
347       path = f.path
348       assert_file.exist?(path)
349     }
350     assert_file.not_exist?(path)
352     Tempfile.create("tempfile-create") {|f|
353       path = f.path
354       f.close
355       File.unlink(f.path)
356     }
357     assert_file.not_exist?(path)
358   end
360   def test_create_without_block
361     path = nil
362     f = Tempfile.create("tempfile-create")
363     path = f.path
364     assert_file.exist?(path)
365     f.close
366     assert_file.exist?(path)
367   ensure
368     f&.close
369     File.unlink path if path
370   end
372   def test_create_default_basename
373     path = nil
374     Tempfile.create {|f|
375       path = f.path
376       assert_file.exist?(path)
377     }
378     assert_file.not_exist?(path)
379   end
381   def test_open
382     Tempfile.open {|f|
383       file = f.open
384       assert_kind_of File, file
385       assert_equal f.to_i, file.to_i
386     }
387   end
389   def test_open_traversal_dir
390     assert_mktmpdir_traversal do |traversal_path|
391       t = Tempfile.open([traversal_path, 'foo'])
392       t.path
393     ensure
394       t&.close!
395     end
396   end
398   def test_new_traversal_dir
399     assert_mktmpdir_traversal do |traversal_path|
400       t = Tempfile.new(traversal_path + 'foo')
401       t.path
402     ensure
403       t&.close!
404     end
405   end
407   def test_create_traversal_dir
408     assert_mktmpdir_traversal do |traversal_path|
409       t = Tempfile.create(traversal_path + 'foo')
410       t.path
411     ensure
412       if t
413         t.close
414         File.unlink(t.path)
415       end
416     end
417   end
419   def assert_mktmpdir_traversal
420     Dir.mktmpdir do |target|
421       target = target.chomp('/') + '/'
422       traversal_path = target.sub(/\A\w:/, '') # for DOSISH
423       traversal_path = Array.new(target.count('/')-2, '..').join('/') + traversal_path
424       actual = yield traversal_path
425       assert_not_send([File.absolute_path(actual), :start_with?, target])
426     end
427   end