nio4r 2.0.0.pre-java → 2.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.rubocop.yml +31 -38
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +9 -19
  6. data/CHANGES.md +94 -42
  7. data/Gemfile +11 -3
  8. data/Guardfile +10 -0
  9. data/LICENSE.txt +1 -1
  10. data/README.md +43 -136
  11. data/Rakefile +2 -0
  12. data/examples/echo_server.rb +1 -0
  13. data/ext/libev/Changes +9 -13
  14. data/ext/libev/ev.c +100 -74
  15. data/ext/libev/ev.h +4 -9
  16. data/ext/libev/ev_epoll.c +6 -3
  17. data/ext/libev/ev_kqueue.c +8 -4
  18. data/ext/libev/ev_poll.c +6 -3
  19. data/ext/libev/ev_port.c +8 -4
  20. data/ext/libev/ev_select.c +4 -2
  21. data/ext/nio4r/bytebuffer.c +265 -257
  22. data/ext/nio4r/extconf.rb +3 -9
  23. data/ext/nio4r/monitor.c +93 -46
  24. data/ext/nio4r/nio4r.h +6 -16
  25. data/ext/nio4r/org/nio4r/ByteBuffer.java +193 -209
  26. data/ext/nio4r/org/nio4r/Monitor.java +164 -0
  27. data/ext/nio4r/org/nio4r/Nio4r.java +13 -391
  28. data/ext/nio4r/org/nio4r/Selector.java +278 -0
  29. data/ext/nio4r/selector.c +72 -64
  30. data/lib/nio.rb +3 -3
  31. data/lib/nio/bytebuffer.rb +179 -132
  32. data/lib/nio/monitor.rb +64 -4
  33. data/lib/nio/selector.rb +36 -13
  34. data/lib/nio/version.rb +1 -1
  35. data/nio4r.gemspec +25 -19
  36. data/spec/nio/acceptables_spec.rb +6 -4
  37. data/spec/nio/bytebuffer_spec.rb +323 -51
  38. data/spec/nio/monitor_spec.rb +122 -79
  39. data/spec/nio/selectables/pipe_spec.rb +5 -1
  40. data/spec/nio/selectables/ssl_socket_spec.rb +15 -12
  41. data/spec/nio/selectables/tcp_socket_spec.rb +42 -31
  42. data/spec/nio/selectables/udp_socket_spec.rb +2 -0
  43. data/spec/nio/selector_spec.rb +10 -4
  44. data/spec/spec_helper.rb +24 -3
  45. data/spec/support/selectable_examples.rb +7 -5
  46. data/tasks/extension.rake +2 -0
  47. data/tasks/rspec.rake +2 -0
  48. data/tasks/rubocop.rake +2 -0
  49. metadata +18 -15
  50. data/.rubocop_todo.yml +0 -35
data/lib/nio/selector.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "set"
2
4
 
3
5
  module NIO
@@ -13,17 +15,33 @@ module NIO
13
15
  @closed = false
14
16
  end
15
17
 
18
+ # Return a symbol representing the backend I/O multiplexing mechanism used.
19
+ # Supported backends are:
20
+ # * :ruby - pure Ruby (i.e IO.select)
21
+ # * :java - Java NIO on JRuby
22
+ # * :epoll - libev w\ Linux epoll
23
+ # * :poll - libev w\ POSIX poll
24
+ # * :kqueue - libev w\ BSD kqueue
25
+ # * :select - libev w\ SysV select
26
+ # * :port - libev w\ I/O completion ports
27
+ # * :unknown - libev w\ unknown backend
28
+ def backend
29
+ :ruby
30
+ end
31
+
16
32
  # Register interest in an IO object with the selector for the given types
17
33
  # of events. Valid event types for interest are:
18
34
  # * :r - is the IO readable?
19
35
  # * :w - is the IO writeable?
20
36
  # * :rw - is the IO either readable or writeable?
21
37
  def register(io, interest)
38
+ io = IO.try_convert(io)
39
+
22
40
  @lock.synchronize do
23
- fail IOError, "selector is closed" if closed?
41
+ raise IOError, "selector is closed" if closed?
24
42
 
25
43
  monitor = @selectables[io]
26
- fail ArgumentError, "already registered as #{monitor.interests.inspect}" if monitor
44
+ raise ArgumentError, "already registered as #{monitor.interests.inspect}" if monitor
27
45
 
