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