xref: /aosp_15_r20/external/skia/tests/StreamTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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(skiatest::Reporter * reporter,SkMemoryStream * memStream)191 static void TestDereferencingData(skiatest::Reporter* reporter, SkMemoryStream* memStream) {
192     REPORTER_ASSERT(reporter, memStream->read(nullptr, 0) == 0);
193     // Reading non-zero bytes from an empty stream should cleanly read zero bytes.
194     char buf[1];
195     REPORTER_ASSERT(reporter, memStream->read(buf, sizeof(buf)) == 0);
196     memStream->getMemoryBase();
197     (void)memStream->getData();
198 }
199 
TestNullData(skiatest::Reporter * reporter)200 static void TestNullData(skiatest::Reporter* reporter) {
201     SkMemoryStream memStream(nullptr);
202     TestDereferencingData(reporter, &memStream);
203 
204     memStream.setData(nullptr);
205     TestDereferencingData(reporter, &memStream);
206 
207 }
208 
DEF_TEST(Stream,reporter)209 DEF_TEST(Stream, reporter) {
210     TestWStream(reporter);
211     TestPackedUInt(reporter);
212     TestNullData(reporter);
213 }
214 
215 #ifndef SK_BUILD_FOR_IOS
216 /**
217  *  Tests peeking and then reading the same amount. The two should provide the
218  *  same results.
219  *  Returns the amount successfully read minus the amount successfully peeked.
220  */
compare_peek_to_read(skiatest::Reporter * reporter,SkStream * stream,size_t bytesToPeek)221 static size_t compare_peek_to_read(skiatest::Reporter* reporter,
222                                    SkStream* stream, size_t bytesToPeek) {
223     // The rest of our tests won't be very interesting if bytesToPeek is zero.
224     REPORTER_ASSERT(reporter, bytesToPeek > 0);
225     SkAutoMalloc peekStorage(bytesToPeek);
226     SkAutoMalloc readStorage(bytesToPeek);
227     void* peekPtr = peekStorage.get();
228     void* readPtr = peekStorage.get();
229 
230     const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek);
231     const size_t bytesRead = stream->read(readPtr, bytesToPeek);
232 
233     // bytesRead should only be less than attempted if the stream is at the
234     // end.
235     REPORTER_ASSERT(reporter, bytesRead == bytesToPeek || stream->isAtEnd());
236 
237     // peek and read should behave the same, except peek returned to the
238     // original position, so they read the same data.
239     REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked));
240 
241     // A stream should never be able to peek more than it can read.
242     REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked);
243 
244     return bytesRead - bytesPeeked;
245 }
246 
test_fully_peekable_stream(skiatest::Reporter * r,SkStream * stream,size_t limit)247 static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) {
248     for (size_t i = 1; !stream->isAtEnd(); i++) {
249         REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0);
250     }
251 }
252 
253 #ifdef SK_ENABLE_ANDROID_UTILS
test_peeking_front_buffered_stream(skiatest::Reporter * r,const SkStream & original,size_t bufferSize)254 static void test_peeking_front_buffered_stream(skiatest::Reporter* r,
255                                                const SkStream& original,
256                                                size_t bufferSize) {
257     std::unique_ptr<SkStream> dupe(original.duplicate());
258     REPORTER_ASSERT(r, dupe != nullptr);
259     auto bufferedStream = android::skia::FrontBufferedStream::Make(
260             std::move(dupe), bufferSize);
261     REPORTER_ASSERT(r, bufferedStream != nullptr);
262 
263     size_t peeked = 0;
264     for (size_t i = 1; !bufferedStream->isAtEnd(); i++) {
265         const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i);
266         if (unpeekableBytes > 0) {
267             // This could not have returned a number greater than i.
268             REPORTER_ASSERT(r, unpeekableBytes <= i);
269 
270             // We have reached the end of the buffer. Verify that it was at least
271             // bufferSize.
272             REPORTER_ASSERT(r, peeked + i - unpeekableBytes >= bufferSize);
273             // No more peeking is supported.
274             break;
275         }
276         peeked += i;
277     }
278 
279     // Test that attempting to peek beyond the length of the buffer does not prevent rewinding.
280     bufferedStream = android::skia::FrontBufferedStream::Make(original.duplicate(), bufferSize);
281     REPORTER_ASSERT(r, bufferedStream != nullptr);
282 
283     const size_t bytesToPeek = bufferSize + 1;
284     SkAutoMalloc peekStorage(bytesToPeek);
285     SkAutoMalloc readStorage(bytesToPeek);
286 
287     for (size_t start = 0; start <= bufferSize; start++) {
288         // Skip to the starting point
289         REPORTER_ASSERT(r, bufferedStream->skip(start) == start);
290 
291         const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek);
292         if (0 == bytesPeeked) {
293             // Peeking should only fail completely if we have read/skipped beyond the buffer.
294             REPORTER_ASSERT(r, start >= bufferSize);
295             break;
296         }
297 
298         // Only read the amount that was successfully peeked.
299         const size_t bytesRead = bufferedStream->read(readStorage.get(), bytesPeeked);
300         REPORTER_ASSERT(r, bytesRead == bytesPeeked);
301         REPORTER_ASSERT(r, !memcmp(peekStorage.get(), readStorage.get(), bytesPeeked));
302 
303         // This should be safe to rewind.
304         REPORTER_ASSERT(r, bufferedStream->rewind());
305     }
306 }
307 #endif
308 
309 // This test uses file system operations that don't work out of the
310 // box on iOS. It's likely that we don't need them on iOS. Ignoring for now.
311 // TODO(stephana): Re-evaluate if we need this in the future.
DEF_TEST(StreamPeek,reporter)312 DEF_TEST(StreamPeek, reporter) {
313     // Test a memory stream.
314     const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz";
315     SkMemoryStream memStream(gAbcs, strlen(gAbcs), false);
316     test_fully_peekable_stream(reporter, &memStream, memStream.getLength());
317 
318     // Test an arbitrary file stream. file streams do not support peeking.
319     auto tmpdir = skiatest::GetTmpDir();
320     if (tmpdir.isEmpty()) {
321         ERRORF(reporter, "no tmp dir!");
322         return;
323     }
324     auto path = SkOSPath::Join(tmpdir.c_str(), "file");
325     {
326         SkFILEWStream wStream(path.c_str());
327         constexpr char filename[] = "images/baby_tux.webp";
328         auto data = GetResourceAsData(filename);
329         if (!data || data->size() == 0) {
330             ERRORF(reporter, "resource missing: %s\n", filename);
331             return;
332         }
333         if (!wStream.isValid() || !wStream.write(data->data(), data->size())) {
334             ERRORF(reporter, "error wrtiting to file %s", path.c_str());
335             return;
336         }
337     }
338     SkFILEStream fileStream(path.c_str());
339     REPORTER_ASSERT(reporter, fileStream.isValid());
340     if (!fileStream.isValid()) {
341         return;
342     }
343     SkAutoMalloc storage(fileStream.getLength());
344     for (size_t i = 1; i < fileStream.getLength(); i++) {
345         REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0);
346     }
347 
348 #ifdef SK_ENABLE_ANDROID_UTILS
349     // Now test some FrontBufferedStreams
350     for (size_t i = 1; i < memStream.getLength(); i++) {
351         test_peeking_front_buffered_stream(reporter, memStream, i);
352     }
353 #endif
354 }
355 #endif
356 
357 // Asserts that asset == expected and is peekable.
stream_peek_test(skiatest::Reporter * rep,SkStreamAsset * asset,const SkData * expected)358 static void stream_peek_test(skiatest::Reporter* rep,
359                              SkStreamAsset* asset,
360                              const SkData* expected) {
361     if (asset->getLength() != expected->size()) {
362         ERRORF(rep, "Unexpected length.");
363         return;
364     }
365     SkRandom rand;
366     uint8_t buffer[4096];
367     const uint8_t* expect = expected->bytes();
368     for (size_t i = 0; i < asset->getLength(); ++i) {
369         uint32_t maxSize =
370                 SkToU32(std::min(sizeof(buffer), asset->getLength() - i));
371         size_t size = rand.nextRangeU(1, maxSize);
372         SkASSERT(size >= 1);
373         SkASSERT(size <= sizeof(buffer));
374         SkASSERT(size + i <= asset->getLength());
375         if (asset->peek(buffer, size) < size) {
376             ERRORF(rep, "Peek Failed!");
377             return;
378         }
379         if (0 != memcmp(buffer, &expect[i], size)) {
380             ERRORF(rep, "Peek returned wrong bytes!");
381             return;
382         }
383         uint8_t value;
384         REPORTER_ASSERT(rep, 1 == asset->read(&value, 1));
385         if (value != expect[i]) {
386             ERRORF(rep, "Read Failed!");
387             return;
388         }
389     }
390 }
391 
DEF_TEST(StreamPeek_BlockMemoryStream,rep)392 DEF_TEST(StreamPeek_BlockMemoryStream, rep) {
393     const static int kSeed = 1234;
394     SkRandom valueSource(kSeed);
395     SkRandom rand(kSeed << 1);
396     uint8_t buffer[4096];
397     SkDynamicMemoryWStream dynamicMemoryWStream;
398     size_t totalWritten = 0;
399     for (int i = 0; i < 32; ++i) {
400         // Randomize the length of the blocks.
401         size_t size = rand.nextRangeU(1, sizeof(buffer));
402         for (size_t j = 0; j < size; ++j) {
403             buffer[j] = valueSource.nextU() & 0xFF;
404         }
405         dynamicMemoryWStream.write(buffer, size);
406         totalWritten += size;
407         REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten());
408     }
409     std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream());
410     sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength()));
411     uint8_t* expectedPtr = static_cast<uint8_t*>(expected->writable_data());
412     valueSource.setSeed(kSeed);  // reseed.
413     // We want the exact same same "random" string of numbers to put
414     // in expected. i.e.: don't rely on SkDynamicMemoryStream to work
415     // correctly while we are testing SkDynamicMemoryStream.
416     for (size_t i = 0; i < asset->getLength(); ++i) {
417         expectedPtr[i] = valueSource.nextU() & 0xFF;
418     }
419     stream_peek_test(rep, asset.get(), expected.get());
420 }
421 
DEF_TEST(StreamRemainingLengthIsBelow_MemoryStream,rep)422 DEF_TEST(StreamRemainingLengthIsBelow_MemoryStream, rep) {
423     SkMemoryStream stream(100);
424     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 0));
425     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 90));
426     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 100));
427 
428     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, 101));
429     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, ULONG_MAX));
430 
431     uint8_t buff[75];
432     REPORTER_ASSERT(rep, stream.read(buff, 75) == 75);
433 
434     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 0));
435     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 24));
436     REPORTER_ASSERT(rep, !StreamRemainingLengthIsBelow(&stream, 25));
437 
438     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, 26));
439     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, 100));
440     REPORTER_ASSERT(rep, StreamRemainingLengthIsBelow(&stream, ULONG_MAX));
441 }
442 
443 namespace {
444 class DumbStream : public SkStream {
445 public:
DumbStream(const uint8_t * data,size_t n)446     DumbStream(const uint8_t* data, size_t n)
447         : fData(data), fCount(n), fIdx(0) {}
read(void * buffer,size_t size)448     size_t read(void* buffer, size_t size) override {
449         size_t copyCount = std::min(fCount - fIdx, size);
450         if (copyCount) {
451             memcpy(buffer, &fData[fIdx], copyCount);
452             fIdx += copyCount;
453         }
454         return copyCount;
455     }
isAtEnd() const456     bool isAtEnd() const override {
457         return fCount == fIdx;
458     }
459  private:
460     const uint8_t* fData;
461     size_t fCount, fIdx;
462 };
463 }  // namespace
464 
stream_copy_test(skiatest::Reporter * reporter,const void * srcData,size_t N,SkStream * stream)465 static void stream_copy_test(skiatest::Reporter* reporter,
466                              const void* srcData,
467                              size_t N,
468                              SkStream* stream) {
469     SkDynamicMemoryWStream tgt;
470     if (!SkStreamCopy(&tgt, stream)) {
471         ERRORF(reporter, "SkStreamCopy failed");
472         return;
473     }
474     sk_sp<SkData> data(tgt.detachAsData());
475     if (data->size() != N) {
476         ERRORF(reporter, "SkStreamCopy incorrect size");
477         return;
478     }
479     if (0 != memcmp(data->data(), srcData, N)) {
480         ERRORF(reporter, "SkStreamCopy bad copy");
481     }
482 }
483 
DEF_TEST(DynamicMemoryWStream_detachAsData,r)484 DEF_TEST(DynamicMemoryWStream_detachAsData, r) {
485     const char az[] = "abcdefghijklmnopqrstuvwxyz";
486     const unsigned N = 40000;
487     SkDynamicMemoryWStream dmws;
488     for (unsigned i = 0; i < N; ++i) {
489         dmws.writeText(az);
490     }
491     REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az));
492     auto data = dmws.detachAsData();
493     REPORTER_ASSERT(r, data->size() == N * strlen(az));
494     const uint8_t* ptr = data->bytes();
495     for (unsigned i = 0; i < N; ++i) {
496         if (0 != memcmp(ptr, az, strlen(az))) {
497             ERRORF(r, "detachAsData() memcmp failed");
498             return;
499         }
500         ptr += strlen(az);
501     }
502 }
503 
DEF_TEST(StreamCopy,reporter)504 DEF_TEST(StreamCopy, reporter) {
505     SkRandom random(123456);
506     static const int N = 10000;
507     AutoTMalloc<uint8_t> src((size_t)N);
508     for (int j = 0; j < N; ++j) {
509         src[j] = random.nextU() & 0xff;
510     }
511     // SkStreamCopy had two code paths; this test both.
512     DumbStream dumbStream(src.get(), (size_t)N);
513     stream_copy_test(reporter, src, N, &dumbStream);
514     SkMemoryStream smartStream(src.get(), (size_t)N);
515     stream_copy_test(reporter, src, N, &smartStream);
516 }
517 
DEF_TEST(StreamEmptyStreamMemoryBase,r)518 DEF_TEST(StreamEmptyStreamMemoryBase, r) {
519     SkDynamicMemoryWStream tmp;
520     std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream());
521     REPORTER_ASSERT(r, nullptr == asset->getMemoryBase());
522 }
523 
DEF_TEST(FILEStreamWithOffset,r)524 DEF_TEST(FILEStreamWithOffset, r) {
525     if (GetResourcePath().isEmpty()) {
526         return;
527     }
528 
529     SkString filename = GetResourcePath("images/baby_tux.png");
530     SkFILEStream stream1(filename.c_str());
531     if (!stream1.isValid()) {
532         ERRORF(r, "Could not create SkFILEStream from %s", filename.c_str());
533         return;
534     }
535     REPORTER_ASSERT(r, stream1.hasLength());
536     REPORTER_ASSERT(r, stream1.hasPosition());
537 
538     // Seek halfway through the file. The second SkFILEStream will be created
539     // with the same filename and offset and therefore will treat that offset as
540     // the beginning.
541     const size_t size = stream1.getLength();
542     const size_t middle = size / 2;
543     if (!stream1.seek(middle)) {
544         ERRORF(r, "Could not seek SkFILEStream to %zu out of %zu", middle, size);
545         return;
546     }
547     REPORTER_ASSERT(r, stream1.getPosition() == middle);
548 
549     FILE* file = sk_fopen(filename.c_str(), kRead_SkFILE_Flag);
550     if (!file) {
551         ERRORF(r, "Could not open %s as a FILE", filename.c_str());
552         return;
553     }
554 
555     if (fseek(file, (long) middle, SEEK_SET) != 0) {
556         ERRORF(r, "Could not fseek FILE to %zu out of %zu", middle, size);
557         return;
558     }
559     SkFILEStream stream2(file);
560 
561     const size_t remaining = size - middle;
562     AutoTMalloc<uint8_t> expected(remaining);
563     REPORTER_ASSERT(r, stream1.read(expected.get(), remaining) == remaining);
564 
565     auto test_full_read = [&r, &expected, remaining](SkStream* stream) {
566         AutoTMalloc<uint8_t> actual(remaining);
567         REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
568         REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
569 
570         REPORTER_ASSERT(r, stream->getPosition() == stream->getLength());
571         REPORTER_ASSERT(r, stream->isAtEnd());
572     };
573 
574     auto test_rewind = [&r, &expected, remaining](SkStream* stream) {
575         // Rewind goes back to original offset.
576         REPORTER_ASSERT(r, stream->rewind());
577         REPORTER_ASSERT(r, stream->getPosition() == 0);
578         AutoTMalloc<uint8_t> actual(remaining);
579         REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
580         REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
581     };
582 
583     auto test_move = [&r, &expected, size, remaining](SkStream* stream) {
584         // Cannot move to before the original offset.
585         REPORTER_ASSERT(r, stream->move(- (long) size));
586         REPORTER_ASSERT(r, stream->getPosition() == 0);
587 
588         REPORTER_ASSERT(r, stream->move(std::numeric_limits<long>::min()));
589         REPORTER_ASSERT(r, stream->getPosition() == 0);
590 
591         AutoTMalloc<uint8_t> actual(remaining);
592         REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
593         REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
594 
595         REPORTER_ASSERT(r, stream->isAtEnd());
596         REPORTER_ASSERT(r, stream->getPosition() == remaining);
597 
598         // Cannot move beyond the end.
599         REPORTER_ASSERT(r, stream->move(1));
600         REPORTER_ASSERT(r, stream->isAtEnd());
601         REPORTER_ASSERT(r, stream->getPosition() == remaining);
602     };
603 
604     auto test_seek = [&r, &expected, middle, remaining](SkStream* stream) {
605         // Seek to an arbitrary position.
606         const size_t arbitrary = middle / 2;
607         REPORTER_ASSERT(r, stream->seek(arbitrary));
608         REPORTER_ASSERT(r, stream->getPosition() == arbitrary);
609         const size_t miniRemaining = remaining - arbitrary;
610         AutoTMalloc<uint8_t> actual(miniRemaining);
611         REPORTER_ASSERT(r, stream->read(actual.get(), miniRemaining) == miniRemaining);
612         REPORTER_ASSERT(r, !memcmp(expected.get() + arbitrary, actual.get(), miniRemaining));
613     };
614 
615     auto test_seek_beginning = [&r, &expected, remaining](SkStream* stream) {
616         // Seek to the beginning.
617         REPORTER_ASSERT(r, stream->seek(0));
618         REPORTER_ASSERT(r, stream->getPosition() == 0);
619         AutoTMalloc<uint8_t> actual(remaining);
620         REPORTER_ASSERT(r, stream->read(actual.get(), remaining) == remaining);
621         REPORTER_ASSERT(r, !memcmp(expected.get(), actual.get(), remaining));
622     };
623 
624     auto test_seek_end = [&r, remaining](SkStream* stream) {
625         // Cannot seek past the end.
626         REPORTER_ASSERT(r, stream->isAtEnd());
627 
628         REPORTER_ASSERT(r, stream->seek(remaining + 1));
629         REPORTER_ASSERT(r, stream->isAtEnd());
630         REPORTER_ASSERT(r, stream->getPosition() == remaining);
631 
632         const size_t middle = remaining / 2;
633         REPORTER_ASSERT(r, stream->seek(middle));
634         REPORTER_ASSERT(r, !stream->isAtEnd());
635         REPORTER_ASSERT(r, stream->getPosition() == middle);
636 
637         REPORTER_ASSERT(r, stream->seek(remaining * 2));
638         REPORTER_ASSERT(r, stream->isAtEnd());
639         REPORTER_ASSERT(r, stream->getPosition() == remaining);
640 
641         REPORTER_ASSERT(r, stream->seek(std::numeric_limits<long>::max()));
642         REPORTER_ASSERT(r, stream->isAtEnd());
643         REPORTER_ASSERT(r, stream->getPosition() == remaining);
644     };
645 
646 
647     std::function<void (SkStream* stream, bool recurse)> test_all;
648     test_all = [&](SkStream* stream, bool recurse) {
649         REPORTER_ASSERT(r, stream->getLength() == remaining);
650         REPORTER_ASSERT(r, stream->getPosition() == 0);
651 
652         test_full_read(stream);
653         test_rewind(stream);
654         test_move(stream);
655         test_seek(stream);
656         test_seek_beginning(stream);
657         test_seek_end(stream);
658 
659         if (recurse) {
660             // Duplicate shares the original offset.
661             auto duplicate = stream->duplicate();
662             if (!duplicate) {
663                 ERRORF(r, "Failed to duplicate the stream!");
664             } else {
665                 test_all(duplicate.get(), false);
666             }
667 
668             // Fork shares the original offset, too.
669             auto fork = stream->fork();
670             if (!fork) {
671                 ERRORF(r, "Failed to fork the stream!");
672             } else {
673                 REPORTER_ASSERT(r, fork->isAtEnd());
674                 REPORTER_ASSERT(r, fork->getLength() == remaining);
675                 REPORTER_ASSERT(r, fork->rewind());
676 
677                 test_all(fork.get(), false);
678             }
679         }
680     };
681 
682     test_all(&stream2, true);
683 }
684 
DEF_TEST(RBuffer,reporter)685 DEF_TEST(RBuffer, reporter) {
686     int32_t value = 0;
687     SkRBuffer buffer(&value, 4);
688     REPORTER_ASSERT(reporter, buffer.isValid());
689 
690     int32_t tmp;
691     REPORTER_ASSERT(reporter, buffer.read(&tmp, 4));
692     REPORTER_ASSERT(reporter, buffer.isValid());
693 
694     REPORTER_ASSERT(reporter, !buffer.read(&tmp, 4));
695     REPORTER_ASSERT(reporter, !buffer.isValid());
696 }
697