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