tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestSourceBuffer.cpp (33778B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include <algorithm>
      6 #include <cstdint>
      7 #include <utility>
      8 
      9 #include "Common.h"
     10 #include "SourceBuffer.h"
     11 #include "SurfaceCache.h"
     12 #include "gtest/gtest.h"
     13 #include "nsIInputStream.h"
     14 
     15 using namespace mozilla;
     16 using namespace mozilla::image;
     17 
     18 using std::min;
     19 
     20 void ExpectChunkAndByteCount(const SourceBufferIterator& aIterator,
     21                             uint32_t aChunks, size_t aBytes) {
     22  EXPECT_EQ(aChunks, aIterator.ChunkCount());
     23  EXPECT_EQ(aBytes, aIterator.ByteCount());
     24 }
     25 
     26 void ExpectRemainingBytes(const SourceBufferIterator& aIterator,
     27                          size_t aBytes) {
     28  EXPECT_TRUE(aIterator.RemainingBytesIsNoMoreThan(aBytes));
     29  EXPECT_TRUE(aIterator.RemainingBytesIsNoMoreThan(aBytes + 1));
     30 
     31  if (aBytes > 0) {
     32    EXPECT_FALSE(aIterator.RemainingBytesIsNoMoreThan(0));
     33    EXPECT_FALSE(aIterator.RemainingBytesIsNoMoreThan(aBytes - 1));
     34  }
     35 }
     36 
     37 char GenerateByte(size_t aIndex) {
     38  uint8_t byte = aIndex % 256;
     39  return *reinterpret_cast<char*>(&byte);
     40 }
     41 
     42 void GenerateData(char* aOutput, size_t aOffset, size_t aLength) {
     43  for (size_t i = 0; i < aLength; ++i) {
     44    aOutput[i] = GenerateByte(aOffset + i);
     45  }
     46 }
     47 
     48 void GenerateData(char* aOutput, size_t aLength) {
     49  GenerateData(aOutput, 0, aLength);
     50 }
     51 
     52 void CheckData(const char* aData, size_t aOffset, size_t aLength) {
     53  for (size_t i = 0; i < aLength; ++i) {
     54    ASSERT_EQ(GenerateByte(aOffset + i), aData[i]);
     55  }
     56 }
     57 
     58 enum class AdvanceMode { eAdvanceAsMuchAsPossible, eAdvanceByLengthExactly };
     59 
     60 class ImageSourceBuffer : public ::testing::Test {
     61 public:
     62  ImageSourceBuffer()
     63      : mSourceBuffer(new SourceBuffer),
     64        mExpectNoResume(new ExpectNoResume),
     65        mCountResumes(new CountResumes) {
     66    GenerateData(mData, sizeof(mData));
     67    EXPECT_FALSE(mSourceBuffer->IsComplete());
     68  }
     69 
     70 protected:
     71  void CheckedAppendToBuffer(const char* aData, size_t aLength) {
     72    EXPECT_NS_SUCCEEDED(mSourceBuffer->Append(aData, aLength));
     73  }
     74 
     75  void CheckedAppendToBufferLastByteForLength(size_t aLength) {
     76    const char lastByte = GenerateByte(aLength);
     77    CheckedAppendToBuffer(&lastByte, 1);
     78  }
     79 
     80  void CheckedAppendToBufferInChunks(size_t aChunkLength, size_t aTotalLength) {
     81    char* data = new char[aChunkLength];
     82 
     83    size_t bytesWritten = 0;
     84    while (bytesWritten < aTotalLength) {
     85      GenerateData(data, bytesWritten, aChunkLength);
     86      size_t toWrite = min(aChunkLength, aTotalLength - bytesWritten);
     87      CheckedAppendToBuffer(data, toWrite);
     88      bytesWritten += toWrite;
     89    }
     90 
     91    delete[] data;
     92  }
     93 
     94  void CheckedCompleteBuffer(nsresult aCompletionStatus = NS_OK) {
     95    mSourceBuffer->Complete(aCompletionStatus);
     96    EXPECT_TRUE(mSourceBuffer->IsComplete());
     97  }
     98 
     99  void CheckedCompleteBuffer(SourceBufferIterator& aIterator, size_t aLength,
    100                             nsresult aCompletionStatus = NS_OK) {
    101    CheckedCompleteBuffer(aCompletionStatus);
    102    ExpectRemainingBytes(aIterator, aLength);
    103  }
    104 
    105  void CheckedAdvanceIteratorStateOnly(
    106      SourceBufferIterator& aIterator, size_t aLength, uint32_t aChunks,
    107      size_t aTotalLength,
    108      AdvanceMode aAdvanceMode = AdvanceMode::eAdvanceAsMuchAsPossible) {
    109    const size_t advanceBy =
    110        aAdvanceMode == AdvanceMode::eAdvanceAsMuchAsPossible ? SIZE_MAX
    111                                                              : aLength;
    112 
    113    auto state = aIterator.AdvanceOrScheduleResume(advanceBy, mExpectNoResume);
    114    ASSERT_EQ(SourceBufferIterator::READY, state);
    115    EXPECT_TRUE(aIterator.Data());
    116    EXPECT_EQ(aLength, aIterator.Length());
    117 
    118    ExpectChunkAndByteCount(aIterator, aChunks, aTotalLength);
    119  }
    120 
    121  void CheckedAdvanceIteratorStateOnly(SourceBufferIterator& aIterator,
    122                                       size_t aLength) {
    123    CheckedAdvanceIteratorStateOnly(aIterator, aLength, 1, aLength);
    124  }
    125 
    126  void CheckedAdvanceIterator(
    127      SourceBufferIterator& aIterator, size_t aLength, uint32_t aChunks,
    128      size_t aTotalLength,
    129      AdvanceMode aAdvanceMode = AdvanceMode::eAdvanceAsMuchAsPossible) {
    130    // Check that the iterator is in the expected state.
    131    CheckedAdvanceIteratorStateOnly(aIterator, aLength, aChunks, aTotalLength,
    132                                    aAdvanceMode);
    133 
    134    // Check that we read the expected data. To do this, we need to compute our
    135    // offset in the SourceBuffer, but fortunately that's pretty easy: it's the
    136    // total number of bytes the iterator has advanced through, minus the length
    137    // of the current chunk.
    138    const size_t offset = aIterator.ByteCount() - aIterator.Length();
    139    CheckData(aIterator.Data(), offset, aIterator.Length());
    140  }
    141 
    142  void CheckedAdvanceIterator(SourceBufferIterator& aIterator, size_t aLength) {
    143    CheckedAdvanceIterator(aIterator, aLength, 1, aLength);
    144  }
    145 
    146  void CheckIteratorMustWait(SourceBufferIterator& aIterator,
    147                             IResumable* aOnResume) {
    148    auto state = aIterator.AdvanceOrScheduleResume(1, aOnResume);
    149    EXPECT_EQ(SourceBufferIterator::WAITING, state);
    150  }
    151 
    152  void CheckIteratorIsComplete(SourceBufferIterator& aIterator,
    153                               uint32_t aChunks, size_t aTotalLength,
    154                               nsresult aCompletionStatus = NS_OK) {
    155    ASSERT_TRUE(mSourceBuffer->IsComplete());
    156    auto state = aIterator.AdvanceOrScheduleResume(1, mExpectNoResume);
    157    ASSERT_EQ(SourceBufferIterator::COMPLETE, state);
    158    EXPECT_EQ(aCompletionStatus, aIterator.CompletionStatus());
    159    ExpectRemainingBytes(aIterator, 0);
    160    ExpectChunkAndByteCount(aIterator, aChunks, aTotalLength);
    161  }
    162 
    163  void CheckIteratorIsComplete(SourceBufferIterator& aIterator,
    164                               size_t aTotalLength) {
    165    CheckIteratorIsComplete(aIterator, 1, aTotalLength);
    166  }
    167 
    168  AutoInitializeImageLib mInit;
    169  char mData[9];
    170  RefPtr<SourceBuffer> mSourceBuffer;
    171  RefPtr<ExpectNoResume> mExpectNoResume;
    172  RefPtr<CountResumes> mCountResumes;
    173 };
    174 
    175 TEST_F(ImageSourceBuffer, InitialState) {
    176  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    177 
    178  // RemainingBytesIsNoMoreThan() should always return false in the initial
    179  // state, since we can't know the answer until Complete() has been called.
    180  EXPECT_FALSE(iterator.RemainingBytesIsNoMoreThan(0));
    181  EXPECT_FALSE(iterator.RemainingBytesIsNoMoreThan(SIZE_MAX));
    182 
    183  // We haven't advanced our iterator at all, so its counters should be zero.
    184  ExpectChunkAndByteCount(iterator, 0, 0);
    185 
    186  // Attempt to advance; we should fail, and end up in the WAITING state. We
    187  // expect no resumes because we don't actually append anything to the
    188  // SourceBuffer in this test.
    189  CheckIteratorMustWait(iterator, mExpectNoResume);
    190 }
    191 
    192 TEST_F(ImageSourceBuffer, ZeroLengthBufferAlwaysFails) {
    193  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    194 
    195  // Complete the buffer without writing to it, providing a successful
    196  // completion status.
    197  CheckedCompleteBuffer(iterator, 0);
    198 
    199  // Completing a buffer without writing to it results in an automatic failure;
    200  // make sure that the actual completion status we get from the iterator
    201  // reflects this.
    202  CheckIteratorIsComplete(iterator, 0, 0, NS_ERROR_FAILURE);
    203 }
    204 
    205 TEST_F(ImageSourceBuffer, CompleteSuccess) {
    206  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    207 
    208  // Write a single byte to the buffer and complete the buffer. (We have to
    209  // write at least one byte because completing a zero length buffer always
    210  // fails; see the ZeroLengthBufferAlwaysFails test.)
    211  CheckedAppendToBuffer(mData, 1);
    212  CheckedCompleteBuffer(iterator, 1);
    213 
    214  // We should be able to advance once (to read the single byte) and then should
    215  // reach the COMPLETE state with a successful status.
    216  CheckedAdvanceIterator(iterator, 1);
    217  CheckIteratorIsComplete(iterator, 1);
    218 }
    219 
    220 TEST_F(ImageSourceBuffer, CompleteFailure) {
    221  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    222 
    223  // Write a single byte to the buffer and complete the buffer. (We have to
    224  // write at least one byte because completing a zero length buffer always
    225  // fails; see the ZeroLengthBufferAlwaysFails test.)
    226  CheckedAppendToBuffer(mData, 1);
    227  CheckedCompleteBuffer(iterator, 1, NS_ERROR_FAILURE);
    228 
    229  // Advance the iterator. Because a failing status is propagated to the
    230  // iterator as soon as it advances, we won't be able to read the single byte
    231  // that we wrote above; we go directly into the COMPLETE state.
    232  CheckIteratorIsComplete(iterator, 0, 0, NS_ERROR_FAILURE);
    233 }
    234 
    235 TEST_F(ImageSourceBuffer, Append) {
    236  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    237 
    238  // Write test data to the buffer.
    239  EXPECT_NS_SUCCEEDED(mSourceBuffer->ExpectLength(sizeof(mData)));
    240  CheckedAppendToBuffer(mData, sizeof(mData));
    241  CheckedCompleteBuffer(iterator, sizeof(mData));
    242 
    243  // Verify that we can read it back via the iterator, and that the final state
    244  // is what we expect.
    245  CheckedAdvanceIterator(iterator, sizeof(mData));
    246  CheckIteratorIsComplete(iterator, sizeof(mData));
    247 }
    248 
    249 TEST_F(ImageSourceBuffer, HugeAppendFails) {
    250  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    251 
    252  // We should fail to append anything bigger than what the SurfaceCache can
    253  // hold, so use the SurfaceCache's maximum capacity to calculate what a
    254  // "massive amount of data" (see below) consists of on this platform.
    255  ASSERT_LT(SurfaceCache::MaximumCapacity(), SIZE_MAX);
    256  const size_t hugeSize = SurfaceCache::MaximumCapacity() + 1;
    257 
    258  // Attempt to write a massive amount of data and verify that it fails. (We'd
    259  // get a buffer overrun during the test if it succeeds, but if it succeeds
    260  // that's the least of our problems.)
    261  EXPECT_NS_FAILED(mSourceBuffer->Append(mData, hugeSize));
    262  EXPECT_TRUE(mSourceBuffer->IsComplete());
    263  CheckIteratorIsComplete(iterator, 0, 0, NS_ERROR_OUT_OF_MEMORY);
    264 }
    265 
    266 TEST_F(ImageSourceBuffer, AppendFromInputStream) {
    267  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    268 
    269  // Construct an input stream with some arbitrary data. (We use test data from
    270  // one of the decoder tests.)
    271  nsCOMPtr<nsIInputStream> inputStream = LoadFile(GreenPNGTestCase().mPath);
    272  ASSERT_TRUE(inputStream != nullptr);
    273 
    274  // Figure out how much data we have.
    275  uint64_t length;
    276  ASSERT_NS_SUCCEEDED(inputStream->Available(&length));
    277 
    278  // Write test data to the buffer.
    279  EXPECT_TRUE(
    280      NS_SUCCEEDED(mSourceBuffer->AppendFromInputStream(inputStream, length)));
    281  CheckedCompleteBuffer(iterator, length);
    282 
    283  // Verify that the iterator sees the appropriate amount of data.
    284  CheckedAdvanceIteratorStateOnly(iterator, length);
    285  CheckIteratorIsComplete(iterator, length);
    286 }
    287 
    288 TEST_F(ImageSourceBuffer, AppendAfterComplete) {
    289  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    290 
    291  // Write test data to the buffer.
    292  EXPECT_NS_SUCCEEDED(mSourceBuffer->ExpectLength(sizeof(mData)));
    293  CheckedAppendToBuffer(mData, sizeof(mData));
    294  CheckedCompleteBuffer(iterator, sizeof(mData));
    295 
    296  // Verify that we can read it back via the iterator, and that the final state
    297  // is what we expect.
    298  CheckedAdvanceIterator(iterator, sizeof(mData));
    299  CheckIteratorIsComplete(iterator, sizeof(mData));
    300 
    301  // Write more data to the completed buffer.
    302  EXPECT_NS_FAILED(mSourceBuffer->Append(mData, sizeof(mData)));
    303 
    304  // Try to read with a new iterator and verify that the new data got ignored.
    305  SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
    306  CheckedAdvanceIterator(iterator2, sizeof(mData));
    307  CheckIteratorIsComplete(iterator2, sizeof(mData));
    308 }
    309 
    310 TEST_F(ImageSourceBuffer, MinChunkCapacity) {
    311  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    312 
    313  // Write test data to the buffer using many small appends. Since
    314  // ExpectLength() isn't being called, we should be able to write up to
    315  // SourceBuffer::MIN_CHUNK_CAPACITY bytes without a second chunk being
    316  // allocated.
    317  CheckedAppendToBufferInChunks(10, SourceBuffer::MIN_CHUNK_CAPACITY);
    318 
    319  // Verify that the iterator sees the appropriate amount of data.
    320  CheckedAdvanceIterator(iterator, SourceBuffer::MIN_CHUNK_CAPACITY);
    321 
    322  // Write one more byte; we expect to see that it triggers an allocation.
    323  CheckedAppendToBufferLastByteForLength(SourceBuffer::MIN_CHUNK_CAPACITY);
    324  CheckedCompleteBuffer(iterator, 1);
    325 
    326  // Verify that the iterator sees the new byte and a new chunk has been
    327  // allocated.
    328  CheckedAdvanceIterator(iterator, 1, 2, SourceBuffer::MIN_CHUNK_CAPACITY + 1);
    329  CheckIteratorIsComplete(iterator, 2, SourceBuffer::MIN_CHUNK_CAPACITY + 1);
    330 }
    331 
    332 TEST_F(ImageSourceBuffer, ExpectLengthAllocatesRequestedCapacity) {
    333  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    334 
    335  // Write SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the buffer,
    336  // but call ExpectLength() first to make SourceBuffer expect only a single
    337  // byte. We expect this to still result in two chunks, because we trust the
    338  // initial guess of ExpectLength() but after that it will only allocate chunks
    339  // of at least MIN_CHUNK_CAPACITY bytes.
    340  EXPECT_NS_SUCCEEDED(mSourceBuffer->ExpectLength(1));
    341  CheckedAppendToBufferInChunks(10, SourceBuffer::MIN_CHUNK_CAPACITY);
    342  CheckedCompleteBuffer(iterator, SourceBuffer::MIN_CHUNK_CAPACITY);
    343 
    344  // Verify that the iterator sees a first chunk with 1 byte, and a second chunk
    345  // with the remaining data.
    346  CheckedAdvanceIterator(iterator, 1, 1, 1);
    347  CheckedAdvanceIterator(iterator, SourceBuffer::MIN_CHUNK_CAPACITY - 1, 2,
    348                         SourceBuffer::MIN_CHUNK_CAPACITY);
    349  CheckIteratorIsComplete(iterator, 2, SourceBuffer::MIN_CHUNK_CAPACITY);
    350 }
    351 
    352 TEST_F(ImageSourceBuffer, ExpectLengthGrowsAboveMinCapacity) {
    353  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    354 
    355  // Write two times SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
    356  // buffer, calling ExpectLength() with the correct length first. We expect
    357  // this to result in only one chunk, because ExpectLength() allows us to
    358  // allocate a larger first chunk than MIN_CHUNK_CAPACITY bytes.
    359  const size_t length = 2 * SourceBuffer::MIN_CHUNK_CAPACITY;
    360  EXPECT_NS_SUCCEEDED(mSourceBuffer->ExpectLength(length));
    361  CheckedAppendToBufferInChunks(10, length);
    362 
    363  // Verify that the iterator sees a single chunk.
    364  CheckedAdvanceIterator(iterator, length);
    365 
    366  // Write one more byte; we expect to see that it triggers an allocation.
    367  CheckedAppendToBufferLastByteForLength(length);
    368  CheckedCompleteBuffer(iterator, 1);
    369 
    370  // Verify that the iterator sees the new byte and a new chunk has been
    371  // allocated.
    372  CheckedAdvanceIterator(iterator, 1, 2, length + 1);
    373  CheckIteratorIsComplete(iterator, 2, length + 1);
    374 }
    375 
    376 TEST_F(ImageSourceBuffer, HugeExpectLengthFails) {
    377  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    378 
    379  // ExpectLength() should fail if the length is bigger than what the
    380  // SurfaceCache can hold, so use the SurfaceCache's maximum capacity to
    381  // calculate what a "massive amount of data" (see below) consists of on this
    382  // platform.
    383  ASSERT_LT(SurfaceCache::MaximumCapacity(), SIZE_MAX);
    384  const size_t hugeSize = SurfaceCache::MaximumCapacity() + 1;
    385 
    386  // Attempt to write a massive amount of data and verify that it fails. (We'd
    387  // get a buffer overrun during the test if it succeeds, but if it succeeds
    388  // that's the least of our problems.)
    389  EXPECT_NS_FAILED(mSourceBuffer->ExpectLength(hugeSize));
    390  EXPECT_TRUE(mSourceBuffer->IsComplete());
    391  CheckIteratorIsComplete(iterator, 0, 0, NS_ERROR_INVALID_ARG);
    392 }
    393 
    394 TEST_F(ImageSourceBuffer, LargeAppendsAllocateOnlyOneChunk) {
    395  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    396 
    397  // Write two times SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
    398  // buffer in a single Append() call. We expect this to result in only one
    399  // chunk even though ExpectLength() wasn't called, because we should always
    400  // allocate a new chunk large enough to store the data we have at hand.
    401  constexpr size_t length = 2 * SourceBuffer::MIN_CHUNK_CAPACITY;
    402  char data[length];
    403  GenerateData(data, sizeof(data));
    404  CheckedAppendToBuffer(data, length);
    405 
    406  // Verify that the iterator sees a single chunk.
    407  CheckedAdvanceIterator(iterator, length);
    408 
    409  // Write one more byte; we expect to see that it triggers an allocation.
    410  CheckedAppendToBufferLastByteForLength(length);
    411  CheckedCompleteBuffer(iterator, 1);
    412 
    413  // Verify that the iterator sees the new byte and a new chunk has been
    414  // allocated.
    415  CheckedAdvanceIterator(iterator, 1, 2, length + 1);
    416  CheckIteratorIsComplete(iterator, 2, length + 1);
    417 }
    418 
    419 TEST_F(ImageSourceBuffer, LargeAppendsAllocateAtMostOneChunk) {
    420  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    421 
    422  // Allocate some data we'll use below.
    423  constexpr size_t firstWriteLength = SourceBuffer::MIN_CHUNK_CAPACITY / 2;
    424  constexpr size_t secondWriteLength = 3 * SourceBuffer::MIN_CHUNK_CAPACITY;
    425  constexpr size_t totalLength = firstWriteLength + secondWriteLength;
    426  char data[totalLength];
    427  GenerateData(data, sizeof(data));
    428 
    429  // Write half of SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
    430  // buffer in a single Append() call. This should fill half of the first chunk.
    431  CheckedAppendToBuffer(data, firstWriteLength);
    432 
    433  // Write three times SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to
    434  // the buffer in a single Append() call. We expect this to result in the first
    435  // of the first chunk being filled and a new chunk being allocated for the
    436  // remainder.
    437  CheckedAppendToBuffer(data + firstWriteLength, secondWriteLength);
    438 
    439  // Verify that the iterator sees a MIN_CHUNK_CAPACITY-length chunk.
    440  CheckedAdvanceIterator(iterator, SourceBuffer::MIN_CHUNK_CAPACITY);
    441 
    442  // Verify that the iterator sees a second chunk of the length we expect.
    443  const size_t expectedSecondChunkLength =
    444      totalLength - SourceBuffer::MIN_CHUNK_CAPACITY;
    445  CheckedAdvanceIterator(iterator, expectedSecondChunkLength, 2, totalLength);
    446 
    447  // Write one more byte; we expect to see that it triggers an allocation.
    448  CheckedAppendToBufferLastByteForLength(totalLength);
    449  CheckedCompleteBuffer(iterator, 1);
    450 
    451  // Verify that the iterator sees the new byte and a new chunk has been
    452  // allocated.
    453  CheckedAdvanceIterator(iterator, 1, 3, totalLength + 1);
    454  CheckIteratorIsComplete(iterator, 3, totalLength + 1);
    455 }
    456 
    457 TEST_F(ImageSourceBuffer, OversizedAppendsAllocateAtMostOneChunk) {
    458  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    459 
    460  // Allocate some data we'll use below.
    461  constexpr size_t writeLength = SourceBuffer::MAX_CHUNK_CAPACITY + 1;
    462 
    463  // Write SourceBuffer::MAX_CHUNK_CAPACITY + 1 bytes of test data to the
    464  // buffer in a single Append() call. This should cause one chunk to be
    465  // allocated because we wrote it as a single block.
    466  CheckedAppendToBufferInChunks(writeLength, writeLength);
    467 
    468  // Verify that the iterator sees a MAX_CHUNK_CAPACITY+1-length chunk.
    469  CheckedAdvanceIterator(iterator, writeLength);
    470 
    471  CheckedCompleteBuffer(NS_OK);
    472  CheckIteratorIsComplete(iterator, 1, writeLength);
    473 }
    474 
    475 TEST_F(ImageSourceBuffer, CompactionHappensWhenBufferIsComplete) {
    476  constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
    477  constexpr size_t totalLength = 2 * chunkLength;
    478 
    479  // Write enough data to create two chunks.
    480  CheckedAppendToBufferInChunks(chunkLength, totalLength);
    481 
    482  {
    483    SourceBufferIterator iterator = mSourceBuffer->Iterator();
    484 
    485    // Verify that the iterator sees two chunks.
    486    CheckedAdvanceIterator(iterator, chunkLength);
    487    CheckedAdvanceIterator(iterator, chunkLength, 2, totalLength);
    488  }
    489 
    490  // Complete the buffer, which should trigger compaction implicitly.
    491  CheckedCompleteBuffer();
    492 
    493  {
    494    SourceBufferIterator iterator = mSourceBuffer->Iterator();
    495 
    496    // Verify that compaction happened and there's now only one chunk.
    497    CheckedAdvanceIterator(iterator, totalLength);
    498    CheckIteratorIsComplete(iterator, 1, totalLength);
    499  }
    500 }
    501 
    502 TEST_F(ImageSourceBuffer, CompactionIsDelayedWhileIteratorsExist) {
    503  constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
    504  constexpr size_t totalLength = 2 * chunkLength;
    505 
    506  {
    507    SourceBufferIterator outerIterator = mSourceBuffer->Iterator();
    508 
    509    {
    510      SourceBufferIterator iterator = mSourceBuffer->Iterator();
    511 
    512      // Write enough data to create two chunks.
    513      CheckedAppendToBufferInChunks(chunkLength, totalLength);
    514      CheckedCompleteBuffer(iterator, totalLength);
    515 
    516      // Verify that the iterator sees two chunks. Since there are live
    517      // iterators, compaction shouldn't have happened when we completed the
    518      // buffer.
    519      CheckedAdvanceIterator(iterator, chunkLength);
    520      CheckedAdvanceIterator(iterator, chunkLength, 2, totalLength);
    521      CheckIteratorIsComplete(iterator, 2, totalLength);
    522    }
    523 
    524    // Now |iterator| has been destroyed, but |outerIterator| still exists, so
    525    // we expect no compaction to have occurred at this point.
    526    CheckedAdvanceIterator(outerIterator, chunkLength);
    527    CheckedAdvanceIterator(outerIterator, chunkLength, 2, totalLength);
    528    CheckIteratorIsComplete(outerIterator, 2, totalLength);
    529  }
    530 
    531  // Now all iterators have been destroyed. Since the buffer was already
    532  // complete, we expect compaction to happen implicitly here.
    533 
    534  {
    535    SourceBufferIterator iterator = mSourceBuffer->Iterator();
    536 
    537    // Verify that compaction happened and there's now only one chunk.
    538    CheckedAdvanceIterator(iterator, totalLength);
    539    CheckIteratorIsComplete(iterator, 1, totalLength);
    540  }
    541 }
    542 
    543 TEST_F(ImageSourceBuffer, SourceBufferIteratorsCanBeMoved) {
    544  constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
    545  constexpr size_t totalLength = 2 * chunkLength;
    546 
    547  // Write enough data to create two chunks. We create an iterator here to make
    548  // sure that compaction doesn't happen during the test.
    549  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    550  CheckedAppendToBufferInChunks(chunkLength, totalLength);
    551  CheckedCompleteBuffer(iterator, totalLength);
    552 
    553  auto GetIterator = [&] {
    554    SourceBufferIterator lambdaIterator = mSourceBuffer->Iterator();
    555    CheckedAdvanceIterator(lambdaIterator, chunkLength);
    556    return lambdaIterator;
    557  };
    558 
    559  // Move-construct |movedIterator| from the iterator returned from
    560  // GetIterator() and check that its state is as we expect.
    561  SourceBufferIterator tmpIterator = GetIterator();
    562  SourceBufferIterator movedIterator(std::move(tmpIterator));
    563  EXPECT_TRUE(movedIterator.Data());
    564  EXPECT_EQ(chunkLength, movedIterator.Length());
    565  ExpectChunkAndByteCount(movedIterator, 1, chunkLength);
    566 
    567  // Make sure that we can advance the iterator.
    568  CheckedAdvanceIterator(movedIterator, chunkLength, 2, totalLength);
    569 
    570  // Make sure that the iterator handles completion properly.
    571  CheckIteratorIsComplete(movedIterator, 2, totalLength);
    572 
    573  // Move-assign |movedIterator| from the iterator returned from
    574  // GetIterator() and check that its state is as we expect.
    575  tmpIterator = GetIterator();
    576  movedIterator = std::move(tmpIterator);
    577  EXPECT_TRUE(movedIterator.Data());
    578  EXPECT_EQ(chunkLength, movedIterator.Length());
    579  ExpectChunkAndByteCount(movedIterator, 1, chunkLength);
    580 
    581  // Make sure that we can advance the iterator.
    582  CheckedAdvanceIterator(movedIterator, chunkLength, 2, totalLength);
    583 
    584  // Make sure that the iterator handles completion properly.
    585  CheckIteratorIsComplete(movedIterator, 2, totalLength);
    586 }
    587 
    588 TEST_F(ImageSourceBuffer, SubchunkAdvance) {
    589  constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
    590  constexpr size_t totalLength = 2 * chunkLength;
    591 
    592  // Write enough data to create two chunks. We create our iterator here to make
    593  // sure that compaction doesn't happen during the test.
    594  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    595  CheckedAppendToBufferInChunks(chunkLength, totalLength);
    596  CheckedCompleteBuffer(iterator, totalLength);
    597 
    598  // Advance through the first chunk. The chunk count should not increase.
    599  // We check that by always passing 1 for the |aChunks| parameter of
    600  // CheckedAdvanceIteratorStateOnly(). We have to call CheckData() manually
    601  // because the offset calculation in CheckedAdvanceIterator() assumes that
    602  // we're advancing a chunk at a time.
    603  size_t offset = 0;
    604  while (offset < chunkLength) {
    605    CheckedAdvanceIteratorStateOnly(iterator, 1, 1, chunkLength,
    606                                    AdvanceMode::eAdvanceByLengthExactly);
    607    CheckData(iterator.Data(), offset++, iterator.Length());
    608  }
    609 
    610  // Read the first byte of the second chunk. This is the point at which we
    611  // can't advance within the same chunk, so the chunk count should increase. We
    612  // check that by passing 2 for the |aChunks| parameter of
    613  // CheckedAdvanceIteratorStateOnly().
    614  CheckedAdvanceIteratorStateOnly(iterator, 1, 2, totalLength,
    615                                  AdvanceMode::eAdvanceByLengthExactly);
    616  CheckData(iterator.Data(), offset++, iterator.Length());
    617 
    618  // Read the rest of the second chunk. The chunk count should not increase.
    619  while (offset < totalLength) {
    620    CheckedAdvanceIteratorStateOnly(iterator, 1, 2, totalLength,
    621                                    AdvanceMode::eAdvanceByLengthExactly);
    622    CheckData(iterator.Data(), offset++, iterator.Length());
    623  }
    624 
    625  // Make sure we reached the end.
    626  CheckIteratorIsComplete(iterator, 2, totalLength);
    627 }
    628 
    629 TEST_F(ImageSourceBuffer, SubchunkZeroByteAdvance) {
    630  constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
    631  constexpr size_t totalLength = 2 * chunkLength;
    632 
    633  // Write enough data to create two chunks. We create our iterator here to make
    634  // sure that compaction doesn't happen during the test.
    635  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    636  CheckedAppendToBufferInChunks(chunkLength, totalLength);
    637  CheckedCompleteBuffer(iterator, totalLength);
    638 
    639  // Make an initial zero-length advance. Although a zero-length advance
    640  // normally won't cause us to read a chunk from the SourceBuffer, we'll do so
    641  // if the iterator is in the initial state to keep the invariant that
    642  // SourceBufferIterator in the READY state always returns a non-null pointer
    643  // from Data().
    644  CheckedAdvanceIteratorStateOnly(iterator, 0, 1, chunkLength,
    645                                  AdvanceMode::eAdvanceByLengthExactly);
    646 
    647  // Advance through the first chunk. As in the |SubchunkAdvance| test, the
    648  // chunk count should not increase. We do a zero-length advance after each
    649  // normal advance to ensure that zero-length advances do not change the
    650  // iterator's position or cause a new chunk to be read.
    651  size_t offset = 0;
    652  while (offset < chunkLength) {
    653    CheckedAdvanceIteratorStateOnly(iterator, 1, 1, chunkLength,
    654                                    AdvanceMode::eAdvanceByLengthExactly);
    655    CheckData(iterator.Data(), offset++, iterator.Length());
    656    CheckedAdvanceIteratorStateOnly(iterator, 0, 1, chunkLength,
    657                                    AdvanceMode::eAdvanceByLengthExactly);
    658  }
    659 
    660  // Read the first byte of the second chunk. This is the point at which we
    661  // can't advance within the same chunk, so the chunk count should increase. As
    662  // before, we do a zero-length advance afterward.
    663  CheckedAdvanceIteratorStateOnly(iterator, 1, 2, totalLength,
    664                                  AdvanceMode::eAdvanceByLengthExactly);
    665  CheckData(iterator.Data(), offset++, iterator.Length());
    666  CheckedAdvanceIteratorStateOnly(iterator, 0, 2, totalLength,
    667                                  AdvanceMode::eAdvanceByLengthExactly);
    668 
    669  // Read the rest of the second chunk. The chunk count should not increase. As
    670  // before, we do a zero-length advance after each normal advance.
    671  while (offset < totalLength) {
    672    CheckedAdvanceIteratorStateOnly(iterator, 1, 2, totalLength,
    673                                    AdvanceMode::eAdvanceByLengthExactly);
    674    CheckData(iterator.Data(), offset++, iterator.Length());
    675    CheckedAdvanceIteratorStateOnly(iterator, 0, 2, totalLength,
    676                                    AdvanceMode::eAdvanceByLengthExactly);
    677  }
    678 
    679  // Make sure we reached the end.
    680  CheckIteratorIsComplete(iterator, 2, totalLength);
    681 }
    682 
    683 TEST_F(ImageSourceBuffer, SubchunkZeroByteAdvanceWithNoData) {
    684  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    685 
    686  // Check that advancing by zero bytes still makes us enter the WAITING state.
    687  // This is because if we entered the READY state before reading any data at
    688  // all, we'd break the invariant that SourceBufferIterator::Data() always
    689  // returns a non-null pointer in the READY state.
    690  auto state = iterator.AdvanceOrScheduleResume(0, mCountResumes);
    691  EXPECT_EQ(SourceBufferIterator::WAITING, state);
    692 
    693  // Call Complete(). This should trigger a resume.
    694  CheckedCompleteBuffer();
    695  EXPECT_EQ(1u, mCountResumes->Count());
    696 }
    697 
    698 TEST_F(ImageSourceBuffer, NullIResumable) {
    699  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    700 
    701  // Check that we can't advance.
    702  CheckIteratorMustWait(iterator, nullptr);
    703 
    704  // Append to the buffer, which would cause a resume if we had passed a
    705  // non-null IResumable.
    706  CheckedAppendToBuffer(mData, sizeof(mData));
    707  CheckedCompleteBuffer(iterator, sizeof(mData));
    708 }
    709 
    710 TEST_F(ImageSourceBuffer, AppendTriggersResume) {
    711  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    712 
    713  // Check that we can't advance.
    714  CheckIteratorMustWait(iterator, mCountResumes);
    715 
    716  // Call Append(). This should trigger a resume.
    717  mSourceBuffer->Append(mData, sizeof(mData));
    718  EXPECT_EQ(1u, mCountResumes->Count());
    719 }
    720 
    721 TEST_F(ImageSourceBuffer, OnlyOneResumeTriggeredPerAppend) {
    722  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    723 
    724  // Check that we can't advance.
    725  CheckIteratorMustWait(iterator, mCountResumes);
    726 
    727  // Allocate some data we'll use below.
    728  constexpr size_t firstWriteLength = SourceBuffer::MIN_CHUNK_CAPACITY / 2;
    729  constexpr size_t secondWriteLength = 3 * SourceBuffer::MIN_CHUNK_CAPACITY;
    730  constexpr size_t totalLength = firstWriteLength + secondWriteLength;
    731  char data[totalLength];
    732  GenerateData(data, sizeof(data));
    733 
    734  // Write half of SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
    735  // buffer in a single Append() call. This should fill half of the first chunk.
    736  // This should trigger a resume.
    737  CheckedAppendToBuffer(data, firstWriteLength);
    738  EXPECT_EQ(1u, mCountResumes->Count());
    739 
    740  // Advance past the new data and wait again.
    741  CheckedAdvanceIterator(iterator, firstWriteLength);
    742  CheckIteratorMustWait(iterator, mCountResumes);
    743 
    744  // Write three times SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to
    745  // the buffer in a single Append() call. We expect this to result in the first
    746  // of the first chunk being filled and a new chunk being allocated for the
    747  // remainder. Even though two chunks are getting written to here, only *one*
    748  // resume should get triggered, for a total of two in this test.
    749  CheckedAppendToBuffer(data + firstWriteLength, secondWriteLength);
    750  EXPECT_EQ(2u, mCountResumes->Count());
    751 }
    752 
    753 TEST_F(ImageSourceBuffer, CompleteTriggersResume) {
    754  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    755 
    756  // Check that we can't advance.
    757  CheckIteratorMustWait(iterator, mCountResumes);
    758 
    759  // Call Complete(). This should trigger a resume.
    760  CheckedCompleteBuffer();
    761  EXPECT_EQ(1u, mCountResumes->Count());
    762 }
    763 
    764 TEST_F(ImageSourceBuffer, ExpectLengthDoesNotTriggerResume) {
    765  SourceBufferIterator iterator = mSourceBuffer->Iterator();
    766 
    767  // Check that we can't advance.
    768  CheckIteratorMustWait(iterator, mExpectNoResume);
    769 
    770  // Call ExpectLength(). If this triggers a resume, |mExpectNoResume| will
    771  // ensure that the test fails.
    772  mSourceBuffer->ExpectLength(1000);
    773 }
    774 
    775 TEST_F(ImageSourceBuffer, CompleteSuccessWithSameReadLength) {
    776  SourceBufferIterator iterator = mSourceBuffer->Iterator(1);
    777 
    778  // Write a single byte to the buffer and complete the buffer. (We have to
    779  // write at least one byte because completing a zero length buffer always
    780  // fails; see the ZeroLengthBufferAlwaysFails test.)
    781  CheckedAppendToBuffer(mData, 1);
    782  CheckedCompleteBuffer(iterator, 1);
    783 
    784  // We should be able to advance once (to read the single byte) and then should
    785  // reach the COMPLETE state with a successful status.
    786  CheckedAdvanceIterator(iterator, 1);
    787  CheckIteratorIsComplete(iterator, 1);
    788 }
    789 
    790 TEST_F(ImageSourceBuffer, CompleteSuccessWithSmallerReadLength) {
    791  // Create an iterator limited to one byte.
    792  SourceBufferIterator iterator = mSourceBuffer->Iterator(1);
    793 
    794  // Write two bytes to the buffer and complete the buffer. (We have to
    795  // write at least one byte because completing a zero length buffer always
    796  // fails; see the ZeroLengthBufferAlwaysFails test.)
    797  CheckedAppendToBuffer(mData, 2);
    798  CheckedCompleteBuffer(iterator, 2);
    799 
    800  // We should be able to advance once (to read the single byte) and then should
    801  // reach the COMPLETE state with a successful status, because our iterator is
    802  // limited to a single byte, rather than the full length.
    803  CheckedAdvanceIterator(iterator, 1);
    804  CheckIteratorIsComplete(iterator, 1);
    805 }
    806 
    807 TEST_F(ImageSourceBuffer, CompleteSuccessWithGreaterReadLength) {
    808  // Create an iterator limited to one byte.
    809  SourceBufferIterator iterator = mSourceBuffer->Iterator(2);
    810 
    811  // Write a single byte to the buffer and complete the buffer. (We have to
    812  // write at least one byte because completing a zero length buffer always
    813  // fails; see the ZeroLengthBufferAlwaysFails test.)
    814  CheckedAppendToBuffer(mData, 1);
    815  CheckedCompleteBuffer(iterator, 1);
    816 
    817  // We should be able to advance once (to read the single byte) and then should
    818  // reach the COMPLETE state with a successful status. Our iterator lets us
    819  // read more but the underlying buffer has been completed.
    820  CheckedAdvanceIterator(iterator, 1);
    821  CheckIteratorIsComplete(iterator, 1);
    822 }