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