• 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 "SkData.h"
9 #include "SkOSPath.h"
10 #include "SkStream.h"
11 #include "SkStreamBuffer.h"
12 
13 #include "FakeStreams.h"
14 #include "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,SkStream * stream,size_t length)28 static 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.
test_flushing(skiatest::Reporter * r,SkStream * stream,size_t length,bool getDataAtPosition)45 static 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 
DEF_TEST(StreamBuffer,r)68 DEF_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 }
136