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 #include "include/core/SkData.h"
9 #include "include/core/SkRefCnt.h"
10 #include "include/core/SkStream.h"
11 #include "include/core/SkString.h"
12 #include "include/core/SkTypes.h"
13 #include "include/private/base/SkTemplates.h"
14 #include "include/private/base/SkTo.h"
15 #include "src/base/SkAutoMalloc.h"
16 #include "src/base/SkBuffer.h"
17 #include "src/base/SkRandom.h"
18 #include "src/core/SkOSFile.h"
19 #include "src/core/SkStreamPriv.h"
20 #include "src/utils/SkOSPath.h"
21 #include "tests/Test.h"
22 #include "tools/Resources.h"
23 
24 #include <algorithm>
25 #include <climits>
26 #include <cstdint>
27 #include <cstdio>
28 #include <cstring>
29 #include <functional>
30 #include <limits>
31 #include <memory>
32 #include <string>
33 
34 using namespace skia_private;
35 
36 #ifdef SK_ENABLE_ANDROID_UTILS
37 #include "client_utils/android/FrontBufferedStream.h"
38 #endif
39 
40 #ifndef SK_BUILD_FOR_WIN
41 #include <fcntl.h>
42 #endif
43 
44 #define MAX_SIZE    (256 * 1024)
45 
test_loop_stream(skiatest::Reporter * reporter,SkStream * stream,const void * src,size_t len,int repeat)46 static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream,
47                              const void* src, size_t len, int repeat) {
48     SkAutoSMalloc<256> storage(len);
49     void* tmp = storage.get();
50 
51     for (int i = 0; i < repeat; ++i) {
52         size_t bytes = stream->read(tmp, len);
53         REPORTER_ASSERT(reporter, bytes == len);
54         REPORTER_ASSERT(reporter, !memcmp(tmp, src, len));
55     }
56 
57     // expect EOF
58     size_t bytes = stream->read(tmp, 1);
59     REPORTER_ASSERT(reporter, 0 == bytes);
60     // isAtEnd might not return true until after the first failing read.
61     REPORTER_ASSERT(reporter, stream->isAtEnd());
62 }
63 
test_filestreams(skiatest::Reporter * reporter,const char * tmpDir)64 static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) {
65     SkString path = SkOSPath::Join(tmpDir, "wstream_test");
66 
67     const char s[] = "abcdefghijklmnopqrstuvwxyz";
68 
69     {
70         SkFILEWStream writer(path.c_str());
71         if (!writer.isValid()) {
72             ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str());
73             return;
74         }
75 
76         for (int i = 0; i < 100; ++i) {
77             writer.write(s, 26);
78         }
79     }
80 
81     {
82         SkFILEStream stream(path.c_str());
83         REPORTER_ASSERT(reporter, stream.isValid());
84         test_loop_stream(reporter, &stream, s, 26, 100);
85 
86         std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
87         test_loop_stream(reporter, stream2.get(), s, 26, 100);
88     }
89 
90     {
91         FILE* file = ::fopen(path.c_str(), "rb");
92         SkFILEStream stream(file);
93         REPORTER_ASSERT(reporter, stream.isValid());
94         test_loop_stream(reporter, &stream, s, 26, 100);
95 
96         std::unique_ptr<SkStreamAsset> stream2(stream.duplicate());
97         test_loop_stream(reporter, stream2.get(), s, 26, 100);
98     }
99 }
100 
TestWStream(skiatest::Reporter * reporter)101 static void TestWStream(skiatest::Reporter* reporter) {
102     SkDynamicMemoryWStream  ds;
103     const char s[] = "abcdefghijklmnopqrstuvwxyz";
104     int i;
105     for (i = 0; i < 100; i++) {
106         REPORTER_ASSERT(reporter, ds.write(s, 26));
107     }
108     REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
109 
110     char* dst = new char[100 * 26 + 1];
111     dst[100*26] = '*';
112     ds.copyTo(dst);
113     REPORTER_ASSERT(reporter, dst[100*26] == '*');
114     for (i = 0; i < 100; i++) {
115         REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0);
116     }
117 
118     {
119         std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
120         REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength());
121         REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
122         test_loop_stream(reporter, stream.get(), s, 26, 100);
123 
124         std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
125         test_loop_stream(reporter, stream2.get(), s, 26, 100);
126 
127         std::unique_ptr<SkStreamAsset> stream3(stream->fork());
128         REPORTER_ASSERT(reporter, stream3->isAtEnd());
129         char tmp;
130         size_t bytes = stream->read(&tmp, 1);
131         REPORTER_ASSERT(reporter, 0 == bytes);
132         stream3->rewind();
133         test_loop_stream(reporter, stream3.get(), s, 26, 100);
134     }
135 
136     for (i = 0; i < 100; i++) {
137         REPORTER_ASSERT(reporter, ds.write(s, 26));
138     }
139     REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26);
140 
141     {
142         // Test that this works after a snapshot.
143         std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream());
144         REPORTER_ASSERT(reporter, ds.bytesWritten() == 0);
145         test_loop_stream(reporter, stream.get(), s, 26, 100);
146 
147         std::unique_ptr<SkStreamAsset> stream2(stream->duplicate());
148         test_loop_stream(reporter, stream2.get(), s, 26, 100);
149     }
150     delete[] dst;
151 
152     SkString tmpDir = skiatest::GetTmpDir();
153     if (!tmpDir.isEmpty()) {
154         test_filestreams(reporter, tmpDir.c_str());
155     }
156 }
157 
TestPackedUInt(skiatest::Reporter * reporter)158 static void TestPackedUInt(skiatest::Reporter* reporter) {
159     // we know that packeduint tries to write 1, 2 or 4 bytes for the length,
160     // so we test values around each of those transitions (and a few others)
161     const size_t sizes[] = {
162         0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769,
163         0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001,
164         0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001,
165         0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF
166     };
167 
168 
169     size_t i;
170     SkDynamicMemoryWStream wstream;
171 
172     for (i = 0; i < std::size(sizes); ++i) {
173         bool success = wstream.writePackedUInt(sizes[i]);
174         REPORTER_ASSERT(reporter, success);
175     }
176 
177     std::unique_ptr<SkStreamAsset> rstream(wstream.detachAsStream());
178     for (i = 0; i < std::size(sizes); ++i) {
179         size_t n;
180         if (!rstream->readPackedUInt(&n)) {
181             ERRORF(reporter, "[%zu] sizes:%zx could not be read\n", i, sizes[i]);
182         }
183         if (sizes[i] != n) {
184             ERRORF(reporter, "[%zu] sizes:%zx != n:%zx\n", i, sizes[i], n);
185         }
186     }
187 }
188 
189 // Test that setting an SkMemoryStream to a nullptr data does not result in a crash when calling
190 // methods that access fData.
TestDereferencingData(SkMemoryStream * memStream)191 static void TestDereferencingData(SkMemoryStream* memStream) {
192     memStream->read(nullptr, 0);
193     memStream->getMemoryBase();
194     (void)memStream->asData();
195 }
196 
TestNullData()197 static void TestNullData() {
198     SkMemoryStream memStream(nullptr);
199     TestDereferencingData(&memStream);
200 
201     memStream.setData(nullptr);
202     TestDereferencingData(&memStream);
203 
204 }
205 
DEF_TEST(Stream,reporter)206 DEF_TEST(Stream, reporter) {
207     TestWStream(reporter);
208     TestPackedUInt(reporter);
209     TestNullData();
210 }
211 
212 #ifndef SK_BUILD_FOR_IOS
213 /**
214  *  Tests peeking and then reading the same amount. The two should provide the
215  *  same results.
216  *  Returns the amount successfully read minus the amount successfully peeked.
217  */
compare_peek_to_read(skiatest::Reporter * reporter,SkStream * stream,size_t bytesToPeek)218 static size_t compare_peek_to_read(skiatest::Reporter* reporter,
219                                    SkStream* stream, size_t bytesToPeek) {
220     // The rest of our tests won't be very interesting if bytesToPeek is zero.
221     REPORTER_ASSERT(reporter, bytesToPeek > 0);
222     SkAutoMalloc peekStorage(bytesToPeek);
223     SkAutoMalloc readStorage(bytesToPeek);
224     void* peekPtr = peekStorage.get();
225     void* readPtr = peekStorage.get();
226 
227     const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek);
228     const size_t bytesRead = stream->read(readPtr, bytesToPeek);
229 
230     // bytesRead should only be less than attempted if the stream is at the
231     // end.
232     REPORTER_ASSERT(reporter, bytesRead == bytesToPeek || stream->isAtEnd());
233 
234     // peek and read should behave the same, except peek returned to the
235     // original position, so they read the same data.
236     REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked));
237 
238     // A stream should never be able to peek more than it can read.
239     REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked);
240 
241     return bytesRead - bytesPeeked;
242 }
243 
test_fully_peekable_stream(skiatest::Reporter * r,SkStream * stream,size_t limit)244 static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
245     for (size_t i = 1; !stream->isAtEnd(); i++) {
246         REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
247     }
248 }
249 
250 #ifdef SK_ENABLE_ANDROID_UTILS
test_peeking_front_buffered_stream(skiatest::Reporter * r,const SkStream & original,size_t bufferSize)251 static void test_peeking_front_buffered_stream(skiatest::Reporter* r,
252                                                const SkStream& original,
253                                                size_t bufferSize) {
254     std::unique_ptr<SkStream> dupe(original.duplicate());
255     REPORTER_ASSERT(r, dupe != nullptr);
256     auto bufferedStream = android::skia::FrontBufferedStream::Make(
257             std::move(dupe), bufferSize);
258     REPORTER_ASSERT(r, bufferedStream != nullptr);
259 
260     size_t peeked = 0;
261     for (size_t i = 1; !bufferedStream->isAtEnd(); i++) {
262         const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i);
263         if (unpeekableBytes > 0) {
264             // This could not have returned a number greater than i.
265             REPORTER_ASSERT(r, unpeekableBytes <= i);
266 
267             // We have reached the end of the buffer. Verify that it was at least
268             // bufferSize.
269             REPORTER_ASSERT(r, peeked + i - unpeekableBytes >= bufferSize);
270             // No more peeking is supported.
271             break;
272         }
273         peeked += i;
274     }
275 
276     // Test that attempting to peek beyond the length of the buffer does not prevent rewinding.
277     bufferedStream = android::skia::FrontBufferedStream::Make(original.duplicate(), bufferSize);
278     REPORTER_ASSERT(r, bufferedStream != nullptr);
279 
280     const size_t bytesToPeek = bufferSize + 1;
281     SkAutoMalloc peekStorage(bytesToPeek);
282     SkAutoMalloc readStorage(bytesToPeek);
283 
284     for (size_t start = 0; start <= bufferSize; start++) {
285         // Skip to the starting point
286         REPORTER_ASSERT(r, bufferedStream->skip(start) == start);
287 
288         const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek);
289         if (0 == bytesPeeked) {
290             // Peeking should only fail completely if we have read/skipped beyond the buffer.
291             REPORTER_ASSERT(r, start >= bufferSize);
292             break;
293         }
294 
295         // Only read the amount that was successfully peeked.
296         const size_t bytesRead = bufferedStream->read(readStorage.get(), bytesPeeked);
297         REPORTER_ASSERT(r, bytesRead == bytesPeeked);
298         REPORTER_ASSERT(r, !memcmp(peekStorage.get(), readStorage.get(), bytesPeeked));
299 
300         // This should be safe to rewind.
301         REPORTER_ASSERT(r, bufferedStream->rewind());
302     }
303 }
304 #endif
305 
306 // This test uses file system operations that don't work out of the
307 // box on iOS. It's likely that we don't need them on iOS. Ignoring for now.
308 // TODO(stephana): Re-evaluate if we need this in the future.
DEF_TEST(StreamPeek,reporter)309 DEF_TEST(StreamPeek, reporter) {
310     // Test a memory stream.
311     const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz";
312     SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
313     test_fully_peekable_stream(reporter, &memStream, memStream.getLength());
314 
315     // Test an arbitrary file stream. file streams do not support peeking.
316     auto tmpdir = skiatest::GetTmpDir();
317     if (tmpdir.isEmpty()) {
318         ERRORF(reporter, "no tmp dir!");
319         return;
320     }
321     auto path = SkOSPath::Join(tmpdir.c_str(), "file");
322     {
323         SkFILEWStream wStream(path.c_str());
324         constexpr char filename[] = "images/baby_tux.webp";
325         auto data = GetResourceAsData(filename);
326         if (!data || data->size() == 0) {
327             ERRORF(reporter, "resource missing: %s\n", filename);
328             return;
329         }
330         if (!wStream.isValid() || !wStream.write(data->data(), data->size())) {
331             ERRORF(reporter, "error wrtiting to file %s", path.c_str());
332             return;
333         }
334     }
335     SkFILEStream fileStream(path.c_str());
336     REPORTER_ASSERT(reporter, fileStream.isValid());
337     if (!fileStream.isValid()) {
338         return;
339     }
340     SkAutoMalloc storage(fileStream.getLength());
341     for (size_t i = 1; i < fileStream.getLength(); i++) {
342         REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0);
343     }
344 
345 #ifdef SK_ENABLE_ANDROID_UTILS
346     // Now test some FrontBufferedStreams
347     for (size_t i = 1; i < memStream.getLength(); i++) {
348         test_peeking_front_buffered_stream(reporter, memStream, i);
349     }
350 #endif
351 }
352 #endif
353 
354 // Asserts that asset == expected and is peekable.
stream_peek_test(skiatest::Reporter * rep,SkStreamAsset * asset,const SkData * expected)355 static void stream_peek_test(skiatest::Reporter* rep,
356                              SkStreamAsset* asset,
357                              const SkData* expected) {
358     if (asset->getLength() != expected->size()) {
359         ERRORF(rep, "Unexpected length.");
360         return;
361     }
362     SkRandom rand;
363     uint8_t buffer[4096];
364     const uint8_t* expect = expected->bytes();
365     for (size_t i = 0; i < asset->getLength(); ++i) {
366         uint32_t maxSize =
367                 SkToU32(std::min(sizeof(buffer), asset->getLength() - i));
368         size_t size = rand.nextRangeU(1, maxSize);
369         SkASSERT(size >= 1);
370         SkASSERT(size <= sizeof(buffer));
371         SkASSERT(size + i <= asset->getLength());
372         if (asset->peek(buffer, size) < size) {
373             ERRORF(rep, "Peek Failed!");
374             return;
375         }
376         if (0 != memcmp(buffer, &expect[i], size)) {
377             ERRORF(rep, "Peek returned wrong bytes!");
378             return;
379         }
380         uint8_t value;
381         REPORTER_ASSERT(rep, 1 == asset->read(&value, 1));
382         if (value != expect[i]) {
383             ERRORF(rep, "Read Failed!");
384             return;
385         }
386     }
387 }
388 
DEF_TEST(StreamPeek_BlockMemoryStream,rep)389 DEF_TEST(StreamPeek_BlockMemoryStream, rep) {
390     const static int kSeed = 1234;
391     SkRandom valueSource(kSeed);
392     SkRandom rand(kSeed << 1);
393     uint8_t buffer[4096];
394     SkDynamicMemoryWStream dynamicMemoryWStream;
395     size_t totalWritten = 0;
396     for (int i = 0; i < 32; ++i) {
397         // Randomize the length of the blocks.
398         size_t size = rand.nextRangeU(1, sizeof(buffer));
399         for (size_t j = 0; j < size; ++j) {
400             buffer[j] = valueSource.nextU() & 0xFF;
401         }
402         dynamicMemoryWStream.write(buffer, size);
403         totalWritten += size;
404         REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten());
405     }
406     std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream());
407     sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength()));
408     uint8_t* expectedPtr = static_cast<uint8_t*>(expected->writable_data());
409     valueSource.setSeed(kSeed);  // reseed.
410     // We want the exact same same "random" string of numbers to put
411     // in expected. i.e.: don't rely on SkDynamicMemoryStream to work
412     // correctly while we are testing SkDynamicMemoryStream.
413     for (size_t i = 0; i < asset->getLength(); ++i) {
414         expectedPtr[i] = valueSource.nextU() & 0xFF;
415     }
416     stream_peek_test(rep, asset.get(), expected.get());
417 }
418 
DEF_TEST(StreamRemainingLengthIsBelow_MemoryStream,rep)419 DEF_TEST(StreamRemainingLengthIsBelow_MemoryStream, rep) {
420     SkMemoryStream stream(100);
421     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 0));
422     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 90));
423     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 100));
424 
425     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, 101));
426     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, ULONG_MAX));
427 
428     uint8_t buff[75];
429     REPORTER_ASSERT(rep, stream.read(buff, 75) == 75);
430 
431     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 0));
432     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 24));
433     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 25));
434 
435     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, 26));
436     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, 100));
437     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, ULONG_MAX));
438 }
439 
440 namespace {
441 class DumbStream : public SkStream {
442 public:
DumbStream(const uint8_t * data,size_t n)443     DumbStream(const uint8_t* data, size_t n)
444         : fData(data), fCount(n), fIdx(0) {}
read(void * buffer,size_t size)445     size_t read(void* buffer, size_t size) override {
446         size_t copyCount = std::min(fCount - fIdx, size);
447         if (copyCount) {
448             memcpy(buffer, &fData[fIdx], copyCount);
449             fIdx += copyCount;
450         }
451         return copyCount;
452     }
isAtEnd() const453     bool isAtEnd() const override {
454         return fCount == fIdx;
455     }
456  private:
457     const uint8_t* fData;
458     size_t fCount, fIdx;
459 };
460 }  // namespace
461 
stream_copy_test(skiatest::Reporter * reporter,const void * srcData,size_t N,SkStream * stream)462 static void stream_copy_test(skiatest::Reporter* reporter,
463                              const void* srcData,
464                              size_t N,
465                              SkStream* stream) {
466     SkDynamicMemoryWStream tgt;
467     if (!SkStreamCopy(&tgt, stream)) {
468         ERRORF(reporter, "SkStreamCopy failed");
469         return;
470     }
471     sk_sp<SkData> data(tgt.detachAsData());
472     if (data->size() != N) {
473         ERRORF(reporter, "SkStreamCopy incorrect size");
474         return;
475     }
476     if (0 != memcmp(data->data(), srcData, N)) {
477         ERRORF(reporter, "SkStreamCopy bad copy");
478     }
479 }
480 
DEF_TEST(DynamicMemoryWStream_detachAsData,r)481 DEF_TEST(DynamicMemoryWStream_detachAsData, r) {
482     const char az[] = "abcdefghijklmnopqrstuvwxyz";
483     const unsigned N = 40000;
484     SkDynamicMemoryWStream dmws;
485     for (unsigned i = 0; i < N; ++i) {
486         dmws.writeText(az);
487     }
488     REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az));
489     auto data = dmws.detachAsData();
490     REPORTER_ASSERT(r, data->size() == N * strlen(az));
491     const uint8_t* ptr = data->bytes();
492     for (unsigned i = 0; i < N; ++i) {
493         if (0 != memcmp(ptr, az, strlen(az))) {
494             ERRORF(r, "detachAsData() memcmp failed");
495             return;
496         }
497         ptr += strlen(az);
498     }
499 }
500 
DEF_TEST(StreamCopy,reporter)501 DEF_TEST(StreamCopy, reporter) {
502     SkRandom random(123456);
503     static const int N = 10000;
504     AutoTMalloc<uint8_t> src((size_t)N);
505     for (int j = 0; j < N; ++j) {
506         src[j] = random.nextU() & 0xff;
507     }
508     // SkStreamCopy had two code paths; this test both.
509     DumbStream dumbStream(src.get(), (size_t)N);
510     stream_copy_test(reporter, src, N, &dumbStream);
511     SkMemoryStream smartStream(src.get(), (size_t)N);
512     stream_copy_test(reporter, src, N, &smartStream);
513 }
514 
DEF_TEST(StreamEmptyStreamMemoryBase,r)515 DEF_TEST(StreamEmptyStreamMemoryBase, r) {
516     SkDynamicMemoryWStream tmp;
517     std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream());
518     REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
519 }
520 
DEF_TEST(FILEStreamWithOffset,r)521 DEF_TEST(FILEStreamWithOffset, r) {
522     if (GetResourcePath().isEmpty()) {
523         return;
524     }
525 
526     SkString filename = GetResourcePath("images/baby_tux.png");
527     SkFILEStream stream1(filename.c_str());
528     if (!stream1.isValid()) {
529         ERRORF(r, "Could not create SkFILEStream from %s", filename.c_str());
530         return;
531     }
532     REPORTER_ASSERT(r, stream1.hasLength());
533     REPORTER_ASSERT(r, stream1.hasPosition());
534 
535     // Seek halfway through the file. The second SkFILEStream will be created
536     // with the same filename and offset and therefore will treat that offset as
537     // the beginning.
538     const size_t size = stream1.getLength();
539     const size_t middle = size / 2;
540     if (!stream1.seek(middle)) {
541         ERRORF(r, "Could not seek SkFILEStream to %zu out of %zu", middle, size);
542         return;
543     }
544     REPORTER_ASSERT(r, stream1.getPosition() == middle);
545 
546     FILE* file = sk_fopen(filename.c_str(), kRead_SkFILE_Flag);
547     if (!file) {
548         ERRORF(r, "Could not open %s as a FILE", filename.c_str());
549         return;
550     }
551 
552     if (fseek(file, (long) middle, SEEK_SET) != 0) {
553         ERRORF(r, "Could not fseek FILE to %zu out of %zu", middle, size);
554         return;
555     }
556     SkFILEStream stream2(file);
557 
558     const size_t remaining = size - middle;
559     AutoTMalloc<uint8_t> expected(remaining);
560     REPORTER_ASSERT(r, stream1.read(expected.get(), remaining) == remaining);
561 
562     auto test_full_read = [&r, &expected, remaining](SkStream* stream) {
563         AutoTMalloc<uint8_t> actual(remaining);
564         REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
565         REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
566 
567         REPORTER_ASSERT(r, stream->getPosition() == stream->getLength());
568         REPORTER_ASSERT(r, stream->isAtEnd());
569     };
570 
571     auto test_rewind = [&r, &expected, remaining](SkStream* stream) {
572         // Rewind goes back to original offset.
573         REPORTER_ASSERT(r, stream->rewind());
574         REPORTER_ASSERT(r, stream->getPosition() == 0);
575         AutoTMalloc<uint8_t> actual(remaining);
576         REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
577         REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
578     };
579 
580     auto test_move = [&r, &expected, size, remaining](SkStream* stream) {
581         // Cannot move to before the original offset.
582         REPORTER_ASSERT(r, stream->move(- (long) size));
583         REPORTER_ASSERT(r, stream->getPosition() == 0);
584 
585         REPORTER_ASSERT(r, stream->move(std::numeric_limits<long>::min()));
586         REPORTER_ASSERT(r, stream->getPosition() == 0);
587 
588         AutoTMalloc<uint8_t> actual(remaining);
589         REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
590         REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
591 
592         REPORTER_ASSERT(r, stream->isAtEnd());
593         REPORTER_ASSERT(r, stream->getPosition() == remaining);
594 
595         // Cannot move beyond the end.
596         REPORTER_ASSERT(r, stream->move(1));
597         REPORTER_ASSERT(r, stream->isAtEnd());
598         REPORTER_ASSERT(r, stream->getPosition() == remaining);
599     };
600 
601     auto test_seek = [&r, &expected, middle, remaining](SkStream* stream) {
602         // Seek to an arbitrary position.
603         const size_t arbitrary = middle / 2;
604         REPORTER_ASSERT(r, stream->seek(arbitrary));
605         REPORTER_ASSERT(r, stream->getPosition() == arbitrary);
606         const size_t miniRemaining = remaining - arbitrary;
607         AutoTMalloc<uint8_t> actual(miniRemaining);
608         REPORTER_ASSERT(r, stream->read(actual.get(), miniRemaining) == miniRemaining);
609         REPORTER_ASSERT(r, !memcmp(expected.get() + arbitrary, actual.get(), miniRemaining));
610     };
611 
612     auto test_seek_beginning = [&r, &expected, remaining](SkStream* stream) {
613         // Seek to the beginning.
614         REPORTER_ASSERT(r, stream->seek(0));
615         REPORTER_ASSERT(r, stream->getPosition() == 0);
616         AutoTMalloc<uint8_t> actual(remaining);
617         REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
618         REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
619     };
620 
621     auto test_seek_end = [&r, remaining](SkStream* stream) {
622         // Cannot seek past the end.
623         REPORTER_ASSERT(r, stream->isAtEnd());
624 
625         REPORTER_ASSERT(r, stream->seek(remaining + 1));
626         REPORTER_ASSERT(r, stream->isAtEnd());
627         REPORTER_ASSERT(r, stream->getPosition() == remaining);
628 
629         const size_t middle = remaining / 2;
630         REPORTER_ASSERT(r, stream->seek(middle));
631         REPORTER_ASSERT(r, !stream->isAtEnd());
632         REPORTER_ASSERT(r, stream->getPosition() == middle);
633 
634         REPORTER_ASSERT(r, stream->seek(remaining * 2));
635         REPORTER_ASSERT(r, stream->isAtEnd());
636         REPORTER_ASSERT(r, stream->getPosition() == remaining);
637 
638         REPORTER_ASSERT(r, stream->seek(std::numeric_limits<long>::max()));
639         REPORTER_ASSERT(r, stream->isAtEnd());
640         REPORTER_ASSERT(r, stream->getPosition() == remaining);
641     };
642 
643 
644     std::function<void (SkStream* stream, bool recurse)> test_all;
645     test_all = [&](SkStream* stream, bool recurse) {
646         REPORTER_ASSERT(r, stream->getLength() == remaining);
647         REPORTER_ASSERT(r, stream->getPosition() == 0);
648 
649         test_full_read(stream);
650         test_rewind(stream);
651         test_move(stream);
652         test_seek(stream);
653         test_seek_beginning(stream);
654         test_seek_end(stream);
655 
656         if (recurse) {
657             // Duplicate shares the original offset.
658             auto duplicate = stream->duplicate();
659             if (!duplicate) {
660                 ERRORF(r, "Failed to duplicate the stream!");
661             } else {
662                 test_all(duplicate.get(), false);
663             }
664 
665             // Fork shares the original offset, too.
666             auto fork = stream->fork();
667             if (!fork) {
668                 ERRORF(r, "Failed to fork the stream!");
669             } else {
670                 REPORTER_ASSERT(r, fork->isAtEnd());
671                 REPORTER_ASSERT(r, fork->getLength() == remaining);
672                 REPORTER_ASSERT(r, fork->rewind());
673 
674                 test_all(fork.get(), false);
675             }
676         }
677     };
678 
679     test_all(&stream2, true);
680 }
681 
DEF_TEST(RBuffer,reporter)682 DEF_TEST(RBuffer, reporter) {
683     int32_t value = 0;
684     SkRBuffer buffer(&value, 4);
685     REPORTER_ASSERT(reporter, buffer.isValid());
686 
687     int32_t tmp;
688     REPORTER_ASSERT(reporter, buffer.read(&tmp, 4));
689     REPORTER_ASSERT(reporter, buffer.isValid());
690 
691     REPORTER_ASSERT(reporter, !buffer.read(&tmp, 4));
692     REPORTER_ASSERT(reporter, !buffer.isValid());
693 }
694