mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 f85733a7ce
			
		
	
	
		f85733a7ce
		
	
	
	
	
		
			
			it sometimes occurs NoMemoryError http://c5664.rubyci.org/~chkbuild/ruby-trunk/log/20130529T033302Z.diff.html.gz git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@40981 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			2708 lines
		
	
	
	
		
			64 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			2708 lines
		
	
	
	
		
			64 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # coding: US-ASCII
 | |
| require 'test/unit'
 | |
| require 'tmpdir'
 | |
| require "fcntl"
 | |
| require 'io/nonblock'
 | |
| require 'socket'
 | |
| require 'stringio'
 | |
| require 'timeout'
 | |
| require 'tempfile'
 | |
| require 'weakref'
 | |
| require_relative 'envutil'
 | |
| 
 | |
| class TestIO < Test::Unit::TestCase
 | |
|   def have_close_on_exec?
 | |
|     begin
 | |
|       $stdin.close_on_exec?
 | |
|       true
 | |
|     rescue NotImplementedError
 | |
|       false
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def have_nonblock?
 | |
|     IO.method_defined?("nonblock=")
 | |
|   end
 | |
| 
 | |
|   def pipe(wp, rp)
 | |
|     re, we = nil, nil
 | |
|     r, w = IO.pipe
 | |
|     rt = Thread.new do
 | |
|       begin
 | |
|         rp.call(r)
 | |
|       rescue Exception
 | |
|         r.close
 | |
|         re = $!
 | |
|       end
 | |
|     end
 | |
|     wt = Thread.new do
 | |
|       begin
 | |
|         wp.call(w)
 | |
|       rescue Exception
 | |
|         w.close
 | |
|         we = $!
 | |
|       end
 | |
|     end
 | |
|     flunk("timeout") unless wt.join(10) && rt.join(10)
 | |
|   ensure
 | |
|     w.close unless !w || w.closed?
 | |
|     r.close unless !r || r.closed?
 | |
|     (wt.kill; wt.join) if wt
 | |
|     (rt.kill; rt.join) if rt
 | |
|     raise we if we
 | |
|     raise re if re
 | |
|   end
 | |
| 
 | |
|   def with_pipe
 | |
|     r, w = IO.pipe
 | |
|     begin
 | |
|       yield r, w
 | |
|     ensure
 | |
|       r.close unless r.closed?
 | |
|       w.close unless w.closed?
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def with_read_pipe(content)
 | |
