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

io-test.c++ (6873B)


      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 #ifndef _GNU_SOURCE
     23 #define _GNU_SOURCE
     24 #endif
     25 
     26 #include "io.h"
     27 #include "debug.h"
     28 #include "miniposix.h"
     29 #include <kj/compat/gtest.h>
     30 
     31 namespace kj {
     32 namespace {
     33 
     34 TEST(Io, WriteVec) {
     35   // Check that writing an array of arrays works even when some of the arrays are empty.  (This
     36   // used to not work in some cases.)
     37 
     38   int fds[2];
     39   KJ_SYSCALL(miniposix::pipe(fds));
     40 
     41   FdInputStream in((AutoCloseFd(fds[0])));
     42   FdOutputStream out((AutoCloseFd(fds[1])));
     43 
     44   ArrayPtr<const byte> pieces[5] = {
     45     arrayPtr(implicitCast<const byte*>(nullptr), 0),
     46     arrayPtr(reinterpret_cast<const byte*>("foo"), 3),
     47     arrayPtr(implicitCast<const byte*>(nullptr), 0),
     48     arrayPtr(reinterpret_cast<const byte*>("bar"), 3),
     49     arrayPtr(implicitCast<const byte*>(nullptr), 0)
     50   };
     51 
     52   out.write(pieces);
     53 
     54   char buf[7];
     55   in.read(buf, 6);
     56   buf[6] = '\0';
     57 
     58   EXPECT_STREQ("foobar", buf);
     59 }
     60 
     61 KJ_TEST("stringify AutoCloseFd") {
     62   int fds[2];
     63   KJ_SYSCALL(miniposix::pipe(fds));
     64   AutoCloseFd in(fds[0]), out(fds[1]);
     65 
     66   KJ_EXPECT(kj::str(in) == kj::str(fds[0]), in, fds[0]);
     67 }
     68 
     69 KJ_TEST("VectorOutputStream") {
     70   VectorOutputStream output(16);
     71   auto buf = output.getWriteBuffer();
     72   KJ_ASSERT(buf.size() == 16);
     73 
     74   for (auto i: kj::indices(buf)) {
     75     buf[i] = 'a' + i;
     76   }
     77 
     78   output.write(buf.begin(), 4);
     79   KJ_ASSERT(output.getArray().begin() == buf.begin());
     80   KJ_ASSERT(output.getArray().size() == 4);
     81 
     82   auto buf2 = output.getWriteBuffer();
     83   KJ_ASSERT(buf2.end() == buf.end());
     84   KJ_ASSERT(buf2.size() == 12);
     85 
     86   output.write(buf2.begin(), buf2.size());
     87   KJ_ASSERT(output.getArray().begin() == buf.begin());
     88   KJ_ASSERT(output.getArray().size() == 16);
     89 
     90   auto buf3 = output.getWriteBuffer();
     91   KJ_ASSERT(buf3.size() == 16);
     92   KJ_ASSERT(output.getArray().begin() != buf.begin());
     93   KJ_ASSERT(output.getArray().end() == buf3.begin());
     94   KJ_ASSERT(kj::str(output.getArray().asChars()) == "abcdefghijklmnop");
     95 
     96   byte junk[24];
     97   for (auto i: kj::indices(junk)) {
     98     junk[i] = 'A' + i;
     99   }
    100 
    101   output.write(junk, 4);
    102   KJ_ASSERT(output.getArray().begin() != buf.begin());
    103   KJ_ASSERT(output.getArray().end() == buf3.begin() + 4);
    104   KJ_ASSERT(kj::str(output.getArray().asChars()) == "abcdefghijklmnopABCD");
    105 
    106   output.write(junk + 4, 20);
    107   // (We can't assert output.getArray().begin() != buf.begin() because the memory allocator could
    108   // legitimately have allocated a new array in the same space.)
    109   KJ_ASSERT(output.getArray().end() != buf3.begin() + 24);
    110   KJ_ASSERT(kj::str(output.getArray().asChars()) == "abcdefghijklmnopABCDEFGHIJKLMNOPQRSTUVWX");
    111 
    112   KJ_ASSERT(output.getWriteBuffer().size() == 24);
    113   KJ_ASSERT(output.getWriteBuffer().begin() == output.getArray().begin() + 40);
    114 }
    115 
    116 class MockInputStream: public InputStream {
    117 public:
    118   MockInputStream(kj::ArrayPtr<const byte> bytes, size_t blockSize)
    119       : bytes(bytes), blockSize(blockSize) {}
    120 
    121   size_t tryRead(void* buffer, size_t minBytes, size_t maxBytes) override {
    122     // Clamp max read to blockSize.
    123     size_t n = kj::min(blockSize, maxBytes);
    124 
    125     // Unless that's less than minBytes -- in which case, use minBytes.
    126     n = kj::max(n, minBytes);
    127 
    128     // But also don't read more data than we have.
    129     n = kj::min(n, bytes.size());
    130 
    131     memcpy(buffer, bytes.begin(), n);
    132     bytes = bytes.slice(n, bytes.size());
    133     return n;
    134   }
    135 
    136 private:
    137   kj::ArrayPtr<const byte> bytes;
    138   size_t blockSize;
    139 };
    140 
    141 KJ_TEST("InputStream::readAllText() / readAllBytes()") {
    142   auto bigText = strArray(kj::repeat("foo bar baz"_kj, 12345), ",");
    143   size_t inputSizes[] = { 0, 1, 256, 4096, 8191, 8192, 8193, 10000, bigText.size() };
    144   size_t blockSizes[] = { 1, 4, 256, 4096, 8192, bigText.size() };
    145   uint64_t limits[] = {
    146     0, 1, 256,
    147     bigText.size() / 2,
    148     bigText.size() - 1,
    149     bigText.size(),
    150     bigText.size() + 1,
    151     kj::maxValue
    152   };
    153 
    154   for (size_t inputSize: inputSizes) {
    155     for (size_t blockSize: blockSizes) {
    156       for (uint64_t limit: limits) {
    157         KJ_CONTEXT(inputSize, blockSize, limit);
    158         auto textSlice = bigText.asBytes().slice(0, inputSize);
    159         auto readAllText = [&]() {
    160           MockInputStream input(textSlice, blockSize);
    161           return input.readAllText(limit);
    162         };
    163         auto readAllBytes = [&]() {
    164           MockInputStream input(textSlice, blockSize);
    165           return input.readAllBytes(limit);
    166         };
    167         if (limit > inputSize) {
    168           KJ_EXPECT(readAllText().asBytes() == textSlice);
    169           KJ_EXPECT(readAllBytes() == textSlice);
    170         } else {
    171           KJ_EXPECT_THROW_MESSAGE("Reached limit before EOF.", readAllText());
    172           KJ_EXPECT_THROW_MESSAGE("Reached limit before EOF.", readAllBytes());
    173         }
    174       }
    175     }
    176   }
    177 }
    178 
    179 KJ_TEST("ArrayOutputStream::write() does not assume adjacent write buffer is its own") {
    180   // Previously, if ArrayOutputStream::write(src, size) saw that `src` equaled its fill position, it
    181   // would assume that the write was already in its buffer. This assumption was buggy if the write
    182   // buffer was directly adjacent in memory to the ArrayOutputStream's buffer, and the
    183   // ArrayOutputStream was full (i.e., its fill position was one-past-the-end).
    184   //
    185   // VectorOutputStream also suffered a similar bug, but it is much harder to test, since it
    186   // performs its own allocation.
    187 
    188   kj::byte buffer[10] = { 0 };
    189 
    190   ArrayOutputStream output(arrayPtr(buffer, buffer + 5));
    191 
    192   // Succeeds and fills the ArrayOutputStream.
    193   output.write(buffer + 5, 5);
    194 
    195   // Previously this threw an inscrutable "size <= array.end() - fillPos" requirement failure.
    196   KJ_EXPECT_THROW_MESSAGE(
    197       "backing array was not large enough for the data written",
    198       output.write(buffer + 5, 5));
    199 }
    200 
    201 }  // namespace
    202 }  // namespace kj