Index: remoting/base/compound_buffer_unittest.cc |
diff --git a/remoting/base/compound_buffer_unittest.cc b/remoting/base/compound_buffer_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..63ede5a02e033ac96f0af543e79b84c04e2e2f05 |
--- /dev/null |
+++ b/remoting/base/compound_buffer_unittest.cc |
@@ -0,0 +1,249 @@ |
+// Copyright (c) 2010 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <string> |
+ |
+#include "base/callback.h" |
+#include "base/scoped_ptr.h" |
+#include "net/base/io_buffer.h" |
+#include "remoting/base/compound_buffer.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+using net::IOBuffer; |
+ |
+namespace remoting { |
+ |
+namespace { |
+const int kDataSize = 1024; |
+ |
+// Chunk sizes used to append and prepend data to the buffer. |
+const int kChunkSizes0[] = {kDataSize, -1}; |
+const int kChunkSizes1[] = {1, 10, 20, -1}; |
+ |
+// Chunk sizes used to test CopyFrom(). |
+const int kCopySizes0[] = {10, 3, -1}; |
+const int kCopySizes1[] = {20, -1}; |
+} // namespace |
+ |
+class CompoundBufferTest : public testing::Test { |
+ public: |
+ |
+ // Following 5 methods are used with IterateOverPieces(). |
+ void Append(int pos, int size) { |
+ target_.Append(data_, data_->data() + pos, size); |
+ } |
+ |
+ void AppendCopyOf(int pos, int size) { |
+ target_.AppendCopyOf(data_->data() + pos, size); |
+ } |
+ |
+ void Prepend(int pos, int size) { |
+ target_.Prepend(data_, data_->data() + kDataSize - pos - size, size); |
+ } |
+ |
+ void PrependCopyOf(int pos, int size) { |
+ target_.PrependCopyOf(data_->data() + (kDataSize - pos - size), size); |
+ } |
+ |
+ void TestCopyFrom(int pos, int size) { |
+ CompoundBuffer copy; |
+ copy.CopyFrom(target_, pos, pos + size); |
+ EXPECT_TRUE(CompareData(copy, data_->data() + pos, size)); |
+ } |
+ |
+ protected: |
+ virtual void SetUp() { |
+ data_ = new IOBuffer(kDataSize); |
+ for (int i = 0; i < kDataSize; ++i) { |
+ data_->data()[i] = i; |
+ } |
+ } |
+ |
+ // Iterate over chunks of data with sizes specified in |sizes| in the |
+ // interval [0..kDataSize]. |function| is called for each chunk. |
+ void IterateOverPieces(const int sizes[], |
+ Callback2<int, int>::Type* function) { |
+ DCHECK_GT(sizes[0], 0); |
+ |
+ int pos = 0; |
+ int index = 0; |
+ while (pos < kDataSize) { |
+ int size = std::min(sizes[index], kDataSize - pos); |
+ ++index; |
+ if (sizes[index] <= 0) |
+ index = 0; |
+ |
+ function->Run(pos, size); |
+ |
+ pos += size; |
+ } |
+ delete function; |
+ } |
+ |
+ bool CompareData(const CompoundBuffer& buffer, char* data, int size) { |
+ scoped_refptr<IOBuffer> buffer_data = buffer.ToIOBufferWithSize(); |
+ return buffer.total_bytes() == size && |
+ memcmp(buffer_data->data(), data, size) == 0; |
+ } |
+ |
+ static size_t ReadFromInput(CompoundBufferInputStream* input, |
+ void* data, size_t size) { |
+ uint8* out = reinterpret_cast<uint8*>(data); |
+ int out_size = size; |
+ |
+ const void* in; |
+ int in_size = 0; |
+ |
+ while (true) { |
+ if (!input->Next(&in, &in_size)) { |
+ return size - out_size; |
+ } |
+ EXPECT_GT(in_size, -1); |
+ |
+ if (out_size <= in_size) { |
+ memcpy(out, in, out_size); |
+ if (in_size > out_size) { |
+ input->BackUp(in_size - out_size); |
+ } |
+ return size; // Copied all of it. |
+ } |
+ |
+ memcpy(out, in, in_size); |
+ out += in_size; |
+ out_size -= in_size; |
+ } |
+ } |
+ |
+ static void ReadString(CompoundBufferInputStream* input, |
+ const std::string& str) { |
+ SCOPED_TRACE(str); |
+ scoped_array<char> buffer(new char[str.size() + 1]); |
+ buffer[str.size()] = '\0'; |
+ EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size()); |
+ EXPECT_STREQ(str.data(), buffer.get()); |
+ } |
+ |
+ // Construct and prepare data in the |buffer|. |
+ static void PrepareData(scoped_ptr<CompoundBuffer>* buffer) { |
+ static const std::string kTestData = |
+ "Hello world!" |
+ "This is testing" |
+ "MultipleArrayInputStream" |
+ "for Chromoting"; |
+ |
+ // Determine how many segments to split kTestData. We split the data in |
+ // 1 character, 2 characters, 1 character, 2 characters ... |
+ int segments = (kTestData.length() / 3) * 2; |
+ int remaining_chars = kTestData.length() % 3; |
+ if (remaining_chars) { |
+ if (remaining_chars == 1) |
+ ++segments; |
+ else |
+ segments += 2; |
+ } |
+ |
+ CompoundBuffer* result = new CompoundBuffer(); |
+ const char* data = kTestData.data(); |
+ for (int i = 0; i < segments; ++i) { |
+ int size = i % 2 == 0 ? 1 : 2; |
+ result->Append(new net::WrappedIOBuffer(data), size); |
+ data += size; |
+ } |
+ result->Lock(); |
+ buffer->reset(result); |
+ } |
+ |
+ CompoundBuffer target_; |
+ scoped_refptr<IOBuffer> data_; |
+}; |
+ |
+TEST_F(CompoundBufferTest, Append) { |
+ target_.Clear(); |
+ IterateOverPieces(kChunkSizes0, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), &CompoundBufferTest::Append)); |
+ EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize)); |
+ |
+ target_.Clear(); |
+ IterateOverPieces(kChunkSizes1, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), &CompoundBufferTest::Append)); |
+ EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize)); |
+} |
+ |
+TEST_F(CompoundBufferTest, AppendCopyOf) { |
+ target_.Clear(); |
+ IterateOverPieces(kChunkSizes0, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), |
+ &CompoundBufferTest::AppendCopyOf)); |
+ EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize)); |
+ |
+ target_.Clear(); |
+ IterateOverPieces(kChunkSizes1, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), |
+ &CompoundBufferTest::AppendCopyOf)); |
+ EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize)); |
+} |
+ |
+TEST_F(CompoundBufferTest, Prepend) { |
+ target_.Clear(); |
+ IterateOverPieces(kChunkSizes0, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), &CompoundBufferTest::Prepend)); |
+ EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize)); |
+ |
+ target_.Clear(); |
+ IterateOverPieces(kChunkSizes1, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), &CompoundBufferTest::Prepend)); |
+ EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize)); |
+} |
+ |
+TEST_F(CompoundBufferTest, PrependCopyOf) { |
+ target_.Clear(); |
+ IterateOverPieces(kChunkSizes0, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), |
+ &CompoundBufferTest::PrependCopyOf)); |
+ EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize)); |
+ |
+ target_.Clear(); |
+ IterateOverPieces(kChunkSizes1, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), |
+ &CompoundBufferTest::PrependCopyOf)); |
+ EXPECT_TRUE(CompareData(target_, data_->data(), kDataSize)); |
+} |
+ |
+TEST_F(CompoundBufferTest, CopyFrom) { |
+ target_.Clear(); |
+ IterateOverPieces(kChunkSizes1, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), &CompoundBufferTest::Append)); |
+ { |
+ SCOPED_TRACE("CopyFrom.kCopySizes0"); |
+ IterateOverPieces(kCopySizes0, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), |
+ &CompoundBufferTest::TestCopyFrom)); |
+ } |
+ { |
+ SCOPED_TRACE("CopyFrom.kCopySizes1"); |
+ IterateOverPieces(kCopySizes1, NewCallback( |
+ static_cast<CompoundBufferTest*>(this), |
+ &CompoundBufferTest::TestCopyFrom)); |
+ } |
+} |
+ |
+TEST_F(CompoundBufferTest, InputStream) { |
+ scoped_ptr<CompoundBuffer> buffer; |
+ PrepareData(&buffer); |
+ CompoundBufferInputStream stream(buffer.get()); |
+ |
+ ReadString(&stream, "Hello world!"); |
+ ReadString(&stream, "This "); |
+ ReadString(&stream, "is test"); |
+ EXPECT_TRUE(stream.Skip(3)); |
+ ReadString(&stream, "MultipleArrayInput"); |
+ EXPECT_TRUE(stream.Skip(6)); |
+ ReadString(&stream, "f"); |
+ ReadString(&stream, "o"); |
+ ReadString(&stream, "r"); |
+ ReadString(&stream, " "); |
+ ReadString(&stream, "Chromoting"); |
+} |
+ |
+} // namespace remoting |