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