Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2016 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 "SkData.h"
      9 #include "SkOSPath.h"
     10 #include "SkStream.h"
     11 #include "SkStreamBuffer.h"
     12 
     13 #include "FakeStreams.h"
     14 #include "Test.h"
     15 
     16 static const char* gText = "Four score and seven years ago";
     17 
     18 static void test_get_data_at_position(skiatest::Reporter* r, SkStreamBuffer* buffer, size_t position,
     19                                     size_t length) {
     20     sk_sp<SkData> data = buffer->getDataAtPosition(position, length);
     21     REPORTER_ASSERT(r, data);
     22     if (data) {
     23         REPORTER_ASSERT(r, !memcmp(data->data(), gText + position, length));
     24     }
     25 }
     26 
     27 // Test buffering from the beginning, by different amounts.
     28 static void test_buffer_from_beginning(skiatest::Reporter* r, SkStream* stream, size_t length) {
     29     SkStreamBuffer buffer(stream);
     30 
     31     // Buffer an arbitrary amount:
     32     size_t buffered = length / 2;
     33     REPORTER_ASSERT(r, buffer.buffer(buffered));
     34     REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, buffered));
     35 
     36     // Buffering less is free:
     37     REPORTER_ASSERT(r, buffer.buffer(buffered / 2));
     38 
     39     // Buffer more should succeed:
     40     REPORTER_ASSERT(r, buffer.buffer(length));
     41     REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, length));
     42 }
     43 
     44 // Test flushing the stream as we read.
     45 static void test_flushing(skiatest::Reporter* r, SkStream* stream, size_t length,
     46                           bool getDataAtPosition) {
     47     SkStreamBuffer buffer(stream);
     48     const size_t step = 5;
     49     for (size_t position = 0; position + step <= length; position += step) {
     50         REPORTER_ASSERT(r, buffer.buffer(step));
     51         REPORTER_ASSERT(r, buffer.markPosition() == position);
     52 
     53         if (!getDataAtPosition) {
     54             REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + position, step));
     55         }
     56         buffer.flush();
     57     }
     58 
     59     REPORTER_ASSERT(r, !buffer.buffer(step));
     60 
     61     if (getDataAtPosition) {
     62         for (size_t position = 0; position + step <= length; position += step) {
     63             test_get_data_at_position(r, &buffer, position, step);
     64         }
     65     }
     66 }
     67 
     68 DEF_TEST(StreamBuffer, r) {
     69     const size_t size = strlen(gText);
     70     sk_sp<SkData> data(SkData::MakeWithoutCopy(gText, size));
     71 
     72     SkString tmpDir = skiatest::GetTmpDir();
     73     const char* subdir = "streamBuffer.txt";
     74     SkString path;
     75 
     76     if (!tmpDir.isEmpty()) {
     77         path = SkOSPath::Join(tmpDir.c_str(), subdir);
     78         SkFILEWStream writer(path.c_str());
     79         writer.write(gText, size);
     80     }
     81 
     82     struct {
     83         std::function<SkStream*()> createStream;
     84         bool                       skipIfNoTmpDir;
     85     } factories[] = {
     86         { [&data]() { return new SkMemoryStream(data); },       false },
     87         { [&data]() { return new NotAssetMemStream(data); },    false },
     88         { [&path]() { return new SkFILEStream(path.c_str()); }, true  },
     89     };
     90 
     91     for (auto f : factories) {
     92         if (tmpDir.isEmpty() && f.skipIfNoTmpDir) {
     93             continue;
     94         }
     95         test_buffer_from_beginning(r, f.createStream(), size);
     96         test_flushing(r, f.createStream(), size, false);
     97         test_flushing(r, f.createStream(), size, true);
     98     }
     99 
    100     // Stream that will receive more data. Will be owned by the SkStreamBuffer.
    101     HaltingStream* stream = new HaltingStream(data, 6);
    102     SkStreamBuffer buffer(stream);
    103 
    104     // Can only buffer less than what's available (6).
    105     REPORTER_ASSERT(r, !buffer.buffer(7));
    106     REPORTER_ASSERT(r, buffer.buffer(5));
    107     REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 5));
    108 
    109     // Add some more data. We can buffer and read all of it.
    110     stream->addNewData(8);
    111     REPORTER_ASSERT(r, buffer.buffer(14));
    112     REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 14));
    113 
    114     // Flush the buffer, which moves the position.
    115     buffer.flush();
    116 
    117     // Add some data, and try to read more. Can only read what is
    118     // available.
    119     stream->addNewData(9);
    120     REPORTER_ASSERT(r, !buffer.buffer(13));
    121     stream->addNewData(4);
    122     REPORTER_ASSERT(r, buffer.buffer(13));
    123 
    124     // Do not call get on this data. We'll come back to this data after adding
    125     // more.
    126     buffer.flush();
    127     const size_t remaining = size - 27;
    128     REPORTER_ASSERT(r, remaining > 0);
    129     stream->addNewData(remaining);
    130     REPORTER_ASSERT(r, buffer.buffer(remaining));
    131     REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + 27, remaining));
    132 
    133     // Now go back to the data we skipped.
    134     test_get_data_at_position(r, &buffer, 14, 13);
    135 }
    136