blob: 49d2005287a4280d165ef577faf09999838023ec [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 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 */
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00007
Leon Scroggins III63cfb362020-04-24 13:00:48 -04008// Make sure SkUserConfig.h is included so #defines are available on
9// Android.
10#include "include/core/SkTypes.h"
11#ifdef SK_ENABLE_ANDROID_UTILS
12#include "client_utils/android/FrontBufferedStream.h"
13#endif
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "include/core/SkData.h"
15#include "include/core/SkStream.h"
16#include "include/private/SkTo.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "include/utils/SkRandom.h"
18#include "src/core/SkAutoMalloc.h"
19#include "src/core/SkOSFile.h"
20#include "src/core/SkStreamPriv.h"
21#include "src/utils/SkOSPath.h"
22#include "tests/Test.h"
23#include "tools/Resources.h"
reed@android.com5e5adfd2009-03-07 03:39:23 +000024
Leon Scroggins III8a8a1442018-05-08 09:35:32 -040025#include <functional>
26#include <limits>
27
reed@google.com789c6f22013-02-25 20:24:24 +000028#ifndef SK_BUILD_FOR_WIN
29#include <unistd.h>
30#include <fcntl.h>
31#endif
32
reed@android.com5e5adfd2009-03-07 03:39:23 +000033#define MAX_SIZE (256 * 1024)
34
reed@google.com789c6f22013-02-25 20:24:24 +000035static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream,
36 const void* src, size_t len, int repeat) {
37 SkAutoSMalloc<256> storage(len);
38 void* tmp = storage.get();
39
40 for (int i = 0; i < repeat; ++i) {
41 size_t bytes = stream->read(tmp, len);
42 REPORTER_ASSERT(reporter, bytes == len);
43 REPORTER_ASSERT(reporter, !memcmp(tmp, src, len));
44 }
45
46 // expect EOF
47 size_t bytes = stream->read(tmp, 1);
48 REPORTER_ASSERT(reporter, 0 == bytes);
bungeman@google.com88682b72013-07-19 13:55:41 +000049 // isAtEnd might not return true until after the first failing read.
50 REPORTER_ASSERT(reporter, stream->isAtEnd());
reed@google.com789c6f22013-02-25 20:24:24 +000051}
52
53static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
tfarinaa8e2e152014-07-28 19:26:58 -070054 SkString path = SkOSPath::Join(tmpDir, "wstream_test");
reed@google.com789c6f22013-02-25 20:24:24 +000055
56 const char s[] = "abcdefghijklmnopqrstuvwxyz";
57
58 {
59 SkFILEWStream writer(path.c_str());
60 if (!writer.isValid()) {
halcanary@google.coma9325fa2014-01-10 14:58:10 +000061 ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +000062 return;
63 }
64
65 for (int i = 0; i < 100; ++i) {
66 writer.write(s, 26);
67 }
68 }
69
70 {
71 SkFILEStream stream(path.c_str());
72 REPORTER_ASSERT(reporter, stream.isValid());
73 test_loop_stream(reporter, &stream, s, 26, 100);
bungeman@google.com6cab1a42013-05-29 13:43:31 +000074
Ben Wagner145dbcd2016-11-03 14:40:50 -040075 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +000076 test_loop_stream(reporter, stream2.get(), s, 26, 100);
reed@google.com789c6f22013-02-25 20:24:24 +000077 }
78
reed@google.com789c6f22013-02-25 20:24:24 +000079 {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000080 FILE* file = ::fopen(path.c_str(), "rb");
Ben Wagner4d1955c2017-03-10 13:08:15 -050081 SkFILEStream stream(file);
reed@google.com789c6f22013-02-25 20:24:24 +000082 REPORTER_ASSERT(reporter, stream.isValid());
83 test_loop_stream(reporter, &stream, s, 26, 100);
bungeman@google.com6cab1a42013-05-29 13:43:31 +000084
Ben Wagner145dbcd2016-11-03 14:40:50 -040085 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +000086 test_loop_stream(reporter, stream2.get(), s, 26, 100);
reed@google.com789c6f22013-02-25 20:24:24 +000087 }
reed@google.com789c6f22013-02-25 20:24:24 +000088}
89
reed@android.com80e39a72009-04-02 16:59:40 +000090static void TestWStream(skiatest::Reporter* reporter) {
91 SkDynamicMemoryWStream ds;
92 const char s[] = "abcdefghijklmnopqrstuvwxyz";
93 int i;
94 for (i = 0; i < 100; i++) {
95 REPORTER_ASSERT(reporter, ds.write(s, 26));
reed@android.com5e5adfd2009-03-07 03:39:23 +000096 }
Ben Wagner884300d2016-12-16 16:51:41 +000097 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
bungeman@google.com88682b72013-07-19 13:55:41 +000098
reed@android.com80e39a72009-04-02 16:59:40 +000099 char* dst = new char[100 * 26 + 1];
100 dst[100*26] = '*';
101 ds.copyTo(dst);
102 REPORTER_ASSERT(reporter, dst[100*26] == '*');
reed@android.com80e39a72009-04-02 16:59:40 +0000103 for (i = 0; i < 100; i++) {
104 REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
reed@android.com5e5adfd2009-03-07 03:39:23 +0000105 }
reed@google.com70442a62011-06-23 21:48:04 +0000106
107 {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400108 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
bungeman@google.com88682b72013-07-19 13:55:41 +0000109 REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
Ben Wagner884300d2016-12-16 16:51:41 +0000110 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
bungeman@google.com88682b72013-07-19 13:55:41 +0000111 test_loop_stream(reporter, stream.get(), s, 26, 100);
112
Ben Wagner145dbcd2016-11-03 14:40:50 -0400113 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
bungeman@google.com88682b72013-07-19 13:55:41 +0000114 test_loop_stream(reporter, stream2.get(), s, 26, 100);
115
Ben Wagner145dbcd2016-11-03 14:40:50 -0400116 std::unique_ptr<SkStreamAsset> stream3(stream->fork());
bungeman@google.com88682b72013-07-19 13:55:41 +0000117 REPORTER_ASSERT(reporter, stream3->isAtEnd());
118 char tmp;
119 size_t bytes = stream->read(&tmp, 1);
120 REPORTER_ASSERT(reporter, 0 == bytes);
121 stream3->rewind();
122 test_loop_stream(reporter, stream3.get(), s, 26, 100);
123 }
124
125 for (i = 0; i < 100; i++) {
126 REPORTER_ASSERT(reporter, ds.write(s, 26));
127 }
Ben Wagner884300d2016-12-16 16:51:41 +0000128 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
bungeman@google.com88682b72013-07-19 13:55:41 +0000129
130 {
reed42943c82016-09-12 12:01:44 -0700131 // Test that this works after a snapshot.
Ben Wagner145dbcd2016-11-03 14:40:50 -0400132 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
Ben Wagner884300d2016-12-16 16:51:41 +0000133 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
bungeman@google.com88682b72013-07-19 13:55:41 +0000134 test_loop_stream(reporter, stream.get(), s, 26, 100);
135
Ben Wagner145dbcd2016-11-03 14:40:50 -0400136 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
bungeman@google.com88682b72013-07-19 13:55:41 +0000137 test_loop_stream(reporter, stream2.get(), s, 26, 100);
reed@google.com70442a62011-06-23 21:48:04 +0000138 }
reed@android.com80e39a72009-04-02 16:59:40 +0000139 delete[] dst;
reed@google.com789c6f22013-02-25 20:24:24 +0000140
halcanary87f3ba42015-01-20 09:30:20 -0800141 SkString tmpDir = skiatest::GetTmpDir();
scroggo@google.comc76218d2013-06-06 14:59:56 +0000142 if (!tmpDir.isEmpty()) {
143 test_filestreams(reporter, tmpDir.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +0000144 }
reed@android.com5e5adfd2009-03-07 03:39:23 +0000145}
146
reed@google.com19f286b2011-10-18 11:49:52 +0000147static void TestPackedUInt(skiatest::Reporter* reporter) {
148 // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
149 // so we test values around each of those transitions (and a few others)
150 const size_t sizes[] = {
151 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
152 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
153 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
154 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
155 };
rmistry@google.comd6176b02012-08-23 18:14:13 +0000156
157
reed@google.com19f286b2011-10-18 11:49:52 +0000158 size_t i;
Mike Reedff80c2a2017-01-07 11:16:28 -0500159 SkDynamicMemoryWStream wstream;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000160
reed@google.com19f286b2011-10-18 11:49:52 +0000161 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
162 bool success = wstream.writePackedUInt(sizes[i]);
163 REPORTER_ASSERT(reporter, success);
164 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000165
Mike Reedff80c2a2017-01-07 11:16:28 -0500166 std::unique_ptr<SkStreamAsset> rstream(wstream.detachAsStream());
reed@google.com19f286b2011-10-18 11:49:52 +0000167 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
Ben Wagner255ab8d2016-10-07 15:50:53 -0400168 size_t n;
169 if (!rstream->readPackedUInt(&n)) {
Adlai Holler684838f2020-05-12 10:41:04 -0400170 ERRORF(reporter, "[%zu] sizes:%zx could not be read\n", i, sizes[i]);
Ben Wagner255ab8d2016-10-07 15:50:53 -0400171 }
reed@google.com19f286b2011-10-18 11:49:52 +0000172 if (sizes[i] != n) {
Adlai Holler684838f2020-05-12 10:41:04 -0400173 ERRORF(reporter, "[%zu] sizes:%zx != n:%zx\n", i, sizes[i], n);
reed@google.com19f286b2011-10-18 11:49:52 +0000174 }
reed@google.com19f286b2011-10-18 11:49:52 +0000175 }
176}
177
halcanary96fcdcc2015-08-27 07:41:13 -0700178// Test that setting an SkMemoryStream to a nullptr data does not result in a crash when calling
scroggo@google.come4904202013-01-09 22:02:58 +0000179// methods that access fData.
180static void TestDereferencingData(SkMemoryStream* memStream) {
halcanary96fcdcc2015-08-27 07:41:13 -0700181 memStream->read(nullptr, 0);
scroggo@google.come4904202013-01-09 22:02:58 +0000182 memStream->getMemoryBase();
reed42943c82016-09-12 12:01:44 -0700183 (void)memStream->asData();
scroggo@google.come4904202013-01-09 22:02:58 +0000184}
185
186static void TestNullData() {
reed42943c82016-09-12 12:01:44 -0700187 SkMemoryStream memStream(nullptr);
scroggo@google.come4904202013-01-09 22:02:58 +0000188 TestDereferencingData(&memStream);
189
reed42943c82016-09-12 12:01:44 -0700190 memStream.setData(nullptr);
scroggo@google.come4904202013-01-09 22:02:58 +0000191 TestDereferencingData(&memStream);
192
193}
194
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000195DEF_TEST(Stream, reporter) {
reed@android.com5e5adfd2009-03-07 03:39:23 +0000196 TestWStream(reporter);
reed@google.com19f286b2011-10-18 11:49:52 +0000197 TestPackedUInt(reporter);
scroggo@google.come4904202013-01-09 22:02:58 +0000198 TestNullData();
reed@android.com5e5adfd2009-03-07 03:39:23 +0000199}
scroggo028a4132015-04-02 13:19:51 -0700200
Mike Klein7d302882016-11-03 14:06:31 -0400201#ifndef SK_BUILD_FOR_IOS
scroggo028a4132015-04-02 13:19:51 -0700202/**
203 * Tests peeking and then reading the same amount. The two should provide the
204 * same results.
scroggod61c3842015-12-07 11:37:13 -0800205 * Returns the amount successfully read minus the amount successfully peeked.
scroggo028a4132015-04-02 13:19:51 -0700206 */
scroggod61c3842015-12-07 11:37:13 -0800207static size_t compare_peek_to_read(skiatest::Reporter* reporter,
208 SkStream* stream, size_t bytesToPeek) {
scroggo028a4132015-04-02 13:19:51 -0700209 // The rest of our tests won't be very interesting if bytesToPeek is zero.
210 REPORTER_ASSERT(reporter, bytesToPeek > 0);
211 SkAutoMalloc peekStorage(bytesToPeek);
212 SkAutoMalloc readStorage(bytesToPeek);
213 void* peekPtr = peekStorage.get();
214 void* readPtr = peekStorage.get();
215
scroggod61c3842015-12-07 11:37:13 -0800216 const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek);
scroggo028a4132015-04-02 13:19:51 -0700217 const size_t bytesRead = stream->read(readPtr, bytesToPeek);
218
219 // bytesRead should only be less than attempted if the stream is at the
220 // end.
221 REPORTER_ASSERT(reporter, bytesRead == bytesToPeek || stream->isAtEnd());
222
223 // peek and read should behave the same, except peek returned to the
224 // original position, so they read the same data.
scroggod61c3842015-12-07 11:37:13 -0800225 REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked));
scroggo028a4132015-04-02 13:19:51 -0700226
scroggod61c3842015-12-07 11:37:13 -0800227 // A stream should never be able to peek more than it can read.
228 REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked);
229
230 return bytesRead - bytesPeeked;
scroggo028a4132015-04-02 13:19:51 -0700231}
232
scroggod61c3842015-12-07 11:37:13 -0800233static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
scroggo028a4132015-04-02 13:19:51 -0700234 for (size_t i = 1; !stream->isAtEnd(); i++) {
scroggod61c3842015-12-07 11:37:13 -0800235 REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
scroggo028a4132015-04-02 13:19:51 -0700236 }
237}
238
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400239#ifdef SK_ENABLE_ANDROID_UTILS
scroggo028a4132015-04-02 13:19:51 -0700240static void test_peeking_front_buffered_stream(skiatest::Reporter* r,
241 const SkStream& original,
242 size_t bufferSize) {
Mike Reed98c5d922017-09-15 21:39:47 -0400243 std::unique_ptr<SkStream> dupe(original.duplicate());
halcanary96fcdcc2015-08-27 07:41:13 -0700244 REPORTER_ASSERT(r, dupe != nullptr);
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400245 auto bufferedStream = android::skia::FrontBufferedStream::Make(
246 std::move(dupe), bufferSize);
halcanary96fcdcc2015-08-27 07:41:13 -0700247 REPORTER_ASSERT(r, bufferedStream != nullptr);
scroggod61c3842015-12-07 11:37:13 -0800248
249 size_t peeked = 0;
250 for (size_t i = 1; !bufferedStream->isAtEnd(); i++) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400251 const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i);
scroggod61c3842015-12-07 11:37:13 -0800252 if (unpeekableBytes > 0) {
253 // This could not have returned a number greater than i.
254 REPORTER_ASSERT(r, unpeekableBytes <= i);
255
256 // We have reached the end of the buffer. Verify that it was at least
257 // bufferSize.
258 REPORTER_ASSERT(r, peeked + i - unpeekableBytes >= bufferSize);
259 // No more peeking is supported.
260 break;
261 }
262 peeked += i;
263 }
264
265 // Test that attempting to peek beyond the length of the buffer does not prevent rewinding.
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400266 bufferedStream = android::skia::FrontBufferedStream::Make(original.duplicate(), bufferSize);
scroggod61c3842015-12-07 11:37:13 -0800267 REPORTER_ASSERT(r, bufferedStream != nullptr);
268
269 const size_t bytesToPeek = bufferSize + 1;
270 SkAutoMalloc peekStorage(bytesToPeek);
271 SkAutoMalloc readStorage(bytesToPeek);
272
273 for (size_t start = 0; start <= bufferSize; start++) {
274 // Skip to the starting point
275 REPORTER_ASSERT(r, bufferedStream->skip(start) == start);
scroggod61c3842015-12-07 11:37:13 -0800276
277 const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek);
278 if (0 == bytesPeeked) {
scroggoef0fed32016-02-18 05:59:25 -0800279 // Peeking should only fail completely if we have read/skipped beyond the buffer.
280 REPORTER_ASSERT(r, start >= bufferSize);
scroggod61c3842015-12-07 11:37:13 -0800281 break;
282 }
283
284 // Only read the amount that was successfully peeked.
285 const size_t bytesRead = bufferedStream->read(readStorage.get(), bytesPeeked);
286 REPORTER_ASSERT(r, bytesRead == bytesPeeked);
287 REPORTER_ASSERT(r, !memcmp(peekStorage.get(), readStorage.get(), bytesPeeked));
288
289 // This should be safe to rewind.
290 REPORTER_ASSERT(r, bufferedStream->rewind());
291 }
scroggo028a4132015-04-02 13:19:51 -0700292}
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400293#endif
scroggo028a4132015-04-02 13:19:51 -0700294
halcanary9d524f22016-03-29 09:03:52 -0700295// This test uses file system operations that don't work out of the
296// box on iOS. It's likely that we don't need them on iOS. Ignoring for now.
297// TODO(stephana): Re-evaluate if we need this in the future.
scroggo028a4132015-04-02 13:19:51 -0700298DEF_TEST(StreamPeek, reporter) {
299 // Test a memory stream.
300 const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz";
301 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
scroggod61c3842015-12-07 11:37:13 -0800302 test_fully_peekable_stream(reporter, &memStream, memStream.getLength());
scroggo028a4132015-04-02 13:19:51 -0700303
304 // Test an arbitrary file stream. file streams do not support peeking.
Hal Canary925e31e2017-12-11 14:42:58 -0500305 auto tmpdir = skiatest::GetTmpDir();
306 if (tmpdir.isEmpty()) {
307 ERRORF(reporter, "no tmp dir!");
Hal Canarya4935102017-12-08 13:35:47 -0500308 return;
309 }
Hal Canary925e31e2017-12-11 14:42:58 -0500310 auto path = SkOSPath::Join(tmpdir.c_str(), "file");
311 {
312 SkFILEWStream wStream(path.c_str());
313 constexpr char filename[] = "images/baby_tux.webp";
314 auto data = GetResourceAsData(filename);
315 if (!data || data->size() == 0) {
316 ERRORF(reporter, "resource missing: %s\n", filename);
317 return;
318 }
319 if (!wStream.isValid() || !wStream.write(data->data(), data->size())) {
320 ERRORF(reporter, "error wrtiting to file %s", path.c_str());
321 return;
322 }
323 }
Hal Canarya4935102017-12-08 13:35:47 -0500324 SkFILEStream fileStream(path.c_str());
scroggo028a4132015-04-02 13:19:51 -0700325 REPORTER_ASSERT(reporter, fileStream.isValid());
caryclark30ac4642015-04-14 06:08:04 -0700326 if (!fileStream.isValid()) {
327 return;
328 }
scroggo028a4132015-04-02 13:19:51 -0700329 SkAutoMalloc storage(fileStream.getLength());
330 for (size_t i = 1; i < fileStream.getLength(); i++) {
scroggod61c3842015-12-07 11:37:13 -0800331 REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0);
scroggo028a4132015-04-02 13:19:51 -0700332 }
333
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400334#ifdef SK_ENABLE_ANDROID_UTILS
scroggo028a4132015-04-02 13:19:51 -0700335 // Now test some FrontBufferedStreams
336 for (size_t i = 1; i < memStream.getLength(); i++) {
337 test_peeking_front_buffered_stream(reporter, memStream, i);
338 }
Leon Scroggins III63cfb362020-04-24 13:00:48 -0400339#endif
scroggo028a4132015-04-02 13:19:51 -0700340}
halcanarye797d0d2015-05-21 08:13:27 -0700341#endif
342
343// Asserts that asset == expected and is peekable.
344static void stream_peek_test(skiatest::Reporter* rep,
345 SkStreamAsset* asset,
346 const SkData* expected) {
347 if (asset->getLength() != expected->size()) {
348 ERRORF(rep, "Unexpected length.");
349 return;
350 }
351 SkRandom rand;
352 uint8_t buffer[4096];
353 const uint8_t* expect = expected->bytes();
354 for (size_t i = 0; i < asset->getLength(); ++i) {
355 uint32_t maxSize =
Brian Osman788b9162020-02-07 10:36:46 -0500356 SkToU32(std::min(sizeof(buffer), asset->getLength() - i));
halcanarye797d0d2015-05-21 08:13:27 -0700357 size_t size = rand.nextRangeU(1, maxSize);
358 SkASSERT(size >= 1);
359 SkASSERT(size <= sizeof(buffer));
360 SkASSERT(size + i <= asset->getLength());
scroggod61c3842015-12-07 11:37:13 -0800361 if (asset->peek(buffer, size) < size) {
halcanarye797d0d2015-05-21 08:13:27 -0700362 ERRORF(rep, "Peek Failed!");
363 return;
364 }
365 if (0 != memcmp(buffer, &expect[i], size)) {
366 ERRORF(rep, "Peek returned wrong bytes!");
367 return;
368 }
369 uint8_t value;
370 REPORTER_ASSERT(rep, 1 == asset->read(&value, 1));
371 if (value != expect[i]) {
372 ERRORF(rep, "Read Failed!");
373 return;
374 }
375 }
376}
377
378DEF_TEST(StreamPeek_BlockMemoryStream, rep) {
379 const static int kSeed = 1234;
380 SkRandom valueSource(kSeed);
381 SkRandom rand(kSeed << 1);
382 uint8_t buffer[4096];
383 SkDynamicMemoryWStream dynamicMemoryWStream;
Mike Reed49282292016-12-14 12:34:06 -0500384 size_t totalWritten = 0;
halcanarye797d0d2015-05-21 08:13:27 -0700385 for (int i = 0; i < 32; ++i) {
386 // Randomize the length of the blocks.
387 size_t size = rand.nextRangeU(1, sizeof(buffer));
388 for (size_t j = 0; j < size; ++j) {
389 buffer[j] = valueSource.nextU() & 0xFF;
390 }
391 dynamicMemoryWStream.write(buffer, size);
Mike Reed49282292016-12-14 12:34:06 -0500392 totalWritten += size;
393 REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten());
halcanarye797d0d2015-05-21 08:13:27 -0700394 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400395 std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream());
bungeman38d909e2016-08-02 14:40:46 -0700396 sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength()));
halcanarye797d0d2015-05-21 08:13:27 -0700397 uint8_t* expectedPtr = static_cast<uint8_t*>(expected->writable_data());
398 valueSource.setSeed(kSeed); // reseed.
399 // We want the exact same same "random" string of numbers to put
400 // in expected. i.e.: don't rely on SkDynamicMemoryStream to work
401 // correctly while we are testing SkDynamicMemoryStream.
402 for (size_t i = 0; i < asset->getLength(); ++i) {
403 expectedPtr[i] = valueSource.nextU() & 0xFF;
404 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400405 stream_peek_test(rep, asset.get(), expected.get());
halcanarye797d0d2015-05-21 08:13:27 -0700406}
halcanary48305e82015-08-18 13:30:25 -0700407
408namespace {
409class DumbStream : public SkStream {
410public:
411 DumbStream(const uint8_t* data, size_t n)
412 : fData(data), fCount(n), fIdx(0) {}
413 size_t read(void* buffer, size_t size) override {
Brian Osman788b9162020-02-07 10:36:46 -0500414 size_t copyCount = std::min(fCount - fIdx, size);
halcanaryd75e21d2015-08-19 07:22:04 -0700415 if (copyCount) {
416 memcpy(buffer, &fData[fIdx], copyCount);
417 fIdx += copyCount;
halcanary48305e82015-08-18 13:30:25 -0700418 }
halcanaryd75e21d2015-08-19 07:22:04 -0700419 return copyCount;
halcanary48305e82015-08-18 13:30:25 -0700420 }
421 bool isAtEnd() const override {
halcanaryd75e21d2015-08-19 07:22:04 -0700422 return fCount == fIdx;
halcanary48305e82015-08-18 13:30:25 -0700423 }
424 private:
425 const uint8_t* fData;
426 size_t fCount, fIdx;
427};
428} // namespace
429
430static void stream_copy_test(skiatest::Reporter* reporter,
431 const void* srcData,
432 size_t N,
433 SkStream* stream) {
434 SkDynamicMemoryWStream tgt;
435 if (!SkStreamCopy(&tgt, stream)) {
436 ERRORF(reporter, "SkStreamCopy failed");
437 return;
438 }
reed42943c82016-09-12 12:01:44 -0700439 sk_sp<SkData> data(tgt.detachAsData());
halcanary48305e82015-08-18 13:30:25 -0700440 if (data->size() != N) {
441 ERRORF(reporter, "SkStreamCopy incorrect size");
442 return;
443 }
444 if (0 != memcmp(data->data(), srcData, N)) {
445 ERRORF(reporter, "SkStreamCopy bad copy");
446 }
447}
448
Hal Canarydabe8ac2017-03-14 15:52:12 -0400449DEF_TEST(DynamicMemoryWStream_detachAsData, r) {
450 const char az[] = "abcdefghijklmnopqrstuvwxyz";
451 const unsigned N = 40000;
452 SkDynamicMemoryWStream dmws;
453 for (unsigned i = 0; i < N; ++i) {
454 dmws.writeText(az);
455 }
456 REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az));
457 auto data = dmws.detachAsData();
458 REPORTER_ASSERT(r, data->size() == N * strlen(az));
459 const uint8_t* ptr = data->bytes();
460 for (unsigned i = 0; i < N; ++i) {
461 if (0 != memcmp(ptr, az, strlen(az))) {
462 ERRORF(r, "detachAsData() memcmp failed");
463 return;
464 }
465 ptr += strlen(az);
466 }
467}
468
halcanary48305e82015-08-18 13:30:25 -0700469DEF_TEST(StreamCopy, reporter) {
470 SkRandom random(123456);
halcanarycb9241b2015-08-19 06:12:40 -0700471 static const int N = 10000;
472 SkAutoTMalloc<uint8_t> src((size_t)N);
473 for (int j = 0; j < N; ++j) {
halcanary48305e82015-08-18 13:30:25 -0700474 src[j] = random.nextU() & 0xff;
475 }
476 // SkStreamCopy had two code paths; this test both.
halcanarycb9241b2015-08-19 06:12:40 -0700477 DumbStream dumbStream(src.get(), (size_t)N);
halcanary48305e82015-08-18 13:30:25 -0700478 stream_copy_test(reporter, src, N, &dumbStream);
halcanarycb9241b2015-08-19 06:12:40 -0700479 SkMemoryStream smartStream(src.get(), (size_t)N);
halcanary48305e82015-08-18 13:30:25 -0700480 stream_copy_test(reporter, src, N, &smartStream);
halcanary48305e82015-08-18 13:30:25 -0700481}
halcanary209c1622015-09-28 07:29:39 -0700482
483DEF_TEST(StreamEmptyStreamMemoryBase, r) {
484 SkDynamicMemoryWStream tmp;
Ben Wagner145dbcd2016-11-03 14:40:50 -0400485 std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream());
halcanary209c1622015-09-28 07:29:39 -0700486 REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
487}
Mike Reed1026ccf2017-01-08 14:35:29 -0500488
Leon Scroggins III8a8a1442018-05-08 09:35:32 -0400489DEF_TEST(FILEStreamWithOffset, r) {
490 if (GetResourcePath().isEmpty()) {
491 return;
492 }
493
494 SkString filename = GetResourcePath("images/baby_tux.png");
495 SkFILEStream stream1(filename.c_str());
496 if (!stream1.isValid()) {
497 ERRORF(r, "Could not create SkFILEStream from %s", filename.c_str());
498 return;
499 }
500 REPORTER_ASSERT(r, stream1.hasLength());
501 REPORTER_ASSERT(r, stream1.hasPosition());
502
503 // Seek halfway through the file. The second SkFILEStream will be created
504 // with the same filename and offset and therefore will treat that offset as
505 // the beginning.
506 const size_t size = stream1.getLength();
507 const size_t middle = size / 2;
508 if (!stream1.seek(middle)) {
509 ERRORF(r, "Could not seek SkFILEStream to %lu out of %lu", middle, size);
510 return;
511 }
512 REPORTER_ASSERT(r, stream1.getPosition() == middle);
513
514 FILE* file = sk_fopen(filename.c_str(), kRead_SkFILE_Flag);
515 if (!file) {
516 ERRORF(r, "Could not open %s as a FILE", filename.c_str());
517 return;
518 }
519
520 if (fseek(file, (long) middle, SEEK_SET) != 0) {
521 ERRORF(r, "Could not fseek FILE to %lu out of %lu", middle, size);
522 return;
523 }
524 SkFILEStream stream2(file);
525
526 const size_t remaining = size - middle;
527 SkAutoTMalloc<uint8_t> expected(remaining);
528 REPORTER_ASSERT(r, stream1.read(expected.get(), remaining) == remaining);
529
530 auto test_full_read = [&r, &expected, remaining](SkStream* stream) {
531 SkAutoTMalloc<uint8_t> actual(remaining);
532 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
533 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
534
535 REPORTER_ASSERT(r, stream->getPosition() == stream->getLength());
536 REPORTER_ASSERT(r, stream->isAtEnd());
537 };
538
539 auto test_rewind = [&r, &expected, remaining](SkStream* stream) {
540 // Rewind goes back to original offset.
541 REPORTER_ASSERT(r, stream->rewind());
542 REPORTER_ASSERT(r, stream->getPosition() == 0);
543 SkAutoTMalloc<uint8_t> actual(remaining);
544 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
545 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
546 };
547
548 auto test_move = [&r, &expected, size, remaining](SkStream* stream) {
549 // Cannot move to before the original offset.
550 REPORTER_ASSERT(r, stream->move(- (long) size));
551 REPORTER_ASSERT(r, stream->getPosition() == 0);
552
553 REPORTER_ASSERT(r, stream->move(std::numeric_limits<long>::min()));
554 REPORTER_ASSERT(r, stream->getPosition() == 0);
555
556 SkAutoTMalloc<uint8_t> actual(remaining);
557 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
558 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
559
560 REPORTER_ASSERT(r, stream->isAtEnd());
561 REPORTER_ASSERT(r, stream->getPosition() == remaining);
562
563 // Cannot move beyond the end.
564 REPORTER_ASSERT(r, stream->move(1));
565 REPORTER_ASSERT(r, stream->isAtEnd());
566 REPORTER_ASSERT(r, stream->getPosition() == remaining);
567 };
568
569 auto test_seek = [&r, &expected, middle, remaining](SkStream* stream) {
570 // Seek to an arbitrary position.
571 const size_t arbitrary = middle / 2;
572 REPORTER_ASSERT(r, stream->seek(arbitrary));
573 REPORTER_ASSERT(r, stream->getPosition() == arbitrary);
574 const size_t miniRemaining = remaining - arbitrary;
575 SkAutoTMalloc<uint8_t> actual(miniRemaining);
576 REPORTER_ASSERT(r, stream->read(actual.get(), miniRemaining) == miniRemaining);
577 REPORTER_ASSERT(r, !memcmp(expected.get() + arbitrary, actual.get(), miniRemaining));
578 };
579
580 auto test_seek_beginning = [&r, &expected, remaining](SkStream* stream) {
581 // Seek to the beginning.
582 REPORTER_ASSERT(r, stream->seek(0));
583 REPORTER_ASSERT(r, stream->getPosition() == 0);
584 SkAutoTMalloc<uint8_t> actual(remaining);
585 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
586 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
587 };
588
589 auto test_seek_end = [&r, remaining](SkStream* stream) {
590 // Cannot seek past the end.
591 REPORTER_ASSERT(r, stream->isAtEnd());
592
593 REPORTER_ASSERT(r, stream->seek(remaining + 1));
594 REPORTER_ASSERT(r, stream->isAtEnd());
595 REPORTER_ASSERT(r, stream->getPosition() == remaining);
596
597 const size_t middle = remaining / 2;
598 REPORTER_ASSERT(r, stream->seek(middle));
599 REPORTER_ASSERT(r, !stream->isAtEnd());
600 REPORTER_ASSERT(r, stream->getPosition() == middle);
601
602 REPORTER_ASSERT(r, stream->seek(remaining * 2));
603 REPORTER_ASSERT(r, stream->isAtEnd());
604 REPORTER_ASSERT(r, stream->getPosition() == remaining);
605
606 REPORTER_ASSERT(r, stream->seek(std::numeric_limits<long>::max()));
607 REPORTER_ASSERT(r, stream->isAtEnd());
608 REPORTER_ASSERT(r, stream->getPosition() == remaining);
609 };
610
611
612 std::function<void (SkStream* stream, bool recurse)> test_all;
613 test_all = [&](SkStream* stream, bool recurse) {
614 REPORTER_ASSERT(r, stream->getLength() == remaining);
615 REPORTER_ASSERT(r, stream->getPosition() == 0);
616
617 test_full_read(stream);
618 test_rewind(stream);
619 test_move(stream);
620 test_seek(stream);
621 test_seek_beginning(stream);
622 test_seek_end(stream);
623
624 if (recurse) {
625 // Duplicate shares the original offset.
626 auto duplicate = stream->duplicate();
627 if (!duplicate) {
628 ERRORF(r, "Failed to duplicate the stream!");
629 } else {
630 test_all(duplicate.get(), false);
631 }
632
633 // Fork shares the original offset, too.
634 auto fork = stream->fork();
635 if (!fork) {
636 ERRORF(r, "Failed to fork the stream!");
637 } else {
638 REPORTER_ASSERT(r, fork->isAtEnd());
639 REPORTER_ASSERT(r, fork->getLength() == remaining);
640 REPORTER_ASSERT(r, fork->rewind());
641
642 test_all(fork.get(), false);
643 }
644 }
645 };
646
647 test_all(&stream2, true);
648}
649
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500650#include "src/core/SkBuffer.h"
Mike Reed1026ccf2017-01-08 14:35:29 -0500651
652DEF_TEST(RBuffer, reporter) {
653 int32_t value = 0;
654 SkRBuffer buffer(&value, 4);
655 REPORTER_ASSERT(reporter, buffer.isValid());
656
657 int32_t tmp;
658 REPORTER_ASSERT(reporter, buffer.read(&tmp, 4));
659 REPORTER_ASSERT(reporter, buffer.isValid());
660
661 REPORTER_ASSERT(reporter, !buffer.read(&tmp, 4));
662 REPORTER_ASSERT(reporter, !buffer.isValid());
663}