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