1# -*- coding: us-ascii -*-
2# frozen_string_literal: false
3require 'test/unit'
4require 'timeout'
5require 'socket'
6begin
7  require 'io/wait'
8rescue LoadError
9end
10
11class TestIOWait < Test::Unit::TestCase
12
13  def setup
14    if /mswin|mingw/ =~ RUBY_PLATFORM
15      @r, @w = Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM, 0)
16    else
17      @r, @w = IO.pipe
18    end
19  end
20
21  def teardown
22    @r.close unless @r.closed?
23    @w.close unless @w.closed?
24  end
25
26  def test_nread
27    assert_equal 0, @r.nread
28    @w.syswrite "."
29    sleep 0.1
30    assert_equal 1, @r.nread
31  end
32
33  def test_nread_buffered
34    @w.syswrite ".\n!"
35    assert_equal ".\n", @r.gets
36    assert_equal 1, @r.nread
37  end
38
39  def test_ready?
40    assert_not_predicate @r, :ready?, "shouldn't ready, but ready"
41    @w.syswrite "."
42    sleep 0.1
43    assert_predicate @r, :ready?, "should ready, but not"
44  end
45
46  def test_buffered_ready?
47    @w.syswrite ".\n!"
48    assert_equal ".\n", @r.gets
49    assert_predicate @r, :ready?
50  end
51
52  def test_wait
53    assert_nil @r.wait(0)
54    @w.syswrite "."
55    sleep 0.1
56    assert_equal @r, @r.wait(0)
57  end
58
59  def test_wait_buffered
60    @w.syswrite ".\n!"
61    assert_equal ".\n", @r.gets
62    assert_equal true, @r.wait(0)
63  end
64
65  def test_wait_forever
66    th = Thread.new { sleep 0.01; @w.syswrite "." }
67    assert_equal @r, @r.wait
68  ensure
69    th.join
70  end
71
72  def test_wait_eof
73    th = Thread.new { sleep 0.01; @w.close }
74    ret = nil
75    assert_nothing_raised(Timeout::Error) do
76      Timeout.timeout(0.1) { ret = @r.wait }
77    end
78    assert_equal @r, ret
79  ensure
80    th.join
81  end
82
83  def test_wait_readable
84    assert_nil @r.wait_readable(0)
85    @w.syswrite "."
86    sleep 0.1
87    assert_equal @r, @r.wait_readable(0)
88  end
89
90  def test_wait_readable_buffered
91    @w.syswrite ".\n!"
92    assert_equal ".\n", @r.gets
93    assert_equal true, @r.wait_readable(0)
94  end
95
96  def test_wait_readable_forever
97    th = Thread.new { sleep 0.01; @w.syswrite "." }
98    assert_equal @r, @r.wait_readable
99  ensure
100    th.join
101  end
102
103  def test_wait_readable_eof
104    th = Thread.new { sleep 0.01; @w.close }
105    ret = nil
106    assert_nothing_raised(Timeout::Error) do
107      Timeout.timeout(0.1) { ret = @r.wait_readable }
108    end
109    assert_equal @r, ret
110  ensure
111    th.join
112  end
113
114  def test_wait_writable
115    assert_equal @w, @w.wait_writable
116  end
117
118  def test_wait_writable_timeout
119    assert_equal @w, @w.wait_writable(0.01)
120    written = fill_pipe
121    assert_nil @w.wait_writable(0.01)
122    @r.read(written)
123    assert_equal @w, @w.wait_writable(0.01)
124  end
125
126  def test_wait_writable_EPIPE
127    fill_pipe
128    @r.close
129    assert_equal @w, @w.wait_writable
130  end
131
132  def test_wait_writable_closed
133    @w.close
134    assert_raise(IOError) { @w.wait_writable }
135  end
136
137  def test_wait_readwrite
138    assert_equal @r.wait(0, :write), @r.wait(0, :read_write)
139  end
140
141  def test_wait_readwrite_timeout
142    assert_equal @w, @w.wait(0.01, :read_write)
143    written = fill_pipe
144    if /aix/ =~ RUBY_PLATFORM
145      # IO#wait internally uses select(2) on AIX.
146      # AIX's select(2) returns "readable" for the write-side fd
147      # of a pipe, so @w.wait(0.01, :read_write) does not return nil.
148      assert_equal @w, @w.wait(0.01, :read_write)
149    else
150      assert_nil @w.wait(0.01, :read_write)
151    end
152    @r.read(written)
153    assert_equal @w, @w.wait(0.01, :read_write)
154  end
155
156private
157
158  def fill_pipe
159    written = 0
160    buf = " " * 4096
161    begin
162      written += @w.write_nonblock(buf)
163    rescue Errno::EAGAIN, Errno::EWOULDBLOCK
164      return written
165    end while true
166  end
167end if IO.method_defined?(:wait)
168