28
46
  monitor = Monitor.new(io, interest, self)
29
47
  @selectables[monitor.io] = monitor
@@ -35,7 +53,7 @@ module NIO
35
53
  # Deregister the given IO object from the selector
36
54
  def deregister(io)
37
55
  @lock.synchronize do
38
- monitor = @selectables.delete io
56
+ monitor = @selectables.delete IO.try_convert(io)
39
57
  monitor.close(false) if monitor && !monitor.closed?
40
58
  monitor
41
59
  end
@@ -60,15 +78,14 @@ module NIO
60
78
  monitor.readiness = nil
61
79
  end
62
80
 
63
- ready_readers, ready_writers = Kernel.select readers, writers, [], timeout
64
- return unless ready_readers # timeout or wakeup
81
+ ready_readers, ready_writers = Kernel.select(readers, writers, [], timeout)
82
+ return unless ready_readers # timeout
65
83
 
66
84
  ready_readers.each do |io|
67
85
  if io == @wakeup
68
86
  # Clear all wakeup signals we've received by reading them
69
87
  # Wakeups should have level triggered behavior
70
88
  @wakeup.read(@wakeup.stat.size)
71
- return
72
89
  else
73
90
  monitor = @selectables[io]
74
91
  monitor.readiness = :r
@@ -78,18 +95,16 @@ module NIO
78
95
 
79
96
  ready_writers.each do |io|
80
97
  monitor = @selectables[io]
81
- monitor.readiness = (monitor.readiness == :r) ? :rw : :w
98
+ monitor.readiness = monitor.readiness == :r ? :rw : :w
82
99
  selected_monitors << monitor
83
100
  end
84
101
  end
85
102
 
86
103
  if block_given?
87
- selected_monitors.each do |m|
88
- yield m
89
- end
104
+ selected_monitors.each { |m| yield m }
90
105
  selected_monitors.size
91
106
  else
92
- selected_monitors
107
+ selected_monitors.to_a
93
108
  end
94
109
  end
95
110
 
@@ -119,8 +134,16 @@ module NIO
119
134
  @lock.synchronize do
120
135
  return if @closed
121
136
 
122
- @wakeup.close rescue nil
123
- @waker.close rescue nil
137
+ begin
138
+ @wakeup.close
139
+ rescue IOError
140
+ end
141
+
142
+ begin
143
+ @waker.close
144
+ rescue IOError
145
+ end
146
+
124
147
  @closed = true
125
148
  end
126
149
  end
data/lib/nio/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module NIO
4
- VERSION = "2.0.0.pre".freeze
4
+ VERSION = "2.1.0"
5
5
  end
data/nio4r.gemspec CHANGED
@@ -1,28 +1,34 @@
1
- # -*- encoding: utf-8 -*-
1
+ # frozen_string_literal: true
2
+
2
3
  require File.expand_path("../lib/nio/version", __FILE__)
3
4
 
4
- Gem::Specification.new do |gem|
5
- gem.authors = ["Tony Arcieri"]
6
- gem.email = ["tony.arcieri@gmail.com"]
7
- gem.description = "New IO for Ruby"
8
- gem.summary = "NIO provides a high performance selector API for monitoring IO objects"
9
- gem.homepage = "https://github.com/celluloid/nio4r"
10
- gem.license = "MIT"
5
+ Gem::Specification.new do |spec|
6
+ spec.authors = ["Tony Arcieri"]
7
+ spec.email = ["bascule@gmail.com"]
8
+ spec.homepage = "https://github.com/socketry/nio4r"
9
+ spec.license = "MIT"
10
+ spec.summary = "New IO for Ruby"
11
+ spec.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
12
+ Cross-platform asynchronous I/O primitives for scalable network clients
13
+ and servers. Inspired by the Java NIO API, but simplified for ease-of-use.
14
+ DESCRIPTION
15
+
16
+ spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
17
+ spec.files = `git ls-files`.split("\n")
18
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ spec.name = "nio4r"
20
+ spec.require_paths = ["lib"]
21
+ spec.version = NIO::VERSION
11
22
 
