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 #ifndef SK_BUILD_FOR_WIN 20 #include <unistd.h> 21 #include <fcntl.h> 22 #endif 23 24 #define MAX_SIZE (256 * 1024) 25 26 static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream, 27 const void* src, size_t len, int repeat) { 28 SkAutoSMalloc<256> storage(len); 29 void* tmp = storage.get(); 30 31 for (int i = 0; i < repeat; ++i) { 32 size_t bytes = stream->read(tmp, len); 33 REPORTER_ASSERT(reporter, bytes == len); 34 REPORTER_ASSERT(reporter, !memcmp(tmp, src, len)); 35 } 36 37 // expect EOF 38 size_t bytes = stream->read(tmp, 1); 39 REPORTER_ASSERT(reporter, 0 == bytes); 40 // isAtEnd might not return true until after the first failing read. 41 REPORTER_ASSERT(reporter, stream->isAtEnd()); 42 } 43 44 static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) { 45 SkString path = SkOSPath::Join(tmpDir, "wstream_test"); 46 47 const char s[] = "abcdefghijklmnopqrstuvwxyz"; 48 49 { 50 SkFILEWStream writer(path.c_str()); 51 if (!writer.isValid()) { 52 ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str()); 53 return; 54 } 55 56 for (int i = 0; i < 100; ++i) { 57 writer.write(s, 26); 58 } 59 } 60 61 { 62 SkFILEStream stream(path.c_str()); 63 REPORTER_ASSERT(reporter, stream.isValid()); 64 test_loop_stream(reporter, &stream, s, 26, 100); 65 66 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate()); 67 test_loop_stream(reporter, stream2.get(), s, 26, 100); 68 } 69 70 { 71 FILE* file = ::fopen(path.c_str(), "rb"); 72 SkFILEStream stream(file); 73 REPORTER_ASSERT(reporter, stream.isValid()); 74 test_loop_stream(reporter, &stream, s, 26, 100); 75 76 std::unique_ptr<SkStreamAsset> stream2(stream.duplicate()); 77 test_loop_stream(reporter, stream2.get(), s, 26, 100); 78 } 79 } 80 81 static void TestWStream(skiatest::Reporter* reporter) { 82 SkDynamicMemoryWStream ds; 83 const char s[] = "abcdefghijklmnopqrstuvwxyz"; 84 int i; 85 for (i = 0; i < 100; i++) { 86 REPORTER_ASSERT(reporter, ds.write(s, 26)); 87 } 88 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26); 89 90 char* dst = new char[100 * 26 + 1]; 91 dst[100*26] = '*'; 92 ds.copyTo(dst); 93 REPORTER_ASSERT(reporter, dst[100*26] == '*'); 94 for (i = 0; i < 100; i++) { 95 REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0); 96 } 97 98 { 99 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream()); 100 REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength()); 101 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0); 102 test_loop_stream(reporter, stream.get(), s, 26, 100); 103 104 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate()); 105 test_loop_stream(reporter, stream2.get(), s, 26, 100); 106 107 std::unique_ptr<SkStreamAsset> stream3(stream->fork()); 108 REPORTER_ASSERT(reporter, stream3->isAtEnd()); 109 char tmp; 110 size_t bytes = stream->read(&tmp, 1); 111 REPORTER_ASSERT(reporter, 0 == bytes); 112 stream3->rewind(); 113 test_loop_stream(reporter, stream3.get(), s, 26, 100); 114 } 115 116 for (i = 0; i < 100; i++) { 117 REPORTER_ASSERT(reporter, ds.write(s, 26)); 118 } 119 REPORTER_ASSERT(reporter, ds.bytesWritten() == 100 * 26); 120 121 { 122 // Test that this works after a snapshot. 123 std::unique_ptr<SkStreamAsset> stream(ds.detachAsStream()); 124 REPORTER_ASSERT(reporter, ds.bytesWritten() == 0); 125 test_loop_stream(reporter, stream.get(), s, 26, 100); 126 127 std::unique_ptr<SkStreamAsset> stream2(stream->duplicate()); 128 test_loop_stream(reporter, stream2.get(), s, 26, 100); 129 } 130 delete[] dst; 131 132 SkString tmpDir = skiatest::GetTmpDir(); 133 if (!tmpDir.isEmpty()) { 134 test_filestreams(reporter, tmpDir.c_str()); 135 } 136 } 137 138 static void TestPackedUInt(skiatest::Reporter* reporter) { 139 // we know that packeduint tries to write 1, 2 or 4 bytes for the length, 140 // so we test values around each of those transitions (and a few others) 141 const size_t sizes[] = { 142 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769, 143 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001, 144 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001, 145 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF 146 }; 147 148 149 size_t i; 150 SkDynamicMemoryWStream wstream; 151 152 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) { 153 bool success = wstream.writePackedUInt(sizes[i]); 154 REPORTER_ASSERT(reporter, success); 155 } 156 157 std::unique_ptr<SkStreamAsset> rstream(wstream.detachAsStream()); 158 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) { 159 size_t n = rstream->readPackedUInt(); 160 if (sizes[i] != n) { 161 ERRORF(reporter, "sizes:%x != n:%x\n", i, sizes[i], n); 162 } 163 } 164 } 165 166 // Test that setting an SkMemoryStream to a nullptr data does not result in a crash when calling 167 // methods that access fData. 168 static void TestDereferencingData(SkMemoryStream* memStream) { 169 memStream->read(nullptr, 0); 170 memStream->getMemoryBase(); 171 (void)memStream->asData(); 172 } 173 174 static void TestNullData() { 175 SkMemoryStream memStream(nullptr); 176 TestDereferencingData(&memStream); 177 178 memStream.setData(nullptr); 179 TestDereferencingData(&memStream); 180 181 } 182 183 DEF_TEST(Stream, reporter) { 184 TestWStream(reporter); 185 TestPackedUInt(reporter); 186 TestNullData(); 187 } 188 189 #ifndef SK_BUILD_FOR_IOS 190 /** 191 * Tests peeking and then reading the same amount. The two should provide the 192 * same results. 193 * Returns the amount successfully read minus the amount successfully peeked. 194 */ 195 static size_t compare_peek_to_read(skiatest::Reporter* reporter, 196 SkStream* stream, size_t bytesToPeek) { 197 // The rest of our tests won't be very interesting if bytesToPeek is zero. 198 REPORTER_ASSERT(reporter, bytesToPeek > 0); 199 SkAutoMalloc peekStorage(bytesToPeek); 200 SkAutoMalloc readStorage(bytesToPeek); 201 void* peekPtr = peekStorage.get(); 202 void* readPtr = peekStorage.get(); 203 204 const size_t bytesPeeked = stream->peek(peekPtr, bytesToPeek); 205 const size_t bytesRead = stream->read(readPtr, bytesToPeek); 206 207 // bytesRead should only be less than attempted if the stream is at the 208 // end. 209 REPORTER_ASSERT(reporter, bytesRead == bytesToPeek || stream->isAtEnd()); 210 211 // peek and read should behave the same, except peek returned to the 212 // original position, so they read the same data. 213 REPORTER_ASSERT(reporter, !memcmp(peekPtr, readPtr, bytesPeeked)); 214 215 // A stream should never be able to peek more than it can read. 216 REPORTER_ASSERT(reporter, bytesRead >= bytesPeeked); 217 218 return bytesRead - bytesPeeked; 219 } 220 221 static void test_fully_peekable_stream(skiatest::Reporter* r, SkStream* stream, size_t limit) { 222 for (size_t i = 1; !stream->isAtEnd(); i++) { 223 REPORTER_ASSERT(r, compare_peek_to_read(r, stream, i) == 0); 224 } 225 } 226 227 static void test_peeking_front_buffered_stream(skiatest::Reporter* r, 228 const SkStream& original, 229 size_t bufferSize) { 230 SkStream* dupe = original.duplicate(); 231 REPORTER_ASSERT(r, dupe != nullptr); 232 std::unique_ptr<SkStream> bufferedStream(SkFrontBufferedStream::Create(dupe, bufferSize)); 233 REPORTER_ASSERT(r, bufferedStream != nullptr); 234 235 size_t peeked = 0; 236 for (size_t i = 1; !bufferedStream->isAtEnd(); i++) { 237 const size_t unpeekableBytes = compare_peek_to_read(r, bufferedStream.get(), i); 238 if (unpeekableBytes > 0) { 239 // This could not have returned a number greater than i. 240 REPORTER_ASSERT(r, unpeekableBytes <= i); 241 242 // We have reached the end of the buffer. Verify that it was at least 243 // bufferSize. 244 REPORTER_ASSERT(r, peeked + i - unpeekableBytes >= bufferSize); 245 // No more peeking is supported. 246 break; 247 } 248 peeked += i; 249 } 250 251 // Test that attempting to peek beyond the length of the buffer does not prevent rewinding. 252 bufferedStream.reset(SkFrontBufferedStream::Create(original.duplicate(), bufferSize)); 253 REPORTER_ASSERT(r, bufferedStream != nullptr); 254 255 const size_t bytesToPeek = bufferSize + 1; 256 SkAutoMalloc peekStorage(bytesToPeek); 257 SkAutoMalloc readStorage(bytesToPeek); 258 259 for (size_t start = 0; start <= bufferSize; start++) { 260 // Skip to the starting point 261 REPORTER_ASSERT(r, bufferedStream->skip(start) == start); 262 263 const size_t bytesPeeked = bufferedStream->peek(peekStorage.get(), bytesToPeek); 264 if (0 == bytesPeeked) { 265 // Peeking should only fail completely if we have read/skipped beyond the buffer. 266 REPORTER_ASSERT(r, start >= bufferSize); 267 break; 268 } 269 270 // Only read the amount that was successfully peeked. 271 const size_t bytesRead = bufferedStream->read(readStorage.get(), bytesPeeked); 272 REPORTER_ASSERT(r, bytesRead == bytesPeeked); 273 REPORTER_ASSERT(r, !memcmp(peekStorage.get(), readStorage.get(), bytesPeeked)); 274 275 // This should be safe to rewind. 276 REPORTER_ASSERT(r, bufferedStream->rewind()); 277 } 278 } 279 280 // This test uses file system operations that don't work out of the 281 // box on iOS. It's likely that we don't need them on iOS. Ignoring for now. 282 // TODO(stephana): Re-evaluate if we need this in the future. 283 DEF_TEST(StreamPeek, reporter) { 284 // Test a memory stream. 285 const char gAbcs[] = "abcdefghijklmnopqrstuvwxyz"; 286 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false); 287 test_fully_peekable_stream(reporter, &memStream, memStream.getLength()); 288 289 // Test an arbitrary file stream. file streams do not support peeking. 290 SkFILEStream fileStream(GetResourcePath("baby_tux.webp").c_str()); 291 REPORTER_ASSERT(reporter, fileStream.isValid()); 292 if (!fileStream.isValid()) { 293 return; 294 } 295 SkAutoMalloc storage(fileStream.getLength()); 296 for (size_t i = 1; i < fileStream.getLength(); i++) { 297 REPORTER_ASSERT(reporter, fileStream.peek(storage.get(), i) == 0); 298 } 299 300 // Now test some FrontBufferedStreams 301 for (size_t i = 1; i < memStream.getLength(); i++) { 302 test_peeking_front_buffered_stream(reporter, memStream, i); 303 } 304 } 305 #endif 306 307 // Asserts that asset == expected and is peekable. 308 static void stream_peek_test(skiatest::Reporter* rep, 309 SkStreamAsset* asset, 310 const SkData* expected) { 311 if (asset->getLength() != expected->size()) { 312 ERRORF(rep, "Unexpected length."); 313 return; 314 } 315 SkRandom rand; 316 uint8_t buffer[4096]; 317 const uint8_t* expect = expected->bytes(); 318 for (size_t i = 0; i < asset->getLength(); ++i) { 319 uint32_t maxSize = 320 SkToU32(SkTMin(sizeof(buffer), asset->getLength() - i)); 321 size_t size = rand.nextRangeU(1, maxSize); 322 SkASSERT(size >= 1); 323 SkASSERT(size <= sizeof(buffer)); 324 SkASSERT(size + i <= asset->getLength()); 325 if (asset->peek(buffer, size) < size) { 326 ERRORF(rep, "Peek Failed!"); 327 return; 328 } 329 if (0 != memcmp(buffer, &expect[i], size)) { 330 ERRORF(rep, "Peek returned wrong bytes!"); 331 return; 332 } 333 uint8_t value; 334 REPORTER_ASSERT(rep, 1 == asset->read(&value, 1)); 335 if (value != expect[i]) { 336 ERRORF(rep, "Read Failed!"); 337 return; 338 } 339 } 340 } 341 342 DEF_TEST(StreamPeek_BlockMemoryStream, rep) { 343 const static int kSeed = 1234; 344 SkRandom valueSource(kSeed); 345 SkRandom rand(kSeed << 1); 346 uint8_t buffer[4096]; 347 SkDynamicMemoryWStream dynamicMemoryWStream; 348 size_t totalWritten = 0; 349 for (int i = 0; i < 32; ++i) { 350 // Randomize the length of the blocks. 351 size_t size = rand.nextRangeU(1, sizeof(buffer)); 352 for (size_t j = 0; j < size; ++j) { 353 buffer[j] = valueSource.nextU() & 0xFF; 354 } 355 dynamicMemoryWStream.write(buffer, size); 356 totalWritten += size; 357 REPORTER_ASSERT(rep, totalWritten == dynamicMemoryWStream.bytesWritten()); 358 } 359 std::unique_ptr<SkStreamAsset> asset(dynamicMemoryWStream.detachAsStream()); 360 sk_sp<SkData> expected(SkData::MakeUninitialized(asset->getLength())); 361 uint8_t* expectedPtr = static_cast<uint8_t*>(expected->writable_data()); 362 valueSource.setSeed(kSeed); // reseed. 363 // We want the exact same same "random" string of numbers to put 364 // in expected. i.e.: don't rely on SkDynamicMemoryStream to work 365 // correctly while we are testing SkDynamicMemoryStream. 366 for (size_t i = 0; i < asset->getLength(); ++i) { 367 expectedPtr[i] = valueSource.nextU() & 0xFF; 368 } 369 stream_peek_test(rep, asset.get(), expected.get()); 370 } 371 372 namespace { 373 class DumbStream : public SkStream { 374 public: 375 DumbStream(const uint8_t* data, size_t n) 376 : fData(data), fCount(n), fIdx(0) {} 377 size_t read(void* buffer, size_t size) override { 378 size_t copyCount = SkTMin(fCount - fIdx, size); 379 if (copyCount) { 380 memcpy(buffer, &fData[fIdx], copyCount); 381 fIdx += copyCount; 382 } 383 return copyCount; 384 } 385 bool isAtEnd() const override { 386 return fCount == fIdx; 387 } 388 private: 389 const uint8_t* fData; 390 size_t fCount, fIdx; 391 }; 392 } // namespace 393 394 static void stream_copy_test(skiatest::Reporter* reporter, 395 const void* srcData, 396 size_t N, 397 SkStream* stream) { 398 SkDynamicMemoryWStream tgt; 399 if (!SkStreamCopy(&tgt, stream)) { 400 ERRORF(reporter, "SkStreamCopy failed"); 401 return; 402 } 403 sk_sp<SkData> data(tgt.detachAsData()); 404 if (data->size() != N) { 405 ERRORF(reporter, "SkStreamCopy incorrect size"); 406 return; 407 } 408 if (0 != memcmp(data->data(), srcData, N)) { 409 ERRORF(reporter, "SkStreamCopy bad copy"); 410 } 411 } 412 413 DEF_TEST(DynamicMemoryWStream_detachAsData, r) { 414 const char az[] = "abcdefghijklmnopqrstuvwxyz"; 415 const unsigned N = 40000; 416 SkDynamicMemoryWStream dmws; 417 for (unsigned i = 0; i < N; ++i) { 418 dmws.writeText(az); 419 } 420 REPORTER_ASSERT(r, dmws.bytesWritten() == N * strlen(az)); 421 auto data = dmws.detachAsData(); 422 REPORTER_ASSERT(r, data->size() == N * strlen(az)); 423 const uint8_t* ptr = data->bytes(); 424 for (unsigned i = 0; i < N; ++i) { 425 if (0 != memcmp(ptr, az, strlen(az))) { 426 ERRORF(r, "detachAsData() memcmp failed"); 427 return; 428 } 429 ptr += strlen(az); 430 } 431 } 432 433 DEF_TEST(StreamCopy, reporter) { 434 SkRandom random(123456); 435 static const int N = 10000; 436 SkAutoTMalloc<uint8_t> src((size_t)N); 437 for (int j = 0; j < N; ++j) { 438 src[j] = random.nextU() & 0xff; 439 } 440 // SkStreamCopy had two code paths; this test both. 441 DumbStream dumbStream(src.get(), (size_t)N); 442 stream_copy_test(reporter, src, N, &dumbStream); 443 SkMemoryStream smartStream(src.get(), (size_t)N); 444 stream_copy_test(reporter, src, N, &smartStream); 445 } 446 447 DEF_TEST(StreamEmptyStreamMemoryBase, r) { 448 SkDynamicMemoryWStream tmp; 449 std::unique_ptr<SkStreamAsset> asset(tmp.detachAsStream()); 450 REPORTER_ASSERT(r, nullptr == asset->getMemoryBase()); 451 } 452 453 #include "SkBuffer.h" 454 455 DEF_TEST(RBuffer, reporter) { 456 int32_t value = 0; 457 SkRBuffer buffer(&value, 4); 458 REPORTER_ASSERT(reporter, buffer.isValid()); 459 460 int32_t tmp; 461 REPORTER_ASSERT(reporter, buffer.read(&tmp, 4)); 462 REPORTER_ASSERT(reporter, buffer.isValid()); 463 464 REPORTER_ASSERT(reporter, !buffer.read(&tmp, 4)); 465 REPORTER_ASSERT(reporter, !buffer.isValid()); 466 } 467