capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

message-test.c++ (7173B)


      1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #include "message.h"
     23 #include "test-util.h"
     24 #include <kj/array.h>
     25 #include <kj/vector.h>
     26 #include <kj/debug.h>
     27 #include <kj/compat/gtest.h>
     28 
     29 namespace capnp {
     30 namespace _ {  // private
     31 namespace {
     32 
     33 TEST(Message, MallocBuilderWithFirstSegment) {
     34   word scratch[16];
     35   memset(scratch, 0, sizeof(scratch));
     36   MallocMessageBuilder builder(kj::arrayPtr(scratch, 16), AllocationStrategy::FIXED_SIZE);
     37 
     38   kj::ArrayPtr<word> segment = builder.allocateSegment(1);
     39   EXPECT_EQ(scratch, segment.begin());
     40   EXPECT_EQ(16u, segment.size());
     41 
     42   segment = builder.allocateSegment(1);
     43   EXPECT_NE(scratch, segment.begin());
     44   EXPECT_EQ(16u, segment.size());
     45 
     46   segment = builder.allocateSegment(1);
     47   EXPECT_NE(scratch, segment.begin());
     48   EXPECT_EQ(16u, segment.size());
     49 }
     50 
     51 class TestInitMessageBuilder: public MessageBuilder {
     52 public:
     53   TestInitMessageBuilder(kj::ArrayPtr<SegmentInit> segments): MessageBuilder(segments) {}
     54 
     55   kj::ArrayPtr<word> allocateSegment(uint minimumSize) override {
     56     auto array = kj::heapArray<word>(minimumSize);
     57     memset(array.begin(), 0, array.asBytes().size());
     58     allocations.add(kj::mv(array));
     59     return allocations.back();
     60   }
     61 
     62   kj::Vector<kj::Array<word>> allocations;
     63 };
     64 
     65 TEST(Message, MessageBuilderInit) {
     66   MallocMessageBuilder builder(2048);
     67   initTestMessage(builder.getRoot<TestAllTypes>());
     68 
     69   // Pull the segments out and make a segment init table out of them.
     70   //
     71   // We const_cast for simplicity of implementing the test, but you shouldn't do that at home. :)
     72   auto segs = builder.getSegmentsForOutput();
     73   ASSERT_EQ(1, segs.size());
     74 
     75   auto segInits = KJ_MAP(seg, segs) -> MessageBuilder::SegmentInit {
     76     return { kj::arrayPtr(const_cast<word*>(seg.begin()), seg.size()), seg.size() };
     77   };
     78 
     79   // Init a new builder from the old segments.
     80   TestInitMessageBuilder builder2(segInits);
     81   checkTestMessage(builder2.getRoot<TestAllTypes>());
     82 
     83   // Verify that they're really using the same underlying memory.
     84   builder2.getRoot<TestAllTypes>().setInt64Field(123321);
     85   EXPECT_EQ(123321, builder.getRoot<TestAllTypes>().getInt64Field());
     86 
     87   // Force builder2 to allocate new space.
     88   EXPECT_EQ(0, builder2.allocations.size());
     89   builder2.getRoot<TestAllTypes>().setTextField("foobarbaz");
     90   EXPECT_EQ(1, builder2.allocations.size());
     91 }
     92 
     93 TEST(Message, MessageBuilderInitMultiSegment) {
     94   // Same as previous test, but with a message containing many segments.
     95 
     96   MallocMessageBuilder builder(1, AllocationStrategy::FIXED_SIZE);
     97   initTestMessage(builder.getRoot<TestAllTypes>());
     98 
     99   // Pull the segments out and make a segment init table out of them.
    100   //
    101   // We const_cast for simplicity of implementing the test, but you shouldn't do that at home. :)
    102   auto segs = builder.getSegmentsForOutput();
    103   ASSERT_NE(1, segs.size());
    104 
    105   auto segInits = KJ_MAP(seg, segs) -> MessageBuilder::SegmentInit {
    106     return { kj::arrayPtr(const_cast<word*>(seg.begin()), seg.size()), seg.size() };
    107   };
    108 
    109   // Init a new builder from the old segments.
    110   TestInitMessageBuilder builder2(segInits);
    111   checkTestMessage(builder2.getRoot<TestAllTypes>());
    112 
    113   // Verify that they're really using the same underlying memory.
    114   builder2.getRoot<TestAllTypes>().setInt64Field(123321);
    115   EXPECT_EQ(123321, builder.getRoot<TestAllTypes>().getInt64Field());
    116 
    117   // Force builder2 to allocate new space.
    118   EXPECT_EQ(0, builder2.allocations.size());
    119   builder2.getRoot<TestAllTypes>().setTextField("foobarbaz");
    120   EXPECT_EQ(1, builder2.allocations.size());
    121 }
    122 
    123 TEST(Message, MessageBuilderInitSpaceAvailable) {
    124   word buffer[2048];
    125   memset(buffer, 0, sizeof(buffer));
    126   MallocMessageBuilder builder(buffer);
    127   initTestMessage(builder.getRoot<TestAllTypes>());
    128 
    129   // Find out how much space in `buffer` was used in order to use in initializing the new message.
    130   auto segs = builder.getSegmentsForOutput();
    131   ASSERT_EQ(1, segs.size());
    132   KJ_ASSERT(segs[0].begin() == buffer);
    133 
    134   MessageBuilder::SegmentInit init = { kj::ArrayPtr<word>(buffer), segs[0].size() };
    135 
    136   // Init a new builder from the old segments.
    137   TestInitMessageBuilder builder2(kj::arrayPtr(&init, 1));
    138   checkTestMessage(builder2.getRoot<TestAllTypes>());
    139 
    140   // Verify that they're really using the same underlying memory.
    141   builder2.getRoot<TestAllTypes>().setInt64Field(123321);
    142   EXPECT_EQ(123321, builder.getRoot<TestAllTypes>().getInt64Field());
    143 
    144   // Ask builder2 to allocate new space. It should go into the free space at the end of the
    145   // segment.
    146   EXPECT_EQ(0, builder2.allocations.size());
    147   builder2.getRoot<TestAllTypes>().setTextField("foobarbaz");
    148   EXPECT_EQ(0, builder2.allocations.size());
    149 
    150   EXPECT_EQ(kj::implicitCast<void*>(buffer + segs[0].size()),
    151             kj::implicitCast<void*>(builder2.getRoot<TestAllTypes>().getTextField().begin()));
    152 }
    153 
    154 TEST(Message, ReadWriteDataStruct) {
    155   MallocMessageBuilder builder;
    156   auto root = builder.getRoot<TestAllTypes>();
    157 
    158   root.setUInt32Field(123);
    159   root.setFloat64Field(1.5);
    160   root.setTextField("foo");
    161 
    162   auto copy = readDataStruct<TestAllTypes>(writeDataStruct(root));
    163   EXPECT_EQ(123, copy.getUInt32Field());
    164   EXPECT_EQ(1.5, copy.getFloat64Field());
    165   EXPECT_FALSE(copy.hasTextField());
    166 
    167   checkTestMessageAllZero(readDataStruct<TestAllTypes>(nullptr));
    168   checkTestMessageAllZero(defaultValue<TestAllTypes>());
    169 }
    170 
    171 KJ_TEST("clone()") {
    172   MallocMessageBuilder builder(2048);
    173   initTestMessage(builder.getRoot<TestAllTypes>());
    174 
    175   auto copy = clone(builder.getRoot<TestAllTypes>().asReader());
    176   checkTestMessage(*copy);
    177 }
    178 
    179 #if !CAPNP_ALLOW_UNALIGNED
    180 KJ_TEST("disallow unaligned") {
    181   union {
    182     char buffer[16];
    183     word align;
    184   };
    185   memset(buffer, 0, sizeof(buffer));
    186 
    187   auto unaligned = kj::arrayPtr(reinterpret_cast<word*>(buffer + 1), 1);
    188 
    189   kj::ArrayPtr<const word> segments[1] = {unaligned};
    190   SegmentArrayMessageReader message(segments);
    191   KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("unaligned", message.getRoot<TestAllTypes>());
    192 }
    193 #endif
    194 
    195 // TODO(test):  More tests.
    196 
    197 }  // namespace
    198 }  // namespace _ (private)
    199 }  // namespace capnp