Skip to content

Commit e6fcb41

Browse files
committed
Add specs for IO::Buffer#free, #resize and #transfer
1 parent c94c26e commit e6fcb41

File tree

5 files changed

+381
-9
lines changed

5 files changed

+381
-9
lines changed

core/io/buffer/free_spec.rb

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
require_relative '../../../spec_helper'
2+
3+
describe "IO::Buffer#free" do
4+
context "with a buffer created with .new" do
5+
it "frees internal memory and nullifies the buffer" do
6+
buffer = IO::Buffer.new(4)
7+
buffer.free
8+
buffer.null?.should be_true
9+
end
10+
11+
it "frees mapped memory and nullifies the buffer" do
12+
buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
13+
buffer.free
14+
buffer.null?.should be_true
15+
end
16+
end
17+
18+
context "with a file-backed buffer created with .map" do
19+
it "frees mapped memory and nullifies the buffer" do
20+
File.open(__FILE__, "r") do |file|
21+
buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
22+
buffer.free
23+
buffer.null?.should be_true
24+
end
25+
end
26+
end
27+
28+
context "with a String-backed buffer created with .for" do
29+
context "without a block" do
30+
it "disassociates the buffer from the string and nullifies the buffer" do
31+
string = +"test"
32+
buffer = IO::Buffer.for(string)
33+
# Read-only buffer, can't modify the string.
34+
buffer.free
35+
buffer.null?.should be_true
36+
end
37+
end
38+
39+
context "with a block" do
40+
it "disassociates the buffer from the string and nullifies the buffer" do
41+
string = +"test"
42+
IO::Buffer.for(string) do |buffer|
43+
buffer.set_string("meat")
44+
buffer.free
45+
buffer.null?.should be_true
46+
end
47+
string.should == "meat"
48+
end
49+
end
50+
end
51+
52+
ruby_version_is "3.3" do
53+
context "with a String-backed buffer created with .string" do
54+
it "disassociates the buffer from the string and nullifies the buffer" do
55+
string =
56+
IO::Buffer.string(4) do |buffer|
57+
buffer.set_string("meat")
58+
buffer.free
59+
buffer.null?.should be_true
60+
end
61+
string.should == "meat"
62+
end
63+
end
64+
end
65+
66+
it "can be called repeatedly without an error" do
67+
buffer = IO::Buffer.new(4)
68+
buffer.free
69+
buffer.null?.should be_true
70+
buffer.free
71+
buffer.null?.should be_true
72+
end
73+
74+
it "is disallowed while locked, raising IO::Buffer::LockedError" do
75+
buffer = IO::Buffer.new(4)
76+
buffer.locked do
77+
-> { buffer.free }.should raise_error(IO::Buffer::LockedError, "Buffer is locked!")
78+
end
79+
buffer.free
80+
buffer.null?.should be_true
81+
end
82+
83+
context "with a slice of a buffer" do
84+
it "nullifies the slice, not touching the buffer" do
85+
buffer = IO::Buffer.new(4)
86+
slice = buffer.slice(0, 2)
87+
88+
buffer.set_string("test")
89+
slice.set_string("ea")
90+
slice.free
91+
slice.null?.should be_true
92+
buffer.null?.should be_false
93+
buffer.get_string.should == "east"
94+
95+
buffer.free
96+
end
97+
98+
it "nullifies buffer, invalidating the slice" do
99+
buffer = IO::Buffer.new(4)
100+
slice = buffer.slice(0, 2)
101+
buffer.free
102+
103+
slice.null?.should be_false
104+
slice.valid?.should be_false
105+
-> { slice.get_string }.should raise_error(IO::Buffer::InvalidatedError, "Buffer has been invalidated!")
106+
end
107+
end
108+
end

core/io/buffer/locked_spec.rb

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,13 @@
1313
end
1414
end
1515

16-
it "disallows freeing while locked, raising IO::Buffer::LockedError" do
16+
it "disallows operations changing buffer itself, raising IO::Buffer::LockedError" do
1717
@buffer = IO::Buffer.new(4)
1818
@buffer.locked do
19-
-> { @buffer.free }.should raise_error(IO::Buffer::LockedError, "Buffer is locked!")
20-
end
21-
end
22-
23-
it "disallows resizing while locked, raising IO::Buffer::LockedError" do
24-
@buffer = IO::Buffer.new(4)
25-
@buffer.locked do
26-
-> { @buffer.resize(8) }.should raise_error(IO::Buffer::LockedError, "Cannot resize locked buffer!")
19+
# See specs of individual methods for error messages.
20+
-> { @buffer.free }.should raise_error(IO::Buffer::LockedError)
21+
-> { @buffer.resize(8) }.should raise_error(IO::Buffer::LockedError)
22+
-> { @buffer.transfer }.should raise_error(IO::Buffer::LockedError)
2723
end
2824
end
2925

