1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8#include "Test.h" 9#include "SkRandom.h" 10#include "SkOSFile.h" 11#include "SkStream.h" 12#include "SkData.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 21static 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 39static 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 SkString msg; 48 msg.printf("Failed to create tmp file %s\n", path.c_str()); 49 reporter->reportFailed(msg); 50 return; 51 } 52 53 for (int i = 0; i < 100; ++i) { 54 writer.write(s, 26); 55 } 56 } 57 58 { 59 SkFILEStream stream(path.c_str()); 60 REPORTER_ASSERT(reporter, stream.isValid()); 61 test_loop_stream(reporter, &stream, s, 26, 100); 62 63 SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate()); 64 test_loop_stream(reporter, stream2.get(), s, 26, 100); 65 } 66 67 { 68 FILE* file = ::fopen(path.c_str(), "rb"); 69 SkFILEStream stream(file, SkFILEStream::kCallerPasses_Ownership); 70 REPORTER_ASSERT(reporter, stream.isValid()); 71 test_loop_stream(reporter, &stream, s, 26, 100); 72 73 SkAutoTUnref<SkStreamAsset> stream2(stream.duplicate()); 74 test_loop_stream(reporter, stream2.get(), s, 26, 100); 75 } 76} 77 78static void TestWStream(skiatest::Reporter* reporter) { 79 SkDynamicMemoryWStream ds; 80 const char s[] = "abcdefghijklmnopqrstuvwxyz"; 81 int i; 82 for (i = 0; i < 100; i++) { 83 REPORTER_ASSERT(reporter, ds.write(s, 26)); 84 } 85 REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26); 86 87 char* dst = new char[100 * 26 + 1]; 88 dst[100*26] = '*'; 89 ds.copyTo(dst); 90 REPORTER_ASSERT(reporter, dst[100*26] == '*'); 91 for (i = 0; i < 100; i++) { 92 REPORTER_ASSERT(reporter, memcmp(&dst[i * 26], s, 26) == 0); 93 } 94 95 { 96 SkAutoTUnref<SkStreamAsset> stream(ds.detachAsStream()); 97 REPORTER_ASSERT(reporter, 100 * 26 == stream->getLength()); 98 REPORTER_ASSERT(reporter, ds.getOffset() == 0); 99 test_loop_stream(reporter, stream.get(), s, 26, 100); 100 101 SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate()); 102 test_loop_stream(reporter, stream2.get(), s, 26, 100); 103 104 SkAutoTUnref<SkStreamAsset> stream3(stream->fork()); 105 REPORTER_ASSERT(reporter, stream3->isAtEnd()); 106 char tmp; 107 size_t bytes = stream->read(&tmp, 1); 108 REPORTER_ASSERT(reporter, 0 == bytes); 109 stream3->rewind(); 110 test_loop_stream(reporter, stream3.get(), s, 26, 100); 111 } 112 113 for (i = 0; i < 100; i++) { 114 REPORTER_ASSERT(reporter, ds.write(s, 26)); 115 } 116 REPORTER_ASSERT(reporter, ds.getOffset() == 100 * 26); 117 118 { 119 SkAutoTUnref<SkData> data(ds.copyToData()); 120 REPORTER_ASSERT(reporter, 100 * 26 == data->size()); 121 REPORTER_ASSERT(reporter, memcmp(dst, data->data(), data->size()) == 0); 122 } 123 124 { 125 // Test that this works after a copyToData. 126 SkAutoTUnref<SkStreamAsset> stream(ds.detachAsStream()); 127 REPORTER_ASSERT(reporter, ds.getOffset() == 0); 128 test_loop_stream(reporter, stream.get(), s, 26, 100); 129 130 SkAutoTUnref<SkStreamAsset> stream2(stream->duplicate()); 131 test_loop_stream(reporter, stream2.get(), s, 26, 100); 132 } 133 delete[] dst; 134 135 SkString tmpDir = skiatest::Test::GetTmpDir(); 136 if (!tmpDir.isEmpty()) { 137 test_filestreams(reporter, tmpDir.c_str()); 138 } 139} 140 141static void TestPackedUInt(skiatest::Reporter* reporter) { 142 // we know that packeduint tries to write 1, 2 or 4 bytes for the length, 143 // so we test values around each of those transitions (and a few others) 144 const size_t sizes[] = { 145 0, 1, 2, 0xFC, 0xFD, 0xFE, 0xFF, 0x100, 0x101, 32767, 32768, 32769, 146 0xFFFD, 0xFFFE, 0xFFFF, 0x10000, 0x10001, 147 0xFFFFFD, 0xFFFFFE, 0xFFFFFF, 0x1000000, 0x1000001, 148 0x7FFFFFFE, 0x7FFFFFFF, 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF 149 }; 150 151 152 size_t i; 153 char buffer[sizeof(sizes) * 4]; 154 155 SkMemoryWStream wstream(buffer, sizeof(buffer)); 156 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) { 157 bool success = wstream.writePackedUInt(sizes[i]); 158 REPORTER_ASSERT(reporter, success); 159 } 160 wstream.flush(); 161 162 SkMemoryStream rstream(buffer, sizeof(buffer)); 163 for (i = 0; i < SK_ARRAY_COUNT(sizes); ++i) { 164 size_t n = rstream.readPackedUInt(); 165 if (sizes[i] != n) { 166 SkDebugf("-- %d: sizes:%x n:%x\n", i, sizes[i], n); 167 } 168 REPORTER_ASSERT(reporter, sizes[i] == n); 169 } 170} 171 172// Test that setting an SkMemoryStream to a NULL data does not result in a crash when calling 173// methods that access fData. 174static void TestDereferencingData(SkMemoryStream* memStream) { 175 memStream->read(NULL, 0); 176 memStream->getMemoryBase(); 177 SkAutoDataUnref data(memStream->copyToData()); 178} 179 180static void TestNullData() { 181 SkData* nullData = NULL; 182 SkMemoryStream memStream(nullData); 183 TestDereferencingData(&memStream); 184 185 memStream.setData(nullData); 186 TestDereferencingData(&memStream); 187 188} 189 190static void TestStreams(skiatest::Reporter* reporter) { 191 TestWStream(reporter); 192 TestPackedUInt(reporter); 193 TestNullData(); 194} 195 196#include "TestClassDef.h" 197DEFINE_TESTCLASS("Stream", StreamTestClass, TestStreams) 198