1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
# encoding: utf-8
require_relative '../fixtures/classes'
describe :io_write, shared: true do
before :each do
@filename = tmp("IO_syswrite_file") + $$.to_s
File.open(@filename, "w") do |file|
file.send(@method, "012345678901234567890123456789")
end
@file = File.open(@filename, "r+")
@readonly_file = File.open(@filename)
end
after :each do
@readonly_file.close if @readonly_file
@file.close if @file
rm_r @filename
end
it "coerces the argument to a string using to_s" do
(obj = mock('test')).should_receive(:to_s).and_return('a string')
@file.send(@method, obj)
end
it "checks if the file is writable if writing more than zero bytes" do
-> { @readonly_file.send(@method, "abcde") }.should raise_error(IOError)
end
it "returns the number of bytes written" do
written = @file.send(@method, "abcde")
written.should == 5
end
it "invokes to_s on non-String argument" do
data = "abcdefgh9876"
(obj = mock(data)).should_receive(:to_s).and_return(data)
@file.send(@method, obj)
@file.seek(0)
@file.read(data.size).should == data
end
it "writes all of the string's bytes without buffering if mode is sync" do
@file.sync = true
written = @file.send(@method, "abcde")
written.should == 5
File.open(@filename) do |file|
file.read(10).should == "abcde56789"
end
end
it "does not warn if called after IO#read" do
@file.read(5)
-> { @file.send(@method, "fghij") }.should_not complain
end
it "writes to the current position after IO#read" do
@file.read(5)
@file.send(@method, "abcd")
@file.rewind
@file.read.should == "01234abcd901234567890123456789"
end
it "advances the file position by the count of given bytes" do
@file.send(@method, "abcde")
@file.read(10).should == "5678901234"
end
it "raises IOError on closed stream" do
-> { IOSpecs.closed_io.send(@method, "hello") }.should raise_error(IOError)
end
describe "on a pipe" do
before :each do
@r, @w = IO.pipe
end
after :each do
@r.close
@w.close
end
it "writes the given String to the pipe" do
@w.send(@method, "foo")
@w.close
@r.read.should == "foo"
end
# [ruby-core:90895] RJIT worker may leave fd open in a forked child.
# For instance, RJIT creates a worker before @r.close with fork(), @r.close happens,
# and the RJIT worker keeps the pipe open until the worker execve().
# TODO: consider acquiring GVL from RJIT worker.
guard_not -> { defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? } do
it "raises Errno::EPIPE if the read end is closed and does not die from SIGPIPE" do
@r.close
-> { @w.send(@method, "foo") }.should raise_error(Errno::EPIPE, /Broken pipe/)
end
end
end
end
describe :io_write_transcode, shared: true do
before :each do
@transcode_filename = tmp("io_write_transcode")
end
after :each do
rm_r @transcode_filename
end
it "transcodes the given string when the external encoding is set and neither is BINARY" do
utf8_str = "hello"
File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
file.external_encoding.should == Encoding::UTF_16BE
file.send(@method, utf8_str)
end
result = File.binread(@transcode_filename)
expected = [0, 104, 0, 101, 0, 108, 0, 108, 0, 111] # UTF-16BE bytes for "hello"
result.bytes.should == expected
end
it "transcodes the given string when the external encoding is set and the string encoding is BINARY" do
str = "été".b
File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
file.external_encoding.should == Encoding::UTF_16BE
-> { file.send(@method, str) }.should raise_error(Encoding::UndefinedConversionError)
end
end
end
describe :io_write_no_transcode, shared: true do
before :each do
@transcode_filename = tmp("io_write_no_transcode")
end
after :each do
rm_r @transcode_filename
end
it "does not transcode the given string even when the external encoding is set" do
utf8_str = "hello"
File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
file.external_encoding.should == Encoding::UTF_16BE
file.send(@method, utf8_str)
end
result = File.binread(@transcode_filename)
result.bytes.should == utf8_str.bytes
end
end
|