compound_buffer_unittest.cc revision 868fa2fe829687343ffae624259930155e16dbd8
1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/memory/scoped_ptr.h"
10#include "net/base/io_buffer.h"
11#include "remoting/base/compound_buffer.h"
12#include "testing/gtest/include/gtest/gtest.h"
13
14using net::IOBuffer;
15
16namespace remoting {
17
18namespace {
19const int kDataSize = 1024;
20
21// Chunk sizes used to append and prepend data to the buffer.
22const int kChunkSizes0[] = {kDataSize, -1};
23const int kChunkSizes1[] = {1, 10, 20, -1};
24
25// Chunk sizes used to test CopyFrom().
26const int kCopySizes0[] = {10, 3, -1};
27const int kCopySizes1[] = {20, -1};
28
29const int kCropSizes[] = {1, -1};
30
31}  // namespace
32
33class CompoundBufferTest : public testing::Test {
34 public:
35
36  // Following 5 methods are used with IterateOverPieces().
37  void Append(int pos, int size) {
38    target_.Append(data_.get(), data_->data() + pos, size);
39  }
40
41  void AppendCopyOf(int pos, int size) {
42    target_.AppendCopyOf(data_->data() + pos, size);
43  }
44
45  void Prepend(int pos, int size) {
46    target_.Prepend(data_.get(), data_->data() + kDataSize - pos - size, size);
47  }
48
49  void PrependCopyOf(int pos, int size) {
50    target_.PrependCopyOf(data_->data() + (kDataSize - pos - size), size);
51  }
52
53  void TestCopyFrom(int pos, int size) {
54    CompoundBuffer copy;
55    copy.CopyFrom(target_, pos, pos + size);
56    EXPECT_TRUE(CompareData(copy, data_->data() + pos, size));
57  }
58
59  void TestCropFront(int pos, int size) {
60    CompoundBuffer cropped;
61    cropped.CopyFrom(target_, 0, target_.total_bytes());
62    cropped.CropFront(pos);
63    EXPECT_TRUE(CompareData(cropped, data_->data() + pos,
64                            target_.total_bytes() - pos));
65  }
66
67  void TestCropBack(int pos, int size) {
68    CompoundBuffer cropped;
69    cropped.CopyFrom(target_, 0, target_.total_bytes());
70    cropped.CropBack(pos);
71    EXPECT_TRUE(CompareData(cropped, data_->data(),
72                            target_.total_bytes() - pos));
73  }
74
75 protected:
76  virtual void SetUp() {
77    data_ = new IOBuffer(kDataSize);
78    for (int i = 0; i < kDataSize; ++i) {
79      data_->data()[i] = i;
80    }
81  }
82
83  // Iterate over chunks of data with sizes specified in |sizes| in the
84  // interval [0..kDataSize]. |function| is called for each chunk.
85  void IterateOverPieces(const int sizes[],
86                         const base::Callback<void(int, int)>& function) {
87    DCHECK_GT(sizes[0], 0);
88
89    int pos = 0;
90    int index = 0;
91    while (pos < kDataSize) {
92      int size = std::min(sizes[index], kDataSize - pos);
93      ++index;
94      if (sizes[index] <= 0)
95        index = 0;
96
97      function.Run(pos, size);
98
99      pos += size;
100    }
101  }
102
103  bool CompareData(const CompoundBuffer& buffer, char* data, int size) {
104    scoped_refptr<IOBuffer> buffer_data = buffer.ToIOBufferWithSize();
105    return buffer.total_bytes() == size &&
106        memcmp(buffer_data->data(), data, size) == 0;
107  }
108
109  static size_t ReadFromInput(CompoundBufferInputStream* input,
110                              void* data, size_t size) {
111    uint8* out = reinterpret_cast<uint8*>(data);
112    int out_size = size;
113
114    const void* in;
115    int in_size = 0;
116
117    while (true) {
118      if (!input->Next(&in, &in_size)) {
119        return size - out_size;
120      }
121      EXPECT_GT(in_size, -1);
122
123      if (out_size <= in_size) {
124        memcpy(out, in, out_size);
125        if (in_size > out_size) {
126          input->BackUp(in_size - out_size);
127        }
128        return size;  // Copied all of it.
129      }
130
131      memcpy(out, in, in_size);
132      out += in_size;
133      out_size -= in_size;
134    }
135  }
136
137  static void ReadString(CompoundBufferInputStream* input,
138                         const std::string& str) {
139    SCOPED_TRACE(str);
140    scoped_ptr<char[]> buffer(new char[str.size() + 1]);
141    buffer[str.size()] = '\0';
142    EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size());
143    EXPECT_STREQ(str.data(), buffer.get());
144  }
145
146  // Construct and prepare data in the |buffer|.
147  static void PrepareData(scoped_ptr<CompoundBuffer>* buffer) {
148    static const std::string kTestData =
149        "Hello world!"
150        "This is testing"
151        "MultipleArrayInputStream"
152        "for Chromoting";
153
154    // Determine how many segments to split kTestData. We split the data in
155    // 1 character, 2 characters, 1 character, 2 characters ...
156    int segments = (kTestData.length() / 3) * 2;
157    int remaining_chars = kTestData.length() % 3;
158    if (remaining_chars) {
159      if (remaining_chars == 1)
160        ++segments;
161      else
162        segments += 2;
163    }
164
165    CompoundBuffer* result = new CompoundBuffer();
166    const char* data = kTestData.data();
167    for (int i = 0; i < segments; ++i) {
168      int size = i % 2 == 0 ? 1 : 2;
169      result->Append(new net::WrappedIOBuffer(data), size);
170      data += size;
171    }
172    result->Lock();
173    buffer->reset(result);
174  }
175
176  CompoundBuffer target_;
177  scoped_refptr<IOBuffer> data_;
178};
179
180TEST_F(CompoundBufferTest, Append) {
181  target_.Clear();
182  IterateOverPieces(kChunkSizes0, base::Bind(
183      &CompoundBufferTest::Append, base::Unretained(this)));
184  EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize));
185
186  target_.Clear();
187  IterateOverPieces(kChunkSizes1, base::Bind(
188      &CompoundBufferTest::Append, base::Unretained(this)));
189  EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize));
190}
191
192TEST_F(CompoundBufferTest, AppendCopyOf) {
193  target_.Clear();
194  IterateOverPieces(kChunkSizes0, base::Bind(
195      &CompoundBufferTest::AppendCopyOf, base::Unretained(this)));
196  EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize));
197
198  target_.Clear();
199  IterateOverPieces(kChunkSizes1, base::Bind(
200      &CompoundBufferTest::AppendCopyOf, base::Unretained(this)));
201  EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize));
202}
203
204TEST_F(CompoundBufferTest, Prepend) {
205  target_.Clear();
206  IterateOverPieces(kChunkSizes0, base::Bind(
207      &CompoundBufferTest::Prepend, base::Unretained(this)));
208  EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize));
209
210  target_.Clear();
211  IterateOverPieces(kChunkSizes1, base::Bind(
212      &CompoundBufferTest::Prepend, base::Unretained(this)));
213  EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize));
214}
215
216TEST_F(CompoundBufferTest, PrependCopyOf) {
217  target_.Clear();
218  IterateOverPieces(kChunkSizes0, base::Bind(
219      &CompoundBufferTest::PrependCopyOf, base::Unretained(this)));
220  EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize));
221
222  target_.Clear();
223  IterateOverPieces(kChunkSizes1, base::Bind(
224      &CompoundBufferTest::PrependCopyOf, base::Unretained(this)));
225  EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize));
226}
227
228TEST_F(CompoundBufferTest, CropFront) {
229  target_.Clear();
230  IterateOverPieces(kChunkSizes1, base::Bind(
231      &CompoundBufferTest::Append, base::Unretained(this)));
232  IterateOverPieces(kCropSizes, base::Bind(
233      &CompoundBufferTest::TestCropFront, base::Unretained(this)));
234}
235
236TEST_F(CompoundBufferTest, CropBack) {
237  target_.Clear();
238  IterateOverPieces(kChunkSizes1, base::Bind(
239      &CompoundBufferTest::Append, base::Unretained(this)));
240  IterateOverPieces(kCropSizes, base::Bind(
241      &CompoundBufferTest::TestCropBack, base::Unretained(this)));
242}
243
244TEST_F(CompoundBufferTest, CopyFrom) {
245  target_.Clear();
246  IterateOverPieces(kChunkSizes1, base::Bind(
247      &CompoundBufferTest::Append, base::Unretained(this)));
248  {
249    SCOPED_TRACE("CopyFrom.kCopySizes0");
250    IterateOverPieces(kCopySizes0, base::Bind(
251        &CompoundBufferTest::TestCopyFrom, base::Unretained(this)));
252  }
253  {
254    SCOPED_TRACE("CopyFrom.kCopySizes1");
255    IterateOverPieces(kCopySizes1, base::Bind(
256        &CompoundBufferTest::TestCopyFrom, base::Unretained(this)));
257  }
258}
259
260TEST_F(CompoundBufferTest, InputStream) {
261  scoped_ptr<CompoundBuffer> buffer;
262  PrepareData(&buffer);
263  CompoundBufferInputStream stream(buffer.get());
264
265  ReadString(&stream, "Hello world!");
266  ReadString(&stream, "This ");
267  ReadString(&stream, "is test");
268  EXPECT_TRUE(stream.Skip(3));
269  ReadString(&stream, "MultipleArrayInput");
270  EXPECT_TRUE(stream.Skip(6));
271  ReadString(&stream, "f");
272  ReadString(&stream, "o");
273  ReadString(&stream, "r");
274  ReadString(&stream, " ");
275  ReadString(&stream, "Chromoting");
276}
277
278}  // namespace remoting
279