* 2022-01-18 [ci skip]
[ruby-80x24.org.git] / test / test_pty.rb
blob1c0c6fb3e87361fb0a25e628f40b4db5b6dbae3e
1 # frozen_string_literal: false
2 require 'test/unit'
3 require 'shellwords'
4 require 'tmpdir'
6 begin
7   require 'pty'
8 rescue LoadError
9 end
11 class TestPTY < Test::Unit::TestCase
12   RUBY = EnvUtil.rubybin
14   def test_spawn_without_block
15     r, w, pid = PTY.spawn(RUBY, '-e', 'puts "a"')
16   rescue RuntimeError
17     omit $!
18   else
19     assert_equal("a\r\n", r.gets)
20   ensure
21     r&.close
22     w&.close
23     Process.wait pid if pid
24   end
26   def test_spawn_with_block
27     PTY.spawn(RUBY, '-e', 'puts "b"') {|r,w,pid|
28       begin
29         assert_equal("b\r\n", r.gets)
30       ensure
31         r.close
32         w.close
33         Process.wait(pid)
34       end
35     }
36   rescue RuntimeError
37     omit $!
38   end
40   def test_commandline
41     commandline = Shellwords.join([RUBY, '-e', 'puts "foo"'])
42     PTY.spawn(commandline) {|r,w,pid|
43       begin
44         assert_equal("foo\r\n", r.gets)
45       ensure
46         r.close
47         w.close
48         Process.wait(pid)
49       end
50     }
51   rescue RuntimeError
52     omit $!
53   end
55   def test_argv0
56     PTY.spawn([RUBY, "argv0"], '-e', 'puts "bar"') {|r,w,pid|
57       begin
58         assert_equal("bar\r\n", r.gets)
59       ensure
60         r.close
61         w.close
62         Process.wait(pid)
63       end
64     }
65   rescue RuntimeError
66     omit $!
67   end
69   def test_open_without_block
70     ret = PTY.open
71   rescue RuntimeError
72     omit $!
73   else
74     assert_kind_of(Array, ret)
75     assert_equal(2, ret.length)
76     assert_equal(IO, ret[0].class)
77     assert_equal(File, ret[1].class)
78     _, slave = ret
79     assert(slave.tty?)
80     assert(File.chardev?(slave.path))
81   ensure
82     if ret
83       ret[0].close
84       ret[1].close
85     end
86   end
88   def test_open_with_block
89     r = nil
90     x = Object.new
91     y = PTY.open {|ret|
92       r = ret;
93       assert_kind_of(Array, ret)
94       assert_equal(2, ret.length)
95       assert_equal(IO, ret[0].class)
96       assert_equal(File, ret[1].class)
97       _, slave = ret
98       assert(slave.tty?)
99       assert(File.chardev?(slave.path))
100       x
101     }
102   rescue RuntimeError
103     omit $!
104   else
105     assert(r[0].closed?)
106     assert(r[1].closed?)
107     assert_equal(y, x)
108   end
110   def test_close_in_block
111     PTY.open {|master, slave|
112       slave.close
113       master.close
114       assert(slave.closed?)
115       assert(master.closed?)
116     }
117   rescue RuntimeError
118     omit $!
119   else
120     assert_nothing_raised {
121       PTY.open {|master, slave|
122         slave.close
123         master.close
124       }
125     }
126   end
128   def test_open
129     PTY.open {|master, slave|
130       slave.puts "foo"
131       assert_equal("foo", master.gets.chomp)
132       master.puts "bar"
133       assert_equal("bar", slave.gets.chomp)
134     }
135   rescue RuntimeError
136     omit $!
137   end
139   def test_stat_slave
140     PTY.open {|master, slave|
141       s =  File.stat(slave.path)
142       assert_equal(Process.uid, s.uid)
143       assert_equal(0600, s.mode & 0777)
144     }
145   rescue RuntimeError
146     omit $!
147   end
149   def test_close_master
150     PTY.open {|master, slave|
151       master.close
152       assert_raise(EOFError) { slave.readpartial(10) }
153     }
154   rescue RuntimeError
155     omit $!
156   end
158   def test_close_slave
159     PTY.open {|master, slave|
160       slave.close
161       # This exception is platform dependent.
162       assert_raise(
163         EOFError,       # FreeBSD
164         Errno::EIO      # GNU/Linux
165       ) { master.readpartial(10) }
166     }
167   rescue RuntimeError
168     omit $!
169   end
171   def test_getpty_nonexistent
172     bug3672 = '[ruby-dev:41965]'
173     Dir.mktmpdir do |tmpdir|
174       assert_raise(Errno::ENOENT, bug3672) {
175         begin
176           PTY.getpty(File.join(tmpdir, "no-such-command"))
177         rescue RuntimeError
178           omit $!
179         end
180       }
181     end
182   end
184   def test_pty_check_default
185     st1 = st2 = pid = nil
186     `echo` # preset $?
187     PTY.spawn("cat") do |r,w,id|
188       pid = id
189       st1 = PTY.check(pid)
190       w.close
191       r.close
192       begin
193         sleep(0.1)
194       end until st2 = PTY.check(pid)
195     end
196   rescue RuntimeError
197     omit $!
198   else
199     assert_nil(st1)
200     assert_equal(pid, st2.pid)
201   end
203   def test_pty_check_raise
204     bug2642 = '[ruby-dev:44600]'
205     st1 = st2 = pid = nil
206     PTY.spawn("cat") do |r,w,id|
207       pid = id
208       assert_nothing_raised(PTY::ChildExited, bug2642) {st1 = PTY.check(pid, true)}
209       w.close
210       r.close
211       sleep(0.1)
212       st2 = assert_raise(PTY::ChildExited, bug2642) {PTY.check(pid, true)}.status
213     end
214   rescue RuntimeError
215     omit $!
216   else
217     assert_nil(st1)
218     assert_equal(pid, st2.pid)
219   end
221   def test_cloexec
222     PTY.open {|m, s|
223       assert(m.close_on_exec?)
224       assert(s.close_on_exec?)
225     }
226     PTY.spawn(RUBY, '-e', '') {|r, w, pid|
227       begin
228         assert(r.close_on_exec?)
229         assert(w.close_on_exec?)
230       ensure
231         r.close
232         w.close
233         Process.wait(pid)
234       end
235     }
236   rescue RuntimeError
237     omit $!
238   end
239 end if defined? PTY