blob: 1cb9c10f91f6b37a8573b9c62f97c9f74d6e8356 [file] [log] [blame]
Brian Silvermana6f7ce02018-07-07 15:04:00 -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//
15///////////////////////////////////////////////////////////////////////////////
16
17#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_...
18
19#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
20
21#include <algorithm> // for addressof
22#include <memory> // for shared_ptr, make_shared, operator<, opera...
23#include <sstream> // for operator<<, ostringstream, basic_ostream:...
24#include <stdint.h> // for uint16_t
25#include <string> // for basic_string, operator==, string, operator<<
26#include <typeinfo> // for type_info
27
28namespace gsl {
29struct fail_fast;
30} // namespace gsl
31
32using namespace gsl;
33
34struct MyBase
35{
36};
37struct MyDerived : public MyBase
38{
39};
40struct Unrelated
41{
42};
43
44// stand-in for a user-defined ref-counted class
45template <typename T>
46struct RefCounted
47{
48 RefCounted(T* p) : p_(p) {}
49 operator T*() { return p_; }
50 T* p_;
51};
52
53// user defined smart pointer with comparison operators returning non bool value
54template <typename T>
55struct CustomPtr
56{
57 CustomPtr(T* p) : p_(p) {}
58 operator T*() { return p_; }
59 bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
60 T* p_ = nullptr;
61};
62
63template <typename T, typename U>
64std::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
70template <typename T, typename U>
71std::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
77template <typename T, typename U>
78std::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
84template <typename T, typename U>
85std::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
91template <typename T, typename U>
92std::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
98template <typename T, typename U>
99std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
100{
101 return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
102 : "false";
103}
104
105struct NonCopyableNonMovable
106{
107 NonCopyableNonMovable() = default;
108 NonCopyableNonMovable(const NonCopyableNonMovable&) = delete;
109 NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete;
110 NonCopyableNonMovable(NonCopyableNonMovable&&) = delete;
111 NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete;
112};
113
114bool helper(not_null<int*> p) { return *p == 12; }
115bool helper_const(not_null<const int*> p) { return *p == 12; }
116
117TEST_CASE("TestNotNullConstructors")
118{
119#ifdef CONFIRM_COMPILATION_ERRORS
120 not_null<int*> p = nullptr; // yay...does not compile!
121 not_null<std::vector<char>*> p = 0; // yay...does not compile!
122 not_null<int*> p; // yay...does not compile!
123 std::unique_ptr<int> up = std::make_unique<int>(120);
124 not_null<int*> p = up;
125
126 // Forbid non-nullptr assignable types
127 not_null<std::vector<int>> f(std::vector<int>{1});
128 not_null<int> z(10);
129 not_null<std::vector<int>> y({1, 2});
130#endif
131 int i = 12;
132 auto rp = RefCounted<int>(&i);
133 not_null<int*> p(rp);
134 CHECK(p.get() == &i);
135
136 not_null<std::shared_ptr<int>> x(
137 std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
138
139#ifdef GSL_THROW_ON_CONTRACT_VIOLATION
140 int* pi = nullptr;
141 CHECK_THROWS_AS(not_null<decltype(pi)>(pi), fail_fast);
142#endif
143}
144
145template<typename T>
146void ostream_helper(T v)
147{
148 not_null<T*> p(&v);
149 {
150 std::ostringstream os;
151 std::ostringstream ref;
152 os << p;
153 ref << &v;
154 CHECK(os.str() == ref.str());
155 }
156 {
157 std::ostringstream os;
158 std::ostringstream ref;
159 os << *p;
160 ref << v;
161 CHECK(os.str() == ref.str());
162 }
163}
164
165TEST_CASE("TestNotNullostream")
166{
167 ostream_helper<int>(17);
168 ostream_helper<float>(21.5f);
169 ostream_helper<double>(3.4566e-7f);
170 ostream_helper<char>('c');
171 ostream_helper<uint16_t>(0x0123u);
172 ostream_helper<const char*>("cstring");
173 ostream_helper<std::string>("string");
174}
175
176
177TEST_CASE("TestNotNullCasting")
178{
179 MyBase base;
180 MyDerived derived;
181 Unrelated unrelated;
182 not_null<Unrelated*> u{&unrelated};
183 (void) u;
184 not_null<MyDerived*> p{&derived};
185 not_null<MyBase*> q(&base);
186 q = p; // allowed with heterogeneous copy ctor
187 CHECK(q == p);
188
189#ifdef CONFIRM_COMPILATION_ERRORS
190 q = u; // no viable conversion possible between MyBase* and Unrelated*
191 p = q; // not possible to implicitly convert MyBase* to MyDerived*
192
193 not_null<Unrelated*> r = p;
194 not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
195#endif
196 not_null<Unrelated*> t(reinterpret_cast<Unrelated*>(p.get()));
197 CHECK(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
198}
199
200TEST_CASE("TestNotNullAssignment")
201{
202 int i = 12;
203 not_null<int*> p(&i);
204 CHECK(helper(p));
205
206 int* q = nullptr;
207 CHECK_THROWS_AS(p = not_null<int*>(q), fail_fast);
208}
209
210TEST_CASE("TestNotNullRawPointerComparison")
211{
212 int ints[2] = {42, 43};
213 int* p1 = &ints[0];
214 const int* p2 = &ints[1];
215
216 using NotNull1 = not_null<decltype(p1)>;
217 using NotNull2 = not_null<decltype(p2)>;
218
219 CHECK((NotNull1(p1) == NotNull1(p1)) == true);
220 CHECK((NotNull1(p1) == NotNull2(p2)) == false);
221
222 CHECK((NotNull1(p1) != NotNull1(p1)) == false);
223 CHECK((NotNull1(p1) != NotNull2(p2)) == true);
224
225 CHECK((NotNull1(p1) < NotNull1(p1)) == false);
226 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
227 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
228
229 CHECK((NotNull1(p1) > NotNull1(p1)) == false);
230 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
231 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
232
233 CHECK((NotNull1(p1) <= NotNull1(p1)) == true);
234 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
235 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
236
237}
238
239TEST_CASE("TestNotNullDereferenceOperator")
240{
241 {
242 auto sp1 = std::make_shared<NonCopyableNonMovable>();
243
244 using NotNullSp1 = not_null<decltype(sp1)>;
245 CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1)));
246 CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1));
247 }
248
249 {
250 int ints[1] = { 42 };
251 CustomPtr<int> p1(&ints[0]);
252
253 using NotNull1 = not_null<decltype(p1)>;
254 CHECK(typeid(*NotNull1(p1)) == typeid(*p1));
255 CHECK(*NotNull1(p1) == 42);
256 *NotNull1(p1) = 43;
257 CHECK(ints[0] == 43);
258 }
259
260 {
261 int v = 42;
262 gsl::not_null<int*> p(&v);
263 CHECK(typeid(*p) == typeid(*(&v)));
264 *p = 43;
265 CHECK(v == 43);
266 }
267}
268
269TEST_CASE("TestNotNullSharedPtrComparison")
270{
271 auto sp1 = std::make_shared<int>(42);
272 auto sp2 = std::make_shared<const int>(43);
273
274 using NotNullSp1 = not_null<decltype(sp1)>;
275 using NotNullSp2 = not_null<decltype(sp2)>;
276
277 CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true);
278 CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false);
279
280 CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false);
281 CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true);
282
283 CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false);
284 CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2));
285 CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1));
286
287 CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false);
288 CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2));
289 CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1));
290
291 CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true);
292 CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2));
293 CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1));
294
295 CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true);
296 CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2));
297 CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1));
298}
299
300TEST_CASE("TestNotNullCustomPtrComparison")
301{
302 int ints[2] = {42, 43};
303 CustomPtr<int> p1(&ints[0]);
304 CustomPtr<const int> p2(&ints[1]);
305
306 using NotNull1 = not_null<decltype(p1)>;
307 using NotNull2 = not_null<decltype(p2)>;
308
309 CHECK((NotNull1(p1) == NotNull1(p1)) == "true");
310 CHECK((NotNull1(p1) == NotNull2(p2)) == "false");
311
312 CHECK((NotNull1(p1) != NotNull1(p1)) == "false");
313 CHECK((NotNull1(p1) != NotNull2(p2)) == "true");
314
315 CHECK((NotNull1(p1) < NotNull1(p1)) == "false");
316 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
317 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
318
319 CHECK((NotNull1(p1) > NotNull1(p1)) == "false");
320 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
321 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
322
323 CHECK((NotNull1(p1) <= NotNull1(p1)) == "true");
324 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
325 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
326
327 CHECK((NotNull1(p1) >= NotNull1(p1)) == "true");
328 CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2));
329 CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1));
330}
331
332
333#if defined(__cplusplus) && (__cplusplus >= 201703L)
334TEST_CASE("TestNotNullConstructorTypeDeduction")
335{
336 {
337 int i = 42;
338
339 not_null x{&i};
340 helper(not_null{&i});
341 helper_const(not_null{&i});
342
343 CHECK(*x == 42);
344 }
345
346 {
347 int i = 42;
348 int* p = &i;
349
350 not_null x{p};
351 helper(not_null{p});
352 helper_const(not_null{p});
353
354 CHECK(*x == 42);
355 }
356
357 {
358 auto workaround_macro = []() {
359 int* p1 = nullptr;
360 not_null x{p1};
361 };
362 CHECK_THROWS_AS(workaround_macro(), fail_fast);
363 }
364
365 {
366 auto workaround_macro = []() {
367 const int* p1 = nullptr;
368 not_null x{p1};
369 };
370 CHECK_THROWS_AS(workaround_macro(), fail_fast);
371 }
372
373 {
374 int* p = nullptr;
375
376 CHECK_THROWS_AS(helper(not_null{p}), fail_fast);
377 CHECK_THROWS_AS(helper_const(not_null{p}), fail_fast);
378 }
379
380#ifdef CONFIRM_COMPILATION_ERRORS
381 {
382 not_null x{nullptr};
383 helper(not_null{nullptr});
384 helper_const(not_null{nullptr});
385 }
386#endif
387}
388#endif // #if defined(__cplusplus) && (__cplusplus >= 201703L)
389
390static_assert(std::is_nothrow_move_constructible<not_null<void *>>::value, "not_null must be no-throw move constructible");