1 /* 2 * Copyright 2013 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 "SkFrontBufferedStream.h" 9 #include "SkRefCnt.h" 10 #include "SkStream.h" 11 #include "SkTypes.h" 12 #include "Test.h" 13 14 static void test_read(skiatest::Reporter* reporter, SkStream* bufferedStream, 15 const void* expectations, size_t bytesToRead) { 16 // output for reading bufferedStream. 17 SkAutoMalloc storage(bytesToRead); 18 19 const size_t bytesRead = bufferedStream->read(storage.get(), bytesToRead); 20 REPORTER_ASSERT(reporter, bytesRead == bytesToRead || bufferedStream->isAtEnd()); 21 REPORTER_ASSERT(reporter, memcmp(storage.get(), expectations, bytesRead) == 0); 22 } 23 24 static void test_rewind(skiatest::Reporter* reporter, 25 SkStream* bufferedStream, bool shouldSucceed) { 26 const bool success = bufferedStream->rewind(); 27 REPORTER_ASSERT(reporter, success == shouldSucceed); 28 } 29 30 // Test that hasLength() returns the correct value, based on the stream 31 // being wrapped. A length can only be known if the wrapped stream has a 32 // length and it has a position (so its initial position can be taken into 33 // account when computing the length). 34 static void test_hasLength(skiatest::Reporter* reporter, 35 const SkStream& bufferedStream, 36 const SkStream& streamBeingBuffered) { 37 if (streamBeingBuffered.hasLength() && streamBeingBuffered.hasPosition()) { 38 REPORTER_ASSERT(reporter, bufferedStream.hasLength()); 39 } else { 40 REPORTER_ASSERT(reporter, !bufferedStream.hasLength()); 41 } 42 } 43 44 // All tests will buffer this string, and compare output to the original. 45 // The string is long to ensure that all of our lengths being tested are 46 // smaller than the string length. 47 const char gAbcs[] = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwx"; 48 49 // Tests reading the stream across boundaries of what has been buffered so far and what 50 // the total buffer size is. 51 static void test_incremental_buffering(skiatest::Reporter* reporter, size_t bufferSize) { 52 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false); 53 54 SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize)); 55 test_hasLength(reporter, *bufferedStream.get(), memStream); 56 57 // First, test reading less than the max buffer size. 58 test_read(reporter, bufferedStream, gAbcs, bufferSize / 2); 59 60 // Now test rewinding back to the beginning and reading less than what was 61 // already buffered. 62 test_rewind(reporter, bufferedStream, true); 63 test_read(reporter, bufferedStream, gAbcs, bufferSize / 4); 64 65 // Now test reading part of what was buffered, and buffering new data. 66 test_read(reporter, bufferedStream, gAbcs + bufferedStream->getPosition(), bufferSize / 2); 67 68 // Now test reading what was buffered, buffering new data, and 69 // reading directly from the stream. 70 test_rewind(reporter, bufferedStream, true); 71 test_read(reporter, bufferedStream, gAbcs, bufferSize << 1); 72 73 // We have reached the end of the buffer, so rewinding will fail. 74 // This test assumes that the stream is larger than the buffer; otherwise the 75 // result of rewind should be true. 76 test_rewind(reporter, bufferedStream, false); 77 } 78 79 static void test_perfectly_sized_buffer(skiatest::Reporter* reporter, size_t bufferSize) { 80 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false); 81 SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize)); 82 test_hasLength(reporter, *bufferedStream.get(), memStream); 83 84 // Read exactly the amount that fits in the buffer. 85 test_read(reporter, bufferedStream, gAbcs, bufferSize); 86 87 // Rewinding should succeed. 88 test_rewind(reporter, bufferedStream, true); 89 90 // Once again reading buffered info should succeed 91 test_read(reporter, bufferedStream, gAbcs, bufferSize); 92 93 // Read past the size of the buffer. At this point, we cannot return. 94 test_read(reporter, bufferedStream, gAbcs + bufferedStream->getPosition(), 1); 95 test_rewind(reporter, bufferedStream, false); 96 } 97 98 static void test_skipping(skiatest::Reporter* reporter, size_t bufferSize) { 99 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false); 100 SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize)); 101 test_hasLength(reporter, *bufferedStream.get(), memStream); 102 103 // Skip half the buffer. 104 bufferedStream->skip(bufferSize / 2); 105 106 // Rewind, then read part of the buffer, which should have been read. 107 test_rewind(reporter, bufferedStream, true); 108 test_read(reporter, bufferedStream, gAbcs, bufferSize / 4); 109 110 // Now skip beyond the buffered piece, but still within the total buffer. 111 bufferedStream->skip(bufferSize / 2); 112 113 // Test that reading will still work. 114 test_read(reporter, bufferedStream, gAbcs + bufferedStream->getPosition(), bufferSize / 4); 115 116 test_rewind(reporter, bufferedStream, true); 117 test_read(reporter, bufferedStream, gAbcs, bufferSize); 118 } 119 120 // A custom class whose isAtEnd behaves the way Android's stream does - since it is an adaptor to a 121 // Java InputStream, it does not know that it is at the end until it has attempted to read beyond 122 // the end and failed. Used by test_read_beyond_buffer. 123 class AndroidLikeMemoryStream : public SkMemoryStream { 124 public: 125 AndroidLikeMemoryStream(void* data, size_t size, bool ownMemory) 126 : INHERITED(data, size, ownMemory) 127 , fIsAtEnd(false) {} 128 129 size_t read(void* dst, size_t requested) SK_OVERRIDE { 130 size_t bytesRead = this->INHERITED::read(dst, requested); 131 if (bytesRead < requested) { 132 fIsAtEnd = true; 133 } 134 return bytesRead; 135 } 136 137 bool isAtEnd() const SK_OVERRIDE { 138 return fIsAtEnd; 139 } 140 141 private: 142 bool fIsAtEnd; 143 typedef SkMemoryStream INHERITED; 144 }; 145 146 // This test ensures that buffering the exact length of the stream and attempting to read beyond it 147 // does not invalidate the buffer. 148 static void test_read_beyond_buffer(skiatest::Reporter* reporter, size_t bufferSize) { 149 // Use a stream that behaves like Android's stream. 150 AndroidLikeMemoryStream memStream((void*)gAbcs, bufferSize, false); 151 152 // Create a buffer that matches the length of the stream. 153 SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize)); 154 test_hasLength(reporter, *bufferedStream.get(), memStream); 155 156 // Attempt to read one more than the bufferSize 157 test_read(reporter, bufferedStream.get(), gAbcs, bufferSize + 1); 158 test_rewind(reporter, bufferedStream.get(), true); 159 160 // Ensure that the initial read did not invalidate the buffer. 161 test_read(reporter, bufferedStream, gAbcs, bufferSize); 162 } 163 164 // Dummy stream that optionally has a length and/or position. Tests that FrontBufferedStream's 165 // length depends on the stream it's buffering having a length and position. 166 class LengthOptionalStream : public SkStream { 167 public: 168 LengthOptionalStream(bool hasLength, bool hasPosition) 169 : fHasLength(hasLength) 170 , fHasPosition(hasPosition) 171 {} 172 173 virtual bool hasLength() const SK_OVERRIDE { 174 return fHasLength; 175 } 176 177 virtual bool hasPosition() const SK_OVERRIDE { 178 return fHasPosition; 179 } 180 181 virtual size_t read(void*, size_t) SK_OVERRIDE { 182 return 0; 183 } 184 185 virtual bool isAtEnd() const SK_OVERRIDE { 186 return true; 187 } 188 189 private: 190 const bool fHasLength; 191 const bool fHasPosition; 192 }; 193 194 // Test all possible combinations of the wrapped stream having a length and a position. 195 static void test_length_combos(skiatest::Reporter* reporter, size_t bufferSize) { 196 for (int hasLen = 0; hasLen <= 1; hasLen++) { 197 for (int hasPos = 0; hasPos <= 1; hasPos++) { 198 LengthOptionalStream stream(SkToBool(hasLen), SkToBool(hasPos)); 199 SkAutoTUnref<SkStream> buffered(SkFrontBufferedStream::Create(&stream, bufferSize)); 200 test_hasLength(reporter, *buffered.get(), stream); 201 } 202 } 203 } 204 205 // Test using a stream with an initial offset. 206 static void test_initial_offset(skiatest::Reporter* reporter, size_t bufferSize) { 207 SkMemoryStream memStream(gAbcs, strlen(gAbcs), false); 208 209 // Skip a few characters into the memStream, so that bufferedStream represents an offset into 210 // the stream it wraps. 211 const size_t arbitraryOffset = 17; 212 memStream.skip(arbitraryOffset); 213 SkAutoTUnref<SkStream> bufferedStream(SkFrontBufferedStream::Create(&memStream, bufferSize)); 214 215 // Since SkMemoryStream has a length and a position, bufferedStream must also. 216 REPORTER_ASSERT(reporter, bufferedStream->hasLength()); 217 218 const size_t amountToRead = 10; 219 const size_t bufferedLength = bufferedStream->getLength(); 220 size_t currentPosition = bufferedStream->getPosition(); 221 REPORTER_ASSERT(reporter, 0 == currentPosition); 222 223 // Read the stream in chunks. After each read, the position must match currentPosition, 224 // which sums the amount attempted to read, unless the end of the stream has been reached. 225 // Importantly, the end should not have been reached until currentPosition == bufferedLength. 226 while (currentPosition < bufferedLength) { 227 REPORTER_ASSERT(reporter, !bufferedStream->isAtEnd()); 228 test_read(reporter, bufferedStream, gAbcs + arbitraryOffset + currentPosition, 229 amountToRead); 230 currentPosition = SkTMin(currentPosition + amountToRead, bufferedLength); 231 REPORTER_ASSERT(reporter, bufferedStream->getPosition() == currentPosition); 232 } 233 REPORTER_ASSERT(reporter, bufferedStream->isAtEnd()); 234 REPORTER_ASSERT(reporter, bufferedLength == currentPosition); 235 } 236 237 static void test_buffers(skiatest::Reporter* reporter, size_t bufferSize) { 238 test_incremental_buffering(reporter, bufferSize); 239 test_perfectly_sized_buffer(reporter, bufferSize); 240 test_skipping(reporter, bufferSize); 241 test_read_beyond_buffer(reporter, bufferSize); 242 test_length_combos(reporter, bufferSize); 243 test_initial_offset(reporter, bufferSize); 244 } 245 246 DEF_TEST(FrontBufferedStream, reporter) { 247 // Test 6 and 64, which are used by Android, as well as another arbitrary length. 248 test_buffers(reporter, 6); 249 test_buffers(reporter, 15); 250 test_buffers(reporter, 64); 251 } 252