Home | History | Annotate | Download | only in base
      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