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