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

array-test.c++ (14366B)


      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 "array.h"
     23 #include "debug.h"
     24 #include <string>
     25 #include <list>
     26 #include <kj/compat/gtest.h>
     27 
     28 namespace kj {
     29 namespace {
     30 
     31 struct TestObject {
     32   TestObject() {
     33     index = count;
     34     KJ_ASSERT(index != throwAt);
     35     ++count;
     36   }
     37   TestObject(const TestObject& other) {
     38     KJ_ASSERT(other.index != throwAt);
     39     index = -1;
     40     copiedCount++;
     41   }
     42   ~TestObject() noexcept(false) {
     43     if (index == -1) {
     44       --copiedCount;
     45     } else {
     46       --count;
     47       EXPECT_EQ(index, count);
     48       KJ_ASSERT(count != throwAt);
     49     }
     50   }
     51 
     52   int index;
     53 
     54   static int count;
     55   static int copiedCount;
     56   static int throwAt;
     57 };
     58 
     59 int TestObject::count = 0;
     60 int TestObject::copiedCount = 0;
     61 int TestObject::throwAt = -1;
     62 
     63 struct TestNoexceptObject {
     64   TestNoexceptObject() noexcept {
     65     index = count;
     66     ++count;
     67   }
     68   TestNoexceptObject(const TestNoexceptObject& other) noexcept {
     69     index = -1;
     70     copiedCount++;
     71   }
     72   ~TestNoexceptObject() noexcept {
     73     if (index == -1) {
     74       --copiedCount;
     75     } else {
     76       --count;
     77       EXPECT_EQ(index, count);
     78     }
     79   }
     80 
     81   int index;
     82 
     83   static int count;
     84   static int copiedCount;
     85 };
     86 
     87 int TestNoexceptObject::count = 0;
     88 int TestNoexceptObject::copiedCount = 0;
     89 
     90 TEST(Array, TrivialConstructor) {
     91 //  char* ptr;
     92   {
     93     Array<char> chars = heapArray<char>(32);
     94 //    ptr = chars.begin();
     95     chars[0] = 12;
     96     chars[1] = 34;
     97   }
     98 
     99   {
    100     Array<char> chars = heapArray<char>(32);
    101 
    102     // TODO(test):  The following doesn't work in opt mode -- I guess some allocators zero the
    103     //   memory?  Is there some other way we can test this?  Maybe override malloc()?
    104 //    // Somewhat hacky:  We can't guarantee that the new array is allocated in the same place, but
    105 //    // any reasonable allocator is highly likely to do so.  If it does, then we expect that the
    106 //    // memory has not been initialized.
    107 //    if (chars.begin() == ptr) {
    108 //      EXPECT_NE(chars[0], 0);
    109 //      EXPECT_NE(chars[1], 0);
    110 //    }
    111   }
    112 }
    113 
    114 TEST(Array, ComplexConstructor) {
    115   TestObject::count = 0;
    116   TestObject::throwAt = -1;
    117 
    118   {
    119     Array<TestObject> array = heapArray<TestObject>(32);
    120     EXPECT_EQ(32, TestObject::count);
    121   }
    122   EXPECT_EQ(0, TestObject::count);
    123 }
    124 
    125 #if !KJ_NO_EXCEPTIONS
    126 TEST(Array, ThrowingConstructor) {
    127   TestObject::count = 0;
    128   TestObject::throwAt = 16;
    129 
    130   // If a constructor throws, the previous elements should still be destroyed.
    131   EXPECT_ANY_THROW(heapArray<TestObject>(32));
    132   EXPECT_EQ(0, TestObject::count);
    133 }
    134 
    135 TEST(Array, ThrowingDestructor) {
    136   TestObject::count = 0;
    137   TestObject::throwAt = -1;
    138 
    139   Array<TestObject> array = heapArray<TestObject>(32);
    140   EXPECT_EQ(32, TestObject::count);
    141 
    142   // If a destructor throws, all elements should still be destroyed.
    143   TestObject::throwAt = 16;
    144   EXPECT_ANY_THROW(array = nullptr);
    145   EXPECT_EQ(0, TestObject::count);
    146 }
    147 #endif  // !KJ_NO_EXCEPTIONS
    148 
    149 TEST(Array, AraryBuilder) {
    150   TestObject::count = 0;
    151   TestObject::throwAt = -1;
    152 
    153   Array<TestObject> array;
    154 
    155   {
    156     ArrayBuilder<TestObject> builder = heapArrayBuilder<TestObject>(32);
    157 
    158     for (int i = 0; i < 32; i++) {
    159       EXPECT_EQ(i, TestObject::count);
    160       builder.add();
    161     }
    162 
    163     EXPECT_EQ(32, TestObject::count);
    164     array = builder.finish();
    165     EXPECT_EQ(32, TestObject::count);
    166   }
    167 
    168   EXPECT_EQ(32, TestObject::count);
    169   array = nullptr;
    170   EXPECT_EQ(0, TestObject::count);
    171 }
    172 
    173 TEST(Array, AraryBuilderAddAll) {
    174   {
    175     // Trivial case.
    176     char text[] = "foo";
    177     ArrayBuilder<char> builder = heapArrayBuilder<char>(5);
    178     builder.add('<');
    179     builder.addAll(text, text + 3);
    180     builder.add('>');
    181     auto array = builder.finish();
    182     EXPECT_EQ("<foo>", std::string(array.begin(), array.end()));
    183   }
    184 
    185   {
    186     // Trivial case, const.
    187     const char* text = "foo";
    188     ArrayBuilder<char> builder = heapArrayBuilder<char>(5);
    189     builder.add('<');
    190     builder.addAll(text, text + 3);
    191     builder.add('>');
    192     auto array = builder.finish();
    193     EXPECT_EQ("<foo>", std::string(array.begin(), array.end()));
    194   }
    195 
    196   {
    197     // Trivial case, non-pointer iterator.
    198     std::list<char> text = {'f', 'o', 'o'};
    199     ArrayBuilder<char> builder = heapArrayBuilder<char>(5);
    200     builder.add('<');
    201     builder.addAll(text);
    202     builder.add('>');
    203     auto array = builder.finish();
    204     EXPECT_EQ("<foo>", std::string(array.begin(), array.end()));
    205   }
    206 
    207   {
    208     // Complex case.
    209     std::string strs[] = {"foo", "bar", "baz"};
    210     ArrayBuilder<std::string> builder = heapArrayBuilder<std::string>(5);
    211     builder.add("qux");
    212     builder.addAll(strs, strs + 3);
    213     builder.add("quux");
    214     auto array = builder.finish();
    215     EXPECT_EQ("qux", array[0]);
    216     EXPECT_EQ("foo", array[1]);
    217     EXPECT_EQ("bar", array[2]);
    218     EXPECT_EQ("baz", array[3]);
    219     EXPECT_EQ("quux", array[4]);
    220   }
    221 
    222   {
    223     // Complex case, noexcept.
    224     TestNoexceptObject::count = 0;
    225     TestNoexceptObject::copiedCount = 0;
    226     TestNoexceptObject objs[3];
    227     EXPECT_EQ(3, TestNoexceptObject::count);
    228     EXPECT_EQ(0, TestNoexceptObject::copiedCount);
    229     ArrayBuilder<TestNoexceptObject> builder = heapArrayBuilder<TestNoexceptObject>(3);
    230     EXPECT_EQ(3, TestNoexceptObject::count);
    231     EXPECT_EQ(0, TestNoexceptObject::copiedCount);
    232     builder.addAll(objs, objs + 3);
    233     EXPECT_EQ(3, TestNoexceptObject::count);
    234     EXPECT_EQ(3, TestNoexceptObject::copiedCount);
    235     auto array = builder.finish();
    236     EXPECT_EQ(3, TestNoexceptObject::count);
    237     EXPECT_EQ(3, TestNoexceptObject::copiedCount);
    238   }
    239   EXPECT_EQ(0, TestNoexceptObject::count);
    240   EXPECT_EQ(0, TestNoexceptObject::copiedCount);
    241 
    242   {
    243     // Complex case, exceptions possible.
    244     TestObject::count = 0;
    245     TestObject::copiedCount = 0;
    246     TestObject::throwAt = -1;
    247     TestObject objs[3];
    248     EXPECT_EQ(3, TestObject::count);
    249     EXPECT_EQ(0, TestObject::copiedCount);
    250     ArrayBuilder<TestObject> builder = heapArrayBuilder<TestObject>(3);
    251     EXPECT_EQ(3, TestObject::count);
    252     EXPECT_EQ(0, TestObject::copiedCount);
    253     builder.addAll(objs, objs + 3);
    254     EXPECT_EQ(3, TestObject::count);
    255     EXPECT_EQ(3, TestObject::copiedCount);
    256     auto array = builder.finish();
    257     EXPECT_EQ(3, TestObject::count);
    258     EXPECT_EQ(3, TestObject::copiedCount);
    259   }
    260   EXPECT_EQ(0, TestObject::count);
    261   EXPECT_EQ(0, TestObject::copiedCount);
    262 
    263 #if !KJ_NO_EXCEPTIONS
    264   {
    265     // Complex case, exceptions occur.
    266     TestObject::count = 0;
    267     TestObject::copiedCount = 0;
    268     TestObject::throwAt = -1;
    269     TestObject objs[3];
    270     EXPECT_EQ(3, TestObject::count);
    271     EXPECT_EQ(0, TestObject::copiedCount);
    272 
    273     TestObject::throwAt = 1;
    274 
    275     ArrayBuilder<TestObject> builder = heapArrayBuilder<TestObject>(3);
    276     EXPECT_EQ(3, TestObject::count);
    277     EXPECT_EQ(0, TestObject::copiedCount);
    278 
    279     EXPECT_ANY_THROW(builder.addAll(objs, objs + 3));
    280     TestObject::throwAt = -1;
    281 
    282     EXPECT_EQ(3, TestObject::count);
    283     EXPECT_EQ(0, TestObject::copiedCount);
    284   }
    285   EXPECT_EQ(0, TestObject::count);
    286   EXPECT_EQ(0, TestObject::copiedCount);
    287 #endif  // !KJ_NO_EXCEPTIONS
    288 }
    289 
    290 TEST(Array, HeapCopy) {
    291   {
    292     Array<char> copy = heapArray("foo", 3);
    293     EXPECT_EQ(3u, copy.size());
    294     EXPECT_EQ("foo", std::string(copy.begin(), 3));
    295   }
    296   {
    297     Array<char> copy = heapArray(ArrayPtr<const char>("bar", 3));
    298     EXPECT_EQ(3u, copy.size());
    299     EXPECT_EQ("bar", std::string(copy.begin(), 3));
    300   }
    301   {
    302     const char* ptr = "baz";
    303     Array<char> copy = heapArray<char>(ptr, ptr + 3);
    304     EXPECT_EQ(3u, copy.size());
    305     EXPECT_EQ("baz", std::string(copy.begin(), 3));
    306   }
    307 }
    308 
    309 TEST(Array, OwnConst) {
    310   ArrayBuilder<int> builder = heapArrayBuilder<int>(2);
    311   int x[2] = {123, 234};
    312   builder.addAll(x, x + 2);
    313 
    314   Array<int> i = builder.finish(); //heapArray<int>({123, 234});
    315   ASSERT_EQ(2u, i.size());
    316   EXPECT_EQ(123, i[0]);
    317   EXPECT_EQ(234, i[1]);
    318 
    319   Array<const int> ci = mv(i);
    320   ASSERT_EQ(2u, ci.size());
    321   EXPECT_EQ(123, ci[0]);
    322   EXPECT_EQ(234, ci[1]);
    323 
    324   Array<const int> ci2 = heapArray<const int>({345, 456});
    325   ASSERT_EQ(2u, ci2.size());
    326   EXPECT_EQ(345, ci2[0]);
    327   EXPECT_EQ(456, ci2[1]);
    328 }
    329 
    330 TEST(Array, Map) {
    331   StringPtr foo = "abcd";
    332   Array<char> bar = KJ_MAP(c, foo) -> char { return c + 1; };
    333   EXPECT_STREQ("bcde", str(bar).cStr());
    334 }
    335 
    336 TEST(Array, MapRawArray) {
    337   uint foo[4] = {1, 2, 3, 4};
    338   Array<uint> bar = KJ_MAP(i, foo) -> uint { return i * i; };
    339   ASSERT_EQ(4, bar.size());
    340   EXPECT_EQ(1, bar[0]);
    341   EXPECT_EQ(4, bar[1]);
    342   EXPECT_EQ(9, bar[2]);
    343   EXPECT_EQ(16, bar[3]);
    344 }
    345 
    346 TEST(Array, ReleaseAsBytesOrChars) {
    347   {
    348     Array<char> chars = kj::heapArray<char>("foo", 3);
    349     Array<byte> bytes = chars.releaseAsBytes();
    350     EXPECT_TRUE(chars == nullptr);
    351     ASSERT_EQ(3, bytes.size());
    352     EXPECT_EQ('f', bytes[0]);
    353     EXPECT_EQ('o', bytes[1]);
    354     EXPECT_EQ('o', bytes[2]);
    355 
    356     chars = bytes.releaseAsChars();
    357     EXPECT_TRUE(bytes == nullptr);
    358     ASSERT_EQ(3, chars.size());
    359     EXPECT_EQ('f', chars[0]);
    360     EXPECT_EQ('o', chars[1]);
    361     EXPECT_EQ('o', chars[2]);
    362   }
    363   {
    364     Array<const char> chars = kj::heapArray<char>("foo", 3);
    365     Array<const byte> bytes = chars.releaseAsBytes();
    366     EXPECT_TRUE(chars == nullptr);
    367     ASSERT_EQ(3, bytes.size());
    368     EXPECT_EQ('f', bytes[0]);
    369     EXPECT_EQ('o', bytes[1]);
    370     EXPECT_EQ('o', bytes[2]);
    371 
    372     chars = bytes.releaseAsChars();
    373     EXPECT_TRUE(bytes == nullptr);
    374     ASSERT_EQ(3, chars.size());
    375     EXPECT_EQ('f', chars[0]);
    376     EXPECT_EQ('o', chars[1]);
    377     EXPECT_EQ('o', chars[2]);
    378   }
    379 }
    380 
    381 #if __cplusplus > 201402L
    382 KJ_TEST("kj::arr()") {
    383   kj::Array<kj::String> array = kj::arr(kj::str("foo"), kj::str(123));
    384   KJ_EXPECT(array == kj::ArrayPtr<const kj::StringPtr>({"foo", "123"}));
    385 }
    386 
    387 struct ImmovableInt {
    388   ImmovableInt(int i): i(i) {}
    389   KJ_DISALLOW_COPY(ImmovableInt);
    390   int i;
    391 };
    392 
    393 KJ_TEST("kj::arrOf()") {
    394   kj::Array<ImmovableInt> array = kj::arrOf<ImmovableInt>(123, 456, 789);
    395   KJ_ASSERT(array.size() == 3);
    396   KJ_EXPECT(array[0].i == 123);
    397   KJ_EXPECT(array[1].i == 456);
    398   KJ_EXPECT(array[2].i == 789);
    399 }
    400 #endif
    401 
    402 struct DestructionOrderRecorder {
    403   DestructionOrderRecorder(uint& counter, uint& recordTo)
    404       : counter(counter), recordTo(recordTo) {}
    405   ~DestructionOrderRecorder() {
    406     recordTo = ++counter;
    407   }
    408 
    409   uint& counter;
    410   uint& recordTo;
    411 };
    412 
    413 TEST(Array, Attach) {
    414   uint counter = 0;
    415   uint destroyed1 = 0;
    416   uint destroyed2 = 0;
    417   uint destroyed3 = 0;
    418 
    419   auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1);
    420   auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2);
    421   auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3);
    422 
    423   auto builder = kj::heapArrayBuilder<Own<DestructionOrderRecorder>>(1);
    424   builder.add(kj::mv(obj1));
    425   auto arr = builder.finish();
    426   auto ptr = arr.begin();
    427 
    428   Array<Own<DestructionOrderRecorder>> combined = arr.attach(kj::mv(obj2), kj::mv(obj3));
    429 
    430   KJ_EXPECT(combined.begin() == ptr);
    431 
    432   KJ_EXPECT(obj1.get() == nullptr);
    433   KJ_EXPECT(obj2.get() == nullptr);
    434   KJ_EXPECT(obj3.get() == nullptr);
    435   KJ_EXPECT(destroyed1 == 0);
    436   KJ_EXPECT(destroyed2 == 0);
    437   KJ_EXPECT(destroyed3 == 0);
    438 
    439   combined = nullptr;
    440 
    441   KJ_EXPECT(destroyed1 == 1, destroyed1);
    442   KJ_EXPECT(destroyed2 == 2, destroyed2);
    443   KJ_EXPECT(destroyed3 == 3, destroyed3);
    444 }
    445 
    446 TEST(Array, AttachNested) {
    447   uint counter = 0;
    448   uint destroyed1 = 0;
    449   uint destroyed2 = 0;
    450   uint destroyed3 = 0;
    451 
    452   auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1);
    453   auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2);
    454   auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3);
    455 
    456   auto builder = kj::heapArrayBuilder<Own<DestructionOrderRecorder>>(1);
    457   builder.add(kj::mv(obj1));
    458   auto arr = builder.finish();
    459   auto ptr = arr.begin();
    460 
    461   Array<Own<DestructionOrderRecorder>> combined = arr.attach(kj::mv(obj2)).attach(kj::mv(obj3));
    462 
    463   KJ_EXPECT(combined.begin() == ptr);
    464   KJ_EXPECT(combined.size() == 1);
    465 
    466   KJ_EXPECT(obj1.get() == nullptr);
    467   KJ_EXPECT(obj2.get() == nullptr);
    468   KJ_EXPECT(obj3.get() == nullptr);
    469   KJ_EXPECT(destroyed1 == 0);
    470   KJ_EXPECT(destroyed2 == 0);
    471   KJ_EXPECT(destroyed3 == 0);
    472 
    473   combined = nullptr;
    474 
    475   KJ_EXPECT(destroyed1 == 1, destroyed1);
    476   KJ_EXPECT(destroyed2 == 2, destroyed2);
    477   KJ_EXPECT(destroyed3 == 3, destroyed3);
    478 }
    479 
    480 TEST(Array, AttachFromArrayPtr) {
    481   uint counter = 0;
    482   uint destroyed1 = 0;
    483   uint destroyed2 = 0;
    484   uint destroyed3 = 0;
    485 
    486   auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1);
    487   auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2);
    488   auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3);
    489 
    490   auto builder = kj::heapArrayBuilder<Own<DestructionOrderRecorder>>(1);
    491   builder.add(kj::mv(obj1));
    492   auto arr = builder.finish();
    493   auto ptr = arr.begin();
    494 
    495   Array<Own<DestructionOrderRecorder>> combined =
    496       arr.asPtr().attach(kj::mv(obj2)).attach(kj::mv(obj3));
    497   KJ_EXPECT(arr != nullptr);
    498 
    499   KJ_EXPECT(combined.begin() == ptr);
    500 
    501   KJ_EXPECT(obj1.get() == nullptr);
    502   KJ_EXPECT(obj2.get() == nullptr);
    503   KJ_EXPECT(obj3.get() == nullptr);
    504   KJ_EXPECT(destroyed1 == 0);
    505   KJ_EXPECT(destroyed2 == 0);
    506   KJ_EXPECT(destroyed3 == 0);
    507 
    508   combined = nullptr;
    509 
    510   KJ_EXPECT(destroyed2 == 1, destroyed2);
    511   KJ_EXPECT(destroyed3 == 2, destroyed3);
    512 
    513   arr = nullptr;
    514 
    515   KJ_EXPECT(destroyed1 == 3, destroyed1);
    516 }
    517 
    518 }  // namespace
    519 }  // namespace kj