Skip to content

Commit fb299b4

Browse files
committed
WIP Add spec for IO::Buffer.map
1 parent d770427 commit fb299b4

File tree

2 files changed

+336
-0
lines changed

2 files changed

+336
-0
lines changed
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
require_relative '../../../spec_helper'
2+
3+
describe "IO::Buffer.map" do
4+
after :each do
5+
@buffer&.free
6+
@buffer = nil
7+
@file&.close
8+
@file = nil
9+
end
10+
11+
def open_fixture
12+
File.open("#{__dir__}/../fixtures/read_text.txt", "r+")
13+
end
14+
15+
it "creates a new buffer mapped from a file" do
16+
@file = open_fixture
17+
@buffer = IO::Buffer.map(@file)
18+
19+
@buffer.size.should == 9
20+
@buffer.get_string.force_encoding(Encoding::UTF_8).should == "abcâdef\n"
21+
end
22+
23+
ruby_version_is ""..."3.3" do
24+
it "creates a buffer with default state and expected flags" do
25+
@file = open_fixture
26+
@buffer = IO::Buffer.map(@file)
27+
28+
@buffer.should_not.internal?
29+
@buffer.should.mapped?
30+
@buffer.should.external?
31+
32+
@buffer.should_not.empty?
33+
@buffer.should_not.null?
34+
35+
@buffer.should.shared?
36+
@buffer.should_not.readonly?
37+
38+
@buffer.should_not.locked?
39+
@buffer.should.valid?
40+
end
41+
end
42+
43+
ruby_version_is "3.3" do
44+
it "creates a buffer with default state and expected flags" do
45+
@file = open_fixture
46+
@buffer = IO::Buffer.map(@file)
47+
48+
@buffer.should_not.internal?
49+
@buffer.should.mapped?
50+
@buffer.should.external?
51+
52+
@buffer.should_not.empty?
53+
@buffer.should_not.null?
54+
55+
@buffer.should.shared?
56+
@buffer.should_not.private?
57+
@buffer.should_not.readonly?
58+
59+
@buffer.should_not.locked?
60+
@buffer.should.valid?
61+
end
62+
end
63+
64+
context "with an empty file" do
65+
it "raises Errno::EINVAL" do
66+
-> { IO::Buffer.map(File.open("#{__dir__}/../fixtures/empty.txt", "r+")) }.should raise_error(Errno::EINVAL)
67+
end
68+
end
69+
70+
context "with size argument" do
71+
it "limits the buffer to the specified size in bytes, starting from the start of the file" do
72+
@file = open_fixture
73+
@buffer = IO::Buffer.map(@file, 4)
74+
75+
@buffer.size.should == 4
76+
@buffer.get_string.force_encoding(Encoding::UTF_8).should == "abc\xC3"
77+
end
78+
79+
it "maps the whole file if size is nil" do
80+
@file = open_fixture
81+
@buffer = IO::Buffer.map(@file, nil)
82+
83+
@buffer.size.should == 9
84+
end
85+
86+
it "raises Errno::EINVAL if size is 0" do
87+
@file = open_fixture
88+
-> { IO::Buffer.map(@file, 0) }.should raise_error(Errno::EINVAL)
89+
end
90+
91+
it "raises TypeError if size is not an Integer or nil" do
92+
@file = open_fixture
93+
-> { IO::Buffer.map(@file, "10") }.should raise_error(TypeError, "not an Integer")
94+
-> { IO::Buffer.map(@file, 10.0) }.should raise_error(TypeError, "not an Integer")
95+
end
96+
97+
it "raises ArgumentError if size is negative" do
98+
@file = open_fixture
99+
-> { IO::Buffer.map(@file, -1) }.should raise_error(ArgumentError, "Size can't be negative!")
100+
end
101+
end
102+
103+
context "with size and offset arguments" do
104+
context "if offset is a multiple of page size" do
105+
it "maps the specified length starting from the offset" do
106+
@file = File.open("#{__dir__}/fixtures/big_file.txt", "r+")
107+
@buffer = IO::Buffer.map(@file, 14, IO::Buffer::PAGE_SIZE)
108+
109+
@buffer.size.should == 14
110+
@buffer.get_string.force_encoding(Encoding::UTF_8).should == "-> { IO::Buffe"
111+
end
112+
113+
it "maps the rest of the file if size is nil" do
114+
@file = File.open("#{__dir__}/fixtures/big_file.txt", "r+")
115+
@buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE * 2)
116+
117+
@buffer.size.should == 5895 # BUG: this is wrong
118+
# @buffer.get_string.force_encoding(Encoding::UTF_8).should == "-> { IO::Buffe"
119+
end
120+
end
121+
122+
it "maps the file from the start if offset is 0" do
123+
@file = open_fixture
124+
@buffer = IO::Buffer.map(@file, 4, 0)
125+
126+
@buffer.size.should == 4
127+
@buffer.get_string.force_encoding(Encoding::UTF_8).should == "abc\xC3"
128+
end
129+
130+
it "raises TypeError if offset is not convertible to Integer" do
131+
@file = open_fixture
132+
-> { IO::Buffer.map(@file, 4, "3") }.should raise_error(TypeError, "no implicit conversion of String into Integer")
133+
end
134+
135+
it "raises Errno::EINVAL if offset is not an Integer" do
136+
@file = open_fixture
137+
-> { IO::Buffer.map(@file, 4, 3.0) }.should raise_error(Errno::EINVAL)
138+
end
139+
140+
it "raises Errno::EINVAL if offset is negative" do
141+
@file = open_fixture
142+
-> { IO::Buffer.map(@file, 4, -1) }.should raise_error(Errno::EINVAL)
143+
end
144+
end
145+
146+
context "with size and flags arguments" do
147+
it "forces mapped buffer with IO::Buffer::MAPPED flag" do
148+
@buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE - 1, IO::Buffer::MAPPED)
149+
@buffer.should.mapped?
150+
@buffer.should_not.internal?
151+
@buffer.should_not.empty?
152+
end
153+
154+
it "forces internal buffer with IO::Buffer::INTERNAL flag" do
155+
@buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::INTERNAL)
156+
@buffer.should.internal?
157+
@buffer.should_not.mapped?
158+
@buffer.should_not.empty?
159+
end
160+
161+
it "raises IO::Buffer::AllocationError if neither IO::Buffer::MAPPED nor IO::Buffer::INTERNAL is given" do
162+
-> { IO::Buffer.new(10, IO::Buffer::READONLY) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!")
163+
-> { IO::Buffer.new(10, 0) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!")
164+
end
165+
166+
ruby_version_is "3.3" do
167+
it "raises ArgumentError if flags is negative" do
168+
-> { IO::Buffer.new(10, -1) }.should raise_error(ArgumentError, "Flags can't be negative!")
169+
end
170+
end
171+
172+
ruby_version_is ""..."3.3" do
173+
it "raises IO::Buffer::AllocationError with non-Integer flags" do
174+
-> { IO::Buffer.new(10, 0.0) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!")
175+
end
176+
end
177+
178+
ruby_version_is "3.3" do
179+
it "raises TypeError with non-Integer flags" do
180+
-> { IO::Buffer.new(10, 0.0) }.should raise_error(TypeError, "not an Integer")
181+
end
182+
end
183+
end
184+
end

core/io/buffer/map_spec.rb

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
require_relative '../../../spec_helper'
2+
3+
describe "IO::Buffer.map" do
4+
after :each do
5+
@buffer&.free
6+
@buffer = nil
7+
@file&.close
8+
@file = nil
9+
end
10+
11+
def open_fixture
12+
File.open("#{__dir__}/../fixtures/read_text.txt", "r+")
13+
end
14+
15+
it "creates a new buffer mapped from a file" do
16+
@file = open_fixture
17+
@buffer = IO::Buffer.map(@file)
18+
19+
@buffer.size.should == 9
20+
@buffer.get_string.force_encoding(Encoding::UTF_8).should == "abcâdef\n"
21+
end
22+
23+
ruby_version_is ""..."3.3" do
24+
it "creates a buffer with default state and expected flags" do
25+
@file = open_fixture
26+
@buffer = IO::Buffer.map(@file)
27+
28+
@buffer.should_not.internal?
29+
@buffer.should.mapped?
30+
@buffer.should.external?
31+
32+
@buffer.should_not.empty?
33+
@buffer.should_not.null?
34+
35+
@buffer.should.shared?
36+
@buffer.should_not.readonly?
37+
38+
@buffer.should_not.locked?
39+
@buffer.should.valid?
40+
end
41+
end
42+
43+
ruby_version_is "3.3" do
44+
it "creates a buffer with default state and expected flags" do
45+
@file = open_fixture
46+
@buffer = IO::Buffer.map(@file)
47+
48+
@buffer.should_not.internal?
49+
@buffer.should.mapped?
50+
@buffer.should.external?
51+
52+
@buffer.should_not.empty?
53+
@buffer.should_not.null?
54+
55+
@buffer.should.shared?
56+
@buffer.should_not.private?
57+
@buffer.should_not.readonly?
58+
59+
@buffer.should_not.locked?
60+
@buffer.should.valid?
61+
end
62+
end
63+
64+
context "with an empty file" do
65+
it "raises Errno::EINVAL" do
66+
@file = File.open("#{__dir__}/../fixtures/empty.txt", "r+")
67+
-> { IO::Buffer.map(@file) }.should raise_error(Errno::EINVAL)
68+
end
69+
end
70+
71+
context "with size argument" do
72+
it "limits the buffer to the specified size in bytes, starting from the start of the file" do
73+
@file = open_fixture
74+
@buffer = IO::Buffer.map(@file, 4)
75+
76+
@buffer.size.should == 4
77+
@buffer.get_string.force_encoding(Encoding::UTF_8).should == "abc\xC3"
78+
end
79+
80+
it "maps the whole file if size is nil" do
81+
@file = open_fixture
82+
@buffer = IO::Buffer.map(@file, nil)
83+
84+
@buffer.size.should == 9
85+
end
86+
87+
it "raises Errno::EINVAL if size is 0" do
88+
@file = open_fixture
89+
-> { IO::Buffer.map(@file, 0) }.should raise_error(Errno::EINVAL)
90+
end
91+
92+
it "raises TypeError if size is not an Integer or nil" do
93+
@file = open_fixture
94+
-> { IO::Buffer.map(@file, "10") }.should raise_error(TypeError, "not an Integer")
95+
-> { IO::Buffer.map(@file, 10.0) }.should raise_error(TypeError, "not an Integer")
96+
end
97+
98+
it "raises ArgumentError if size is negative" do
99+
@file = open_fixture
100+
-> { IO::Buffer.map(@file, -1) }.should raise_error(ArgumentError, "Size can't be negative!")
101+
end
102+
end
103+
104+
context "with size and offset arguments" do
105+
context "if offset is a multiple of page size" do
106+
it "maps the specified length starting from the offset" do
107+
@file = File.open("#{__dir__}/fixtures/big_file.txt", "r+")
108+
@buffer = IO::Buffer.map(@file, 14, IO::Buffer::PAGE_SIZE)
109+
110+
@buffer.size.should == 14
111+
@buffer.get_string(0, 14).force_encoding(Encoding::UTF_8).should == "-> { IO::Buffe"
112+
end
113+
114+
# A second mapping just doesn't work?
115+
it "maps the rest of the file if size is nil" do
116+
@file = File.open("#{__dir__}/fixtures/big_file.txt", "r+")
117+
@buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
118+
119+
@buffer.size.should == 5895 # BUG: why is this the total size?
120+
@buffer.get_string(0, 16).force_encoding(Encoding::UTF_8).should == "-> { IO::Buffer."
121+
end
122+
end
123+
124+
it "raises Errno::EINVAL if offset is not a multiple of page size" do
125+
@file = open_fixture
126+
-> { IO::Buffer.map(@file, 4, IO::Buffer::PAGE_SIZE / 2) }.should raise_error(Errno::EINVAL)
127+
end
128+
129+
it "maps the file from the start if offset is 0" do
130+
@file = open_fixture
131+
@buffer = IO::Buffer.map(@file, 4, 0)
132+
133+
@buffer.size.should == 4
134+
@buffer.get_string.force_encoding(Encoding::UTF_8).should == "abc\xC3"
135+
end
136+
137+
it "raises TypeError if offset is not convertible to Integer" do
138+
@file = open_fixture
139+
-> { IO::Buffer.map(@file, 4, "3") }.should raise_error(TypeError, "no implicit conversion of String into Integer")
140+
end
141+
142+
it "raises Errno::EINVAL if offset is not an Integer" do
143+
@file = open_fixture
144+
-> { IO::Buffer.map(@file, 4, 3.0) }.should raise_error(Errno::EINVAL)
145+
end
146+
147+
it "raises Errno::EINVAL if offset is negative" do
148+
@file = open_fixture
149+
-> { IO::Buffer.map(@file, 4, -1) }.should raise_error(Errno::EINVAL)
150+
end
151+
end
152+
end

0 commit comments

Comments
 (0)