blob: 7cf8d92bc5b3d20d4213c19ed0ff670352896789 [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
scroggo028a4132015-04-02 13:19:51 -07008#include "Resources.h"
Hal Canary95e3c052017-01-11 12:44:43 -05009#include "SkAutoMalloc.h"
reed@google.com8d0b5772011-06-24 13:07:31 +000010#include "SkData.h"
scroggo028a4132015-04-02 13:19:51 -070011#include "SkFrontBufferedStream.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000012#include "SkOSFile.h"
Ben Wagnerbf111d72016-11-07 18:05:29 -050013#include "SkOSPath.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000014#include "SkRandom.h"
15#include "SkStream.h"
halcanary48305e82015-08-18 13:30:25 -070016#include "SkStreamPriv.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000017#include "Test.h"
reed@android.com5e5adfd2009-03-07 03:39:23 +000018
Leon Scroggins III8a8a1442018-05-08 09:35:32 -040019#include <functional>
20#include <limits>
21
reed@google.com789c6f22013-02-25 20:24:24 +000022#ifndef SK_BUILD_FOR_WIN
23#include <unistd.h>
24#include <fcntl.h>
25#endif
26
reed@android.com5e5adfd2009-03-07 03:39:23 +000027#define MAX_SIZE (256 * 1024)
28
reed@google.com789c6f22013-02-25 20:24:24 +000029static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream,
30 const void* src, size_t len, int repeat) {
31 SkAutoSMalloc<256> storage(len);
32 void* tmp = storage.get();
33
34 for (int i = 0; i < repeat; ++i) {
35 size_t bytes = stream->read(tmp, len);
36 REPORTER_ASSERT(reporter, bytes == len);
37 REPORTER_ASSERT(reporter, !memcmp(tmp, src, len));
38 }
39
40 // expect EOF
41 size_t bytes = stream->read(tmp, 1);
42 REPORTER_ASSERT(reporter, 0 == bytes);
bungeman@google.com88682b72013-07-19 13:55:41 +000043 // isAtEnd might not return true until after the first failing read.
44 REPORTER_ASSERT(reporter, stream->isAtEnd());
reed@google.com789c6f22013-02-25 20:24:24 +000045}
46
47static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
tfarinaa8e2e152014-07-28 19:26:58 -070048 SkString path = SkOSPath::Join(tmpDir, "wstream_test");
reed@google.com789c6f22013-02-25 20:24:24 +000049
50 const char s[] = "abcdefghijklmnopqrstuvwxyz";
51
52 {
53 SkFILEWStream writer(path.c_str());
54 if (!writer.isValid()) {
halcanary@google.coma9325fa2014-01-10 14:58:10 +000055 ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +000056 return;
57 }
58
59 for (int i = 0; i < 100; ++i) {
60 writer.write(s, 26);
61 }
62 }
63
64 {
65 SkFILEStream stream(path.c_str());
66 REPORTER_ASSERT(reporter, stream.isValid());
67 test_loop_stream(reporter, &stream, s, 26, 100);
bungeman@google.com6cab1a42013-05-29 13:43:31 +000068
Ben Wagner145dbcd2016-11-03 14:40:50 -040069 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +000070 test_loop_stream(reporter, stream2.get(), s, 26, 100);
reed@google.com789c6f22013-02-25 20:24:24 +000071 }
72
reed@google.com789c6f22013-02-25 20:24:24 +000073 {
bungeman@google.com6cab1a42013-05-29 13:43:31 +000074 FILE* file = ::fopen(path.c_str(), "rb");
Ben Wagner4d1955c2017-03-10 13:08:15 -050075 SkFILEStream stream(file);
reed@google.com789c6f22013-02-25 20:24:24 +000076 REPORTER_ASSERT(reporter, stream.isValid());
77 test_loop_stream(reporter, &stream, s, 26, 100);
bungeman@google.com6cab1a42013-05-29 13:43:31 +000078
Ben Wagner145dbcd2016-11-03 14:40:50 -040079 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
bungeman@google.com6cab1a42013-05-29 13:43:31 +000080 test_loop_stream(reporter, stream2.get(), s, 26, 100);
reed@google.com789c6f22013-02-25 20:24:24 +000081 }
reed@google.com789c6f22013-02-25 20:24:24 +000082}
83
reed@android.com80e39a72009-04-02 16:59:40 +000084static void TestWStream(skiatest::Reporter* reporter) {
85 SkDynamicMemoryWStream ds;
86 const char s[] = "abcdefghijklmnopqrstuvwxyz";
87 int i;
88 for (i = 0; i < 100; i++) {
89 REPORTER_ASSERT(reporter, ds.write(s, 26));
reed@android.com5e5adfd2009-03-07 03:39:23 +000090 }
Ben Wagner884300d2016-12-16 16:51:41 +000091 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
bungeman@google.com88682b72013-07-19 13:55:41 +000092
reed@android.com80e39a72009-04-02 16:59:40 +000093 char* dst = new char[100 * 26 + 1];
94 dst[100*26] = '*';
95 ds.copyTo(dst);
96 REPORTER_ASSERT(reporter, dst[100*26] == '*');
reed@android.com80e39a72009-04-02 16:59:40 +000097 for (i = 0; i < 100; i++) {
98 REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
reed@android.com5e5adfd2009-03-07 03:39:23 +000099 }
reed@google.com70442a62011-06-23 21:48:04 +0000100
101 {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400102 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
bungeman@google.com88682b72013-07-19 13:55:41 +0000103 REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
Ben Wagner884300d2016-12-16 16:51:41 +0000104 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
bungeman@google.com88682b72013-07-19 13:55:41 +0000105 test_loop_stream(reporter, stream.get(), s, 26, 100);
106
Ben Wagner145dbcd2016-11-03 14:40:50 -0400107 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
bungeman@google.com88682b72013-07-19 13:55:41 +0000108 test_loop_stream(reporter, stream2.get(), s, 26, 100);
109
Ben Wagner145dbcd2016-11-03 14:40:50 -0400110 std::unique_ptr<SkStreamAsset> stream3(stream->fork());
bungeman@google.com88682b72013-07-19 13:55:41 +0000111 REPORTER_ASSERT(reporter, stream3->isAtEnd());
112 char tmp;
113 size_t bytes = stream->read(&tmp, 1);
114 REPORTER_ASSERT(reporter, 0 == bytes);
115 stream3->rewind();
116 test_loop_stream(reporter, stream3.get(), s, 26, 100);
117 }
118
119 for (i = 0; i < 100; i++) {
120 REPORTER_ASSERT(reporter, ds.write(s, 26));
121 }
Ben Wagner884300d2016-12-16 16:51:41 +0000122 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
bungeman@google.com88682b72013-07-19 13:55:41 +0000123
124 {
reed42943c82016-09-12 12:01:44 -0700125 // Test that this works after a snapshot.
Ben Wagner145dbcd2016-11-03 14:40:50 -0400126 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
Ben Wagner884300d2016-12-16 16:51:41 +0000127 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
bungeman@google.com88682b72013-07-19 13:55:41 +0000128 test_loop_stream(reporter, stream.get(), s, 26, 100);
129
Ben Wagner145dbcd2016-11-03 14:40:50 -0400130 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
bungeman@google.com88682b72013-07-19 13:55:41 +0000131 test_loop_stream(reporter, stream2.get(), s, 26, 100);
reed@google.com70442a62011-06-23 21:48:04 +0000132 }
reed@android.com80e39a72009-04-02 16:59:40 +0000133 delete[] dst;
reed@google.com789c6f22013-02-25 20:24:24 +0000134
halcanary87f3ba42015-01-20 09:30:20 -0800135 SkString tmpDir = skiatest::GetTmpDir();
scroggo@google.comc76218d2013-06-06 14:59:56 +0000136 if (!tmpDir.isEmpty()) {
137 test_filestreams(reporter, tmpDir.c_str());
reed@google.com789c6f22013-02-25 20:24:24 +0000138 }
reed@android.com5e5adfd2009-03-07 03:39:23 +0000139}
140
reed@google.com19f286b2011-10-18 11:49:52 +0000141static void TestPackedUInt(skiatest::Reporter* reporter) {
142 // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
143 // so we test values around each of those transitions (and a few others)
144 const size_t sizes[] = {
145 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
146 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
147 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
148 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
149 };
rmistry@google.comd6176b02012-08-23 18:14:13 +0000150
151
reed@google.com19f286b2011-10-18 11:49:52 +0000152 size_t i;
Mike Reedff80c2a2017-01-07 11:16:28 -0500153 SkDynamicMemoryWStream wstream;
rmistry@google.comd6176b02012-08-23 18:14:13 +0000154
reed@google.com19f286b2011-10-18 11:49:52 +0000155 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
156 bool success = wstream.writePackedUInt(sizes[i]);
157 REPORTER_ASSERT(reporter, success);
158 }
rmistry@google.comd6176b02012-08-23 18:14:13 +0000159
Mike Reedff80c2a2017-01-07 11:16:28 -0500160 std::unique_ptr<SkStreamAsset> rstream(wstream.detachAsStream());
reed@google.com19f286b2011-10-18 11:49:52 +0000161 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
Ben Wagner255ab8d2016-10-07 15:50:53 -0400162 size_t n;
163 if (!rstream->readPackedUInt(&n)) {
164 ERRORF(reporter, "[%d] sizes:%x could not be read\n", i, sizes[i]);
165 }
reed@google.com19f286b2011-10-18 11:49:52 +0000166 if (sizes[i] != n) {
Ben Wagner255ab8d2016-10-07 15:50:53 -0400167 ERRORF(reporter, "[%d] sizes:%x != n:%x\n", i, sizes[i], n);
reed@google.com19f286b2011-10-18 11:49:52 +0000168 }
reed@google.com19f286b2011-10-18 11:49:52 +0000169 }
170}
171
halcanary96fcdcc2015-08-27 07:41:13 -0700172// 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 +0000173// methods that access fData.
174static void TestDereferencingData(SkMemoryStream* memStream) {
halcanary96fcdcc2015-08-27 07:41:13 -0700175 memStream->read(nullptr, 0);
scroggo@google.come4904202013-01-09 22:02:58 +0000176 memStream->getMemoryBase();
reed42943c82016-09-12 12:01:44 -0700177 (void)memStream->asData();
scroggo@google.come4904202013-01-09 22:02:58 +0000178}
179
180static void TestNullData() {
reed42943c82016-09-12 12:01:44 -0700181 SkMemoryStream memStream(nullptr);
scroggo@google.come4904202013-01-09 22:02:58 +0000182 TestDereferencingData(&memStream);
183
reed42943c82016-09-12 12:01:44 -0700184 memStream.setData(nullptr);
scroggo@google.come4904202013-01-09 22:02:58 +0000185 TestDereferencingData(&memStream);
186
187}
188
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000189DEF_TEST(Stream, reporter) {
reed@android.com5e5adfd2009-03-07 03:39:23 +0000190 TestWStream(reporter);
reed@google.com19f286b2011-10-18 11:49:52 +0000191 TestPackedUInt(reporter);
scroggo@google.come4904202013-01-09 22:02:58 +0000192 TestNullData();
reed@android.com5e5adfd2009-03-07 03:39:23 +0000193}
scroggo028a4132015-04-02 13:19:51 -0700194
Mike Klein7d302882016-11-03 14:06:31 -0400195#ifndef SK_BUILD_FOR_IOS
scroggo028a4132015-04-02 13:19:51 -0700196/**
197 * Tests peeking and then reading the same amount. The two should provide the
198 * same results.
scroggod61c3842015-12-07 11:37:13 -0800199 * Returns the amount successfully read minus the amount successfully peeked.
scroggo028a4132015-04-02 13:19:51 -0700200 */
scroggod61c3842015-12-07 11:37:13 -0800201static size_t compare_peek_to_read(skiatest::Reporter* reporter,
202 SkStream* stream, size_t bytesToPeek) {
scroggo028a4132015-04-02 13:19:51 -0700203 // The rest of our tests won't be very interesting if bytesToPeek is zero.
204 REPORTER_ASSERT(reporter, bytesToPeek > 0);
205 SkAutoMalloc peekStorage(bytesToPeek);
206 SkAutoMalloc readStorage(bytesToPeek);
207 void* peekPtr = peekStorage.get();
208 void* readPtr = peekStorage.get();
209
scroggod61c3842015-12-07 11:37:13 -0800210 const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek);
scroggo028a4132015-04-02 13:19:51 -0700211 const size_t bytesRead = stream->read(readPtr, bytesToPeek);
212
213 // bytesRead should only be less than attempted if the stream is at the
214 // end.
215 REPORTER_ASSERT(reporter, bytesRead == bytesToPeek || stream->isAtEnd());
216
217 // peek and read should behave the same, except peek returned to the
218 // original position, so they read the same data.
scroggod61c3842015-12-07 11:37:13 -0800219 REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked));
scroggo028a4132015-04-02 13:19:51 -0700220
scroggod61c3842015-12-07 11:37:13 -0800221 // A stream should never be able to peek more than it can read.
222 REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked);
223
224 return bytesRead - bytesPeeked;
scroggo028a4132015-04-02 13:19:51 -0700225}
226
scroggod61c3842015-12-07 11:37:13 -0800227static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
scroggo028a4132015-04-02 13:19:51 -0700228 for (size_t i = 1; !stream->isAtEnd(); i++) {
scroggod61c3842015-12-07 11:37:13 -0800229 REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
scroggo028a4132015-04-02 13:19:51 -0700230 }
231}
232
233static void test_peeking_front_buffered_stream(skiatest::Reporter* r,
234 const SkStream& original,
235 size_t bufferSize) {
Mike Reed98c5d922017-09-15 21:39:47 -0400236 std::unique_ptr<SkStream> dupe(original.duplicate());
halcanary96fcdcc2015-08-27 07:41:13 -0700237 REPORTER_ASSERT(r, dupe != nullptr);
Mike Reed98c5d922017-09-15 21:39:47 -0400238 auto bufferedStream = SkFrontBufferedStream::Make(std::move(dupe), bufferSize);
halcanary96fcdcc2015-08-27 07:41:13 -0700239 REPORTER_ASSERT(r, bufferedStream != nullptr);
scroggod61c3842015-12-07 11:37:13 -0800240
241 size_t peeked = 0;
242 for (size_t i = 1; !bufferedStream->isAtEnd(); i++) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400243 const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i);
scroggod61c3842015-12-07 11:37:13 -0800244 if (unpeekableBytes > 0) {
245 // This could not have returned a number greater than i.
246 REPORTER_ASSERT(r, unpeekableBytes <= i);
247
248 // We have reached the end of the buffer. Verify that it was at least
249 // bufferSize.
250 REPORTER_ASSERT(r, peeked + i - unpeekableBytes >= bufferSize);
251 // No more peeking is supported.
252 break;
253 }
254 peeked += i;
255 }
256
257 // Test that attempting to peek beyond the length of the buffer does not prevent rewinding.
Mike Reed98c5d922017-09-15 21:39:47 -0400258 bufferedStream = SkFrontBufferedStream::Make(original.duplicate(), bufferSize);
scroggod61c3842015-12-07 11:37:13 -0800259 REPORTER_ASSERT(r, bufferedStream != nullptr);
260
261 const size_t bytesToPeek = bufferSize + 1;
262 SkAutoMalloc peekStorage(bytesToPeek);
263 SkAutoMalloc readStorage(bytesToPeek);
264
265 for (size_t start = 0; start <= bufferSize; start++) {
266 // Skip to the starting point
267 REPORTER_ASSERT(r, bufferedStream->skip(start) == start);
scroggod61c3842015-12-07 11:37:13 -0800268
269 const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek);
270 if (0 == bytesPeeked) {
scroggoef0fed32016-02-18 05:59:25 -0800271 // Peeking should only fail completely if we have read/skipped beyond the buffer.
272 REPORTER_ASSERT(r, start >= bufferSize);
scroggod61c3842015-12-07 11:37:13 -0800273 break;
274 }
275
276 // Only read the amount that was successfully peeked.
277 const size_t bytesRead = bufferedStream->read(readStorage.get(), bytesPeeked);
278 REPORTER_ASSERT(r, bytesRead == bytesPeeked);
279 REPORTER_ASSERT(r, !memcmp(peekStorage.get(), readStorage.get(), bytesPeeked));
280
281 // This should be safe to rewind.
282 REPORTER_ASSERT(r, bufferedStream->rewind());
283 }
scroggo028a4132015-04-02 13:19:51 -0700284}
285
halcanary9d524f22016-03-29 09:03:52 -0700286// This test uses file system operations that don't work out of the
287// box on iOS. It's likely that we don't need them on iOS. Ignoring for now.
288// TODO(stephana): Re-evaluate if we need this in the future.
scroggo028a4132015-04-02 13:19:51 -0700289DEF_TEST(StreamPeek, reporter) {
290 // Test a memory stream.
291 const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz";
292 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
scroggod61c3842015-12-07 11:37:13 -0800293 test_fully_peekable_stream(reporter, &memStream, memStream.getLength());
scroggo028a4132015-04-02 13:19:51 -0700294
295 // Test an arbitrary file stream. file streams do not support peeking.
Hal Canary925e31e2017-12-11 14:42:58 -0500296 auto tmpdir = skiatest::GetTmpDir();
297 if (tmpdir.isEmpty()) {
298 ERRORF(reporter, "no tmp dir!");
Hal Canarya4935102017-12-08 13:35:47 -0500299 return;
300 }
Hal Canary925e31e2017-12-11 14:42:58 -0500301 auto path = SkOSPath::Join(tmpdir.c_str(), "file");
302 {
303 SkFILEWStream wStream(path.c_str());
304 constexpr char filename[] = "images/baby_tux.webp";
305 auto data = GetResourceAsData(filename);
306 if (!data || data->size() == 0) {
307 ERRORF(reporter, "resource missing: %s\n", filename);
308 return;
309 }
310 if (!wStream.isValid() || !wStream.write(data->data(), data->size())) {
311 ERRORF(reporter, "error wrtiting to file %s", path.c_str());
312 return;
313 }
314 }
Hal Canarya4935102017-12-08 13:35:47 -0500315 SkFILEStream fileStream(path.c_str());
scroggo028a4132015-04-02 13:19:51 -0700316 REPORTER_ASSERT(reporter, fileStream.isValid());
caryclark30ac4642015-04-14 06:08:04 -0700317 if (!fileStream.isValid()) {
318 return;
319 }
scroggo028a4132015-04-02 13:19:51 -0700320 SkAutoMalloc storage(fileStream.getLength());
321 for (size_t i = 1; i < fileStream.getLength(); i++) {
scroggod61c3842015-12-07 11:37:13 -0800322 REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0);
scroggo028a4132015-04-02 13:19:51 -0700323 }
324
325 // Now test some FrontBufferedStreams
326 for (size_t i = 1; i < memStream.getLength(); i++) {
327 test_peeking_front_buffered_stream(reporter, memStream, i);
328 }
329}
halcanarye797d0d2015-05-21 08:13:27 -0700330#endif
331
332// Asserts that asset == expected and is peekable.
333static void stream_peek_test(skiatest::Reporter* rep,
334 SkStreamAsset* asset,
335 const SkData* expected) {
336 if (asset->getLength() != expected->size()) {
337 ERRORF(rep, "Unexpected length.");
338 return;
339 }
340 SkRandom rand;
341 uint8_t buffer[4096];
342 const uint8_t* expect = expected->bytes();
343 for (size_t i = 0; i < asset->getLength(); ++i) {
344 uint32_t maxSize =
345 SkToU32(SkTMin(sizeof(buffer), asset->getLength() - i));
346 size_t size = rand.nextRangeU(1, maxSize);
347 SkASSERT(size >= 1);
348 SkASSERT(size <= sizeof(buffer));
349 SkASSERT(size + i <= asset->getLength());
scroggod61c3842015-12-07 11:37:13 -0800350 if (asset->peek(buffer, size) < size) {
halcanarye797d0d2015-05-21 08:13:27 -0700351 ERRORF(rep, "Peek Failed!");
352 return;
353 }
354 if (0 != memcmp(buffer, &expect[i], size)) {
355 ERRORF(rep, "Peek returned wrong bytes!");
356 return;
357 }
358 uint8_t value;
359 REPORTER_ASSERT(rep, 1 == asset->read(&value, 1));
360 if (value != expect[i]) {
361 ERRORF(rep, "Read Failed!");
362 return;
363 }
364 }
365}
366
367DEF_TEST(StreamPeek_BlockMemoryStream, rep) {
368 const static int kSeed = 1234;
369 SkRandom valueSource(kSeed);
370 SkRandom rand(kSeed << 1);
371 uint8_t buffer[4096];
372 SkDynamicMemoryWStream dynamicMemoryWStream;
Mike Reed49282292016-12-14 12:34:06 -0500373 size_t totalWritten = 0;
halcanarye797d0d2015-05-21 08:13:27 -0700374 for (int i = 0; i < 32; ++i) {
375 // Randomize the length of the blocks.
376 size_t size = rand.nextRangeU(1, sizeof(buffer));
377 for (size_t j = 0; j < size; ++j) {
378 buffer[j] = valueSource.nextU() & 0xFF;
379 }
380 dynamicMemoryWStream.write(buffer, size);
Mike Reed49282292016-12-14 12:34:06 -0500381 totalWritten += size;
382 REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten());
halcanarye797d0d2015-05-21 08:13:27 -0700383 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400384 std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream());
bungeman38d909e2016-08-02 14:40:46 -0700385 sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength()));
halcanarye797d0d2015-05-21 08:13:27 -0700386 uint8_t* expectedPtr = static_cast<uint8_t*>(expected->writable_data());
387 valueSource.setSeed(kSeed); // reseed.
388 // We want the exact same same "random" string of numbers to put
389 // in expected. i.e.: don't rely on SkDynamicMemoryStream to work
390 // correctly while we are testing SkDynamicMemoryStream.
391 for (size_t i = 0; i < asset->getLength(); ++i) {
392 expectedPtr[i] = valueSource.nextU() & 0xFF;
393 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400394 stream_peek_test(rep, asset.get(), expected.get());
halcanarye797d0d2015-05-21 08:13:27 -0700395}
halcanary48305e82015-08-18 13:30:25 -0700396
397namespace {
398class DumbStream : public SkStream {
399public:
400 DumbStream(const uint8_t* data, size_t n)
401 : fData(data), fCount(n), fIdx(0) {}
402 size_t read(void* buffer, size_t size) override {
halcanaryd75e21d2015-08-19 07:22:04 -0700403 size_t copyCount = SkTMin(fCount - fIdx, size);
404 if (copyCount) {
405 memcpy(buffer, &fData[fIdx], copyCount);
406 fIdx += copyCount;
halcanary48305e82015-08-18 13:30:25 -0700407 }
halcanaryd75e21d2015-08-19 07:22:04 -0700408 return copyCount;
halcanary48305e82015-08-18 13:30:25 -0700409 }
410 bool isAtEnd() const override {
halcanaryd75e21d2015-08-19 07:22:04 -0700411 return fCount == fIdx;
halcanary48305e82015-08-18 13:30:25 -0700412 }
413 private:
414 const uint8_t* fData;
415 size_t fCount, fIdx;
416};
417} // namespace
418
419static void stream_copy_test(skiatest::Reporter* reporter,
420 const void* srcData,
421 size_t N,
422 SkStream* stream) {
423 SkDynamicMemoryWStream tgt;
424 if (!SkStreamCopy(&tgt, stream)) {
425 ERRORF(reporter, "SkStreamCopy failed");
426 return;
427 }
reed42943c82016-09-12 12:01:44 -0700428 sk_sp<SkData> data(tgt.detachAsData());
halcanary48305e82015-08-18 13:30:25 -0700429 if (data->size() != N) {
430 ERRORF(reporter, "SkStreamCopy incorrect size");
431 return;
432 }
433 if (0 != memcmp(data->data(), srcData, N)) {
434 ERRORF(reporter, "SkStreamCopy bad copy");
435 }
436}
437
Hal Canarydabe8ac2017-03-14 15:52:12 -0400438DEF_TEST(DynamicMemoryWStream_detachAsData, r) {
439 const char az[] = "abcdefghijklmnopqrstuvwxyz";
440 const unsigned N = 40000;
441 SkDynamicMemoryWStream dmws;
442 for (unsigned i = 0; i < N; ++i) {
443 dmws.writeText(az);
444 }
445 REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az));
446 auto data = dmws.detachAsData();
447 REPORTER_ASSERT(r, data->size() == N * strlen(az));
448 const uint8_t* ptr = data->bytes();
449 for (unsigned i = 0; i < N; ++i) {
450 if (0 != memcmp(ptr, az, strlen(az))) {
451 ERRORF(r, "detachAsData() memcmp failed");
452 return;
453 }
454 ptr += strlen(az);
455 }
456}
457
halcanary48305e82015-08-18 13:30:25 -0700458DEF_TEST(StreamCopy, reporter) {
459 SkRandom random(123456);
halcanarycb9241b2015-08-19 06:12:40 -0700460 static const int N = 10000;
461 SkAutoTMalloc<uint8_t> src((size_t)N);
462 for (int j = 0; j < N; ++j) {
halcanary48305e82015-08-18 13:30:25 -0700463 src[j] = random.nextU() & 0xff;
464 }
465 // SkStreamCopy had two code paths; this test both.
halcanarycb9241b2015-08-19 06:12:40 -0700466 DumbStream dumbStream(src.get(), (size_t)N);
halcanary48305e82015-08-18 13:30:25 -0700467 stream_copy_test(reporter, src, N, &dumbStream);
halcanarycb9241b2015-08-19 06:12:40 -0700468 SkMemoryStream smartStream(src.get(), (size_t)N);
halcanary48305e82015-08-18 13:30:25 -0700469 stream_copy_test(reporter, src, N, &smartStream);
halcanary48305e82015-08-18 13:30:25 -0700470}
halcanary209c1622015-09-28 07:29:39 -0700471
472DEF_TEST(StreamEmptyStreamMemoryBase, r) {
473 SkDynamicMemoryWStream tmp;
Ben Wagner145dbcd2016-11-03 14:40:50 -0400474 std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream());
halcanary209c1622015-09-28 07:29:39 -0700475 REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
476}
Mike Reed1026ccf2017-01-08 14:35:29 -0500477
Leon Scroggins III8a8a1442018-05-08 09:35:32 -0400478DEF_TEST(FILEStreamWithOffset, r) {
479 if (GetResourcePath().isEmpty()) {
480 return;
481 }
482
483 SkString filename = GetResourcePath("images/baby_tux.png");
484 SkFILEStream stream1(filename.c_str());
485 if (!stream1.isValid()) {
486 ERRORF(r, "Could not create SkFILEStream from %s", filename.c_str());
487 return;
488 }
489 REPORTER_ASSERT(r, stream1.hasLength());
490 REPORTER_ASSERT(r, stream1.hasPosition());
491
492 // Seek halfway through the file. The second SkFILEStream will be created
493 // with the same filename and offset and therefore will treat that offset as
494 // the beginning.
495 const size_t size = stream1.getLength();
496 const size_t middle = size / 2;
497 if (!stream1.seek(middle)) {
498 ERRORF(r, "Could not seek SkFILEStream to %lu out of %lu", middle, size);
499 return;
500 }
501 REPORTER_ASSERT(r, stream1.getPosition() == middle);
502
503 FILE* file = sk_fopen(filename.c_str(), kRead_SkFILE_Flag);
504 if (!file) {
505 ERRORF(r, "Could not open %s as a FILE", filename.c_str());
506 return;
507 }
508
509 if (fseek(file, (long) middle, SEEK_SET) != 0) {
510 ERRORF(r, "Could not fseek FILE to %lu out of %lu", middle, size);
511 return;
512 }
513 SkFILEStream stream2(file);
514
515 const size_t remaining = size - middle;
516 SkAutoTMalloc<uint8_t> expected(remaining);
517 REPORTER_ASSERT(r, stream1.read(expected.get(), remaining) == remaining);
518
519 auto test_full_read = [&r, &expected, remaining](SkStream* stream) {
520 SkAutoTMalloc<uint8_t> actual(remaining);
521 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
522 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
523
524 REPORTER_ASSERT(r, stream->getPosition() == stream->getLength());
525 REPORTER_ASSERT(r, stream->isAtEnd());
526 };
527
528 auto test_rewind = [&r, &expected, remaining](SkStream* stream) {
529 // Rewind goes back to original offset.
530 REPORTER_ASSERT(r, stream->rewind());
531 REPORTER_ASSERT(r, stream->getPosition() == 0);
532 SkAutoTMalloc<uint8_t> actual(remaining);
533 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
534 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
535 };
536
537 auto test_move = [&r, &expected, size, remaining](SkStream* stream) {
538 // Cannot move to before the original offset.
539 REPORTER_ASSERT(r, stream->move(- (long) size));
540 REPORTER_ASSERT(r, stream->getPosition() == 0);
541
542 REPORTER_ASSERT(r, stream->move(std::numeric_limits<long>::min()));
543 REPORTER_ASSERT(r, stream->getPosition() == 0);
544
545 SkAutoTMalloc<uint8_t> actual(remaining);
546 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
547 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
548
549 REPORTER_ASSERT(r, stream->isAtEnd());
550 REPORTER_ASSERT(r, stream->getPosition() == remaining);
551
552 // Cannot move beyond the end.
553 REPORTER_ASSERT(r, stream->move(1));
554 REPORTER_ASSERT(r, stream->isAtEnd());
555 REPORTER_ASSERT(r, stream->getPosition() == remaining);
556 };
557
558 auto test_seek = [&r, &expected, middle, remaining](SkStream* stream) {
559 // Seek to an arbitrary position.
560 const size_t arbitrary = middle / 2;
561 REPORTER_ASSERT(r, stream->seek(arbitrary));
562 REPORTER_ASSERT(r, stream->getPosition() == arbitrary);
563 const size_t miniRemaining = remaining - arbitrary;
564 SkAutoTMalloc<uint8_t> actual(miniRemaining);
565 REPORTER_ASSERT(r, stream->read(actual.get(), miniRemaining) == miniRemaining);
566 REPORTER_ASSERT(r, !memcmp(expected.get() + arbitrary, actual.get(), miniRemaining));
567 };
568
569 auto test_seek_beginning = [&r, &expected, remaining](SkStream* stream) {
570 // Seek to the beginning.
571 REPORTER_ASSERT(r, stream->seek(0));
572 REPORTER_ASSERT(r, stream->getPosition() == 0);
573 SkAutoTMalloc<uint8_t> actual(remaining);
574 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
575 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
576 };
577
578 auto test_seek_end = [&r, remaining](SkStream* stream) {
579 // Cannot seek past the end.
580 REPORTER_ASSERT(r, stream->isAtEnd());
581
582 REPORTER_ASSERT(r, stream->seek(remaining + 1));
583 REPORTER_ASSERT(r, stream->isAtEnd());
584 REPORTER_ASSERT(r, stream->getPosition() == remaining);
585
586 const size_t middle = remaining / 2;
587 REPORTER_ASSERT(r, stream->seek(middle));
588 REPORTER_ASSERT(r, !stream->isAtEnd());
589 REPORTER_ASSERT(r, stream->getPosition() == middle);
590
591 REPORTER_ASSERT(r, stream->seek(remaining * 2));
592 REPORTER_ASSERT(r, stream->isAtEnd());
593 REPORTER_ASSERT(r, stream->getPosition() == remaining);
594
595 REPORTER_ASSERT(r, stream->seek(std::numeric_limits<long>::max()));
596 REPORTER_ASSERT(r, stream->isAtEnd());
597 REPORTER_ASSERT(r, stream->getPosition() == remaining);
598 };
599
600
601 std::function<void (SkStream* stream, bool recurse)> test_all;
602 test_all = [&](SkStream* stream, bool recurse) {
603 REPORTER_ASSERT(r, stream->getLength() == remaining);
604 REPORTER_ASSERT(r, stream->getPosition() == 0);
605
606 test_full_read(stream);
607 test_rewind(stream);
608 test_move(stream);
609 test_seek(stream);
610 test_seek_beginning(stream);
611 test_seek_end(stream);
612
613 if (recurse) {
614 // Duplicate shares the original offset.
615 auto duplicate = stream->duplicate();
616 if (!duplicate) {
617 ERRORF(r, "Failed to duplicate the stream!");
618 } else {
619 test_all(duplicate.get(), false);
620 }
621
622 // Fork shares the original offset, too.
623 auto fork = stream->fork();
624 if (!fork) {
625 ERRORF(r, "Failed to fork the stream!");
626 } else {
627 REPORTER_ASSERT(r, fork->isAtEnd());
628 REPORTER_ASSERT(r, fork->getLength() == remaining);
629 REPORTER_ASSERT(r, fork->rewind());
630
631 test_all(fork.get(), false);
632 }
633 }
634 };
635
636 test_all(&stream2, true);
637}
638
Mike Reed1026ccf2017-01-08 14:35:29 -0500639#include "SkBuffer.h"
640
641DEF_TEST(RBuffer, reporter) {
642 int32_t value = 0;
643 SkRBuffer buffer(&value, 4);
644 REPORTER_ASSERT(reporter, buffer.isValid());
645
646 int32_t tmp;
647 REPORTER_ASSERT(reporter, buffer.read(&tmp, 4));
648 REPORTER_ASSERT(reporter, buffer.isValid());
649
650 REPORTER_ASSERT(reporter, !buffer.read(&tmp, 4));
651 REPORTER_ASSERT(reporter, !buffer.isValid());
652}