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