blob: 50b15f6458d9a823f7d622d04ae9b5af23dcd078 [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
Tiago0d33bf62017-11-28 07:13:49 -080017#include <catch/catch.hpp> // for AssertionHandler, StringRef, CHECK, TEST_...
Tiagoebe7ebf2017-04-20 07:51:37 -070018
Tiago0d33bf62017-11-28 07:13:49 -080019#include <gsl/pointers> // for not_null, operator<, operator<=, operator>
Tiagoebe7ebf2017-04-20 07:51:37 -070020
Tiago0d33bf62017-11-28 07:13:49 -080021#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
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070031
Neil MacIntoshef626fd2015-09-29 16:41:37 -070032using namespace gsl;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070033
Tiagoebe7ebf2017-04-20 07:51:37 -070034struct MyBase
35{
36};
37struct MyDerived : public MyBase
38{
39};
40struct Unrelated
41{
42};
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070043
44// stand-in for a user-defined ref-counted class
Tiagoebe7ebf2017-04-20 07:51:37 -070045template <typename T>
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070046struct RefCounted
47{
48 RefCounted(T* p) : p_(p) {}
49 operator T*() { return p_; }
50 T* p_;
51};
52
Alexey Malov534bb4c2017-04-13 03:34:39 +030053// user defined smart pointer with comparison operators returning non bool value
54template <typename T>
55struct CustomPtr
56{
Tiagoebe7ebf2017-04-20 07:51:37 -070057 CustomPtr(T* p) : p_(p) {}
58 operator T*() { return p_; }
59 bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
60 T* p_ = nullptr;
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
98template <typename T, typename U>
99std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
100{
Tiagoebe7ebf2017-04-20 07:51:37 -0700101 return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true"
102 : "false";
Alexey Malov534bb4c2017-04-13 03:34:39 +0300103}
104
Alexey Malov247c4252017-05-31 21:18:55 +0300105struct 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
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700114bool helper(not_null<int*> p) { return *p == 12; }
Alexey Malov247c4252017-05-31 21:18:55 +0300115
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700116TEST_CASE("TestNotNullConstructors")
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700117{
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700118#ifdef CONFIRM_COMPILATION_ERRORS
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700119 not_null<int*> p = nullptr; // yay...does not compile!
120 not_null<std::vector<char>*> p = 0; // yay...does not compile!
121 not_null<int*> p; // yay...does not compile!
122 std::unique_ptr<int> up = std::make_unique<int>(120);
123 not_null<int*> p = up;
Kern Handa2b6d9042015-09-25 09:41:40 -0700124
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700125 // Forbid non-nullptr assignable types
126 not_null<std::vector<int>> f(std::vector<int>{1});
127 not_null<int> z(10);
128 not_null<std::vector<int>> y({1, 2});
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700129#endif
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700130 int i = 12;
131 auto rp = RefCounted<int>(&i);
132 not_null<int*> p(rp);
133 CHECK(p.get() == &i);
Kern Handa2b6d9042015-09-25 09:41:40 -0700134
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700135 not_null<std::shared_ptr<int>> x(
136 std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700137}
138
menete2ad93a32017-11-14 17:14:20 +0100139template<typename T>
140void ostream_helper(T v)
141{
142 not_null<T*> p(&v);
143 {
144 std::ostringstream os;
145 std::ostringstream ref;
146 os << p;
147 ref << &v;
148 CHECK(os.str() == ref.str());
149 }
150 {
151 std::ostringstream os;
152 std::ostringstream ref;
153 os << *p;
154 ref << v;
155 CHECK(os.str() == ref.str());
156 }
157}
158
159TEST_CASE("TestNotNullostream")
160{
161 ostream_helper<int>(17);
162 ostream_helper<float>(21.5f);
163 ostream_helper<double>(3.4566e-7f);
164 ostream_helper<char>('c');
165 ostream_helper<uint16_t>(0x0123u);
166 ostream_helper<const char*>("cstring");
167 ostream_helper<std::string>("string");
168}
169
170
Neil MacIntoshb2ee4842017-07-13 13:53:56 -0700171TEST_CASE("TestNotNullCasting")
172{
173 MyBase base;
174 MyDerived derived;
175 Unrelated unrelated;
176 not_null<Unrelated*> u = &unrelated;
177 (void) u;
178 not_null<MyDerived*> p = &derived;
179 not_null<MyBase*> q = &base;
180 q = p; // allowed with heterogeneous copy ctor
181 CHECK(q == p);
182
183#ifdef CONFIRM_COMPILATION_ERRORS
184 q = u; // no viable conversion possible between MyBase* and Unrelated*
185 p = q; // not possible to implicitly convert MyBase* to MyDerived*
186
187 not_null<Unrelated*> r = p;
188 not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
189#endif
190 not_null<Unrelated*> t = reinterpret_cast<Unrelated*>(p.get());
191 CHECK(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
192}
193
194TEST_CASE("TestNotNullAssignment")
195{
196 int i = 12;
197 not_null<int*> p = &i;
198 CHECK(helper(p));
199
200 int* q = nullptr;
201 CHECK_THROWS_AS(p = q, fail_fast);
202}
203
204TEST_CASE("TestNotNullRawPointerComparison")
205{
206 int ints[2] = {42, 43};
207 int* p1 = &ints[0];
208 const int* p2 = &ints[1];
209
210 using NotNull1 = not_null<decltype(p1)>;
211 using NotNull2 = not_null<decltype(p2)>;
212
213 CHECK((NotNull1(p1) == NotNull1(p1)) == true);
214 CHECK((NotNull1(p1) == NotNull2(p2)) == false);
215
216 CHECK((NotNull1(p1) != NotNull1(p1)) == false);
217 CHECK((NotNull1(p1) != NotNull2(p2)) == true);
218
219 CHECK((NotNull1(p1) < NotNull1(p1)) == false);
220 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
221 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
222
223 CHECK((NotNull1(p1) > NotNull1(p1)) == false);
224 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
225 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
226
227 CHECK((NotNull1(p1) <= NotNull1(p1)) == true);
228 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
229 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
230
231}
232
233TEST_CASE("TestNotNullDereferenceOperator")
234{
235 {
236 auto sp1 = std::make_shared<NonCopyableNonMovable>();
237
238 using NotNullSp1 = not_null<decltype(sp1)>;
239 CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1)));
240 CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1));
241 }
242
243 {
244 int ints[1] = { 42 };
245 CustomPtr<int> p1(&ints[0]);
246
247 using NotNull1 = not_null<decltype(p1)>;
248 CHECK(typeid(*NotNull1(p1)) == typeid(*p1));
249 CHECK(*NotNull1(p1) == 42);
250 *NotNull1(p1) = 43;
251 CHECK(ints[0] == 43);
252 }
253
254 {
255 int v = 42;
256 gsl::not_null<int*> p(&v);
257 CHECK(typeid(*p) == typeid(*(&v)));
258 *p = 43;
259 CHECK(v == 43);
260 }
261}
262
263TEST_CASE("TestNotNullSharedPtrComparison")
264{
265 auto sp1 = std::make_shared<int>(42);
266 auto sp2 = std::make_shared<const int>(43);
267
268 using NotNullSp1 = not_null<decltype(sp1)>;
269 using NotNullSp2 = not_null<decltype(sp2)>;
270
271 CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true);
272 CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false);
273
274 CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false);
275 CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true);
276
277 CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false);
278 CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2));
279 CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1));
280
281 CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false);
282 CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2));
283 CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1));
284
285 CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true);
286 CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2));
287 CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1));
288
289 CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true);
290 CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2));
291 CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1));
292}
293
294TEST_CASE("TestNotNullCustomPtrComparison")
295{
296 int ints[2] = {42, 43};
297 CustomPtr<int> p1(&ints[0]);
298 CustomPtr<const int> p2(&ints[1]);
299
300 using NotNull1 = not_null<decltype(p1)>;
301 using NotNull2 = not_null<decltype(p2)>;
302
303 CHECK((NotNull1(p1) == NotNull1(p1)) == "true");
304 CHECK((NotNull1(p1) == NotNull2(p2)) == "false");
305
306 CHECK((NotNull1(p1) != NotNull1(p1)) == "false");
307 CHECK((NotNull1(p1) != NotNull2(p2)) == "true");
308
309 CHECK((NotNull1(p1) < NotNull1(p1)) == "false");
310 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
311 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
312
313 CHECK((NotNull1(p1) > NotNull1(p1)) == "false");
314 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
315 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
316
317 CHECK((NotNull1(p1) <= NotNull1(p1)) == "true");
318 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
319 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
320
321 CHECK((NotNull1(p1) >= NotNull1(p1)) == "true");
322 CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2));
323 CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1));
324}