Skip to content

Commit 9fef30b

Browse files
committed
Add specs for IO#wait
1 parent 272eb88 commit 9fef30b

File tree

4 files changed

+163
-1
lines changed

4 files changed

+163
-1
lines changed

lib/truffle/io/wait.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def wait(*args)
6363
when :w, :write, :writable then IO::WRITABLE
6464
when :rw, :read_write, :readable_writable then IO::READABLE | IO::WRITABLE
6565
else
66-
raise ArgumentError, "unsupported mode: #{mode.inspect}"
66+
raise ArgumentError, "unsupported mode: #{arg}"
6767
end
6868

6969
elsif timeout == :undef
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module IOWaitSpec
2+
def self.exhaust_write_buffer(io)
3+
written = 0
4+
buf = " " * 4096
5+
6+
begin
7+
written += io.write_nonblock(buf)
8+
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
9+
return written
10+
end while true
11+
end
12+
end
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
require_relative '../../spec_helper'
2+
require_relative 'fixtures/classes'
3+
4+
ruby_version_is ''...'3.2' do
5+
require 'io/wait'
6+
end
7+
8+
describe "IO#wait" do
9+
before :each do
10+
@io = File.new(__FILE__ )
11+
12+
if /mswin|mingw/ =~ RUBY_PLATFORM
13+
@r, @w = Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM, 0)
14+
else
15+
@r, @w = IO.pipe
16+
end
17+
end
18+
19+
after :each do
20+
@io.close unless @io.closed?
21+
22+
@r.close unless @r.closed?
23+
@w.close unless @w.closed?
24+
end
25+
26+
ruby_version_is "3.0" do
27+
context "[events, timeout] passed" do
28+
ruby_version_is "3.0"..."3.2" do
29+
it "returns self when the READABLE event is ready during the timeout" do
30+
@w.write('data to read')
31+
@r.wait(IO::READABLE, 2).should.equal?(@r)
32+
end
33+
34+
it "returns self when the WRITABLE event is ready during the timeout" do
35+
@w.wait(IO::WRITABLE, 0).should.equal?(@w)
36+
end
37+
end
38+
39+
ruby_version_is "3.2" do
40+
it "returns events mask when the READABLE event is ready during the timeout" do
41+
@w.write('data to read')
42+
@r.wait(IO::READABLE, 2).should == IO::READABLE
43+
end
44+
45+
it "returns events mask when the WRITABLE event is ready during the timeout" do
46+
@w.wait(IO::WRITABLE, 0).should == IO::WRITABLE
47+
end
48+
end
49+
50+
ruby_version_is "3.0" do
51+
it "waits for the READABLE event to be ready" do
52+
queue = Queue.new
53+
thread = Thread.new { queue.pop; sleep 1; @w.write('data to read') };
54+
55+
queue.push('signal');
56+
@r.wait(IO::READABLE, 2).should_not == nil
57+
58+
thread.join
59+
end
60+
61+
it "waits for the WRITABLE event to be ready" do
62+
written_bytes = IOWaitSpec.exhaust_write_buffer(@w)
63+
64+
queue = Queue.new
65+
thread = Thread.new { queue.pop; sleep 1; @r.read(written_bytes) };
66+
67+
queue.push('signal');
68+
@w.wait(IO::WRITABLE, 2).should_not == nil
69+
70+
thread.join
71+
end
72+
73+
it "returns nil when the READABLE event is not ready during the timeout" do
74+
@w.wait(IO::READABLE, 0).should == nil
75+
end
76+
77+
it "returns nil when the WRITABLE event is not ready during the timeout" do
78+
IOWaitSpec.exhaust_write_buffer(@w)
79+
@w.wait(IO::WRITABLE, 0).should == nil
80+
end
81+
82+
it "raises IOError when io is closed (closed stream (IOError))" do
83+
@io.close
84+
-> { @io.wait(IO::READABLE, 0) }.should raise_error(IOError, "closed stream")
85+
end
86+
87+
ruby_version_is "3.2" do
88+
it "raises ArgumentError when events is not positive" do
89+
-> { @w.wait(0, 0) }.should raise_error(ArgumentError, "Events must be positive integer!")
90+
-> { @w.wait(-1, 0) }.should raise_error(ArgumentError, "Events must be positive integer!")
91+
end
92+
end
93+
end
94+
end
95+
end
96+
97+
context "[timeout, mode] passed" do
98+
it "accepts :r, :read, :readable mode to check READABLE event" do
99+
@io.wait(0, :r).should == @io
100+
@io.wait(0, :read).should == @io
101+
@io.wait(0, :readable).should == @io
102+
end
103+
104+
it "accepts :w, :write, :writable mode to check WRITABLE event" do
105+
@io.wait(0, :w).should == @io
106+
@io.wait(0, :write).should == @io
107+
@io.wait(0, :writable).should == @io
108+
end
109+
110+
it "accepts :rw, :read_write, :readable_writable mode to check READABLE and WRITABLE events" do
111+
@io.wait(0, :rw).should == @io
112+
@io.wait(0, :read_write).should == @io
113+
@io.wait(0, :readable_writable).should == @io
114+
end
115+
116+
it "accepts a list of modes" do
117+
@io.wait(0, :r, :w, :rw).should == @io
118+
end
119+
120+
# It works at least since 2.7 but by some reason may fail on 3.1
121+
ruby_version_is "3.2" do
122+
it "accepts timeout and mode in any order" do
123+
@io.wait(0, :r).should == @io
124+
@io.wait(:r, 0).should == @io
125+
@io.wait(:r, 0, :w).should == @io
126+
end
127+
end
128+
129+
it "raises ArgumentError when passed wrong Symbol value as mode argument" do
130+
-> { @io.wait(0, :wrong) }.should raise_error(ArgumentError, "unsupported mode: wrong")
131+
end
132+
133+
# It works since 3.0 but by some reason may fail on 3.1
134+
ruby_version_is "3.2" do
135+
it "raises ArgumentError when several Integer arguments passed" do
136+
-> { @w.wait(0, 10, :r) }.should raise_error(ArgumentError, "timeout given more than once")
137+
end
138+
end
139+
140+
ruby_version_is "3.2" do
141+
it "raises IOError when io is closed (closed stream (IOError))" do
142+
@io.close
143+
-> { @io.wait(0, :r) }.should raise_error(IOError, "closed stream")
144+
end
145+
end
146+
end
147+
end
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fails:IO#wait [events, timeout] passed returns self when the READABLE event is ready during the timeout
2+
fails:IO#wait [events, timeout] passed returns self when the WRITABLE event is ready during the timeout
3+
fails:IO#wait [events, timeout] passed waits for the READABLE event to be ready

0 commit comments

Comments
 (0)