blob: bc00f4529e99313f5977fc5ddd19ef4704c32801 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkData.h"
9#include "include/core/SkStream.h"
10#include "include/private/SkTo.h"
11#include "include/utils/SkFrontBufferedStream.h"
12#include "include/utils/SkRandom.h"
13#include "src/core/SkAutoMalloc.h"
14#include "src/core/SkOSFile.h"
15#include "src/core/SkStreamPriv.h"
16#include "src/utils/SkOSPath.h"
17#include "tests/Test.h"
18#include "tools/Resources.h"
reed@android.com5e5adfd2009-03-07 03:39:23 +000019
Leon Scroggins III8a8a1442018-05-08 09:35:32 -040020#include <functional>
21#include <limits>
22
reed@google.com789c6f22013-02-25 20:24:24 +000023#ifndef SK_BUILD_FOR_WIN
24#include <unistd.h>
25#include <fcntl.h>
26#endif
27
reed@android.com5e5adfd2009-03-07 03:39:23 +000028#define MAX_SIZE (256 * 1024)
29
reed@google.com789c6f22013-02-25 20:24:24 +000030static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream,
31 const void* src, size_t len, int repeat) {
32 SkAutoSMalloc<256> storage(len);
33 void* tmp = storage.get();
34
35 for (int i = 0; i < repeat; ++i) {
36 size_t bytes = stream->read(tmp, len);
37 REPORTER_ASSERT(reporter, bytes == len);
38 REPORTER_ASSERT(reporter, !memcmp(tmp, src, len));
39 }
40
41 // expect EOF
42 size_t bytes = stream->read(tmp, 1);
43 REPORTER_ASSERT(reporter, 0 == bytes);
bungeman@google.com88682b72013-07-19 13:55:41 +000044 // isAtEnd might not return true until after the first failing read.
45 REPORTER_ASSERT(reporter, stream->isAtEnd());
reed@google.com789c6f22013-02-25 20:24:24 +000046}
47
48static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
tfarinaa8e2e152014-07-28 19:26:58 -070049 SkString path = SkOSPath::Join(tmpDir, "wstream_test");
reed@google.com789c6f22013-02-25 20:24:24 +000050
51 const char s[] = "abcdefghijklmnopqrstuvwxyz";
52
53 {
54 SkFILEWStream writer(path.c_str());
55 if (!writer.isValid()) {
halcanary@google.coma9325fa2014-01-10 14:58:10 +000056 ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +000057 return;
58 }
59
60 for (int i = 0; i < 100; ++i) {
61 writer.write(s, 26);
62 }
63 }
64
65 {
66 SkFILEStream stream(path.c_str());
67 REPORTER_ASSERT(reporter, stream.isValid());
68 test_loop_stream(reporter, &stream, s, 26, 100);
bungeman@google.com6cab1a42013-05-29 13:43:31 +000069
Ben Wagner145dbcd2016-11-03 14:40:50 -040070 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +000071 test_loop_stream(reporter, stream2.get(), s, 26, 100);
reed@google.com789c6f22013-02-25 20:24:24 +000072 }
73
reed@google.com789c6f22013-02-25 20:24:24 +000074 {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000075 FILE* file = ::fopen(path.c_str(), "rb");
Ben Wagner4d1955c2017-03-10 13:08:15 -050076 SkFILEStream stream(file);
reed@google.com789c6f22013-02-25 20:24:24 +000077 REPORTER_ASSERT(reporter, stream.isValid());
78 test_loop_stream(reporter, &stream, s, 26, 100);
bungeman@google.com6cab1a42013-05-29 13:43:31 +000079
Ben Wagner145dbcd2016-11-03 14:40:50 -040080 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +000081 test_loop_stream(reporter, stream2.get(), s, 26, 100);
reed@google.com789c6f22013-02-25 20:24:24 +000082 }
reed@google.com789c6f22013-02-25 20:24:24 +000083}
84
reed@android.com80e39a72009-04-02 16:59:40 +000085static void TestWStream(skiatest::Reporter* reporter) {
86 SkDynamicMemoryWStream ds;
87 const char s[] = "abcdefghijklmnopqrstuvwxyz";
88 int i;
89 for (i = 0; i < 100; i++) {
90 REPORTER_ASSERT(reporter, ds.write(s, 26));
reed@android.com5e5adfd2009-03-07 03:39:23 +000091 }
Ben Wagner884300d2016-12-16 16:51:41 +000092 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
bungeman@google.com88682b72013-07-19 13:55:41 +000093
reed@android.com80e39a72009-04-02 16:59:40 +000094 char* dst = new char[100 * 26 + 1];
95 dst[100*26] = '*';
96 ds.copyTo(dst);
97 REPORTER_ASSERT(reporter, dst[100*26] == '*');
reed@android.com80e39a72009-04-02 16:59:40 +000098 for (i = 0; i < 100; i++) {
99 REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
reed@android.com5e5adfd2009-03-07 03:39:23 +0000100 }
reed@google.com70442a62011-06-23 21:48:04 +0000101
102 {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400103 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
bungeman@google.com88682b72013-07-19 13:55:41 +0000104 REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
Ben Wagner884300d2016-12-16 16:51:41 +0000105 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
bungeman@google.com88682b72013-07-19 13:55:41 +0000106 test_loop_stream(reporter, stream.get(), s, 26, 100);
107
Ben Wagner145dbcd2016-11-03 14:40:50 -0400108 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
bungeman@google.com88682b72013-07-19 13:55:41 +0000109 test_loop_stream(reporter, stream2.get(), s, 26, 100);
110
Ben Wagner145dbcd2016-11-03 14:40:50 -0400111 std::unique_ptr<SkStreamAsset> stream3(stream->fork());
bungeman@google.com88682b72013-07-19 13:55:41 +0000112 REPORTER_ASSERT(reporter, stream3->isAtEnd());
113 char tmp;
114 size_t bytes = stream->read(&tmp, 1);
115 REPORTER_ASSERT(reporter, 0 == bytes);
116 stream3->rewind();
117 test_loop_stream(reporter, stream3.get(), s, 26, 100);
118 }
119
120 for (i = 0; i < 100; i++) {
121 REPORTER_ASSERT(reporter, ds.write(s, 26));
122 }
Ben Wagner884300d2016-12-16 16:51:41 +0000123 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
bungeman@google.com88682b72013-07-19 13:55:41 +0000124
125 {
reed42943c82016-09-12 12:01:44 -0700126 // Test that this works after a snapshot.
Ben Wagner145dbcd2016-11-03 14:40:50 -0400127 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
Ben Wagner884300d2016-12-16 16:51:41 +0000128 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
bungeman@google.com88682b72013-07-19 13:55:41 +0000129 test_loop_stream(reporter, stream.get(), s, 26, 100);
130
Ben Wagner145dbcd2016-11-03 14:40:50 -0400131 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
bungeman@google.com88682b72013-07-19 13:55:41 +0000132 test_loop_stream(reporter, stream2.get(), s, 26, 100);
reed@google.com70442a62011-06-23 21:48:04 +0000133 }
reed@android.com80e39a72009-04-02 16:59:40 +0000134 delete[] dst;
reed@google.com789c6f22013-02-25 20:24:24 +0000135
halcanary87f3ba42015-01-20 09:30:20 -0800136 SkString tmpDir = skiatest::GetTmpDir();
scroggo@google.comc76218d2013-06-06 14:59:56 +0000137 if (!tmpDir.isEmpty()) {
138 test_filestreams(reporter, tmpDir.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +0000139 }
reed@android.com5e5adfd2009-03-07 03:39:23 +0000140}
141
reed@google.com19f286b2011-10-18 11:49:52 +0000142static void TestPackedUInt(skiatest::Reporter* reporter) {
143 // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
144 // so we test values around each of those transitions (and a few others)
145 const size_t sizes[] = {
146 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
147 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
148 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
149 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
150 };
rmistry@google.comd6176b02012-08-23 18:14:13 +0000151
152
reed@google.com19f286b2011-10-18 11:49:52 +0000153 size_t i;
Mike Reedff80c2a2017-01-07 11:16:28 -0500154 SkDynamicMemoryWStream wstream;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000155
reed@google.com19f286b2011-10-18 11:49:52 +0000156 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
157 bool success = wstream.writePackedUInt(sizes[i]);
158 REPORTER_ASSERT(reporter, success);
159 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000160
Mike Reedff80c2a2017-01-07 11:16:28 -0500161 std::unique_ptr<SkStreamAsset> rstream(wstream.detachAsStream());
reed@google.com19f286b2011-10-18 11:49:52 +0000162 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
Ben Wagner255ab8d2016-10-07 15:50:53 -0400163 size_t n;
164 if (!rstream->readPackedUInt(&n)) {
165 ERRORF(reporter, "[%d] sizes:%x could not be read\n", i, sizes[i]);
166 }
reed@google.com19f286b2011-10-18 11:49:52 +0000167 if (sizes[i] != n) {
Ben Wagner255ab8d2016-10-07 15:50:53 -0400168 ERRORF(reporter, "[%d] sizes:%x != n:%x\n", i, sizes[i], n);
reed@google.com19f286b2011-10-18 11:49:52 +0000169 }
reed@google.com19f286b2011-10-18 11:49:52 +0000170 }
171}
172
halcanary96fcdcc2015-08-27 07:41:13 -0700173// 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 +0000174// methods that access fData.
175static void TestDereferencingData(SkMemoryStream* memStream) {
halcanary96fcdcc2015-08-27 07:41:13 -0700176 memStream->read(nullptr, 0);
scroggo@google.come4904202013-01-09 22:02:58 +0000177 memStream->getMemoryBase();
reed42943c82016-09-12 12:01:44 -0700178 (void)memStream->asData();
scroggo@google.come4904202013-01-09 22:02:58 +0000179}
180
181static void TestNullData() {
reed42943c82016-09-12 12:01:44 -0700182 SkMemoryStream memStream(nullptr);
scroggo@google.come4904202013-01-09 22:02:58 +0000183 TestDereferencingData(&memStream);
184
reed42943c82016-09-12 12:01:44 -0700185 memStream.setData(nullptr);
scroggo@google.come4904202013-01-09 22:02:58 +0000186 TestDereferencingData(&memStream);
187
188}
189
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000190DEF_TEST(Stream, reporter) {
reed@android.com5e5adfd2009-03-07 03:39:23 +0000191 TestWStream(reporter);
reed@google.com19f286b2011-10-18 11:49:52 +0000192 TestPackedUInt(reporter);
scroggo@google.come4904202013-01-09 22:02:58 +0000193 TestNullData();
reed@android.com5e5adfd2009-03-07 03:39:23 +0000194}
scroggo028a4132015-04-02 13:19:51 -0700195
Mike Klein7d302882016-11-03 14:06:31 -0400196#ifndef SK_BUILD_FOR_IOS
scroggo028a4132015-04-02 13:19:51 -0700197/**
198 * Tests peeking and then reading the same amount. The two should provide the
199 * same results.
scroggod61c3842015-12-07 11:37:13 -0800200 * Returns the amount successfully read minus the amount successfully peeked.
scroggo028a4132015-04-02 13:19:51 -0700201 */
scroggod61c3842015-12-07 11:37:13 -0800202static size_t compare_peek_to_read(skiatest::Reporter* reporter,
203 SkStream* stream, size_t bytesToPeek) {
scroggo028a4132015-04-02 13:19:51 -0700204 // The rest of our tests won't be very interesting if bytesToPeek is zero.
205 REPORTER_ASSERT(reporter, bytesToPeek > 0);
206 SkAutoMalloc peekStorage(bytesToPeek);
207 SkAutoMalloc readStorage(bytesToPeek);
208 void* peekPtr = peekStorage.get();
209 void* readPtr = peekStorage.get();
210
scroggod61c3842015-12-07 11:37:13 -0800211 const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek);
scroggo028a4132015-04-02 13:19:51 -0700212 const size_t bytesRead = stream->read(readPtr, bytesToPeek);
213
214 // bytesRead should only be less than attempted if the stream is at the
215 // end.
216 REPORTER_ASSERT(reporter, bytesRead == bytesToPeek || stream->isAtEnd());
217
218 // peek and read should behave the same, except peek returned to the
219 // original position, so they read the same data.
scroggod61c3842015-12-07 11:37:13 -0800220 REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked));
scroggo028a4132015-04-02 13:19:51 -0700221
scroggod61c3842015-12-07 11:37:13 -0800222 // A stream should never be able to peek more than it can read.
223 REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked);
224
225 return bytesRead - bytesPeeked;
scroggo028a4132015-04-02 13:19:51 -0700226}
227
scroggod61c3842015-12-07 11:37:13 -0800228static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
scroggo028a4132015-04-02 13:19:51 -0700229 for (size_t i = 1; !stream->isAtEnd(); i++) {
scroggod61c3842015-12-07 11:37:13 -0800230 REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
scroggo028a4132015-04-02 13:19:51 -0700231 }
232}
233
234static void test_peeking_front_buffered_stream(skiatest::Reporter* r,
235 const SkStream& original,
236 size_t bufferSize) {
Mike Reed98c5d922017-09-15 21:39:47 -0400237 std::unique_ptr<SkStream> dupe(original.duplicate());
halcanary96fcdcc2015-08-27 07:41:13 -0700238 REPORTER_ASSERT(r, dupe != nullptr);
Mike Reed98c5d922017-09-15 21:39:47 -0400239 auto bufferedStream = SkFrontBufferedStream::Make(std::move(dupe), bufferSize);
halcanary96fcdcc2015-08-27 07:41:13 -0700240 REPORTER_ASSERT(r, bufferedStream != nullptr);
scroggod61c3842015-12-07 11:37:13 -0800241
242 size_t peeked = 0;
243 for (size_t i = 1; !bufferedStream->isAtEnd(); i++) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400244 const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i);
scroggod61c3842015-12-07 11:37:13 -0800245 if (unpeekableBytes > 0) {
246 // This could not have returned a number greater than i.
247 REPORTER_ASSERT(r, unpeekableBytes <= i);
248
249 // We have reached the end of the buffer. Verify that it was at least
250 // bufferSize.
251 REPORTER_ASSERT(r, peeked + i - unpeekableBytes >= bufferSize);
252 // No more peeking is supported.
253 break;
254 }
255 peeked += i;
256 }
257
258 // Test that attempting to peek beyond the length of the buffer does not prevent rewinding.
Mike Reed98c5d922017-09-15 21:39:47 -0400259 bufferedStream = SkFrontBufferedStream::Make(original.duplicate(), bufferSize);
scroggod61c3842015-12-07 11:37:13 -0800260 REPORTER_ASSERT(r, bufferedStream != nullptr);
261
262 const size_t bytesToPeek = bufferSize + 1;
263 SkAutoMalloc peekStorage(bytesToPeek);
264 SkAutoMalloc readStorage(bytesToPeek);
265
266 for (size_t start = 0; start <= bufferSize; start++) {
267 // Skip to the starting point
268 REPORTER_ASSERT(r, bufferedStream->skip(start) == start);
scroggod61c3842015-12-07 11:37:13 -0800269
270 const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek);
271 if (0 == bytesPeeked) {
scroggoef0fed32016-02-18 05:59:25 -0800272 // Peeking should only fail completely if we have read/skipped beyond the buffer.
273 REPORTER_ASSERT(r, start >= bufferSize);
scroggod61c3842015-12-07 11:37:13 -0800274 break;
275 }
276
277 // Only read the amount that was successfully peeked.
278 const size_t bytesRead = bufferedStream->read(readStorage.get(), bytesPeeked);
279 REPORTER_ASSERT(r, bytesRead == bytesPeeked);
280 REPORTER_ASSERT(r, !memcmp(peekStorage.get(), readStorage.get(), bytesPeeked));
281
282 // This should be safe to rewind.
283 REPORTER_ASSERT(r, bufferedStream->rewind());
284 }
scroggo028a4132015-04-02 13:19:51 -0700285}
286
halcanary9d524f22016-03-29 09:03:52 -0700287// This test uses file system operations that don't work out of the
288// box on iOS. It's likely that we don't need them on iOS. Ignoring for now.
289// TODO(stephana): Re-evaluate if we need this in the future.
scroggo028a4132015-04-02 13:19:51 -0700290DEF_TEST(StreamPeek, reporter) {
291 // Test a memory stream.
292 const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz";
293 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
scroggod61c3842015-12-07 11:37:13 -0800294 test_fully_peekable_stream(reporter, &memStream, memStream.getLength());
scroggo028a4132015-04-02 13:19:51 -0700295
296 // Test an arbitrary file stream. file streams do not support peeking.
Hal Canary925e31e2017-12-11 14:42:58 -0500297 auto tmpdir = skiatest::GetTmpDir();
298 if (tmpdir.isEmpty()) {
299 ERRORF(reporter, "no tmp dir!");
Hal Canarya4935102017-12-08 13:35:47 -0500300 return;
301 }
Hal Canary925e31e2017-12-11 14:42:58 -0500302 auto path = SkOSPath::Join(tmpdir.c_str(), "file");
303 {
304 SkFILEWStream wStream(path.c_str());
305 constexpr char filename[] = "images/baby_tux.webp";
306 auto data = GetResourceAsData(filename);
307 if (!data || data->size() == 0) {
308 ERRORF(reporter, "resource missing: %s\n", filename);
309 return;
310 }
311 if (!wStream.isValid() || !wStream.write(data->data(), data->size())) {
312 ERRORF(reporter, "error wrtiting to file %s", path.c_str());
313 return;
314 }
315 }
Hal Canarya4935102017-12-08 13:35:47 -0500316 SkFILEStream fileStream(path.c_str());
scroggo028a4132015-04-02 13:19:51 -0700317 REPORTER_ASSERT(reporter, fileStream.isValid());
caryclark30ac4642015-04-14 06:08:04 -0700318 if (!fileStream.isValid()) {
319 return;
320 }
scroggo028a4132015-04-02 13:19:51 -0700321 SkAutoMalloc storage(fileStream.getLength());
322 for (size_t i = 1; i < fileStream.getLength(); i++) {
scroggod61c3842015-12-07 11:37:13 -0800323 REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0);
scroggo028a4132015-04-02 13:19:51 -0700324 }
325
326 // Now test some FrontBufferedStreams
327 for (size_t i = 1; i < memStream.getLength(); i++) {
328 test_peeking_front_buffered_stream(reporter, memStream, i);
329 }
330}
halcanarye797d0d2015-05-21 08:13:27 -0700331#endif
332
333// Asserts that asset == expected and is peekable.
334static void stream_peek_test(skiatest::Reporter* rep,
335 SkStreamAsset* asset,
336 const SkData* expected) {
337 if (asset->getLength() != expected->size()) {
338 ERRORF(rep, "Unexpected length.");
339 return;
340 }
341 SkRandom rand;
342 uint8_t buffer[4096];
343 const uint8_t* expect = expected->bytes();
344 for (size_t i = 0; i < asset->getLength(); ++i) {
345 uint32_t maxSize =
346 SkToU32(SkTMin(sizeof(buffer), asset->getLength() - i));
347 size_t size = rand.nextRangeU(1, maxSize);
348 SkASSERT(size >= 1);
349 SkASSERT(size <= sizeof(buffer));
350 SkASSERT(size + i <= asset->getLength());
scroggod61c3842015-12-07 11:37:13 -0800351 if (asset->peek(buffer, size) < size) {
halcanarye797d0d2015-05-21 08:13:27 -0700352 ERRORF(rep, "Peek Failed!");
353 return;
354 }
355 if (0 != memcmp(buffer, &expect[i], size)) {
356 ERRORF(rep, "Peek returned wrong bytes!");
357 return;
358 }
359 uint8_t value;
360 REPORTER_ASSERT(rep, 1 == asset->read(&value, 1));
361 if (value != expect[i]) {
362 ERRORF(rep, "Read Failed!");
363 return;
364 }
365 }
366}
367
368DEF_TEST(StreamPeek_BlockMemoryStream, rep) {
369 const static int kSeed = 1234;
370 SkRandom valueSource(kSeed);
371 SkRandom rand(kSeed << 1);
372 uint8_t buffer[4096];
373 SkDynamicMemoryWStream dynamicMemoryWStream;
Mike Reed49282292016-12-14 12:34:06 -0500374 size_t totalWritten = 0;
halcanarye797d0d2015-05-21 08:13:27 -0700375 for (int i = 0; i < 32; ++i) {
376 // Randomize the length of the blocks.
377 size_t size = rand.nextRangeU(1, sizeof(buffer));
378 for (size_t j = 0; j < size; ++j) {
379 buffer[j] = valueSource.nextU() & 0xFF;
380 }
381 dynamicMemoryWStream.write(buffer, size);
Mike Reed49282292016-12-14 12:34:06 -0500382 totalWritten += size;
383 REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten());
halcanarye797d0d2015-05-21 08:13:27 -0700384 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400385 std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream());
bungeman38d909e2016-08-02 14:40:46 -0700386 sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength()));
halcanarye797d0d2015-05-21 08:13:27 -0700387 uint8_t* expectedPtr = static_cast<uint8_t*>(expected->writable_data());
388 valueSource.setSeed(kSeed); // reseed.
389 // We want the exact same same "random" string of numbers to put
390 // in expected. i.e.: don't rely on SkDynamicMemoryStream to work
391 // correctly while we are testing SkDynamicMemoryStream.
392 for (size_t i = 0; i < asset->getLength(); ++i) {
393 expectedPtr[i] = valueSource.nextU() & 0xFF;
394 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400395 stream_peek_test(rep, asset.get(), expected.get());
halcanarye797d0d2015-05-21 08:13:27 -0700396}
halcanary48305e82015-08-18 13:30:25 -0700397
398namespace {
399class DumbStream : public SkStream {
400public:
401 DumbStream(const uint8_t* data, size_t n)
402 : fData(data), fCount(n), fIdx(0) {}
403 size_t read(void* buffer, size_t size) override {
halcanaryd75e21d2015-08-19 07:22:04 -0700404 size_t copyCount = SkTMin(fCount - fIdx, size);
405 if (copyCount) {
406 memcpy(buffer, &fData[fIdx], copyCount);
407 fIdx += copyCount;
halcanary48305e82015-08-18 13:30:25 -0700408 }
halcanaryd75e21d2015-08-19 07:22:04 -0700409 return copyCount;
halcanary48305e82015-08-18 13:30:25 -0700410 }
411 bool isAtEnd() const override {
halcanaryd75e21d2015-08-19 07:22:04 -0700412 return fCount == fIdx;
halcanary48305e82015-08-18 13:30:25 -0700413 }
414 private:
415 const uint8_t* fData;
416 size_t fCount, fIdx;
417};
418} // namespace
419
420static void stream_copy_test(skiatest::Reporter* reporter,
421 const void* srcData,
422 size_t N,
423 SkStream* stream) {
424 SkDynamicMemoryWStream tgt;
425 if (!SkStreamCopy(&tgt, stream)) {
426 ERRORF(reporter, "SkStreamCopy failed");
427 return;
428 }
reed42943c82016-09-12 12:01:44 -0700429 sk_sp<SkData> data(tgt.detachAsData());
halcanary48305e82015-08-18 13:30:25 -0700430 if (data->size() != N) {
431 ERRORF(reporter, "SkStreamCopy incorrect size");
432 return;
433 }
434 if (0 != memcmp(data->data(), srcData, N)) {
435 ERRORF(reporter, "SkStreamCopy bad copy");
436 }
437}
438
Hal Canarydabe8ac2017-03-14 15:52:12 -0400439DEF_TEST(DynamicMemoryWStream_detachAsData, r) {
440 const char az[] = "abcdefghijklmnopqrstuvwxyz";
441 const unsigned N = 40000;
442 SkDynamicMemoryWStream dmws;
443 for (unsigned i = 0; i < N; ++i) {
444 dmws.writeText(az);
445 }
446 REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az));
447 auto data = dmws.detachAsData();
448 REPORTER_ASSERT(r, data->size() == N * strlen(az));
449 const uint8_t* ptr = data->bytes();
450 for (unsigned i = 0; i < N; ++i) {
451 if (0 != memcmp(ptr, az, strlen(az))) {
452 ERRORF(r, "detachAsData() memcmp failed");
453 return;
454 }
455 ptr += strlen(az);
456 }
457}
458
halcanary48305e82015-08-18 13:30:25 -0700459DEF_TEST(StreamCopy, reporter) {
460 SkRandom random(123456);
halcanarycb9241b2015-08-19 06:12:40 -0700461 static const int N = 10000;
462 SkAutoTMalloc<uint8_t> src((size_t)N);
463 for (int j = 0; j < N; ++j) {
halcanary48305e82015-08-18 13:30:25 -0700464 src[j] = random.nextU() & 0xff;
465 }
466 // SkStreamCopy had two code paths; this test both.
halcanarycb9241b2015-08-19 06:12:40 -0700467 DumbStream dumbStream(src.get(), (size_t)N);
halcanary48305e82015-08-18 13:30:25 -0700468 stream_copy_test(reporter, src, N, &dumbStream);
halcanarycb9241b2015-08-19 06:12:40 -0700469 SkMemoryStream smartStream(src.get(), (size_t)N);
halcanary48305e82015-08-18 13:30:25 -0700470 stream_copy_test(reporter, src, N, &smartStream);
halcanary48305e82015-08-18 13:30:25 -0700471}
halcanary209c1622015-09-28 07:29:39 -0700472
473DEF_TEST(StreamEmptyStreamMemoryBase, r) {
474 SkDynamicMemoryWStream tmp;
Ben Wagner145dbcd2016-11-03 14:40:50 -0400475 std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream());
halcanary209c1622015-09-28 07:29:39 -0700476 REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
477}
Mike Reed1026ccf2017-01-08 14:35:29 -0500478
Leon Scroggins III8a8a1442018-05-08 09:35:32 -0400479DEF_TEST(FILEStreamWithOffset, r) {
480 if (GetResourcePath().isEmpty()) {
481 return;
482 }
483
484 SkString filename = GetResourcePath("images/baby_tux.png");
485 SkFILEStream stream1(filename.c_str());
486 if (!stream1.isValid()) {
487 ERRORF(r, "Could not create SkFILEStream from %s", filename.c_str());
488 return;
489 }
490 REPORTER_ASSERT(r, stream1.hasLength());
491 REPORTER_ASSERT(r, stream1.hasPosition());
492
493 // Seek halfway through the file. The second SkFILEStream will be created
494 // with the same filename and offset and therefore will treat that offset as
495 // the beginning.
496 const size_t size = stream1.getLength();
497 const size_t middle = size / 2;
498 if (!stream1.seek(middle)) {
499 ERRORF(r, "Could not seek SkFILEStream to %lu out of %lu", middle, size);
500 return;
501 }
502 REPORTER_ASSERT(r, stream1.getPosition() == middle);
503
504 FILE* file = sk_fopen(filename.c_str(), kRead_SkFILE_Flag);
505 if (!file) {
506 ERRORF(r, "Could not open %s as a FILE", filename.c_str());
507 return;
508 }
509
510 if (fseek(file, (long) middle, SEEK_SET) != 0) {
511 ERRORF(r, "Could not fseek FILE to %lu out of %lu", middle, size);
512 return;
513 }
514 SkFILEStream stream2(file);
515
516 const size_t remaining = size - middle;
517 SkAutoTMalloc<uint8_t> expected(remaining);
518 REPORTER_ASSERT(r, stream1.read(expected.get(), remaining) == remaining);
519
520 auto test_full_read = [&r, &expected, remaining](SkStream* stream) {
521 SkAutoTMalloc<uint8_t> actual(remaining);
522 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
523 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
524
525 REPORTER_ASSERT(r, stream->getPosition() == stream->getLength());
526 REPORTER_ASSERT(r, stream->isAtEnd());
527 };
528
529 auto test_rewind = [&r, &expected, remaining](SkStream* stream) {
530 // Rewind goes back to original offset.
531 REPORTER_ASSERT(r, stream->rewind());
532 REPORTER_ASSERT(r, stream->getPosition() == 0);
533 SkAutoTMalloc<uint8_t> actual(remaining);
534 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
535 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
536 };
537
538 auto test_move = [&r, &expected, size, remaining](SkStream* stream) {
539 // Cannot move to before the original offset.
540 REPORTER_ASSERT(r, stream->move(- (long) size));
541 REPORTER_ASSERT(r, stream->getPosition() == 0);
542
543 REPORTER_ASSERT(r, stream->move(std::numeric_limits<long>::min()));
544 REPORTER_ASSERT(r, stream->getPosition() == 0);
545
546 SkAutoTMalloc<uint8_t> actual(remaining);
547 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
548 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
549
550 REPORTER_ASSERT(r, stream->isAtEnd());
551 REPORTER_ASSERT(r, stream->getPosition() == remaining);
552
553 // Cannot move beyond the end.
554 REPORTER_ASSERT(r, stream->move(1));
555 REPORTER_ASSERT(r, stream->isAtEnd());
556 REPORTER_ASSERT(r, stream->getPosition() == remaining);
557 };
558
559 auto test_seek = [&r, &expected, middle, remaining](SkStream* stream) {
560 // Seek to an arbitrary position.
561 const size_t arbitrary = middle / 2;
562 REPORTER_ASSERT(r, stream->seek(arbitrary));
563 REPORTER_ASSERT(r, stream->getPosition() == arbitrary);
564 const size_t miniRemaining = remaining - arbitrary;
565 SkAutoTMalloc<uint8_t> actual(miniRemaining);
566 REPORTER_ASSERT(r, stream->read(actual.get(), miniRemaining) == miniRemaining);
567 REPORTER_ASSERT(r, !memcmp(expected.get() + arbitrary, actual.get(), miniRemaining));
568 };
569
570 auto test_seek_beginning = [&r, &expected, remaining](SkStream* stream) {
571 // Seek to the beginning.
572 REPORTER_ASSERT(r, stream->seek(0));
573 REPORTER_ASSERT(r, stream->getPosition() == 0);
574 SkAutoTMalloc<uint8_t> actual(remaining);
575 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
576 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
577 };
578
579 auto test_seek_end = [&r, remaining](SkStream* stream) {
580 // Cannot seek past the end.
581 REPORTER_ASSERT(r, stream->isAtEnd());
582
583 REPORTER_ASSERT(r, stream->seek(remaining + 1));
584 REPORTER_ASSERT(r, stream->isAtEnd());
585 REPORTER_ASSERT(r, stream->getPosition() == remaining);
586
587 const size_t middle = remaining / 2;
588 REPORTER_ASSERT(r, stream->seek(middle));
589 REPORTER_ASSERT(r, !stream->isAtEnd());
590 REPORTER_ASSERT(r, stream->getPosition() == middle);
591
592 REPORTER_ASSERT(r, stream->seek(remaining * 2));
593 REPORTER_ASSERT(r, stream->isAtEnd());
594 REPORTER_ASSERT(r, stream->getPosition() == remaining);
595
596 REPORTER_ASSERT(r, stream->seek(std::numeric_limits<long>::max()));
597 REPORTER_ASSERT(r, stream->isAtEnd());
598 REPORTER_ASSERT(r, stream->getPosition() == remaining);
599 };
600
601
602 std::function<void (SkStream* stream, bool recurse)> test_all;
603 test_all = [&](SkStream* stream, bool recurse) {
604 REPORTER_ASSERT(r, stream->getLength() == remaining);
605 REPORTER_ASSERT(r, stream->getPosition() == 0);
606
607 test_full_read(stream);
608 test_rewind(stream);
609 test_move(stream);
610 test_seek(stream);
611 test_seek_beginning(stream);
612 test_seek_end(stream);
613
614 if (recurse) {
615 // Duplicate shares the original offset.
616 auto duplicate = stream->duplicate();
617 if (!duplicate) {
618 ERRORF(r, "Failed to duplicate the stream!");
619 } else {
620 test_all(duplicate.get(), false);
621 }
622
623 // Fork shares the original offset, too.
624 auto fork = stream->fork();
625 if (!fork) {
626 ERRORF(r, "Failed to fork the stream!");
627 } else {
628 REPORTER_ASSERT(r, fork->isAtEnd());
629 REPORTER_ASSERT(r, fork->getLength() == remaining);
630 REPORTER_ASSERT(r, fork->rewind());
631
632 test_all(fork.get(), false);
633 }
634 }
635 };
636
637 test_all(&stream2, true);
638}
639
Mike Kleinc0bd9f92019-04-23 12:05:21 -0500640#include "src/core/SkBuffer.h"
Mike Reed1026ccf2017-01-08 14:35:29 -0500641
642DEF_TEST(RBuffer, reporter) {
643 int32_t value = 0;
644 SkRBuffer buffer(&value, 4);
645 REPORTER_ASSERT(reporter, buffer.isValid());
646
647 int32_t tmp;
648 REPORTER_ASSERT(reporter, buffer.read(&tmp, 4));
649 REPORTER_ASSERT(reporter, buffer.isValid());
650
651 REPORTER_ASSERT(reporter, !buffer.read(&tmp, 4));
652 REPORTER_ASSERT(reporter, !buffer.isValid());
653}