diff --git a/ext/bson/init.c b/ext/bson/init.c index 9de5d75b5..2d217d9fa 100644 --- a/ext/bson/init.c +++ b/ext/bson/init.c @@ -276,7 +276,7 @@ void Init_bson_native() /* * call-seq: - * buffer.put_hash(hash) -> ByteBuffer + * buffer.put_hash(hash, validating_keys) -> ByteBuffer * * Writes a Hash into the byte buffer. * @@ -329,6 +329,10 @@ void Init_bson_native() * * Returns the contents of the buffer as a binary string. * + * If the buffer is used for reading, the returned contents is the data + * that was not yet read. If the buffer is used for writing, the returned + * contents is the complete data that has been written so far. + * * Note: this method copies the buffer's contents into a newly allocated * +String+ instance. It does not return a reference to the data stored in * the buffer itself. diff --git a/spec/bson/byte_buffer_spec.rb b/spec/bson/byte_buffer_spec.rb index 79de137d9..ab2df38a8 100644 --- a/spec/bson/byte_buffer_spec.rb +++ b/spec/bson/byte_buffer_spec.rb @@ -65,6 +65,37 @@ expect(buffer.length).to eq(1) end end + + context 'after the byte buffer was converted to string' do + + shared_examples 'returns the total buffer length' do + it 'returns the total buffer length' do + expect(buffer.length).to eq(5) + buffer.to_s.length.should == 5 + expect(buffer.length).to eq(5) + end + end + + context 'read buffer' do + + let(:buffer) do + described_class.new({}.to_bson.to_s) + end + + include_examples 'returns the total buffer length' + end + + context 'write buffer' do + + let(:buffer) do + described_class.new.tap do |buffer| + buffer.put_bytes('hello') + end + end + + include_examples 'returns the total buffer length' + end + end end describe '#rewind!' do @@ -160,4 +191,40 @@ end end end + + describe '#to_s' do + context 'read buffer' do + let(:buffer) do + described_class.new("\x18\x00\x00\x00*\x00\x00\x00") + end + + it 'returns the data' do + buffer.to_s.should == "\x18\x00\x00\x00*\x00\x00\x00" + end + + it 'returns the remaining buffer contents after a read' do + buffer.to_s.should == "\x18\x00\x00\x00*\x00\x00\x00" + buffer.get_int32.should == 24 + buffer.to_s.should == "*\x00\x00\x00" + end + end + + context 'write buffer' do + let(:buffer) do + described_class.new.tap do |buffer| + buffer.put_int32(24) + end + end + + it 'returns the data' do + buffer.to_s.should == "\x18\x00\x00\x00".force_encoding('binary') + end + + it 'returns the complete buffer contents after a write' do + buffer.to_s.should == "\x18\x00\x00\x00".force_encoding('binary') + buffer.put_int32(42) + buffer.to_s.should == "\x18\x00\x00\x00*\x00\x00\x00".force_encoding('binary') + end + end + end end diff --git a/src/main/org/bson/ByteBuf.java b/src/main/org/bson/ByteBuf.java index 91a6cd3e9..3b8637b1f 100644 --- a/src/main/org/bson/ByteBuf.java +++ b/src/main/org/bson/ByteBuf.java @@ -152,11 +152,15 @@ public IRubyObject initialize(final RubyString value) { * @version 4.0.0 */ @JRubyMethod(name = "length") - public RubyFixnum getLength() { + public RubyFixnum getLength(ThreadContext context) { + return new RubyFixnum(context.runtime, getLengthInternal()); + } + + private int getLengthInternal() { if (this.mode == Mode.WRITE) { - return getWritePosition(); + return this.writePosition; } else { - return new RubyFixnum(getRuntime(), this.buffer.remaining()); + return this.buffer.remaining(); } } @@ -168,8 +172,8 @@ public RubyFixnum getLength() { * @version 4.0.0 */ @JRubyMethod(name = "read_position") - public RubyFixnum getReadPosition() { - return new RubyFixnum(getRuntime(), this.readPosition); + public RubyFixnum getReadPosition(ThreadContext context) { + return new RubyFixnum(context.runtime, this.readPosition); } /** @@ -180,8 +184,8 @@ public RubyFixnum getReadPosition() { * @version 4.0.0 */ @JRubyMethod(name = "write_position") - public RubyFixnum getWritePosition() { - return new RubyFixnum(getRuntime(), this.writePosition); + public RubyFixnum getWritePosition(ThreadContext context) { + return new RubyFixnum(context.runtime, this.writePosition); } /** @@ -207,11 +211,16 @@ public ByteBuf rewind() { * @version 4.0.0 */ @JRubyMethod(name = "to_s") - public RubyString toRubyString() { - ensureBsonRead(); - byte[] bytes = new byte[this.writePosition]; - this.buffer.get(bytes, 0, this.writePosition); - return RubyString.newString(getRuntime(), bytes); + public RubyString toRubyString(ThreadContext context) { + ByteBuffer buffer_copy = this.buffer.duplicate(); + if (this.mode == Mode.WRITE) { + buffer_copy.flip(); + } + int length = this.getLengthInternal(); + byte[] bytes = new byte[length]; + buffer_copy.get(bytes, 0, length); + + return RubyString.newString(context.runtime, bytes); } /**