blob: 35bebad27485fd6a63386e0eff5756a493600cb4 [file] [log] [blame]
Leon Scroggins III932efed2016-12-16 11:39:51 -05001/*
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"
Mike Reedede7bac2017-07-23 15:30:02 -04009#include "SkMakeUnique.h"
Leon Scroggins III932efed2016-12-16 11:39:51 -050010#include "SkOSPath.h"
11#include "SkStream.h"
12#include "SkStreamBuffer.h"
13
14#include "FakeStreams.h"
15#include "Test.h"
16
17static const char* gText = "Four score and seven years ago";
18
19static void test_get_data_at_position(skiatest::Reporter* r, SkStreamBuffer* buffer, size_t position,
20 size_t length) {
21 sk_sp<SkData> data = buffer->getDataAtPosition(position, length);
22 REPORTER_ASSERT(r, data);
23 if (data) {
24 REPORTER_ASSERT(r, !memcmp(data->data(), gText + position, length));
25 }
26}
27
28// Test buffering from the beginning, by different amounts.
Mike Reedede7bac2017-07-23 15:30:02 -040029static void test_buffer_from_beginning(skiatest::Reporter* r, std::unique_ptr<SkStream> stream,
30 size_t length) {
31 SkStreamBuffer buffer(std::move(stream));
Leon Scroggins III932efed2016-12-16 11:39:51 -050032
33 // Buffer an arbitrary amount:
34 size_t buffered = length / 2;
35 REPORTER_ASSERT(r, buffer.buffer(buffered));
36 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, buffered));
37
38 // Buffering less is free:
39 REPORTER_ASSERT(r, buffer.buffer(buffered / 2));
40
41 // Buffer more should succeed:
42 REPORTER_ASSERT(r, buffer.buffer(length));
43 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, length));
44}
45
46// Test flushing the stream as we read.
Mike Reedede7bac2017-07-23 15:30:02 -040047static void test_flushing(skiatest::Reporter* r, std::unique_ptr<SkStream> stream, size_t length,
Leon Scroggins III932efed2016-12-16 11:39:51 -050048 bool getDataAtPosition) {
Mike Reedede7bac2017-07-23 15:30:02 -040049 SkStreamBuffer buffer(std::move(stream));
Leon Scroggins III932efed2016-12-16 11:39:51 -050050 const size_t step = 5;
51 for (size_t position = 0; position + step <= length; position += step) {
52 REPORTER_ASSERT(r, buffer.buffer(step));
53 REPORTER_ASSERT(r, buffer.markPosition() == position);
54
55 if (!getDataAtPosition) {
56 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + position, step));
57 }
58 buffer.flush();
59 }
60
61 REPORTER_ASSERT(r, !buffer.buffer(step));
62
63 if (getDataAtPosition) {
64 for (size_t position = 0; position + step <= length; position += step) {
65 test_get_data_at_position(r, &buffer, position, step);
66 }
67 }
68}
69
70DEF_TEST(StreamBuffer, r) {
71 const size_t size = strlen(gText);
72 sk_sp<SkData> data(SkData::MakeWithoutCopy(gText, size));
73
74 SkString tmpDir = skiatest::GetTmpDir();
75 const char* subdir = "streamBuffer.txt";
76 SkString path;
77
78 if (!tmpDir.isEmpty()) {
79 path = SkOSPath::Join(tmpDir.c_str(), subdir);
80 SkFILEWStream writer(path.c_str());
81 writer.write(gText, size);
82 }
83
84 struct {
Mike Reedede7bac2017-07-23 15:30:02 -040085 std::function<std::unique_ptr<SkStream>()> createStream;
86 bool skipIfNoTmpDir;
Leon Scroggins III932efed2016-12-16 11:39:51 -050087 } factories[] = {
Mike Reedede7bac2017-07-23 15:30:02 -040088 { [&data]() { return skstd::make_unique<SkMemoryStream>(data); }, false },
89 { [&data]() { return skstd::make_unique<NotAssetMemStream>(data); }, false },
90 { [&path]() { return skstd::make_unique<SkFILEStream>(path.c_str()); }, true },
Leon Scroggins III932efed2016-12-16 11:39:51 -050091 };
92
93 for (auto f : factories) {
94 if (tmpDir.isEmpty() && f.skipIfNoTmpDir) {
95 continue;
96 }
97 test_buffer_from_beginning(r, f.createStream(), size);
98 test_flushing(r, f.createStream(), size, false);
99 test_flushing(r, f.createStream(), size, true);
100 }
101
102 // Stream that will receive more data. Will be owned by the SkStreamBuffer.
Mike Reedede7bac2017-07-23 15:30:02 -0400103 auto halting = skstd::make_unique<HaltingStream>(data, 6);
104 HaltingStream* peekHalting = halting.get();
105 SkStreamBuffer buffer(std::move(halting));
Leon Scroggins III932efed2016-12-16 11:39:51 -0500106
107 // Can only buffer less than what's available (6).
108 REPORTER_ASSERT(r, !buffer.buffer(7));
109 REPORTER_ASSERT(r, buffer.buffer(5));
110 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 5));
111
112 // Add some more data. We can buffer and read all of it.
Mike Reedede7bac2017-07-23 15:30:02 -0400113 peekHalting->addNewData(8);
Leon Scroggins III932efed2016-12-16 11:39:51 -0500114 REPORTER_ASSERT(r, buffer.buffer(14));
115 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 14));
116
117 // Flush the buffer, which moves the position.
118 buffer.flush();
119
120 // Add some data, and try to read more. Can only read what is
121 // available.
Mike Reedede7bac2017-07-23 15:30:02 -0400122 peekHalting->addNewData(9);
Leon Scroggins III932efed2016-12-16 11:39:51 -0500123 REPORTER_ASSERT(r, !buffer.buffer(13));
Mike Reedede7bac2017-07-23 15:30:02 -0400124 peekHalting->addNewData(4);
Leon Scroggins III932efed2016-12-16 11:39:51 -0500125 REPORTER_ASSERT(r, buffer.buffer(13));
126
127 // Do not call get on this data. We'll come back to this data after adding
128 // more.
129 buffer.flush();
130 const size_t remaining = size - 27;
131 REPORTER_ASSERT(r, remaining > 0);
Mike Reedede7bac2017-07-23 15:30:02 -0400132 peekHalting->addNewData(remaining);
Leon Scroggins III932efed2016-12-16 11:39:51 -0500133 REPORTER_ASSERT(r, buffer.buffer(remaining));
134 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + 27, remaining));
135
136 // Now go back to the data we skipped.
137 test_get_data_at_position(r, &buffer, 14, 13);
138}