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 "SkDataTable.h" 10#include "SkOSFile.h" 11#include "SkOSPath.h" 12#include "SkReadBuffer.h" 13#include "SkWriteBuffer.h" 14#include "SkStream.h" 15#include "SkTArray.h" 16#include "Test.h" 17 18static void test_is_equal(skiatest::Reporter* reporter, 19 const SkDataTable* a, const SkDataTable* b) { 20 REPORTER_ASSERT(reporter, a->count() == b->count()); 21 for (int i = 0; i < a->count(); ++i) { 22 size_t sizea, sizeb; 23 const void* mema = a->at(i, &sizea); 24 const void* memb = b->at(i, &sizeb); 25 REPORTER_ASSERT(reporter, sizea == sizeb); 26 REPORTER_ASSERT(reporter, !memcmp(mema, memb, sizea)); 27 } 28} 29 30static void test_datatable_is_empty(skiatest::Reporter* reporter, SkDataTable* table) { 31 REPORTER_ASSERT(reporter, table->isEmpty()); 32 REPORTER_ASSERT(reporter, 0 == table->count()); 33} 34 35static void test_emptytable(skiatest::Reporter* reporter) { 36 sk_sp<SkDataTable> table0(SkDataTable::MakeEmpty()); 37 sk_sp<SkDataTable> table1(SkDataTable::MakeCopyArrays(nullptr, nullptr, 0)); 38 sk_sp<SkDataTable> table2(SkDataTable::MakeCopyArray(nullptr, 0, 0)); 39 sk_sp<SkDataTable> table3(SkDataTable::MakeArrayProc(nullptr, 0, 0, nullptr, nullptr)); 40 41 test_datatable_is_empty(reporter, table0.get()); 42 test_datatable_is_empty(reporter, table1.get()); 43 test_datatable_is_empty(reporter, table2.get()); 44 test_datatable_is_empty(reporter, table3.get()); 45 46 test_is_equal(reporter, table0.get(), table1.get()); 47 test_is_equal(reporter, table0.get(), table2.get()); 48 test_is_equal(reporter, table0.get(), table3.get()); 49} 50 51static void test_simpletable(skiatest::Reporter* reporter) { 52 const int idata[] = { 1, 4, 9, 16, 25, 63 }; 53 int icount = SK_ARRAY_COUNT(idata); 54 sk_sp<SkDataTable> itable(SkDataTable::MakeCopyArray(idata, sizeof(idata[0]), icount)); 55 REPORTER_ASSERT(reporter, itable->count() == icount); 56 for (int i = 0; i < icount; ++i) { 57 size_t size; 58 REPORTER_ASSERT(reporter, sizeof(int) == itable->atSize(i)); 59 REPORTER_ASSERT(reporter, *itable->atT<int>(i, &size) == idata[i]); 60 REPORTER_ASSERT(reporter, sizeof(int) == size); 61 } 62} 63 64static void test_vartable(skiatest::Reporter* reporter) { 65 const char* str[] = { 66 "", "a", "be", "see", "deigh", "ef", "ggggggggggggggggggggggggggg" 67 }; 68 int count = SK_ARRAY_COUNT(str); 69 size_t sizes[SK_ARRAY_COUNT(str)]; 70 for (int i = 0; i < count; ++i) { 71 sizes[i] = strlen(str[i]) + 1; 72 } 73 74 sk_sp<SkDataTable> table(SkDataTable::MakeCopyArrays((const void*const*)str, sizes, count)); 75 76 REPORTER_ASSERT(reporter, table->count() == count); 77 for (int i = 0; i < count; ++i) { 78 size_t size; 79 REPORTER_ASSERT(reporter, table->atSize(i) == sizes[i]); 80 REPORTER_ASSERT(reporter, !strcmp(table->atT<const char>(i, &size), 81 str[i])); 82 REPORTER_ASSERT(reporter, size == sizes[i]); 83 84 const char* s = table->atStr(i); 85 REPORTER_ASSERT(reporter, strlen(s) == strlen(str[i])); 86 } 87} 88 89static void test_globaltable(skiatest::Reporter* reporter) { 90 static const int gData[] = { 91 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 92 }; 93 int count = SK_ARRAY_COUNT(gData); 94 95 sk_sp<SkDataTable> table( 96 SkDataTable::MakeArrayProc(gData, sizeof(gData[0]), count, nullptr, nullptr)); 97 98 REPORTER_ASSERT(reporter, table->count() == count); 99 for (int i = 0; i < count; ++i) { 100 size_t size; 101 REPORTER_ASSERT(reporter, table->atSize(i) == sizeof(int)); 102 REPORTER_ASSERT(reporter, *table->atT<const char>(i, &size) == i); 103 REPORTER_ASSERT(reporter, sizeof(int) == size); 104 } 105} 106 107DEF_TEST(DataTable, reporter) { 108 test_emptytable(reporter); 109 test_simpletable(reporter); 110 test_vartable(reporter); 111 test_globaltable(reporter); 112} 113 114static void* gGlobal; 115 116static void delete_int_proc(const void* ptr, void* context) { 117 int* data = (int*)ptr; 118 SkASSERT(context == gGlobal); 119 delete[] data; 120} 121 122static void assert_len(skiatest::Reporter* reporter, const sk_sp<SkData>& ref, size_t len) { 123 REPORTER_ASSERT(reporter, ref->size() == len); 124} 125 126static void assert_data(skiatest::Reporter* reporter, const sk_sp<SkData>& ref, 127 const void* data, size_t len) { 128 REPORTER_ASSERT(reporter, ref->size() == len); 129 REPORTER_ASSERT(reporter, !memcmp(ref->data(), data, len)); 130} 131 132static void test_cstring(skiatest::Reporter* reporter) { 133 const char str[] = "Hello world"; 134 size_t len = strlen(str); 135 136 sk_sp<SkData> r0(SkData::MakeWithCopy(str, len + 1)); 137 sk_sp<SkData> r1(SkData::MakeWithCString(str)); 138 139 REPORTER_ASSERT(reporter, r0->equals(r1.get())); 140 141 sk_sp<SkData> r2(SkData::MakeWithCString(nullptr)); 142 REPORTER_ASSERT(reporter, 1 == r2->size()); 143 REPORTER_ASSERT(reporter, 0 == *r2->bytes()); 144} 145 146static void test_files(skiatest::Reporter* reporter) { 147 SkString tmpDir = skiatest::GetTmpDir(); 148 if (tmpDir.isEmpty()) { 149 return; 150 } 151 152 SkString path = SkOSPath::Join(tmpDir.c_str(), "data_test"); 153 154 const char s[] = "abcdefghijklmnopqrstuvwxyz"; 155 { 156 SkFILEWStream writer(path.c_str()); 157 if (!writer.isValid()) { 158 ERRORF(reporter, "Failed to create tmp file %s\n", path.c_str()); 159 return; 160 } 161 writer.write(s, 26); 162 } 163 164 FILE* file = sk_fopen(path.c_str(), kRead_SkFILE_Flag); 165 sk_sp<SkData> r1(SkData::MakeFromFILE(file)); 166 REPORTER_ASSERT(reporter, r1.get() != nullptr); 167 REPORTER_ASSERT(reporter, r1->size() == 26); 168 REPORTER_ASSERT(reporter, strncmp(static_cast<const char*>(r1->data()), s, 26) == 0); 169 170 int fd = sk_fileno(file); 171 sk_sp<SkData> r2(SkData::MakeFromFD(fd)); 172 REPORTER_ASSERT(reporter, r2.get() != nullptr); 173 REPORTER_ASSERT(reporter, r2->size() == 26); 174 REPORTER_ASSERT(reporter, strncmp(static_cast<const char*>(r2->data()), s, 26) == 0); 175} 176 177DEF_TEST(Data, reporter) { 178 const char* str = "We the people, in order to form a more perfect union."; 179 const int N = 10; 180 181 sk_sp<SkData> r0(SkData::MakeEmpty()); 182 sk_sp<SkData> r1(SkData::MakeWithCopy(str, strlen(str))); 183 sk_sp<SkData> r2(SkData::MakeWithProc(new int[N], N*sizeof(int), delete_int_proc, gGlobal)); 184 sk_sp<SkData> r3(SkData::MakeSubset(r1.get(), 7, 6)); 185 186 assert_len(reporter, r0, 0); 187 assert_len(reporter, r1, strlen(str)); 188 assert_len(reporter, r2, N * sizeof(int)); 189 assert_len(reporter, r3, 6); 190 191 assert_data(reporter, r1, str, strlen(str)); 192 assert_data(reporter, r3, "people", 6); 193 194 sk_sp<SkData> tmp(SkData::MakeSubset(r1.get(), strlen(str), 10)); 195 assert_len(reporter, tmp, 0); 196 tmp = SkData::MakeSubset(r1.get(), 0, 0); 197 assert_len(reporter, tmp, 0); 198 199 test_cstring(reporter); 200 test_files(reporter); 201} 202 203/////////////////////////////////////////////////////////////////////////////////////////////////// 204#include "SkRWBuffer.h" 205 206const char gABC[] = "abcdefghijklmnopqrstuvwxyz"; 207 208static void check_abcs(skiatest::Reporter* reporter, const char buffer[], size_t size) { 209 REPORTER_ASSERT(reporter, size % 26 == 0); 210 for (size_t offset = 0; offset < size; offset += 26) { 211 REPORTER_ASSERT(reporter, !memcmp(&buffer[offset], gABC, 26)); 212 } 213} 214 215// stream should contain an integral number of copies of gABC. 216static void check_alphabet_stream(skiatest::Reporter* reporter, SkStream* stream) { 217 REPORTER_ASSERT(reporter, stream->hasLength()); 218 size_t size = stream->getLength(); 219 REPORTER_ASSERT(reporter, size % 26 == 0); 220 221 SkAutoTMalloc<char> storage(size); 222 char* array = storage.get(); 223 size_t bytesRead = stream->read(array, size); 224 REPORTER_ASSERT(reporter, bytesRead == size); 225 check_abcs(reporter, array, size); 226 227 // try checking backwards 228 for (size_t offset = size; offset > 0; offset -= 26) { 229 REPORTER_ASSERT(reporter, stream->seek(offset - 26)); 230 REPORTER_ASSERT(reporter, stream->getPosition() == offset - 26); 231 REPORTER_ASSERT(reporter, stream->read(array, 26) == 26); 232 check_abcs(reporter, array, 26); 233 REPORTER_ASSERT(reporter, stream->getPosition() == offset); 234 } 235} 236 237// reader should contains an integral number of copies of gABC. 238static void check_alphabet_buffer(skiatest::Reporter* reporter, const SkROBuffer* reader) { 239 size_t size = reader->size(); 240 REPORTER_ASSERT(reporter, size % 26 == 0); 241 242 SkAutoTMalloc<char> storage(size); 243 SkROBuffer::Iter iter(reader); 244 size_t offset = 0; 245 do { 246 SkASSERT(offset + iter.size() <= size); 247 memcpy(storage.get() + offset, iter.data(), iter.size()); 248 offset += iter.size(); 249 } while (iter.next()); 250 REPORTER_ASSERT(reporter, offset == size); 251 check_abcs(reporter, storage.get(), size); 252} 253 254#include "SkTaskGroup.h" 255 256DEF_TEST(RWBuffer, reporter) { 257 // Knowing that the default capacity is 4096, choose N large enough so we force it to use 258 // multiple buffers internally. 259 static constexpr int N = 1000; 260 SkSTArray<N, sk_sp<SkROBuffer>> readers; 261 SkSTArray<N, std::unique_ptr<SkStream>> streams; 262 263 { 264 SkRWBuffer buffer; 265 for (int i = 0; i < N; ++i) { 266 buffer.append(gABC, 26); 267 readers.push_back(buffer.makeROBufferSnapshot()); 268 streams.push_back(buffer.makeStreamSnapshot()); 269 } 270 REPORTER_ASSERT(reporter, N*26 == buffer.size()); 271 } 272 273 // Verify that although the SkRWBuffer's destructor has run, the readers are still valid. 274 for (int i = 0; i < N; ++i) { 275 REPORTER_ASSERT(reporter, (i + 1) * 26U == readers[i]->size()); 276 check_alphabet_buffer(reporter, readers[i].get()); 277 check_alphabet_stream(reporter, streams[i].get()); 278 } 279} 280 281DEF_TEST(RWBuffer_threaded, reporter) { 282 // Knowing that the default capacity is 4096, choose N large enough so we force it to use 283 // multiple buffers internally. 284 const int N = 1000; 285 SkTaskGroup tasks; 286 SkRWBuffer buffer; 287 for (int i = 0; i < N; ++i) { 288 buffer.append(gABC, 26); 289 sk_sp<SkROBuffer> reader = buffer.makeROBufferSnapshot(); 290 SkStream* stream = buffer.makeStreamSnapshot().release(); 291 REPORTER_ASSERT(reporter, reader->size() == buffer.size()); 292 REPORTER_ASSERT(reporter, stream->getLength() == buffer.size()); 293 294 // reader's copy constructor will ref the SkROBuffer, which will be unreffed 295 // when the task ends. 296 // Ownership of stream is passed to the task, which will delete it. 297 tasks.add([reporter, i, reader, stream] { 298 REPORTER_ASSERT(reporter, (i + 1) * 26U == reader->size()); 299 REPORTER_ASSERT(reporter, stream->getLength() == reader->size()); 300 check_alphabet_buffer(reporter, reader.get()); 301 check_alphabet_stream(reporter, stream); 302 REPORTER_ASSERT(reporter, stream->rewind()); 303 delete stream; 304 }); 305 } 306 REPORTER_ASSERT(reporter, N*26 == buffer.size()); 307 tasks.wait(); 308} 309 310// Tests that it is safe to call SkROBuffer::Iter::size() when exhausted. 311DEF_TEST(RWBuffer_size, r) { 312 SkRWBuffer buffer; 313 buffer.append(gABC, 26); 314 315 sk_sp<SkROBuffer> roBuffer(buffer.makeROBufferSnapshot()); 316 SkROBuffer::Iter iter(roBuffer.get()); 317 REPORTER_ASSERT(r, iter.data()); 318 REPORTER_ASSERT(r, iter.size() == 26); 319 320 // There is only one block in this buffer. 321 REPORTER_ASSERT(r, !iter.next()); 322 REPORTER_ASSERT(r, 0 == iter.size()); 323} 324 325// Tests that operations (including the destructor) are safe on an SkRWBuffer 326// without any data appended. 327DEF_TEST(RWBuffer_noAppend, r) { 328 SkRWBuffer buffer; 329 REPORTER_ASSERT(r, 0 == buffer.size()); 330 331 sk_sp<SkROBuffer> roBuffer = buffer.makeROBufferSnapshot(); 332 REPORTER_ASSERT(r, roBuffer); 333 if (roBuffer) { 334 REPORTER_ASSERT(r, roBuffer->size() == 0); 335 SkROBuffer::Iter iter(roBuffer.get()); 336 REPORTER_ASSERT(r, iter.size() == 0); 337 REPORTER_ASSERT(r, !iter.data()); 338 REPORTER_ASSERT(r, !iter.next()); 339 } 340 341 std::unique_ptr<SkStream> stream(buffer.makeStreamSnapshot()); 342 REPORTER_ASSERT(r, stream); 343 if (stream) { 344 REPORTER_ASSERT(r, stream->hasLength()); 345 REPORTER_ASSERT(r, stream->getLength() == 0); 346 REPORTER_ASSERT(r, stream->skip(10) == 0); 347 } 348} 349