public void Buffer_get_should_return_expected_result()
        {
            var mockBuffer = new Mock<IByteBuffer>();
            var subject = new ByteBufferStream(mockBuffer.Object);

            var result = subject.Buffer;

            result.Should().BeSameAs(mockBuffer.Object);
        }
        public void Buffer_get_should_return_expected_result()
        {
            var buffer = Substitute.For<IByteBuffer>();
            var subject = new ByteBufferStream(buffer);

            var result = subject.Buffer;

            result.Should().BeSameAs(buffer);
        }
示例#3
0
        /// <summary>
        /// Writes a raw BSON document.
        /// </summary>
        /// <param name="slice">The byte buffer containing the raw BSON document.</param>
        public virtual void WriteRawBsonDocument(IByteBuffer slice)
        {
            // overridden in BsonBinaryWriter to write the raw bytes to the stream
            // for all other streams, deserialize the raw bytes and serialize the resulting document instead

            using (var stream = new ByteBufferStream(slice, ownsByteBuffer: false))
                using (var bsonReader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults))
                {
                    var deserializationContext = BsonDeserializationContext.CreateRoot <BsonDocument>(bsonReader);
                    var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext);

                    var serializationContext = BsonSerializationContext.CreateRoot <BsonDocument>(this);
                    BsonDocumentSerializer.Instance.Serialize(serializationContext, document);
                }
        }
        private void ProcessReplyMessage(CommandState state, ResponseMessage message, IByteBuffer buffer, ConnectionId connectionId, MessageEncoderSettings encoderSettings)
        {
            state.Stopwatch.Stop();
            bool disposeOfDocuments = false;
            var replyMessage = message as ReplyMessage<RawBsonDocument>;
            if (replyMessage == null)
            {
                // ReplyMessage is generic, which means that we can't use it here, so, we need to use a different one...
                using (var stream = new ByteBufferStream(buffer, ownsBuffer: false))
                {
                    var encoderFactory = new BinaryMessageEncoderFactory(stream, encoderSettings);
                    replyMessage = (ReplyMessage<RawBsonDocument>)encoderFactory
                        .GetReplyMessageEncoder(RawBsonDocumentSerializer.Instance)
                        .ReadMessage();
                    disposeOfDocuments = true;
                }
            }

            try
            {
                if (replyMessage.CursorNotFound ||
                    replyMessage.QueryFailure ||
                    (state.ExpectedResponseType != ExpectedResponseType.Query && replyMessage.Documents.Count == 0))
                {
                    var queryFailureDocument = replyMessage.QueryFailureDocument;
                    if (__securitySensitiveCommands.Contains(state.CommandName))
                    {
                        queryFailureDocument = new BsonDocument();
                    }
                    if (_failedEvent != null)
                    {
                        _failedEvent(new CommandFailedEvent(
                            state.CommandName,
                            new MongoCommandException(
                                connectionId,
                                string.Format("{0} command failed", state.CommandName),
                                null,
                                queryFailureDocument),
                            state.OperationId,
                            replyMessage.ResponseTo,
                            connectionId,
                            state.Stopwatch.Elapsed));
                    }
                }
                else
                {
                    switch (state.ExpectedResponseType)
                    {
                        case ExpectedResponseType.Command:
                            ProcessCommandReplyMessage(state, replyMessage, connectionId);
                            break;
                        case ExpectedResponseType.GLE:
                            ProcessGLEReplyMessage(state, replyMessage, connectionId);
                            break;
                        case ExpectedResponseType.Query:
                            ProcessQueryReplyMessage(state, replyMessage, connectionId);
                            break;
                    }
                }
            }
            finally
            {
                if (disposeOfDocuments && replyMessage.Documents != null)
                {
                    replyMessage.Documents.ForEach(d => d.Dispose());
                }
            }
        }
        /// <summary>
        /// Writes a raw BSON array.
        /// </summary>
        /// <param name="slice">The byte buffer containing the raw BSON array.</param>
        public virtual void WriteRawBsonArray(IByteBuffer slice)
        {
            // overridden in BsonBinaryWriter to write the raw bytes to the stream
            // for all other streams, deserialize the raw bytes and serialize the resulting array instead

            using (var chunkSource = new InputBufferChunkSource(BsonChunkPool.Default))
            using (var buffer = new MultiChunkBuffer(chunkSource))
            using (var stream = new ByteBufferStream(buffer))
            {
                // wrap the array in a fake document so we can deserialize it
                var documentLength = slice.Length + 8;
                buffer.EnsureCapacity(documentLength);
                stream.WriteInt32(documentLength);
                stream.WriteBsonType(BsonType.Array);
                stream.WriteByte((byte)'x');
                stream.WriteByte(0);
                stream.WriteSlice(slice);
                stream.WriteByte(0);
                buffer.MakeReadOnly();

                stream.Position = 0;
                using (var reader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults))
                {
                    var deserializationContext = BsonDeserializationContext.CreateRoot(reader);
                    reader.ReadStartDocument();
                    reader.ReadName("x");
                    var array = BsonArraySerializer.Instance.Deserialize(deserializationContext);
                    reader.ReadEndDocument();

                    var serializationContext = BsonSerializationContext.CreateRoot(this);
                    BsonArraySerializer.Instance.Serialize(serializationContext, array);
                }
            }
        }
        /// <summary>
        /// Writes a raw BSON document.
        /// </summary>
        /// <param name="slice">The byte buffer containing the raw BSON document.</param>
        public virtual void WriteRawBsonDocument(IByteBuffer slice)
        {
            // overridden in BsonBinaryWriter to write the raw bytes to the stream
            // for all other streams, deserialize the raw bytes and serialize the resulting document instead

            using (var stream = new ByteBufferStream(slice, ownsBuffer: false))
            using (var bsonReader = new BsonBinaryReader(stream, BsonBinaryReaderSettings.Defaults))
            {
                var deserializationContext = BsonDeserializationContext.CreateRoot(bsonReader);
                var document = BsonDocumentSerializer.Instance.Deserialize(deserializationContext);

                var serializationContext = BsonSerializationContext.CreateRoot(this);
                BsonDocumentSerializer.Instance.Serialize(serializationContext, document);
            }
        }
        /// <summary>
        /// Gets an enumerator that can enumerate the elements of the array.
        /// </summary>
        /// <returns>An enumerator.</returns>
        public override IEnumerator<BsonValue> GetEnumerator()
        {
            ThrowIfDisposed();
            using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
            using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
            {
                var context = BsonDeserializationContext.CreateRoot(bsonReader);

                bsonReader.ReadStartDocument();
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    bsonReader.SkipName();
                    yield return DeserializeBsonValue(context);
                }
                bsonReader.ReadEndDocument();
            }
        }
 /// <summary>
 /// Materializes the RawBsonDocument into a regular BsonDocument.
 /// </summary>
 /// <param name="binaryReaderSettings">The binary reader settings.</param>
 /// <returns>A BsonDocument.</returns>
 public BsonDocument Materialize(BsonBinaryReaderSettings binaryReaderSettings)
 {
     ThrowIfDisposed();
     using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
     using (var reader = new BsonBinaryReader(stream, binaryReaderSettings))
     {
         var context = BsonDeserializationContext.CreateRoot(reader);
         return BsonDocumentSerializer.Instance.Deserialize(context);
     }
 }
        public void constructor_should_initialize_subject(
            [Values(false, true)]
            bool ownsBuffer)
        {
            var length = 123;
            var mockBuffer = new Mock<IByteBuffer>();
            mockBuffer.SetupGet(s => s.Length).Returns(length);

            var subject = new ByteBufferStream(mockBuffer.Object, ownsBuffer);

            var reflector = new Reflector(subject);
            subject.Buffer.Should().BeSameAs(mockBuffer.Object);
            subject.Length.Should().Be(length);
            subject.Position.Should().Be(0);
            reflector._disposed.Should().BeFalse();
            reflector._ownsBuffer.Should().Be(ownsBuffer);
        }
        /// <summary>
        /// Tests whether the array contains a value.
        /// </summary>
        /// <param name="value">The value to test for.</param>
        /// <returns>True if the array contains the value.</returns>
        public override bool Contains(BsonValue value)
        {
            ThrowIfDisposed();
            using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
            using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
            {
                var context = BsonDeserializationContext.CreateRoot(bsonReader);

                bsonReader.ReadStartDocument();
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    bsonReader.SkipName();
                    if (DeserializeBsonValue(context).Equals(value))
                    {
                        return true;
                    }
                }
                bsonReader.ReadEndDocument();

                return false;
            }
        }
            public ResponseMessage DecodeMessage(IByteBuffer buffer, IMessageEncoderSelector encoderSelector, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                _stopwatch.Stop();
                _networkDuration = _stopwatch.Elapsed;

                ResponseMessage message;
                _stopwatch.Restart();
                using (var stream = new ByteBufferStream(buffer, ownsBuffer: false))
                {
                    var encoderFactory = new BinaryMessageEncoderFactory(stream, _messageEncoderSettings);
                    var encoder = encoderSelector.GetEncoder(encoderFactory);
                    message = (ResponseMessage)encoder.ReadMessage();
                }
                _stopwatch.Stop();
                _deserializationDuration = _stopwatch.Elapsed;

                return message;
            }
        /// <summary>
        /// Tests whether the document contains an element with the specified name.
        /// </summary>
        /// <param name="name">The name of the element to look for.</param>
        /// <returns>
        /// True if the document contains an element with the specified name.
        /// </returns>
        public override bool Contains(string name)
        {
            if (name == null)
            {
                throw new ArgumentNullException("name");
            }
            ThrowIfDisposed();

            using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
            using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
            {
                bsonReader.ReadStartDocument();
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    if (bsonReader.ReadName() == name)
                    {
                        return true;
                    }
                    bsonReader.SkipValue();
                }
                bsonReader.ReadEndDocument();

                return false;
            }
        }
        public async Task<ResponseMessage> ReceiveMessageAsync(
            int responseTo,
            IMessageEncoderSelector encoderSelector,
            MessageEncoderSettings messageEncoderSettings,
            CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(encoderSelector, nameof(encoderSelector));
            ThrowIfDisposedOrNotOpen();

            try
            {
                if (_receivingMessageEventHandler != null)
                {
                    _receivingMessageEventHandler(new ConnectionReceivingMessageEvent(_connectionId, responseTo, EventContext.OperationId));
                }

                ResponseMessage reply;
                var stopwatch = Stopwatch.StartNew();
                using (var buffer = await ReceiveBufferAsync(responseTo, cancellationToken).ConfigureAwait(false))
                {
                    stopwatch.Stop();
                    var networkDuration = stopwatch.Elapsed;

                    cancellationToken.ThrowIfCancellationRequested();

                    stopwatch.Restart();
                    using (var stream = new ByteBufferStream(buffer))
                    {
                        var encoderFactory = new BinaryMessageEncoderFactory(stream, messageEncoderSettings);
                        var encoder = encoderSelector.GetEncoder(encoderFactory);
                        reply = (ResponseMessage)encoder.ReadMessage();
                    }
                    stopwatch.Stop();

                    if (_commandEventHelper.ShouldCallAfterReceiving)
                    {
                        _commandEventHelper.AfterReceiving(reply, buffer, _connectionId, messageEncoderSettings);
                    }

                    if (_receivedMessageEventHandler != null)
                    {
                        _receivedMessageEventHandler(new ConnectionReceivedMessageEvent(_connectionId, responseTo, buffer.Length, networkDuration, stopwatch.Elapsed, EventContext.OperationId));
                    }
                }

                return reply;
            }
            catch (Exception ex)
            {
                if (_commandEventHelper.ShouldCallErrorReceiving)
                {
                    _commandEventHelper.ErrorReceiving(responseTo, _connectionId, ex);
                }

                if (_failedReceivingMessageEventHandler != null)
                {
                    _failedReceivingMessageEventHandler(new ConnectionReceivingMessageFailedEvent(_connectionId, responseTo, ex, EventContext.OperationId));
                }

                throw;
            }
        }
        public async Task SendMessagesAsync(IEnumerable<RequestMessage> messages, MessageEncoderSettings messageEncoderSettings, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(messages, nameof(messages));
            ThrowIfDisposedOrNotOpen();

            var messagesToSend = messages.ToList();
            var requestIds = messagesToSend.Select(x => x.RequestId).ToList();
            try
            {
                if (_sendingMessagesEventHandler != null)
                {
                    _sendingMessagesEventHandler(new ConnectionSendingMessagesEvent(_connectionId, requestIds, EventContext.OperationId));
                }

                cancellationToken.ThrowIfCancellationRequested();

                var stopwatch = Stopwatch.StartNew();
                var outputBufferChunkSource = new OutputBufferChunkSource(BsonChunkPool.Default);
                using (var buffer = new MultiChunkBuffer(outputBufferChunkSource))
                {
                    using (var stream = new ByteBufferStream(buffer, ownsBuffer: false))
                    {
                        var encoderFactory = new BinaryMessageEncoderFactory(stream, messageEncoderSettings);
                        foreach (var message in messagesToSend)
                        {
                            if (message.ShouldBeSent == null || message.ShouldBeSent())
                            {
                                var encoder = message.GetEncoder(encoderFactory);
                                encoder.WriteMessage(message);
                                message.WasSent = true;
                            }

                            // Encoding messages includes serializing the
                            // documents, so encoding message could be expensive
                            // and worthy of us honoring cancellation here.
                            cancellationToken.ThrowIfCancellationRequested();
                        }
                        buffer.Length = (int)stream.Length;
                        buffer.MakeReadOnly();
                    }

                    var serializationDuration = stopwatch.Elapsed;

                    if (_commandEventHelper.ShouldCallBeforeSending)
                    {
                        _commandEventHelper.BeforeSending(
                            messages,
                            _connectionId,
                            buffer,
                            messageEncoderSettings,
                            stopwatch);
                    }

                    var stopwatchCheckPoint = stopwatch.Elapsed;

                    await SendBufferAsync(buffer, cancellationToken).ConfigureAwait(false);

                    var networkDuration = stopwatch.Elapsed - stopwatchCheckPoint;

                    if (_commandEventHelper.ShouldCallAfterSending)
                    {
                        _commandEventHelper.AfterSending(messages, _connectionId);
                    }

                    if (_sentMessagesEventHandler != null)
                    {
                        _sentMessagesEventHandler(new ConnectionSentMessagesEvent(_connectionId, requestIds, buffer.Length, networkDuration, serializationDuration, EventContext.OperationId));
                    }
                }
            }
            catch (Exception ex)
            {
                if (_commandEventHelper.ShouldCallErrorSending)
                {
                    _commandEventHelper.ErrorSending(messages, _connectionId, ex);
                }

                if (_failedSendingMessagesEvent != null)
                {
                    _failedSendingMessagesEvent(new ConnectionSendingMessagesFailedEvent(_connectionId, requestIds, ex, EventContext.OperationId));
                }

                throw;
            }
        }
        public void PrepareToWrite_should_throw_when_stream_would_exceed_2GB()
        {
            using (var buffer = new MultiChunkBuffer(BsonChunkPool.Default))
            using (var subject = new ByteBufferStream(buffer))
            {
                var bytes = new byte[int.MaxValue / 2 + 1024];
                subject.Write(bytes, 0, bytes.Length);

                Action action = () => subject.Write(bytes, 0, bytes.Length); // indirectly calls private PrepareToWrite method

                action.ShouldThrow<IOException>();
            }
        }
        public void ThrowIfEndOfStream_should_throw_when_position_plus_length_exceeds_2GB()
        {
            using (var buffer = new ByteArrayBuffer(new byte[1024]))
            using (var subject = new ByteBufferStream(buffer))
            {
                subject.Position = 1024;
                subject.WriteInt32(int.MaxValue - 128);
                subject.Position = 1024;

                Action action = () => subject.ReadSlice(); // indirectly calls private ThrowIfEndOfStream method

                action.ShouldThrow<EndOfStreamException>();
            }
        }
        public void ReadSlice_should_return_expected_result(int length, byte[] bytes)
        {
            var mockBuffer = new Mock<IByteBuffer>();
            mockBuffer.Setup(s => s.AccessBackingBytes(It.IsAny<int>())).Returns((int p) => { return new ArraySegment<byte>(bytes, p, bytes.Length - p); });
            mockBuffer.SetupGet(s => s.IsReadOnly).Returns(true);
            mockBuffer.SetupGet(s => s.Length).Returns(bytes.Length);
            var subject = new ByteBufferStream(mockBuffer.Object);
            var expectedPosition = length;

            subject.ReadSlice();

            subject.Position.Should().Be(expectedPosition);
            mockBuffer.Verify(b => b.GetSlice(0, bytes.Length), Times.Once);
        }
        public void BeforeSending(IEnumerable<RequestMessage> messages, ConnectionId connectionId, IByteBuffer buffer, MessageEncoderSettings encoderSettings, Stopwatch stopwatch)
        {
            using (var stream = new ByteBufferStream(buffer, ownsBuffer: false))
            {
                var messageQueue = new Queue<RequestMessage>(messages);

                while (messageQueue.Count > 0)
                {
                    ProcessRequestMessages(messageQueue, connectionId, stream, encoderSettings, stopwatch);
                }
            }
        }
        /// <summary>
        /// Tries to get the value of an element of this document.
        /// </summary>
        /// <param name="name">The name of the element.</param>
        /// <param name="value">The value of the element.</param>
        /// <returns>
        /// True if an element with that name was found.
        /// </returns>
        public override bool TryGetValue(string name, out BsonValue value)
        {
            ThrowIfDisposed();
            using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
            using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
            {
                var context = BsonDeserializationContext.CreateRoot(bsonReader);
                
                bsonReader.ReadStartDocument();
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    if (bsonReader.ReadName() == name)
                    {
                        value = DeserializeBsonValue(context);
                        return true;
                    }

                    bsonReader.SkipValue();
                }
                bsonReader.ReadEndDocument();

                value = null;
                return false;
            }
        }
        private IEnumerable<BsonElement> MaterializeThisLevel()
        {
            var elements = new List<BsonElement>();

            using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
            using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
            {
                var context = BsonDeserializationContext.CreateRoot(bsonReader);

                bsonReader.ReadStartDocument();
                BsonType bsonType;
                while ((bsonType = bsonReader.ReadBsonType()) != BsonType.EndOfDocument)
                {
                    var name = bsonReader.ReadName();
                    BsonValue value;
                    switch (bsonType)
                    {
                        case BsonType.Array: value = DeserializeLazyBsonArray(bsonReader); break;
                        case BsonType.Document: value = DeserializeLazyBsonDocument(bsonReader); break;
                        default: value = BsonValueSerializer.Instance.Deserialize(context); break;
                    }
                    elements.Add(new BsonElement(name, value));
                }
                bsonReader.ReadEndDocument();
            }

            return elements;
        }
        public void Dispose_should_dispose_buffer_if_it_owns_it(
            [Values(false, true)]
            bool ownsBuffer)
        {
            var mockBuffer = new Mock<IByteBuffer>();
            var subject = new ByteBufferStream(mockBuffer.Object, ownsBuffer: ownsBuffer);

            subject.Dispose();

            mockBuffer.Verify(s => s.Dispose(), Times.Exactly(ownsBuffer ? 1 : 0));
        }
            public IByteBuffer EncodeMessages(CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var serializationStopwatch = Stopwatch.StartNew();
                var outputBufferChunkSource = new OutputBufferChunkSource(BsonChunkPool.Default);
                var buffer = new MultiChunkBuffer(outputBufferChunkSource);
                using (var stream = new ByteBufferStream(buffer, ownsBuffer: false))
                {
                    var encoderFactory = new BinaryMessageEncoderFactory(stream, _messageEncoderSettings);
                    foreach (var message in _messages)
                    {
                        if (message.ShouldBeSent == null || message.ShouldBeSent())
                        {
                            var encoder = message.GetEncoder(encoderFactory);
                            encoder.WriteMessage(message);
                            message.WasSent = true;
                        }

                        // Encoding messages includes serializing the
                        // documents, so encoding message could be expensive
                        // and worthy of us honoring cancellation here.
                        cancellationToken.ThrowIfCancellationRequested();
                    }
                    buffer.Length = (int)stream.Length;
                    buffer.MakeReadOnly();
                }
                serializationStopwatch.Stop();
                _serializationDuration = serializationStopwatch.Elapsed;

                return buffer;
            }
        public void constructor_should_initialize_subject(
            [Values(false, true)]
            bool ownsBuffer)
        {
            var length = 123;
            var buffer = Substitute.For<IByteBuffer>();
            buffer.Length.Returns(length);

            var subject = new ByteBufferStream(buffer, ownsBuffer);

            var reflector = new Reflector(subject);
            subject.Buffer.Should().BeSameAs(buffer);
            subject.Length.Should().Be(length);
            subject.Position.Should().Be(0);
            reflector._disposed.Should().BeFalse();
            reflector._ownsBuffer.Should().Be(ownsBuffer);
        }
        /// <summary>
        /// Gets an element of this document.
        /// </summary>
        /// <param name="index">The zero based index of the element.</param>
        /// <returns>
        /// The element.
        /// </returns>
        public override BsonElement GetElement(int index)
        {
            if (index < 0)
            {
                throw new ArgumentOutOfRangeException("index");
            }
            ThrowIfDisposed();

            using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
            using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
            {
                var context = BsonDeserializationContext.CreateRoot(bsonReader);
                
                bsonReader.ReadStartDocument();
                var i = 0;
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    if (i == index)
                    {
                        var name = bsonReader.ReadName();
                        var value = DeserializeBsonValue(context);
                        return new BsonElement(name, value);
                    }

                    bsonReader.SkipName();
                    bsonReader.SkipValue();
                    i++;
                }
                bsonReader.ReadEndDocument();

                throw new ArgumentOutOfRangeException("index");
            }
        }
 public Reflector(ByteBufferStream instance)
 {
     _instance = instance;
 }
        // public indexers
        /// <summary>
        /// Gets or sets a value by position.
        /// </summary>
        /// <param name="index">The position.</param>
        /// <returns>The value.</returns>
        public override BsonValue this[int index]
        {
            get
            {
                if (index < 0)
                {
                    throw new ArgumentOutOfRangeException("index");
                }
                ThrowIfDisposed();

                using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
                using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
                {
                    bsonReader.ReadStartDocument();
                    var i = 0;
                    while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                    {
                        bsonReader.SkipName();
                        if (i == index)
                        {
                            var context = BsonDeserializationContext.CreateRoot(bsonReader);
                            return DeserializeBsonValue(context);
                        }

                        bsonReader.SkipValue();
                        i++;
                    }
                    bsonReader.ReadEndDocument();

                    throw new ArgumentOutOfRangeException("index");
                }
            }
            set
            {
                throw new NotSupportedException("RawBsonArray instances are immutable.");
            }
        }
        public void Dispose_should_dispose_buffer_if_it_owns_it(
            [Values(false, true)]
            bool ownsBuffer)
        {
            var buffer = Substitute.For<IByteBuffer>();
            var subject = new ByteBufferStream(buffer, ownsBuffer: ownsBuffer);

            subject.Dispose();

            buffer.Received(ownsBuffer ? 1 : 0).Dispose();
        }
        public override void CopyTo(object[] array, int arrayIndex)
        {
            ThrowIfDisposed();
            using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
            using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
            {
                var context = BsonDeserializationContext.CreateRoot(bsonReader);

                bsonReader.ReadStartDocument();
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    bsonReader.SkipName();
                    array[arrayIndex++] = DeserializeBsonValue(context).RawValue;
                }
                bsonReader.ReadEndDocument();
            }
        }
        public void ReadSlice_should_return_expected_result(int length, byte[] bytes)
        {
            var buffer = Substitute.For<IByteBuffer>();
            buffer.AccessBackingBytes(Arg.Any<int>()).Returns(x => { var p = (int)x[0]; return new ArraySegment<byte>(bytes, p, bytes.Length - p); });
            buffer.IsReadOnly.Returns(true);
            buffer.Length.Returns(bytes.Length);
            var subject = new ByteBufferStream(buffer);
            var expectedPosition = length;

            subject.ReadSlice();

            subject.Position.Should().Be(expectedPosition);
            subject.Buffer.Received(1).GetSlice(0, bytes.Length);
        }
        /// <summary>
        /// Gets the index of a value in the array.
        /// </summary>
        /// <param name="value">The value to search for.</param>
        /// <param name="index">The zero based index at which to start the search.</param>
        /// <param name="count">The number of elements to search.</param>
        /// <returns>The zero based index of the value (or -1 if not found).</returns>
        public override int IndexOf(BsonValue value, int index, int count)
        {
            ThrowIfDisposed();
            using (var stream = new ByteBufferStream(_slice, ownsBuffer: false))
            using (var bsonReader = new BsonBinaryReader(stream, _readerSettings))
            {
                var context = BsonDeserializationContext.CreateRoot(bsonReader);

                bsonReader.ReadStartDocument();
                var i = 0;
                while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
                {
                    bsonReader.SkipName();
                    if (i >= index)
                    {
                        if (count == 0)
                        {
                            return -1;
                        }

                        if (DeserializeBsonValue(context).Equals(value))
                        {
                            return i;
                        }

                        count--;
                    }
                    else
                    {
                        bsonReader.SkipValue();
                    }

                    i++;
                }
                bsonReader.ReadEndDocument();

                return -1;
            }
        }
        public void Test20KDocument()
        {
            // manufacture an approximately 20K document using 200 strings each 100 characters long
            // it's enough to cause the document to straddle a chunk boundary
            var document = new BsonDocument();
            var value = new string('x', 100);
            for (int i = 0; i < 200; i++)
            {
                var name = i.ToString();
                document.Add(name, value);
            }

            // round trip tests
            var bson = document.ToBson();
            var rehydrated = BsonSerializer.Deserialize<BsonDocument>(bson);
            Assert.IsTrue(bson.SequenceEqual(rehydrated.ToBson()));

            // test failure mode when 20 bytes are truncated from the buffer
            using (var byteBuffer = new MultiChunkBuffer(BsonChunkPool.Default))
            using (var byteBufferStream = new ByteBufferStream(byteBuffer, ownsBuffer: true))
            {
                using (var memoryStream = new MemoryStream(bson))
                {
                    memoryStream.CopyTo(byteBufferStream);
                }
                byteBufferStream.SetLength(byteBufferStream.Length - 20);
                byteBufferStream.Position = 0;

                using (var bsonReader = new BsonBinaryReader(byteBufferStream))
                {
                    Assert.Throws<EndOfStreamException>(() => BsonSerializer.Deserialize<BsonDocument>(bsonReader));
                }
            }
        }