* io.c (io_read_nonblock): support non-blocking reads without raising

exceptions. As in: `io.read_nonblock(size, exception: false)`
  [ruby-core:38666] [Feature #5138]
* ext/openssl/ossl_ssl.c (ossl_ssl_read_internal): ditto
* ext/stringio/stringio.c (strio_sysread): ditto
* io.c (rb_io_write_nonblock): support non-blocking writes without
  raising an exception.
* ext/openssl/ossl_ssl.c (ossl_ssl_write_internal): ditto
* test/openssl/test_pair.rb (class OpenSSL): tests
* test/ruby/test_io.rb (class TestIO): ditto
* test/socket/test_nonblock.rb (class TestSocketNonblock): ditto
* test/stringio/test_stringio.rb (class TestStringIO): ditto

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42695 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
tenderlove 2013-08-26 22:41:44 +00:00
Родитель eadad2c900
Коммит 988ca60565
9 изменённых файлов: 330 добавлений и 55 удалений

Просмотреть файл

@ -1,3 +1,18 @@
Tue Aug 27 07:35:05 2013 Aaron Patterson <aaron@tenderlovemaking.com>
* io.c (io_read_nonblock): support non-blocking reads without raising
exceptions. As in: `io.read_nonblock(size, exception: false)`
[ruby-core:38666] [Feature #5138]
* ext/openssl/ossl_ssl.c (ossl_ssl_read_internal): ditto
* ext/stringio/stringio.c (strio_sysread): ditto
* io.c (rb_io_write_nonblock): support non-blocking writes without
raising an exception.
* ext/openssl/ossl_ssl.c (ossl_ssl_write_internal): ditto
* test/openssl/test_pair.rb (class OpenSSL): tests
* test/ruby/test_io.rb (class TestIO): ditto
* test/socket/test_nonblock.rb (class TestSocketNonblock): ditto
* test/stringio/test_stringio.rb (class TestStringIO): ditto
Tue Aug 27 05:24:34 2013 Eric Hodel <drbrain@segment7.net>
* lib/rubygems: Import RubyGems 2.1.0 Release Candidate

Просмотреть файл

@ -161,7 +161,7 @@ module OpenSSL::Buffering
# when the peer requests a new TLS/SSL handshake. See openssl the FAQ for
# more details. http://www.openssl.org/support/faq.html
def read_nonblock(maxlen, buf=nil)
def read_nonblock(maxlen, buf=nil, exception: true)
if maxlen == 0
if buf
buf.clear
@ -171,7 +171,7 @@ module OpenSSL::Buffering
end
end
if @rbuffer.empty?
return sysread_nonblock(maxlen, buf)
return sysread_nonblock(maxlen, buf, exception: exception)
end
ret = consume_rbuff(maxlen)
if buf
@ -370,9 +370,9 @@ module OpenSSL::Buffering
# is when the peer requests a new TLS/SSL handshake. See the openssl FAQ
# for more details. http://www.openssl.org/support/faq.html
def write_nonblock(s)
def write_nonblock(s, exception: true)
flush
syswrite_nonblock(s)
syswrite_nonblock(s, exception: exception)
end
##

Просмотреть файл

@ -103,6 +103,8 @@ static const char *ossl_ssl_attrs[] = {
ID ID_callback_state;
static VALUE sym_exception;
/*
* SSLContext class
*/
@ -1373,10 +1375,16 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
{
SSL *ssl;
int ilen, nread = 0;
int no_exception = 0;
VALUE len, str;
rb_io_t *fptr;
VALUE opts = Qnil;
rb_scan_args(argc, argv, "11:", &len, &str, &opts);
if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
no_exception = 1;
rb_scan_args(argc, argv, "11", &len, &str);
ilen = NUM2INT(len);
if(NIL_P(str)) str = rb_str_new(0, ilen);
else{
@ -1397,17 +1405,23 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_ZERO_RETURN:
if (no_exception) { return Qnil; }
rb_eof_error();
case SSL_ERROR_WANT_WRITE:
if (no_exception) { return ID2SYM(rb_intern("wait_writable")); }
write_would_block(nonblock);
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
if (no_exception) { return ID2SYM(rb_intern("wait_readable")); }
read_would_block(nonblock);
rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_SYSCALL:
if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
if(ERR_peek_error() == 0 && nread == 0) {
if (no_exception) { return Qnil; }
rb_eof_error();
}
rb_sys_fail(0);
default:
ossl_raise(eSSLError, "SSL_read");
@ -1445,9 +1459,11 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self)
* call-seq:
* ssl.sysread_nonblock(length) => string
* ssl.sysread_nonblock(length, buffer) => buffer
* ssl.sysread_nonblock(length[, buffer [, opts]) => buffer
*
* A non-blocking version of #sysread. Raises an SSLError if reading would
* block.
* block. If "exception: false" is passed, this method returns a symbol of
* :wait_writable, :wait_writable, or nil, rather than raising an exception.
*
* Reads +length+ bytes from the SSL connection. If a pre-allocated +buffer+
* is provided the data will be written into it.
@ -1459,7 +1475,7 @@ ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self)
}
static VALUE
ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock)
ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock, int no_exception)
{
SSL *ssl;
int nwrite = 0;
@ -1476,10 +1492,12 @@ ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock)
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_WANT_WRITE:
if (no_exception) { return ID2SYM(rb_intern("wait_writable")); }
write_would_block(nonblock);
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
if (no_exception) { return ID2SYM(rb_intern("wait_readable")); }
read_would_block(nonblock);
rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
@ -1509,7 +1527,7 @@ ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock)
static VALUE
ossl_ssl_write(VALUE self, VALUE str)
{
return ossl_ssl_write_internal(self, str, 0);
return ossl_ssl_write_internal(self, str, 0, 0);
}
/*
@ -1520,9 +1538,18 @@ ossl_ssl_write(VALUE self, VALUE str)
* SSLError if writing would block.
*/
static VALUE
ossl_ssl_write_nonblock(VALUE self, VALUE str)
ossl_ssl_write_nonblock(int argc, VALUE *argv, VALUE self)
{
return ossl_ssl_write_internal(self, str, 1);
VALUE str;
VALUE opts = Qnil;
int no_exception = 0;
rb_scan_args(argc, argv, "1:", &str, &opts);
if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
no_exception = 1;
return ossl_ssl_write_internal(self, str, 1, no_exception);
}
/*
@ -2168,7 +2195,7 @@ Init_ossl_ssl()
rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1);
rb_define_private_method(cSSLSocket, "sysread_nonblock", ossl_ssl_read_nonblock, -1);
rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1);
rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, 1);
rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, -1);
rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0);
rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0);
rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0);
@ -2239,4 +2266,6 @@ Init_ossl_ssl()
ossl_ssl_def_const(OP_PKCS1_CHECK_2);
ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG);
ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
sym_exception = ID2SYM(rb_intern("exception"));
}

Просмотреть файл

@ -119,6 +119,8 @@ typedef char strio_flags_check[(STRIO_READABLE/FMODE_READABLE == STRIO_WRITABLE/
#define READABLE(strio) STRIO_MODE_SET_P(strio, READABLE)
#define WRITABLE(strio) STRIO_MODE_SET_P(strio, WRITABLE)
static VALUE sym_exception;
static struct StringIO*
readable(VALUE strio)
{
@ -1327,7 +1329,6 @@ strio_read(int argc, VALUE *argv, VALUE self)
* call-seq:
* strio.sysread(integer[, outbuf]) -> string
* strio.readpartial(integer[, outbuf]) -> string
* strio.read_nonblock(integer[, outbuf]) -> string
*
* Similar to #read, but raises +EOFError+ at end of string instead of
* returning +nil+, as well as IO#sysread does.
@ -1342,8 +1343,50 @@ strio_sysread(int argc, VALUE *argv, VALUE self)
return val;
}
/*
* call-seq:
* strio.read_nonblock(integer[, outbuf [, opts]]) -> string
*
* Similar to #read, but raises +EOFError+ at end of string unless the
* +exception: false+ option is passed in.
*/
static VALUE
strio_read_nonblock(int argc, VALUE *argv, VALUE self)
{
VALUE opts = Qnil;
int no_exception = 0;
rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
if (!NIL_P(opts)) {
argc--;
if (Qfalse == rb_hash_aref(opts, sym_exception))
no_exception = 1;
}
VALUE val = strio_read(argc, argv, self);
if (NIL_P(val)) {
if (no_exception)
return Qnil;
else
rb_eof_error();
}
return val;
}
#define strio_syswrite rb_io_write
static VALUE
strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
{
VALUE str;
rb_scan_args(argc, argv, "10:", &str, NULL);
return strio_syswrite(self, str);
}
#define strio_isatty strio_false
#define strio_pid strio_nil
@ -1542,7 +1585,7 @@ Init_stringio()
rb_define_method(mReadable, "readline", strio_readline, -1);
rb_define_method(mReadable, "sysread", strio_sysread, -1);
rb_define_method(mReadable, "readpartial", strio_sysread, -1);
rb_define_method(mReadable, "read_nonblock", strio_sysread, -1);
rb_define_method(mReadable, "read_nonblock", strio_read_nonblock, -1);
rb_include_module(StringIO, mReadable);
}
{
@ -1552,7 +1595,9 @@ Init_stringio()
rb_define_method(mWritable, "printf", strio_printf, -1);
rb_define_method(mWritable, "puts", strio_puts, -1);
rb_define_method(mWritable, "syswrite", strio_syswrite, 1);
rb_define_method(mWritable, "write_nonblock", strio_syswrite, 1);
rb_define_method(mWritable, "write_nonblock", strio_syswrite_nonblock, -1);
rb_include_module(StringIO, mWritable);
}
sym_exception = ID2SYM(rb_intern("exception"));
}

