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