1 // 2 // Tests for 3 // template <typename U, typename Policy> 4 // bounded_ptr& operator=(bounded_ptr<U, Policy> const& other); 5 // 6 7 #include <libkern/c++/bounded_ptr.h> 8 #include <array> 9 #include <darwintest.h> 10 #include <darwintest_utils.h> 11 #include "test_utils.h" 12 13 #define _assert(...) T_ASSERT_TRUE((__VA_ARGS__), # __VA_ARGS__) 14 15 struct Base { int i; }; 16 struct Derived : Base { }; 17 18 struct Base1 { int i; }; 19 struct Base2 { long l; }; 20 struct DerivedMultiple : Base1, Base2 { 21 DerivedMultiple(int i) : Base1{i}, Base2{i + 10} 22 { 23 } 24 }; 25 26 struct Unrelated { }; 27 28 struct dummy_policy1 { 29 static constexpr void 30 trap(char const*) 31 { 32 } 33 }; 34 struct dummy_policy2 { 35 static constexpr void 36 trap(char const*) 37 { 38 } 39 }; 40 41 template <typename Stored, typename From, typename To> 42 static void 43 tests() 44 { 45 std::array<Stored, 5> array = {Stored{0}, Stored{1}, Stored{2}, Stored{3}, Stored{4}}; 46 Stored* const ptr1 = array.begin() + 2; 47 Stored* const ptr2 = array.begin() + 3; 48 49 { 50 test_bounded_ptr<From> const from(ptr1, array.begin(), array.end()); 51 test_bounded_ptr<To> to; 52 test_bounded_ptr<To>& ref = (to = from); 53 _assert(to.discard_bounds() == static_cast<To const*>(ptr1)); 54 _assert(&ref == &to); // make sure we return *this 55 } 56 57 // Test assigning to a non-null pointer 58 { 59 test_bounded_ptr<From> const from(ptr1, array.begin(), array.end()); 60 test_bounded_ptr<To> to(ptr2, array.begin(), array.end()); 61 _assert(to.discard_bounds() == static_cast<To const*>(ptr2)); 62 63 test_bounded_ptr<To>& ref = (to = from); 64 _assert(to.discard_bounds() == static_cast<To const*>(ptr1)); 65 _assert(&ref == &to); // make sure we return *this 66 } 67 68 // Test assigning from a null pointer 69 { 70 test_bounded_ptr<From> const from = nullptr; 71 test_bounded_ptr<To> to; 72 test_bounded_ptr<To>& ref = (to = from); 73 _assert(to.unsafe_discard_bounds() == nullptr); 74 _assert(&ref == &to); // make sure we return *this 75 } 76 77 // Test with different policies 78 { 79 libkern::bounded_ptr<From, dummy_policy1> from(ptr1, array.begin(), array.end()); 80 libkern::bounded_ptr<To, dummy_policy2> to; 81 libkern::bounded_ptr<To, dummy_policy2>& ref = (to = from); 82 _assert(to.discard_bounds() == static_cast<To const*>(ptr1)); 83 _assert(&ref == &to); // make sure we return *this 84 } 85 86 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 87 // ^ ^ ^ 88 // | | | 89 // from begin end 90 { 91 test_bounded_ptr<From> const from(array.begin(), array.begin() + 1, array.end()); 92 test_bounded_ptr<To> to; 93 to = from; 94 _assert(to.unsafe_discard_bounds() == static_cast<To const*>(array.begin())); 95 } 96 } 97 98 T_DECL(assign_convert, "bounded_ptr.assign.convert") { 99 tests</*stored*/ Derived, /*from*/ Derived, /*to*/ Derived>(); 100 tests</*stored*/ Derived, /*from*/ Derived const, /*to*/ Derived const>(); 101 tests</*stored*/ Derived, /*from*/ Derived volatile, /*to*/ Derived volatile>(); 102 tests</*stored*/ Derived, /*from*/ Derived const volatile, /*to*/ Derived const volatile>(); 103 104 tests</*stored*/ Derived, /*from*/ Derived, /*to*/ Base>(); 105 tests</*stored*/ Derived, /*from*/ Derived const, /*to*/ Base const>(); 106 tests</*stored*/ Derived, /*from*/ Derived volatile, /*to*/ Base volatile>(); 107 tests</*stored*/ Derived, /*from*/ Derived const volatile, /*to*/ Base const volatile>(); 108 109 tests</*stored*/ DerivedMultiple, /*from*/ DerivedMultiple, /*to*/ Base1>(); 110 tests</*stored*/ DerivedMultiple, /*from*/ DerivedMultiple const, /*to*/ Base1 const>(); 111 tests</*stored*/ DerivedMultiple, /*from*/ DerivedMultiple volatile, /*to*/ Base1 volatile>(); 112 tests</*stored*/ DerivedMultiple, /*from*/ DerivedMultiple const volatile, /*to*/ Base1 const volatile>(); 113 114 tests</*stored*/ DerivedMultiple, /*from*/ DerivedMultiple, /*to*/ Base2>(); 115 tests</*stored*/ DerivedMultiple, /*from*/ DerivedMultiple const, /*to*/ Base2 const>(); 116 tests</*stored*/ DerivedMultiple, /*from*/ DerivedMultiple volatile, /*to*/ Base2 volatile>(); 117 tests</*stored*/ DerivedMultiple, /*from*/ DerivedMultiple const volatile, /*to*/ Base2 const volatile>(); 118 119 tests</*stored*/ Derived, /*from*/ Derived, /*to*/ void>(); 120 tests</*stored*/ Derived, /*from*/ Derived const, /*to*/ void const>(); 121 tests</*stored*/ Derived, /*from*/ Derived volatile, /*to*/ void volatile>(); 122 tests</*stored*/ Derived, /*from*/ Derived const volatile, /*to*/ void const volatile>(); 123 124 // Make sure downcasts are disabled 125 static_assert(!std::is_assignable_v</*to*/ test_bounded_ptr<Derived>, /*from*/ test_bounded_ptr<Base> >); 126 static_assert(!std::is_assignable_v</*to*/ test_bounded_ptr<DerivedMultiple>, /*from*/ test_bounded_ptr<Base1> >); 127 static_assert(!std::is_assignable_v</*to*/ test_bounded_ptr<DerivedMultiple>, /*from*/ test_bounded_ptr<Base2> >); 128 static_assert(!std::is_assignable_v</*to*/ test_bounded_ptr<Base2>, /*from*/ test_bounded_ptr<Base1> >); 129 130 // Make sure const-casting away doesn't work 131 static_assert(!std::is_assignable_v</*to*/ test_bounded_ptr<Derived>, /*from*/ test_bounded_ptr<Derived const> >); 132 133 // Make sure casting to unrelated types doesn't work implicitly 134 static_assert(!std::is_assignable_v</*to*/ test_bounded_ptr<char>, /*from*/ test_bounded_ptr<Derived> >); 135 static_assert(!std::is_assignable_v</*to*/ test_bounded_ptr<Unrelated>, /*from*/ test_bounded_ptr<Derived> >); 136 static_assert(!std::is_assignable_v</*to*/ test_bounded_ptr<Base2>, /*from*/ test_bounded_ptr<Base1> >); 137 138 // Make sure we can't assign from raw pointers 139 static_assert(!std::is_assignable_v</*to*/ test_bounded_ptr<Derived>, /*from*/ Derived*>); 140 } 141