blob: 96bca35c9226b5a5399447bbfc27fca39d2cf969 [file] [log] [blame]
Leon Scroggins III932efed2016-12-16 11:39:51 -05001/*
2 * Copyright 2016 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 "SkOSPath.h"
10#include "SkStream.h"
11#include "SkStreamBuffer.h"
12
13#include "FakeStreams.h"
14#include "Test.h"
15
16static const char* gText = "Four score and seven years ago";
17
18static void test_get_data_at_position(skiatest::Reporter* r, SkStreamBuffer* buffer, size_t position,
19 size_t length) {
20 sk_sp<SkData> data = buffer->getDataAtPosition(position, length);
21 REPORTER_ASSERT(r, data);
22 if (data) {
23 REPORTER_ASSERT(r, !memcmp(data->data(), gText + position, length));
24 }
25}
26
27// Test buffering from the beginning, by different amounts.
28static void test_buffer_from_beginning(skiatest::Reporter* r, SkStream* stream, size_t length) {
29 SkStreamBuffer buffer(stream);
30
31 // Buffer an arbitrary amount:
32 size_t buffered = length / 2;
33 REPORTER_ASSERT(r, buffer.buffer(buffered));
34 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, buffered));
35
36 // Buffering less is free:
37 REPORTER_ASSERT(r, buffer.buffer(buffered / 2));
38
39 // Buffer more should succeed:
40 REPORTER_ASSERT(r, buffer.buffer(length));
41 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, length));
42}
43
44// Test flushing the stream as we read.
45static void test_flushing(skiatest::Reporter* r, SkStream* stream, size_t length,
46 bool getDataAtPosition) {
47 SkStreamBuffer buffer(stream);
48 const size_t step = 5;
49 for (size_t position = 0; position + step <= length; position += step) {
50 REPORTER_ASSERT(r, buffer.buffer(step));
51 REPORTER_ASSERT(r, buffer.markPosition() == position);
52
53 if (!getDataAtPosition) {
54 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + position, step));
55 }
56 buffer.flush();
57 }
58
59 REPORTER_ASSERT(r, !buffer.buffer(step));
60
61 if (getDataAtPosition) {
62 for (size_t position = 0; position + step <= length; position += step) {
63 test_get_data_at_position(r, &buffer, position, step);
64 }
65 }
66}
67
68DEF_TEST(StreamBuffer, r) {
69 const size_t size = strlen(gText);
70 sk_sp<SkData> data(SkData::MakeWithoutCopy(gText, size));
71
72 SkString tmpDir = skiatest::GetTmpDir();
73 const char* subdir = "streamBuffer.txt";
74 SkString path;
75
76 if (!tmpDir.isEmpty()) {
77 path = SkOSPath::Join(tmpDir.c_str(), subdir);
78 SkFILEWStream writer(path.c_str());
79 writer.write(gText, size);
80 }
81
82 struct {
83 std::function<SkStream*()> createStream;
84 bool skipIfNoTmpDir;
85 } factories[] = {
86 { [&data]() { return new SkMemoryStream(data); }, false },
87 { [&data]() { return new NotAssetMemStream(data); }, false },
88 { [&path]() { return new SkFILEStream(path.c_str()); }, true },
89 };
90
91 for (auto f : factories) {
92 if (tmpDir.isEmpty() && f.skipIfNoTmpDir) {
93 continue;
94 }
95 test_buffer_from_beginning(r, f.createStream(), size);
96 test_flushing(r, f.createStream(), size, false);
97 test_flushing(r, f.createStream(), size, true);
98 }
99
100 // Stream that will receive more data. Will be owned by the SkStreamBuffer.
101 HaltingStream* stream = new HaltingStream(data, 6);
102 SkStreamBuffer buffer(stream);
103
104 // Can only buffer less than what's available (6).
105 REPORTER_ASSERT(r, !buffer.buffer(7));
106 REPORTER_ASSERT(r, buffer.buffer(5));
107 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 5));
108
109 // Add some more data. We can buffer and read all of it.
110 stream->addNewData(8);
111 REPORTER_ASSERT(r, buffer.buffer(14));
112 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText, 14));
113
114 // Flush the buffer, which moves the position.
115 buffer.flush();
116
117 // Add some data, and try to read more. Can only read what is
118 // available.
119 stream->addNewData(9);
120 REPORTER_ASSERT(r, !buffer.buffer(13));
121 stream->addNewData(4);
122 REPORTER_ASSERT(r, buffer.buffer(13));
123
124 // Do not call get on this data. We'll come back to this data after adding
125 // more.
126 buffer.flush();
127 const size_t remaining = size - 27;
128 REPORTER_ASSERT(r, remaining > 0);
129 stream->addNewData(remaining);
130 REPORTER_ASSERT(r, buffer.buffer(remaining));
131 REPORTER_ASSERT(r, !memcmp(buffer.get(), gText + 27, remaining));
132
133 // Now go back to the data we skipped.
134 test_get_data_at_position(r, &buffer, 14, 13);
135}