PageRenderTime 62ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/test/ruby/test_io.rb

http://github.com/ruby/ruby
Ruby | 3974 lines | 3592 code | 354 blank | 28 comment | 113 complexity | 3bfa2bc38b8f6ed057baf875d82c1953 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. # coding: US-ASCII
  2. # frozen_string_literal: false
  3. require 'test/unit'
  4. require 'tmpdir'
  5. require "fcntl"
  6. require 'io/nonblock'
  7. require 'pathname'
  8. require 'socket'
  9. require 'stringio'
  10. require 'timeout'
  11. require 'tempfile'
  12. require 'weakref'
  13. class TestIO < Test::Unit::TestCase
  14. module Feature
  15. def have_close_on_exec?
  16. $stdin.close_on_exec?
  17. true
  18. rescue NotImplementedError
  19. false
  20. end
  21. def have_nonblock?
  22. IO.method_defined?("nonblock=")
  23. end
  24. end
  25. include Feature
  26. extend Feature
  27. def pipe(wp, rp)
  28. re, we = nil, nil
  29. r, w = IO.pipe
  30. rt = Thread.new do
  31. begin
  32. rp.call(r)
  33. rescue Exception
  34. r.close
  35. re = $!
  36. end
  37. end
  38. wt = Thread.new do
  39. begin
  40. wp.call(w)
  41. rescue Exception
  42. w.close
  43. we = $!
  44. end
  45. end
  46. flunk("timeout") unless wt.join(10) && rt.join(10)
  47. ensure
  48. w&.close
  49. r&.close
  50. (wt.kill; wt.join) if wt
  51. (rt.kill; rt.join) if rt
  52. raise we if we
  53. raise re if re
  54. end
  55. def with_pipe
  56. r, w = IO.pipe
  57. begin
  58. yield r, w
  59. ensure
  60. r.close
  61. w.close
  62. end
  63. end
  64. def with_read_pipe(content)
  65. pipe(proc do |w|
  66. w << content
  67. w.close
  68. end, proc do |r|
  69. yield r
  70. end)
  71. end
  72. def mkcdtmpdir
  73. Dir.mktmpdir {|d|
  74. Dir.chdir(d) {
  75. yield
  76. }
  77. }
  78. end
  79. def trapping_usr2
  80. @usr2_rcvd = 0
  81. r, w = IO.pipe
  82. trap(:USR2) do
  83. w.write([@usr2_rcvd += 1].pack('L'))
  84. end
  85. yield r
  86. ensure
  87. trap(:USR2, "DEFAULT")
  88. w&.close
  89. r&.close
  90. end
  91. def test_pipe
  92. r, w = IO.pipe
  93. assert_instance_of(IO, r)
  94. assert_instance_of(IO, w)
  95. [
  96. Thread.start{
  97. w.print "abc"
  98. w.close
  99. },
  100. Thread.start{
  101. assert_equal("abc", r.read)
  102. r.close
  103. }
  104. ].each{|thr| thr.join}
  105. end
  106. def test_binmode_pipe
  107. EnvUtil.with_default_internal(Encoding::UTF_8) do
  108. EnvUtil.with_default_external(Encoding::UTF_8) do
  109. begin
  110. reader0, writer0 = IO.pipe
  111. reader0.binmode
  112. writer0.binmode
  113. reader1, writer1 = IO.pipe
  114. reader2, writer2 = IO.pipe(binmode: true)
  115. assert_predicate writer0, :binmode?
  116. assert_predicate writer2, :binmode?
  117. assert_equal writer0.binmode?, writer2.binmode?
  118. assert_equal writer0.external_encoding, writer2.external_encoding
  119. assert_equal writer0.internal_encoding, writer2.internal_encoding
  120. assert_predicate reader0, :binmode?
  121. assert_predicate reader2, :binmode?
  122. assert_equal reader0.binmode?, reader2.binmode?
  123. assert_equal reader0.external_encoding, reader2.external_encoding
  124. assert_equal reader0.internal_encoding, reader2.internal_encoding
  125. reader3, writer3 = IO.pipe("UTF-8:UTF-8", binmode: true)
  126. assert_predicate writer3, :binmode?
  127. assert_equal writer1.external_encoding, writer3.external_encoding
  128. assert_equal writer1.internal_encoding, writer3.internal_encoding
  129. assert_predicate reader3, :binmode?
  130. assert_equal reader1.external_encoding, reader3.external_encoding
  131. assert_equal reader1.internal_encoding, reader3.internal_encoding
  132. reader4, writer4 = IO.pipe("UTF-8:UTF-8", binmode: true)
  133. assert_predicate writer4, :binmode?
  134. assert_equal writer1.external_encoding, writer4.external_encoding
  135. assert_equal writer1.internal_encoding, writer4.internal_encoding
  136. assert_predicate reader4, :binmode?
  137. assert_equal reader1.external_encoding, reader4.external_encoding
  138. assert_equal reader1.internal_encoding, reader4.internal_encoding
  139. reader5, writer5 = IO.pipe("UTF-8", "UTF-8", binmode: true)
  140. assert_predicate writer5, :binmode?
  141. assert_equal writer1.external_encoding, writer5.external_encoding
  142. assert_equal writer1.internal_encoding, writer5.internal_encoding
  143. assert_predicate reader5, :binmode?
  144. assert_equal reader1.external_encoding, reader5.external_encoding
  145. assert_equal reader1.internal_encoding, reader5.internal_encoding
  146. ensure
  147. [
  148. reader0, writer0,
  149. reader1, writer1,
  150. reader2, writer2,
  151. reader3, writer3,
  152. reader4, writer4,
  153. reader5, writer5,
  154. ].compact.map(&:close)
  155. end
  156. end
  157. end
  158. end
  159. def test_pipe_block
  160. x = nil
  161. ret = IO.pipe {|r, w|
  162. x = [r,w]
  163. assert_instance_of(IO, r)
  164. assert_instance_of(IO, w)
  165. [
  166. Thread.start do
  167. w.print "abc"
  168. w.close
  169. end,
  170. Thread.start do
  171. assert_equal("abc", r.read)
  172. end
  173. ].each{|thr| thr.join}
  174. assert_not_predicate(r, :closed?)
  175. assert_predicate(w, :closed?)
  176. :foooo
  177. }
  178. assert_equal(:foooo, ret)
  179. assert_predicate(x[0], :closed?)
  180. assert_predicate(x[1], :closed?)
  181. end
  182. def test_pipe_block_close
  183. 4.times {|i|
  184. x = nil
  185. IO.pipe {|r, w|
  186. x = [r,w]
  187. r.close if (i&1) == 0
  188. w.close if (i&2) == 0
  189. }
  190. assert_predicate(x[0], :closed?)
  191. assert_predicate(x[1], :closed?)
  192. }
  193. end
  194. def test_gets_rs
  195. rs = ":"
  196. pipe(proc do |w|
  197. w.print "aaa:bbb"
  198. w.close
  199. end, proc do |r|
  200. assert_equal "aaa:", r.gets(rs)
  201. assert_equal "bbb", r.gets(rs)
  202. assert_nil r.gets(rs)
  203. r.close
  204. end)
  205. end
  206. def test_gets_default_rs
  207. pipe(proc do |w|
  208. w.print "aaa\nbbb\n"
  209. w.close
  210. end, proc do |r|
  211. assert_equal "aaa\n", r.gets
  212. assert_equal "bbb\n", r.gets
  213. assert_nil r.gets
  214. r.close
  215. end)
  216. end
  217. def test_gets_rs_nil
  218. pipe(proc do |w|
  219. w.print "a\n\nb\n\n"
  220. w.close
  221. end, proc do |r|
  222. assert_equal "a\n\nb\n\n", r.gets(nil)
  223. assert_nil r.gets("")
  224. r.close
  225. end)
  226. end
  227. def test_gets_rs_377
  228. pipe(proc do |w|
  229. w.print "\377xyz"
  230. w.close
  231. end, proc do |r|
  232. r.binmode
  233. assert_equal("\377", r.gets("\377"), "[ruby-dev:24460]")
  234. r.close
  235. end)
  236. end
  237. def test_gets_paragraph
  238. pipe(proc do |w|
  239. w.print "a\n\nb\n\n"
  240. w.close
  241. end, proc do |r|
  242. assert_equal "a\n\n", r.gets(""), "[ruby-core:03771]"
  243. assert_equal "b\n\n", r.gets("")
  244. assert_nil r.gets("")
  245. r.close
  246. end)
  247. end
  248. def test_gets_chomp_rs
  249. rs = ":"
  250. pipe(proc do |w|
  251. w.print "aaa:bbb"
  252. w.close
  253. end, proc do |r|
  254. assert_equal "aaa", r.gets(rs, chomp: true)
  255. assert_equal "bbb", r.gets(rs, chomp: true)
  256. assert_nil r.gets(rs, chomp: true)
  257. r.close
  258. end)
  259. end
  260. def test_gets_chomp_default_rs
  261. pipe(proc do |w|
  262. w.print "aaa\r\nbbb\nccc"
  263. w.close
  264. end, proc do |r|
  265. assert_equal "aaa", r.gets(chomp: true)
  266. assert_equal "bbb", r.gets(chomp: true)
  267. assert_equal "ccc", r.gets(chomp: true)
  268. assert_nil r.gets
  269. r.close
  270. end)
  271. (0..3).each do |i|
  272. pipe(proc do |w|
  273. w.write("a" * ((4096 << i) - 4), "\r\n" "a\r\n")
  274. w.close
  275. end,
  276. proc do |r|
  277. r.gets
  278. assert_equal "a", r.gets(chomp: true)
  279. assert_nil r.gets
  280. r.close
  281. end)
  282. end
  283. end
  284. def test_gets_chomp_rs_nil
  285. pipe(proc do |w|
  286. w.print "a\n\nb\n\n"
  287. w.close
  288. end, proc do |r|
  289. assert_equal "a\n\nb\n", r.gets(nil, chomp: true)
  290. assert_nil r.gets("")
  291. r.close
  292. end)
  293. end
  294. def test_gets_chomp_paragraph
  295. pipe(proc do |w|
  296. w.print "a\n\nb\n\n"
  297. w.close
  298. end, proc do |r|
  299. assert_equal "a", r.gets("", chomp: true)
  300. assert_equal "b", r.gets("", chomp: true)
  301. assert_nil r.gets("", chomp: true)
  302. r.close
  303. end)
  304. end
  305. def test_gets_limit_extra_arg
  306. pipe(proc do |w|
  307. w << "0123456789\n0123456789"
  308. w.close
  309. end, proc do |r|
  310. assert_equal("0123456789\n0", r.gets(nil, 12))
  311. assert_raise(TypeError) { r.gets(3,nil) }
  312. end)
  313. end
  314. # This test cause SEGV.
  315. def test_ungetc
  316. pipe(proc do |w|
  317. w.close
  318. end, proc do |r|
  319. s = "a" * 1000
  320. assert_raise(IOError, "[ruby-dev:31650]") { 200.times { r.ungetc s } }
  321. end)
  322. end
  323. def test_ungetbyte
  324. make_tempfile {|t|
  325. t.open
  326. t.binmode
  327. t.ungetbyte(0x41)
  328. assert_equal(-1, t.pos)
  329. assert_equal(0x41, t.getbyte)
  330. t.rewind
  331. assert_equal(0, t.pos)
  332. t.ungetbyte("qux")
  333. assert_equal(-3, t.pos)
  334. assert_equal("quxfoo\n", t.gets)
  335. assert_equal(4, t.pos)
  336. t.set_encoding("utf-8")
  337. t.ungetbyte(0x89)
  338. t.ungetbyte(0x8e)
  339. t.ungetbyte("\xe7")
  340. t.ungetbyte("\xe7\xb4\x85")
  341. assert_equal(-2, t.pos)
  342. assert_equal("\u7d05\u7389bar\n", t.gets)
  343. }
  344. end
  345. def test_each_byte
  346. pipe(proc do |w|
  347. w << "abc def"
  348. w.close
  349. end, proc do |r|
  350. r.each_byte {|byte| break if byte == 32 }
  351. assert_equal("def", r.read, "[ruby-dev:31659]")
  352. end)
  353. end
  354. def test_each_byte_with_seek
  355. make_tempfile {|t|
  356. bug5119 = '[ruby-core:38609]'
  357. i = 0
  358. open(t.path) do |f|
  359. f.each_byte {i = f.pos}
  360. end
  361. assert_equal(12, i, bug5119)
  362. }
  363. end
  364. def test_each_codepoint
  365. make_tempfile {|t|
  366. bug2959 = '[ruby-core:28650]'
  367. a = ""
  368. File.open(t, 'rt') {|f|
  369. f.each_codepoint {|c| a << c}
  370. }
  371. assert_equal("foo\nbar\nbaz\n", a, bug2959)
  372. }
  373. end
  374. def test_codepoints
  375. make_tempfile {|t|
  376. bug2959 = '[ruby-core:28650]'
  377. a = ""
  378. File.open(t, 'rt') {|f|
  379. assert_warn(/deprecated/) {
  380. f.codepoints {|c| a << c}
  381. }
  382. }
  383. assert_equal("foo\nbar\nbaz\n", a, bug2959)
  384. }
  385. end
  386. def test_rubydev33072
  387. t = make_tempfile
  388. path = t.path
  389. t.close!
  390. assert_raise(Errno::ENOENT, "[ruby-dev:33072]") do
  391. File.read(path, nil, nil, **{})
  392. end
  393. end
  394. def with_srccontent(content = "baz")
  395. src = "src"
  396. mkcdtmpdir {
  397. File.open(src, "w") {|f| f << content }
  398. yield src, content
  399. }
  400. end
  401. def test_copy_stream_small
  402. with_srccontent("foobar") {|src, content|
  403. ret = IO.copy_stream(src, "dst")
  404. assert_equal(content.bytesize, ret)
  405. assert_equal(content, File.read("dst"))
  406. }
  407. end
  408. def test_copy_stream_append
  409. with_srccontent("foobar") {|src, content|
  410. File.open('dst', 'ab') do |dst|
  411. ret = IO.copy_stream(src, dst)
  412. assert_equal(content.bytesize, ret)
  413. assert_equal(content, File.read("dst"))
  414. end
  415. }
  416. end
  417. def test_copy_stream_smaller
  418. with_srccontent {|src, content|
  419. # overwrite by smaller file.
  420. dst = "dst"
  421. File.open(dst, "w") {|f| f << "foobar"}
  422. ret = IO.copy_stream(src, dst)
  423. assert_equal(content.bytesize, ret)
  424. assert_equal(content, File.read(dst))
  425. ret = IO.copy_stream(src, dst, 2)
  426. assert_equal(2, ret)
  427. assert_equal(content[0,2], File.read(dst))
  428. ret = IO.copy_stream(src, dst, 0)
  429. assert_equal(0, ret)
  430. assert_equal("", File.read(dst))
  431. ret = IO.copy_stream(src, dst, nil, 1)
  432. assert_equal(content.bytesize-1, ret)
  433. assert_equal(content[1..-1], File.read(dst))
  434. }
  435. end
  436. def test_copy_stream_noent
  437. with_srccontent {|src, content|
  438. assert_raise(Errno::ENOENT) {
  439. IO.copy_stream("nodir/foo", "dst")
  440. }
  441. assert_raise(Errno::ENOENT) {
  442. IO.copy_stream(src, "nodir/bar")
  443. }
  444. }
  445. end
  446. def test_copy_stream_pipe
  447. with_srccontent {|src, content|
  448. pipe(proc do |w|
  449. ret = IO.copy_stream(src, w)
  450. assert_equal(content.bytesize, ret)
  451. w.close
  452. end, proc do |r|
  453. assert_equal(content, r.read)
  454. end)
  455. }
  456. end
  457. def test_copy_stream_write_pipe
  458. with_srccontent {|src, content|
  459. with_pipe {|r, w|
  460. w.close
  461. assert_raise(IOError) { IO.copy_stream(src, w) }
  462. }
  463. }
  464. end
  465. def with_pipecontent
  466. mkcdtmpdir {
  467. yield "abc"
  468. }
  469. end
  470. def test_copy_stream_pipe_to_file
  471. with_pipecontent {|pipe_content|
  472. dst = "dst"
  473. with_read_pipe(pipe_content) {|r|
  474. ret = IO.copy_stream(r, dst)
  475. assert_equal(pipe_content.bytesize, ret)
  476. assert_equal(pipe_content, File.read(dst))
  477. }
  478. }
  479. end
  480. def test_copy_stream_read_pipe
  481. with_pipecontent {|pipe_content|
  482. with_read_pipe(pipe_content) {|r1|
  483. assert_equal("a", r1.getc)
  484. pipe(proc do |w2|
  485. w2.sync = false
  486. w2 << "def"
  487. ret = IO.copy_stream(r1, w2)
  488. assert_equal(2, ret)
  489. w2.close
  490. end, proc do |r2|
  491. assert_equal("defbc", r2.read)
  492. end)
  493. }
  494. with_read_pipe(pipe_content) {|r1|
  495. assert_equal("a", r1.getc)
  496. pipe(proc do |w2|
  497. w2.sync = false
  498. w2 << "def"
  499. ret = IO.copy_stream(r1, w2, 1)
  500. assert_equal(1, ret)
  501. w2.close
  502. end, proc do |r2|
  503. assert_equal("defb", r2.read)
  504. end)
  505. }
  506. with_read_pipe(pipe_content) {|r1|
  507. assert_equal("a", r1.getc)
  508. pipe(proc do |w2|
  509. ret = IO.copy_stream(r1, w2)
  510. assert_equal(2, ret)
  511. w2.close
  512. end, proc do |r2|
  513. assert_equal("bc", r2.read)
  514. end)
  515. }
  516. with_read_pipe(pipe_content) {|r1|
  517. assert_equal("a", r1.getc)
  518. pipe(proc do |w2|
  519. ret = IO.copy_stream(r1, w2, 1)
  520. assert_equal(1, ret)
  521. w2.close
  522. end, proc do |r2|
  523. assert_equal("b", r2.read)
  524. end)
  525. }
  526. with_read_pipe(pipe_content) {|r1|
  527. assert_equal("a", r1.getc)
  528. pipe(proc do |w2|
  529. ret = IO.copy_stream(r1, w2, 0)
  530. assert_equal(0, ret)
  531. w2.close
  532. end, proc do |r2|
  533. assert_equal("", r2.read)
  534. end)
  535. }
  536. pipe(proc do |w1|
  537. w1 << "abc"
  538. w1 << "def"
  539. w1.close
  540. end, proc do |r1|
  541. assert_equal("a", r1.getc)
  542. pipe(proc do |w2|
  543. ret = IO.copy_stream(r1, w2)
  544. assert_equal(5, ret)
  545. w2.close
  546. end, proc do |r2|
  547. assert_equal("bcdef", r2.read)
  548. end)
  549. end)
  550. }
  551. end
  552. def test_copy_stream_file_to_pipe
  553. with_srccontent {|src, content|
  554. pipe(proc do |w|
  555. ret = IO.copy_stream(src, w, 1, 1)
  556. assert_equal(1, ret)
  557. w.close
  558. end, proc do |r|
  559. assert_equal(content[1,1], r.read)
  560. end)
  561. }
  562. end
  563. if have_nonblock?
  564. def test_copy_stream_no_busy_wait
  565. skip "MJIT has busy wait on GC. This sometimes fails with --jit." if RubyVM::MJIT.enabled?
  566. skip "multiple threads already active" if Thread.list.size > 1
  567. msg = 'r58534 [ruby-core:80969] [Backport #13533]'
  568. IO.pipe do |r,w|
  569. r.nonblock = true
  570. assert_cpu_usage_low(msg, stop: ->{w.close}) do
  571. IO.copy_stream(r, IO::NULL)
  572. end
  573. end
  574. end
  575. def test_copy_stream_pipe_nonblock
  576. mkcdtmpdir {
  577. with_read_pipe("abc") {|r1|
  578. assert_equal("a", r1.getc)
  579. with_pipe {|r2, w2|
  580. begin
  581. w2.nonblock = true
  582. rescue Errno::EBADF
  583. skip "nonblocking IO for pipe is not implemented"
  584. end
  585. s = w2.syswrite("a" * 100000)
  586. t = Thread.new { sleep 0.1; r2.read }
  587. ret = IO.copy_stream(r1, w2)
  588. w2.close
  589. assert_equal(2, ret)
  590. assert_equal("a" * s + "bc", t.value)
  591. }
  592. }
  593. }
  594. end
  595. end
  596. def with_bigcontent
  597. yield "abc" * 123456
  598. end
  599. def with_bigsrc
  600. mkcdtmpdir {
  601. with_bigcontent {|bigcontent|
  602. bigsrc = "bigsrc"
  603. File.open("bigsrc", "w") {|f| f << bigcontent }
  604. yield bigsrc, bigcontent
  605. }
  606. }
  607. end
  608. def test_copy_stream_bigcontent
  609. with_bigsrc {|bigsrc, bigcontent|
  610. ret = IO.copy_stream(bigsrc, "bigdst")
  611. assert_equal(bigcontent.bytesize, ret)
  612. assert_equal(bigcontent, File.read("bigdst"))
  613. }
  614. end
  615. def test_copy_stream_bigcontent_chop
  616. with_bigsrc {|bigsrc, bigcontent|
  617. ret = IO.copy_stream(bigsrc, "bigdst", nil, 100)
  618. assert_equal(bigcontent.bytesize-100, ret)
  619. assert_equal(bigcontent[100..-1], File.read("bigdst"))
  620. }
  621. end
  622. def test_copy_stream_bigcontent_mid
  623. with_bigsrc {|bigsrc, bigcontent|
  624. ret = IO.copy_stream(bigsrc, "bigdst", 30000, 100)
  625. assert_equal(30000, ret)
  626. assert_equal(bigcontent[100, 30000], File.read("bigdst"))
  627. }
  628. end
  629. def test_copy_stream_bigcontent_fpos
  630. with_bigsrc {|bigsrc, bigcontent|
  631. File.open(bigsrc) {|f|
  632. begin
  633. assert_equal(0, f.pos)
  634. ret = IO.copy_stream(f, "bigdst", nil, 10)
  635. assert_equal(bigcontent.bytesize-10, ret)
  636. assert_equal(bigcontent[10..-1], File.read("bigdst"))
  637. assert_equal(0, f.pos)
  638. ret = IO.copy_stream(f, "bigdst", 40, 30)
  639. assert_equal(40, ret)
  640. assert_equal(bigcontent[30, 40], File.read("bigdst"))
  641. assert_equal(0, f.pos)
  642. rescue NotImplementedError
  643. #skip "pread(2) is not implemented."
  644. end
  645. }
  646. }
  647. end
  648. def test_copy_stream_closed_pipe
  649. with_srccontent {|src,|
  650. with_pipe {|r, w|
  651. w.close
  652. assert_raise(IOError) { IO.copy_stream(src, w) }
  653. }
  654. }
  655. end
  656. def with_megacontent
  657. yield "abc" * 1234567
  658. end
  659. def with_megasrc
  660. mkcdtmpdir {
  661. with_megacontent {|megacontent|
  662. megasrc = "megasrc"
  663. File.open(megasrc, "w") {|f| f << megacontent }
  664. yield megasrc, megacontent
  665. }
  666. }
  667. end
  668. if have_nonblock?
  669. def test_copy_stream_megacontent_nonblock
  670. with_megacontent {|megacontent|
  671. with_pipe {|r1, w1|
  672. with_pipe {|r2, w2|
  673. begin
  674. r1.nonblock = true
  675. w2.nonblock = true
  676. rescue Errno::EBADF
  677. skip "nonblocking IO for pipe is not implemented"
  678. end
  679. t1 = Thread.new { w1 << megacontent; w1.close }
  680. t2 = Thread.new { r2.read }
  681. t3 = Thread.new {
  682. ret = IO.copy_stream(r1, w2)
  683. assert_equal(megacontent.bytesize, ret)
  684. w2.close
  685. }
  686. _, t2_value, _ = assert_join_threads([t1, t2, t3])
  687. assert_equal(megacontent, t2_value)
  688. }
  689. }
  690. }
  691. end
  692. end
  693. def test_copy_stream_megacontent_pipe_to_file
  694. with_megasrc {|megasrc, megacontent|
  695. with_pipe {|r1, w1|
  696. with_pipe {|r2, w2|
  697. t1 = Thread.new { w1 << megacontent; w1.close }
  698. t2 = Thread.new { r2.read }
  699. t3 = Thread.new {
  700. ret = IO.copy_stream(r1, w2)
  701. assert_equal(megacontent.bytesize, ret)
  702. w2.close
  703. }
  704. _, t2_value, _ = assert_join_threads([t1, t2, t3])
  705. assert_equal(megacontent, t2_value)
  706. }
  707. }
  708. }
  709. end
  710. def test_copy_stream_megacontent_file_to_pipe
  711. with_megasrc {|megasrc, megacontent|
  712. with_pipe {|r, w|
  713. t1 = Thread.new { r.read }
  714. t2 = Thread.new {
  715. ret = IO.copy_stream(megasrc, w)
  716. assert_equal(megacontent.bytesize, ret)
  717. w.close
  718. }
  719. t1_value, _ = assert_join_threads([t1, t2])
  720. assert_equal(megacontent, t1_value)
  721. }
  722. }
  723. end
  724. def test_copy_stream_rbuf
  725. mkcdtmpdir {
  726. begin
  727. pipe(proc do |w|
  728. File.open("foo", "w") {|f| f << "abcd" }
  729. File.open("foo") {|f|
  730. f.read(1)
  731. assert_equal(3, IO.copy_stream(f, w, 10, 1))
  732. }
  733. w.close
  734. end, proc do |r|
  735. assert_equal("bcd", r.read)
  736. end)
  737. rescue NotImplementedError
  738. skip "pread(2) is not implemtented."
  739. end
  740. }
  741. end
  742. def with_socketpair
  743. s1, s2 = UNIXSocket.pair
  744. begin
  745. yield s1, s2
  746. ensure
  747. s1.close unless s1.closed?
  748. s2.close unless s2.closed?
  749. end
  750. end
  751. def test_copy_stream_socket1
  752. with_srccontent("foobar") {|src, content|
  753. with_socketpair {|s1, s2|
  754. ret = IO.copy_stream(src, s1)
  755. assert_equal(content.bytesize, ret)
  756. s1.close
  757. assert_equal(content, s2.read)
  758. }
  759. }
  760. end if defined? UNIXSocket
  761. def test_copy_stream_socket2
  762. with_bigsrc {|bigsrc, bigcontent|
  763. with_socketpair {|s1, s2|
  764. t1 = Thread.new { s2.read }
  765. t2 = Thread.new {
  766. ret = IO.copy_stream(bigsrc, s1)
  767. assert_equal(bigcontent.bytesize, ret)
  768. s1.close
  769. }
  770. result, _ = assert_join_threads([t1, t2])
  771. assert_equal(bigcontent, result)
  772. }
  773. }
  774. end if defined? UNIXSocket
  775. def test_copy_stream_socket3
  776. with_bigsrc {|bigsrc, bigcontent|
  777. with_socketpair {|s1, s2|
  778. t1 = Thread.new { s2.read }
  779. t2 = Thread.new {
  780. ret = IO.copy_stream(bigsrc, s1, 10000)
  781. assert_equal(10000, ret)
  782. s1.close
  783. }
  784. result, _ = assert_join_threads([t1, t2])
  785. assert_equal(bigcontent[0,10000], result)
  786. }
  787. }
  788. end if defined? UNIXSocket
  789. def test_copy_stream_socket4
  790. with_bigsrc {|bigsrc, bigcontent|
  791. File.open(bigsrc) {|f|
  792. assert_equal(0, f.pos)
  793. with_socketpair {|s1, s2|
  794. t1 = Thread.new { s2.read }
  795. t2 = Thread.new {
  796. ret = IO.copy_stream(f, s1, nil, 100)
  797. assert_equal(bigcontent.bytesize-100, ret)
  798. assert_equal(0, f.pos)
  799. s1.close
  800. }
  801. result, _ = assert_join_threads([t1, t2])
  802. assert_equal(bigcontent[100..-1], result)
  803. }
  804. }
  805. }
  806. end if defined? UNIXSocket
  807. def test_copy_stream_socket5
  808. with_bigsrc {|bigsrc, bigcontent|
  809. File.open(bigsrc) {|f|
  810. assert_equal(bigcontent[0,100], f.read(100))
  811. assert_equal(100, f.pos)
  812. with_socketpair {|s1, s2|
  813. t1 = Thread.new { s2.read }
  814. t2 = Thread.new {
  815. ret = IO.copy_stream(f, s1)
  816. assert_equal(bigcontent.bytesize-100, ret)
  817. assert_equal(bigcontent.length, f.pos)
  818. s1.close
  819. }
  820. result, _ = assert_join_threads([t1, t2])
  821. assert_equal(bigcontent[100..-1], result)
  822. }
  823. }
  824. }
  825. end if defined? UNIXSocket
  826. def test_copy_stream_socket6
  827. mkcdtmpdir {
  828. megacontent = "abc" * 1234567
  829. File.open("megasrc", "w") {|f| f << megacontent }
  830. with_socketpair {|s1, s2|
  831. begin
  832. s1.nonblock = true
  833. rescue Errno::EBADF
  834. skip "nonblocking IO for pipe is not implemented"
  835. end
  836. t1 = Thread.new { s2.read }
  837. t2 = Thread.new {
  838. ret = IO.copy_stream("megasrc", s1)
  839. assert_equal(megacontent.bytesize, ret)
  840. s1.close
  841. }
  842. result, _ = assert_join_threads([t1, t2])
  843. assert_equal(megacontent, result)
  844. }
  845. }
  846. end if defined? UNIXSocket
  847. def test_copy_stream_socket7
  848. GC.start
  849. mkcdtmpdir {
  850. megacontent = "abc" * 1234567
  851. File.open("megasrc", "w") {|f| f << megacontent }
  852. with_socketpair {|s1, s2|
  853. begin
  854. s1.nonblock = true
  855. rescue Errno::EBADF
  856. skip "nonblocking IO for pipe is not implemented"
  857. end
  858. trapping_usr2 do |rd|
  859. nr = 30
  860. begin
  861. pid = fork do
  862. s1.close
  863. IO.select([s2])
  864. Process.kill(:USR2, Process.ppid)
  865. buf = String.new(capacity: 16384)
  866. nil while s2.read(16384, buf)
  867. end
  868. s2.close
  869. nr.times do
  870. assert_equal megacontent.bytesize, IO.copy_stream("megasrc", s1)
  871. end
  872. assert_equal(1, rd.read(4).unpack1('L'))
  873. ensure
  874. s1.close
  875. _, status = Process.waitpid2(pid) if pid
  876. end
  877. assert_predicate(status, :success?)
  878. end
  879. }
  880. }
  881. end if defined? UNIXSocket and IO.method_defined?("nonblock=")
  882. def test_copy_stream_strio
  883. src = StringIO.new("abcd")
  884. dst = StringIO.new
  885. ret = IO.copy_stream(src, dst)
  886. assert_equal(4, ret)
  887. assert_equal("abcd", dst.string)
  888. assert_equal(4, src.pos)
  889. end
  890. def test_copy_stream_strio_len
  891. src = StringIO.new("abcd")
  892. dst = StringIO.new
  893. ret = IO.copy_stream(src, dst, 3)
  894. assert_equal(3, ret)
  895. assert_equal("abc", dst.string)
  896. assert_equal(3, src.pos)
  897. end
  898. def test_copy_stream_strio_off
  899. src = StringIO.new("abcd")
  900. with_pipe {|r, w|
  901. assert_raise(ArgumentError) {
  902. IO.copy_stream(src, w, 3, 1)
  903. }
  904. }
  905. end
  906. def test_copy_stream_fname_to_strio
  907. mkcdtmpdir {
  908. File.open("foo", "w") {|f| f << "abcd" }
  909. src = "foo"
  910. dst = StringIO.new
  911. ret = IO.copy_stream(src, dst, 3)
  912. assert_equal(3, ret)
  913. assert_equal("abc", dst.string)
  914. }
  915. end
  916. def test_copy_stream_strio_to_fname
  917. mkcdtmpdir {
  918. # StringIO to filename
  919. src = StringIO.new("abcd")
  920. ret = IO.copy_stream(src, "fooo", 3)
  921. assert_equal(3, ret)
  922. assert_equal("abc", File.read("fooo"))
  923. assert_equal(3, src.pos)
  924. }
  925. end
  926. def test_copy_stream_io_to_strio
  927. mkcdtmpdir {
  928. # IO to StringIO
  929. File.open("bar", "w") {|f| f << "abcd" }
  930. File.open("bar") {|src|
  931. dst = StringIO.new
  932. ret = IO.copy_stream(src, dst, 3)
  933. assert_equal(3, ret)
  934. assert_equal("abc", dst.string)
  935. assert_equal(3, src.pos)
  936. }
  937. }
  938. end
  939. def test_copy_stream_strio_to_io
  940. mkcdtmpdir {
  941. # StringIO to IO
  942. src = StringIO.new("abcd")
  943. ret = File.open("baz", "w") {|dst|
  944. IO.copy_stream(src, dst, 3)
  945. }
  946. assert_equal(3, ret)
  947. assert_equal("abc", File.read("baz"))
  948. assert_equal(3, src.pos)
  949. }
  950. end
  951. def test_copy_stream_strio_to_tempfile
  952. bug11015 = '[ruby-core:68676] [Bug #11015]'
  953. # StringIO to Tempfile
  954. src = StringIO.new("abcd")
  955. dst = Tempfile.new("baz")
  956. ret = IO.copy_stream(src, dst)
  957. assert_equal(4, ret)
  958. pos = dst.pos
  959. dst.rewind
  960. assert_equal("abcd", dst.read)
  961. assert_equal(4, pos, bug11015)
  962. ensure
  963. dst.close!
  964. end
  965. def test_copy_stream_pathname_to_pathname
  966. bug11199 = '[ruby-dev:49008] [Bug #11199]'
  967. mkcdtmpdir {
  968. File.open("src", "w") {|f| f << "ok" }
  969. src = Pathname.new("src")
  970. dst = Pathname.new("dst")
  971. IO.copy_stream(src, dst)
  972. assert_equal("ok", IO.read("dst"), bug11199)
  973. }
  974. end
  975. def test_copy_stream_write_in_binmode
  976. bug8767 = '[ruby-core:56518] [Bug #8767]'
  977. mkcdtmpdir {
  978. EnvUtil.with_default_internal(Encoding::UTF_8) do
  979. # StringIO to object with to_path
  980. bytes = "\xDE\xAD\xBE\xEF".force_encoding(Encoding::ASCII_8BIT)
  981. src = StringIO.new(bytes)
  982. dst = Object.new
  983. def dst.to_path
  984. "qux"
  985. end
  986. assert_nothing_raised(bug8767) {
  987. IO.copy_stream(src, dst)
  988. }
  989. assert_equal(bytes, File.binread("qux"), bug8767)
  990. assert_equal(4, src.pos, bug8767)
  991. end
  992. }
  993. end
  994. def test_copy_stream_read_in_binmode
  995. bug8767 = '[ruby-core:56518] [Bug #8767]'
  996. mkcdtmpdir {
  997. EnvUtil.with_default_internal(Encoding::UTF_8) do
  998. # StringIO to object with to_path
  999. bytes = "\xDE\xAD\xBE\xEF".force_encoding(Encoding::ASCII_8BIT)
  1000. File.binwrite("qux", bytes)
  1001. dst = StringIO.new
  1002. src = Object.new
  1003. def src.to_path
  1004. "qux"
  1005. end
  1006. assert_nothing_raised(bug8767) {
  1007. IO.copy_stream(src, dst)
  1008. }
  1009. assert_equal(bytes, dst.string.b, bug8767)
  1010. assert_equal(4, dst.pos, bug8767)
  1011. end
  1012. }
  1013. end
  1014. class Rot13IO
  1015. def initialize(io)
  1016. @io = io
  1017. end
  1018. def readpartial(*args)
  1019. ret = @io.readpartial(*args)
  1020. ret.tr!('a-zA-Z', 'n-za-mN-ZA-M')
  1021. ret
  1022. end
  1023. def write(str)
  1024. @io.write(str.tr('a-zA-Z', 'n-za-mN-ZA-M'))
  1025. end
  1026. def to_io
  1027. @io
  1028. end
  1029. end
  1030. def test_copy_stream_io_to_rot13
  1031. mkcdtmpdir {
  1032. File.open("bar", "w") {|f| f << "vex" }
  1033. File.open("bar") {|src|
  1034. File.open("baz", "w") {|dst0|
  1035. dst = Rot13IO.new(dst0)
  1036. ret = IO.copy_stream(src, dst, 3)
  1037. assert_equal(3, ret)
  1038. }
  1039. assert_equal("irk", File.read("baz"))
  1040. }
  1041. }
  1042. end
  1043. def test_copy_stream_rot13_to_io
  1044. mkcdtmpdir {
  1045. File.open("bar", "w") {|f| f << "flap" }
  1046. File.open("bar") {|src0|
  1047. src = Rot13IO.new(src0)
  1048. File.open("baz", "w") {|dst|
  1049. ret = IO.copy_stream(src, dst, 4)
  1050. assert_equal(4, ret)
  1051. }
  1052. }
  1053. assert_equal("sync", File.read("baz"))
  1054. }
  1055. end
  1056. def test_copy_stream_rot13_to_rot13
  1057. mkcdtmpdir {
  1058. File.open("bar", "w") {|f| f << "bin" }
  1059. File.open("bar") {|src0|
  1060. src = Rot13IO.new(src0)
  1061. File.open("baz", "w") {|dst0|
  1062. dst = Rot13IO.new(dst0)
  1063. ret = IO.copy_stream(src, dst, 3)
  1064. assert_equal(3, ret)
  1065. }
  1066. }
  1067. assert_equal("bin", File.read("baz"))
  1068. }
  1069. end
  1070. def test_copy_stream_strio_flush
  1071. with_pipe {|r, w|
  1072. w.sync = false
  1073. w.write "zz"
  1074. src = StringIO.new("abcd")
  1075. IO.copy_stream(src, w)
  1076. t1 = Thread.new {
  1077. w.close
  1078. }
  1079. t2 = Thread.new { r.read }
  1080. _, result = assert_join_threads([t1, t2])
  1081. assert_equal("zzabcd", result)
  1082. }
  1083. end
  1084. def test_copy_stream_strio_rbuf
  1085. pipe(proc do |w|
  1086. w << "abcd"
  1087. w.close
  1088. end, proc do |r|
  1089. assert_equal("a", r.read(1))
  1090. sio = StringIO.new
  1091. IO.copy_stream(r, sio)
  1092. assert_equal("bcd", sio.string)
  1093. end)
  1094. end
  1095. def test_copy_stream_src_wbuf
  1096. mkcdtmpdir {
  1097. pipe(proc do |w|
  1098. File.open("foe", "w+") {|f|
  1099. f.write "abcd\n"
  1100. f.rewind
  1101. f.write "xy"
  1102. IO.copy_stream(f, w)
  1103. }
  1104. assert_equal("xycd\n", File.read("foe"))
  1105. w.close
  1106. end, proc do |r|
  1107. assert_equal("cd\n", r.read)
  1108. r.close
  1109. end)
  1110. }
  1111. end
  1112. class Bug5237
  1113. attr_reader :count
  1114. def initialize
  1115. @count = 0
  1116. end
  1117. def read(bytes, buffer)
  1118. @count += 1
  1119. buffer.replace "this is a test"
  1120. nil
  1121. end
  1122. end
  1123. def test_copy_stream_broken_src_read_eof
  1124. src = Bug5237.new
  1125. dst = StringIO.new
  1126. assert_equal 0, src.count
  1127. th = Thread.new { IO.copy_stream(src, dst) }
  1128. flunk("timeout") unless th.join(10)
  1129. assert_equal 1, src.count
  1130. end
  1131. def test_copy_stream_dst_rbuf
  1132. mkcdtmpdir {
  1133. pipe(proc do |w|
  1134. w << "xyz"
  1135. w.close
  1136. end, proc do |r|
  1137. File.open("fom", "w+b") {|f|
  1138. f.write "abcd\n"
  1139. f.rewind
  1140. assert_equal("abc", f.read(3))
  1141. f.ungetc "c"
  1142. IO.copy_stream(r, f)
  1143. }
  1144. assert_equal("abxyz", File.read("fom"))
  1145. end)
  1146. }
  1147. end
  1148. def test_copy_stream_to_duplex_io
  1149. result = IO.pipe {|a,w|
  1150. th = Thread.start {w.puts "yes"; w.close}
  1151. IO.popen([EnvUtil.rubybin, '-pe$_="#$.:#$_"'], "r+") {|b|
  1152. IO.copy_stream(a, b)
  1153. b.close_write
  1154. assert_join_threads([th])
  1155. b.read
  1156. }
  1157. }
  1158. assert_equal("1:yes\n", result)
  1159. end
  1160. def ruby(*args)
  1161. args = ['-e', '$>.write($<.read)'] if args.empty?
  1162. ruby = EnvUtil.rubybin
  1163. opts = {}
  1164. if defined?(Process::RLIMIT_NPROC)
  1165. lim = Process.getrlimit(Process::RLIMIT_NPROC)[1]
  1166. opts[:rlimit_nproc] = [lim, 2048].min
  1167. end
  1168. f = IO.popen([ruby] + args, 'r+', opts)
  1169. pid = f.pid
  1170. yield(f)
  1171. ensure
  1172. f.close unless !f || f.closed?
  1173. begin
  1174. Process.wait(pid)
  1175. rescue Errno::ECHILD, Errno::ESRCH
  1176. end
  1177. end
  1178. def test_try_convert
  1179. assert_equal(STDOUT, IO.try_convert(STDOUT))
  1180. assert_equal(nil, IO.try_convert("STDOUT"))
  1181. end
  1182. def test_ungetc2
  1183. f = false
  1184. pipe(proc do |w|
  1185. Thread.pass until f
  1186. w.write("1" * 10000)
  1187. w.close
  1188. end, proc do |r|
  1189. r.ungetc("0" * 10000)
  1190. f = true
  1191. assert_equal("0" * 10000 + "1" * 10000, r.read)
  1192. end)
  1193. end
  1194. def test_write_with_multiple_arguments
  1195. pipe(proc do |w|
  1196. w.write("foo", "bar")
  1197. w.close
  1198. end, proc do |r|
  1199. assert_equal("foobar", r.read)
  1200. end)
  1201. end
  1202. def test_write_with_multiple_arguments_and_buffer
  1203. mkcdtmpdir do
  1204. line = "x"*9+"\n"
  1205. file = "test.out"
  1206. open(file, "wb") do |w|
  1207. w.write(line)
  1208. assert_equal(11, w.write(line, "\n"))
  1209. end
  1210. open(file, "rb") do |r|
  1211. assert_equal([line, line, "\n"], r.readlines)
  1212. end
  1213. line = "x"*99+"\n"
  1214. open(file, "wb") do |w|
  1215. w.write(line*81) # 8100 bytes
  1216. assert_equal(100, w.write("a"*99, "\n"))
  1217. end
  1218. open(file, "rb") do |r|
  1219. 81.times {assert_equal(line, r.gets)}
  1220. assert_equal("a"*99+"\n", r.gets)
  1221. end
  1222. end
  1223. end
  1224. def test_write_with_many_arguments
  1225. [1023, 1024].each do |n|
  1226. pipe(proc do |w|
  1227. w.write(*(["a"] * n))
  1228. w.close
  1229. end, proc do |r|
  1230. assert_equal("a" * n, r.read)
  1231. end)
  1232. end
  1233. end
  1234. def test_write_with_multiple_nonstring_arguments
  1235. assert_in_out_err([], "STDOUT.write(:foo, :bar)", ["foobar"])
  1236. end
  1237. def test_write_buffered_with_multiple_arguments
  1238. out, err, (_, status) = EnvUtil.invoke_ruby(["-e", "sleep 0.1;puts 'foo'"], "", true, true) do |_, o, e, i|
  1239. [o.read, e.read, Process.waitpid2(i)]
  1240. end
  1241. assert_predicate(status, :success?)
  1242. assert_equal("foo\n", out)
  1243. assert_empty(err)
  1244. end
  1245. def test_write_no_args
  1246. IO.pipe do |r, w|
  1247. assert_equal 0, w.write, '[ruby-core:86285] [Bug #14338]'
  1248. assert_equal :wait_readable, r.read_nonblock(1, exception: false)
  1249. end
  1250. end
  1251. def test_write_non_writable
  1252. with_pipe do |r, w|
  1253. assert_raise(IOError) do
  1254. r.write "foobarbaz"
  1255. end
  1256. end
  1257. end
  1258. def test_dup
  1259. ruby do |f|
  1260. begin
  1261. f2 = f.dup
  1262. f.puts "foo"
  1263. f2.puts "bar"
  1264. f.close_write
  1265. f2.close_write
  1266. assert_equal("foo\nbar\n", f.read)
  1267. assert_equal("", f2.read)
  1268. ensure
  1269. f2.close
  1270. end
  1271. end
  1272. end
  1273. def test_dup_many
  1274. opts = {}
  1275. opts[:rlimit_nofile] = 1024 if defined?(Process::RLIMIT_NOFILE)
  1276. assert_separately([], <<-'End', **opts)
  1277. a = []
  1278. assert_raise(Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM) do
  1279. loop {a << IO.pipe}
  1280. end
  1281. assert_raise(Errno::EMFILE, Errno::ENFILE, Errno::ENOMEM) do
  1282. loop {a << [a[-1][0].dup, a[-1][1].dup]}
  1283. end
  1284. End
  1285. end
  1286. def test_inspect
  1287. with_pipe do |r, w|
  1288. assert_match(/^#<IO:fd \d+>$/, r.inspect)
  1289. r.freeze
  1290. assert_match(/^#<IO:fd \d+>$/, r.inspect)
  1291. end
  1292. end
  1293. def test_readpartial
  1294. pipe(proc do |w|
  1295. w.write "foobarbaz"
  1296. w.close
  1297. end, proc do |r|
  1298. assert_raise(ArgumentError) { r.readpartial(-1) }
  1299. assert_equal("fooba", r.readpartial(5))
  1300. r.readpartial(5, s = "")
  1301. assert_equal("rbaz", s)
  1302. end)
  1303. end
  1304. def test_readpartial_lock
  1305. with_pipe do |r, w|
  1306. s = ""
  1307. t = Thread.new { r.readpartial(5, s) }
  1308. Thread.pass until t.stop?
  1309. assert_raise(RuntimeError) { s.clear }
  1310. w.write "foobarbaz"
  1311. w.close
  1312. assert_equal("fooba", t.value)
  1313. end
  1314. end
  1315. def test_readpartial_pos
  1316. mkcdtmpdir {
  1317. open("foo", "w") {|f| f << "abc" }
  1318. open("foo") {|f|
  1319. f.seek(0)
  1320. assert_equal("ab", f.readpartial(2))
  1321. assert_equal(2, f.pos)
  1322. }
  1323. }
  1324. end
  1325. def test_readpartial_with_not_empty_buffer
  1326. pipe(proc do |w|
  1327. w.write "foob"
  1328. w.close
  1329. end, proc do |r|
  1330. r.readpartial(5, s = "01234567")
  1331. assert_equal("foob", s)
  1332. end)
  1333. end
  1334. def test_readpartial_buffer_error
  1335. with_pipe do |r, w|
  1336. s = ""
  1337. t = Thread.new { r.readpartial(5, s) }
  1338. Thread.pass until t.stop?
  1339. t.kill
  1340. t.value
  1341. assert_equal("", s)
  1342. end
  1343. end if /cygwin/ !~ RUBY_PLATFORM
  1344. def test_read
  1345. pipe(proc do |w|
  1346. w.write "foobarbaz"
  1347. w.close
  1348. end, proc do |r|
  1349. assert_raise(ArgumentError) { r.read(-1) }
  1350. assert_equal("fooba", r.read(5))
  1351. r.read(nil, s = "")
  1352. assert_equal("rbaz", s)
  1353. end)
  1354. end
  1355. def test_read_lock
  1356. with_pipe do |r, w|
  1357. s = ""
  1358. t = Thread.new { r.read(5, s) }
  1359. Thread.pass until t.stop?
  1360. assert_raise(RuntimeError) { s.clear }
  1361. w.write "foobarbaz"
  1362. w.close
  1363. assert_equal("fooba", t.value)
  1364. end
  1365. end
  1366. def test_read_with_not_empty_buffer
  1367. pipe(proc do |w|
  1368. w.write "foob"
  1369. w.close
  1370. end, proc do |r|
  1371. r.read(nil, s = "01234567")
  1372. assert_equal("foob", s)
  1373. end)
  1374. end
  1375. def test_read_buffer_error
  1376. with_pipe do |r, w|
  1377. s = ""
  1378. t = Thread.new { r.read(5, s) }
  1379. Thread.pass until t.stop?
  1380. t.kill
  1381. t.value
  1382. assert_equal("", s)
  1383. end
  1384. with_pipe do |r, w|
  1385. s = "xxx"
  1386. t = Thread.new {r.read(2, s)}
  1387. Thread.pass until t.stop?
  1388. t.kill
  1389. t.value
  1390. assert_equal("xxx", s)
  1391. end
  1392. end if /cygwin/ !~ RUBY_PLATFORM
  1393. def test_write_nonblock
  1394. pipe(proc do |w|
  1395. w.write_nonblock(1)
  1396. w.close
  1397. end, proc do |r|
  1398. assert_equal("1", r.read)
  1399. end)
  1400. end
  1401. def test_read_nonblock_with_not_empty_buffer
  1402. with_pipe {|r, w|
  1403. w.write "foob"
  1404. w.close
  1405. r.read_nonblock(5, s = "01234567")
  1406. assert_equal("foob", s)
  1407. }
  1408. end
  1409. def test_write_nonblock_simple_no_exceptions
  1410. pipe(proc do |w|
  1411. w.write_nonblock('1', exception: false)
  1412. w.close
  1413. end, proc do |r|
  1414. assert_equal("1", r.read)
  1415. end)
  1416. end
  1417. def test_read_nonblock_error
  1418. with_pipe {|r, w|
  1419. begin
  1420. r.read_nonblock 4096
  1421. rescue Errno::EWOULDBLOCK
  1422. assert_kind_of(IO::WaitReadable, $!)
  1423. end
  1424. }
  1425. with_pipe {|r, w|
  1426. begin
  1427. r.read_nonblock 4096, ""
  1428. rescue Errno::EWOULDBLOCK
  1429. assert_kind_of(IO::WaitReadable, $!)
  1430. end
  1431. }
  1432. end if have_nonblock?
  1433. def test_read_nonblock_invalid_exception
  1434. with_pipe {|r, w|
  1435. assert_raise(ArgumentError) {r.read_nonblock(4096, exception: 1)}
  1436. }
  1437. end if have_nonblock?
  1438. def test_read_nonblock_no_exceptions
  1439. skip '[ruby-core:90895] MJIT worker may leave fd open in a forked child' if RubyVM::MJIT.enabled? # TODO: consider acquiring GVL from MJIT worker.
  1440. with_pipe {|r, w|
  1441. assert_equal :wait_readable, r.read_nonblock(4096, exception: false)
  1442. w.puts "HI!"
  1443. assert_equal "HI!\n", r.read_nonblock(4096, exception: false)
  1444. w.close
  1445. assert_equal nil, r.read_nonblock(4096, exception: false)
  1446. }
  1447. end if have_nonblock?
  1448. def test_read_nonblock_with_buffer_no_exceptions
  1449. with_pipe {|r, w|
  1450. assert_equal :wait_readable, r.read_nonblock(4096, "", exception: false)
  1451. w.puts "HI!"
  1452. buf = "buf"
  1453. value = r.read_nonblock(4096, buf, exception: false)
  1454. assert_equal value, "HI!\n"
  1455. assert_same(buf, value)
  1456. w.close
  1457. assert_equal nil, r.read_nonblock(4096, "", exception: false)
  1458. }
  1459. end if have_nonblock?
  1460. def test_write_nonblock_error
  1461. with_pipe {|r, w|
  1462. begin
  1463. loop {
  1464. w.write_nonblock "a"*100000
  1465. }
  1466. rescue Errno::EWOULDBLOCK
  1467. assert_kind_of(IO::WaitWritable, $!)
  1468. end
  1469. }
  1470. end if have_nonblock?
  1471. def test_write_nonblock_invalid_exception
  1472. with_pipe {|r, w|
  1473. assert_raise(ArgumentError) {w.write_nonblock(4096, exception: 1)}
  1474. }
  1475. end if have_nonblock?
  1476. def test_write_nonblock_no_exceptions
  1477. with_pipe {|r, w|
  1478. loop {
  1479. ret = w.write_nonblock("a"*100000, exception: false)
  1480. if ret.is_a?(Symbol)
  1481. assert_equal :wait_writable, ret
  1482. break
  1483. end
  1484. }
  1485. }
  1486. end if have_nonblock?
  1487. def test_gets
  1488. pipe(proc do |w|
  1489. w.write "foobarbaz"
  1490. w.close
  1491. end, proc do |r|
  1492. assert_equal("", r.gets(0))
  1493. assert_equal("foobarbaz", r.gets(9))
  1494. end)
  1495. end
  1496. def test_close_read
  1497. ruby do |f|
  1498. f.close_read
  1499. f.write "foobarbaz"
  1500. assert_raise(IOError) { f.read }
  1501. assert_nothing_raised(IOError) {f.close_read}
  1502. assert_nothing_raised(IOError) {f.close}
  1503. assert_nothing_raised(IOError) {f.close_read}
  1504. end
  1505. end
  1506. def test_close_read_pipe
  1507. with_pipe do |r, w|
  1508. r.close_read
  1509. assert_raise(Errno::EPIPE) { w.write "foobarbaz" }
  1510. assert_nothing_raised(IOError) {r.close_read}
  1511. assert_nothing_raised(IOError) {r.close}
  1512. assert_nothing_raised(IOError) {r.close_read}
  1513. end
  1514. end
  1515. def test_write_epipe_nosync
  1516. assert_separately([], <<-"end;")
  1517. r, w = IO.pipe
  1518. r.close
  1519. w.sync = false
  1520. assert_raise(Errno::EPIPE) {
  1521. loop { w.write "a" }
  1522. }
  1523. end;
  1524. end
  1525. def test_close_read_non_readable
  1526. with_pipe do |r, w|
  1527. assert_raise(IOError) do
  1528. w.close_read
  1529. end
  1530. end
  1531. end
  1532. def test_close_write
  1533. ruby do |f|
  1534. f.write "foobarbaz"
  1535. f.close_write
  1536. assert_equal("foobarbaz", f.read)
  1537. assert_nothing_raised(IOError) {f.close_write}
  1538. assert_nothing_raised(IOError) {f.close}
  1539. assert_nothing_raised(IOError) {f.close_write}
  1540. end
  1541. end
  1542. def test_close_write_non_readable
  1543. with_pipe do |r, w|
  1544. assert_raise(IOError) do
  1545. r.close_write
  1546. end
  1547. end
  1548. end
  1549. def test_close_read_write_separately
  1550. bug = '[ruby-list:49598]'
  1551. (1..10).each do |i|
  1552. assert_nothing_raised(IOError, "#{bug} trying ##{i}") do
  1553. IO.popen(EnvUtil.rubybin, "r+") {|f|
  1554. th = Thread.new {f.close_write}
  1555. f.close_read
  1556. th.join
  1557. }
  1558. end
  1559. end
  1560. end
  1561. def test_pid
  1562. IO.pipe {|r, w|
  1563. assert_equal(nil, r.pid)
  1564. assert_equal(nil, w.pid)
  1565. }
  1566. begin
  1567. pipe = IO.popen(EnvUtil.rubybin, "r+")
  1568. pid1 = pipe.pid
  1569. pipe.puts "p $$"
  1570. pipe.close_write
  1571. pid2 = pipe.read.chomp.to_i
  1572. assert_equal(pid2, pid1)
  1573. assert_equal(pid2, pipe.pid)
  1574. ensure
  1575. pipe.close
  1576. end
  1577. assert_raise(IOError) { pipe.pid }
  1578. end
  1579. def test_pid_after_close_read
  1580. pid1 = pid2 = nil
  1581. IO.popen("exit ;", "r+") do |io|
  1582. pid1 = io.pid
  1583. io.close_read
  1584. pid2 = io.pid
  1585. end
  1586. assert_not_nil(pid1)
  1587. assert_equal(pid1, pid2)
  1588. end
  1589. def make_tempfile
  1590. t = Tempfile.new("test_io")
  1591. t.binmode
  1592. t.puts "foo"
  1593. t.puts "bar"
  1594. t.puts "baz"
  1595. t.close
  1596. if block_given?
  1597. begin
  1598. yield t
  1599. ensure
  1600. t.close(true)
  1601. end
  1602. else
  1603. t
  1604. end
  1605. end
  1606. def test_set_lineno
  1607. make_tempfile {|t|
  1608. assert_separately(["-", t.path], <<-SRC)
  1609. open(ARGV[0]) do |f|
  1610. assert_equal(0, $.)
  1611. f.gets; assert_equal(1, $.)
  1612. f.gets; assert_equal(2, $.)
  1613. f.lineno = 1000; assert_equal(2, $.)
  1614. f.gets; assert_equal(1001, $.)
  1615. f.gets; assert_equal(1001, $.)
  1616. f.rewind; assert_equal(1001, $.)
  1617. f.gets; assert_equal(1, $.)
  1618. f.gets; assert_equal(2, $.)
  1619. f.gets; assert_equal(3, $.)
  1620. f.gets; assert_equal(3, $.)
  1621. end
  1622. SRC
  1623. }
  1624. end
  1625. def test_set_lineno_gets
  1626. pipe(proc do |w|
  1627. w.puts "foo"
  1628. w.puts "bar"
  1629. w.puts "baz"
  1630. w.close
  1631. end, proc do |r|
  1632. r.gets; assert_equal(1, $.)
  1633. r.gets; assert_equal(2, $.)
  1634. r.lineno = 1000; assert_equal(2, $.)
  1635. r.gets; assert_equal(1001, $.)
  1636. r.gets; assert_equal(1001, $.)
  1637. end)
  1638. end
  1639. def test_set_lineno_readline
  1640. pipe(proc do |w|
  1641. w.puts "foo"
  1642. w.puts "bar"
  1643. w.puts "baz"
  1644. w.close
  1645. end, proc do |r|
  1646. r.readline; assert_equal(1, $.)
  1647. r.readline; assert_equal(2, $.)
  1648. r.lineno = 1000; assert_equal(2, $.)
  1649. r.readline; assert_equal(1001, $.)
  1650. assert_raise(EOFError) { r.readline }
  1651. end)
  1652. end
  1653. def test_each_char
  1654. pipe(proc do |w|
  1655. w.puts "foo"
  1656. w.puts "bar"
  1657. w.puts "baz"
  1658. w.close
  1659. end, proc do |r|
  1660. a = []
  1661. r.each_char {|c| a << c }
  1662. assert_equal(%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"], a)
  1663. end)
  1664. end
  1665. def test_lines
  1666. verbose, $VERBOSE = $VERBOSE, nil
  1667. pipe(proc do |w|
  1668. w.puts "foo"
  1669. w.puts "bar"
  1670. w.puts "baz"
  1671. w.close
  1672. end, proc do |r|
  1673. e = nil
  1674. assert_warn(/deprecated/) {
  1675. e = r.lines
  1676. }
  1677. assert_equal("foo\n", e.next)
  1678. assert_equal("bar\n", e.next)
  1679. assert_equal("baz\n", e.next)
  1680. assert_raise(StopIteration) { e.next }
  1681. end)
  1682. ensure
  1683. $VERBOSE = verbose
  1684. end
  1685. def test_bytes
  1686. verbose, $VERBOSE = $VERBOSE, nil
  1687. pipe(proc do |w|
  1688. w.binmode
  1689. w.puts "foo"
  1690. w.puts "bar"
  1691. w.puts "baz"
  1692. w.close
  1693. end, proc do |r|
  1694. e = nil
  1695. assert_warn(/deprecated/) {
  1696. e = r.bytes
  1697. }
  1698. (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
  1699. assert_equal(c.ord, e.next)
  1700. end
  1701. assert_raise(StopIteration) { e.next }
  1702. end)
  1703. ensure
  1704. $VERBOSE = verbose
  1705. end
  1706. def test_chars
  1707. verbose, $VERBOSE = $VERBOSE, nil
  1708. pipe(proc do |w|
  1709. w.puts "foo"
  1710. w.puts "bar"
  1711. w.puts "baz"
  1712. w.close
  1713. end, proc do |r|
  1714. e = nil
  1715. assert_warn(/deprecated/) {
  1716. e = r.chars
  1717. }
  1718. (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
  1719. assert_equal(c, e.next)
  1720. end
  1721. assert_raise(StopIteration) { e.next }
  1722. end)
  1723. ensure
  1724. $VERBOSE = verbose
  1725. end
  1726. def test_readbyte
  1727. pipe(proc do |w|
  1728. w.binmode
  1729. w.puts "foo"
  1730. w.puts "bar"
  1731. w.puts "baz"
  1732. w.close
  1733. end, proc do |r|
  1734. r.binmode
  1735. (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
  1736. assert_equal(c.ord, r.readbyte)
  1737. end
  1738. assert_raise(EOFError) { r.readbyte }
  1739. end)
  1740. end
  1741. def test_readchar
  1742. pipe(proc do |w|
  1743. w.puts "foo"
  1744. w.puts "bar"
  1745. w.puts "baz"
  1746. w.close
  1747. end, proc do |r|
  1748. (%w(f o o) + ["\n"] + %w(b a r) + ["\n"] + %w(b a z) + ["\n"]).each do |c|
  1749. assert_equal(c, r.readchar)
  1750. end
  1751. assert_raise(EOFError) { r.readchar }
  1752. end)
  1753. end
  1754. def test_close_on_exec
  1755. ruby do |f|
  1756. assert_equal(true, f.close_on_exec?)
  1757. f.close_on_exec = false
  1758. assert_equal(false, f.close_on_exec?)
  1759. f.close_on_exec = true
  1760. assert_equal(true, f.close_on_exec?)
  1761. f.close_on_exec = false
  1762. assert_equal(false, f.close_on_exec?)
  1763. end
  1764. with_pipe do |r, w|
  1765. assert_equal(true, r.close_on_exec?)
  1766. r.close_on_exec = false
  1767. assert_equal(false, r.close_on_exec?)
  1768. r.close_on_exec = true
  1769. assert_equal(true, r.close_on_exec?)
  1770. r.close_on_exec = false
  1771. assert_equal(false, r.close_on_exec?)
  1772. assert_equal(true, w.close_on_exec?)
  1773. w.close_on_exec = false
  1774. assert_equal(false, w.close_on_exec?)
  1775. w.close_on_exec = true
  1776. assert_equal(true, w.close_on_exec?)
  1777. w.close_on_exec = false
  1778. assert_equal(false, w.close_on_exec?)
  1779. end
  1780. end if have_close_on_exec?
  1781. def test_pos
  1782. make_tempfile {|t|
  1783. open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f|
  1784. f.write "Hello"
  1785. assert_equal(5, f.pos)
  1786. end
  1787. open(t.path, IO::RDWR|IO::CREAT|IO::TRUNC, 0600) do |f|
  1788. f.sync = true
  1789. f.read
  1790. f.write "Hello"
  1791. assert_equal(5, f.pos)
  1792. end
  1793. }
  1794. end
  1795. def test_pos_with_getc
  1796. _bug6179 = '[ruby-core:43497]'
  1797. make_tempfile {|t|
  1798. ["", "t", "b"].each do |mode|
  1799. open(t.path, "w#{mode}") do |f|
  1800. f.write "0123456789\n"
  1801. end
  1802. open(t.path, "r#{mode}") do |f|
  1803. assert_equal 0, f.pos, "mode=r#{mode}"
  1804. assert_equal '0', f.getc, "mode=r#{mode}"
  1805. assert_equal 1, f.pos, "mode=r#{mode}"
  1806. assert_equal '1', f.getc, "mode=r#{mode}"
  1807. assert_equal 2, f.pos, "mode=r#{mode}"
  1808. assert_equal '2', f.getc, "mode=r#{mode}"
  1809. assert_equal 3, f.pos, "mode=r#{mode}"
  1810. assert_equal '3', f.getc, "mode=r#{mode}"
  1811. assert_equal 4, f.pos, "mode=r#{mode}"
  1812. assert_equal '4', f.getc, "mode=r#{mode}"
  1813. end
  1814. end
  1815. }
  1816. end
  1817. def can_seek_data(f)
  1818. if /linux/ =~ RUBY_PLATFORM
  1819. require "-test-/file"
  1820. # lseek(2)
  1821. case Bug::File::Fs.fsname(f.path)
  1822. when "btrfs"
  1823. return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,1]) >= 0
  1824. when "ocfs"
  1825. return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,2]) >= 0
  1826. when "xfs"
  1827. return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,5]) >= 0
  1828. when "ext4"
  1829. return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,8]) >= 0
  1830. when "tmpfs"
  1831. return true if (Etc.uname[:release].split('.').map(&:to_i) <=> [3,8]) >= 0
  1832. end
  1833. end
  1834. false
  1835. end
  1836. def test_seek
  1837. make_tempfile {|t|
  1838. open(t.path) { |f|
  1839. f.seek(9)
  1840. assert_equal("az\n", f.read)
  1841. }
  1842. open(t.path) { |f|
  1843. f.seek(9, IO::SEEK_SET)
  1844. assert_equal("az\n", f.read)
  1845. }
  1846. open(t.path) { |f|
  1847. f.seek(-4, IO::SEEK_END)
  1848. assert_equal("baz\n", f.read)
  1849. }
  1850. open(t.path) { |f|
  1851. assert_equal("foo\n", f.gets)
  1852. f.seek(2, IO::SEEK_CUR)
  1853. assert_equal("r\nbaz\n", f.read)
  1854. }
  1855. if defined?(IO::SEEK_DATA)
  1856. open(t.path) { |f|
  1857. break unless can_seek_data(f)
  1858. assert_equal("foo\n", f.gets)
  1859. f.seek(0, IO::SEEK_DATA)
  1860. assert_equal("foo\nbar\nbaz\n", f.read)
  1861. }
  1862. open(t.path, 'r+') { |f|
  1863. break unless can_seek_data(f)
  1864. f.seek(100*1024, IO::SEEK_SET)
  1865. f.print("zot\n")
  1866. f.seek(50*1024, IO::SEEK_DATA)
  1867. assert_operator(f.pos, :>=, 50*1024)
  1868. assert_match(/\A\0*zot\n\z/, f.read)
  1869. }
  1870. end
  1871. if defined?(IO::SEEK_HOLE)
  1872. open(t.path) { |f|
  1873. break unless can_seek_dat

Large files files are truncated, but you can click here to view the full file