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 }