12
- gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
13
- gem.files = `git ls-files`.split("\n")
14
- gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
- gem.name = "nio4r"
16
- gem.require_paths = ["lib"]
17
- gem.version = NIO::VERSION
23
+ spec.required_ruby_version = ">= 2.2.2"
18
24
 
19
25
  if defined? JRUBY_VERSION
20
- gem.files << "lib/nio4r_ext.jar"
21
- gem.platform = "java"
26
+ spec.files << "lib/nio4r_ext.jar"
27
+ spec.platform = "java"
22
28
  else
23
- gem.extensions = ["ext/nio4r/extconf.rb"]
29
+ spec.extensions = ["ext/nio4r/extconf.rb"]
24
30
  end
25
31
 
26
- gem.add_development_dependency "rake"
27
- gem.add_development_dependency "bundler"
32
+ spec.add_development_dependency "rake"
33
+ spec.add_development_dependency "bundler"
28
34
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  RSpec.describe "NIO acceptables" do
@@ -15,16 +17,16 @@ RSpec.describe "NIO acceptables" do
15
17
  end
16
18
 
17
19
  describe TCPServer do
18
- let(:tcp_port) { 23_456 }
20
+ let(:port) { next_available_tcp_port }
19
21
 
20
22
  let :acceptable_subject do
21
- server = TCPServer.new("localhost", tcp_port)
22
- TCPSocket.open("localhost", tcp_port)
23
+ server = TCPServer.new("localhost", port)
24
+ TCPSocket.open("localhost", port)
23
25
  server
24
26
  end
25
27
 
26
28
  let :unacceptable_subject do
27
- TCPServer.new("localhost", tcp_port + 1)
29
+ TCPServer.new("localhost", port + 1)
28
30
  end
29
31
 
30
32
  it_behaves_like "an NIO acceptable"
@@ -1,76 +1,348 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  RSpec.describe NIO::ByteBuffer do
4
- describe "#Behaviour of ByteBuffer" do
5
- subject { bytebuffer }
6
+ let(:capacity) { 256 }
7
+ let(:example_string) { "Testing 1 2 3..." }
8
+ subject(:bytebuffer) { described_class.new(capacity) }
6
9
 
7
- context "allocates a given size buffer" do
8
- let(:bytebuffer) { NIO::ByteBuffer.new(256, nil, nil) }
10
+ describe "#initialize" do
11
+ it "raises TypeError if given a bogus argument" do
12
+ expect { described_class.new(:symbols_are_bogus) }.to raise_error(TypeError)
13
+ end
14
+ end
9
15
 
10
- before :each do
11
- bytebuffer.clear
12
- end
16
+ describe "#clear" do
17
+ it "clears the buffer" do
18
+ bytebuffer << example_string
19
+ bytebuffer.clear
13
20
 
14
- it "Checks the allocation" do
15
- expect(bytebuffer.capacity).to eql(256)
16
- end
21
+ expect(bytebuffer.remaining).to eq capacity
22
+ end
23
+ end
17
24
 
18
- it "checks remaining" do
19
- expect(bytebuffer.remaining).to eql(256)
20
- end
25
+ describe "#position" do
26
+ it "defaults to zero" do
27
+ expect(bytebuffer.position).to be_zero
28
+ end
29
+ end
21
30
 
