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 "SkData.h" 9 #include "SkOSFile.h" 10 #include "SkRandom.h" 11 #include "SkStream.h" 12 #include "Test.h" 13 14 #ifndef SK_BUILD_FOR_WIN 15 #include <unistd.h> 16 #include <fcntl.h> 17 #endif 18 19 #define MAX_SIZE (256 * 1024) 20 21 static void test_loop_stream(skiatest::Reporter* reporter, SkStream* stream, 22 const void* src, size_t len, int repeat) { 23 SkAutoSMalloc<256> storage(len); 24 void* tmp = storage.get(); 25 26 for (int i = 0; i < repeat; ++i) { 27 size_t bytes = stream->read(tmp, len); 28 REPORTER_ASSERT(reporter, bytes == len); 29 REPORTER_ASSERT(reporter, !memcmp(tmp, src, len)); 30 } 31 32 // expect EOF 33 size_t bytes = stream->read(tmp, 1); 34 REPORTER_ASSERT(reporter, 0 == bytes); 35 // isAtEnd might not return true until after the first failing read. 36 REPORTER_ASSERT(reporter, stream->isAtEnd()); 37 } 38 39 static void test_filestreams(skiatest::Reporter* reporter, const char* tmpDir) { 40 SkString path = SkOSPath::SkPathJoin(tmpDir, "wstream_test"); 41 42 const char s[] = "abcdefghijklmnopqrstuvwxyz"; 43 44 { 45 SkFILEWStream writer(path.c_str()); 46 if (!writer.isValid()) { 47 ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str()); 48 return; 49 } 50 51 for (int i = 0; i < 100; ++i) { 52 writer.write(s, 26); 53 } 54 } 55 56 { 57 SkFILEStream stream(path.c_str()); 58 REPORTER_ASSERT(reporter, stream.isValid()); 59 test_loop_stream(reporter, &stream, s, 26, 100); 60 61 SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate()); 62 test_loop_stream(reporter, stream2.get(), s, 26, 100); 63 } 64 65 { 66 FILE* file = ::fopen(path.c_str(), "rb"); 67 SkFILEStream stream(file, SkFILEStream::kCallerPasses_Ownership); 68 REPORTER_ASSERT(reporter, stream.isValid()); 69 test_loop_stream(reporter, &stream, s, 26, 100); 70 71 SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate()); 72 test_loop_stream(reporter, stream2.get(), s, 26, 100); 73 } 74 } 75 76 static void TestWStream(skiatest::Reporter* reporter) { 77 SkDynamicMemoryWStream ds; 78 const char s[] = "abcdefghijklmnopqrstuvwxyz"; 79 int i; 80 for (i = 0; i < 100; i++) { 81 REPORTER_ASSERT(reporter, ds.write(s, 26)); 82 } 83 REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26); 84 85 char* dst = new char[100 * 26 + 1]; 86 dst[100*26] = '*'; 87 ds.copyTo(dst); 88 REPORTER_ASSERT(reporter, dst[100*26] == '*'); 89 for (i = 0; i < 100; i++) { 90 REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0); 91 } 92 93 { 94 SkAutoTUnref<SkStreamAsset> stream(ds.detachAsStream()); 95 REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength()); 96 REPORTER_ASSERT(reporter, ds.getOffset() == 0); 97 test_loop_stream(reporter, stream.get(), s, 26, 100); 98 99 SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate()); 100 test_loop_stream(reporter, stream2.get(), s, 26, 100); 101 102 SkAutoTUnref<SkStreamAsset> stream3(stream->fork()); 103 REPORTER_ASSERT(reporter, stream3->isAtEnd()); 104 char tmp; 105 size_t bytes = stream->read(&tmp, 1); 106 REPORTER_ASSERT(reporter, 0 == bytes); 107 stream3->rewind(); 108 test_loop_stream(reporter, stream3.get(), s, 26, 100); 109 } 110 111 for (i = 0; i < 100; i++) { 112 REPORTER_ASSERT(reporter, ds.write(s, 26)); 113 } 114 REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26); 115 116 { 117 SkAutoTUnref<SkData> data(ds.copyToData()); 118 REPORTER_ASSERT(reporter, 100 * 26 == data->size()); 119 REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0); 120 } 121 122 { 123 // Test that this works after a copyToData. 124 SkAutoTUnref<SkStreamAsset> stream(ds.detachAsStream()); 125 REPORTER_ASSERT(reporter, ds.getOffset() == 0); 126 test_loop_stream(reporter, stream.get(), s, 26, 100); 127 128 SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate()); 129 test_loop_stream(reporter, stream2.get(), s, 26, 100); 130 } 131 delete[] dst; 132 133 SkString tmpDir = skiatest::Test::GetTmpDir(); 134 if (!tmpDir.isEmpty()) { 135 test_filestreams(reporter, tmpDir.c_str()); 136 } 137 } 138 139 static void TestPackedUInt(skiatest::Reporter* reporter) { 140 // we know that packeduint tries to write 1, 2 or 4 bytes for the length, 141 // so we test values around each of those transitions (and a few others) 142 const size_t sizes[] = { 143 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769, 144 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001, 145 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001, 146 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF 147 }; 148 149 150 size_t i; 151 char buffer[sizeof(sizes) * 4]; 152 153 SkMemoryWStream wstream(buffer, sizeof(buffer)); 154 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) { 155 bool success = wstream.writePackedUInt(sizes[i]); 156 REPORTER_ASSERT(reporter, success); 157 } 158 wstream.flush(); 159 160 SkMemoryStream rstream(buffer, sizeof(buffer)); 161 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) { 162 size_t n = rstream.readPackedUInt(); 163 if (sizes[i] != n) { 164 SkDebugf("-- %d: sizes:%x n:%x\n", i, sizes[i], n); 165 } 166 REPORTER_ASSERT(reporter, sizes[i] == n); 167 } 168 } 169 170 // Test that setting an SkMemoryStream to a NULL data does not result in a crash when calling 171 // methods that access fData. 172 static void TestDereferencingData(SkMemoryStream* memStream) { 173 memStream->read(NULL, 0); 174 memStream->getMemoryBase(); 175 SkAutoDataUnref data(memStream->copyToData()); 176 } 177 178 static void TestNullData() { 179 SkData* nullData = NULL; 180 SkMemoryStream memStream(nullData); 181 TestDereferencingData(&memStream); 182 183 memStream.setData(nullData); 184 TestDereferencingData(&memStream); 185 186 } 187 188 DEF_TEST(Stream, reporter) { 189 TestWStream(reporter); 190 TestPackedUInt(reporter); 191 TestNullData(); 192 } 193