4 class TestIO < Test::Unit::TestCase
5 WINDOWS = Config::CONFIG['host_os'] =~ /Windows|mswin/
10 @file3 = "Test3IO_tmp"
14 @devnull = '/dev/null'
19 @to_close.each {|io| io.close rescue nil }
20 File.unlink @file rescue nil
21 File.unlink @file2 rescue nil
22 File.unlink @file3 rescue nil
25 def test_erroneous_io_usage
26 assert_raises(ArgumentError) { IO.new }
27 # commented out until JRUBY-1048 is completed
28 #assert_raises(StandardError) { IO.new(123) }
29 assert_raises(TypeError) { IO.new "FROGGER" }
30 assert_raises(TypeError) { IO.foreach 3 }
33 def test_gets_delimiting
34 f = File.new(@file3, "w")
37 f = File.new(@file3, "r")
42 assert(b == "\nB\n", "gets of non-paragraph \"\\n\\n\" failed")
45 def test_two_ios_with_same_filenos
46 # Two ios with same fileno, but different objects.
47 f = File.new(@file, "w")
51 assert_equal(f.fileno, g.fileno)
52 assert_raises(IOError) { g.gets }
54 assert_raises(IOError) { g.puts }
56 f = File.new(@file, "r")
59 assert_equal(f.fileno, g.fileno)
60 assert_raises(IOError) { g.puts }
61 # If g closes then g knows that it was once a valid descriptor.
62 # So it throws an IOError.
64 assert_raises(IOError) { g.gets }
67 def test_puts_on_a_recursive_array
68 # Puts a recursive array
71 f = File.new(@file, "w")
78 f = File.new(@file, "r")
84 assert_equal("2\n", a)
85 assert_equal("[...]\n", b)
88 def test_premature_close_raises_appropriate_errors
90 # In this case we will have f close (which will pull the rug
91 # out from under g) and thus make g try the ops and fail
96 assert_raises(Errno::EBADF) { g.readchar }
97 assert_raises(Errno::EBADF) { g.readline }
98 assert_raises(Errno::EBADF) { g.gets }
99 assert_raises(Errno::EBADF) { g.close }
100 assert_raises(IOError) { g.getc }
101 assert_raises(IOError) { g.readchar }
102 assert_raises(IOError) { g.read }
103 assert_raises(IOError) { g.sysread 1 }
105 f = File.open(@file, "w")
109 assert_nothing_raised { g.print "" }
110 assert_nothing_raised { g.write "" }
111 assert_nothing_raised { g.puts "" }
112 assert_nothing_raised { g.putc 'c' }
113 assert_raises(Errno::EBADF) { g.syswrite "" }
116 def test_ios_with_incompatible_flags
117 ensure_files @file, @file2
118 # Cannot open an IO which does not have compatible permission with
120 f = File.new(@file2, "w")
122 assert_raises(Errno::EINVAL) { g = IO.new(f.fileno, "r") }
125 f = File.new(@file, "r")
127 assert_raises(Errno::EINVAL) { g = IO.new(f.fileno, "w") }
131 def test_ios_with_compatible_flags
133 # However, you can open a second with less permissions
134 f = File.new(@file, "r+")
136 g = IO.new(f.fileno, "r")
140 assert_raises(IOError) { g.write "HOH" }
141 assert_equal(f.fileno, g.fileno)
149 assert_raises(Errno::EINVAL) { f.seek(-1) }
150 # Advance one + single arg seek
152 assert_equal(f.pos, 1)
156 def test_empty_write_does_not_complain
157 # empty write...writes nothing and does not complain
158 f = File.new(@file, "w")
162 i = f.syswrite("heh")
168 assert_raises(Errno::ENOENT) { File.foreach("nonexistent_file") {} }
172 ensure_files @file, @file2
173 file = File.open(@file)
176 file2 = File.open(@file2)
178 file2_fileno = file2.fileno;
179 file2 = file2.reopen(file)
180 assert_equal(file.pos, file2.pos)
181 assert_equal(file2_fileno, file2.fileno);
182 assert(file.fileno != file2.fileno);
186 # reopen of a filename after a close should succeed (JRUBY-1885)
187 assert_nothing_raised { file.reopen(@file) }
190 def test_file_puts_gets_readline
191 f = File.open(@file, "w")
199 assert_equal(f.gets(), $_)
200 assert_equal(f.readline(), $_)
206 # test that read returns correct values
210 assert_equal("", f.read)
211 assert_equal(nil, f.read(1))
215 # MRI 1.8.5 and 1.8.6 permit nil buffers with reads.
216 def test_file_read_with_nil_buffer
221 assert_equal " ", f.read(1, nil)
227 assert_raises(ArgumentError) { io = IO.open }
231 assert_raises(ArgumentError) { io = IO.open(f.fileno, "r", :gratuitous) }
232 io = IO.open(f.fileno, "r")
234 assert_equal(f.fileno, io.fileno)
240 assert_raises(Errno::EBADF) { f.close }
243 def test_open_with_block
248 IO.open(f.fileno, "r") do |io|
249 assert_equal(f.fileno, io.fileno)
254 assert_raises(Errno::EBADF) { f.close }
258 ensure_files @file, @file2, @file3
259 # Test deleting files
260 assert(File.delete(@file, @file2, @file3))
265 assert_equal(nil, select(nil, nil, nil, 0))
266 assert_raises(ArgumentError) { select(nil, nil, nil, -1) }
271 def initialize(stream, passthrough = false)
273 @passthrough = passthrough
277 @stream.write(content) if @passthrough
281 def test_puts_and_warn_redirection
284 $stdout = StringIO.new
285 $stderr = StringIO.new
290 assert_equal ":hi\n", $stdout.string
291 assert_equal ":hello\n", $stderr.string
300 File.open(@file, "wb") do |file|
303 File.open(@file, "rb") do |file|
304 assert_equal(255, file.getc)
309 def test_ungetc_empty_file
310 File.open(@file, "w+") {}
311 File.open(@file) do |file|
312 assert_nil(file.getc)
313 assert_equal(0, file.pos)
316 # The following line is an intentional regression tests,
317 # it checks that JRuby doesn't break.
318 assert_equal(0, file.pos)
320 assert_equal(100, file.getc)
325 def test_ungetc_nonempty_file
326 File.open(@file, "w+") { |file| file.puts("HELLO") }
327 File.open(@file) do |file|
328 assert_equal(72, file.getc)
329 assert_equal(1, file.pos)
331 assert_equal(0, file.pos)
332 assert_equal(100, file.getc)
333 assert_equal(1, file.pos)
338 def test_ungetc_position_change
339 File.open(@file, "w+") { |file| file.puts("HELLO") }
341 # getc/ungetc the same char
342 File.open(@file) do |f|
344 assert_equal(0, f.pos)
345 assert_equal("HELLO", f.read(5))
346 assert_equal(5, f.pos)
349 # getc/ungetc different char
350 File.open(@file) do |f|
353 assert_equal(0, f.pos)
354 assert_equal("dELLO", f.read(5))
355 assert_equal(5, f.pos)
360 # unget char should be discarded after position changing calls
361 def test_unget_before_position_change
362 File.open(@file, "w+") { |file| file.puts("HELLO") }
363 File.open(@file) do |f|
367 assert_equal("LLO", f.read(3))
371 assert_equal("LLO", f.read(3))
375 assert_equal("HELLO", f.read(5))
378 f.seek(-3, IO::SEEK_END)
379 assert_equal("LO", f.read(2))
384 def test_reopen_doesnt_close_same_handler
385 f = File.open(@file, "w")
395 out = File.read(@file)
396 assert_equal "..", out
400 def test_very_big_read
401 # See JRUBY-1686: this caused OOM
405 assert_nothing_raised { f.read(1000000000) }
408 # JRUBY-2023, multithreaded writes
409 def test_multithreaded_writes
410 f = File.open("__temp1", "w")
414 threads << Thread.new { 100.times { f.print('.') } }
416 threads.each {|thread| thread.join}
418 assert File.size("__temp1") == 100*100
420 File.unlink("__temp1")
424 def test_eof_on_dev_null
425 File.open(@devnull, 'rb') { |f|
431 def test_read_dev_null
432 File.open(@devnull, 'rb') { |f|
433 assert_equal("", f.read)
434 assert_equal(nil, f.read(1))
435 assert_equal([], f.readlines)
436 assert_raise EOFError do
444 def test_copy_dev_null
447 FileUtils.cp(@devnull, 'somefile')
448 assert(File.exists?('somefile'))
449 assert_equal(0, File.size('somefile'))
451 File.delete('somefile') rescue nil
458 def test_null_open_windows
459 null_names = ['NUL', 'NUL:', 'nul', 'nul:']
460 null_names.each { |name|
461 File.open(name) { |f|
462 assert_equal("", f.read)
465 File.open(name, 'r+') { |f|
466 assert_nil(f.puts("test"))
472 def test_file_constants_included
473 assert IO.include?(File::Constants)
474 assert_equal ["APPEND", "BINARY", "CREAT", "EXCL", "Enumerator", "FNM_CASEFOLD",
475 "FNM_DOTMATCH", "FNM_NOESCAPE", "FNM_PATHNAME", "FNM_SYSCASE",
476 "LOCK_EX", "LOCK_NB", "LOCK_SH", "LOCK_UN", "NOCTTY", "NONBLOCK",
477 "RDONLY", "RDWR", "SEEK_CUR", "SEEK_END", "SEEK_SET", "SYNC", "TRUNC",
478 "WRONLY"], IO.constants.sort
482 def ensure_files(*files)
483 files.each {|f| File.open(f, "w") {|g| g << " " } }