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

memory-test.c++ (11840B)


      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 "memory.h"
     23 #include <kj/compat/gtest.h>
     24 #include "debug.h"
     25 
     26 namespace kj {
     27 namespace {
     28 
     29 TEST(Memory, OwnConst) {
     30   Own<int> i = heap<int>(2);
     31   EXPECT_EQ(2, *i);
     32 
     33   Own<const int> ci = mv(i);
     34   EXPECT_EQ(2, *ci);
     35 
     36   Own<const int> ci2 = heap<const int>(3);
     37   EXPECT_EQ(3, *ci2);
     38 }
     39 
     40 TEST(Memory, CanConvert) {
     41   struct Super { virtual ~Super() {} };
     42   struct Sub: public Super {};
     43 
     44   static_assert(canConvert<Own<Sub>, Own<Super>>(), "failure");
     45   static_assert(!canConvert<Own<Super>, Own<Sub>>(), "failure");
     46 }
     47 
     48 struct Nested {
     49   Nested(bool& destroyed): destroyed(destroyed) {}
     50   ~Nested() { destroyed = true; }
     51 
     52   bool& destroyed;
     53   Own<Nested> nested;
     54 };
     55 
     56 TEST(Memory, AssignNested) {
     57   bool destroyed1 = false, destroyed2 = false;
     58   auto nested = heap<Nested>(destroyed1);
     59   nested->nested = heap<Nested>(destroyed2);
     60   EXPECT_FALSE(destroyed1 || destroyed2);
     61   nested = kj::mv(nested->nested);
     62   EXPECT_TRUE(destroyed1);
     63   EXPECT_FALSE(destroyed2);
     64   nested = nullptr;
     65   EXPECT_TRUE(destroyed1 && destroyed2);
     66 }
     67 
     68 struct DestructionOrderRecorder {
     69   DestructionOrderRecorder(uint& counter, uint& recordTo)
     70       : counter(counter), recordTo(recordTo) {}
     71   ~DestructionOrderRecorder() {
     72     recordTo = ++counter;
     73   }
     74 
     75   uint& counter;
     76   uint& recordTo;
     77 };
     78 
     79 TEST(Memory, Attach) {
     80   uint counter = 0;
     81   uint destroyed1 = 0;
     82   uint destroyed2 = 0;
     83   uint destroyed3 = 0;
     84 
     85   auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1);
     86   auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2);
     87   auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3);
     88 
     89   auto ptr = obj1.get();
     90 
     91   Own<DestructionOrderRecorder> combined = obj1.attach(kj::mv(obj2), kj::mv(obj3));
     92 
     93   KJ_EXPECT(combined.get() == ptr);
     94 
     95   KJ_EXPECT(obj1.get() == nullptr);
     96   KJ_EXPECT(obj2.get() == nullptr);
     97   KJ_EXPECT(obj3.get() == nullptr);
     98   KJ_EXPECT(destroyed1 == 0);
     99   KJ_EXPECT(destroyed2 == 0);
    100   KJ_EXPECT(destroyed3 == 0);
    101 
    102   combined = nullptr;
    103 
    104   KJ_EXPECT(destroyed1 == 1, destroyed1);
    105   KJ_EXPECT(destroyed2 == 2, destroyed2);
    106   KJ_EXPECT(destroyed3 == 3, destroyed3);
    107 }
    108 
    109 TEST(Memory, AttachNested) {
    110   uint counter = 0;
    111   uint destroyed1 = 0;
    112   uint destroyed2 = 0;
    113   uint destroyed3 = 0;
    114 
    115   auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1);
    116   auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2);
    117   auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3);
    118 
    119   auto ptr = obj1.get();
    120 
    121   Own<DestructionOrderRecorder> combined = obj1.attach(kj::mv(obj2)).attach(kj::mv(obj3));
    122 
    123   KJ_EXPECT(combined.get() == ptr);
    124 
    125   KJ_EXPECT(obj1.get() == nullptr);
    126   KJ_EXPECT(obj2.get() == nullptr);
    127   KJ_EXPECT(obj3.get() == nullptr);
    128   KJ_EXPECT(destroyed1 == 0);
    129   KJ_EXPECT(destroyed2 == 0);
    130   KJ_EXPECT(destroyed3 == 0);
    131 
    132   combined = nullptr;
    133 
    134   KJ_EXPECT(destroyed1 == 1, destroyed1);
    135   KJ_EXPECT(destroyed2 == 2, destroyed2);
    136   KJ_EXPECT(destroyed3 == 3, destroyed3);
    137 }
    138 
    139 KJ_TEST("attachRef") {
    140   uint counter = 0;
    141   uint destroyed1 = 0;
    142   uint destroyed2 = 0;
    143   uint destroyed3 = 0;
    144 
    145   auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1);
    146   auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2);
    147   auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3);
    148 
    149   int i = 123;
    150 
    151   Own<int> combined = attachRef(i, kj::mv(obj1), kj::mv(obj2), kj::mv(obj3));
    152 
    153   KJ_EXPECT(combined.get() == &i);
    154 
    155   KJ_EXPECT(obj1.get() == nullptr);
    156   KJ_EXPECT(obj2.get() == nullptr);
    157   KJ_EXPECT(obj3.get() == nullptr);
    158   KJ_EXPECT(destroyed1 == 0);
    159   KJ_EXPECT(destroyed2 == 0);
    160   KJ_EXPECT(destroyed3 == 0);
    161 
    162   combined = nullptr;
    163 
    164   KJ_EXPECT(destroyed1 == 1, destroyed1);
    165   KJ_EXPECT(destroyed2 == 2, destroyed2);
    166   KJ_EXPECT(destroyed3 == 3, destroyed3);
    167 }
    168 
    169 KJ_TEST("attachVal") {
    170   uint counter = 0;
    171   uint destroyed1 = 0;
    172   uint destroyed2 = 0;
    173   uint destroyed3 = 0;
    174 
    175   auto obj1 = kj::heap<DestructionOrderRecorder>(counter, destroyed1);
    176   auto obj2 = kj::heap<DestructionOrderRecorder>(counter, destroyed2);
    177   auto obj3 = kj::heap<DestructionOrderRecorder>(counter, destroyed3);
    178 
    179   int i = 123;
    180 
    181   Own<int> combined = attachVal(i, kj::mv(obj1), kj::mv(obj2), kj::mv(obj3));
    182 
    183   int* ptr = combined.get();
    184   KJ_EXPECT(ptr != &i);
    185   KJ_EXPECT(*ptr == i);
    186 
    187   KJ_EXPECT(obj1.get() == nullptr);
    188   KJ_EXPECT(obj2.get() == nullptr);
    189   KJ_EXPECT(obj3.get() == nullptr);
    190   KJ_EXPECT(destroyed1 == 0);
    191   KJ_EXPECT(destroyed2 == 0);
    192   KJ_EXPECT(destroyed3 == 0);
    193 
    194   combined = nullptr;
    195 
    196   KJ_EXPECT(destroyed1 == 1, destroyed1);
    197   KJ_EXPECT(destroyed2 == 2, destroyed2);
    198   KJ_EXPECT(destroyed3 == 3, destroyed3);
    199 }
    200 
    201 struct StaticType {
    202   int i;
    203 };
    204 
    205 struct DynamicType1 {
    206   virtual void foo() {}
    207 
    208   int j;
    209 
    210   DynamicType1(int j): j(j) {}
    211 };
    212 
    213 struct DynamicType2 {
    214   virtual void bar() {}
    215 
    216   int k;
    217 
    218   DynamicType2(int k): k(k) {}
    219 };
    220 
    221 struct SingularDerivedDynamic final: public DynamicType1 {
    222   SingularDerivedDynamic(int j, bool& destructorCalled)
    223       : DynamicType1(j), destructorCalled(destructorCalled) {}
    224 
    225   ~SingularDerivedDynamic() {
    226     destructorCalled = true;
    227   }
    228   KJ_DISALLOW_COPY(SingularDerivedDynamic);
    229 
    230   bool& destructorCalled;
    231 };
    232 
    233 struct MultipleDerivedDynamic final: public DynamicType1, public DynamicType2 {
    234   MultipleDerivedDynamic(int j, int k, bool& destructorCalled)
    235       : DynamicType1(j), DynamicType2(k), destructorCalled(destructorCalled) {}
    236 
    237   ~MultipleDerivedDynamic() {
    238     destructorCalled = true;
    239   }
    240 
    241   KJ_DISALLOW_COPY(MultipleDerivedDynamic);
    242 
    243   bool& destructorCalled;
    244 };
    245 
    246 TEST(Memory, OwnVoid) {
    247   {
    248     Own<StaticType> ptr = heap<StaticType>({123});
    249     StaticType* addr = ptr.get();
    250     Own<void> voidPtr = kj::mv(ptr);
    251     KJ_EXPECT(voidPtr.get() == implicitCast<void*>(addr));
    252   }
    253 
    254   {
    255     bool destructorCalled = false;
    256     Own<SingularDerivedDynamic> ptr = heap<SingularDerivedDynamic>(123, destructorCalled);
    257     SingularDerivedDynamic* addr = ptr.get();
    258     Own<void> voidPtr = kj::mv(ptr);
    259     KJ_EXPECT(voidPtr.get() == implicitCast<void*>(addr));
    260   }
    261 
    262   {
    263     bool destructorCalled = false;
    264     Own<MultipleDerivedDynamic> ptr = heap<MultipleDerivedDynamic>(123, 456, destructorCalled);
    265     MultipleDerivedDynamic* addr = ptr.get();
    266     Own<void> voidPtr = kj::mv(ptr);
    267     KJ_EXPECT(voidPtr.get() == implicitCast<void*>(addr));
    268 
    269     KJ_EXPECT(!destructorCalled);
    270     voidPtr = nullptr;
    271     KJ_EXPECT(destructorCalled);
    272   }
    273 
    274   {
    275     bool destructorCalled = false;
    276     Own<MultipleDerivedDynamic> ptr = heap<MultipleDerivedDynamic>(123, 456, destructorCalled);
    277     MultipleDerivedDynamic* addr = ptr.get();
    278     Own<DynamicType2> basePtr = kj::mv(ptr);
    279     DynamicType2* baseAddr = basePtr.get();
    280 
    281     // On most (all?) C++ ABIs, the second base class in a multiply-inherited class is offset from
    282     // the beginning of the object (assuming the first base class has non-zero size). We use this
    283     // fact here to verify that then casting to Own<void> does in fact result in a pointer that
    284     // points to the start of the overall object, not the base class. We expect that the pointers
    285     // are different here to prove that the test below is non-trivial.
    286     //
    287     // If there is some other ABI where these pointers are the same, and thus this expectation
    288     // fails, then it's no problem to #ifdef out the expectation on that platform.
    289     KJ_EXPECT(static_cast<void*>(baseAddr) != static_cast<void*>(addr));
    290 
    291     Own<void> voidPtr = kj::mv(basePtr);
    292     KJ_EXPECT(voidPtr.get() == static_cast<void*>(addr));
    293 
    294     KJ_EXPECT(!destructorCalled);
    295     voidPtr = nullptr;
    296     KJ_EXPECT(destructorCalled);
    297   }
    298 }
    299 
    300 TEST(Memory, OwnConstVoid) {
    301   {
    302     Own<StaticType> ptr = heap<StaticType>({123});
    303     StaticType* addr = ptr.get();
    304     Own<const void> voidPtr = kj::mv(ptr);
    305     KJ_EXPECT(voidPtr.get() == implicitCast<void*>(addr));
    306   }
    307 
    308   {
    309     bool destructorCalled = false;
    310     Own<SingularDerivedDynamic> ptr = heap<SingularDerivedDynamic>(123, destructorCalled);
    311     SingularDerivedDynamic* addr = ptr.get();
    312     Own<const void> voidPtr = kj::mv(ptr);
    313     KJ_EXPECT(voidPtr.get() == implicitCast<void*>(addr));
    314   }
    315 
    316   {
    317     bool destructorCalled = false;
    318     Own<MultipleDerivedDynamic> ptr = heap<MultipleDerivedDynamic>(123, 456, destructorCalled);
    319     MultipleDerivedDynamic* addr = ptr.get();
    320     Own<const void> voidPtr = kj::mv(ptr);
    321     KJ_EXPECT(voidPtr.get() == implicitCast<void*>(addr));
    322 
    323     KJ_EXPECT(!destructorCalled);
    324     voidPtr = nullptr;
    325     KJ_EXPECT(destructorCalled);
    326   }
    327 
    328   {
    329     bool destructorCalled = false;
    330     Own<MultipleDerivedDynamic> ptr = heap<MultipleDerivedDynamic>(123, 456, destructorCalled);
    331     MultipleDerivedDynamic* addr = ptr.get();
    332     Own<DynamicType2> basePtr = kj::mv(ptr);
    333     DynamicType2* baseAddr = basePtr.get();
    334 
    335     // On most (all?) C++ ABIs, the second base class in a multiply-inherited class is offset from
    336     // the beginning of the object (assuming the first base class has non-zero size). We use this
    337     // fact here to verify that then casting to Own<void> does in fact result in a pointer that
    338     // points to the start of the overall object, not the base class. We expect that the pointers
    339     // are different here to prove that the test below is non-trivial.
    340     //
    341     // If there is some other ABI where these pointers are the same, and thus this expectation
    342     // fails, then it's no problem to #ifdef out the expectation on that platform.
    343     KJ_EXPECT(static_cast<void*>(baseAddr) != static_cast<void*>(addr));
    344 
    345     Own<const void> voidPtr = kj::mv(basePtr);
    346     KJ_EXPECT(voidPtr.get() == static_cast<void*>(addr));
    347 
    348     KJ_EXPECT(!destructorCalled);
    349     voidPtr = nullptr;
    350     KJ_EXPECT(destructorCalled);
    351   }
    352 }
    353 
    354 struct IncompleteType;
    355 KJ_DECLARE_NON_POLYMORPHIC(IncompleteType)
    356 
    357 template <typename T, typename U>
    358 struct IncompleteTemplate;
    359 template <typename T, typename U>
    360 KJ_DECLARE_NON_POLYMORPHIC(IncompleteTemplate<T, U>)
    361 
    362 struct IncompleteDisposer: public Disposer {
    363   mutable void* sawPtr = nullptr;
    364 
    365   virtual void disposeImpl(void* pointer) const {
    366     sawPtr = pointer;
    367   }
    368 };
    369 
    370 KJ_TEST("Own<IncompleteType>") {
    371   static int i;
    372   void* ptr = &i;
    373 
    374   {
    375     IncompleteDisposer disposer;
    376 
    377     {
    378       kj::Own<IncompleteType> foo(reinterpret_cast<IncompleteType*>(ptr), disposer);
    379       kj::Own<IncompleteType> bar = kj::mv(foo);
    380     }
    381 
    382     KJ_EXPECT(disposer.sawPtr == ptr);
    383   }
    384 
    385   {
    386     IncompleteDisposer disposer;
    387 
    388     {
    389       kj::Own<IncompleteTemplate<int, char>> foo(
    390           reinterpret_cast<IncompleteTemplate<int, char>*>(ptr), disposer);
    391       kj::Own<IncompleteTemplate<int, char>> bar = kj::mv(foo);
    392     }
    393 
    394     KJ_EXPECT(disposer.sawPtr == ptr);
    395   }
    396 }
    397 
    398 // TODO(test):  More tests.
    399 
    400 }  // namespace
    401 }  // namespace kj