Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2011 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 "Resources.h"
      9 #include "SkAutoMalloc.h"
     10 #include "SkData.h"
     11 #include "SkFrontBufferedStream.h"
     12 #include "SkOSFile.h"
     13 #include "SkOSPath.h"
     14 #include "SkRandom.h"
     15 #include "SkStream.h"
     16 #include "SkStreamPriv.h"
     17 #include "Test.h"
     18 
     19 #ifndef SK_BUILD_FOR_WIN
     20 #include <unistd.h>
     21 #include <fcntl.h>
     22 #endif
     23 
     24 #define MAX_SIZE    (256 * 1024)
     25 
     26 static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream,
     27                              const void* src, size_t len, int repeat) {
     28     SkAutoSMalloc<256> storage(len);
     29     void* tmp = storage.get();
     30 
     31     for (int i = 0; i < repeat; ++i) {
     32         size_t bytes = stream->read(tmp, len);
     33         REPORTER_ASSERT(reporter, bytes == len);
     34         REPORTER_ASSERT(reporter, !memcmp(tmp, src, len));
     35     }
     36 
     37     // expect EOF
     38     size_t bytes = stream->read(tmp, 1);
     39     REPORTER_ASSERT(reporter, 0 == bytes);
     40     // isAtEnd might not return true until after the first failing read.
     41     REPORTER_ASSERT(reporter, stream->isAtEnd());
     42 }
     43 
     44 static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
     45     SkString path = SkOSPath::Join(tmpDir, "wstream_test");
     46 
     47     const char s[] = "abcdefghijklmnopqrstuvwxyz";
     48 
     49     {
     50         SkFILEWStream writer(path.c_str());
     51         if (!writer.isValid()) {
     52             ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
     53             return;
     54         }
     55 
     56         for (int i = 0; i < 100; ++i) {
     57             writer.write(s, 26);
     58         }
     59     }
     60 
     61     {
     62         SkFILEStream stream(path.c_str());
     63         REPORTER_ASSERT(reporter, stream.isValid());
     64         test_loop_stream(reporter, &stream, s, 26, 100);
     65 
     66         std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
     67         test_loop_stream(reporter, stream2.get(), s, 26, 100);
     68     }
     69 
     70     {
     71         FILE* file = ::fopen(path.c_str(), "rb");
     72         SkFILEStream stream(file);
     73         REPORTER_ASSERT(reporter, stream.isValid());
     74         test_loop_stream(reporter, &stream, s, 26, 100);
     75 
     76         std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
     77         test_loop_stream(reporter, stream2.get(), s, 26, 100);
     78     }
     79 }
     80 
     81 static void TestWStream(skiatest::Reporter* reporter) {
     82     SkDynamicMemoryWStream  ds;
     83     const char s[] = "abcdefghijklmnopqrstuvwxyz";
     84     int i;
     85     for (i = 0; i < 100; i++) {
     86         REPORTER_ASSERT(reporter, ds.write(s, 26));
     87     }
     88     REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
     89 
     90     char* dst = new char[100 * 26 + 1];
     91     dst[100*26] = '*';
     92     ds.copyTo(dst);
     93     REPORTER_ASSERT(reporter, dst[100*26] == '*');
     94     for (i = 0; i < 100; i++) {
     95         REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
     96     }
     97 
     98     {
     99         std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
    100         REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
    101         REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
    102         test_loop_stream(reporter, stream.get(), s, 26, 100);
    103 
    104         std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
    105         test_loop_stream(reporter, stream2.get(), s, 26, 100);
    106 
    107         std::unique_ptr<SkStreamAsset> stream3(stream->fork());
    108         REPORTER_ASSERT(reporter, stream3->isAtEnd());
    109         char tmp;
    110         size_t bytes = stream->read(&tmp, 1);
    111         REPORTER_ASSERT(reporter, 0 == bytes);
    112         stream3->rewind();
    113         test_loop_stream(reporter, stream3.get(), s, 26, 100);
    114     }
    115 
    116     for (i = 0; i < 100; i++) {
    117         REPORTER_ASSERT(reporter, ds.write(s, 26));
    118     }
    119     REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
    120 
    121     {
    122         // Test that this works after a snapshot.
    123         std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
    124         REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
    125         test_loop_stream(reporter, stream.get(), s, 26, 100);
    126 
    127         std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
    128         test_loop_stream(reporter, stream2.get(), s, 26, 100);
    129     }
    130     delete[] dst;
    131 
    132     SkString tmpDir = skiatest::GetTmpDir();
    133     if (!tmpDir.isEmpty()) {
    134         test_filestreams(reporter, tmpDir.c_str());
    135     }
    136 }
    137 
    138 static void TestPackedUInt(skiatest::Reporter* reporter) {
    139     // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
    140     // so we test values around each of those transitions (and a few others)
    141     const size_t sizes[] = {
    142         0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
    143         0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
    144         0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
    145         0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
    146     };
    147 
    148 
    149     size_t i;
    150     SkDynamicMemoryWStream wstream;
    151 
    152     for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
    153         bool success = wstream.writePackedUInt(sizes[i]);
    154         REPORTER_ASSERT(reporter, success);
    155     }
    156 
    157     std::unique_ptr<SkStreamAsset> rstream(wstream.detachAsStream());
    158     for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
    159         size_t n = rstream->readPackedUInt();
    160         if (sizes[i] != n) {
    161             ERRORF(reporter, "sizes:%x != n:%x\n", i, sizes[i], n);
    162         }
    163     }
    164 }
    165 
    166 // Test that setting an SkMemoryStream to a nullptr data does not result in a crash when calling
    167 // methods that access fData.
    168 static void TestDereferencingData(SkMemoryStream* memStream) {
    169     memStream->read(nullptr, 0);
    170     memStream->getMemoryBase();
    171     (void)memStream->asData();
    172 }
    173 
    174 static void TestNullData() {
    175     SkMemoryStream memStream(nullptr);
    176     TestDereferencingData(&memStream);
    177 
    178     memStream.setData(nullptr);
    179     TestDereferencingData(&memStream);
    180 
    181 }
    182 
    183 DEF_TEST(Stream, reporter) {
    184     TestWStream(reporter);
    185     TestPackedUInt(reporter);
    186     TestNullData();
    187 }
    188 
    189 #ifndef SK_BUILD_FOR_IOS
    190 /**
    191  *  Tests peeking and then reading the same amount. The two should provide the
    192  *  same results.
    193  *  Returns the amount successfully read minus the amount successfully peeked.
    194  */
    195 static size_t compare_peek_to_read(skiatest::Reporter* reporter,
    196                                    SkStream* stream, size_t bytesToPeek) {
    197     // The rest of our tests won't be very interesting if bytesToPeek is zero.
    198     REPORTER_ASSERT(reporter, bytesToPeek > 0);
    199     SkAutoMalloc peekStorage(bytesToPeek);
    200     SkAutoMalloc readStorage(bytesToPeek);
    201     void* peekPtr = peekStorage.get();
    202     void* readPtr = peekStorage.get();
    203 
    204     const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek);
    205     const size_t bytesRead = stream->read(readPtr, bytesToPeek);
    206 
    207     // bytesRead should only be less than attempted if the stream is at the
    208     // end.
    209     REPORTER_ASSERT(reporter, bytesRead == bytesToPeek || stream->isAtEnd());
    210 
    211     // peek and read should behave the same, except peek returned to the
    212     // original position, so they read the same data.
    213     REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked));
    214 
    215     // A stream should never be able to peek more than it can read.
    216     REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked);
    217 
    218     return bytesRead - bytesPeeked;
    219 }
    220 
    221 static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
    222     for (size_t i = 1; !stream->isAtEnd(); i++) {
    223         REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
    224     }
    225 }
    226 
    227 static void test_peeking_front_buffered_stream(skiatest::Reporter* r,
    228                                                const SkStream& original,
    229                                                size_t bufferSize) {
    230     SkStream* dupe = original.duplicate();
    231     REPORTER_ASSERT(r, dupe != nullptr);
    232     std::unique_ptr<SkStream> bufferedStream(SkFrontBufferedStream::Create(dupe, bufferSize));
    233     REPORTER_ASSERT(r, bufferedStream != nullptr);
    234 
    235     size_t peeked = 0;
    236     for (size_t i = 1; !bufferedStream->isAtEnd(); i++) {
    237         const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i);
    238         if (unpeekableBytes > 0) {
    239             // This could not have returned a number greater than i.
    240             REPORTER_ASSERT(r, unpeekableBytes <= i);
    241 
    242             // We have reached the end of the buffer. Verify that it was at least
    243             // bufferSize.
    244             REPORTER_ASSERT(r, peeked + i - unpeekableBytes >= bufferSize);
    245             // No more peeking is supported.
    246             break;
    247         }
    248         peeked += i;
    249     }
    250 
    251     // Test that attempting to peek beyond the length of the buffer does not prevent rewinding.
    252     bufferedStream.reset(SkFrontBufferedStream::Create(original.duplicate(), bufferSize));
    253     REPORTER_ASSERT(r, bufferedStream != nullptr);
    254 
    255     const size_t bytesToPeek = bufferSize + 1;
    256     SkAutoMalloc peekStorage(bytesToPeek);
    257     SkAutoMalloc readStorage(bytesToPeek);
    258 
    259     for (size_t start = 0; start <= bufferSize; start++) {
    260         // Skip to the starting point
    261         REPORTER_ASSERT(r, bufferedStream->skip(start) == start);
    262 
    263         const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek);
    264         if (0 == bytesPeeked) {
    265             // Peeking should only fail completely if we have read/skipped beyond the buffer.
    266             REPORTER_ASSERT(r, start >= bufferSize);
    267             break;
    268         }
    269 
    270         // Only read the amount that was successfully peeked.
    271         const size_t bytesRead = bufferedStream->read(readStorage.get(), bytesPeeked);
    272         REPORTER_ASSERT(r, bytesRead == bytesPeeked);
    273         REPORTER_ASSERT(r, !memcmp(peekStorage.get(), readStorage.get(), bytesPeeked));
    274 
    275         // This should be safe to rewind.
    276         REPORTER_ASSERT(r, bufferedStream->rewind());
    277     }
    278 }
    279 
    280 // This test uses file system operations that don't work out of the
    281 // box on iOS. It's likely that we don't need them on iOS. Ignoring for now.
    282 // TODO(stephana): Re-evaluate if we need this in the future.
    283 DEF_TEST(StreamPeek, reporter) {
    284     // Test a memory stream.
    285     const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz";
    286     SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
    287     test_fully_peekable_stream(reporter, &memStream, memStream.getLength());
    288 
    289     // Test an arbitrary file stream. file streams do not support peeking.
    290     SkFILEStream fileStream(GetResourcePath("baby_tux.webp").c_str());
    291     REPORTER_ASSERT(reporter, fileStream.isValid());
    292     if (!fileStream.isValid()) {
    293         return;
    294     }
    295     SkAutoMalloc storage(fileStream.getLength());
    296     for (size_t i = 1; i < fileStream.getLength(); i++) {
    297         REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0);
    298     }
    299 
    300     // Now test some FrontBufferedStreams
    301     for (size_t i = 1; i < memStream.getLength(); i++) {
    302         test_peeking_front_buffered_stream(reporter, memStream, i);
    303     }
    304 }
    305 #endif
    306 
    307 // Asserts that asset == expected and is peekable.
    308 static void stream_peek_test(skiatest::Reporter* rep,
    309                              SkStreamAsset* asset,
    310                              const SkData* expected) {
    311     if (asset->getLength() != expected->size()) {
    312         ERRORF(rep, "Unexpected length.");
    313         return;
    314     }
    315     SkRandom rand;
    316     uint8_t buffer[4096];
    317     const uint8_t* expect = expected->bytes();
    318     for (size_t i = 0; i < asset->getLength(); ++i) {
    319         uint32_t maxSize =
    320                 SkToU32(SkTMin(sizeof(buffer), asset->getLength() - i));
    321         size_t size = rand.nextRangeU(1, maxSize);
    322         SkASSERT(size >= 1);
    323         SkASSERT(size <= sizeof(buffer));
    324         SkASSERT(size + i <= asset->getLength());
    325         if (asset->peek(buffer, size) < size) {
    326             ERRORF(rep, "Peek Failed!");
    327             return;
    328         }
    329         if (0 != memcmp(buffer, &expect[i], size)) {
    330             ERRORF(rep, "Peek returned wrong bytes!");
    331             return;
    332         }
    333         uint8_t value;
    334         REPORTER_ASSERT(rep, 1 == asset->read(&value, 1));
    335         if (value != expect[i]) {
    336             ERRORF(rep, "Read Failed!");
    337             return;
    338         }
    339     }
    340 }
    341 
    342 DEF_TEST(StreamPeek_BlockMemoryStream, rep) {
    343     const static int kSeed = 1234;
    344     SkRandom valueSource(kSeed);
    345     SkRandom rand(kSeed << 1);
    346     uint8_t buffer[4096];
    347     SkDynamicMemoryWStream dynamicMemoryWStream;
    348     size_t totalWritten = 0;
    349     for (int i = 0; i < 32; ++i) {
    350         // Randomize the length of the blocks.
    351         size_t size = rand.nextRangeU(1, sizeof(buffer));
    352         for (size_t j = 0; j < size; ++j) {
    353             buffer[j] = valueSource.nextU() & 0xFF;
    354         }
    355         dynamicMemoryWStream.write(buffer, size);
    356         totalWritten += size;
    357         REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten());
    358     }
    359     std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream());
    360     sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength()));
    361     uint8_t* expectedPtr = static_cast<uint8_t*>(expected->writable_data());
    362     valueSource.setSeed(kSeed);  // reseed.
    363     // We want the exact same same "random" string of numbers to put
    364     // in expected. i.e.: don't rely on SkDynamicMemoryStream to work
    365     // correctly while we are testing SkDynamicMemoryStream.
    366     for (size_t i = 0; i < asset->getLength(); ++i) {
    367         expectedPtr[i] = valueSource.nextU() & 0xFF;
    368     }
    369     stream_peek_test(rep, asset.get(), expected.get());
    370 }
    371 
    372 namespace {
    373 class DumbStream : public SkStream {
    374 public:
    375     DumbStream(const uint8_t* data, size_t n)
    376         : fData(data), fCount(n), fIdx(0) {}
    377     size_t read(void* buffer, size_t size) override {
    378         size_t copyCount = SkTMin(fCount - fIdx, size);
    379         if (copyCount) {
    380             memcpy(buffer, &fData[fIdx], copyCount);
    381             fIdx += copyCount;
    382         }
    383         return copyCount;
    384     }
    385     bool isAtEnd() const override {
    386         return fCount == fIdx;
    387     }
    388  private:
    389     const uint8_t* fData;
    390     size_t fCount, fIdx;
    391 };
    392 }  // namespace
    393 
    394 static void stream_copy_test(skiatest::Reporter* reporter,
    395                              const void* srcData,
    396                              size_t N,
    397                              SkStream* stream) {
    398     SkDynamicMemoryWStream tgt;
    399     if (!SkStreamCopy(&tgt, stream)) {
    400         ERRORF(reporter, "SkStreamCopy failed");
    401         return;
    402     }
    403     sk_sp<SkData> data(tgt.detachAsData());
    404     if (data->size() != N) {
    405         ERRORF(reporter, "SkStreamCopy incorrect size");
    406         return;
    407     }
    408     if (0 != memcmp(data->data(), srcData, N)) {
    409         ERRORF(reporter, "SkStreamCopy bad copy");
    410     }
    411 }
    412 
    413 DEF_TEST(DynamicMemoryWStream_detachAsData, r) {
    414     const char az[] = "abcdefghijklmnopqrstuvwxyz";
    415     const unsigned N = 40000;
    416     SkDynamicMemoryWStream dmws;
    417     for (unsigned i = 0; i < N; ++i) {
    418         dmws.writeText(az);
    419     }
    420     REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az));
    421     auto data = dmws.detachAsData();
    422     REPORTER_ASSERT(r, data->size() == N * strlen(az));
    423     const uint8_t* ptr = data->bytes();
    424     for (unsigned i = 0; i < N; ++i) {
    425         if (0 != memcmp(ptr, az, strlen(az))) {
    426             ERRORF(r, "detachAsData() memcmp failed");
    427             return;
    428         }
    429         ptr += strlen(az);
    430     }
    431 }
    432 
    433 DEF_TEST(StreamCopy, reporter) {
    434     SkRandom random(123456);
    435     static const int N = 10000;
    436     SkAutoTMalloc<uint8_t> src((size_t)N);
    437     for (int j = 0; j < N; ++j) {
    438         src[j] = random.nextU() & 0xff;
    439     }
    440     // SkStreamCopy had two code paths; this test both.
    441     DumbStream dumbStream(src.get(), (size_t)N);
    442     stream_copy_test(reporter, src, N, &dumbStream);
    443     SkMemoryStream smartStream(src.get(), (size_t)N);
    444     stream_copy_test(reporter, src, N, &smartStream);
    445 }
    446 
    447 DEF_TEST(StreamEmptyStreamMemoryBase, r) {
    448     SkDynamicMemoryWStream tmp;
    449     std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream());
    450     REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
    451 }
    452 
    453 #include "SkBuffer.h"
    454 
    455 DEF_TEST(RBuffer, reporter) {
    456     int32_t value = 0;
    457     SkRBuffer buffer(&value, 4);
    458     REPORTER_ASSERT(reporter, buffer.isValid());
    459 
    460     int32_t tmp;
    461     REPORTER_ASSERT(reporter, buffer.read(&tmp, 4));
    462     REPORTER_ASSERT(reporter, buffer.isValid());
    463 
    464     REPORTER_ASSERT(reporter, !buffer.read(&tmp, 4));
    465     REPORTER_ASSERT(reporter, !buffer.isValid());
    466 }
    467