1 /*
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 */
7
8 // 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
14 #include "include/core/SkData.h"
15 #include "include/core/SkStream.h"
16 #include "include/private/SkTo.h"
17 #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"
24
25 #include <functional>
26 #include <limits>
27
28 #ifndef SK_BUILD_FOR_WIN
29 #include <unistd.h>
30 #include <fcntl.h>
31 #endif
32
33 #define MAX_SIZE (256 * 1024)
34
test_loop_stream(skiatest::Reporter * reporter,SkStream * stream,const void * src,size_t len,int repeat)35 static 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);
49 // isAtEnd might not return true until after the first failing read.
50 REPORTER_ASSERT(reporter, stream->isAtEnd());
51 }
52
test_filestreams(skiatest::Reporter * reporter,const char * tmpDir)53 static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
54 SkString path = SkOSPath::Join(tmpDir, "wstream_test");
55
56 const char s[] = "abcdefghijklmnopqrstuvwxyz";
57
58 {
59 SkFILEWStream writer(path.c_str());
60 if (!writer.isValid()) {
61 ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
62 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);
74
75 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
76 test_loop_stream(reporter, stream2.get(), s, 26, 100);
77 }
78
79 {
80 FILE* file = ::fopen(path.c_str(), "rb");
81 SkFILEStream stream(file);
82 REPORTER_ASSERT(reporter, stream.isValid());
83 test_loop_stream(reporter, &stream, s, 26, 100);
84
85 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
86 test_loop_stream(reporter, stream2.get(), s, 26, 100);
87 }
88 }
89
TestWStream(skiatest::Reporter * reporter)90 static 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));
96 }
97 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
98
99 char* dst = new char[100 * 26 + 1];
100 dst[100*26] = '*';
101 ds.copyTo(dst);
102 REPORTER_ASSERT(reporter, dst[100*26] == '*');
103 for (i = 0; i < 100; i++) {
104 REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
105 }
106
107 {
108 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
109 REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
110 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
111 test_loop_stream(reporter, stream.get(), s, 26, 100);
112
113 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
114 test_loop_stream(reporter, stream2.get(), s, 26, 100);
115
116 std::unique_ptr<SkStreamAsset> stream3(stream->fork());
117 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 }
128 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
129
130 {
131 // Test that this works after a snapshot.
132 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
133 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
134 test_loop_stream(reporter, stream.get(), s, 26, 100);
135
136 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
137 test_loop_stream(reporter, stream2.get(), s, 26, 100);
138 }
139 delete[] dst;
140
141 SkString tmpDir = skiatest::GetTmpDir();
142 if (!tmpDir.isEmpty()) {
143 test_filestreams(reporter, tmpDir.c_str());
144 }
145 }
146
TestPackedUInt(skiatest::Reporter * reporter)147 static 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 };
156
157
158 size_t i;
159 SkDynamicMemoryWStream wstream;
160
161 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
162 bool success = wstream.writePackedUInt(sizes[i]);
163 REPORTER_ASSERT(reporter, success);
164 }
165
166 std::unique_ptr<SkStreamAsset> rstream(wstream.detachAsStream());
167 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) {
168 size_t n;
169 if (!rstream->readPackedUInt(&n)) {
170 ERRORF(reporter, "[%zu] sizes:%zx could not be read\n", i, sizes[i]);
171 }
172 if (sizes[i] != n) {
173 ERRORF(reporter, "[%zu] sizes:%zx != n:%zx\n", i, sizes[i], n);
174 }
175 }
176 }
177
178 // Test that setting an SkMemoryStream to a nullptr data does not result in a crash when calling
179 // methods that access fData.
TestDereferencingData(SkMemoryStream * memStream)180 static void TestDereferencingData(SkMemoryStream* memStream) {
181 memStream->read(nullptr, 0);
182 memStream->getMemoryBase();
183 (void)memStream->asData();
184 }
185
TestNullData()186 static void TestNullData() {
187 SkMemoryStream memStream(nullptr);
188 TestDereferencingData(&memStream);
189
190 memStream.setData(nullptr);
191 TestDereferencingData(&memStream);
192
193 }
194
DEF_TEST(Stream,reporter)195 DEF_TEST(Stream, reporter) {
196 TestWStream(reporter);
197 TestPackedUInt(reporter);
198 TestNullData();
199 }
200
201 #ifndef SK_BUILD_FOR_IOS
202 /**
203 * Tests peeking and then reading the same amount. The two should provide the
204 * same results.
205 * Returns the amount successfully read minus the amount successfully peeked.
206 */
compare_peek_to_read(skiatest::Reporter * reporter,SkStream * stream,size_t bytesToPeek)207 static size_t compare_peek_to_read(skiatest::Reporter* reporter,
208 SkStream* stream, size_t bytesToPeek) {
209 // 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
216 const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek);
217 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.
225 REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked));
226
227 // A stream should never be able to peek more than it can read.
228 REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked);
229
230 return bytesRead - bytesPeeked;
231 }
232
test_fully_peekable_stream(skiatest::Reporter * r,SkStream * stream,size_t limit)233 static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
234 for (size_t i = 1; !stream->isAtEnd(); i++) {
235 REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
236 }
237 }
238
239 #ifdef SK_ENABLE_ANDROID_UTILS
test_peeking_front_buffered_stream(skiatest::Reporter * r,const SkStream & original,size_t bufferSize)240 static void test_peeking_front_buffered_stream(skiatest::Reporter* r,
241 const SkStream& original,
242 size_t bufferSize) {
243 std::unique_ptr<SkStream> dupe(original.duplicate());
244 REPORTER_ASSERT(r, dupe != nullptr);
245 auto bufferedStream = android::skia::FrontBufferedStream::Make(
246 std::move(dupe), bufferSize);
247 REPORTER_ASSERT(r, bufferedStream != nullptr);
248
249 size_t peeked = 0;
250 for (size_t i = 1; !bufferedStream->isAtEnd(); i++) {
251 const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i);
252 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.
266 bufferedStream = android::skia::FrontBufferedStream::Make(original.duplicate(), bufferSize);
267 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);
276
277 const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek);
278 if (0 == bytesPeeked) {
279 // Peeking should only fail completely if we have read/skipped beyond the buffer.
280 REPORTER_ASSERT(r, start >= bufferSize);
281 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 }
292 }
293 #endif
294
295 // 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.
DEF_TEST(StreamPeek,reporter)298 DEF_TEST(StreamPeek, reporter) {
299 // Test a memory stream.
300 const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz";
301 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
302 test_fully_peekable_stream(reporter, &memStream, memStream.getLength());
303
304 // Test an arbitrary file stream. file streams do not support peeking.
305 auto tmpdir = skiatest::GetTmpDir();
306 if (tmpdir.isEmpty()) {
307 ERRORF(reporter, "no tmp dir!");
308 return;
309 }
310 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 }
324 SkFILEStream fileStream(path.c_str());
325 REPORTER_ASSERT(reporter, fileStream.isValid());
326 if (!fileStream.isValid()) {
327 return;
328 }
329 SkAutoMalloc storage(fileStream.getLength());
330 for (size_t i = 1; i < fileStream.getLength(); i++) {
331 REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0);
332 }
333
334 #ifdef SK_ENABLE_ANDROID_UTILS
335 // Now test some FrontBufferedStreams
336 for (size_t i = 1; i < memStream.getLength(); i++) {
337 test_peeking_front_buffered_stream(reporter, memStream, i);
338 }
339 #endif
340 }
341 #endif
342
343 // Asserts that asset == expected and is peekable.
stream_peek_test(skiatest::Reporter * rep,SkStreamAsset * asset,const SkData * expected)344 static 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 =
356 SkToU32(std::min(sizeof(buffer), asset->getLength() - i));
357 size_t size = rand.nextRangeU(1, maxSize);
358 SkASSERT(size >= 1);
359 SkASSERT(size <= sizeof(buffer));
360 SkASSERT(size + i <= asset->getLength());
361 if (asset->peek(buffer, size) < size) {
362 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
DEF_TEST(StreamPeek_BlockMemoryStream,rep)378 DEF_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;
384 size_t totalWritten = 0;
385 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);
392 totalWritten += size;
393 REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten());
394 }
395 std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream());
396 sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength()));
397 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 }
405 stream_peek_test(rep, asset.get(), expected.get());
406 }
407
408 namespace {
409 class DumbStream : public SkStream {
410 public:
DumbStream(const uint8_t * data,size_t n)411 DumbStream(const uint8_t* data, size_t n)
412 : fData(data), fCount(n), fIdx(0) {}
read(void * buffer,size_t size)413 size_t read(void* buffer, size_t size) override {
414 size_t copyCount = std::min(fCount - fIdx, size);
415 if (copyCount) {
416 memcpy(buffer, &fData[fIdx], copyCount);
417 fIdx += copyCount;
418 }
419 return copyCount;
420 }
isAtEnd() const421 bool isAtEnd() const override {
422 return fCount == fIdx;
423 }
424 private:
425 const uint8_t* fData;
426 size_t fCount, fIdx;
427 };
428 } // namespace
429
stream_copy_test(skiatest::Reporter * reporter,const void * srcData,size_t N,SkStream * stream)430 static 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 }
439 sk_sp<SkData> data(tgt.detachAsData());
440 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
DEF_TEST(DynamicMemoryWStream_detachAsData,r)449 DEF_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
DEF_TEST(StreamCopy,reporter)469 DEF_TEST(StreamCopy, reporter) {
470 SkRandom random(123456);
471 static const int N = 10000;
472 SkAutoTMalloc<uint8_t> src((size_t)N);
473 for (int j = 0; j < N; ++j) {
474 src[j] = random.nextU() & 0xff;
475 }
476 // SkStreamCopy had two code paths; this test both.
477 DumbStream dumbStream(src.get(), (size_t)N);
478 stream_copy_test(reporter, src, N, &dumbStream);
479 SkMemoryStream smartStream(src.get(), (size_t)N);
480 stream_copy_test(reporter, src, N, &smartStream);
481 }
482
DEF_TEST(StreamEmptyStreamMemoryBase,r)483 DEF_TEST(StreamEmptyStreamMemoryBase, r) {
484 SkDynamicMemoryWStream tmp;
485 std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream());
486 REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
487 }
488
DEF_TEST(FILEStreamWithOffset,r)489 DEF_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
650 #include "src/core/SkBuffer.h"
651
DEF_TEST(RBuffer,reporter)652 DEF_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 }
664