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 "SkRandom.h"
9#include "SkReader32.h"
10#include "SkWriter32.h"
11#include "Test.h"
12
13static void check_contents(skiatest::Reporter* reporter, const SkWriter32& writer,
14                           const void* expected, size_t size) {
15    SkAutoSMalloc<256> storage(size);
16    REPORTER_ASSERT(reporter, writer.bytesWritten() == size);
17    writer.flatten(storage.get());
18    REPORTER_ASSERT(reporter, !memcmp(storage.get(), expected, size));
19}
20
21
22static void test_reserve(skiatest::Reporter* reporter) {
23    // There used to be a bug where we'd assert your first reservation had to
24    // fit in external storage if you used it.  This would crash in debug mode.
25    uint8_t storage[4];
26    SkWriter32 writer(storage, sizeof(storage));
27    writer.reserve(40);
28}
29
30static void test_string_null(skiatest::Reporter* reporter) {
31    uint8_t storage[8];
32    SkWriter32 writer(storage, sizeof(storage));
33
34    // Can we write NULL?
35    writer.writeString(NULL);
36    const int32_t expected[] = { 0x0, 0x0 };
37    check_contents(reporter, writer, expected, sizeof(expected));
38}
39
40static void test_rewind(skiatest::Reporter* reporter) {
41    SkSWriter32<32> writer;
42    int32_t array[3] = { 1, 2, 4 };
43
44    REPORTER_ASSERT(reporter, 0 == writer.bytesWritten());
45    for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) {
46        writer.writeInt(array[i]);
47    }
48    check_contents(reporter, writer, array, sizeof(array));
49
50    writer.rewindToOffset(2*sizeof(int32_t));
51    REPORTER_ASSERT(reporter, sizeof(array) - 4 == writer.bytesWritten());
52    writer.writeInt(3);
53    REPORTER_ASSERT(reporter, sizeof(array) == writer.bytesWritten());
54    array[2] = 3;
55    check_contents(reporter, writer, array, sizeof(array));
56
57    // test rewinding past allocated chunks. This used to crash because we
58    // didn't truncate our link-list after freeing trailing blocks
59    {
60        SkWriter32 writer;
61        for (int i = 0; i < 100; ++i) {
62            writer.writeInt(i);
63        }
64        REPORTER_ASSERT(reporter, 100*4 == writer.bytesWritten());
65        for (int j = 100*4; j >= 0; j -= 16) {
66            writer.rewindToOffset(j);
67        }
68        REPORTER_ASSERT(reporter, writer.bytesWritten() < 16);
69    }
70}
71
72static void test_ptr(skiatest::Reporter* reporter) {
73    SkSWriter32<32> writer;
74
75    void* p0 = reporter;
76    void* p1 = &writer;
77
78    // try writing ptrs where at least one of them may be at a non-multiple of
79    // 8 boundary, to confirm this works on 64bit machines.
80
81    writer.writePtr(p0);
82    writer.write8(0x33);
83    writer.writePtr(p1);
84    writer.write8(0x66);
85
86    size_t size = writer.bytesWritten();
87    REPORTER_ASSERT(reporter, 2 * sizeof(void*) + 2 * sizeof(int32_t));
88
89    char buffer[32];
90    SkASSERT(sizeof(buffer) >= size);
91    writer.flatten(buffer);
92
93    SkReader32 reader(buffer, size);
94    REPORTER_ASSERT(reporter, reader.readPtr() == p0);
95    REPORTER_ASSERT(reporter, reader.readInt() == 0x33);
96    REPORTER_ASSERT(reporter, reader.readPtr() == p1);
97    REPORTER_ASSERT(reporter, reader.readInt() == 0x66);
98}
99
100static void test1(skiatest::Reporter* reporter, SkWriter32* writer) {
101    const uint32_t data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
102    for (size_t i = 0; i < SK_ARRAY_COUNT(data); ++i) {
103        REPORTER_ASSERT(reporter, i*4 == writer->bytesWritten());
104        writer->write32(data[i]);
105        REPORTER_ASSERT(reporter, data[i] == writer->readTAt<uint32_t>(i * 4));
106    }
107
108    char buffer[sizeof(data)];
109    REPORTER_ASSERT(reporter, sizeof(buffer) == writer->bytesWritten());
110    writer->flatten(buffer);
111    REPORTER_ASSERT(reporter, !memcmp(data, buffer, sizeof(buffer)));
112}
113
114static void test2(skiatest::Reporter* reporter, SkWriter32* writer) {
115    static const char gStr[] = "abcdefghimjklmnopqrstuvwxyz";
116    size_t i;
117
118    size_t len = 0;
119    for (i = 0; i <= 26; ++i) {
120        len += SkWriter32::WriteStringSize(gStr, i);
121        writer->writeString(gStr, i);
122    }
123    REPORTER_ASSERT(reporter, writer->bytesWritten() == len);
124
125    SkAutoMalloc storage(len);
126    writer->flatten(storage.get());
127
128    SkReader32 reader;
129    reader.setMemory(storage.get(), len);
130    for (i = 0; i <= 26; ++i) {
131        REPORTER_ASSERT(reporter, !reader.eof());
132        const char* str = reader.readString(&len);
133        REPORTER_ASSERT(reporter, i == len);
134        REPORTER_ASSERT(reporter, strlen(str) == len);
135        REPORTER_ASSERT(reporter, !memcmp(str, gStr, len));
136        // Ensure that the align4 of the string is padded with zeroes.
137        size_t alignedSize = SkAlign4(len + 1);
138        for (size_t j = len; j < alignedSize; j++) {
139            REPORTER_ASSERT(reporter, 0 == str[j]);
140        }
141    }
142    REPORTER_ASSERT(reporter, reader.eof());
143}
144
145static void testWritePad(skiatest::Reporter* reporter, SkWriter32* writer) {
146    // Create some random data to write.
147    const size_t dataSize = 10<<2;
148    SkASSERT(SkIsAlign4(dataSize));
149
150    SkAutoMalloc originalData(dataSize);
151    {
152        SkRandom rand(0);
153        uint32_t* ptr = static_cast<uint32_t*>(originalData.get());
154        uint32_t* stop = ptr + (dataSize>>2);
155        while (ptr < stop) {
156            *ptr++ = rand.nextU();
157        }
158
159        // Write  the random data to the writer at different lengths for
160        // different alignments.
161        for (size_t len = 0; len < dataSize; len++) {
162            writer->writePad(originalData.get(), len);
163        }
164    }
165
166    uint32_t totalBytes = writer->bytesWritten();
167
168    SkAutoMalloc readStorage(totalBytes);
169    writer->flatten(readStorage.get());
170
171    SkReader32 reader;
172    reader.setMemory(readStorage.get(), totalBytes);
173
174    for (size_t len = 0; len < dataSize; len++) {
175        const char* readPtr = static_cast<const char*>(reader.skip(len));
176        // Ensure that the data read is the same as what was written.
177        REPORTER_ASSERT(reporter, memcmp(readPtr, originalData.get(), len) == 0);
178        // Ensure that the rest is padded with zeroes.
179        const char* stop = readPtr + SkAlign4(len);
180        readPtr += len;
181        while (readPtr < stop) {
182            REPORTER_ASSERT(reporter, *readPtr++ == 0);
183        }
184    }
185}
186
187static void testOverwriteT(skiatest::Reporter* reporter, SkWriter32* writer) {
188    const size_t padding = 64;
189
190    const uint32_t uint1 = 0x12345678;
191    const uint32_t uint2 = 0x98765432;
192    const SkScalar scalar1 = 1234.5678f;
193    const SkScalar scalar2 = 9876.5432f;
194    const SkRect rect1 = SkRect::MakeXYWH(1, 2, 3, 4);
195    const SkRect rect2 = SkRect::MakeXYWH(5, 6, 7, 8);
196
197    for (size_t i = 0; i < (padding / 4); ++i) {
198        writer->write32(0);
199    }
200
201    writer->write32(uint1);
202    writer->writeRect(rect1);
203    writer->writeScalar(scalar1);
204
205    for (size_t i = 0; i < (padding / 4); ++i) {
206        writer->write32(0);
207    }
208
209    REPORTER_ASSERT(reporter, writer->readTAt<uint32_t>(padding) == uint1);
210    REPORTER_ASSERT(reporter, writer->readTAt<SkRect>(padding + sizeof(uint32_t)) == rect1);
211    REPORTER_ASSERT(reporter, writer->readTAt<SkScalar>(
212                        padding + sizeof(uint32_t) + sizeof(SkRect)) == scalar1);
213
214    writer->overwriteTAt(padding, uint2);
215    writer->overwriteTAt(padding + sizeof(uint32_t), rect2);
216    writer->overwriteTAt(padding + sizeof(uint32_t) + sizeof(SkRect), scalar2);
217
218    REPORTER_ASSERT(reporter, writer->readTAt<uint32_t>(padding) == uint2);
219    REPORTER_ASSERT(reporter, writer->readTAt<SkRect>(padding + sizeof(uint32_t)) == rect2);
220    REPORTER_ASSERT(reporter, writer->readTAt<SkScalar>(
221                        padding + sizeof(uint32_t) + sizeof(SkRect)) == scalar2);
222}
223
224DEF_TEST(Writer32_dynamic, reporter) {
225    SkWriter32 writer;
226    test1(reporter, &writer);
227
228    writer.reset();
229    test2(reporter, &writer);
230
231    writer.reset();
232    testWritePad(reporter, &writer);
233
234    writer.reset();
235    testOverwriteT(reporter, &writer);
236}
237
238DEF_TEST(Writer32_contiguous, reporter) {
239    uint32_t storage[256];
240    SkWriter32 writer;
241    writer.reset(storage, sizeof(storage));
242    // This write is small enough to fit in storage, so it's contiguous.
243    test1(reporter, &writer);
244    REPORTER_ASSERT(reporter, writer.contiguousArray() != NULL);
245
246    // Everything other aspect of contiguous/non-contiguous is an
247    // implementation detail, not part of the public contract for
248    // SkWriter32, and so not tested here.
249}
250
251DEF_TEST(Writer32_small, reporter) {
252    SkSWriter32<8 * sizeof(intptr_t)> writer;
253    test1(reporter, &writer);
254    writer.reset(); // should just rewind our storage
255    test2(reporter, &writer);
256
257    writer.reset();
258    testWritePad(reporter, &writer);
259
260    writer.reset();
261    testOverwriteT(reporter, &writer);
262}
263
264DEF_TEST(Writer32_large, reporter) {
265    SkSWriter32<1024 * sizeof(intptr_t)> writer;
266    test1(reporter, &writer);
267    writer.reset(); // should just rewind our storage
268    test2(reporter, &writer);
269
270    writer.reset();
271    testWritePad(reporter, &writer);
272
273    writer.reset();
274    testOverwriteT(reporter, &writer);
275}
276
277DEF_TEST(Writer32_misc, reporter) {
278    test_reserve(reporter);
279    test_string_null(reporter);
280    test_ptr(reporter);
281    test_rewind(reporter);
282}
283
284DEF_TEST(Writer32_snapshot, reporter) {
285    int32_t array[] = { 1, 2, 4, 11 };
286    SkSWriter32<sizeof(array) + 4> writer;
287    writer.write(array, sizeof(array));
288    check_contents(reporter, writer, array, sizeof(array));
289    const void* beforeData = writer.contiguousArray();
290    SkAutoDataUnref snapshot(writer.snapshotAsData());
291    // check the snapshot forced a copy of the static data
292    REPORTER_ASSERT(reporter, snapshot->data() != beforeData);
293    REPORTER_ASSERT(reporter, snapshot->size() == writer.bytesWritten());
294}
295
296DEF_TEST(Writer32_snapshot_dynamic, reporter) {
297    int32_t array[] = { 1, 2, 4, 11 };
298    SkWriter32 writer;
299    writer.write(array, sizeof(array));
300    check_contents(reporter, writer, array, sizeof(array));
301    // force a capacity increase so we can test COW behaviour
302    writer.write(array, sizeof(array));
303    writer.rewindToOffset(sizeof(array));
304    const void* beforeData = writer.contiguousArray();
305    SkAutoDataUnref snapshot(writer.snapshotAsData());
306    // check the snapshot still points to the same data as the writer
307    REPORTER_ASSERT(reporter, writer.contiguousArray() == beforeData);
308    REPORTER_ASSERT(reporter, snapshot->data() == beforeData);
309    REPORTER_ASSERT(reporter, snapshot->size() == writer.bytesWritten());
310    // write more data that would fit in the buffer
311    writer.write(array, sizeof(array));
312    // test it triggered COW anyway
313    REPORTER_ASSERT(reporter, writer.contiguousArray() != beforeData);
314}
315