|     pipe(proc do |w|
 | |
|       w << content
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       yield r
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def mkcdtmpdir
 | |
|     Dir.mktmpdir {|d|
 | |
|       Dir.chdir(d) {
 | |
|         yield
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def trapping_usr1
 | |
|     @usr1_rcvd  = 0
 | |
|     trap(:USR1) { @usr1_rcvd += 1 }
 | |
|     yield
 | |
|   ensure
 | |
|     trap(:USR1, "DEFAULT")
 | |
|   end
 | |
| 
 | |
|   def test_pipe
 | |
|     r, w = IO.pipe
 | |
|     assert_instance_of(IO, r)
 | |
|     assert_instance_of(IO, w)
 | |
|     [
 | |
|       Thread.start{
 | |
|         w.print "abc"
 | |
|         w.close
 | |
|       },
 | |
|       Thread.start{
 | |
|         assert_equal("abc", r.read)
 | |
|         r.close
 | |
|       }
 | |
|     ].each{|thr| thr.join}
 | |
|   end
 | |
| 
 | |
|   def test_pipe_block
 | |
|     x = nil
 | |
|     ret = IO.pipe {|r, w|
 | |
|       x = [r,w]
 | |
|       assert_instance_of(IO, r)
 | |
|       assert_instance_of(IO, w)
 | |
|       [
 | |
|         Thread.start do
 | |
|           w.print "abc"
 | |
|           w.close
 | |
|         end,
 | |
|         Thread.start do
 | |
|           assert_equal("abc", r.read)
 | |
|         end
 | |
|       ].each{|thr| thr.join}
 | |
|       assert(!r.closed?)
 | |
|       assert(w.closed?)
 | |
|       :foooo
 | |
|     }
 | |
|     assert_equal(:foooo, ret)
 | |
|     assert(x[0].closed?)
 | |
|     assert(x[1].closed?)
 | |
|   end
 | |
| 
 | |
|   def test_pipe_block_close
 | |
|     4.times {|i|
 | |
|       x = nil
 | |
|       IO.pipe {|r, w|
 | |
|         x = [r,w]
 | |
|         r.close if (i&1) == 0
 | |
|         w.close if (i&2) == 0
 | |
|       }
 | |
|       assert(x[0].closed?)
 | |
|       assert(x[1].closed?)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_gets_rs
 | |
|     # default_rs
 | |
|     pipe(proc do |w|
 | |
|       w.print "aaa\nbbb\n"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal "aaa\n", r.gets
 | |
|       assert_equal "bbb\n", r.gets
 | |
|       assert_nil r.gets
 | |
|       r.close
 | |
|     end)
 | |
| 
 | |
|     # nil
 | |
|     pipe(proc do |w|
 | |
|       w.print "a\n\nb\n\n"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal "a\n\nb\n\n", r.gets(nil)
 | |
|       assert_nil r.gets("")
 | |
|       r.close
 | |
|     end)
 | |
| 
 | |
|     # "\377"
 | |
|     pipe(proc do |w|
 | |
|       w.print "\377xyz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       r.binmode
 | |
|       assert_equal("\377", r.gets("\377"), "[ruby-dev:24460]")
 | |
|       r.close
 | |
|     end)
 | |
| 
 | |
|     # ""
 | |
|     pipe(proc do |w|
 | |
|       w.print "a\n\nb\n\n"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal "a\n\n", r.gets(""), "[ruby-core:03771]"
 | |
|       assert_equal "b\n\n", r.gets("")
 | |
|       assert_nil r.gets("")
 | |
|       r.close
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_gets_limit_extra_arg
 | |
|     pipe(proc do |w|
 | |
|       w << "0123456789\n0123456789"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal("0123456789\n0", r.gets(nil, 12))
 | |
|       assert_raise(TypeError) { r.gets(3,nil) }
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   # This test cause SEGV.
 | |
|   def test_ungetc
 | |
|     pipe(proc do |w|
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       s = "a" * 1000
 | |
|       assert_raise(IOError, "[ruby-dev:31650]") { 200.times { r.ungetc s } }
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_ungetbyte
 | |
|     make_tempfile {|t|
 | |
|       t.open
 | |
|       t.binmode
 | |
|       t.ungetbyte(0x41)
 | |
|       assert_equal(-1, t.pos)
 | |
|       assert_equal(0x41, t.getbyte)
 | |
|       t.rewind
 | |
|       assert_equal(0, t.pos)
 | |
|       t.ungetbyte("qux")
 | |
|       assert_equal(-3, t.pos)
 | |
|       assert_equal("quxfoo\n", t.gets)
 | |
|       assert_equal(4, t.pos)
 | |
|       t.set_encoding("utf-8")
 | |
|       t.ungetbyte(0x89)
 | |
|       t.ungetbyte(0x8e)
 | |
|       t.ungetbyte("\xe7")
 | |
|       t.ungetbyte("\xe7\xb4\x85")
 | |
|       assert_equal(-2, t.pos)
 | |
|       assert_equal("\u7d05\u7389bar\n", t.gets)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_each_byte
 | |
|     pipe(proc do |w|
 | |
|       w << "abc def"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       r.each_byte {|byte| break if byte == 32 }
 | |
|       assert_equal("def", r.read, "[ruby-dev:31659]")
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_each_byte_with_seek
 | |
|     make_tempfile {|t|
 | |
|       bug5119 = '[ruby-core:38609]'
 | |
|       i = 0
 | |
|       open(t.path) do |f|
 | |
|         f.each_byte {i = f.pos}
 | |
|       end
 | |
|       assert_equal(12, i, bug5119)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_each_codepoint
 | |
|     make_tempfile {|t|
 | |
|       bug2959 = '[ruby-core:28650]'
 | |
|       a = ""
 | |
|       File.open(t, 'rt') {|f|
 | |
|         f.each_codepoint {|c| a << c}
 | |
|       }
 | |
|       assert_equal("foo\nbar\nbaz\n", a, bug2959)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_codepoints
 | |
|     make_tempfile {|t|
 | |
|       bug2959 = '[ruby-core:28650]'
 | |
|       a = ""
 | |
|       File.open(t, 'rt') {|f|
 | |
|         assert_warn(/deprecated/) {
 | |
|           f.codepoints {|c| a << c}
 | |
|         }
 | |
|       }
 | |
|       assert_equal("foo\nbar\nbaz\n", a, bug2959)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_rubydev33072
 | |
|     t = make_tempfile
 | |
|     path = t.path
 | |
|     t.close!
 | |
|     assert_raise(Errno::ENOENT, "[ruby-dev:33072]") do
 | |
|       File.read(path, nil, nil, {})
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream
 | |
|     mkcdtmpdir {
 | |
| 
 | |
|       content = "foobar"
 | |
|       File.open("src", "w") {|f| f << content }
 | |
|       ret = IO.copy_stream("src", "dst")
 | |
|       assert_equal(content.bytesize, ret)
 | |
|       assert_equal(content, File.read("dst"))
 | |
| 
 | |
|       # overwrite by smaller file.
 | |
|       content = "baz"
 | |
|       File.open("src", "w") {|f| f << content }
 | |
|       ret = IO.copy_stream("src", "dst")
 | |
|       assert_equal(content.bytesize, ret)
 | |
|       assert_equal(content, File.read("dst"))
 | |
| 
 | |
|       ret = IO.copy_stream("src", "dst", 2)
 | |
|       assert_equal(2, ret)
 | |
|       assert_equal(content[0,2], File.read("dst"))
 | |
| 
 | |
|       ret = IO.copy_stream("src", "dst", 0)
 | |
|       assert_equal(0, ret)
 | |
|       assert_equal("", File.read("dst"))
 | |
| 
 | |
|       ret = IO.copy_stream("src", "dst", nil, 1)
 | |
|       assert_equal(content.bytesize-1, ret)
 | |
|       assert_equal(content[1..-1], File.read("dst"))
 | |
| 
 | |
|       assert_raise(Errno::ENOENT) {
 | |
|         IO.copy_stream("nodir/foo", "dst")
 | |
|       }
 | |
| 
 | |
|       assert_raise(Errno::ENOENT) {
 | |
|         IO.copy_stream("src", "nodir/bar")
 | |
|       }
 | |
| 
 | |
|       pipe(proc do |w|
 | |
|         ret = IO.copy_stream("src", w)
 | |
|         assert_equal(content.bytesize, ret)
 | |
|         w.close
 | |
|       end, proc do |r|
 | |
|         assert_equal(content, r.read)
 | |
|       end)
 | |
| 
 | |
|       with_pipe {|r, w|
 | |
|         w.close
 | |
|         assert_raise(IOError) { IO.copy_stream("src", w) }
 | |
|       }
 | |
| 
 | |
|       pipe_content = "abc"
 | |
|       with_read_pipe(pipe_content) {|r|
 | |
|         ret = IO.copy_stream(r, "dst")
 | |
|         assert_equal(pipe_content.bytesize, ret)
 | |
|         assert_equal(pipe_content, File.read("dst"))
 | |
|       }
 | |
| 
 | |
|       with_read_pipe("abc") {|r1|
 | |
|         assert_equal("a", r1.getc)
 | |
|         pipe(proc do |w2|
 | |
|           w2.sync = false
 | |
|           w2 << "def"
 | |
|           ret = IO.copy_stream(r1, w2)
 | |
|           assert_equal(2, ret)
 | |
|           w2.close
 | |
|         end, proc do |r2|
 | |
|           assert_equal("defbc", r2.read)
 | |
|         end)
 | |
|       }
 | |
| 
 | |
|       with_read_pipe("abc") {|r1|
 | |
|         assert_equal("a", r1.getc)
 | |
|         pipe(proc do |w2|
 | |
|           w2.sync = false
 | |
|           w2 << "def"
 | |
|           ret = IO.copy_stream(r1, w2, 1)
 | |
|           assert_equal(1, ret)
 | |
|           w2.close
 | |
|         end, proc do |r2|
 | |
|           assert_equal("defb", r2.read)
 | |
|         end)
 | |
|       }
 | |
| 
 | |
|       with_read_pipe("abc") {|r1|
 | |
|         assert_equal("a", r1.getc)
 | |
|         pipe(proc do |w2|
 | |
|           ret = IO.copy_stream(r1, w2)
 | |
|           assert_equal(2, ret)
 | |
|           w2.close
 | |
|         end, proc do |r2|
 | |
|           assert_equal("bc", r2.read)
 | |
|         end)
 | |
|       }
 | |
| 
 | |
|       with_read_pipe("abc") {|r1|
 | |
|         assert_equal("a", r1.getc)
 | |
|         pipe(proc do |w2|
 | |
|           ret = IO.copy_stream(r1, w2, 1)
 | |
|           assert_equal(1, ret)
 | |
|           w2.close
 | |
|         end, proc do |r2|
 | |
|           assert_equal("b", r2.read)
 | |
|         end)
 | |
|       }
 | |
| 
 | |
|       with_read_pipe("abc") {|r1|
 | |
|         assert_equal("a", r1.getc)
 | |
|         pipe(proc do |w2|
 | |
|           ret = IO.copy_stream(r1, w2, 0)
 | |
|           assert_equal(0, ret)
 | |
|           w2.close
 | |
|         end, proc do |r2|
 | |
|           assert_equal("", r2.read)
 | |
|         end)
 | |
|       }
 | |
| 
 | |
|       pipe(proc do |w1|
 | |
|         w1 << "abc"
 | |
|         w1 << "def"
 | |
|         w1.close
 | |
|       end, proc do |r1|
 | |
|         assert_equal("a", r1.getc)
 | |
|         pipe(proc do |w2|
 | |
|           ret = IO.copy_stream(r1, w2)
 | |
|           assert_equal(5, ret)
 | |
|           w2.close
 | |
|         end, proc do |r2|
 | |
|           assert_equal("bcdef", r2.read)
 | |
|         end)
 | |
|       end)
 | |
| 
 | |
|       pipe(proc do |w|
 | |
|         ret = IO.copy_stream("src", w, 1, 1)
 | |
|         assert_equal(1, ret)
 | |
|         w.close
 | |
|       end, proc do |r|
 | |
|         assert_equal(content[1,1], r.read)
 | |
|       end)
 | |
| 
 | |
|       if have_nonblock?
 | |
|         with_read_pipe("abc") {|r1|
 | |
|           assert_equal("a", r1.getc)
 | |
|           with_pipe {|r2, w2|
 | |
|             begin
 | |
|               w2.nonblock = true
 | |
|             rescue Errno::EBADF
 | |
|               skip "nonblocking IO for pipe is not implemented"
 | |
|               break
 | |
|             end
 | |
|             s = w2.syswrite("a" * 100000)
 | |
|             t = Thread.new { sleep 0.1; r2.read }
 | |
|             ret = IO.copy_stream(r1, w2)
 | |
|             w2.close
 | |
|             assert_equal(2, ret)
 | |
|             assert_equal("a" * s + "bc", t.value)
 | |
|           }
 | |
|         }
 | |
|       end
 | |
| 
 | |
|       bigcontent = "abc" * 123456
 | |
|       File.open("bigsrc", "w") {|f| f << bigcontent }
 | |
|       ret = IO.copy_stream("bigsrc", "bigdst")
 | |
|       assert_equal(bigcontent.bytesize, ret)
 | |
|       assert_equal(bigcontent, File.read("bigdst"))
 | |
| 
 | |
|       File.unlink("bigdst")
 | |
|       ret = IO.copy_stream("bigsrc", "bigdst", nil, 100)
 | |
|       assert_equal(bigcontent.bytesize-100, ret)
 | |
|       assert_equal(bigcontent[100..-1], File.read("bigdst"))
 | |
| 
 | |
|       File.unlink("bigdst")
 | |
|       ret = IO.copy_stream("bigsrc", "bigdst", 30000, 100)
 | |
|       assert_equal(30000, ret)
 | |
|       assert_equal(bigcontent[100, 30000], File.read("bigdst"))
 | |
| 
 | |
|       File.open("bigsrc") {|f|
 | |
|         begin
 | |
|           assert_equal(0, f.pos)
 | |
|           ret = IO.copy_stream(f, "bigdst", nil, 10)
 | |
|           assert_equal(bigcontent.bytesize-10, ret)
 | |
|           assert_equal(bigcontent[10..-1], File.read("bigdst"))
 | |
|           assert_equal(0, f.pos)
 | |
|           ret = IO.copy_stream(f, "bigdst", 40, 30)
 | |
|           assert_equal(40, ret)
 | |
|           assert_equal(bigcontent[30, 40], File.read("bigdst"))
 | |
|           assert_equal(0, f.pos)
 | |
|         rescue NotImplementedError
 | |
|           #skip "pread(2) is not implemtented."
 | |
|         end
 | |
|       }
 | |
| 
 | |
|       with_pipe {|r, w|
 | |
|         w.close
 | |
|         assert_raise(IOError) { IO.copy_stream("src", w) }
 | |
|       }
 | |
| 
 | |
|       megacontent = "abc" * 1234567
 | |
|       File.open("megasrc", "w") {|f| f << megacontent }
 | |
| 
 | |
|       if have_nonblock?
 | |
|         with_pipe {|r1, w1|
 | |
|           with_pipe {|r2, w2|
 | |
|             begin
 | |
|               r1.nonblock = true
 | |
|               w2.nonblock = true
 | |
|             rescue Errno::EBADF
 | |
|               skip "nonblocking IO for pipe is not implemented"
 | |
|             end
 | |
|             t1 = Thread.new { w1 << megacontent; w1.close }
 | |
|             t2 = Thread.new { r2.read }
 | |
|             ret = IO.copy_stream(r1, w2)
 | |
|             assert_equal(megacontent.bytesize, ret)
 | |
|             w2.close
 | |
|             t1.join
 | |
|             assert_equal(megacontent, t2.value)
 | |
|           }
 | |
|         }
 | |
|       end
 | |
| 
 | |
|       with_pipe {|r1, w1|
 | |
|         with_pipe {|r2, w2|
 | |
|           t1 = Thread.new { w1 << megacontent; w1.close }
 | |
|           t2 = Thread.new { r2.read }
 | |
|           ret = IO.copy_stream(r1, w2)
 | |
|           assert_equal(megacontent.bytesize, ret)
 | |
|           w2.close
 | |
|           t1.join
 | |
|           assert_equal(megacontent, t2.value)
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       with_pipe {|r, w|
 | |
|         t = Thread.new { r.read }
 | |
|         ret = IO.copy_stream("megasrc", w)
 | |
|         assert_equal(megacontent.bytesize, ret)
 | |
|         w.close
 | |
|         assert_equal(megacontent, t.value)
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_rbuf
 | |
|     mkcdtmpdir {
 | |
|       begin
 | |
|         pipe(proc do |w|
 | |
|           File.open("foo", "w") {|f| f << "abcd" }
 | |
|           File.open("foo") {|f|
 | |
|             f.read(1)
 | |
|             assert_equal(3, IO.copy_stream(f, w, 10, 1))
 | |
|           }
 | |
|           w.close
 | |
|         end, proc do |r|
 | |
|           assert_equal("bcd", r.read)
 | |
|         end)
 | |
|       rescue NotImplementedError
 | |
|         skip "pread(2) is not implemtented."
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def with_socketpair
 | |
|     s1, s2 = UNIXSocket.pair
 | |
|     begin
 | |
|       yield s1, s2
 | |
|     ensure
 | |
|       s1.close unless s1.closed?
 | |
|       s2.close unless s2.closed?
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_socket1
 | |
|     mkcdtmpdir {
 | |
|       content = "foobar"
 | |
|       File.open("src", "w") {|f| f << content }
 | |
| 
 | |
|       with_socketpair {|s1, s2|
 | |
|         ret = IO.copy_stream("src", s1)
 | |
|         assert_equal(content.bytesize, ret)
 | |
|         s1.close
 | |
|         assert_equal(content, s2.read)
 | |
|       }
 | |
|     }
 | |
|   end if defined? UNIXSocket
 | |
| 
 | |
|   def test_copy_stream_socket2
 | |
|     mkcdtmpdir {
 | |
|       bigcontent = "abc" * 123456
 | |
|       File.open("bigsrc", "w") {|f| f << bigcontent }
 | |
| 
 | |
|       with_socketpair {|s1, s2|
 | |
|         t = Thread.new { s2.read }
 | |
|         ret = IO.copy_stream("bigsrc", s1)
 | |
|         assert_equal(bigcontent.bytesize, ret)
 | |
|         s1.close
 | |
|         result = t.value
 | |
|         assert_equal(bigcontent, result)
 | |
|       }
 | |
|     }
 | |
|   end if defined? UNIXSocket
 | |
| 
 | |
|   def test_copy_stream_socket3
 | |
|     mkcdtmpdir {
 | |
|       bigcontent = "abc" * 123456
 | |
|       File.open("bigsrc", "w") {|f| f << bigcontent }
 | |
| 
 | |
|       with_socketpair {|s1, s2|
 | |
|         t = Thread.new { s2.read }
 | |
|         ret = IO.copy_stream("bigsrc", s1, 10000)
 | |
|         assert_equal(10000, ret)
 | |
|         s1.close
 | |
|         result = t.value
 | |
|         assert_equal(bigcontent[0,10000], result)
 | |
|       }
 | |
|     }
 | |
|   end if defined? UNIXSocket
 | |
| 
 | |
|   def test_copy_stream_socket4
 | |
|     mkcdtmpdir {
 | |
|       bigcontent = "abc" * 123456
 | |
|       File.open("bigsrc", "w") {|f| f << bigcontent }
 | |
| 
 | |
|       File.open("bigsrc") {|f|
 | |
|         assert_equal(0, f.pos)
 | |
|         with_socketpair {|s1, s2|
 | |
|           t = Thread.new { s2.read }
 | |
|           ret = IO.copy_stream(f, s1, nil, 100)
 | |
|           assert_equal(bigcontent.bytesize-100, ret)
 | |
|           assert_equal(0, f.pos)
 | |
|           s1.close
 | |
|           result = t.value
 | |
|           assert_equal(bigcontent[100..-1], result)
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   end if defined? UNIXSocket
 | |
| 
 | |
|   def test_copy_stream_socket5
 | |
|     mkcdtmpdir {
 | |
|       bigcontent = "abc" * 123456
 | |
|       File.open("bigsrc", "w") {|f| f << bigcontent }
 | |
| 
 | |
|       File.open("bigsrc") {|f|
 | |
|         assert_equal(bigcontent[0,100], f.read(100))
 | |
|         assert_equal(100, f.pos)
 | |
|         with_socketpair {|s1, s2|
 | |
|           t = Thread.new { s2.read }
 | |
|           ret = IO.copy_stream(f, s1)
 | |
|           assert_equal(bigcontent.bytesize-100, ret)
 | |
|           assert_equal(bigcontent.length, f.pos)
 | |
|           s1.close
 | |
|           result = t.value
 | |
|           assert_equal(bigcontent[100..-1], result)
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   end if defined? UNIXSocket
 | |
| 
 | |
|   def test_copy_stream_socket6
 | |
|     mkcdtmpdir {
 | |
|       megacontent = "abc" * 1234567
 | |
|       File.open("megasrc", "w") {|f| f << megacontent }
 | |
| 
 | |
|       with_socketpair {|s1, s2|
 | |
|         begin
 | |
|           s1.nonblock = true
 | |
|         rescue Errno::EBADF
 | |
|           skip "nonblocking IO for pipe is not implemented"
 | |
|         end
 | |
|         t = Thread.new { s2.read }
 | |
|         ret = IO.copy_stream("megasrc", s1)
 | |
|         assert_equal(megacontent.bytesize, ret)
 | |
|         s1.close
 | |
|         result = t.value
 | |
|         assert_equal(megacontent, result)
 | |
|       }
 | |
|     }
 | |
|   end if defined? UNIXSocket
 | |
| 
 | |
|   def test_copy_stream_socket7
 | |
|     GC.start
 | |
|     mkcdtmpdir {
 | |
|       megacontent = "abc" * 1234567
 | |
|       File.open("megasrc", "w") {|f| f << megacontent }
 | |
| 
 | |
|       with_socketpair {|s1, s2|
 | |
|         begin
 | |
|           s1.nonblock = true
 | |
|         rescue Errno::EBADF
 | |
|           skip "nonblocking IO for pipe is not implemented"
 | |
|         end
 | |
|         trapping_usr1 do
 | |
|           nr = 30
 | |
|           begin
 | |
|             pid = fork do
 | |
|               s1.close
 | |
|               IO.select([s2])
 | |
|               Process.kill(:USR1, Process.ppid)
 | |
|               s2.read
 | |
|             end
 | |
|             s2.close
 | |
|             nr.times do
 | |
|               assert_equal megacontent.bytesize, IO.copy_stream("megasrc", s1)
 | |
|             end
 | |
|             assert_equal(1, @usr1_rcvd)
 | |
|           ensure
 | |
|             s1.close
 | |
|             _, status = Process.waitpid2(pid) if pid
 | |
|           end
 | |
|           assert status.success?, status.inspect
 | |
|         end
 | |
|       }
 | |
|     }
 | |
|   end if defined? UNIXSocket and IO.method_defined?("nonblock=")
 | |
| 
 | |
|   def test_copy_stream_strio
 | |
|     src = StringIO.new("abcd")
 | |
|     dst = StringIO.new
 | |
|     ret = IO.copy_stream(src, dst)
 | |
|     assert_equal(4, ret)
 | |
|     assert_equal("abcd", dst.string)
 | |
|     assert_equal(4, src.pos)
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_strio_len
 | |
|     src = StringIO.new("abcd")
 | |
|     dst = StringIO.new
 | |
|     ret = IO.copy_stream(src, dst, 3)
 | |
|     assert_equal(3, ret)
 | |
|     assert_equal("abc", dst.string)
 | |
|     assert_equal(3, src.pos)
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_strio_off
 | |
|     src = StringIO.new("abcd")
 | |
|     with_pipe {|r, w|
 | |
|       assert_raise(ArgumentError) {
 | |
|         IO.copy_stream(src, w, 3, 1)
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_fname_to_strio
 | |
|     mkcdtmpdir {
 | |
|       File.open("foo", "w") {|f| f << "abcd" }
 | |
|       src = "foo"
 | |
|       dst = StringIO.new
 | |
|       ret = IO.copy_stream(src, dst, 3)
 | |
|       assert_equal(3, ret)
 | |
|       assert_equal("abc", dst.string)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_strio_to_fname
 | |
|     mkcdtmpdir {
 | |
|       # StringIO to filename
 | |
|       src = StringIO.new("abcd")
 | |
|       ret = IO.copy_stream(src, "fooo", 3)
 | |
|       assert_equal(3, ret)
 | |
|       assert_equal("abc", File.read("fooo"))
 | |
|       assert_equal(3, src.pos)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_io_to_strio
 | |
|     mkcdtmpdir {
 | |
|       # IO to StringIO
 | |
|       File.open("bar", "w") {|f| f << "abcd" }
 | |
|       File.open("bar") {|src|
 | |
|         dst = StringIO.new
 | |
|         ret = IO.copy_stream(src, dst, 3)
 | |
|         assert_equal(3, ret)
 | |
|         assert_equal("abc", dst.string)
 | |
|         assert_equal(3, src.pos)
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_strio_to_io
 | |
|     mkcdtmpdir {
 | |
|       # StringIO to IO
 | |
|       src = StringIO.new("abcd")
 | |
|       ret = File.open("baz", "w") {|dst|
 | |
|         IO.copy_stream(src, dst, 3)
 | |
|       }
 | |
|       assert_equal(3, ret)
 | |
|       assert_equal("abc", File.read("baz"))
 | |
|       assert_equal(3, src.pos)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   class Rot13IO
 | |
|     def initialize(io)
 | |
|       @io = io
 | |
|     end
 | |
| 
 | |
|     def readpartial(*args)
 | |
|       ret = @io.readpartial(*args)
 | |
|       ret.tr!('a-zA-Z', 'n-za-mN-ZA-M')
 | |
|       ret
 | |
|     end
 | |
| 
 | |
|     def write(str)
 | |
|       @io.write(str.tr('a-zA-Z', 'n-za-mN-ZA-M'))
 | |
|     end
 | |
| 
 | |
|     def to_io
 | |
|       @io
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_io_to_rot13
 | |
|     mkcdtmpdir {
 | |
|       File.open("bar", "w") {|f| f << "vex" }
 | |
|       File.open("bar") {|src|
 | |
|         File.open("baz", "w") {|dst0|
 | |
|           dst = Rot13IO.new(dst0)
 | |
|           ret = IO.copy_stream(src, dst, 3)
 | |
|           assert_equal(3, ret)
 | |
|         }
 | |
|         assert_equal("irk", File.read("baz"))
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_rot13_to_io
 | |
|     mkcdtmpdir {
 | |
|       File.open("bar", "w") {|f| f << "flap" }
 | |
|       File.open("bar") {|src0|
 | |
|         src = Rot13IO.new(src0)
 | |
|         File.open("baz", "w") {|dst|
 | |
|           ret = IO.copy_stream(src, dst, 4)
 | |
|           assert_equal(4, ret)
 | |
|         }
 | |
|       }
 | |
|       assert_equal("sync", File.read("baz"))
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_rot13_to_rot13
 | |
|     mkcdtmpdir {
 | |
|       File.open("bar", "w") {|f| f << "bin" }
 | |
|       File.open("bar") {|src0|
 | |
|         src = Rot13IO.new(src0)
 | |
|         File.open("baz", "w") {|dst0|
 | |
|           dst = Rot13IO.new(dst0)
 | |
|           ret = IO.copy_stream(src, dst, 3)
 | |
|           assert_equal(3, ret)
 | |
|         }
 | |
|       }
 | |
|       assert_equal("bin", File.read("baz"))
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_strio_flush
 | |
|     with_pipe {|r, w|
 | |
|       w.sync = false
 | |
|       w.write "zz"
 | |
|       src = StringIO.new("abcd")
 | |
|       IO.copy_stream(src, w)
 | |
|       t = Thread.new {
 | |
|         w.close
 | |
|       }
 | |
|       assert_equal("zzabcd", r.read)
 | |
|       t.join
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_strio_rbuf
 | |
|     pipe(proc do |w|
 | |
|       w << "abcd"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal("a", r.read(1))
 | |
|       sio = StringIO.new
 | |
|       IO.copy_stream(r, sio)
 | |
|       assert_equal("bcd", sio.string)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_src_wbuf
 | |
|     mkcdtmpdir {
 | |
|       pipe(proc do |w|
 | |
|         File.open("foe", "w+") {|f|
 | |
|           f.write "abcd\n"
 | |
|           f.rewind
 | |
|           f.write "xy"
 | |
|           IO.copy_stream(f, w)
 | |
|         }
 | |
|         assert_equal("xycd\n", File.read("foe"))
 | |
|         w.close
 | |
|       end, proc do |r|
 | |
|         assert_equal("cd\n", r.read)
 | |
|         r.close
 | |
|       end)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   class Bug5237
 | |
|     attr_reader :count
 | |
|     def initialize
 | |
|       @count = 0
 | |
|     end
 | |
| 
 | |
|     def read(bytes, buffer)
 | |
|       @count += 1
 | |
|       buffer.replace "this is a test"
 | |
|       nil
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_broken_src_read_eof
 | |
|     src = Bug5237.new
 | |
|     dst = StringIO.new
 | |
|     assert_equal 0, src.count
 | |
|     th = Thread.new { IO.copy_stream(src, dst) }
 | |
|     flunk("timeout") unless th.join(10)
 | |
|     assert_equal 1, src.count
 | |
|   end
 | |
| 
 | |
|   def test_copy_stream_dst_rbuf
 | |
|     mkcdtmpdir {
 | |
|       pipe(proc do |w|
 | |
|         w << "xyz"
 | |
|         w.close
 | |
|       end, proc do |r|
 | |
|         File.open("fom", "w+b") {|f|
 | |
|           f.write "abcd\n"
 | |
|           f.rewind
 | |
|           assert_equal("abc", f.read(3))
 | |
|           f.ungetc "c"
 | |
|           IO.copy_stream(r, f)
 | |
|         }
 | |
|         assert_equal("abxyz", File.read("fom"))
 | |
|       end)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def safe_4
 | |
|     t = Thread.new do
 | |
|       $SAFE = 4
 | |
|       yield
 | |
|     end
 | |
|     unless t.join(10)
 | |
|       t.kill
 | |
|       flunk("timeout in safe_4")
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def ruby(*args)
 | |
|     args = ['-e', '$>.write($<.read)'] if args.empty?
 | |
|     ruby = EnvUtil.rubybin
 | |
|     f = IO.popen([ruby] + args, 'r+')
 | |
|     yield(f)
 | |
|   ensure
 | |
|     f.close unless !f || f.closed?
 | |
|   end
 | |
| 
 | |
|   def test_try_convert
 | |
|     assert_equal(STDOUT, IO.try_convert(STDOUT))
 | |
|     assert_equal(nil, IO.try_convert("STDOUT"))
 | |
|   end
 | |
| 
 | |
|   def test_ungetc2
 | |
|     f = false
 | |
|     pipe(proc do |w|
 | |
|       Thread.pass until f
 | |
|       w.write("1" * 10000)
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       r.ungetc("0" * 10000)
 | |
|       f = true
 | |
|       assert_equal("0" * 10000 + "1" * 10000, r.read)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_write_non_writable
 | |
|     with_pipe do |r, w|
 | |
|       assert_raise(IOError) do
 | |
|         r.write "foobarbaz"
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_dup
 | |
|     ruby do |f|
 | |
|       f2 = f.dup
 | |
|       f.puts "foo"
 | |
|       f2.puts "bar"
 | |
|       f.close_write
 | |
|       f2.close_write
 | |
|       assert_equal("foo\nbar\n", f.read)
 | |
|       assert_equal("", f2.read)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_dup_many
 | |
|     ruby('-e', <<-'End') {|f|
 | |
|       ok = 0
 | |
|       a = []
 | |
|       begin
 | |
|         loop {a << IO.pipe}
 | |
|       rescue Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM
 | |
|         ok += 1
 | |
|       end
 | |
|       print "no" if ok != 1
 | |
|       begin
 | |
|         loop {a << [a[-1][0].dup, a[-1][1].dup]}
 | |
|       rescue Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM
 | |
|         ok += 1
 | |
|       end
 | |
|       print "no" if ok != 2
 | |
|       print "ok"
 | |
|     End
 | |
|       assert_equal("ok", f.read)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_inspect
 | |
|     with_pipe do |r, w|
 | |
|       assert_match(/^#<IO:fd \d+>$/, r.inspect)
 | |
|       assert_raise(SecurityError) do
 | |
|         safe_4 { r.inspect }
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_readpartial
 | |
|     pipe(proc do |w|
 | |
|       w.write "foobarbaz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_raise(ArgumentError) { r.readpartial(-1) }
 | |
|       assert_equal("fooba", r.readpartial(5))
 | |
|       r.readpartial(5, s = "")
 | |
|       assert_equal("rbaz", s)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_readpartial_lock
 | |
|     with_pipe do |r, w|
 | |
|       s = ""
 | |
|       t = Thread.new { r.readpartial(5, s) }
 | |
|       Thread.pass until t.stop?
 | |
|       assert_raise(RuntimeError) { s.clear }
 | |
|       w.write "foobarbaz"
 | |
|       w.close
 | |
|       assert_equal("fooba", t.value)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_readpartial_pos
 | |
|     mkcdtmpdir {
 | |
|       open("foo", "w") {|f| f << "abc" }
 | |
|       open("foo") {|f|
 | |
|         f.seek(0)
 | |
|         assert_equal("ab", f.readpartial(2))
 | |
|         assert_equal(2, f.pos)
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_readpartial_with_not_empty_buffer
 | |
|     pipe(proc do |w|
 | |
|       w.write "foob"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       r.readpartial(5, s = "01234567")
 | |
|       assert_equal("foob", s)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_readpartial_buffer_error
 | |
|     with_pipe do |r, w|
 | |
|       s = ""
 | |
|       t = Thread.new { r.readpartial(5, s) }
 | |
|       Thread.pass until t.stop?
 | |
|       t.kill
 | |
|       t.value
 | |
|       assert_equal("", s)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_read
 | |
|     pipe(proc do |w|
 | |
|       w.write "foobarbaz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_raise(ArgumentError) { r.read(-1) }
 | |
|       assert_equal("fooba", r.read(5))
 | |
|       r.read(nil, s = "")
 | |
|       assert_equal("rbaz", s)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_read_lock
 | |
|     with_pipe do |r, w|
 | |
|       s = ""
 | |
|       t = Thread.new { r.read(5, s) }
 | |
|       Thread.pass until t.stop?
 | |
|       assert_raise(RuntimeError) { s.clear }
 | |
|       w.write "foobarbaz"
 | |
|       w.close
 | |
|       assert_equal("fooba", t.value)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_read_with_not_empty_buffer
 | |
|     pipe(proc do |w|
 | |
|       w.write "foob"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       r.read(nil, s = "01234567")
 | |
|       assert_equal("foob", s)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_read_buffer_error
 | |
|     with_pipe do |r, w|
 | |
|       s = ""
 | |
|       t = Thread.new { r.read(5, s) }
 | |
|       Thread.pass until t.stop?
 | |
|       t.kill
 | |
|       t.value
 | |
|       assert_equal("", s)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_write_nonblock
 | |
|     skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
 | |
|     pipe(proc do |w|
 | |
|       w.write_nonblock(1)
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal("1", r.read)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_read_nonblock_with_not_empty_buffer
 | |
|     skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
 | |
|     with_pipe {|r, w|
 | |
|       w.write "foob"
 | |
|       w.close
 | |
|       r.read_nonblock(5, s = "01234567")
 | |
|       assert_equal("foob", s)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_read_nonblock_error
 | |
|     return if !have_nonblock?
 | |
|     skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
 | |
|     with_pipe {|r, w|
 | |
|       begin
 | |
|         r.read_nonblock 4096
 | |
|       rescue Errno::EWOULDBLOCK
 | |
|         assert_kind_of(IO::WaitReadable, $!)
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_write_nonblock_error
 | |
|     return if !have_nonblock?
 | |
|     skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
 | |
|     with_pipe {|r, w|
 | |
|       begin
 | |
|         loop {
 | |
|           w.write_nonblock "a"*100000
 | |
|         }
 | |
|       rescue Errno::EWOULDBLOCK
 | |
|         assert_kind_of(IO::WaitWritable, $!)
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_gets
 | |
|     pipe(proc do |w|
 | |
|       w.write "foobarbaz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal("", r.gets(0))
 | |
|       assert_equal("foobarbaz", r.gets(9))
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_close_read
 | |
|     ruby do |f|
 | |
|       f.close_read
 | |
|       f.write "foobarbaz"
 | |
|       assert_raise(IOError) { f.read }
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_close_read_pipe
 | |
|     with_pipe do |r, w|
 | |
|       r.close_read
 | |
|       assert_raise(Errno::EPIPE) { w.write "foobarbaz" }
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_close_read_security_error
 | |
|     with_pipe do |r, w|
 | |
|       assert_raise(SecurityError) do
 | |
|         safe_4 { r.close_read }
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_close_read_non_readable
 | |
|     with_pipe do |r, w|
 | |
|       assert_raise(IOError) do
 | |
|         w.close_read
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_close_write
 | |
|     ruby do |f|
 | |
|       f.write "foobarbaz"
 | |
|       f.close_write
 | |
|       assert_equal("foobarbaz", f.read)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_close_write_security_error
 | |
|     with_pipe do |r, w|
 | |
|       assert_raise(SecurityError) do
 | |
|         safe_4 { r.close_write }
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_close_write_non_readable
 | |
|     with_pipe do |r, w|
 | |
|       assert_raise(IOError) do
 | |
|         r.close_write
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_pid
 | |
|     r, w = IO.pipe
 | |
|     assert_equal(nil, r.pid)
 | |
|     assert_equal(nil, w.pid)
 | |
| 
 | |
|     pipe = IO.popen(EnvUtil.rubybin, "r+")
 | |
|     pid1 = pipe.pid
 | |
|     pipe.puts "p $$"
 | |
|     pipe.close_write
 | |
|     pid2 = pipe.read.chomp.to_i
 | |
|     assert_equal(pid2, pid1)
 | |
|     assert_equal(pid2, pipe.pid)
 | |
|     pipe.close
 | |
|     assert_raise(IOError) { pipe.pid }
 | |
|   end
 | |
| 
 | |
|   def make_tempfile
 | |
|     t = Tempfile.new("test_io")
 | |
|     t.binmode
 | |
|     t.puts "foo"
 | |
|     t.puts "bar"
 | |
|     t.puts "baz"
 | |
|     t.close
 | |
|     if block_given?
 | |
|       begin
 | |
|         yield t
 | |
|       ensure
 | |
|         t.close(true)
 | |
|       end
 | |
|     else
 | |
|       t
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_set_lineno
 | |
|     make_tempfile {|t|
 | |
|       ruby("-e", <<-SRC, t.path) do |f|
 | |
|         open(ARGV[0]) do |f|
 | |
|           p $.
 | |
|           f.gets; p $.
 | |
|           f.gets; p $.
 | |
|           f.lineno = 1000; p $.
 | |
|           f.gets; p $.
 | |
|           f.gets; p $.
 | |
|           f.rewind; p $.
 | |
|           f.gets; p $.
 | |
|           f.gets; p $.
 | |
|           f.gets; p $.
 | |
|           f.gets; p $.
 | |
|         end
 | |
|       SRC
 | |
|         assert_equal("0,1,2,2,1001,1001,1001,1,2,3,3", f.read.chomp.gsub("\n", ","))
 | |
|       end
 | |
| 
 | |
|       pipe(proc do |w|
 | |
|         w.puts "foo"
 | |
|         w.puts "bar"
 | |
|         w.puts "baz"
 | |
|         w.close
 | |
|       end, proc do |r|
 | |
|         r.gets; assert_equal(1, $.)
 | |
|         r.gets; assert_equal(2, $.)
 | |
|         r.lineno = 1000; assert_equal(2, $.)
 | |
|         r.gets; assert_equal(1001, $.)
 | |
|         r.gets; assert_equal(1001, $.)
 | |
|       end)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_readline
 | |
|     pipe(proc do |w|
 | |
|       w.puts "foo"
 | |
|       w.puts "bar"
 | |
|       w.puts "baz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       r.readline; assert_equal(1, $.)
 | |
|       r.readline; assert_equal(2, $.)
 | |
|       r.lineno = 1000; assert_equal(2, $.)
 | |
|       r.readline; assert_equal(1001, $.)
 | |
|       assert_raise(EOFError) { r.readline }
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_each_char
 | |
|     pipe(proc do |w|
 | |
|       w.puts "foo"
 | |
|       w.puts "bar"
 | |
|       w.puts "baz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       a = []
 | |
|       r.each_char {|c| a << c }
 | |
|       assert_equal(%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"], a)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_lines
 | |
|     verbose, $VERBOSE = $VERBOSE, nil
 | |
|     pipe(proc do |w|
 | |
|       w.puts "foo"
 | |
|       w.puts "bar"
 | |
|       w.puts "baz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       e = nil
 | |
|       assert_warn(/deprecated/) {
 | |
|         e = r.lines
 | |
|       }
 | |
|       assert_equal("foo\n", e.next)
 | |
|       assert_equal("bar\n", e.next)
 | |
|       assert_equal("baz\n", e.next)
 | |
|       assert_raise(StopIteration) { e.next }
 | |
|     end)
 | |
|   ensure
 | |
|     $VERBOSE = verbose
 | |
|   end
 | |
| 
 | |
|   def test_bytes
 | |
|     verbose, $VERBOSE = $VERBOSE, nil
 | |
|     pipe(proc do |w|
 | |
|       w.binmode
 | |
|       w.puts "foo"
 | |
|       w.puts "bar"
 | |
|       w.puts "baz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       e = nil
 | |
|       assert_warn(/deprecated/) {
 | |
|         e = r.bytes
 | |
|       }
 | |
|       (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
 | |
|         assert_equal(c.ord, e.next)
 | |
|       end
 | |
|       assert_raise(StopIteration) { e.next }
 | |
|     end)
 | |
|   ensure
 | |
|     $VERBOSE = verbose
 | |
|   end
 | |
| 
 | |
|   def test_chars
 | |
|     verbose, $VERBOSE = $VERBOSE, nil
 | |
|     pipe(proc do |w|
 | |
|       w.puts "foo"
 | |
|       w.puts "bar"
 | |
|       w.puts "baz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       e = nil
 | |
|       assert_warn(/deprecated/) {
 | |
|         e = r.chars
 | |
|       }
 | |
|       (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
 | |
|         assert_equal(c, e.next)
 | |
|       end
 | |
|       assert_raise(StopIteration) { e.next }
 | |
|     end)
 | |
|   ensure
 | |
|     $VERBOSE = verbose
 | |
|   end
 | |
| 
 | |
|   def test_readbyte
 | |
|     pipe(proc do |w|
 | |
|       w.binmode
 | |
|       w.puts "foo"
 | |
|       w.puts "bar"
 | |
|       w.puts "baz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       r.binmode
 | |
|       (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
 | |
|         assert_equal(c.ord, r.readbyte)
 | |
|       end
 | |
|       assert_raise(EOFError) { r.readbyte }
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_readchar
 | |
|     pipe(proc do |w|
 | |
|       w.puts "foo"
 | |
|       w.puts "bar"
 | |
|       w.puts "baz"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
 | |
|         assert_equal(c, r.readchar)
 | |
|       end
 | |
|       assert_raise(EOFError) { r.readchar }
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_close_on_exec
 | |
|     skip "IO\#close_on_exec is not implemented." unless have_close_on_exec?
 | |
|     ruby do |f|
 | |
|       assert_equal(true, f.close_on_exec?)
 | |
|       f.close_on_exec = false
 | |
|       assert_equal(false, f.close_on_exec?)
 | |
|       f.close_on_exec = true
 | |
|       assert_equal(true, f.close_on_exec?)
 | |
|       f.close_on_exec = false
 | |
|       assert_equal(false, f.close_on_exec?)
 | |
|     end
 | |
| 
 | |
|     with_pipe do |r, w|
 | |
|       assert_equal(true, r.close_on_exec?)
 | |
|       r.close_on_exec = false
 | |
|       assert_equal(false, r.close_on_exec?)
 | |
|       r.close_on_exec = true
 | |
|       assert_equal(true, r.close_on_exec?)
 | |
|       r.close_on_exec = false
 | |
|       assert_equal(false, r.close_on_exec?)
 | |
| 
 | |
|       assert_equal(true, w.close_on_exec?)
 | |
|       w.close_on_exec = false
 | |
|       assert_equal(false, w.close_on_exec?)
 | |
|       w.close_on_exec = true
 | |
|       assert_equal(true, w.close_on_exec?)
 | |
|       w.close_on_exec = false
 | |
|       assert_equal(false, w.close_on_exec?)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_close_security_error
 | |
|     with_pipe do |r, w|
 | |
|       assert_raise(SecurityError) do
 | |
|         safe_4 { r.close }
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_pos
 | |
|     make_tempfile {|t|
 | |
| 
 | |
|       open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f|
 | |
|         f.write "Hello"
 | |
|         assert_equal(5, f.pos)
 | |
|       end
 | |
|       open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f|
 | |
|         f.sync = true
 | |
|         f.read
 | |
|         f.write "Hello"
 | |
|         assert_equal(5, f.pos)
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_pos_with_getc
 | |
|     bug6179 = '[ruby-core:43497]'
 | |
|     make_tempfile {|t|
 | |
|       ["", "t", "b"].each do |mode|
 | |
|         open(t.path, "w#{mode}") do |f|
 | |
|           f.write "0123456789\n"
 | |
|         end
 | |
| 
 | |
|         open(t.path, "r#{mode}") do |f|
 | |
|           assert_equal 0, f.pos, "mode=r#{mode}"
 | |
|           assert_equal '0', f.getc, "mode=r#{mode}"
 | |
|           assert_equal 1, f.pos, "mode=r#{mode}"
 | |
|           assert_equal '1', f.getc, "mode=r#{mode}"
 | |
|           assert_equal 2, f.pos, "mode=r#{mode}"
 | |
|           assert_equal '2', f.getc, "mode=r#{mode}"
 | |
|           assert_equal 3, f.pos, "mode=r#{mode}"
 | |
|           assert_equal '3', f.getc, "mode=r#{mode}"
 | |
|           assert_equal 4, f.pos, "mode=r#{mode}"
 | |
|           assert_equal '4', f.getc, "mode=r#{mode}"
 | |
|         end
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
| 
 | |
|   def test_seek
 | |
|     make_tempfile {|t|
 | |
|       open(t.path) { |f|
 | |
|         f.seek(9)
 | |
|         assert_equal("az\n", f.read)
 | |
|       }
 | |
| 
 | |
|       open(t.path) { |f|
 | |
|         f.seek(9, IO::SEEK_SET)
 | |
|         assert_equal("az\n", f.read)
 | |
|       }
 | |
| 
 | |
|       open(t.path) { |f|
 | |
|         f.seek(-4, IO::SEEK_END)
 | |
|         assert_equal("baz\n", f.read)
 | |
|       }
 | |
| 
 | |
|       open(t.path) { |f|
 | |
|         assert_equal("foo\n", f.gets)
 | |
|         f.seek(2, IO::SEEK_CUR)
 | |
|         assert_equal("r\nbaz\n", f.read)
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_seek_symwhence
 | |
|     make_tempfile {|t|
 | |
|       open(t.path) { |f|
 | |
|         f.seek(9, :SET)
 | |
|         assert_equal("az\n", f.read)
 | |
|       }
 | |
| 
 | |
|       open(t.path) { |f|
 | |
|         f.seek(-4, :END)
 | |
|         assert_equal("baz\n", f.read)
 | |
|       }
 | |
| 
 | |
|       open(t.path) { |f|
 | |
|         assert_equal("foo\n", f.gets)
 | |
|         f.seek(2, :CUR)
 | |
|         assert_equal("r\nbaz\n", f.read)
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_sysseek
 | |
|     make_tempfile {|t|
 | |
|       open(t.path) do |f|
 | |
|         f.sysseek(-4, IO::SEEK_END)
 | |
|         assert_equal("baz\n", f.read)
 | |
|       end
 | |
| 
 | |
|       open(t.path) do |f|
 | |
|         a = [f.getc, f.getc, f.getc]
 | |
|         a.reverse_each {|c| f.ungetc c }
 | |
|         assert_raise(IOError) { f.sysseek(1) }
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_syswrite
 | |
|     make_tempfile {|t|
 | |
|       open(t.path, "w") do |f|
 | |
|         o = Object.new
 | |
|         def o.to_s; "FOO\n"; end
 | |
|         f.syswrite(o)
 | |
|       end
 | |
|       assert_equal("FOO\n", File.read(t.path))
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_sysread
 | |
|     make_tempfile {|t|
 | |
|       open(t.path) do |f|
 | |
|         a = [f.getc, f.getc, f.getc]
 | |
|         a.reverse_each {|c| f.ungetc c }
 | |
|         assert_raise(IOError) { f.sysread(1) }
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_sysread_with_not_empty_buffer
 | |
|     pipe(proc do |w|
 | |
|       w.write "foob"
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       r.sysread( 5, s = "01234567" )
 | |
|       assert_equal( "foob", s )
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_flag
 | |
|     make_tempfile {|t|
 | |
|       assert_raise(ArgumentError) do
 | |
|         open(t.path, "z") { }
 | |
|       end
 | |
| 
 | |
|       assert_raise(ArgumentError) do
 | |
|         open(t.path, "rr") { }
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_sysopen
 | |
|     make_tempfile {|t|
 | |
|       fd = IO.sysopen(t.path)
 | |
|       assert_kind_of(Integer, fd)
 | |
|       f = IO.for_fd(fd)
 | |
|       assert_equal("foo\nbar\nbaz\n", f.read)
 | |
|       f.close
 | |
| 
 | |
|       fd = IO.sysopen(t.path, "w", 0666)
 | |
|       assert_kind_of(Integer, fd)
 | |
|       if defined?(Fcntl::F_GETFL)
 | |
|         f = IO.for_fd(fd)
 | |
|       else
 | |
|         f = IO.for_fd(fd, 0666)
 | |
|       end
 | |
|       f.write("FOO\n")
 | |
|       f.close
 | |
| 
 | |
|       fd = IO.sysopen(t.path, "r")
 | |
|       assert_kind_of(Integer, fd)
 | |
|       f = IO.for_fd(fd)
 | |
|       assert_equal("FOO\n", f.read)
 | |
|       f.close
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def try_fdopen(fd, autoclose = true, level = 50)
 | |
|     if level > 0
 | |
|       begin
 | |
|         1.times {return try_fdopen(fd, autoclose, level - 1)}
 | |
|       ensure
 | |
|         GC.start
 | |
|       end
 | |
|     else
 | |
|       WeakRef.new(IO.for_fd(fd, autoclose: autoclose))
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_autoclose
 | |
|     feature2250 = '[ruby-core:26222]'
 | |
|     pre = 'ft2250'
 | |
| 
 | |
|     Dir.mktmpdir {|d|
 | |
|       t = open("#{d}/#{pre}", "w")
 | |
|       f = IO.for_fd(t.fileno)
 | |
|       assert_equal(true, f.autoclose?)
 | |
|       f.autoclose = false
 | |
|       assert_equal(false, f.autoclose?)
 | |
|       f.close
 | |
|       assert_nothing_raised(Errno::EBADF, feature2250) {t.close}
 | |
| 
 | |
|       t = open("#{d}/#{pre}", "w")
 | |
|       f = IO.for_fd(t.fileno, autoclose: false)
 | |
|       assert_equal(false, f.autoclose?)
 | |
|       f.autoclose = true
 | |
|       assert_equal(true, f.autoclose?)
 | |
|       f.close
 | |
|       assert_raise(Errno::EBADF, feature2250) {t.close}
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_autoclose_true_closed_by_finalizer
 | |
|     feature2250 = '[ruby-core:26222]'
 | |
|     pre = 'ft2250'
 | |
|     t = Tempfile.new(pre)
 | |
|     w = try_fdopen(t.fileno)
 | |
|     begin
 | |
|       w.close
 | |
|       begin
 | |
|         t.close
 | |
|       rescue Errno::EBADF
 | |
|       end
 | |
|       skip "expect IO object was GC'ed but not recycled yet"
 | |
|     rescue WeakRef::RefError
 | |
|       assert_raise(Errno::EBADF, feature2250) {t.close}
 | |
|     end
 | |
|   ensure
 | |
|     t.unlink
 | |
|   end
 | |
| 
 | |
|   def test_autoclose_false_closed_by_finalizer
 | |
|     feature2250 = '[ruby-core:26222]'
 | |
|     pre = 'ft2250'
 | |
|     t = Tempfile.new(pre)
 | |
|     w = try_fdopen(t.fileno, false)
 | |
|     begin
 | |
|       w.close
 | |
|       t.close
 | |
|       skip "expect IO object was GC'ed but not recycled yet"
 | |
|     rescue WeakRef::RefError
 | |
|       assert_nothing_raised(Errno::EBADF, feature2250) {t.close}
 | |
|     end
 | |
|   ensure
 | |
|     t.unlink
 | |
|   end
 | |
| 
 | |
|   def test_open_redirect
 | |
|     o = Object.new
 | |
|     def o.to_open; self; end
 | |
|     assert_equal(o, open(o))
 | |
|     o2 = nil
 | |
|     open(o) do |f|
 | |
|       o2 = f
 | |
|     end
 | |
|     assert_equal(o, o2)
 | |
|   end
 | |
| 
 | |
|   def test_open_pipe
 | |
|     open("|" + EnvUtil.rubybin, "r+") do |f|
 | |
|       f.puts "puts 'foo'"
 | |
|       f.close_write
 | |
|       assert_equal("foo\n", f.read)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_reopen
 | |
|     make_tempfile {|t|
 | |
|       with_pipe do |r, w|
 | |
|         assert_raise(SecurityError) do
 | |
|           safe_4 { r.reopen(t.path) }
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       open(__FILE__) do |f|
 | |
|         f.gets
 | |
|         assert_nothing_raised {
 | |
|           f.reopen(t.path)
 | |
|           assert_equal("foo\n", f.gets)
 | |
|         }
 | |
|       end
 | |
| 
 | |
|       open(__FILE__) do |f|
 | |
|         f.gets
 | |
|         f2 = open(t.path)
 | |
|         begin
 | |
|           f2.gets
 | |
|           assert_nothing_raised {
 | |
|             f.reopen(f2)
 | |
|             assert_equal("bar\n", f.gets, '[ruby-core:24240]')
 | |
|           }
 | |
|         ensure
 | |
|           f2.close
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       open(__FILE__) do |f|
 | |
|         f2 = open(t.path)
 | |
|         begin
 | |
|           f.reopen(f2)
 | |
|           assert_equal("foo\n", f.gets)
 | |
|           assert_equal("bar\n", f.gets)
 | |
|           f.reopen(f2)
 | |
|           assert_equal("baz\n", f.gets, '[ruby-dev:39479]')
 | |
|         ensure
 | |
|           f2.close
 | |
|         end
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_reopen_inherit
 | |
|     mkcdtmpdir {
 | |
|       system(EnvUtil.rubybin, '-e', <<"End")
 | |
|         f = open("out", "w")
 | |
|         STDOUT.reopen(f)
 | |
|         STDERR.reopen(f)
 | |
|         system(#{EnvUtil.rubybin.dump}, '-e', 'STDOUT.print "out"')
 | |
|         system(#{EnvUtil.rubybin.dump}, '-e', 'STDERR.print "err"')
 | |
| End
 | |
|       assert_equal("outerr", File.read("out"))
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_reopen_mode
 | |
|     feature7067 = '[ruby-core:47694]'
 | |
|     make_tempfile {|t|
 | |
|       open(__FILE__) do |f|
 | |
|         assert_nothing_raised {
 | |
|           f.reopen(t.path, "r")
 | |
|           assert_equal("foo\n", f.gets)
 | |
|         }
 | |
|       end
 | |
| 
 | |
|       open(__FILE__) do |f|
 | |
|         assert_nothing_raised(feature7067) {
 | |
|           f.reopen(t.path, File::RDONLY)
 | |
|           assert_equal("foo\n", f.gets)
 | |
|         }
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_reopen_opt
 | |
|     feature7103 = '[ruby-core:47806]'
 | |
|     make_tempfile {|t|
 | |
|       open(__FILE__) do |f|
 | |
|         assert_nothing_raised(feature7103) {
 | |
|           f.reopen(t.path, "r", binmode: true)
 | |
|         }
 | |
|         assert_equal("foo\n", f.gets)
 | |
|       end
 | |
| 
 | |
|       open(__FILE__) do |f|
 | |
|         assert_nothing_raised(feature7103) {
 | |
|           f.reopen(t.path, autoclose: false)
 | |
|         }
 | |
|         assert_equal("foo\n", f.gets)
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def make_tempfile_for_encoding
 | |
|     t = make_tempfile
 | |
|     open(t.path, "rb+:utf-8") {|f| f.puts "\u7d05\u7389bar\n"}
 | |
|     if block_given?
 | |
|       yield t
 | |
|     else
 | |
|       t
 | |
|     end
 | |
|   ensure
 | |
|     t.close(true) if t and block_given?
 | |
|   end
 | |
| 
 | |
|   def test_reopen_encoding
 | |
|     make_tempfile_for_encoding {|t|
 | |
|       open(__FILE__) {|f|
 | |
|         f.reopen(t.path, "r:utf-8")
 | |
|         s = f.gets
 | |
|         assert_equal(Encoding::UTF_8, s.encoding)
 | |
|         assert_equal("\u7d05\u7389bar\n", s)
 | |
|       }
 | |
| 
 | |
|       open(__FILE__) {|f|
 | |
|         f.reopen(t.path, "r:UTF-8:EUC-JP")
 | |
|         s = f.gets
 | |
|         assert_equal(Encoding::EUC_JP, s.encoding)
 | |
|         assert_equal("\xB9\xC8\xB6\xCCbar\n".force_encoding(Encoding::EUC_JP), s)
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_reopen_opt_encoding
 | |
|     feature7103 = '[ruby-core:47806]'
 | |
|     make_tempfile_for_encoding {|t|
 | |
|       open(__FILE__) {|f|
 | |
|         assert_nothing_raised(feature7103) {f.reopen(t.path, encoding: "ASCII-8BIT")}
 | |
|         s = f.gets
 | |
|         assert_equal(Encoding::ASCII_8BIT, s.encoding)
 | |
|         assert_equal("\xe7\xb4\x85\xe7\x8e\x89bar\n", s)
 | |
|       }
 | |
| 
 | |
|       open(__FILE__) {|f|
 | |
|         assert_nothing_raised(feature7103) {f.reopen(t.path, encoding: "UTF-8:EUC-JP")}
 | |
|         s = f.gets
 | |
|         assert_equal(Encoding::EUC_JP, s.encoding)
 | |
|         assert_equal("\xB9\xC8\xB6\xCCbar\n".force_encoding(Encoding::EUC_JP), s)
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_foreach
 | |
|     a = []
 | |
|     IO.foreach("|" + EnvUtil.rubybin + " -e 'puts :foo; puts :bar; puts :baz'") {|x| a << x }
 | |
|     assert_equal(["foo\n", "bar\n", "baz\n"], a)
 | |
| 
 | |
|     make_tempfile {|t|
 | |
|       a = []
 | |
|       IO.foreach(t.path) {|x| a << x }
 | |
|       assert_equal(["foo\n", "bar\n", "baz\n"], a)
 | |
| 
 | |
|       a = []
 | |
|       IO.foreach(t.path, {:mode => "r" }) {|x| a << x }
 | |
|       assert_equal(["foo\n", "bar\n", "baz\n"], a)
 | |
| 
 | |
|       a = []
 | |
|       IO.foreach(t.path, {:open_args => [] }) {|x| a << x }
 | |
|       assert_equal(["foo\n", "bar\n", "baz\n"], a)
 | |
| 
 | |
|       a = []
 | |
|       IO.foreach(t.path, {:open_args => ["r"] }) {|x| a << x }
 | |
|       assert_equal(["foo\n", "bar\n", "baz\n"], a)
 | |
| 
 | |
|       a = []
 | |
|       IO.foreach(t.path, "b") {|x| a << x }
 | |
|       assert_equal(["foo\nb", "ar\nb", "az\n"], a)
 | |
| 
 | |
|       a = []
 | |
|       IO.foreach(t.path, 3) {|x| a << x }
 | |
|       assert_equal(["foo", "\n", "bar", "\n", "baz", "\n"], a)
 | |
| 
 | |
|       a = []
 | |
|       IO.foreach(t.path, "b", 3) {|x| a << x }
 | |
|       assert_equal(["foo", "\nb", "ar\n", "b", "az\n"], a)
 | |
| 
 | |
|       bug = '[ruby-dev:31525]'
 | |
|       assert_raise(ArgumentError, bug) {IO.foreach}
 | |
| 
 | |
|       a = nil
 | |
|       assert_nothing_raised(ArgumentError, bug) {a = IO.foreach(t.path).to_a}
 | |
|       assert_equal(["foo\n", "bar\n", "baz\n"], a, bug)
 | |
| 
 | |
|       bug6054 = '[ruby-dev:45267]'
 | |
|       e = assert_raise(IOError, bug6054) {IO.foreach(t.path, mode:"w").next}
 | |
|       assert_match(/not opened for reading/, e.message, bug6054)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_s_readlines
 | |
|     make_tempfile {|t|
 | |
|       assert_equal(["foo\n", "bar\n", "baz\n"], IO.readlines(t.path))
 | |
|       assert_equal(["foo\nb", "ar\nb", "az\n"], IO.readlines(t.path, "b"))
 | |
|       assert_equal(["fo", "o\n", "ba", "r\n", "ba", "z\n"], IO.readlines(t.path, 2))
 | |
|       assert_equal(["fo", "o\n", "b", "ar", "\nb", "az", "\n"], IO.readlines(t.path, "b", 2))
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_printf
 | |
|     pipe(proc do |w|
 | |
|       printf(w, "foo %s baz\n", "bar")
 | |
|       w.close_write
 | |
|     end, proc do |r|
 | |
|       assert_equal("foo bar baz\n", r.read)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_print
 | |
|     make_tempfile {|t|
 | |
|       assert_in_out_err(["-", t.path],
 | |
|                         "print while $<.gets",
 | |
|                         %w(foo bar baz), [])
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_print_separators
 | |
|     $, = ':'
 | |
|     $\ = "\n"
 | |
|     pipe(proc do |w|
 | |
|       w.print('a')
 | |
|       w.print('a','b','c')
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal("a\n", r.gets)
 | |
|       assert_equal("a:b:c\n", r.gets)
 | |
|       assert_nil r.gets
 | |
|       r.close
 | |
|     end)
 | |
|   ensure
 | |
|     $, = nil
 | |
|     $\ = nil
 | |
|   end
 | |
| 
 | |
|   def test_putc
 | |
|     pipe(proc do |w|
 | |
|       w.putc "A"
 | |
|       w.putc "BC"
 | |
|       w.putc 68
 | |
|       w.close_write
 | |
|     end, proc do |r|
 | |
|       assert_equal("ABD", r.read)
 | |
|     end)
 | |
| 
 | |
|     assert_in_out_err([], "putc 65", %w(A), [])
 | |
|   end
 | |
| 
 | |
|   def test_puts_recursive_array
 | |
|     a = ["foo"]
 | |
|     a << a
 | |
|     pipe(proc do |w|
 | |
|       w.puts a
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal("foo\n[...]\n", r.read)
 | |
|     end)
 | |
|   end
 | |
| 
 | |
|   def test_display
 | |
|     pipe(proc do |w|
 | |
|       "foo".display(w)
 | |
|       w.close
 | |
|     end, proc do |r|
 | |
|       assert_equal("foo", r.read)
 | |
|     end)
 | |
| 
 | |
|     assert_in_out_err([], "'foo'.display", %w(foo), [])
 | |
|   end
 | |
| 
 | |
|   def test_set_stdout
 | |
|     assert_raise(TypeError) { $> = Object.new }
 | |
| 
 | |
|     assert_in_out_err([], "$> = $stderr\nputs 'foo'", [], %w(foo))
 | |
|   end
 | |
| 
 | |
|   def test_initialize
 | |
|     return unless defined?(Fcntl::F_GETFL)
 | |
| 
 | |
|     make_tempfile {|t|
 | |
| 
 | |
|       fd = IO.sysopen(t.path, "w")
 | |
|       assert_kind_of(Integer, fd)
 | |
|       %w[r r+ w+ a+].each do |mode|
 | |
|         assert_raise(Errno::EINVAL, "#{mode} [ruby-dev:38571]") {IO.new(fd, mode)}
 | |
|       end
 | |
|       f = IO.new(fd, "w")
 | |
|       f.write("FOO\n")
 | |
|       f.close
 | |
| 
 | |
|       assert_equal("FOO\n", File.read(t.path))
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_reinitialize
 | |
|     make_tempfile {|t|
 | |
|       f = open(t.path)
 | |
|       begin
 | |
|         assert_raise(RuntimeError) do
 | |
|           f.instance_eval { initialize }
 | |
|         end
 | |
|       ensure
 | |
|         f.close
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_new_with_block
 | |
|     assert_in_out_err([], "r, w = IO.pipe; IO.new(r) {}", [], /^.+$/)
 | |
|   end
 | |
| 
 | |
|   def test_readline2
 | |
|     assert_in_out_err(["-e", <<-SRC], "foo\nbar\nbaz\n", %w(foo bar baz end), [])
 | |
|       puts readline
 | |
|       puts readline
 | |
|       puts readline
 | |
|       begin
 | |
|         puts readline
 | |
|       rescue EOFError
 | |
|         puts "end"
 | |
|       end
 | |
|     SRC
 | |
|   end
 | |
| 
 | |
|   def test_readlines
 | |
|     assert_in_out_err(["-e", "p readlines"], "foo\nbar\nbaz\n",
 | |
|                       ["[\"foo\\n\", \"bar\\n\", \"baz\\n\"]"], [])
 | |
|   end
 | |
| 
 | |
|   def test_s_read
 | |
|     make_tempfile {|t|
 | |
|       assert_equal("foo\nbar\nbaz\n", File.read(t.path))
 | |
|       assert_equal("foo\nba", File.read(t.path, 6))
 | |
|       assert_equal("bar\n", File.read(t.path, 4, 4))
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_uninitialized
 | |
|     assert_raise(IOError) { IO.allocate.print "" }
 | |
|   end
 | |
| 
 | |
|   def test_nofollow
 | |
|     # O_NOFOLLOW is not standard.
 | |
|     return if /freebsd|linux/ !~ RUBY_PLATFORM
 | |
|     return unless defined? File::NOFOLLOW
 | |
|     mkcdtmpdir {
 | |
|       open("file", "w") {|f| f << "content" }
 | |
|       begin
 | |
|         File.symlink("file", "slnk")
 | |
|       rescue NotImplementedError
 | |
|         return
 | |
|       end
 | |
|       assert_raise(Errno::EMLINK, Errno::ELOOP) {
 | |
|         open("slnk", File::RDONLY|File::NOFOLLOW) {}
 | |
|       }
 | |
|       assert_raise(Errno::EMLINK, Errno::ELOOP) {
 | |
|         File.foreach("slnk", :open_args=>[File::RDONLY|File::NOFOLLOW]) {}
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_tainted
 | |
|     make_tempfile {|t|
 | |
|       assert(File.read(t.path, 4).tainted?, '[ruby-dev:38826]')
 | |
|       assert(File.open(t.path) {|f| f.read(4)}.tainted?, '[ruby-dev:38826]')
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_binmode_after_closed
 | |
|     make_tempfile {|t|
 | |
|       assert_raise(IOError) {t.binmode}
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_threaded_flush
 | |
|     bug3585 = '[ruby-core:31348]'
 | |
|     src = %q{\
 | |
|       t = Thread.new { sleep 3 }
 | |
|       Thread.new {sleep 1; t.kill; p 'hi!'}
 | |
|       t.join
 | |
|     }.gsub(/^\s+/, '')
 | |
|     10.times.map do
 | |
|       Thread.start do
 | |
|         assert_in_out_err([], src) {|stdout, stderr|
 | |
|           assert_no_match(/hi.*hi/, stderr.join, bug3585)
 | |
|         }
 | |
|       end
 | |
|     end.each {|th| th.join}
 | |
|   end
 | |
| 
 | |
|   def test_flush_in_finalizer1
 | |
|     require 'tempfile'
 | |
|     bug3910 = '[ruby-dev:42341]'
 | |
|     Tempfile.open("bug3910") {|t|
 | |
|       path = t.path
 | |
|       t.close
 | |
|       fds = []
 | |
|       assert_nothing_raised(TypeError, bug3910) do
 | |
|         500.times {
 | |
|           f = File.open(path, "w")
 | |
|           fds << f.fileno
 | |
|           f.print "hoge"
 | |
|         }
 | |
|       end
 | |
|       t.unlink
 | |
|     }
 | |
|   ensure
 | |
|     GC.start
 | |
|   end
 | |
| 
 | |
|   def test_flush_in_finalizer2
 | |
|     require 'tempfile'
 | |
|     bug3910 = '[ruby-dev:42341]'
 | |
|     Tempfile.open("bug3910") {|t|
 | |
|       path = t.path
 | |
|       t.close
 | |
|       1.times do
 | |
|         io = open(path,"w")
 | |
|         io.print "hoge"
 | |
|       end
 | |
|       assert_nothing_raised(TypeError, bug3910) do
 | |
|         GC.start
 | |
|       end
 | |
|       t.unlink
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_readlines_limit_0
 | |
|     bug4024 = '[ruby-dev:42538]'
 | |
|     make_tempfile {|t|
 | |
|       open(t.path, "r") do |io|
 | |
|         assert_raise(ArgumentError, bug4024) do
 | |
|           io.readlines(0)
 | |
|         end
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_each_line_limit_0
 | |
|     bug4024 = '[ruby-dev:42538]'
 | |
|     make_tempfile {|t|
 | |
|       open(t.path, "r") do |io|
 | |
|         assert_raise(ArgumentError, bug4024) do
 | |
|           io.each_line(0).next
 | |
|         end
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_advise
 | |
|     make_tempfile {|tf|
 | |
|       assert_raise(ArgumentError, "no arguments") { tf.advise }
 | |
|       %w{normal random sequential willneed dontneed noreuse}.map(&:to_sym).each do |adv|
 | |
|         [[0,0], [0, 20], [400, 2]].each do |offset, len|
 | |
|           open(tf.path) do |t|
 | |
|             assert_equal(t.advise(adv, offset, len), nil)
 | |
|             assert_raise(ArgumentError, "superfluous arguments") do
 | |
|               t.advise(adv, offset, len, offset)
 | |
|             end
 | |
|             assert_raise(TypeError, "wrong type for first argument") do
 | |
|               t.advise(adv.to_s, offset, len)
 | |
|             end
 | |
|             assert_raise(TypeError, "wrong type for last argument") do
 | |
|               t.advise(adv, offset, Array(len))
 | |
|             end
 | |
|             assert_raise(RangeError, "last argument too big") do
 | |
|               t.advise(adv, offset, 9999e99)
 | |
|             end
 | |
|           end
 | |
|           assert_raise(IOError, "closed file") do
 | |
|             make_tempfile {|tf2|
 | |
|               tf2.advise(adv.to_sym, offset, len)
 | |
|             }
 | |
|           end
 | |
|         end
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_invalid_advise
 | |
|     feature4204 = '[ruby-dev:42887]'
 | |
|     make_tempfile {|tf|
 | |
|       %w{Normal rand glark will_need zzzzzzzzzzzz \u2609}.map(&:to_sym).each do |adv|
 | |
|         [[0,0], [0, 20], [400, 2]].each do |offset, len|
 | |
|           open(tf.path) do |t|
 | |
|             assert_raise(NotImplementedError, feature4204) { t.advise(adv, offset, len) }
 | |
|           end
 | |
|         end
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_fcntl_lock_linux
 | |
|     return if /x86_64-linux/ !~ RUBY_PLATFORM # A binary form of struct flock depend on platform
 | |
|     return if [nil].pack("p").bytesize != 8 # Return if x32 platform.
 | |
| 
 | |
|     pad=0
 | |
|     Tempfile.create(self.class.name) do |f|
 | |
|       r, w = IO.pipe
 | |
|       pid = fork do
 | |
|         r.close
 | |
|         lock = [Fcntl::F_WRLCK, IO::SEEK_SET, pad, 12, 34, 0].pack("s!s!i!L!L!i!")
 | |
|         f.fcntl Fcntl::F_SETLKW, lock
 | |
|         w.syswrite "."
 | |
|         sleep
 | |
|       end
 | |
|       w.close
 | |
|       assert_equal ".", r.read(1)
 | |
|       r.close
 | |
|       pad = 0
 | |
|       getlock = [Fcntl::F_WRLCK, 0, pad, 0, 0, 0].pack("s!s!i!L!L!i!")
 | |
|       f.fcntl Fcntl::F_GETLK, getlock
 | |
| 
 | |
|       ptype, whence, pad, start, len, lockpid = getlock.unpack("s!s!i!L!L!i!")
 | |
| 
 | |
|       assert_equal(ptype, Fcntl::F_WRLCK)
 | |
|       assert_equal(whence, IO::SEEK_SET)
 | |
|       assert_equal(start, 12)
 | |
|       assert_equal(len, 34)
 | |
|       assert_equal(pid, lockpid)
 | |
| 
 | |
|       Process.kill :TERM, pid
 | |
|       Process.waitpid2(pid)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_fcntl_lock_freebsd
 | |
|     return if /freebsd/ !~ RUBY_PLATFORM # A binary form of struct flock depend on platform
 | |
| 
 | |
|     start = 12
 | |
|     len = 34
 | |
|     sysid = 0
 | |
|     Tempfile.create(self.class.name) do |f|
 | |
|       r, w = IO.pipe
 | |
|       pid = fork do
 | |
|         r.close
 | |
|         lock = [start, len, 0, Fcntl::F_WRLCK, IO::SEEK_SET, sysid].pack("qqis!s!i!")
 | |
|         f.fcntl Fcntl::F_SETLKW, lock
 | |
|         w.syswrite "."
 | |
|         sleep
 | |
|       end
 | |
|       w.close
 | |
|       assert_equal ".", r.read(1)
 | |
|       r.close
 | |
| 
 | |
|       getlock = [0, 0, 0, Fcntl::F_WRLCK, 0, 0].pack("qqis!s!i!")
 | |
|       f.fcntl Fcntl::F_GETLK, getlock
 | |
| 
 | |
|       start, len, lockpid, ptype, whence, sysid = getlock.unpack("qqis!s!i!")
 | |
| 
 | |
|       assert_equal(ptype, Fcntl::F_WRLCK)
 | |
|       assert_equal(whence, IO::SEEK_SET)
 | |
|       assert_equal(start, 12)
 | |
|       assert_equal(len, 34)
 | |
|       assert_equal(pid, lockpid)
 | |
| 
 | |
|       Process.kill :TERM, pid
 | |
|       Process.waitpid2(pid)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_fcntl_dupfd
 | |
|     Tempfile.create(self.class.name) do |f|
 | |
|       fd = f.fcntl(Fcntl::F_DUPFD, 63)
 | |
|       begin
 | |
|         assert_operator(fd, :>=, 63)
 | |
|       ensure
 | |
|         IO.for_fd(fd).close
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_cross_thread_close_fd
 | |
|     skip "cross thread close causes hung-up if pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
 | |
|     with_pipe do |r,w|
 | |
|       read_thread = Thread.new do
 | |
|         begin
 | |
|           r.read(1)
 | |
|         rescue => e
 | |
|           e
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       sleep(0.1) until read_thread.stop?
 | |
|       r.close
 | |
|       read_thread.join
 | |
|       assert_kind_of(IOError, read_thread.value)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_cross_thread_close_stdio
 | |
|     with_pipe do |r,w|
 | |
|       pid = fork do
 | |
|         $stdin.reopen(r)
 | |
|         r.close
 | |
|         read_thread = Thread.new do
 | |
|           begin
 | |
|             $stdin.read(1)
 | |
|           rescue => e
 | |
|             e
 | |
|           end
 | |
|         end
 | |
|         sleep(0.1) until read_thread.stop?
 | |
|         $stdin.close
 | |
|         read_thread.join
 | |
|         exit(IOError === read_thread.value)
 | |
|       end
 | |
|       assert Process.waitpid2(pid)[1].success?
 | |
|     end
 | |
|     rescue NotImplementedError
 | |
|   end
 | |
| 
 | |
|   def test_open_mode
 | |
|     feature4742 = "[ruby-core:36338]"
 | |
|     bug6055 = '[ruby-dev:45268]'
 | |
| 
 | |
|     mkcdtmpdir do
 | |
|       assert_not_nil(f = File.open('symbolic', 'w'))
 | |
|       f.close
 | |
|       assert_not_nil(f = File.open('numeric',  File::WRONLY|File::TRUNC|File::CREAT))
 | |
|       f.close
 | |
|       assert_not_nil(f = File.open('hash-symbolic', :mode => 'w'))
 | |
|       f.close
 | |
|       assert_not_nil(f = File.open('hash-numeric', :mode => File::WRONLY|File::TRUNC|File::CREAT), feature4742)
 | |
|       f.close
 | |
|       assert_nothing_raised(bug6055) {f = File.open('hash-symbolic', binmode: true)}
 | |
|       f.close
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_s_write
 | |
|     mkcdtmpdir do
 | |
|       path = "test_s_write"
 | |
|       File.write(path, "foo\nbar\nbaz")
 | |
|       assert_equal("foo\nbar\nbaz", File.read(path))
 | |
|       File.write(path, "FOO", 0)
 | |
|       assert_equal("FOO\nbar\nbaz", File.read(path))
 | |
|       File.write(path, "BAR")
 | |
|       assert_equal("BAR", File.read(path))
 | |
|       File.write(path, "\u{3042}", mode: "w", encoding: "EUC-JP")
 | |
|       assert_equal("\u{3042}".encode("EUC-JP"), File.read(path, encoding: "EUC-JP"))
 | |
|       File.delete path
 | |
|       assert_equal(6, File.write(path, 'string', 2))
 | |
|       File.delete path
 | |
|       assert_raise(Errno::EINVAL) { File.write('nonexisting','string', -2) }
 | |
|       assert_equal(6, File.write(path, 'string'))
 | |
|       assert_equal(3, File.write(path, 'sub', 1))
 | |
|       assert_equal("ssubng", File.read(path))
 | |
|       File.delete path
 | |
|       assert_equal(3, File.write(path, "foo", encoding: "UTF-8"))
 | |
|       File.delete path
 | |
|       assert_equal(3, File.write(path, "foo", 0, encoding: "UTF-8"))
 | |
|       assert_equal("foo", File.read(path))
 | |
|       assert_equal(1, File.write(path, "f", 1, encoding: "UTF-8"))
 | |
|       assert_equal("ffo", File.read(path))
 | |
|       File.delete path
 | |
|       assert_equal(1, File.write(path, "f", 1, encoding: "UTF-8"))
 | |
|       assert_equal("\00f", File.read(path))
 | |
|       assert_equal(1, File.write(path, "f", 0, encoding: "UTF-8"))
 | |
|       assert_equal("ff", File.read(path))
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_s_binwrite
 | |
|     mkcdtmpdir do
 | |
|       path = "test_s_binwrite"
 | |
|       File.binwrite(path, "foo\nbar\nbaz")
 | |
|       assert_equal("foo\nbar\nbaz", File.read(path))
 | |
|       File.binwrite(path, "FOO", 0)
 | |
|       assert_equal("FOO\nbar\nbaz", File.read(path))
 | |
|       File.binwrite(path, "BAR")
 | |
|       assert_equal("BAR", File.read(path))
 | |
|       File.binwrite(path, "\u{3042}")
 | |
|       assert_equal("\u{3042}".force_encoding("ASCII-8BIT"), File.binread(path))
 | |
|       File.delete path
 | |
|       assert_equal(6, File.binwrite(path, 'string', 2))
 | |
|       File.delete path
 | |
|       assert_equal(6, File.binwrite(path, 'string'))
 | |
|       assert_equal(3, File.binwrite(path, 'sub', 1))
 | |
|       assert_equal("ssubng", File.binread(path))
 | |
|       assert_equal(6, File.size(path))
 | |
|       assert_raise(Errno::EINVAL) { File.binwrite('nonexisting', 'string', -2) }
 | |
|       assert_nothing_raised(TypeError) { File.binwrite(path, "string", mode: "w", encoding: "EUC-JP") }
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_race_between_read
 | |
|     Tempfile.create("test") {|file|
 | |
|       begin
 | |
|         path = file.path
 | |
|         file.close
 | |
|         write_file = File.open(path, "wt")
 | |
|         read_file = File.open(path, "rt")
 | |
| 
 | |
|         threads = []
 | |
|         10.times do |i|
 | |
|           threads << Thread.new {write_file.print(i)}
 | |
|           threads << Thread.new {read_file.read}
 | |
|         end
 | |
|         threads.each {|t| t.join}
 | |
|         assert(true, "[ruby-core:37197]")
 | |
|       ensure
 | |
|         read_file.close
 | |
|         write_file.close
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_warn
 | |
|     assert_warning "warning\n" do
 | |
|       warn "warning"
 | |
|     end
 | |
| 
 | |
|     assert_warning '' do
 | |
|       warn
 | |
|     end
 | |
| 
 | |
|     assert_warning "[Feature #5029]\n[ruby-core:38070]\n" do
 | |
|       warn "[Feature #5029]", "[ruby-core:38070]"
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_cloexec
 | |
|     return unless defined? Fcntl::FD_CLOEXEC
 | |
|     open(__FILE__) {|f|
 | |
|       assert(f.close_on_exec?)
 | |
|       g = f.dup
 | |
|       begin
 | |
|         assert(g.close_on_exec?)
 | |
|         f.reopen(g)
 | |
|         assert(f.close_on_exec?)
 | |
|       ensure
 | |
|         g.close
 | |
|       end
 | |
|       g = IO.new(f.fcntl(Fcntl::F_DUPFD))
 | |
|       begin
 | |
|         assert(g.close_on_exec?)
 | |
|       ensure
 | |
|         g.close
 | |
|       end
 | |
|     }
 | |
|     IO.pipe {|r,w|
 | |
|       assert(r.close_on_exec?)
 | |
|       assert(w.close_on_exec?)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_ioctl_linux
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     # Alpha, mips, sparc and ppc have an another ioctl request number scheme.
 | |
|     # So, hardcoded 0x80045200 may fail.
 | |
|     return if /^i.?86|^x86_64/ !~ RUBY_PLATFORM
 | |
| 
 | |
|     assert_nothing_raised do
 | |
|       File.open('/dev/urandom'){|f1|
 | |
|         entropy_count = ""
 | |
|         # RNDGETENTCNT(0x80045200) mean "get entropy count".
 | |
|         f1.ioctl(0x80045200, entropy_count)
 | |
|       }
 | |
|     end
 | |
| 
 | |
|     buf = ''
 | |
|     assert_nothing_raised do
 | |
|       fionread = 0x541B
 | |
|       File.open(__FILE__){|f1|
 | |
|         f1.ioctl(fionread, buf)
 | |
|       }
 | |
|     end
 | |
|     assert_equal(File.size(__FILE__), buf.unpack('i!')[0])
 | |
|   end
 | |
| 
 | |
|   def test_ioctl_linux2
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     return if /^i.?86|^x86_64/ !~ RUBY_PLATFORM
 | |
| 
 | |
|     return unless system('tty', '-s') # stdin is not a terminal
 | |
|     File.open('/dev/tty') { |f|
 | |
|       tiocgwinsz=0x5413
 | |
|       winsize=""
 | |
|       assert_nothing_raised {
 | |
|         f.ioctl(tiocgwinsz, winsize)
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_setpos
 | |
|     mkcdtmpdir {
 | |
|       File.open("tmp.txt", "wb") {|f|
 | |
|         f.puts "a"
 | |
|         f.puts "bc"
 | |
|         f.puts "def"
 | |
|       }
 | |
|       pos1 = pos2 = pos3 = nil
 | |
|       File.open("tmp.txt", "rb") {|f|
 | |
|         assert_equal("a\n", f.gets)
 | |
|         pos1 = f.pos
 | |
|         assert_equal("bc\n", f.gets)
 | |
|         pos2 = f.pos
 | |
|         assert_equal("def\n", f.gets)
 | |
|         pos3 = f.pos
 | |
|         assert_equal(nil, f.gets)
 | |
|       }
 | |
|       File.open("tmp.txt", "rb") {|f|
 | |
|         f.pos = pos1
 | |
|         assert_equal("bc\n", f.gets)
 | |
|         assert_equal("def\n", f.gets)
 | |
|         assert_equal(nil, f.gets)
 | |
|       }
 | |
|       File.open("tmp.txt", "rb") {|f|
 | |
|         f.pos = pos2
 | |
|         assert_equal("def\n", f.gets)
 | |
|         assert_equal(nil, f.gets)
 | |
|       }
 | |
|       File.open("tmp.txt", "rb") {|f|
 | |
|         f.pos = pos3
 | |
|         assert_equal(nil, f.gets)
 | |
|       }
 | |
|       File.open("tmp.txt", "rb") {|f|
 | |
|         f.pos = File.size("tmp.txt")
 | |
|         s = "not empty string        "
 | |
|         assert_equal("", f.read(0,s))
 | |
|       }
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def test_std_fileno
 | |
|     assert_equal(0, STDIN.fileno)
 | |
|     assert_equal(1, STDOUT.fileno)
 | |
|     assert_equal(2, STDERR.fileno)
 | |
|     assert_equal(0, $stdin.fileno)
 | |
|     assert_equal(1, $stdout.fileno)
 | |
|     assert_equal(2, $stderr.fileno)
 | |
|   end
 | |
| 
 | |
|   def test_sysread_locktmp
 | |
|     bug6099 = '[ruby-dev:45297]'
 | |
|     buf = " " * 100
 | |
|     data = "a" * 100
 | |
|     with_pipe do |r,w|
 | |
|       th = Thread.new {r.sysread(100, buf)}
 | |
|       Thread.pass until th.stop?
 | |
|       buf.replace("")
 | |
|       assert_empty(buf, bug6099)
 | |
|       w.write(data)
 | |
|       Thread.pass while th.alive?
 | |
|       th.join
 | |
|     end
 | |
|     assert_equal(data, buf, bug6099)
 | |
|   end
 | |
| 
 | |
|   def test_readpartial_locktmp
 | |
|     skip "nonblocking mode is not supported for pipe on this platform" if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
 | |
|     bug6099 = '[ruby-dev:45297]'
 | |
|     buf = " " * 100
 | |
|     data = "a" * 100
 | |
|     with_pipe do |r,w|
 | |
|       r.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK)
 | |
|       th = Thread.new {r.readpartial(100, buf)}
 | |
|       Thread.pass until th.stop?
 | |
|       buf.replace("")
 | |
|       assert_empty(buf, bug6099)
 | |
|       w.write(data)
 | |
|       Thread.pass while th.alive?
 | |
|       th.join
 | |
|     end
 | |
|     assert_equal(data, buf, bug6099)
 | |
|   rescue RuntimeError # can't modify string; temporarily locked
 | |
|   end
 | |
| 
 | |
|   def test_advise_pipe
 | |
|     # we don't know if other platforms have a real posix_fadvise()
 | |
|     return if /linux/ !~ RUBY_PLATFORM
 | |
|     with_pipe do |r,w|
 | |
|       # Linux 2.6.15 and earlier returned EINVAL instead of ESPIPE
 | |
|       assert_raise(Errno::ESPIPE, Errno::EINVAL) { r.advise(:willneed) }
 | |
|       assert_raise(Errno::ESPIPE, Errno::EINVAL) { w.advise(:willneed) }
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def assert_buffer_not_raise_shared_string_error
 | |
|     bug6764 = '[ruby-core:46586]'
 | |
|     size = 28
 | |
|     data = [*"a".."z", *"A".."Z"].shuffle.join("")
 | |
|     t = Tempfile.new("test_io")
 | |
|     t.write(data)
 | |
|     t.close
 | |
|     w = Tempfile.new("test_io")
 | |
|     assert_nothing_raised(RuntimeError, bug6764) do
 | |
|       File.open(t.path, "r") do |r|
 | |
|         buf = ''
 | |
|         while yield(r, size, buf)
 | |
|           w << buf
 | |
|         end
 | |
|       end
 | |
|     end
 | |
|     w.close
 | |
|     assert_equal(data, w.open.read, bug6764)
 | |
|   ensure
 | |
|     t.close!
 | |
|     w.close!
 | |
|   end
 | |
| 
 | |
|   def test_read_buffer_not_raise_shared_string_error
 | |
|     assert_buffer_not_raise_shared_string_error do |r, size, buf|
 | |
|       r.read(size, buf)
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_sysread_buffer_not_raise_shared_string_error
 | |
|     assert_buffer_not_raise_shared_string_error do |r, size, buf|
 | |
|       begin
 | |
|         r.sysread(size, buf)
 | |
|       rescue EOFError
 | |
|         nil
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_readpartial_buffer_not_raise_shared_string_error
 | |
|     assert_buffer_not_raise_shared_string_error do |r, size, buf|
 | |
|       begin
 | |
|         r.readpartial(size, buf)
 | |
|       rescue EOFError
 | |
|         nil
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def test_puts_recursive_ary
 | |
|     bug5986 = '[ruby-core:42444]'
 | |
|     c = Class.new {
 | |
|       def to_ary
 | |
|         [self]
 | |
|       end
 | |
|     }
 | |
|     s = StringIO.new
 | |
|     s.puts(c.new)
 | |
|     assert_equal("[...]\n", s.string, bug5986)
 | |
|   end
 | |
| 
 | |
|   def test_io_select_with_many_files
 | |
|     bug8080 = '[ruby-core:53349]'
 | |
| 
 | |
|     assert_normal_exit %q{
 | |
|       require "tempfile"
 | |
| 
 | |
|       # try to raise RLIM_NOFILE to >FD_SETSIZE
 | |
|       # Unfortunately, ruby export FD_SETSIZE. then we assume it's 1024.
 | |
|       fd_setsize = 1024
 | |
| 
 | |
|       begin
 | |
|         Process.setrlimit(Process::RLIMIT_NOFILE, fd_setsize+10)
 | |
|       rescue =>e
 | |
|         # Process::RLIMIT_NOFILE couldn't be raised. skip the test
 | |
|         exit 0
 | |
|       end
 | |
| 
 | |
|       tempfiles = []
 | |
|       (0..fd_setsize+1).map {|i|
 | |
|         tempfiles << Tempfile.open("test_io_select_with_many_files")
 | |
|       }
 | |
| 
 | |
|       IO.select(tempfiles)
 | |
|   }, bug8080
 | |
|   end
 | |
| 
 | |
|   def test_read_32bit_boundary
 | |
|     bug8431 = '[ruby-core:55098] [Bug #8431]'
 | |
|     make_tempfile {|t|
 | |
|       assert_separately(["-", bug8431, t.path], <<-"end;")
 | |
|         msg = ARGV.shift
 | |
|         f = open(ARGV[0], "rb")
 | |
|         f.seek(0xffff_ffff)
 | |
|         assert_nil(f.read(1), msg)
 | |
|       end;
 | |
|     }
 | |
|   end if /mswin|mingw/ =~ RUBY_PLATFORM
 | |
| 
 | |
|   def test_write_32bit_boundary
 | |
|     bug8431 = '[ruby-core:55098] [Bug #8431]'
 | |
|     make_tempfile {|t|
 | |
|       assert_separately(["-", bug8431, t.path], <<-"end;", timeout: 30)
 | |
|         msg = ARGV.shift
 | |
|         f = open(ARGV[0], "wb")
 | |
|         f.seek(0xffff_ffff)
 | |
|         begin
 | |
|           # this will consume very long time or fail by ENOSPC on a
 | |
|           # filesystem which sparse file is not supported
 | |
|           f.write('1')
 | |
|         rescue SystemCallError
 | |
|         else
 | |
|           assert_equal(0x1_0000_0000, f.tell, msg)
 | |
|         end
 | |
|       end;
 | |
|     }
 | |
|   end if /mswin|mingw/ =~ RUBY_PLATFORM
 | |
| end
 |