blob: 62f1e57617642a286baf6a77285477c9bfcaae1c [file] [log] [blame]
Tiagoebe7ebf2017-04-20 07:51:37 -07001///////////////////////////////////////////////////////////////////////////////
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//
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070015///////////////////////////////////////////////////////////////////////////////
16
Neil MacIntoshb2ee4842017-07-13 13:53:56 -070017#include <catch/catch.hpp>
Tiagoebe7ebf2017-04-20 07:51:37 -070018
Galik222c2d82016-08-10 17:24:00 +010019#include <gsl/gsl>
Tiagoebe7ebf2017-04-20 07:51:37 -070020
Alexey Malov534bb4c2017-04-13 03:34:39 +030021#include <memory>
22#include <string>
Tiagoebe7ebf2017-04-20 07:51:37 -070023#include <vector>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070024
Neil MacIntoshef626fd2015-09-29 16:41:37 -070025using namespace gsl;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070026
Tiagoebe7ebf2017-04-20 07:51:37 -070027struct MyBase
28{
29};
30struct MyDerived : public MyBase
31{
32};
33struct Unrelated
34{
35};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070036
37// stand-in for a user-defined ref-counted class
Tiagoebe7ebf2017-04-20 07:51:37 -070038template <typename T>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070039struct RefCounted
40{
41 RefCounted(T* p) : p_(p) {}
42 operator T*() { return p_; }
43 T* p_;
44};
45
Alexey Malov534bb4c2017-04-13 03:34:39 +030046// user defined smart pointer with comparison operators returning non bool value
47template <typename T>
48struct CustomPtr
49{
Tiagoebe7ebf2017-04-20 07:51:37 -070050 CustomPtr(T* p) : p_(p) {}
51 operator T*() { return p_; }
52 bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
53 T* p_ = nullptr;
Alexey Malov534bb4c2017-04-13 03:34:39 +030054};
55
56template <typename T, typename U>
57std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
58{
Tiagoebe7ebf2017-04-20 07:51:37 -070059 return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
60 : "false";
Alexey Malov534bb4c2017-04-13 03:34:39 +030061}
62
63template <typename T, typename U>
64std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
65{
Tiagoebe7ebf2017-04-20 07:51:37 -070066 return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true"
67 : "false";
Alexey Malov534bb4c2017-04-13 03:34:39 +030068}
69
70template <typename T, typename U>
71std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
72{
Tiagoebe7ebf2017-04-20 07:51:37 -070073 return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true"
74 : "false";
Alexey Malov534bb4c2017-04-13 03:34:39 +030075}
76
77template <typename T, typename U>
78std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
79{
Tiagoebe7ebf2017-04-20 07:51:37 -070080 return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true"
81 : "false";
Alexey Malov534bb4c2017-04-13 03:34:39 +030082}
83
84template <typename T, typename U>
85std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
86{
Tiagoebe7ebf2017-04-20 07:51:37 -070087 return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true"
88 : "false";
Alexey Malov534bb4c2017-04-13 03:34:39 +030089}
90
91template <typename T, typename U>
92std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
93{
Tiagoebe7ebf2017-04-20 07:51:37 -070094 return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
95 : "false";
Alexey Malov534bb4c2017-04-13 03:34:39 +030096}
97
Alexey Malov247c4252017-05-31 21:18:55 +030098struct 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
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700107bool helper(not_null<int*> p) { return *p == 12; }
Alexey Malov247c4252017-05-31 21:18:55 +0300108
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700109TEST_CASE("TestNotNullConstructors")
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700110{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700111#ifdef CONFIRM_COMPILATION_ERRORS
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700112 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;
Kern Handa2b6d9042015-09-25 09:41:40 -0700117
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700118 // 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});
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700122#endif
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700123 int i = 12;
124 auto rp = RefCounted<int>(&i);
125 not_null<int*> p(rp);
126 CHECK(p.get() == &i);
Kern Handa2b6d9042015-09-25 09:41:40 -0700127
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700128 not_null<std::shared_ptr<int>> x(
129 std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700130}
131
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700132TEST_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
155TEST_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
165TEST_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
194TEST_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
224TEST_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
255TEST_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}