Flutter Engine
The Flutter Engine
FrontBufferedStreamTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 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// Make sure SkUserConfig.h is included so #defines are available on
9// Android.
11#ifdef SK_ENABLE_ANDROID_UTILS
18#include "tests/Test.h"
19
20static void test_read(skiatest::Reporter* reporter, SkStream* bufferedStream,
21 const void* expectations, size_t bytesToRead) {
22 // output for reading bufferedStream.
23 SkAutoMalloc storage(bytesToRead);
24
25 const size_t bytesRead = bufferedStream->read(storage.get(), bytesToRead);
26 REPORTER_ASSERT(reporter, bytesRead == bytesToRead || bufferedStream->isAtEnd());
27 REPORTER_ASSERT(reporter, memcmp(storage.get(), expectations, bytesRead) == 0);
28}
29
31 SkStream* bufferedStream, bool shouldSucceed) {
32 const bool success = bufferedStream->rewind();
33 REPORTER_ASSERT(reporter, success == shouldSucceed);
34}
35
36// Test that hasLength() returns the correct value, based on the stream
37// being wrapped. A length can only be known if the wrapped stream has a
38// length and it has a position (so its initial position can be taken into
39// account when computing the length).
40static void test_hasLength(skiatest::Reporter* reporter,
41 const SkStream& bufferedStream,
42 const SkStream& streamBeingBuffered) {
43 if (streamBeingBuffered.hasLength() && streamBeingBuffered.hasPosition()) {
44 REPORTER_ASSERT(reporter, bufferedStream.hasLength());
45 } else {
46 REPORTER_ASSERT(reporter, !bufferedStream.hasLength());
47 }
48}
49
50// All tests will buffer this string, and compare output to the original.
51// The string is long to ensure that all of our lengths being tested are
52// smaller than the string length.
53const char gAbcs[] = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx";
54
55// Tests reading the stream across boundaries of what has been buffered so far and what
56// the total buffer size is.
57static void test_incremental_buffering(skiatest::Reporter* reporter, size_t bufferSize) {
58 // NOTE: For this and other tests in this file, we cheat and continue to refer to the
59 // wrapped stream, but that's okay because we know the wrapping stream has not been
60 // deleted yet (and we only call const methods in it).
61 SkMemoryStream* memStream = SkMemoryStream::MakeDirect(gAbcs, strlen(gAbcs)).release();
62
63 auto bufferedStream = android::skia::FrontBufferedStream::Make(
64 std::unique_ptr<SkStream>(memStream), bufferSize);
65
66 test_hasLength(reporter, *bufferedStream, *memStream);
67
68 // First, test reading less than the max buffer size.
69 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize / 2);
70
71 // Now test rewinding back to the beginning and reading less than what was
72 // already buffered.
73 test_rewind(reporter, bufferedStream.get(), true);
74 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize / 4);
75
76 // Now test reading part of what was buffered, and buffering new data.
77 test_read(reporter, bufferedStream.get(), gAbcs + bufferSize / 4, bufferSize / 2);
78
79 // Now test reading what was buffered, buffering new data, and
80 // reading directly from the stream.
81 test_rewind(reporter, bufferedStream.get(), true);
82 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize << 1);
83
84 // We have reached the end of the buffer, so rewinding will fail.
85 // This test assumes that the stream is larger than the buffer; otherwise the
86 // result of rewind should be true.
87 test_rewind(reporter, bufferedStream.get(), false);
88}
89
90static void test_perfectly_sized_buffer(skiatest::Reporter* reporter, size_t bufferSize) {
91 SkMemoryStream* memStream = SkMemoryStream::MakeDirect(gAbcs, strlen(gAbcs)).release();
92 auto bufferedStream = android::skia::FrontBufferedStream::Make(
93 std::unique_ptr<SkStream>(memStream), bufferSize);
94 test_hasLength(reporter, *bufferedStream, *memStream);
95
96 // Read exactly the amount that fits in the buffer.
97 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize);
98
99 // Rewinding should succeed.
100 test_rewind(reporter, bufferedStream.get(), true);
101
102 // Once again reading buffered info should succeed
103 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize);
104
105 // Read past the size of the buffer. At this point, we cannot return.
106 test_read(reporter, bufferedStream.get(), gAbcs + memStream->getPosition(), 1);
107 test_rewind(reporter, bufferedStream.get(), false);
108}
109
110static void test_skipping(skiatest::Reporter* reporter, size_t bufferSize) {
111 SkMemoryStream* memStream = SkMemoryStream::MakeDirect(gAbcs, strlen(gAbcs)).release();
112 auto bufferedStream = android::skia::FrontBufferedStream::Make(
113 std::unique_ptr<SkStream>(memStream), bufferSize);
114 test_hasLength(reporter, *bufferedStream, *memStream);
115
116 // Skip half the buffer.
117 bufferedStream->skip(bufferSize / 2);
118
119 // Rewind, then read part of the buffer, which should have been read.
120 test_rewind(reporter, bufferedStream.get(), true);
121 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize / 4);
122
123 // Now skip beyond the buffered piece, but still within the total buffer.
124 bufferedStream->skip(bufferSize / 2);
125
126 // Test that reading will still work.
127 test_read(reporter, bufferedStream.get(), gAbcs + memStream->getPosition(), bufferSize / 4);
128
129 test_rewind(reporter, bufferedStream.get(), true);
130 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize);
131}
132
133// A custom class whose isAtEnd behaves the way Android's stream does - since it is an adaptor to a
134// Java InputStream, it does not know that it is at the end until it has attempted to read beyond
135// the end and failed. Used by test_read_beyond_buffer.
136class AndroidLikeMemoryStream : public SkMemoryStream {
137public:
138 AndroidLikeMemoryStream(void* data, size_t size, bool ownMemory)
139 : INHERITED(data, size, ownMemory)
140 , fIsAtEnd(false) {}
141
142 size_t read(void* dst, size_t requested) override {
143 size_t bytesRead = this->INHERITED::read(dst, requested);
144 if (bytesRead < requested) {
145 fIsAtEnd = true;
146 }
147 return bytesRead;
148 }
149
150 bool isAtEnd() const override {
151 return fIsAtEnd;
152 }
153
154private:
155 bool fIsAtEnd;
157};
158
159// This test ensures that buffering the exact length of the stream and attempting to read beyond it
160// does not invalidate the buffer.
161static void test_read_beyond_buffer(skiatest::Reporter* reporter, size_t bufferSize) {
162 // Use a stream that behaves like Android's stream.
163 AndroidLikeMemoryStream* memStream =
164 new AndroidLikeMemoryStream((void*)gAbcs, bufferSize, false);
165
166 // Create a buffer that matches the length of the stream.
167 auto bufferedStream = android::skia::FrontBufferedStream::Make(
168 std::unique_ptr<SkStream>(memStream), bufferSize);
169 test_hasLength(reporter, *bufferedStream, *memStream);
170
171 // Attempt to read one more than the bufferSize
172 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize + 1);
173 test_rewind(reporter, bufferedStream.get(), true);
174
175 // Ensure that the initial read did not invalidate the buffer.
176 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize);
177}
178
179// Mock stream that optionally has a length and/or position. Tests that FrontBufferedStream's
180// length depends on the stream it's buffering having a length and position.
181class LengthOptionalStream : public SkStream {
182public:
183 LengthOptionalStream(bool hasLength, bool hasPosition)
184 : fHasLength(hasLength)
185 , fHasPosition(hasPosition)
186 {}
187
188 bool hasLength() const override {
189 return fHasLength;
190 }
191
192 bool hasPosition() const override {
193 return fHasPosition;
194 }
195
196 size_t read(void*, size_t) override {
197 return 0;
198 }
199
200 bool isAtEnd() const override {
201 return true;
202 }
203
204private:
205 const bool fHasLength;
206 const bool fHasPosition;
207};
208
209// Test all possible combinations of the wrapped stream having a length and a position.
210static void test_length_combos(skiatest::Reporter* reporter, size_t bufferSize) {
211 for (int hasLen = 0; hasLen <= 1; hasLen++) {
212 for (int hasPos = 0; hasPos <= 1; hasPos++) {
213 LengthOptionalStream* stream =
214 new LengthOptionalStream(SkToBool(hasLen), SkToBool(hasPos));
216 std::unique_ptr<SkStream>(stream), bufferSize);
217 test_hasLength(reporter, *buffered, *stream);
218 }
219 }
220}
221
222// Test using a stream with an initial offset.
223static void test_initial_offset(skiatest::Reporter* reporter, size_t bufferSize) {
224 SkMemoryStream* memStream = new SkMemoryStream(gAbcs, strlen(gAbcs), false);
225
226 // Skip a few characters into the memStream, so that bufferedStream represents an offset into
227 // the stream it wraps.
228 const size_t arbitraryOffset = 17;
229 memStream->skip(arbitraryOffset);
230 auto bufferedStream = android::skia::FrontBufferedStream::Make(
231 std::unique_ptr<SkStream>(memStream), bufferSize);
232
233 // Since SkMemoryStream has a length, bufferedStream must also.
234 REPORTER_ASSERT(reporter, bufferedStream->hasLength());
235
236 const size_t amountToRead = 10;
237 const size_t bufferedLength = bufferedStream->getLength();
238 size_t currentPosition = 0;
239
240 // Read the stream in chunks. After each read, the position must match currentPosition,
241 // which sums the amount attempted to read, unless the end of the stream has been reached.
242 // Importantly, the end should not have been reached until currentPosition == bufferedLength.
243 while (currentPosition < bufferedLength) {
244 REPORTER_ASSERT(reporter, !bufferedStream->isAtEnd());
245 test_read(reporter, bufferedStream.get(), gAbcs + arbitraryOffset + currentPosition,
246 amountToRead);
247 currentPosition = std::min(currentPosition + amountToRead, bufferedLength);
248 REPORTER_ASSERT(reporter, memStream->getPosition() - arbitraryOffset == currentPosition);
249 }
250 REPORTER_ASSERT(reporter, bufferedStream->isAtEnd());
251 REPORTER_ASSERT(reporter, bufferedLength == currentPosition);
252}
253
254static void test_buffers(skiatest::Reporter* reporter, size_t bufferSize) {
255 test_incremental_buffering(reporter, bufferSize);
256 test_perfectly_sized_buffer(reporter, bufferSize);
257 test_skipping(reporter, bufferSize);
258 test_read_beyond_buffer(reporter, bufferSize);
259 test_length_combos(reporter, bufferSize);
260 test_initial_offset(reporter, bufferSize);
261}
262
263DEF_TEST(FrontBufferedStream, reporter) {
264 // Test 6 and 64, which are used by Android, as well as another arbitrary length.
265 test_buffers(reporter, 6);
266 test_buffers(reporter, 15);
267 test_buffers(reporter, 64);
268}
269
270// Test that a FrontBufferedStream does not allow reading after the end of a stream.
271// This class is a mock SkStream which reports that it is at the end on the first
272// read (simulating a failure). Then it tracks whether someone calls read() again.
273class FailingStream : public SkStream {
274public:
275 FailingStream()
276 : fAtEnd(false)
277 {}
278
279 size_t read(void* buffer, size_t size) override {
280 SkASSERT(!fAtEnd);
281 fAtEnd = true;
282 return 0;
283 }
284
285 bool isAtEnd() const override {
286 return fAtEnd;
287 }
288
289private:
290 bool fAtEnd;
291};
292
293DEF_TEST(ShortFrontBufferedStream, reporter) {
294 FailingStream* failingStream = new FailingStream;
296 std::unique_ptr<SkStream>(failingStream), 64);
297
298 // This will fail to create a codec. However, what we really want to test is that we
299 // won't read past the end of the stream.
300 std::unique_ptr<SkCodec> codec(SkCodec::MakeFromStream(std::move(stream)));
301}
302#endif // SK_ENABLE_ANDROID_UTILS
reporter
Definition: FontMgrTest.cpp:39
static void test_read(skiatest::Reporter *reporter)
#define SkASSERT(cond)
Definition: SkAssert.h:116
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
#define DEF_TEST(name, reporter)
Definition: Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
static void test_rewind(skiatest::Reporter *reporter)
static std::unique_ptr< SkCodec > MakeFromStream(std::unique_ptr< SkStream >, SkSpan< const SkCodecs::Decoder > decoders, Result *=nullptr, SkPngChunkReader *=nullptr, SelectionPolicy selectionPolicy=SelectionPolicy::kPreferStillImage)
Definition: SkCodec.cpp:163
bool isAtEnd() const override
Definition: SkStream.cpp:361
size_t read(void *buffer, size_t size) override
Definition: SkStream.cpp:337
static std::unique_ptr< SkMemoryStream > MakeDirect(const void *data, size_t length)
Definition: SkStream.cpp:310
size_t getPosition() const override
Definition: SkStream.cpp:374
virtual bool rewind()
Definition: SkStream.h:100
virtual bool hasPosition() const
Definition: SkStream.h:117
size_t skip(size_t size)
Definition: SkStream.h:51
virtual bool isAtEnd() const =0
virtual size_t getLength() const
Definition: SkStream.h:137
virtual bool hasLength() const
Definition: SkStream.h:135
virtual size_t read(void *buffer, size_t size)=0
static std::unique_ptr< SkStreamRewindable > Make(std::unique_ptr< SkStream > stream, size_t minBufferSize)
static float min(float r, float g, float b)
Definition: hsl.cpp:48
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
dst
Definition: cp.py:12
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63