blob: 49810aedb4805dae1ce040056b150f4649bffbe0 [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) {
Mike Reedff80c2a2017-01-07 11:16:28 -0500162 size_t n = rstream->readPackedUInt();
reed@google.com19f286b2011-10-18 11:49:52 +0000163 if (sizes[i] != n) {
halcanary7d571242016-02-24 17:59:16 -0800164 ERRORF(reporter, "sizes:%x != n:%x\n", i, sizes[i], n);
reed@google.com19f286b2011-10-18 11:49:52 +0000165 }
reed@google.com19f286b2011-10-18 11:49:52 +0000166 }
167}
168
halcanary96fcdcc2015-08-27 07:41:13 -0700169// 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 +0000170// methods that access fData.
171static void TestDereferencingData(SkMemoryStream* memStream) {
halcanary96fcdcc2015-08-27 07:41:13 -0700172 memStream->read(nullptr, 0);
scroggo@google.come4904202013-01-09 22:02:58 +0000173 memStream->getMemoryBase();
reed42943c82016-09-12 12:01:44 -0700174 (void)memStream->asData();
scroggo@google.come4904202013-01-09 22:02:58 +0000175}
176
177static void TestNullData() {
reed42943c82016-09-12 12:01:44 -0700178 SkMemoryStream memStream(nullptr);
scroggo@google.come4904202013-01-09 22:02:58 +0000179 TestDereferencingData(&memStream);
180
reed42943c82016-09-12 12:01:44 -0700181 memStream.setData(nullptr);
scroggo@google.come4904202013-01-09 22:02:58 +0000182 TestDereferencingData(&memStream);
183
184}
185
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000186DEF_TEST(Stream, reporter) {
reed@android.com5e5adfd2009-03-07 03:39:23 +0000187 TestWStream(reporter);
reed@google.com19f286b2011-10-18 11:49:52 +0000188 TestPackedUInt(reporter);
scroggo@google.come4904202013-01-09 22:02:58 +0000189 TestNullData();
reed@android.com5e5adfd2009-03-07 03:39:23 +0000190}
scroggo028a4132015-04-02 13:19:51 -0700191
Mike Klein7d302882016-11-03 14:06:31 -0400192#ifndef SK_BUILD_FOR_IOS
scroggo028a4132015-04-02 13:19:51 -0700193/**
194 * Tests peeking and then reading the same amount. The two should provide the
195 * same results.
scroggod61c3842015-12-07 11:37:13 -0800196 * Returns the amount successfully read minus the amount successfully peeked.
scroggo028a4132015-04-02 13:19:51 -0700197 */
scroggod61c3842015-12-07 11:37:13 -0800198static size_t compare_peek_to_read(skiatest::Reporter* reporter,
199 SkStream* stream, size_t bytesToPeek) {
scroggo028a4132015-04-02 13:19:51 -0700200 // The rest of our tests won't be very interesting if bytesToPeek is zero.
201 REPORTER_ASSERT(reporter, bytesToPeek > 0);
202 SkAutoMalloc peekStorage(bytesToPeek);
203 SkAutoMalloc readStorage(bytesToPeek);
204 void* peekPtr = peekStorage.get();
205 void* readPtr = peekStorage.get();
206
scroggod61c3842015-12-07 11:37:13 -0800207 const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek);
scroggo028a4132015-04-02 13:19:51 -0700208 const size_t bytesRead = stream->read(readPtr, bytesToPeek);
209
210 // bytesRead should only be less than attempted if the stream is at the
211 // end.
212 REPORTER_ASSERT(reporter, bytesRead == bytesToPeek || stream->isAtEnd());
213
214 // peek and read should behave the same, except peek returned to the
215 // original position, so they read the same data.
scroggod61c3842015-12-07 11:37:13 -0800216 REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked));
scroggo028a4132015-04-02 13:19:51 -0700217
scroggod61c3842015-12-07 11:37:13 -0800218 // A stream should never be able to peek more than it can read.
219 REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked);
220
221 return bytesRead - bytesPeeked;
scroggo028a4132015-04-02 13:19:51 -0700222}
223
scroggod61c3842015-12-07 11:37:13 -0800224static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
scroggo028a4132015-04-02 13:19:51 -0700225 for (size_t i = 1; !stream->isAtEnd(); i++) {
scroggod61c3842015-12-07 11:37:13 -0800226 REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
scroggo028a4132015-04-02 13:19:51 -0700227 }
228}
229
230static void test_peeking_front_buffered_stream(skiatest::Reporter* r,
231 const SkStream& original,
232 size_t bufferSize) {
Mike Reed98c5d922017-09-15 21:39:47 -0400233 std::unique_ptr<SkStream> dupe(original.duplicate());
halcanary96fcdcc2015-08-27 07:41:13 -0700234 REPORTER_ASSERT(r, dupe != nullptr);
Mike Reed98c5d922017-09-15 21:39:47 -0400235 auto bufferedStream = SkFrontBufferedStream::Make(std::move(dupe), bufferSize);
halcanary96fcdcc2015-08-27 07:41:13 -0700236 REPORTER_ASSERT(r, bufferedStream != nullptr);
scroggod61c3842015-12-07 11:37:13 -0800237
238 size_t peeked = 0;
239 for (size_t i = 1; !bufferedStream->isAtEnd(); i++) {
Ben Wagner145dbcd2016-11-03 14:40:50 -0400240 const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i);
scroggod61c3842015-12-07 11:37:13 -0800241 if (unpeekableBytes > 0) {
242 // This could not have returned a number greater than i.
243 REPORTER_ASSERT(r, unpeekableBytes <= i);
244
245 // We have reached the end of the buffer. Verify that it was at least
246 // bufferSize.
247 REPORTER_ASSERT(r, peeked + i - unpeekableBytes >= bufferSize);
248 // No more peeking is supported.
249 break;
250 }
251 peeked += i;
252 }
253
254 // Test that attempting to peek beyond the length of the buffer does not prevent rewinding.
Mike Reed98c5d922017-09-15 21:39:47 -0400255 bufferedStream = SkFrontBufferedStream::Make(original.duplicate(), bufferSize);
scroggod61c3842015-12-07 11:37:13 -0800256 REPORTER_ASSERT(r, bufferedStream != nullptr);
257
258 const size_t bytesToPeek = bufferSize + 1;
259 SkAutoMalloc peekStorage(bytesToPeek);
260 SkAutoMalloc readStorage(bytesToPeek);
261
262 for (size_t start = 0; start <= bufferSize; start++) {
263 // Skip to the starting point
264 REPORTER_ASSERT(r, bufferedStream->skip(start) == start);
scroggod61c3842015-12-07 11:37:13 -0800265
266 const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek);
267 if (0 == bytesPeeked) {
scroggoef0fed32016-02-18 05:59:25 -0800268 // Peeking should only fail completely if we have read/skipped beyond the buffer.
269 REPORTER_ASSERT(r, start >= bufferSize);
scroggod61c3842015-12-07 11:37:13 -0800270 break;
271 }
272
273 // Only read the amount that was successfully peeked.
274 const size_t bytesRead = bufferedStream->read(readStorage.get(), bytesPeeked);
275 REPORTER_ASSERT(r, bytesRead == bytesPeeked);
276 REPORTER_ASSERT(r, !memcmp(peekStorage.get(), readStorage.get(), bytesPeeked));
277
278 // This should be safe to rewind.
279 REPORTER_ASSERT(r, bufferedStream->rewind());
280 }
scroggo028a4132015-04-02 13:19:51 -0700281}
282
halcanary9d524f22016-03-29 09:03:52 -0700283// This test uses file system operations that don't work out of the
284// box on iOS. It's likely that we don't need them on iOS. Ignoring for now.
285// TODO(stephana): Re-evaluate if we need this in the future.
scroggo028a4132015-04-02 13:19:51 -0700286DEF_TEST(StreamPeek, reporter) {
287 // Test a memory stream.
288 const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz";
289 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
scroggod61c3842015-12-07 11:37:13 -0800290 test_fully_peekable_stream(reporter, &memStream, memStream.getLength());
scroggo028a4132015-04-02 13:19:51 -0700291
292 // Test an arbitrary file stream. file streams do not support peeking.
Hal Canary925e31e2017-12-11 14:42:58 -0500293 auto tmpdir = skiatest::GetTmpDir();
294 if (tmpdir.isEmpty()) {
295 ERRORF(reporter, "no tmp dir!");
Hal Canarya4935102017-12-08 13:35:47 -0500296 return;
297 }
Hal Canary925e31e2017-12-11 14:42:58 -0500298 auto path = SkOSPath::Join(tmpdir.c_str(), "file");
299 {
300 SkFILEWStream wStream(path.c_str());
301 constexpr char filename[] = "images/baby_tux.webp";
302 auto data = GetResourceAsData(filename);
303 if (!data || data->size() == 0) {
304 ERRORF(reporter, "resource missing: %s\n", filename);
305 return;
306 }
307 if (!wStream.isValid() || !wStream.write(data->data(), data->size())) {
308 ERRORF(reporter, "error wrtiting to file %s", path.c_str());
309 return;
310 }
311 }
Hal Canarya4935102017-12-08 13:35:47 -0500312 SkFILEStream fileStream(path.c_str());
scroggo028a4132015-04-02 13:19:51 -0700313 REPORTER_ASSERT(reporter, fileStream.isValid());
caryclark30ac4642015-04-14 06:08:04 -0700314 if (!fileStream.isValid()) {
315 return;
316 }
scroggo028a4132015-04-02 13:19:51 -0700317 SkAutoMalloc storage(fileStream.getLength());
318 for (size_t i = 1; i < fileStream.getLength(); i++) {
scroggod61c3842015-12-07 11:37:13 -0800319 REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0);
scroggo028a4132015-04-02 13:19:51 -0700320 }
321
322 // Now test some FrontBufferedStreams
323 for (size_t i = 1; i < memStream.getLength(); i++) {
324 test_peeking_front_buffered_stream(reporter, memStream, i);
325 }
326}
halcanarye797d0d2015-05-21 08:13:27 -0700327#endif
328
329// Asserts that asset == expected and is peekable.
330static void stream_peek_test(skiatest::Reporter* rep,
331 SkStreamAsset* asset,
332 const SkData* expected) {
333 if (asset->getLength() != expected->size()) {
334 ERRORF(rep, "Unexpected length.");
335 return;
336 }
337 SkRandom rand;
338 uint8_t buffer[4096];
339 const uint8_t* expect = expected->bytes();
340 for (size_t i = 0; i < asset->getLength(); ++i) {
341 uint32_t maxSize =
342 SkToU32(SkTMin(sizeof(buffer), asset->getLength() - i));
343 size_t size = rand.nextRangeU(1, maxSize);
344 SkASSERT(size >= 1);
345 SkASSERT(size <= sizeof(buffer));
346 SkASSERT(size + i <= asset->getLength());
scroggod61c3842015-12-07 11:37:13 -0800347 if (asset->peek(buffer, size) < size) {
halcanarye797d0d2015-05-21 08:13:27 -0700348 ERRORF(rep, "Peek Failed!");
349 return;
350 }
351 if (0 != memcmp(buffer, &expect[i], size)) {
352 ERRORF(rep, "Peek returned wrong bytes!");
353 return;
354 }
355 uint8_t value;
356 REPORTER_ASSERT(rep, 1 == asset->read(&value, 1));
357 if (value != expect[i]) {
358 ERRORF(rep, "Read Failed!");
359 return;
360 }
361 }
362}
363
364DEF_TEST(StreamPeek_BlockMemoryStream, rep) {
365 const static int kSeed = 1234;
366 SkRandom valueSource(kSeed);
367 SkRandom rand(kSeed << 1);
368 uint8_t buffer[4096];
369 SkDynamicMemoryWStream dynamicMemoryWStream;
Mike Reed49282292016-12-14 12:34:06 -0500370 size_t totalWritten = 0;
halcanarye797d0d2015-05-21 08:13:27 -0700371 for (int i = 0; i < 32; ++i) {
372 // Randomize the length of the blocks.
373 size_t size = rand.nextRangeU(1, sizeof(buffer));
374 for (size_t j = 0; j < size; ++j) {
375 buffer[j] = valueSource.nextU() & 0xFF;
376 }
377 dynamicMemoryWStream.write(buffer, size);
Mike Reed49282292016-12-14 12:34:06 -0500378 totalWritten += size;
379 REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten());
halcanarye797d0d2015-05-21 08:13:27 -0700380 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400381 std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream());
bungeman38d909e2016-08-02 14:40:46 -0700382 sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength()));
halcanarye797d0d2015-05-21 08:13:27 -0700383 uint8_t* expectedPtr = static_cast<uint8_t*>(expected->writable_data());
384 valueSource.setSeed(kSeed); // reseed.
385 // We want the exact same same "random" string of numbers to put
386 // in expected. i.e.: don't rely on SkDynamicMemoryStream to work
387 // correctly while we are testing SkDynamicMemoryStream.
388 for (size_t i = 0; i < asset->getLength(); ++i) {
389 expectedPtr[i] = valueSource.nextU() & 0xFF;
390 }
Ben Wagner145dbcd2016-11-03 14:40:50 -0400391 stream_peek_test(rep, asset.get(), expected.get());
halcanarye797d0d2015-05-21 08:13:27 -0700392}
halcanary48305e82015-08-18 13:30:25 -0700393
394namespace {
395class DumbStream : public SkStream {
396public:
397 DumbStream(const uint8_t* data, size_t n)
398 : fData(data), fCount(n), fIdx(0) {}
399 size_t read(void* buffer, size_t size) override {
halcanaryd75e21d2015-08-19 07:22:04 -0700400 size_t copyCount = SkTMin(fCount - fIdx, size);
401 if (copyCount) {
402 memcpy(buffer, &fData[fIdx], copyCount);
403 fIdx += copyCount;
halcanary48305e82015-08-18 13:30:25 -0700404 }
halcanaryd75e21d2015-08-19 07:22:04 -0700405 return copyCount;
halcanary48305e82015-08-18 13:30:25 -0700406 }
407 bool isAtEnd() const override {
halcanaryd75e21d2015-08-19 07:22:04 -0700408 return fCount == fIdx;
halcanary48305e82015-08-18 13:30:25 -0700409 }
410 private:
411 const uint8_t* fData;
412 size_t fCount, fIdx;
413};
414} // namespace
415
416static void stream_copy_test(skiatest::Reporter* reporter,
417 const void* srcData,
418 size_t N,
419 SkStream* stream) {
420 SkDynamicMemoryWStream tgt;
421 if (!SkStreamCopy(&tgt, stream)) {
422 ERRORF(reporter, "SkStreamCopy failed");
423 return;
424 }
reed42943c82016-09-12 12:01:44 -0700425 sk_sp<SkData> data(tgt.detachAsData());
halcanary48305e82015-08-18 13:30:25 -0700426 if (data->size() != N) {
427 ERRORF(reporter, "SkStreamCopy incorrect size");
428 return;
429 }
430 if (0 != memcmp(data->data(), srcData, N)) {
431 ERRORF(reporter, "SkStreamCopy bad copy");
432 }
433}
434
Hal Canarydabe8ac2017-03-14 15:52:12 -0400435DEF_TEST(DynamicMemoryWStream_detachAsData, r) {
436 const char az[] = "abcdefghijklmnopqrstuvwxyz";
437 const unsigned N = 40000;
438 SkDynamicMemoryWStream dmws;
439 for (unsigned i = 0; i < N; ++i) {
440 dmws.writeText(az);
441 }
442 REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az));
443 auto data = dmws.detachAsData();
444 REPORTER_ASSERT(r, data->size() == N * strlen(az));
445 const uint8_t* ptr = data->bytes();
446 for (unsigned i = 0; i < N; ++i) {
447 if (0 != memcmp(ptr, az, strlen(az))) {
448 ERRORF(r, "detachAsData() memcmp failed");
449 return;
450 }
451 ptr += strlen(az);
452 }
453}
454
halcanary48305e82015-08-18 13:30:25 -0700455DEF_TEST(StreamCopy, reporter) {
456 SkRandom random(123456);
halcanarycb9241b2015-08-19 06:12:40 -0700457 static const int N = 10000;
458 SkAutoTMalloc<uint8_t> src((size_t)N);
459 for (int j = 0; j < N; ++j) {
halcanary48305e82015-08-18 13:30:25 -0700460 src[j] = random.nextU() & 0xff;
461 }
462 // SkStreamCopy had two code paths; this test both.
halcanarycb9241b2015-08-19 06:12:40 -0700463 DumbStream dumbStream(src.get(), (size_t)N);
halcanary48305e82015-08-18 13:30:25 -0700464 stream_copy_test(reporter, src, N, &dumbStream);
halcanarycb9241b2015-08-19 06:12:40 -0700465 SkMemoryStream smartStream(src.get(), (size_t)N);
halcanary48305e82015-08-18 13:30:25 -0700466 stream_copy_test(reporter, src, N, &smartStream);
halcanary48305e82015-08-18 13:30:25 -0700467}
halcanary209c1622015-09-28 07:29:39 -0700468
469DEF_TEST(StreamEmptyStreamMemoryBase, r) {
470 SkDynamicMemoryWStream tmp;
Ben Wagner145dbcd2016-11-03 14:40:50 -0400471 std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream());
halcanary209c1622015-09-28 07:29:39 -0700472 REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
473}
Mike Reed1026ccf2017-01-08 14:35:29 -0500474
Leon Scroggins III8a8a1442018-05-08 09:35:32 -0400475DEF_TEST(FILEStreamWithOffset, r) {
476 if (GetResourcePath().isEmpty()) {
477 return;
478 }
479
480 SkString filename = GetResourcePath("images/baby_tux.png");
481 SkFILEStream stream1(filename.c_str());
482 if (!stream1.isValid()) {
483 ERRORF(r, "Could not create SkFILEStream from %s", filename.c_str());
484 return;
485 }
486 REPORTER_ASSERT(r, stream1.hasLength());
487 REPORTER_ASSERT(r, stream1.hasPosition());
488
489 // Seek halfway through the file. The second SkFILEStream will be created
490 // with the same filename and offset and therefore will treat that offset as
491 // the beginning.
492 const size_t size = stream1.getLength();
493 const size_t middle = size / 2;
494 if (!stream1.seek(middle)) {
495 ERRORF(r, "Could not seek SkFILEStream to %lu out of %lu", middle, size);
496 return;
497 }
498 REPORTER_ASSERT(r, stream1.getPosition() == middle);
499
500 FILE* file = sk_fopen(filename.c_str(), kRead_SkFILE_Flag);
501 if (!file) {
502 ERRORF(r, "Could not open %s as a FILE", filename.c_str());
503 return;
504 }
505
506 if (fseek(file, (long) middle, SEEK_SET) != 0) {
507 ERRORF(r, "Could not fseek FILE to %lu out of %lu", middle, size);
508 return;
509 }
510 SkFILEStream stream2(file);
511
512 const size_t remaining = size - middle;
513 SkAutoTMalloc<uint8_t> expected(remaining);
514 REPORTER_ASSERT(r, stream1.read(expected.get(), remaining) == remaining);
515
516 auto test_full_read = [&r, &expected, remaining](SkStream* stream) {
517 SkAutoTMalloc<uint8_t> actual(remaining);
518 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
519 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
520
521 REPORTER_ASSERT(r, stream->getPosition() == stream->getLength());
522 REPORTER_ASSERT(r, stream->isAtEnd());
523 };
524
525 auto test_rewind = [&r, &expected, remaining](SkStream* stream) {
526 // Rewind goes back to original offset.
527 REPORTER_ASSERT(r, stream->rewind());
528 REPORTER_ASSERT(r, stream->getPosition() == 0);
529 SkAutoTMalloc<uint8_t> actual(remaining);
530 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
531 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
532 };
533
534 auto test_move = [&r, &expected, size, remaining](SkStream* stream) {
535 // Cannot move to before the original offset.
536 REPORTER_ASSERT(r, stream->move(- (long) size));
537 REPORTER_ASSERT(r, stream->getPosition() == 0);
538
539 REPORTER_ASSERT(r, stream->move(std::numeric_limits<long>::min()));
540 REPORTER_ASSERT(r, stream->getPosition() == 0);
541
542 SkAutoTMalloc<uint8_t> actual(remaining);
543 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
544 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
545
546 REPORTER_ASSERT(r, stream->isAtEnd());
547 REPORTER_ASSERT(r, stream->getPosition() == remaining);
548
549 // Cannot move beyond the end.
550 REPORTER_ASSERT(r, stream->move(1));
551 REPORTER_ASSERT(r, stream->isAtEnd());
552 REPORTER_ASSERT(r, stream->getPosition() == remaining);
553 };
554
555 auto test_seek = [&r, &expected, middle, remaining](SkStream* stream) {
556 // Seek to an arbitrary position.
557 const size_t arbitrary = middle / 2;
558 REPORTER_ASSERT(r, stream->seek(arbitrary));
559 REPORTER_ASSERT(r, stream->getPosition() == arbitrary);
560 const size_t miniRemaining = remaining - arbitrary;
561 SkAutoTMalloc<uint8_t> actual(miniRemaining);
562 REPORTER_ASSERT(r, stream->read(actual.get(), miniRemaining) == miniRemaining);
563 REPORTER_ASSERT(r, !memcmp(expected.get() + arbitrary, actual.get(), miniRemaining));
564 };
565
566 auto test_seek_beginning = [&r, &expected, remaining](SkStream* stream) {
567 // Seek to the beginning.
568 REPORTER_ASSERT(r, stream->seek(0));
569 REPORTER_ASSERT(r, stream->getPosition() == 0);
570 SkAutoTMalloc<uint8_t> actual(remaining);
571 REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
572 REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
573 };
574
575 auto test_seek_end = [&r, remaining](SkStream* stream) {
576 // Cannot seek past the end.
577 REPORTER_ASSERT(r, stream->isAtEnd());
578
579 REPORTER_ASSERT(r, stream->seek(remaining + 1));
580 REPORTER_ASSERT(r, stream->isAtEnd());
581 REPORTER_ASSERT(r, stream->getPosition() == remaining);
582
583 const size_t middle = remaining / 2;
584 REPORTER_ASSERT(r, stream->seek(middle));
585 REPORTER_ASSERT(r, !stream->isAtEnd());
586 REPORTER_ASSERT(r, stream->getPosition() == middle);
587
588 REPORTER_ASSERT(r, stream->seek(remaining * 2));
589 REPORTER_ASSERT(r, stream->isAtEnd());
590 REPORTER_ASSERT(r, stream->getPosition() == remaining);
591
592 REPORTER_ASSERT(r, stream->seek(std::numeric_limits<long>::max()));
593 REPORTER_ASSERT(r, stream->isAtEnd());
594 REPORTER_ASSERT(r, stream->getPosition() == remaining);
595 };
596
597
598 std::function<void (SkStream* stream, bool recurse)> test_all;
599 test_all = [&](SkStream* stream, bool recurse) {
600 REPORTER_ASSERT(r, stream->getLength() == remaining);
601 REPORTER_ASSERT(r, stream->getPosition() == 0);
602
603 test_full_read(stream);
604 test_rewind(stream);
605 test_move(stream);
606 test_seek(stream);
607 test_seek_beginning(stream);
608 test_seek_end(stream);
609
610 if (recurse) {
611 // Duplicate shares the original offset.
612 auto duplicate = stream->duplicate();
613 if (!duplicate) {
614 ERRORF(r, "Failed to duplicate the stream!");
615 } else {
616 test_all(duplicate.get(), false);
617 }
618
619 // Fork shares the original offset, too.
620 auto fork = stream->fork();
621 if (!fork) {
622 ERRORF(r, "Failed to fork the stream!");
623 } else {
624 REPORTER_ASSERT(r, fork->isAtEnd());
625 REPORTER_ASSERT(r, fork->getLength() == remaining);
626 REPORTER_ASSERT(r, fork->rewind());
627
628 test_all(fork.get(), false);
629 }
630 }
631 };
632
633 test_all(&stream2, true);
634}
635
Mike Reed1026ccf2017-01-08 14:35:29 -0500636#include "SkBuffer.h"
637
638DEF_TEST(RBuffer, reporter) {
639 int32_t value = 0;
640 SkRBuffer buffer(&value, 4);
641 REPORTER_ASSERT(reporter, buffer.isValid());
642
643 int32_t tmp;
644 REPORTER_ASSERT(reporter, buffer.read(&tmp, 4));
645 REPORTER_ASSERT(reporter, buffer.isValid());
646
647 REPORTER_ASSERT(reporter, !buffer.read(&tmp, 4));
648 REPORTER_ASSERT(reporter, !buffer.isValid());
649}