22
- it "puts a given string to buffer" do
23
- bytebuffer << "Song of Ice & Fire"
24
- expect(bytebuffer.remaining).to eql(238)
25
- end
31
+ describe "#position=" do
32
+ let(:example_position) { 42 }
33
+
34
+ it "sets the buffer's position to a valid value" do
35
+ expect(bytebuffer.position).to be_zero
36
+ bytebuffer.position = example_position
37
+ expect(bytebuffer.position).to eq example_position
38
+ end
39
+
40
+ it "raises ArgumentError if the specified position is less than zero" do
41
+ expect { bytebuffer.position = -1 }.to raise_error(ArgumentError)
42
+ end
43
+
44
+ it "raises ArgumentError if the specified position exceeds the limit" do
45
+ expect { bytebuffer.position = capacity + 1 }.to raise_error(ArgumentError)
46
+ end
47
+ end
48
+
49
+ describe "#limit" do
50
+ it "defaults to the buffer's capacity" do
51
+ expect(bytebuffer.limit).to eq capacity
52
+ end
53
+ end
54
+
55
+ describe "#limit=" do
56
+ it "sets the buffer's limit to a valid value" do
57
+ bytebuffer.flip
58
+ expect(bytebuffer.limit).to be_zero
59
+
60
+ new_limit = capacity / 2
61
+ bytebuffer.limit = new_limit
62
+ expect(bytebuffer.limit).to eq new_limit
63
+ end
64
+
65
+ it "preserves position and mark if they're less than the new limit" do
66
+ bytebuffer << "four"
67
+ bytebuffer.mark
68
+ bytebuffer << "more"
69
+
70
+ bytebuffer.limit = capacity / 2
71
+ expect(bytebuffer.position).to eq 8
72
+ bytebuffer.reset
73
+ expect(bytebuffer.position).to eq 4
74
+ end
75
+
76
+ it "sets position to the new limit if the previous position is beyond the limit" do
77
+ bytebuffer << "four"
78
+ bytebuffer.limit = 2
79
+ expect(bytebuffer.position).to eq 2
80
+ end
81
+
82
+ it "clears the mark if the new limit is before the current mark" do
83
+ bytebuffer << "four"
84
+ bytebuffer.mark
85
+ bytebuffer.limit = 2
86
+ expect { bytebuffer.reset }.to raise_error(NIO::ByteBuffer::MarkUnsetError)
87
+ end
26
88
 
