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