2016-12-16 16:39:51 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2016 Google Inc.
|
|
|
|
*
|
|
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
|
|
* found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "SkData.h"
|
2017-07-23 19:30:02 +00:00
|
|
|
#include "SkMakeUnique.h"
|
2016-12-16 16:39:51 +00:00
|
|
|
#include "SkOSPath.h"
|
|
|
|
#include "SkStream.h"
|
|
|
|
#include "SkStreamBuffer.h"
|
|
|
|
|
|
|
|
#include "FakeStreams.h"
|
|
|
|
#include "Test.h"
|
|
|
|
|
|
|
|
static const char* gText = "Four score and seven years ago";
|
|
|
|
|
|
|
|
static void test_get_data_at_position(skiatest::Reporter* r, SkStreamBuffer* buffer, size_t position,
|
|
|
|
size_t length) {
|
|
|
|
sk_sp<SkData> data = buffer->getDataAtPosition(position, length);
|
|
|
|
REPORTER_ASSERT(r, data);
|
|
|
|
if (data) {
|
|
|
|
REPORTER_ASSERT(r, !memcmp(data->data(), gText + position, length));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test buffering from the beginning, by different amounts.
|
2017-07-23 19:30:02 +00:00
|
|
|
static void test_buffer_from_beginning(skiatest::Reporter* r, std::unique_ptr<SkStream> stream,
|
|
|
|
size_t length) {
|
|
|
|
SkStreamBuffer buffer(std::move(stream));
|
2016-12-16 16:39:51 +00:00
|
|
|
|
|
|
|
// Buffer an arbitrary amount:
|
|
|
|
size_t buffered = length / 2;
|
|
|
|
REPORTER_ASSERT(r, buffer.buffer(buffered));
|
|
|
|
REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, buffered));
|
|
|
|
|
|
|
|
// Buffering less is free:
|
|
|
|
REPORTER_ASSERT(r, buffer.buffer(buffered / 2));
|
|
|
|
|
|
|
|
// Buffer more should succeed:
|
|
|
|
REPORTER_ASSERT(r, buffer.buffer(length));
|
|
|
|
REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, length));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test flushing the stream as we read.
|
2017-07-23 19:30:02 +00:00
|
|
|
static void test_flushing(skiatest::Reporter* r, std::unique_ptr<SkStream> stream, size_t length,
|
2016-12-16 16:39:51 +00:00
|
|
|
bool getDataAtPosition) {
|
2017-07-23 19:30:02 +00:00
|
|
|
SkStreamBuffer buffer(std::move(stream));
|
2016-12-16 16:39:51 +00:00
|
|
|
const size_t step = 5;
|
|
|
|
for (size_t position = 0; position + step <= length; position += step) {
|
|
|
|
REPORTER_ASSERT(r, buffer.buffer(step));
|
|
|
|
REPORTER_ASSERT(r, buffer.markPosition() == position);
|
|
|
|
|
|
|
|
if (!getDataAtPosition) {
|
|
|
|
REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + position, step));
|
|
|
|
}
|
|
|
|
buffer.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
REPORTER_ASSERT(r, !buffer.buffer(step));
|
|
|
|
|
|
|
|
if (getDataAtPosition) {
|
|
|
|
for (size_t position = 0; position + step <= length; position += step) {
|
|
|
|
test_get_data_at_position(r, &buffer, position, step);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DEF_TEST(StreamBuffer, r) {
|
|
|
|
const size_t size = strlen(gText);
|
|
|
|
sk_sp<SkData> data(SkData::MakeWithoutCopy(gText, size));
|
|
|
|
|
|
|
|
SkString tmpDir = skiatest::GetTmpDir();
|
|
|
|
const char* subdir = "streamBuffer.txt";
|
|
|
|
SkString path;
|
|
|
|
|
|
|
|
if (!tmpDir.isEmpty()) {
|
|
|
|
path = SkOSPath::Join(tmpDir.c_str(), subdir);
|
|
|
|
SkFILEWStream writer(path.c_str());
|
|
|
|
writer.write(gText, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct {
|
2017-07-23 19:30:02 +00:00
|
|
|
std::function<std::unique_ptr<SkStream>()> createStream;
|
|
|
|
bool skipIfNoTmpDir;
|
2016-12-16 16:39:51 +00:00
|
|
|
} factories[] = {
|
2017-07-23 19:30:02 +00:00
|
|
|
{ [&data]() { return skstd::make_unique<SkMemoryStream>(data); }, false },
|
|
|
|
{ [&data]() { return skstd::make_unique<NotAssetMemStream>(data); }, false },
|
|
|
|
{ [&path]() { return skstd::make_unique<SkFILEStream>(path.c_str()); }, true },
|
2016-12-16 16:39:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
for (auto f : factories) {
|
|
|
|
if (tmpDir.isEmpty() && f.skipIfNoTmpDir) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
test_buffer_from_beginning(r, f.createStream(), size);
|
|
|
|
test_flushing(r, f.createStream(), size, false);
|
|
|
|
test_flushing(r, f.createStream(), size, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stream that will receive more data. Will be owned by the SkStreamBuffer.
|
2017-07-23 19:30:02 +00:00
|
|
|
auto halting = skstd::make_unique<HaltingStream>(data, 6);
|
|
|
|
HaltingStream* peekHalting = halting.get();
|
|
|
|
SkStreamBuffer buffer(std::move(halting));
|
2016-12-16 16:39:51 +00:00
|
|
|
|
|
|
|
// Can only buffer less than what's available (6).
|
|
|
|
REPORTER_ASSERT(r, !buffer.buffer(7));
|
|
|
|
REPORTER_ASSERT(r, buffer.buffer(5));
|
|
|
|
REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 5));
|
|
|
|
|
|
|
|
// Add some more data. We can buffer and read all of it.
|
2017-07-23 19:30:02 +00:00
|
|
|
peekHalting->addNewData(8);
|
2016-12-16 16:39:51 +00:00
|
|
|
REPORTER_ASSERT(r, buffer.buffer(14));
|
|
|
|
REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 14));
|
|
|
|
|
|
|
|
// Flush the buffer, which moves the position.
|
|
|
|
buffer.flush();
|
|
|
|
|
|
|
|
// Add some data, and try to read more. Can only read what is
|
|
|
|
// available.
|
2017-07-23 19:30:02 +00:00
|
|
|
peekHalting->addNewData(9);
|
2016-12-16 16:39:51 +00:00
|
|
|
REPORTER_ASSERT(r, !buffer.buffer(13));
|
2017-07-23 19:30:02 +00:00
|
|
|
peekHalting->addNewData(4);
|
2016-12-16 16:39:51 +00:00
|
|
|
REPORTER_ASSERT(r, buffer.buffer(13));
|
|
|
|
|
|
|
|
// Do not call get on this data. We'll come back to this data after adding
|
|
|
|
// more.
|
|
|
|
buffer.flush();
|
|
|
|
const size_t remaining = size - 27;
|
|
|
|
REPORTER_ASSERT(r, remaining > 0);
|
2017-07-23 19:30:02 +00:00
|
|
|
peekHalting->addNewData(remaining);
|
2016-12-16 16:39:51 +00:00
|
|
|
REPORTER_ASSERT(r, buffer.buffer(remaining));
|
|
|
|
REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + 27, remaining));
|
|
|
|
|
|
|
|
// Now go back to the data we skipped.
|
|
|
|
test_get_data_at_position(r, &buffer, 14, 13);
|
|
|
|
}
|