27
- it "reads the content added" do
28
- bytebuffer << "Test"
29
- bytebuffer << "Text"
30
- bytebuffer << "Dumb"
89
+ it "raises ArgumentError if specified limit is less than zero" do
90
+ expect { bytebuffer.limit = -1 }.to raise_error(ArgumentError)
91
+ end
92
+
93
+ it "raises ArgumentError if specified limit exceeds capacity" do
94
+ expect { bytebuffer.limit = capacity }.not_to raise_error
95
+ expect { bytebuffer.limit = capacity + 1 }.to raise_error(ArgumentError)
96
+ end
97
+ end
98
+
99
+ describe "#capacity" do
100
+ it "has the requested capacity" do
101
+ expect(bytebuffer.capacity).to eq capacity
102
+ end
103
+ end
104
+
105
+ describe "#remaining" do
106
+ it "calculates the number of bytes remaining" do
107
+ expect(bytebuffer.remaining).to eq capacity
108
+ bytebuffer << example_string
109
+ expect(bytebuffer.remaining).to eq(capacity - example_string.length)
110
+ end
111
+ end
112
+
113
+ describe "#full?" do
114
+ it "returns false when there is space remaining in the buffer" do
115
+ expect(bytebuffer).not_to be_full
116
+ end
117
+
118
+ it "returns true when the buffer is full" do
119
+ bytebuffer << "X" * capacity
120
+ expect(bytebuffer).to be_full
121
+ end
122
+ end
123
+
124
+ describe "#get" do
125
+ it "reads all remaining data if no length is given" do
126
+ bytebuffer << example_string
127
+ bytebuffer.flip
128
+
129
+ expect(bytebuffer.get).to eq example_string
130
+ end
131
+
132
+ it "reads zeroes from a newly initialized buffer" do
133
+ expect(bytebuffer.get(capacity)).to eq("\0" * capacity)
134
+ end
135
+
136
+ it "advances position as data is read" do
137
+ bytebuffer << "First"
138
+ bytebuffer << "Second"
139
+ bytebuffer << "Third"
140
+ bytebuffer.flip
141
+
142
+ expect(bytebuffer.position).to be_zero
143
+ expect(bytebuffer.get(10)).to eq "FirstSecon"
144
+ expect(bytebuffer.position).to eq 10
145
+ end
146
+
147
+ it "raises NIO::ByteBuffer::UnderflowError if there is not enough data in the buffer" do
148
+ bytebuffer << example_string
149
+ bytebuffer.flip
150
+
151
+ expect { bytebuffer.get(example_string.length + 1) }.to raise_error(NIO::ByteBuffer::UnderflowError)
152
+ expect(bytebuffer.get(example_string.length)).to eq example_string
153
+ end
154
+ end
155
+
156
+ describe "#[]" do
157
+ it "obtains bytes at a given index without altering position" do
158
+ bytebuffer << example_string
159
+ expect(bytebuffer[7]).to eq example_string.bytes[7]
160
+ expect(bytebuffer.position).to eq example_string.length
161
+ end
162
+
163
+ it "raises ArgumentError if the index is less than zero" do
164
+ expect { bytebuffer[-1] }.to raise_error(ArgumentError)
165
+ end
166
+
167
+ it "raises ArgumentError if the index exceeds the limit" do
168
+ bytebuffer << example_string
169
+ bytebuffer.flip
170
+ expect(bytebuffer[bytebuffer.limit - 1]).to eq example_string.bytes.last
171
+ expect { bytebuffer[bytebuffer.limit] }.to raise_error(ArgumentError)
172
+ end
173
+ end
174
+
175
+ describe "#<<" do
176
+ it "adds strings to the buffer" do
177
+ bytebuffer << example_string
178
+ expect(bytebuffer.position).to eq example_string.length
179
+ expect(bytebuffer.limit).to eq capacity
180
+ end
181
+
182
+ it "raises NIO::ByteBuffer::OverflowError if the buffer is full" do
183
+ bytebuffer << "X" * (capacity - 1)
184
+ expect { bytebuffer << "X" }.not_to raise_error
185
+ expect { bytebuffer << "X" }.to raise_error(NIO::ByteBuffer::OverflowError)
186
+ end
187
+ end
188
+
189
+ describe "#flip" do
190
+ it "flips the bytebuffer" do
191
+ bytebuffer << example_string
192
+ expect(bytebuffer.position).to eql example_string.length
193
+
194
+ expect(bytebuffer.flip).to eq bytebuffer
195
+
196
+ expect(bytebuffer.position).to be_zero
197
+ expect(bytebuffer.limit).to eq example_string.length
198
+ expect(bytebuffer.get).to eq example_string
199
+ end
200
+
201
+ it "sets remaining to the previous position" do
202
+ bytebuffer << example_string
203
+ previous_position = bytebuffer.position
204
+ expect(bytebuffer.remaining).to eq(capacity - previous_position)
205
+ expect(bytebuffer.flip.remaining).to eq previous_position
206
+ end
207
+
208
+ it "sets limit to the previous position" do
209
+ bytebuffer << example_string
210
+ expect(bytebuffer.limit).to eql(capacity)
211
+
212
+ previous_position = bytebuffer.position
213
+ expect(bytebuffer.flip.limit).to eql previous_position
214
+ end
215
+ end
216
+
217
+ describe "#rewind" do
218
+ it "rewinds the buffer leaving the limit intact" do
219
+ bytebuffer << example_string
220
+ expect(bytebuffer.rewind).to eq bytebuffer
221
+
222
+ expect(bytebuffer.position).to be_zero
223
+ expect(bytebuffer.limit).to eq capacity
224
+ end
225
+ end
226
+
227
+ describe "#mark" do
228
+ it "returns self" do
229
+ expect(bytebuffer.mark).to eql bytebuffer
230
+ end
231
+ end
232
+
233
+ describe "#reset" do
234
+ it "returns to a previously marked position" do
235
+ bytebuffer << "First"
236
+ expected_position = bytebuffer.position
237
+
238
+ expect(bytebuffer.mark).to eq bytebuffer
239
+ bytebuffer << "Second"
240
+ expect(bytebuffer.position).not_to eq expected_position
241
+ expect(bytebuffer.reset.position).to eq expected_position
242
+ end
243
+
244
+ it "raises NIO::ByteBuffer::MarkUnsetError unless mark has been set" do
245
+ expect { bytebuffer.reset }.to raise_error(NIO::ByteBuffer::MarkUnsetError)
246
+ end
247
+ end
248
+
249
+ describe "#compact" do
250
+ let(:first_string) { "CompactMe" }
251
+ let(:second_string) { "Leftover" }
252
+
253
+ it "copies data from the current position to the beginning of the buffer" do
254
+ bytebuffer << first_string << second_string
255
+ bytebuffer.position = first_string.length
256
+ bytebuffer.limit = first_string.length + second_string.length
257
+ bytebuffer.compact
258
+
259
+ expect(bytebuffer.position).to eq second_string.length
260
+ expect(bytebuffer.limit).to eq capacity
261
+ expect(bytebuffer.flip.get).to eq second_string
262
+ end
263
+ end
264
+
265
+ describe "#each" do
266
+ it "iterates over data in the buffer" do
267
+ bytebuffer << example_string
268
+ bytebuffer.flip
269
+
270
+ bytes = []
271
+ bytebuffer.each { |byte| bytes << byte }
272
+ expect(bytes).to eq example_string.bytes
273
+ end
274
+ end
275
+
276
+ describe "#inspect" do
277
+ it "inspects the buffer offsets" do
278
+ regex = /\A#<NIO::ByteBuffer:.*? @position=0 @limit=#{capacity} @capacity=#{capacity}>\z/
279
+ expect(bytebuffer.inspect).to match(regex)
280
+ end
281
+ end
282
+
283
+ context "I/O" do
284
+ let(:addr) { "localhost" }
285
+ let(:port) { next_available_tcp_port }
286
+ let(:server) { TCPServer.new(addr, port) }
287
+ let(:client) { TCPSocket.new(addr, port) }
288
+ let(:peer) { server_thread.value }
289
+
290
+ let(:server_thread) do
291
+ server
292
+
293
+ thread = Thread.new { server.accept }
294
+ Thread.pass while thread.status && thread.status != "sleep"
295
+
296
+ thread
297
+ end
298
+
299
+ before do
300
+ server_thread
301
+ client
302
+ end
303
+
304
+ after do
305
+ server_thread.kill if server_thread.alive?
306
+
307
+ server.close rescue nil
308
+ client.close rescue nil
309
+ peer.close rescue nil
310
+ end
311
+
312
+ describe "#read_from" do
313
+ it "reads data into the buffer" do
314
+ client.write(example_string)
315
+ expect(bytebuffer.read_from(peer)).to eq example_string.length
31
316
  bytebuffer.flip
