Implement QuicStreamSequencerBuffer::PeekRegion().

gfe-relnote: n/a, no functional change.
PiperOrigin-RevId: 254856738
Change-Id: I34f1fd30429f8d5d403fa17fc1f4a127c074f952
diff --git a/quic/core/quic_stream_sequencer_buffer_test.cc b/quic/core/quic_stream_sequencer_buffer_test.cc
index 49f83f0..20dbe05 100644
--- a/quic/core/quic_stream_sequencer_buffer_test.cc
+++ b/quic/core/quic_stream_sequencer_buffer_test.cc
@@ -602,14 +602,14 @@
   iovec iov;
   EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
   EXPECT_EQ(source, IovecToStringPiece(iov));
-  // The second frame goes into the same bucket.
+  // The second frame goes into the same block.
   std::string source2(800, 'a');
   buffer_->OnStreamData(1024, source2, &written_, &error_details_);
   EXPECT_TRUE(buffer_->PrefetchNextRegion(&iov));
   EXPECT_EQ(source2, IovecToStringPiece(iov));
 }
 
-TEST_F(QuicStreamSequencerBufferTest, PrefetchBufferWithMultipleBucket) {
+TEST_F(QuicStreamSequencerBufferTest, PrefetchBufferWithMultipleBlocks) {
   const size_t data_size = 1024;
   std::string source(data_size, 'a');
   buffer_->OnStreamData(0, source, &written_, &error_details_);
@@ -678,6 +678,164 @@
   EXPECT_FALSE(buffer_->PrefetchNextRegion(&iov));
 }
 
+TEST_F(QuicStreamSequencerBufferTest, PeekEmptyBuffer) {
+  iovec iov;
+  EXPECT_FALSE(buffer_->PeekRegion(0, &iov));
+  EXPECT_FALSE(buffer_->PeekRegion(1, &iov));
+  EXPECT_FALSE(buffer_->PeekRegion(100, &iov));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, PeekSingleBlock) {
+  std::string source(kBlockSizeBytes, 'a');
+  buffer_->OnStreamData(0, source, &written_, &error_details_);
+
+  iovec iov;
+  EXPECT_TRUE(buffer_->PeekRegion(0, &iov));
+  EXPECT_EQ(source, IovecToStringPiece(iov));
+
+  // Peeking again gives the same result.
+  EXPECT_TRUE(buffer_->PeekRegion(0, &iov));
+  EXPECT_EQ(source, IovecToStringPiece(iov));
+
+  // Peek at a different offset.
+  EXPECT_TRUE(buffer_->PeekRegion(100, &iov));
+  EXPECT_EQ(QuicStringPiece(source).substr(100), IovecToStringPiece(iov));
+
+  // Peeking at or after FirstMissingByte() returns false.
+  EXPECT_FALSE(buffer_->PeekRegion(kBlockSizeBytes, &iov));
+  EXPECT_FALSE(buffer_->PeekRegion(kBlockSizeBytes + 1, &iov));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, PeekTwoWritesInSingleBlock) {
+  const size_t length1 = 1024;
+  std::string source1(length1, 'a');
+  buffer_->OnStreamData(0, source1, &written_, &error_details_);
+
+  iovec iov;
+  EXPECT_TRUE(buffer_->PeekRegion(0, &iov));
+  EXPECT_EQ(source1, IovecToStringPiece(iov));
+
+  // The second frame goes into the same block.
+  const size_t length2 = 800;
+  std::string source2(length2, 'b');
+  buffer_->OnStreamData(length1, source2, &written_, &error_details_);
+
+  EXPECT_TRUE(buffer_->PeekRegion(length1, &iov));
+  EXPECT_EQ(source2, IovecToStringPiece(iov));
+
+  // Peek with an offset inside the first write.
+  const QuicStreamOffset offset1 = 500;
+  EXPECT_TRUE(buffer_->PeekRegion(offset1, &iov));
+  EXPECT_EQ(QuicStringPiece(source1).substr(offset1),
+            IovecToStringPiece(iov).substr(0, length1 - offset1));
+  EXPECT_EQ(QuicStringPiece(source2),
+            IovecToStringPiece(iov).substr(length1 - offset1));
+
+  // Peek with an offset inside the second write.
+  const QuicStreamOffset offset2 = 1500;
+  EXPECT_TRUE(buffer_->PeekRegion(offset2, &iov));
+  EXPECT_EQ(QuicStringPiece(source2).substr(offset2 - length1),
+            IovecToStringPiece(iov));
+
+  // Peeking at or after FirstMissingByte() returns false.
+  EXPECT_FALSE(buffer_->PeekRegion(length1 + length2, &iov));
+  EXPECT_FALSE(buffer_->PeekRegion(length1 + length2 + 1, &iov));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, PeekBufferWithMultipleBlocks) {
+  const size_t length1 = 1024;
+  std::string source1(length1, 'a');
+  buffer_->OnStreamData(0, source1, &written_, &error_details_);
+
+  iovec iov;
+  EXPECT_TRUE(buffer_->PeekRegion(0, &iov));
+  EXPECT_EQ(source1, IovecToStringPiece(iov));
+
+  const size_t length2 = kBlockSizeBytes + 2;
+  std::string source2(length2, 'b');
+  buffer_->OnStreamData(length1, source2, &written_, &error_details_);
+
+  // Peek with offset 0 returns the entire block.
+  EXPECT_TRUE(buffer_->PeekRegion(0, &iov));
+  EXPECT_EQ(kBlockSizeBytes, iov.iov_len);
+  EXPECT_EQ(source1, IovecToStringPiece(iov).substr(0, length1));
+  EXPECT_EQ(QuicStringPiece(source2).substr(0, kBlockSizeBytes - length1),
+            IovecToStringPiece(iov).substr(length1));
+
+  EXPECT_TRUE(buffer_->PeekRegion(length1, &iov));
+  EXPECT_EQ(QuicStringPiece(source2).substr(0, kBlockSizeBytes - length1),
+            IovecToStringPiece(iov));
+
+  EXPECT_TRUE(buffer_->PeekRegion(kBlockSizeBytes, &iov));
+  EXPECT_EQ(QuicStringPiece(source2).substr(kBlockSizeBytes - length1),
+            IovecToStringPiece(iov));
+
+  // Peeking at or after FirstMissingByte() returns false.
+  EXPECT_FALSE(buffer_->PeekRegion(length1 + length2, &iov));
+  EXPECT_FALSE(buffer_->PeekRegion(length1 + length2 + 1, &iov));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, PeekAfterConsumed) {
+  std::string source1(kBlockSizeBytes, 'a');
+  buffer_->OnStreamData(0, source1, &written_, &error_details_);
+
+  iovec iov;
+  EXPECT_TRUE(buffer_->PeekRegion(0, &iov));
+  EXPECT_EQ(source1, IovecToStringPiece(iov));
+
+  // Consume some data.
+  EXPECT_TRUE(buffer_->MarkConsumed(1024));
+
+  // Peeking into consumed data fails.
+  EXPECT_FALSE(buffer_->PeekRegion(0, &iov));
+  EXPECT_FALSE(buffer_->PeekRegion(512, &iov));
+
+  EXPECT_TRUE(buffer_->PeekRegion(1024, &iov));
+  EXPECT_EQ(QuicStringPiece(source1).substr(1024), IovecToStringPiece(iov));
+
+  EXPECT_TRUE(buffer_->PeekRegion(1500, &iov));
+  EXPECT_EQ(QuicStringPiece(source1).substr(1500), IovecToStringPiece(iov));
+
+  // Consume rest of block.
+  EXPECT_TRUE(buffer_->MarkConsumed(kBlockSizeBytes - 1024));
+
+  // Read new data.
+  std::string source2(300, 'b');
+  buffer_->OnStreamData(kBlockSizeBytes, source2, &written_, &error_details_);
+
+  // Peek into new data.
+  EXPECT_TRUE(buffer_->PeekRegion(kBlockSizeBytes, &iov));
+  EXPECT_EQ(source2, IovecToStringPiece(iov));
+
+  EXPECT_TRUE(buffer_->PeekRegion(kBlockSizeBytes + 128, &iov));
+  EXPECT_EQ(QuicStringPiece(source2).substr(128), IovecToStringPiece(iov));
+
+  // Peeking into consumed data still fails.
+  EXPECT_FALSE(buffer_->PeekRegion(0, &iov));
+  EXPECT_FALSE(buffer_->PeekRegion(512, &iov));
+  EXPECT_FALSE(buffer_->PeekRegion(1024, &iov));
+  EXPECT_FALSE(buffer_->PeekRegion(1500, &iov));
+}
+
+TEST_F(QuicStreamSequencerBufferTest, PeekContinously) {
+  std::string source1(kBlockSizeBytes, 'a');
+  buffer_->OnStreamData(0, source1, &written_, &error_details_);
+
+  iovec iov;
+  EXPECT_TRUE(buffer_->PeekRegion(0, &iov));
+  EXPECT_EQ(source1, IovecToStringPiece(iov));
+
+  std::string source2(kBlockSizeBytes, 'b');
+  buffer_->OnStreamData(kBlockSizeBytes, source2, &written_, &error_details_);
+
+  EXPECT_TRUE(buffer_->PeekRegion(kBlockSizeBytes, &iov));
+  EXPECT_EQ(source2, IovecToStringPiece(iov));
+
+  // First block is still there.
+  EXPECT_TRUE(buffer_->PeekRegion(0, &iov));
+  EXPECT_EQ(source1, IovecToStringPiece(iov));
+}
+
 TEST_F(QuicStreamSequencerBufferTest, MarkConsumedInOneBlock) {
   // Write into [0, 1024) and then read out [0, 256)
   std::string source(1024, 'a');