blob: a6b71f6621a5bba8e266b7ee4af5b1cfaf2572cb [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkData.h"
9#include "include/core/SkStream.h"
10#include "src/codec/SkStreamBuffer.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/utils/SkOSPath.h"
Leon Scroggins III932efed2016-12-16 11:39:51 -050012
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "tests/FakeStreams.h"
14#include "tests/Test.h"
Leon Scroggins III932efed2016-12-16 11:39:51 -050015
16static const char* gText = "Four score and seven years ago";
17
18static 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.
Mike Reedede7bac2017-07-23 15:30:02 -040028static void test_buffer_from_beginning(skiatest::Reporter* r, std::unique_ptr<SkStream> stream,
29 size_t length) {
Hal Canary925e31e2017-12-11 14:42:58 -050030 if (!stream) {
31 return;
32 }
Mike Reedede7bac2017-07-23 15:30:02 -040033 SkStreamBuffer buffer(std::move(stream));
Leon Scroggins III932efed2016-12-16 11:39:51 -050034
35 // Buffer an arbitrary amount:
36 size_t buffered = length / 2;
37 REPORTER_ASSERT(r, buffer.buffer(buffered));
38 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, buffered));
39
40 // Buffering less is free:
41 REPORTER_ASSERT(r, buffer.buffer(buffered / 2));
42
43 // Buffer more should succeed:
44 REPORTER_ASSERT(r, buffer.buffer(length));
45 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, length));
46}
47
48// Test flushing the stream as we read.
Mike Reedede7bac2017-07-23 15:30:02 -040049static void test_flushing(skiatest::Reporter* r, std::unique_ptr<SkStream> stream, size_t length,
Leon Scroggins III932efed2016-12-16 11:39:51 -050050 bool getDataAtPosition) {
Hal Canary925e31e2017-12-11 14:42:58 -050051 if (!stream) {
52 return;
53 }
Mike Reedede7bac2017-07-23 15:30:02 -040054 SkStreamBuffer buffer(std::move(stream));
Leon Scroggins III932efed2016-12-16 11:39:51 -050055 const size_t step = 5;
56 for (size_t position = 0; position + step <= length; position += step) {
57 REPORTER_ASSERT(r, buffer.buffer(step));
58 REPORTER_ASSERT(r, buffer.markPosition() == position);
59
60 if (!getDataAtPosition) {
61 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + position, step));
62 }
63 buffer.flush();
64 }
65
66 REPORTER_ASSERT(r, !buffer.buffer(step));
67
68 if (getDataAtPosition) {
69 for (size_t position = 0; position + step <= length; position += step) {
70 test_get_data_at_position(r, &buffer, position, step);
71 }
72 }
73}
74
75DEF_TEST(StreamBuffer, r) {
76 const size_t size = strlen(gText);
77 sk_sp<SkData> data(SkData::MakeWithoutCopy(gText, size));
78
79 SkString tmpDir = skiatest::GetTmpDir();
80 const char* subdir = "streamBuffer.txt";
81 SkString path;
82
83 if (!tmpDir.isEmpty()) {
84 path = SkOSPath::Join(tmpDir.c_str(), subdir);
85 SkFILEWStream writer(path.c_str());
Hal Canary925e31e2017-12-11 14:42:58 -050086 if (!writer.isValid()) {
87 ERRORF(r, "unable to write to '%s'\n", path.c_str());
88 return;
89 }
Leon Scroggins III932efed2016-12-16 11:39:51 -050090 writer.write(gText, size);
91 }
92
John Stilesbd3ffa42020-07-30 20:24:57 -040093 struct Factory {
Mike Reedede7bac2017-07-23 15:30:02 -040094 std::function<std::unique_ptr<SkStream>()> createStream;
95 bool skipIfNoTmpDir;
John Stilesbd3ffa42020-07-30 20:24:57 -040096 };
97
98 Factory factories[] = {
Mike Kleinf46d5ca2019-12-11 10:45:01 -050099 { [&data]() { return std::make_unique<SkMemoryStream>(data); }, false },
100 { [&data]() { return std::make_unique<NotAssetMemStream>(data); }, false },
Hal Canary925e31e2017-12-11 14:42:58 -0500101 { [&path]() { return path.isEmpty()
102 ? nullptr
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500103 : std::make_unique<SkFILEStream>(path.c_str()); }, true },
Leon Scroggins III932efed2016-12-16 11:39:51 -0500104 };
105
John Stilesbd3ffa42020-07-30 20:24:57 -0400106 for (const Factory& f : factories) {
Leon Scroggins III932efed2016-12-16 11:39:51 -0500107 if (tmpDir.isEmpty() && f.skipIfNoTmpDir) {
108 continue;
109 }
110 test_buffer_from_beginning(r, f.createStream(), size);
111 test_flushing(r, f.createStream(), size, false);
112 test_flushing(r, f.createStream(), size, true);
113 }
114
115 // Stream that will receive more data. Will be owned by the SkStreamBuffer.
Mike Kleinf46d5ca2019-12-11 10:45:01 -0500116 auto halting = std::make_unique<HaltingStream>(data, 6);
Mike Reedede7bac2017-07-23 15:30:02 -0400117 HaltingStream* peekHalting = halting.get();
118 SkStreamBuffer buffer(std::move(halting));
Leon Scroggins III932efed2016-12-16 11:39:51 -0500119
120 // Can only buffer less than what's available (6).
121 REPORTER_ASSERT(r, !buffer.buffer(7));
122 REPORTER_ASSERT(r, buffer.buffer(5));
123 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 5));
124
125 // Add some more data. We can buffer and read all of it.
Mike Reedede7bac2017-07-23 15:30:02 -0400126 peekHalting->addNewData(8);
Leon Scroggins III932efed2016-12-16 11:39:51 -0500127 REPORTER_ASSERT(r, buffer.buffer(14));
128 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 14));
129
130 // Flush the buffer, which moves the position.
131 buffer.flush();
132
133 // Add some data, and try to read more. Can only read what is
134 // available.
Mike Reedede7bac2017-07-23 15:30:02 -0400135 peekHalting->addNewData(9);
Leon Scroggins III932efed2016-12-16 11:39:51 -0500136 REPORTER_ASSERT(r, !buffer.buffer(13));
Mike Reedede7bac2017-07-23 15:30:02 -0400137 peekHalting->addNewData(4);
Leon Scroggins III932efed2016-12-16 11:39:51 -0500138 REPORTER_ASSERT(r, buffer.buffer(13));
139
140 // Do not call get on this data. We'll come back to this data after adding
141 // more.
142 buffer.flush();
143 const size_t remaining = size - 27;
144 REPORTER_ASSERT(r, remaining > 0);
Mike Reedede7bac2017-07-23 15:30:02 -0400145 peekHalting->addNewData(remaining);
Leon Scroggins III932efed2016-12-16 11:39:51 -0500146 REPORTER_ASSERT(r, buffer.buffer(remaining));
147 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + 27, remaining));
148
149 // Now go back to the data we skipped.
150 test_get_data_at_position(r, &buffer, 14, 13);
151}