32
- expect(bytebuffer.read_next(5)).to eql "TestT"
33
- end
34
317
 
35
- it "rewinds the buffer" do
318
+ expect(bytebuffer.get).to eq example_string
36
319
  end
37
320
 
38
- it "compacts the buffer" do
39
- bytebuffer << "Test"
40
- bytebuffer << " Text"
41
- bytebuffer << "Dumb"
42
- bytebuffer.flip
43
- bytebuffer.read_next 5
44
- bytebuffer.compact
45
- bytebuffer << " RRMARTIN"
46
- bytebuffer.flip
47
- # expect(bytebuffer.limit?).to eql(10)
48
- expect(bytebuffer.get).to eql("TextDumb RRMARTIN")
321
+ it "raises NIO::ByteBuffer::OverflowError if the buffer is already full" do
322
+ client.write(example_string)
323
+ bytebuffer << "X" * capacity
324
+ expect { bytebuffer.read_from(peer) }.to raise_error(NIO::ByteBuffer::OverflowError)
49
325
  end
50
326
 
51
- it "flips the bytebuffer" do
52
- bytebuffer << "Test"
53
- bytebuffer.flip
54
- expect(bytebuffer.get).to eql("Test")
327
+ it "returns 0 if no data is available" do
328
+ expect(bytebuffer.read_from(peer)).to eq 0
55
329
  end
330
+ end
56
331
 
57
- it "reads the next items" do
58
- bytebuffer << "John Snow"
332
+ describe "#write_to" do
333
+ it "writes data from the buffer" do
334
+ bytebuffer << example_string
59
335
  bytebuffer.flip
60
- bytebuffer.read_next 5
61
- expect(bytebuffer.read_next(4)).to eql("Snow")
62
- end
63
336
 
64
- it "clears the buffer" do
65
- bytebuffer << "Game of Thrones"
66
- bytebuffer.clear
67
- expect(bytebuffer.remaining).to eql(256)
337
+ expect(bytebuffer.write_to(client)).to eq example_string.length
338
+ client.close
339
+
340
+ expect(peer.read(example_string.length)).to eq example_string
68
341
  end
69
342
 
70
- it "gets the content of the bytebuffer" do
71
- bytebuffer << "Test"
343
+ it "raises NIO::ByteBuffer::UnderflowError if the buffer is out of data" do
72
344
  bytebuffer.flip
73
- expect(bytebuffer.get).to eql("Test")
345
+ expect { bytebuffer.write_to(peer) }.to raise_error(NIO::ByteBuffer::UnderflowError)
74
346
  end
75
347
  end
76
348
  end