core/io/buffer/resize_spec.rb

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
require_relative '../../../spec_helper'
2+
3+
describe "IO::Buffer#resize" do
4+
after :each do
5+
@buffer&.free
6+
@buffer = nil
7+
end
8+
9+
context "with a buffer created with .new" do
10+
it "resizes internal buffer, preserving type" do
11+
@buffer = IO::Buffer.new(4)
12+
@buffer.resize(IO::Buffer::PAGE_SIZE)
13+
@buffer.size.should == IO::Buffer::PAGE_SIZE
14+
@buffer.internal?.should be_true
15+
@buffer.mapped?.should be_false
16+
end
17+
18+
platform_is :linux do
19+
it "resizes mapped buffer, preserving type" do
20+
@buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::MAPPED)
21+
@buffer.resize(4)
22+
@buffer.size.should == 4
23+
@buffer.internal?.should be_false
24+
@buffer.mapped?.should be_true
25+
end
26+
end
27+
28+
platform_is_not :linux do
29+
it "resizes mapped buffer, changing type to internal" do
30+
@buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::MAPPED)
31+
@buffer.resize(4)
32+
@buffer.size.should == 4
33+
@buffer.internal?.should be_true
34+
@buffer.mapped?.should be_false
35+
end
36+
end
37+
end
38+
39+
context "with a file-backed buffer created with .map" do
40+
it "disallows resizing shared buffer, raising IO::Buffer::AccessError" do
41+
File.open(__FILE__, "r+") do |file|
42+
@buffer = IO::Buffer.map(file)
43+
-> { @buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
44+
end
45+
end
46+
47+
ruby_version_is "3.3" do
48+
it "resizes private buffer, discarding excess contents" do
49+
File.open(__FILE__, "r") do |file|
50+
@buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
51+
@buffer.resize(10)
52+
@buffer.size.should == 10
53+
@buffer.get_string.should == "require_re"
54+
@buffer.resize(12)
55+
@buffer.size.should == 12
56+
@buffer.get_string.should == "require_re\0\0"
57+
end
58+
end
59+
end
60+
end
61+
62+
context "with a String-backed buffer created with .for" do
63+
context "without a block" do
64+
it "disallows resizing, raising IO::Buffer::AccessError" do
65+
@buffer = IO::Buffer.for(+"test")
66+
-> { @buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
67+
end
68+
end
69+
70+
context "with a block" do
71+
it "disallows resizing, raising IO::Buffer::AccessError" do
72+
IO::Buffer.for(+'test') do |buffer|
73+
-> { buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
74+
end
75+
end
76+
end
77+
end
78+
79+
ruby_version_is "3.3" do
80+
context "with a String-backed buffer created with .string" do
81+
it "disallows resizing, raising IO::Buffer::AccessError" do
82+
IO::Buffer.string(4) do |buffer|
83+
-> { buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
84+
end
85+
end
86+
end
87+
end
88+
89+
context "with a null buffer" do
90+
it "allows resizing a 0-sized buffer, creating a regular buffer according to new size" do
91+
@buffer = IO::Buffer.new(0)
92+
@buffer.resize(IO::Buffer::PAGE_SIZE)
93+
@buffer.size.should == IO::Buffer::PAGE_SIZE
94+
@buffer.internal?.should be_false
95+
@buffer.mapped?.should be_true
96+
end
97+
98+
it "allows resizing after a free, creating a regular buffer according to new size" do
99+
@buffer = IO::Buffer.for("test")
100+
@buffer.free
101+
@buffer.resize(10)
102+
@buffer.size.should == 10
103+
@buffer.internal?.should be_true
104+
@buffer.mapped?.should be_false
105+
end
106+
end
107+
108+
it "allows resizing to 0, freeing memory" do
109+
@buffer = IO::Buffer.new(4)
110+
@buffer.resize(0)
111+
@buffer.null?.should be_true
112+
end
113+
114+
it "can be called repeatedly" do
115+
@buffer = IO::Buffer.new(4)
116+
@buffer.resize(10)
117+
@buffer.resize(27)
118+
@buffer.resize(1)
119+
@buffer.size.should == 1
120+
end
121+
122+
it "always clears extra memory" do
123+
@buffer = IO::Buffer.new(4)
124+
@buffer.set_string("test")
125+
# This should not cause a re-allocation, just a technical resizing,
126+
# even with very aggressive memory allocation.
127+
@buffer.resize(2)
128+
@buffer.resize(4)
129+
@buffer.get_string.should == "te\0\0"
130+
end
131+
132+
it "is disallowed while locked, raising IO::Buffer::LockedError" do
133+
@buffer = IO::Buffer.new(4)
134+
@buffer.locked do
135+
-> { @buffer.resize(10) }.should raise_error(IO::Buffer::LockedError, "Cannot resize locked buffer!")
136+
end
137+
end
138+
139+
context "with a slice of a buffer" do
140+
# Current behavior of slice resizing seems unintended (it's undocumented, too).
141+
# It either creates a completely new buffer, or breaks the slice on size 0.
142+
it "needs to be reviewed for spec completeness"
143+
end
144+
end

core/io/buffer/shared/null_and_empty.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,10 @@
5050
@buffer.resize(0)
5151
@buffer.send(@method).should be_true
5252
end
53+
54+
it "is true for a buffer whose memory was transferred" do
55+
buffer = IO::Buffer.new(1)
56+
@buffer = buffer.transfer
57+
buffer.send(@method).should be_true
58+
end
5359
end

0 commit comments

Comments
 (0)