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