Home | History | Annotate | Download | only in tests
      1 ///////////////////////////////////////////////////////////////////////////////
      2 //
      3 // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
      4 //
      5 // This code is licensed under the MIT License (MIT).
      6 //
      7 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      8 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      9 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     10 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     11 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     12 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     13 // THE SOFTWARE.
     14 //
     15 ///////////////////////////////////////////////////////////////////////////////
     16 
     17 #include <catch/catch.hpp>
     18 
     19 #include <gsl/gsl>
     20 
     21 #include <memory>
     22 #include <string>
     23 #include <vector>
     24 
     25 using namespace gsl;
     26 
     27 struct MyBase
     28 {
     29 };
     30 struct MyDerived : public MyBase
     31 {
     32 };
     33 struct Unrelated
     34 {
     35 };
     36 
     37 // stand-in for a user-defined ref-counted class
     38 template <typename T>
     39 struct RefCounted
     40 {
     41     RefCounted(T* p) : p_(p) {}
     42     operator T*() { return p_; }
     43     T* p_;
     44 };
     45 
     46 // user defined smart pointer with comparison operators returning non bool value
     47 template <typename T>
     48 struct CustomPtr
     49 {
     50     CustomPtr(T* p) : p_(p) {}
     51     operator T*() { return p_; }
     52     bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
     53     T* p_ = nullptr;
     54 };
     55 
     56 template <typename T, typename U>
     57 std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
     58 {
     59     return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
     60                                                                                           : "false";
     61 }
     62 
     63 template <typename T, typename U>
     64 std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
     65 {
     66     return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
     67                                                                                           : "false";
     68 }
     69 
     70 template <typename T, typename U>
     71 std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
     72 {
     73     return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
     74                                                                                          : "false";
     75 }
     76 
     77 template <typename T, typename U>
     78 std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
     79 {
     80     return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
     81                                                                                          : "false";
     82 }
     83 
     84 template <typename T, typename U>
     85 std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
     86 {
     87     return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
     88                                                                                           : "false";
     89 }
     90 
     91 template <typename T, typename U>
     92 std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
     93 {
     94     return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
     95                                                                                           : "false";
     96 }
     97 
     98 struct NonCopyableNonMovable
     99 {
    100     NonCopyableNonMovable() = default;
    101     NonCopyableNonMovable(const NonCopyableNonMovable&) = delete;
    102     NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete;
    103     NonCopyableNonMovable(NonCopyableNonMovable&&) = delete;
    104     NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete;
    105 };
    106 
    107 bool helper(not_null<int*> p) { return *p == 12; }
    108 
    109 TEST_CASE("TestNotNullConstructors")
    110 {
    111 #ifdef CONFIRM_COMPILATION_ERRORS
    112     not_null<int*> p = nullptr;         // yay...does not compile!
    113     not_null<std::vector<char>*> p = 0; // yay...does not compile!
    114     not_null<int*> p;                   // yay...does not compile!
    115     std::unique_ptr<int> up = std::make_unique<int>(120);
    116     not_null<int*> p = up;
    117 
    118     // Forbid non-nullptr assignable types
    119     not_null<std::vector<int>> f(std::vector<int>{1});
    120     not_null<int> z(10);
    121     not_null<std::vector<int>> y({1, 2});
    122 #endif
    123     int i = 12;
    124     auto rp = RefCounted<int>(&i);
    125     not_null<int*> p(rp);
    126     CHECK(p.get() == &i);
    127 
    128     not_null<std::shared_ptr<int>> x(
    129         std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
    130 }
    131 
    132 TEST_CASE("TestNotNullCasting")
    133 {
    134     MyBase base;
    135     MyDerived derived;
    136     Unrelated unrelated;
    137     not_null<Unrelated*> u = &unrelated;
    138     (void) u;
    139     not_null<MyDerived*> p = &derived;
    140     not_null<MyBase*> q = &base;
    141     q = p; // allowed with heterogeneous copy ctor
    142     CHECK(q == p);
    143 
    144 #ifdef CONFIRM_COMPILATION_ERRORS
    145     q = u; // no viable conversion possible between MyBase* and Unrelated*
    146     p = q; // not possible to implicitly convert MyBase* to MyDerived*
    147 
    148     not_null<Unrelated*> r = p;
    149     not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
    150 #endif
    151     not_null<Unrelated*> t = reinterpret_cast<Unrelated*>(p.get());
    152     CHECK(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
    153 }
    154 
    155 TEST_CASE("TestNotNullAssignment")
    156 {
    157     int i = 12;
    158     not_null<int*> p = &i;
    159     CHECK(helper(p));
    160 
    161     int* q = nullptr;
    162     CHECK_THROWS_AS(p = q, fail_fast);
    163 }
    164 
    165 TEST_CASE("TestNotNullRawPointerComparison")
    166 {
    167     int ints[2] = {42, 43};
    168     int* p1 = &ints[0];
    169     const int* p2 = &ints[1];
    170 
    171     using NotNull1 = not_null<decltype(p1)>;
    172     using NotNull2 = not_null<decltype(p2)>;
    173 
    174     CHECK((NotNull1(p1) == NotNull1(p1)) == true);
    175     CHECK((NotNull1(p1) == NotNull2(p2)) == false);
    176 
    177     CHECK((NotNull1(p1) != NotNull1(p1)) == false);
    178     CHECK((NotNull1(p1) != NotNull2(p2)) == true);
    179 
    180     CHECK((NotNull1(p1) < NotNull1(p1)) == false);
    181     CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
    182     CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
    183 
    184     CHECK((NotNull1(p1) > NotNull1(p1)) == false);
    185     CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
    186     CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
    187 
    188     CHECK((NotNull1(p1) <= NotNull1(p1)) == true);
    189     CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
    190     CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
    191 
    192 }
    193 
    194 TEST_CASE("TestNotNullDereferenceOperator")
    195 {
    196     {
    197         auto sp1 = std::make_shared<NonCopyableNonMovable>();
    198 
    199         using NotNullSp1 = not_null<decltype(sp1)>;
    200         CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1)));
    201         CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1));
    202     }
    203 
    204     {
    205         int ints[1] = { 42 };
    206         CustomPtr<int> p1(&ints[0]);
    207 
    208         using NotNull1 = not_null<decltype(p1)>;
    209         CHECK(typeid(*NotNull1(p1)) == typeid(*p1));
    210         CHECK(*NotNull1(p1) == 42);
    211         *NotNull1(p1) = 43;
    212         CHECK(ints[0] == 43);
    213     }
    214 
    215     {
    216         int v = 42;
    217         gsl::not_null<int*> p(&v);
    218         CHECK(typeid(*p) == typeid(*(&v)));
    219         *p = 43;
    220         CHECK(v == 43);
    221     }
    222 }
    223 
    224 TEST_CASE("TestNotNullSharedPtrComparison")
    225 {
    226     auto sp1 = std::make_shared<int>(42);
    227     auto sp2 = std::make_shared<const int>(43);
    228 
    229     using NotNullSp1 = not_null<decltype(sp1)>;
    230     using NotNullSp2 = not_null<decltype(sp2)>;
    231 
    232     CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true);
    233     CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false);
    234 
    235     CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false);
    236     CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true);
    237 
    238     CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false);
    239     CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2));
    240     CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1));
    241 
    242     CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false);
    243     CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2));
    244     CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1));
    245 
    246     CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true);
    247     CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2));
    248     CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1));
    249 
    250     CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true);
    251     CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2));
    252     CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1));
    253 }
    254 
    255 TEST_CASE("TestNotNullCustomPtrComparison")
    256 {
    257     int ints[2] = {42, 43};
    258     CustomPtr<int> p1(&ints[0]);
    259     CustomPtr<const int> p2(&ints[1]);
    260 
    261     using NotNull1 = not_null<decltype(p1)>;
    262     using NotNull2 = not_null<decltype(p2)>;
    263 
    264     CHECK((NotNull1(p1) == NotNull1(p1)) == "true");
    265     CHECK((NotNull1(p1) == NotNull2(p2)) == "false");
    266 
    267     CHECK((NotNull1(p1) != NotNull1(p1)) == "false");
    268     CHECK((NotNull1(p1) != NotNull2(p2)) == "true");
    269 
    270     CHECK((NotNull1(p1) < NotNull1(p1)) == "false");
    271     CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
    272     CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
    273 
    274     CHECK((NotNull1(p1) > NotNull1(p1)) == "false");
    275     CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
    276     CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
    277 
    278     CHECK((NotNull1(p1) <= NotNull1(p1)) == "true");
    279     CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
    280     CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
    281 
    282     CHECK((NotNull1(p1) >= NotNull1(p1)) == "true");
    283     CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2));
    284     CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1));
    285 }
    286