serialize-packed-test.c++ (18666B)
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 "serialize-packed.h" 23 #include <kj/debug.h> 24 #include <kj/compat/gtest.h> 25 #include <string> 26 #include <stdlib.h> 27 #include "test-util.h" 28 29 namespace capnp { 30 namespace _ { // private 31 namespace { 32 33 class TestPipe: public kj::BufferedInputStream, public kj::OutputStream { 34 public: 35 TestPipe() 36 : preferredReadSize(kj::maxValue), readPos(0) {} 37 explicit TestPipe(size_t preferredReadSize) 38 : preferredReadSize(preferredReadSize), readPos(0) {} 39 ~TestPipe() {} 40 41 const std::string& getData() { return data; } 42 43 kj::ArrayPtr<const byte> getArray() { 44 return kj::arrayPtr(reinterpret_cast<const byte*>(data.data()), data.size()); 45 } 46 47 void resetRead(size_t preferredReadSize = kj::maxValue) { 48 readPos = 0; 49 this->preferredReadSize = preferredReadSize; 50 } 51 52 bool allRead() { 53 return readPos == data.size(); 54 } 55 56 void clear(size_t preferredReadSize = kj::maxValue) { 57 resetRead(preferredReadSize); 58 data.clear(); 59 } 60 61 void write(const void* buffer, size_t size) override { 62 data.append(reinterpret_cast<const char*>(buffer), size); 63 } 64 65 size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override { 66 KJ_ASSERT(maxBytes <= data.size() - readPos, "Overran end of stream."); 67 size_t amount = kj::min(maxBytes, kj::max(minBytes, preferredReadSize)); 68 memcpy(buffer, data.data() + readPos, amount); 69 readPos += amount; 70 return amount; 71 } 72 73 void skip(size_t bytes) override { 74 KJ_ASSERT(bytes <= data.size() - readPos, "Overran end of stream."); 75 readPos += bytes; 76 } 77 78 kj::ArrayPtr<const byte> tryGetReadBuffer() override { 79 size_t amount = kj::min(data.size() - readPos, preferredReadSize); 80 return kj::arrayPtr(reinterpret_cast<const byte*>(data.data() + readPos), amount); 81 } 82 83 private: 84 size_t preferredReadSize; 85 std::string data; 86 std::string::size_type readPos; 87 }; 88 89 void expectPacksTo(kj::ArrayPtr<const byte> unpackedUnaligned, kj::ArrayPtr<const byte> packed) { 90 TestPipe pipe; 91 92 auto unpackedSizeInWords = computeUnpackedSizeInWords(packed); 93 EXPECT_EQ(unpackedUnaligned.size(), unpackedSizeInWords * sizeof(word)); 94 95 // Make a guaranteed-to-be-aligned copy of the unpacked buffer. 96 kj::Array<word> unpackedWords = kj::heapArray<word>(unpackedSizeInWords); 97 if (unpackedUnaligned.size() != 0u) { 98 memcpy(unpackedWords.begin(), unpackedUnaligned.begin(), unpackedUnaligned.size()); 99 } 100 kj::ArrayPtr<const byte> unpacked = unpackedWords.asBytes(); 101 102 // ----------------------------------------------------------------- 103 // write 104 105 { 106 kj::BufferedOutputStreamWrapper bufferedOut(pipe); 107 PackedOutputStream packedOut(bufferedOut); 108 packedOut.write(unpacked.begin(), unpacked.size()); 109 } 110 111 if (pipe.getData() != std::string(packed.asChars().begin(), packed.asChars().size())) { 112 KJ_FAIL_ASSERT("Tried to pack `unpacked`, expected `packed`, got `pipe.getData()`", 113 unpacked, packed, pipe.getData()); 114 return; 115 } 116 117 // ----------------------------------------------------------------- 118 // read 119 120 kj::Array<byte> roundTrip = kj::heapArray<byte>(unpacked.size()); 121 122 { 123 PackedInputStream packedIn(pipe); 124 packedIn.InputStream::read(roundTrip.begin(), roundTrip.size()); 125 EXPECT_TRUE(pipe.allRead()); 126 } 127 128 if (memcmp(roundTrip.begin(), unpacked.begin(), unpacked.size()) != 0) { 129 KJ_FAIL_ASSERT("Tried to unpack `packed`, expected `unpacked`, got `roundTrip`", 130 packed, unpacked, roundTrip); 131 return; 132 } 133 134 for (uint blockSize = 1; blockSize < packed.size(); blockSize <<= 1) { 135 pipe.resetRead(blockSize); 136 137 { 138 PackedInputStream packedIn(pipe); 139 packedIn.InputStream::read(roundTrip.begin(), roundTrip.size()); 140 EXPECT_TRUE(pipe.allRead()); 141 } 142 143 if (memcmp(roundTrip.begin(), unpacked.begin(), unpacked.size()) != 0) { 144 KJ_FAIL_ASSERT("Tried to unpack `packed`, expected `unpacked`, got `roundTrip`", 145 packed, blockSize, unpacked, roundTrip); 146 } 147 } 148 149 // ----------------------------------------------------------------- 150 // skip 151 152 pipe.resetRead(); 153 154 { 155 PackedInputStream packedIn(pipe); 156 packedIn.skip(unpacked.size()); 157 EXPECT_TRUE(pipe.allRead()); 158 } 159 160 for (uint blockSize = 1; blockSize < packed.size(); blockSize <<= 1) { 161 pipe.resetRead(blockSize); 162 163 { 164 PackedInputStream packedIn(pipe); 165 packedIn.skip(unpacked.size()); 166 EXPECT_TRUE(pipe.allRead()); 167 } 168 } 169 170 pipe.clear(); 171 172 // ----------------------------------------------------------------- 173 // write / read multiple 174 175 { 176 kj::BufferedOutputStreamWrapper bufferedOut(pipe); 177 PackedOutputStream packedOut(bufferedOut); 178 for (uint i = 0; i < 5; i++) { 179 packedOut.write(unpacked.begin(), unpacked.size()); 180 } 181 } 182 183 for (uint i = 0; i < 5; i++) { 184 PackedInputStream packedIn(pipe); 185 packedIn.InputStream::read(&*roundTrip.begin(), roundTrip.size()); 186 187 if (memcmp(roundTrip.begin(), unpacked.begin(), unpacked.size()) != 0) { 188 KJ_FAIL_ASSERT("Tried to unpack `packed`, expected `unpacked`, got `roundTrip`", 189 packed, i, unpacked, roundTrip); 190 } 191 } 192 193 EXPECT_TRUE(pipe.allRead()); 194 } 195 196 #ifdef __CDT_PARSER__ 197 // CDT doesn't seem to understand these initializer lists. 198 #define expectPacksTo(...) 199 #endif 200 201 TEST(Packed, SimplePacking) { 202 expectPacksTo({}, {}); 203 expectPacksTo({0,0,0,0,0,0,0,0}, {0,0}); 204 expectPacksTo({0,0,12,0,0,34,0,0}, {0x24,12,34}); 205 expectPacksTo({1,3,2,4,5,7,6,8}, {0xff,1,3,2,4,5,7,6,8,0}); 206 expectPacksTo({0,0,0,0,0,0,0,0,1,3,2,4,5,7,6,8}, {0,0,0xff,1,3,2,4,5,7,6,8,0}); 207 expectPacksTo({0,0,12,0,0,34,0,0,1,3,2,4,5,7,6,8}, {0x24,12,34,0xff,1,3,2,4,5,7,6,8,0}); 208 expectPacksTo({1,3,2,4,5,7,6,8,8,6,7,4,5,2,3,1}, {0xff,1,3,2,4,5,7,6,8,1,8,6,7,4,5,2,3,1}); 209 210 expectPacksTo( 211 {1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 0,2,4,0,9,0,5,1}, 212 {0xff,1,2,3,4,5,6,7,8, 3, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 0xd6,2,4,9,5,1}); 213 expectPacksTo( 214 {1,2,3,4,5,6,7,8, 1,2,3,4,5,6,7,8, 6,2,4,3,9,0,5,1, 1,2,3,4,5,6,7,8, 0,2,4,0,9,0,5,1}, 215 {0xff,1,2,3,4,5,6,7,8, 3, 1,2,3,4,5,6,7,8, 6,2,4,3,9,0,5,1, 1,2,3,4,5,6,7,8, 0xd6,2,4,9,5,1}); 216 217 expectPacksTo( 218 {8,0,100,6,0,1,1,2, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,1,0,2,0,3,1}, 219 {0xed,8,100,6,1,1,2, 0,2, 0xd4,1,2,3,1}); 220 } 221 222 // ======================================================================================= 223 224 class TestMessageBuilder: public MallocMessageBuilder { 225 // A MessageBuilder that tries to allocate an exact number of total segments, by allocating 226 // minimum-size segments until it reaches the number, then allocating one large segment to 227 // finish. 228 229 public: 230 explicit TestMessageBuilder(uint desiredSegmentCount) 231 : MallocMessageBuilder(0, AllocationStrategy::FIXED_SIZE), 232 desiredSegmentCount(desiredSegmentCount) {} 233 ~TestMessageBuilder() { 234 EXPECT_EQ(0u, desiredSegmentCount); 235 } 236 237 kj::ArrayPtr<word> allocateSegment(uint minimumSize) override { 238 if (desiredSegmentCount <= 1) { 239 if (desiredSegmentCount < 1) { 240 ADD_FAILURE() << "Allocated more segments than desired."; 241 } else { 242 --desiredSegmentCount; 243 } 244 return MallocMessageBuilder::allocateSegment(SUGGESTED_FIRST_SEGMENT_WORDS); 245 } else { 246 --desiredSegmentCount; 247 return MallocMessageBuilder::allocateSegment(minimumSize); 248 } 249 } 250 251 private: 252 uint desiredSegmentCount; 253 }; 254 255 TEST(Packed, RoundTrip) { 256 TestMessageBuilder builder(1); 257 initTestMessage(builder.initRoot<TestAllTypes>()); 258 259 TestPipe pipe; 260 writePackedMessage(pipe, builder); 261 262 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 263 264 PackedMessageReader reader(pipe); 265 checkTestMessage(reader.getRoot<TestAllTypes>()); 266 } 267 268 TEST(Packed, RoundTripScratchSpace) { 269 TestMessageBuilder builder(1); 270 initTestMessage(builder.initRoot<TestAllTypes>()); 271 272 TestPipe pipe; 273 writePackedMessage(pipe, builder); 274 275 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 276 277 word scratch[1024]; 278 PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr<word>(scratch, 1024)); 279 checkTestMessage(reader.getRoot<TestAllTypes>()); 280 } 281 282 TEST(Packed, RoundTripLazy) { 283 TestMessageBuilder builder(1); 284 initTestMessage(builder.initRoot<TestAllTypes>()); 285 286 TestPipe pipe(1); 287 writePackedMessage(pipe, builder); 288 289 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 290 291 PackedMessageReader reader(pipe); 292 checkTestMessage(reader.getRoot<TestAllTypes>()); 293 } 294 295 TEST(Packed, RoundTripOddSegmentCount) { 296 TestMessageBuilder builder(7); 297 initTestMessage(builder.initRoot<TestAllTypes>()); 298 299 TestPipe pipe; 300 writePackedMessage(pipe, builder); 301 302 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 303 304 PackedMessageReader reader(pipe); 305 checkTestMessage(reader.getRoot<TestAllTypes>()); 306 } 307 308 TEST(Packed, RoundTripOddSegmentCountLazy) { 309 TestMessageBuilder builder(7); 310 initTestMessage(builder.initRoot<TestAllTypes>()); 311 312 TestPipe pipe(1); 313 writePackedMessage(pipe, builder); 314 315 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 316 317 PackedMessageReader reader(pipe); 318 checkTestMessage(reader.getRoot<TestAllTypes>()); 319 } 320 321 TEST(Packed, RoundTripEvenSegmentCount) { 322 TestMessageBuilder builder(10); 323 initTestMessage(builder.initRoot<TestAllTypes>()); 324 325 TestPipe pipe; 326 writePackedMessage(pipe, builder); 327 328 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 329 330 PackedMessageReader reader(pipe); 331 checkTestMessage(reader.getRoot<TestAllTypes>()); 332 } 333 334 TEST(Packed, RoundTripEvenSegmentCountLazy) { 335 TestMessageBuilder builder(10); 336 initTestMessage(builder.initRoot<TestAllTypes>()); 337 338 TestPipe pipe(1); 339 writePackedMessage(pipe, builder); 340 341 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 342 343 PackedMessageReader reader(pipe); 344 checkTestMessage(reader.getRoot<TestAllTypes>()); 345 } 346 347 TEST(Packed, RoundTripTwoMessages) { 348 TestMessageBuilder builder(1); 349 initTestMessage(builder.initRoot<TestAllTypes>()); 350 351 TestMessageBuilder builder2(1); 352 builder2.initRoot<TestAllTypes>().setTextField("Second message."); 353 354 TestPipe pipe; 355 writePackedMessage(pipe, builder); 356 writePackedMessage(pipe, builder2); 357 358 EXPECT_EQ(computeSerializedSizeInWords(builder) + computeSerializedSizeInWords(builder2), 359 computeUnpackedSizeInWords(pipe.getArray())); 360 361 { 362 PackedMessageReader reader(pipe); 363 checkTestMessage(reader.getRoot<TestAllTypes>()); 364 } 365 366 { 367 PackedMessageReader reader(pipe); 368 EXPECT_EQ("Second message.", reader.getRoot<TestAllTypes>().getTextField()); 369 } 370 } 371 372 // ======================================================================================= 373 374 TEST(Packed, RoundTripAllZero) { 375 TestMessageBuilder builder(1); 376 builder.initRoot<TestAllTypes>(); 377 378 TestPipe pipe; 379 writePackedMessage(pipe, builder); 380 381 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 382 383 PackedMessageReader reader(pipe); 384 checkTestMessageAllZero(reader.getRoot<TestAllTypes>()); 385 386 // Segment table packs to 2 bytes. 387 // Root pointer packs to 3 bytes. 388 // Content packs to 2 bytes (zero span). 389 EXPECT_LE(pipe.getData().size(), 7u); 390 } 391 392 TEST(Packed, RoundTripAllZeroScratchSpace) { 393 TestMessageBuilder builder(1); 394 builder.initRoot<TestAllTypes>(); 395 396 TestPipe pipe; 397 writePackedMessage(pipe, builder); 398 399 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 400 401 word scratch[1024]; 402 PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr<word>(scratch, 1024)); 403 checkTestMessageAllZero(reader.getRoot<TestAllTypes>()); 404 } 405 406 TEST(Packed, RoundTripAllZeroLazy) { 407 TestMessageBuilder builder(1); 408 builder.initRoot<TestAllTypes>(); 409 410 TestPipe pipe(1); 411 writePackedMessage(pipe, builder); 412 413 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 414 415 PackedMessageReader reader(pipe); 416 checkTestMessageAllZero(reader.getRoot<TestAllTypes>()); 417 } 418 419 TEST(Packed, RoundTripAllZeroOddSegmentCount) { 420 TestMessageBuilder builder(3); 421 builder.initRoot<TestAllTypes>().initStructField().initStructField(); 422 423 TestPipe pipe; 424 writePackedMessage(pipe, builder); 425 426 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 427 428 PackedMessageReader reader(pipe); 429 checkTestMessageAllZero(reader.getRoot<TestAllTypes>()); 430 } 431 432 TEST(Packed, RoundTripAllZeroOddSegmentCountLazy) { 433 TestMessageBuilder builder(3); 434 builder.initRoot<TestAllTypes>().initStructField().initStructField(); 435 436 TestPipe pipe(1); 437 writePackedMessage(pipe, builder); 438 439 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 440 441 PackedMessageReader reader(pipe); 442 checkTestMessageAllZero(reader.getRoot<TestAllTypes>()); 443 } 444 445 TEST(Packed, RoundTripAllZeroEvenSegmentCount) { 446 TestMessageBuilder builder(2); 447 builder.initRoot<TestAllTypes>().initStructField().initStructField(); 448 449 TestPipe pipe; 450 writePackedMessage(pipe, builder); 451 452 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 453 454 PackedMessageReader reader(pipe); 455 checkTestMessageAllZero(reader.getRoot<TestAllTypes>()); 456 } 457 458 TEST(Packed, RoundTripAllZeroEvenSegmentCountLazy) { 459 TestMessageBuilder builder(2); 460 builder.initRoot<TestAllTypes>().initStructField().initStructField(); 461 462 TestPipe pipe(1); 463 writePackedMessage(pipe, builder); 464 465 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 466 467 PackedMessageReader reader(pipe); 468 checkTestMessageAllZero(reader.getRoot<TestAllTypes>()); 469 } 470 471 // ======================================================================================= 472 473 TEST(Packed, RoundTripHugeString) { 474 kj::String huge = kj::heapString(5023); 475 memset(huge.begin(), 'x', 5023); 476 477 TestMessageBuilder builder(1); 478 builder.initRoot<TestAllTypes>().setTextField(huge); 479 480 TestPipe pipe; 481 writePackedMessage(pipe, builder); 482 483 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 484 485 PackedMessageReader reader(pipe); 486 EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge); 487 } 488 489 TEST(Packed, RoundTripHugeStringScratchSpace) { 490 kj::String huge = kj::heapString(5023); 491 memset(huge.begin(), 'x', 5023); 492 493 TestMessageBuilder builder(1); 494 builder.initRoot<TestAllTypes>().setTextField(huge); 495 496 TestPipe pipe; 497 writePackedMessage(pipe, builder); 498 499 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 500 501 word scratch[1024]; 502 PackedMessageReader reader(pipe, ReaderOptions(), kj::ArrayPtr<word>(scratch, 1024)); 503 EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge); 504 } 505 506 TEST(Packed, RoundTripHugeStringLazy) { 507 kj::String huge = kj::heapString(5023); 508 memset(huge.begin(), 'x', 5023); 509 510 TestMessageBuilder builder(1); 511 builder.initRoot<TestAllTypes>().setTextField(huge); 512 513 TestPipe pipe(1); 514 writePackedMessage(pipe, builder); 515 516 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 517 518 PackedMessageReader reader(pipe); 519 EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge); 520 } 521 522 TEST(Packed, RoundTripHugeStringOddSegmentCount) { 523 kj::String huge = kj::heapString(5023); 524 memset(huge.begin(), 'x', 5023); 525 526 TestMessageBuilder builder(3); 527 builder.initRoot<TestAllTypes>().setTextField(huge); 528 529 TestPipe pipe; 530 writePackedMessage(pipe, builder); 531 532 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 533 534 PackedMessageReader reader(pipe); 535 EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge); 536 } 537 538 TEST(Packed, RoundTripHugeStringOddSegmentCountLazy) { 539 kj::String huge = kj::heapString(5023); 540 memset(huge.begin(), 'x', 5023); 541 542 TestMessageBuilder builder(3); 543 builder.initRoot<TestAllTypes>().setTextField(huge); 544 545 TestPipe pipe(1); 546 writePackedMessage(pipe, builder); 547 548 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 549 550 PackedMessageReader reader(pipe); 551 EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge); 552 } 553 554 TEST(Packed, RoundTripHugeStringEvenSegmentCount) { 555 kj::String huge = kj::heapString(5023); 556 memset(huge.begin(), 'x', 5023); 557 558 TestMessageBuilder builder(2); 559 builder.initRoot<TestAllTypes>().setTextField(huge); 560 561 TestPipe pipe; 562 writePackedMessage(pipe, builder); 563 564 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 565 566 PackedMessageReader reader(pipe); 567 EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge); 568 } 569 570 TEST(Packed, RoundTripHugeStringEvenSegmentCountLazy) { 571 kj::String huge = kj::heapString(5023); 572 memset(huge.begin(), 'x', 5023); 573 574 TestMessageBuilder builder(2); 575 builder.initRoot<TestAllTypes>().setTextField(huge); 576 577 TestPipe pipe(1); 578 writePackedMessage(pipe, builder); 579 580 EXPECT_EQ(computeSerializedSizeInWords(builder), computeUnpackedSizeInWords(pipe.getArray())); 581 582 PackedMessageReader reader(pipe); 583 EXPECT_TRUE(reader.getRoot<TestAllTypes>().getTextField() == huge); 584 } 585 586 // TODO(test): Test error cases. 587 588 } // namespace 589 } // namespace _ (private) 590 } // namespace capnp