Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2013 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkAutoMalloc.h"
      9 #include "SkBitmap.h"
     10 #include "SkCodec.h"
     11 #include "SkFrontBufferedStream.h"
     12 #include "SkRefCnt.h"
     13 #include "SkStream.h"
     14 #include "Test.h"
     15 
     16 static void test_read(skiatest::Reporter* reporter, SkStream* bufferedStream,
     17                       const void* expectations, size_t bytesToRead) {
     18     // output for reading bufferedStream.
     19     SkAutoMalloc storage(bytesToRead);
     20 
     21     const size_t bytesRead = bufferedStream->read(storage.get(), bytesToRead);
     22     REPORTER_ASSERT(reporter, bytesRead == bytesToRead || bufferedStream->isAtEnd());
     23     REPORTER_ASSERT(reporter, memcmp(storage.get(), expectations, bytesRead) == 0);
     24 }
     25 
     26 static void test_rewind(skiatest::Reporter* reporter,
     27                         SkStream* bufferedStream, bool shouldSucceed) {
     28     const bool success = bufferedStream->rewind();
     29     REPORTER_ASSERT(reporter, success == shouldSucceed);
     30 }
     31 
     32 // Test that hasLength() returns the correct value, based on the stream
     33 // being wrapped. A length can only be known if the wrapped stream has a
     34 // length and it has a position (so its initial position can be taken into
     35 // account when computing the length).
     36 static void test_hasLength(skiatest::Reporter* reporter,
     37                            const SkStream& bufferedStream,
     38                            const SkStream& streamBeingBuffered) {
     39     if (streamBeingBuffered.hasLength() && streamBeingBuffered.hasPosition()) {
     40         REPORTER_ASSERT(reporter, bufferedStream.hasLength());
     41     } else {
     42         REPORTER_ASSERT(reporter, !bufferedStream.hasLength());
     43     }
     44 }
     45 
     46 // All tests will buffer this string, and compare output to the original.
     47 // The string is long to ensure that all of our lengths being tested are
     48 // smaller than the string length.
     49 const char gAbcs[] = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx";
     50 
     51 // Tests reading the stream across boundaries of what has been buffered so far and what
     52 // the total buffer size is.
     53 static void test_incremental_buffering(skiatest::Reporter* reporter, size_t bufferSize) {
     54     // NOTE: For this and other tests in this file, we cheat and continue to refer to the
     55     // wrapped stream, but that's okay because we know the wrapping stream has not been
     56     // deleted yet (and we only call const methods in it).
     57     SkMemoryStream* memStream = SkMemoryStream::MakeDirect(gAbcs, strlen(gAbcs)).release();
     58 
     59     auto bufferedStream = SkFrontBufferedStream::Make(std::unique_ptr<SkStream>(memStream),
     60                                                       bufferSize);
     61     test_hasLength(reporter, *bufferedStream, *memStream);
     62 
     63     // First, test reading less than the max buffer size.
     64     test_read(reporter, bufferedStream.get(), gAbcs, bufferSize / 2);
     65 
     66     // Now test rewinding back to the beginning and reading less than what was
     67     // already buffered.
     68     test_rewind(reporter, bufferedStream.get(), true);
     69     test_read(reporter, bufferedStream.get(), gAbcs, bufferSize / 4);
     70 
     71     // Now test reading part of what was buffered, and buffering new data.
     72     test_read(reporter, bufferedStream.get(), gAbcs + bufferSize / 4, bufferSize / 2);
     73 
     74     // Now test reading what was buffered, buffering new data, and
     75     // reading directly from the stream.
     76     test_rewind(reporter, bufferedStream.get(), true);
     77     test_read(reporter, bufferedStream.get(), gAbcs, bufferSize << 1);
     78 
     79     // We have reached the end of the buffer, so rewinding will fail.
     80     // This test assumes that the stream is larger than the buffer; otherwise the
     81     // result of rewind should be true.
     82     test_rewind(reporter, bufferedStream.get(), false);
     83 }
     84 
     85 static void test_perfectly_sized_buffer(skiatest::Reporter* reporter, size_t bufferSize) {
     86     SkMemoryStream* memStream = SkMemoryStream::MakeDirect(gAbcs, strlen(gAbcs)).release();
     87     auto bufferedStream = SkFrontBufferedStream::Make(std::unique_ptr<SkStream>(memStream),
     88                                                       bufferSize);
     89     test_hasLength(reporter, *bufferedStream, *memStream);
     90 
     91     // Read exactly the amount that fits in the buffer.
     92     test_read(reporter, bufferedStream.get(), gAbcs, bufferSize);
     93 
     94     // Rewinding should succeed.
     95     test_rewind(reporter, bufferedStream.get(), true);
     96 
     97     // Once again reading buffered info should succeed
     98     test_read(reporter, bufferedStream.get(), gAbcs, bufferSize);
     99 
    100     // Read past the size of the buffer. At this point, we cannot return.
    101     test_read(reporter, bufferedStream.get(), gAbcs + memStream->getPosition(), 1);
    102     test_rewind(reporter, bufferedStream.get(), false);
    103 }
    104 
    105 static void test_skipping(skiatest::Reporter* reporter, size_t bufferSize) {
    106     SkMemoryStream* memStream = SkMemoryStream::MakeDirect(gAbcs, strlen(gAbcs)).release();
    107     auto bufferedStream = SkFrontBufferedStream::Make(std::unique_ptr<SkStream>(memStream),
    108                                                       bufferSize);
    109     test_hasLength(reporter, *bufferedStream, *memStream);
    110 
    111     // Skip half the buffer.
    112     bufferedStream->skip(bufferSize / 2);
    113 
    114     // Rewind, then read part of the buffer, which should have been read.
    115     test_rewind(reporter, bufferedStream.get(), true);
    116     test_read(reporter, bufferedStream.get(), gAbcs, bufferSize / 4);
    117 
    118     // Now skip beyond the buffered piece, but still within the total buffer.
    119     bufferedStream->skip(bufferSize / 2);
    120 
    121     // Test that reading will still work.
    122     test_read(reporter, bufferedStream.get(), gAbcs + memStream->getPosition(), bufferSize / 4);
    123 
    124     test_rewind(reporter, bufferedStream.get(), true);
    125     test_read(reporter, bufferedStream.get(), gAbcs, bufferSize);
    126 }
    127 
    128 // A custom class whose isAtEnd behaves the way Android's stream does - since it is an adaptor to a
    129 // Java InputStream, it does not know that it is at the end until it has attempted to read beyond
    130 // the end and failed. Used by test_read_beyond_buffer.
    131 class AndroidLikeMemoryStream : public SkMemoryStream {
    132 public:
    133     AndroidLikeMemoryStream(void* data, size_t size, bool ownMemory)
    134         : INHERITED(data, size, ownMemory)
    135         , fIsAtEnd(false) {}
    136 
    137     size_t read(void* dst, size_t requested) override {
    138         size_t bytesRead = this->INHERITED::read(dst, requested);
    139         if (bytesRead < requested) {
    140             fIsAtEnd = true;
    141         }
    142         return bytesRead;
    143     }
    144 
    145     bool isAtEnd() const override {
    146         return fIsAtEnd;
    147     }
    148 
    149 private:
    150     bool fIsAtEnd;
    151     typedef SkMemoryStream INHERITED;
    152 };
    153 
    154 // This test ensures that buffering the exact length of the stream and attempting to read beyond it
    155 // does not invalidate the buffer.
    156 static void test_read_beyond_buffer(skiatest::Reporter* reporter, size_t bufferSize) {
    157     // Use a stream that behaves like Android's stream.
    158     AndroidLikeMemoryStream* memStream =
    159             new AndroidLikeMemoryStream((void*)gAbcs, bufferSize, false);
    160 
    161     // Create a buffer that matches the length of the stream.
    162     auto bufferedStream = SkFrontBufferedStream::Make(std::unique_ptr<SkStream>(memStream),
    163                                                       bufferSize);
    164     test_hasLength(reporter, *bufferedStream.get(), *memStream);
    165 
    166     // Attempt to read one more than the bufferSize
    167     test_read(reporter, bufferedStream.get(), gAbcs, bufferSize + 1);
    168     test_rewind(reporter, bufferedStream.get(), true);
    169 
    170     // Ensure that the initial read did not invalidate the buffer.
    171     test_read(reporter, bufferedStream.get(), gAbcs, bufferSize);
    172 }
    173 
    174 // Dummy stream that optionally has a length and/or position. Tests that FrontBufferedStream's
    175 // length depends on the stream it's buffering having a length and position.
    176 class LengthOptionalStream : public SkStream {
    177 public:
    178     LengthOptionalStream(bool hasLength, bool hasPosition)
    179         : fHasLength(hasLength)
    180         , fHasPosition(hasPosition)
    181     {}
    182 
    183     bool hasLength() const override {
    184         return fHasLength;
    185     }
    186 
    187     bool hasPosition() const override {
    188         return fHasPosition;
    189     }
    190 
    191     size_t read(void*, size_t) override {
    192         return 0;
    193     }
    194 
    195     bool isAtEnd() const override {
    196         return true;
    197     }
    198 
    199 private:
    200     const bool fHasLength;
    201     const bool fHasPosition;
    202 };
    203 
    204 // Test all possible combinations of the wrapped stream having a length and a position.
    205 static void test_length_combos(skiatest::Reporter* reporter, size_t bufferSize) {
    206     for (int hasLen = 0; hasLen <= 1; hasLen++) {
    207         for (int hasPos = 0; hasPos <= 1; hasPos++) {
    208             LengthOptionalStream* stream =
    209                     new LengthOptionalStream(SkToBool(hasLen), SkToBool(hasPos));
    210             auto buffered = SkFrontBufferedStream::Make(std::unique_ptr<SkStream>(stream),
    211                                                         bufferSize);
    212             test_hasLength(reporter, *buffered.get(), *stream);
    213         }
    214     }
    215 }
    216 
    217 // Test using a stream with an initial offset.
    218 static void test_initial_offset(skiatest::Reporter* reporter, size_t bufferSize) {
    219     SkMemoryStream* memStream = new SkMemoryStream(gAbcs, strlen(gAbcs), false);
    220 
    221     // Skip a few characters into the memStream, so that bufferedStream represents an offset into
    222     // the stream it wraps.
    223     const size_t arbitraryOffset = 17;
    224     memStream->skip(arbitraryOffset);
    225     auto bufferedStream = SkFrontBufferedStream::Make(std::unique_ptr<SkStream>(memStream),
    226                                                       bufferSize);
    227 
    228     // Since SkMemoryStream has a length, bufferedStream must also.
    229     REPORTER_ASSERT(reporter, bufferedStream->hasLength());
    230 
    231     const size_t amountToRead = 10;
    232     const size_t bufferedLength = bufferedStream->getLength();
    233     size_t currentPosition = 0;
    234 
    235     // Read the stream in chunks. After each read, the position must match currentPosition,
    236     // which sums the amount attempted to read, unless the end of the stream has been reached.
    237     // Importantly, the end should not have been reached until currentPosition == bufferedLength.
    238     while (currentPosition < bufferedLength) {
    239         REPORTER_ASSERT(reporter, !bufferedStream->isAtEnd());
    240         test_read(reporter, bufferedStream.get(), gAbcs + arbitraryOffset + currentPosition,
    241                   amountToRead);
    242         currentPosition = SkTMin(currentPosition + amountToRead, bufferedLength);
    243         REPORTER_ASSERT(reporter, memStream->getPosition() - arbitraryOffset == currentPosition);
    244     }
    245     REPORTER_ASSERT(reporter, bufferedStream->isAtEnd());
    246     REPORTER_ASSERT(reporter, bufferedLength == currentPosition);
    247 }
    248 
    249 static void test_buffers(skiatest::Reporter* reporter, size_t bufferSize) {
    250     test_incremental_buffering(reporter, bufferSize);
    251     test_perfectly_sized_buffer(reporter, bufferSize);
    252     test_skipping(reporter, bufferSize);
    253     test_read_beyond_buffer(reporter, bufferSize);
    254     test_length_combos(reporter, bufferSize);
    255     test_initial_offset(reporter, bufferSize);
    256 }
    257 
    258 DEF_TEST(FrontBufferedStream, reporter) {
    259     // Test 6 and 64, which are used by Android, as well as another arbitrary length.
    260     test_buffers(reporter, 6);
    261     test_buffers(reporter, 15);
    262     test_buffers(reporter, 64);
    263 }
    264 
    265 // Test that a FrontBufferedStream does not allow reading after the end of a stream.
    266 // This class is a dummy SkStream which reports that it is at the end on the first
    267 // read (simulating a failure). Then it tracks whether someone calls read() again.
    268 class FailingStream : public SkStream {
    269 public:
    270     FailingStream()
    271     : fAtEnd(false)
    272     {}
    273 
    274     size_t read(void* buffer, size_t size) override {
    275         SkASSERT(!fAtEnd);
    276         fAtEnd = true;
    277         return 0;
    278     }
    279 
    280     bool isAtEnd() const override {
    281         return fAtEnd;
    282     }
    283 
    284 private:
    285     bool fAtEnd;
    286 };
    287 
    288 DEF_TEST(ShortFrontBufferedStream, reporter) {
    289     FailingStream* failingStream = new FailingStream;
    290     auto stream = SkFrontBufferedStream::Make(std::unique_ptr<SkStream>(failingStream), 64);
    291 
    292     // This will fail to create a codec.  However, what we really want to test is that we
    293     // won't read past the end of the stream.
    294     std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
    295 }
    296