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 14 using net::IOBuffer; 15 16 namespace remoting { 17 18 namespace { 19 const int kDataSize = 1024; 20 21 // Chunk sizes used to append and prepend data to the buffer. 22 const int kChunkSizes0[] = {kDataSize, -1}; 23 const int kChunkSizes1[] = {1, 10, 20, -1}; 24 25 // Chunk sizes used to test CopyFrom(). 26 const int kCopySizes0[] = {10, 3, -1}; 27 const int kCopySizes1[] = {20, -1}; 28 29 const int kCropSizes[] = {1, -1}; 30 31 } // namespace 32 33 class 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 180 TEST_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 192 TEST_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 204 TEST_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 216 TEST_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 228 TEST_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 236 TEST_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 244 TEST_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 260 TEST_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