serialize-snappy-test.c++ 7.82 KB
Newer Older
Kenton Varda's avatar
Kenton Varda committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// Copyright (c) 2013, Kenton Varda <temporal@gmail.com>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
//    list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "serialize-snappy.h"
Kenton Varda's avatar
Kenton Varda committed
25
#include <kj/debug.h>
26
#include "test.capnp.h"
Kenton Varda's avatar
Kenton Varda committed
27 28 29 30 31
#include <gtest/gtest.h>
#include <string>
#include <stdlib.h>
#include "test-util.h"

32
namespace capnp {
33
namespace _ {  // private
Kenton Varda's avatar
Kenton Varda committed
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
namespace {

class TestMessageBuilder: public MallocMessageBuilder {
  // A MessageBuilder that tries to allocate an exact number of total segments, by allocating
  // minimum-size segments until it reaches the number, then allocating one large segment to
  // finish.

public:
  explicit TestMessageBuilder(uint desiredSegmentCount)
      : MallocMessageBuilder(0, AllocationStrategy::FIXED_SIZE),
        desiredSegmentCount(desiredSegmentCount) {}
  ~TestMessageBuilder() {
    EXPECT_EQ(0u, desiredSegmentCount);
  }

49
  kj::ArrayPtr<word> allocateSegment(uint minimumSize) override {
Kenton Varda's avatar
Kenton Varda committed
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
    if (desiredSegmentCount <= 1) {
      if (desiredSegmentCount < 1) {
        ADD_FAILURE() << "Allocated more segments than desired.";
      } else {
        --desiredSegmentCount;
      }
      return MallocMessageBuilder::allocateSegment(SUGGESTED_FIRST_SEGMENT_WORDS);
    } else {
      --desiredSegmentCount;
      return MallocMessageBuilder::allocateSegment(minimumSize);
    }
  }

private:
  uint desiredSegmentCount;
};

67
class TestPipe: public kj::BufferedInputStream, public kj::OutputStream {
Kenton Varda's avatar
Kenton Varda committed
68
public:
69 70 71 72
  TestPipe()
      : preferredReadSize(std::numeric_limits<size_t>::max()), readPos(0) {}
  explicit TestPipe(size_t preferredReadSize)
      : preferredReadSize(preferredReadSize), readPos(0) {}
Kenton Varda's avatar
Kenton Varda committed
73 74
  ~TestPipe() {}

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
  const std::string& getData() { return data; }
  std::string getUnreadData() { return data.substr(readPos); }
  std::string::size_type getReadPos() { return readPos; }

  void resetRead(size_t preferredReadSize = std::numeric_limits<size_t>::max()) {
    readPos = 0;
    this->preferredReadSize = preferredReadSize;
  }

  bool allRead() {
    return readPos == data.size();
  }