102
io.c
Просмотреть файл

@ -159,7 +159,7 @@ static VALUE argf;
static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding;
static VALUE sym_mode, sym_perm, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
static VALUE sym_textmode, sym_binmode, sym_autoclose;
static VALUE sym_textmode, sym_binmode, sym_autoclose, sym_exception;
static VALUE sym_SET, sym_CUR, sym_END;
#ifdef SEEK_DATA
static VALUE sym_DATA;
@ -2413,14 +2413,14 @@ read_internal_call(VALUE arg)
}
static VALUE
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock, int no_exception)
{
rb_io_t *fptr;
VALUE length, str;
long n, len;
struct read_internal_arg arg;
rb_scan_args(argc, argv, "11", &length, &str);
rb_scan_args(argc, argv, "11:", &length, &str, NULL);
if ((len = NUM2LONG(length)) < 0) {
rb_raise(rb_eArgError, "negative length %ld given", len);
@ -2452,8 +2452,12 @@ io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
if (n < 0) {
if (!nonblock && rb_io_wait_readable(fptr->fd))
goto again;
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
if (no_exception)
return ID2SYM(rb_intern("wait_readable"));
else
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "read would block");
}
rb_sys_fail_path(fptr->pathv);
}
}
@ -2529,7 +2533,7 @@ io_readpartial(int argc, VALUE *argv, VALUE io)
{
VALUE ret;
ret = io_getpartial(argc, argv, io, 0);
ret = io_getpartial(argc, argv, io, 0, 0);
if (NIL_P(ret))
rb_eof_error();
return ret;
@ -2590,16 +2594,62 @@ static VALUE
io_read_nonblock(int argc, VALUE *argv, VALUE io)
{
VALUE ret;
VALUE opts = Qnil;
int no_exception = 0;
ret = io_getpartial(argc, argv, io, 1);
if (NIL_P(ret))
rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
no_exception = 1;
ret = io_getpartial(argc, argv, io, 1, no_exception);
if (NIL_P(ret)) {
if (no_exception)
return Qnil;
else
rb_eof_error();
}
return ret;
}
static VALUE
io_write_nonblock(VALUE io, VALUE str, int no_exception)
{
rb_io_t *fptr;
long n;
if (!RB_TYPE_P(str, T_STRING))
str = rb_obj_as_string(str);
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
if (io_fflush(fptr) < 0)
rb_sys_fail(0);
rb_io_set_nonblock(fptr);
n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
if (n == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
if (no_exception) {
return ID2SYM(rb_intern("wait_writable"));
} else {
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
}
}
rb_sys_fail_path(fptr->pathv);
}
return LONG2FIX(n);
}
/*
* call-seq:
* ios.write_nonblock(string) -> integer
* ios.write_nonblock(string [, options]) -> integer
*
* Writes the given string to <em>ios</em> using
* the write(2) system call after O_NONBLOCK is set for
@ -2648,34 +2698,25 @@ io_read_nonblock(int argc, VALUE *argv, VALUE io)
* according to the kind of the IO object.
* In such cases, write_nonblock raises <code>Errno::EBADF</code>.
*
* By specifying `exception: false`, the options hash allows you to indicate
* that write_nonblock should not raise an IO::WaitWritable exception, but
* return the symbol :wait_writable instead.
*
*/
static VALUE
rb_io_write_nonblock(VALUE io, VALUE str)
rb_io_write_nonblock(int argc, VALUE *argv, VALUE io)
{
rb_io_t *fptr;
long n;
VALUE str;
VALUE opts = Qnil;
int no_exceptions = 0;
if (!RB_TYPE_P(str, T_STRING))
str = rb_obj_as_string(str);
rb_scan_args(argc, argv, "10:", &str, &opts);
io = GetWriteIO(io);
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
no_exceptions = 1;
if (io_fflush(fptr) < 0)
rb_sys_fail(0);
rb_io_set_nonblock(fptr);
n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
if (n == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN)
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
rb_sys_fail_path(fptr->pathv);
}
return LONG2FIX(n);
return io_write_nonblock(io, str, no_exceptions);
}
/*
@ -10809,7 +10850,7 @@ argf_getpartial(int argc, VALUE *argv, VALUE argf, int nonblock)
RUBY_METHOD_FUNC(0), Qnil, rb_eEOFError, (VALUE)0);
}
else {
tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock);
tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock, 0);
}
if (NIL_P(tmp)) {
if (ARGF.next_p == -1) {
@ -11851,7 +11892,7 @@ Init_IO(void)
rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
rb_define_method(rb_cIO, "read_nonblock", io_read_nonblock, -1);
rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, 1);
rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, -1);
rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
rb_define_method(rb_cIO, "read", io_read, -1);
rb_define_method(rb_cIO, "write", io_write_m, 1);
@ -12056,4 +12097,5 @@ Init_IO(void)
#ifdef SEEK_HOLE
sym_HOLE = ID2SYM(rb_intern("HOLE"));
#endif
sym_exception = ID2SYM(rb_intern("exception"));
}

Просмотреть файл

@ -156,19 +156,46 @@ class OpenSSL::TestPair < Test::Unit::TestCase
ret = nil
assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10) }
assert_equal("def\n", ret)
s1.close
assert_raise(EOFError) { s2.read_nonblock(10) }
}
end
def test_read_nonblock_no_exception
ssl_pair {|s1, s2|
assert_equal :wait_readable, s2.read_nonblock(10, exception: false)
s1.write "abc\ndef\n"
IO.select([s2])
assert_equal("ab", s2.read_nonblock(2, exception: false))
assert_equal("c\n", s2.gets)
ret = nil
assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10, exception: false) }
assert_equal("def\n", ret)
s1.close
assert_equal(nil, s2.read_nonblock(10, exception: false))
}
end
def write_nonblock(socket, meth, str)
ret = socket.send(meth, str)
ret.is_a?(Symbol) ? 0 : ret
end
def write_nonblock_no_ex(socket, str)
ret = socket.write_nonblock str, exception: false
ret.is_a?(Symbol) ? 0 : ret
end
def test_write_nonblock
ssl_pair {|s1, s2|
n = 0
begin
n += s1.write_nonblock("a" * 100000)
n += s1.write_nonblock("b" * 100000)
n += s1.write_nonblock("c" * 100000)
n += s1.write_nonblock("d" * 100000)
n += s1.write_nonblock("e" * 100000)
n += s1.write_nonblock("f" * 100000)
n += write_nonblock s1, :write_nonblock, "a" * 100000
n += write_nonblock s1, :write_nonblock, "b" * 100000
n += write_nonblock s1, :write_nonblock, "c" * 100000
n += write_nonblock s1, :write_nonblock, "d" * 100000
n += write_nonblock s1, :write_nonblock, "e" * 100000
n += write_nonblock s1, :write_nonblock, "f" * 100000
rescue IO::WaitWritable
end
s1.close
@ -176,6 +203,20 @@ class OpenSSL::TestPair < Test::Unit::TestCase
}
end
def test_write_nonblock_no_exceptions
ssl_pair {|s1, s2|
n = 0
n += write_nonblock_no_ex s1, "a" * 100000
n += write_nonblock_no_ex s1, "b" * 100000
n += write_nonblock_no_ex s1, "c" * 100000
n += write_nonblock_no_ex s1, "d" * 100000
n += write_nonblock_no_ex s1, "e" * 100000
n += write_nonblock_no_ex s1, "f" * 100000
s1.close
assert_equal(n, s2.read.length)
}
end
def test_write_nonblock_with_buffered_data
ssl_pair {|s1, s2|
s1.write "foo"
@ -186,6 +227,16 @@ class OpenSSL::TestPair < Test::Unit::TestCase
}
end
def test_write_nonblock_with_buffered_data_no_exceptions
ssl_pair {|s1, s2|
s1.write "foo"
s1.write_nonblock("bar", exception: false)
s1.write "baz"
s1.close
assert_equal("foobarbaz", s2.read)
}
end
def test_connect_accept_nonblock
host = "127.0.0.1"
port = 0

Просмотреть файл

@ -1205,6 +1205,16 @@ class TestIO < Test::Unit::TestCase
}
end
def test_write_nonblock_simple_no_exceptions
skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
pipe(proc do |w|
w.write_nonblock('1', exception: false)
w.close
end, proc do |r|
assert_equal("1", r.read)
end)
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
@ -1215,6 +1225,41 @@ class TestIO < Test::Unit::TestCase
assert_kind_of(IO::WaitReadable, $!)
end
}
with_pipe {|r, w|
begin
r.read_nonblock 4096, ""
rescue Errno::EWOULDBLOCK
assert_kind_of(IO::WaitReadable, $!)
end
}
end
def test_read_nonblock_no_exceptions
return if !have_nonblock?
skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
assert_equal :wait_readable, r.read_nonblock(4096, exception: false)
w.puts "HI!"
assert_equal "HI!\n", r.read_nonblock(4096, exception: false)
w.close
assert_equal nil, r.read_nonblock(4096, exception: false)
}
end
def test_read_nonblock_with_buffer_no_exceptions
return if !have_nonblock?
skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
assert_equal :wait_readable, r.read_nonblock(4096, "", exception: false)
w.puts "HI!"
buf = "buf"
value = r.read_nonblock(4096, buf, exception: false)
assert_equal value, "HI!\n"
assert buf.equal?(value)
w.close
assert_equal nil, r.read_nonblock(4096, "", exception: false)
}
end
def test_write_nonblock_error
@ -1231,6 +1276,20 @@ class TestIO < Test::Unit::TestCase
}
end
def test_write_nonblock_no_exceptions
return if !have_nonblock?
skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
with_pipe {|r, w|
loop {
ret = w.write_nonblock("a"*100000, exception: false)
if ret.is_a?(Symbol)
assert_equal :wait_writable, ret
break
end
}
}
end
def test_gets
pipe(proc do |w|
w.write "foobarbaz"

Просмотреть файл

@ -190,6 +190,20 @@ class TestSocketNonblock < Test::Unit::TestCase
s.close if s
end
def test_read_nonblock_no_exception
c, s = tcp_pair
assert_equal :wait_readable, c.read_nonblock(100, exception: false)
assert_equal :wait_readable, s.read_nonblock(100, exception: false)
c.write("abc")
IO.select [s]
assert_equal("a", s.read_nonblock(1, exception: false))
assert_equal("bc", s.read_nonblock(100, exception: false))
assert_equal :wait_readable, s.read_nonblock(100, exception: false)
ensure
c.close if c
s.close if s
end
=begin
def test_write_nonblock
c, s = tcp_pair

Просмотреть файл

@ -89,6 +89,14 @@ class TestStringIO < Test::Unit::TestCase
f.close unless f.closed?
end
def test_write_nonblock_no_exceptions
s = ""
f = StringIO.new(s, "w")
f.write_nonblock("foo", exception: false)
f.close
assert_equal("foo", s)
end
def test_write_nonblock
s = ""
f = StringIO.new(s, "w")
@ -437,7 +445,7 @@ class TestStringIO < Test::Unit::TestCase
f = StringIO.new("\u3042\u3044")
assert_raise(ArgumentError) { f.readpartial(-1) }
assert_raise(ArgumentError) { f.readpartial(1, 2, 3) }
assert_equal("\u3042\u3044", f.readpartial)
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.readpartial(100))
f.rewind
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.readpartial(f.size))
f.rewind
@ -450,7 +458,19 @@ class TestStringIO < Test::Unit::TestCase
f = StringIO.new("\u3042\u3044")
assert_raise(ArgumentError) { f.read_nonblock(-1) }
assert_raise(ArgumentError) { f.read_nonblock(1, 2, 3) }
assert_equal("\u3042\u3044", f.read_nonblock)
assert_equal("\u3042\u3044".force_encoding("BINARY"), f.read_nonblock(100))
assert_raise(EOFError) { f.read_nonblock(10) }
f.rewind
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.read_nonblock(f.size))
end
def test_read_nonblock_no_exceptions
f = StringIO.new("\u3042\u3044")
assert_raise(ArgumentError) { f.read_nonblock(-1, exception: false) }
assert_raise(ArgumentError) { f.read_nonblock(1, 2, 3, exception: false) }
assert_raise(ArgumentError) { f.read_nonblock }
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.read_nonblock(100, exception: false))
assert_equal(nil, f.read_nonblock(10, exception: false))
f.rewind
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.read_nonblock(f.size))
f.rewind