  void clear(size_t preferredReadSize = std::numeric_limits<size_t>::max()) {
    resetRead(preferredReadSize);
    data.clear();
  }

Kenton Varda's avatar
Kenton Varda committed
93 94 95 96
  void write(const void* buffer, size_t size) override {
    data.append(reinterpret_cast<const char*>(buffer), size);
  }

97
  size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override {
98
    KJ_ASSERT(maxBytes <= data.size() - readPos, "Overran end of stream.");
99
    size_t amount = std::min(maxBytes, std::max(minBytes, preferredReadSize));
Kenton Varda's avatar
Kenton Varda committed
100 101 102 103 104
    memcpy(buffer, data.data() + readPos, amount);
    readPos += amount;
    return amount;
  }

105
  void skip(size_t bytes) override {
106
    KJ_ASSERT(bytes <= data.size() - readPos, "Overran end of stream.");
107 108 109
    readPos += bytes;
  }

110
  kj::ArrayPtr<const byte> tryGetReadBuffer() override {
111
    size_t amount = std::min(data.size() - readPos, preferredReadSize);
112
    return kj::arrayPtr(reinterpret_cast<const byte*>(data.data() + readPos), amount);
113 114
  }

Kenton Varda's avatar
Kenton Varda committed
115
private:
116
  size_t preferredReadSize;
Kenton Varda's avatar
Kenton Varda committed
117 118 119 120
  std::string data;
  std::string::size_type readPos;
};

Kenton Varda's avatar
Kenton Varda committed
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
//struct DisplayByteArray {
//  DisplayByteArray(const std::string& str)
//      : data(reinterpret_cast<const uint8_t*>(str.data())), size(str.size()) {}
//  DisplayByteArray(const std::initializer_list<uint8_t>& list)
//      : data(list.begin()), size(list.size()) {}
//
//  const uint8_t* data;
//  size_t size;
//};
//
//std::ostream& operator<<(std::ostream& os, const DisplayByteArray& bytes) {
//  os << "{ ";
//  for (size_t i = 0; i < bytes.size; i++) {
//    if (i > 0) {
//      os << ", ";
//    }
//    os << (uint)bytes.data[i];
//  }
//  os << " }";
//
//  return os;
//}
143

Kenton Varda's avatar
Kenton Varda committed
144 145 146 147
TEST(Snappy, RoundTrip) {
  TestMessageBuilder builder(1);
  initTestMessage(builder.initRoot<TestAllTypes>());

148 149
  TestPipe pipe;
  writeSnappyPackedMessage(pipe, builder);
Kenton Varda's avatar
Kenton Varda committed
150

151
  SnappyPackedMessageReader reader(pipe);
Kenton Varda's avatar
Kenton Varda committed
152
  checkTestMessage(reader.getRoot<TestAllTypes>());
153
  EXPECT_TRUE(pipe.allRead());
Kenton Varda's avatar
Kenton Varda committed
154 155 156 157 158 159
}

TEST(Snappy, RoundTripScratchSpace) {
  TestMessageBuilder builder(1);
  initTestMessage(builder.initRoot<TestAllTypes>());

160 161
  TestPipe pipe;
  writeSnappyPackedMessage(pipe, builder);
Kenton Varda's avatar
Kenton Varda committed
162 163

  word scratch[1024];
164
  SnappyPackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr<word>(scratch, 1024));
Kenton Varda's avatar
Kenton Varda committed
165
  checkTestMessage(reader.getRoot<TestAllTypes>());
166
  EXPECT_TRUE(pipe.allRead());
Kenton Varda's avatar
Kenton Varda committed
167 168 169 170 171 172
}

TEST(Snappy, RoundTripLazy) {
  TestMessageBuilder builder(1);
  initTestMessage(builder.initRoot<TestAllTypes>());

173 174
  TestPipe pipe(1);
  writeSnappyPackedMessage(pipe, builder);
Kenton Varda's avatar
Kenton Varda committed
175

176
  SnappyPackedMessageReader reader(pipe);
Kenton Varda's avatar
Kenton Varda committed
177
  checkTestMessage(reader.getRoot<TestAllTypes>());
178
  EXPECT_TRUE(pipe.allRead());
Kenton Varda's avatar
Kenton Varda committed
179 180 181 182 183 184
}

TEST(Snappy, RoundTripOddSegmentCount) {
  TestMessageBuilder builder(7);
  initTestMessage(builder.initRoot<TestAllTypes>());

185 186
  TestPipe pipe;
  writeSnappyPackedMessage(pipe, builder);
Kenton Varda's avatar
Kenton Varda committed
187

188
  SnappyPackedMessageReader reader(pipe);
Kenton Varda's avatar
Kenton Varda committed
189
  checkTestMessage(reader.getRoot<TestAllTypes>());
190
  EXPECT_TRUE(pipe.allRead());
Kenton Varda's avatar
Kenton Varda committed
191 192 193 194 195 196
}

TEST(Snappy, RoundTripOddSegmentCountLazy) {
  TestMessageBuilder builder(7);
  initTestMessage(builder.initRoot<TestAllTypes>());

197 198
  TestPipe pipe(1);
  writeSnappyPackedMessage(pipe, builder);
Kenton Varda's avatar
Kenton Varda committed
199

200
  SnappyPackedMessageReader reader(pipe);
Kenton Varda's avatar
Kenton Varda committed
201
  checkTestMessage(reader.getRoot<TestAllTypes>());
202
  EXPECT_TRUE(pipe.allRead());
Kenton Varda's avatar
Kenton Varda committed
203 204 205 206 207 208
}

TEST(Snappy, RoundTripEvenSegmentCount) {
  TestMessageBuilder builder(10);
  initTestMessage(builder.initRoot<TestAllTypes>());

209 210
  TestPipe pipe;
  writeSnappyPackedMessage(pipe, builder);
Kenton Varda's avatar
Kenton Varda committed
211

212
  SnappyPackedMessageReader reader(pipe);
Kenton Varda's avatar
Kenton Varda committed
213
  checkTestMessage(reader.getRoot<TestAllTypes>());
214
  EXPECT_TRUE(pipe.allRead());
Kenton Varda's avatar
Kenton Varda committed
215 216 217 218 219 220
}

TEST(Snappy, RoundTripEvenSegmentCountLazy) {
  TestMessageBuilder builder(10);
  initTestMessage(builder.initRoot<TestAllTypes>());

221 222
  TestPipe pipe(1);
  writeSnappyPackedMessage(pipe, builder);
Kenton Varda's avatar
Kenton Varda committed
223

224
  SnappyPackedMessageReader reader(pipe);
Kenton Varda's avatar
Kenton Varda committed
225
  checkTestMessage(reader.getRoot<TestAllTypes>());
226
  EXPECT_TRUE(pipe.allRead());
Kenton Varda's avatar
Kenton Varda committed
227 228 229 230 231 232 233 234 235
}

TEST(Snappy, RoundTripTwoMessages) {
  TestMessageBuilder builder(1);
  initTestMessage(builder.initRoot<TestAllTypes>());

  TestMessageBuilder builder2(1);
  builder2.initRoot<TestAllTypes>().setTextField("Second message.");

236 237 238 239
  TestPipe pipe(1);
  writeSnappyPackedMessage(pipe, builder);
  size_t firstSize = pipe.getData().size();
  writeSnappyPackedMessage(pipe, builder2);
Kenton Varda's avatar
Kenton Varda committed
240 241

  {
242
    SnappyPackedMessageReader reader(pipe);
Kenton Varda's avatar
Kenton Varda committed
243 244 245
    checkTestMessage(reader.getRoot<TestAllTypes>());
  }

246 247
  EXPECT_EQ(firstSize, pipe.getReadPos());

Kenton Varda's avatar
Kenton Varda committed
248
  {
249
    SnappyPackedMessageReader reader(pipe);
Kenton Varda's avatar
Kenton Varda committed
250 251
    EXPECT_EQ("Second message.", reader.getRoot<TestAllTypes>().getTextField());
  }
252
  EXPECT_TRUE(pipe.allRead());
Kenton Varda's avatar
Kenton Varda committed
253 254
}

255
// TODO(test):  Test error cases.
Kenton Varda's avatar
Kenton Varda committed
256 257

}  // namespace
258
}  // namespace _ (private)
259
}  // namespace capnp