blob: bb043bbf0e2d68647767187749a9524cfca8242d [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
Tiagoebe7ebf2017-04-20 07:51:37 -070017#include <UnitTest++/UnitTest++.h>
18
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
Neil MacIntosha9dcbe02015-08-20 18:09:14 -070098SUITE(NotNullTests)
99{
100
Tiagoebe7ebf2017-04-20 07:51:37 -0700101 bool helper(not_null<int*> p) { return *p == 12; }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700102
103 TEST(TestNotNullConstructors)
104 {
105#ifdef CONFIRM_COMPILATION_ERRORS
Tiagoebe7ebf2017-04-20 07:51:37 -0700106 not_null<int*> p = nullptr; // yay...does not compile!
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700107 not_null<std::vector<char>*> p = 0; // yay...does not compile!
Tiagoebe7ebf2017-04-20 07:51:37 -0700108 not_null<int*> p; // yay...does not compile!
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700109 std::unique_ptr<int> up = std::make_unique<int>(120);
110 not_null<int*> p = up;
Kern Handa2b6d9042015-09-25 09:41:40 -0700111
112 // Forbid non-nullptr assignable types
113 not_null<std::vector<int>> f(std::vector<int>{1});
114 not_null<int> z(10);
Tiagoebe7ebf2017-04-20 07:51:37 -0700115 not_null<std::vector<int>> y({1, 2});
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700116#endif
Tiagoebe7ebf2017-04-20 07:51:37 -0700117 int i = 12;
118 auto rp = RefCounted<int>(&i);
119 not_null<int*> p(rp);
120 CHECK(p.get() == &i);
Kern Handa2b6d9042015-09-25 09:41:40 -0700121
Tiagoebe7ebf2017-04-20 07:51:37 -0700122 not_null<std::shared_ptr<int>> x(
123 std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700124 }
125
126 TEST(TestNotNullCasting)
127 {
Kern Handa783eaab2015-09-28 07:35:18 +0000128 MyBase base;
Tiagoebe7ebf2017-04-20 07:51:37 -0700129 MyDerived derived;
130 Unrelated unrelated;
131 not_null<Unrelated*> u = &unrelated;
132 (void) u;
133 not_null<MyDerived*> p = &derived;
Kern Handa783eaab2015-09-28 07:35:18 +0000134 not_null<MyBase*> q = &base;
Tiagoebe7ebf2017-04-20 07:51:37 -0700135 q = p; // allowed with heterogeneous copy ctor
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700136 CHECK(q == p);
137
138#ifdef CONFIRM_COMPILATION_ERRORS
Tiagoebe7ebf2017-04-20 07:51:37 -0700139 q = u; // no viable conversion possible between MyBase* and Unrelated*
140 p = q; // not possible to implicitly convert MyBase* to MyDerived*
Kern Handa783eaab2015-09-28 07:35:18 +0000141
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700142 not_null<Unrelated*> r = p;
143 not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p);
144#endif
145 not_null<Unrelated*> t = reinterpret_cast<Unrelated*>(p.get());
Rian Quinnd6417962016-11-03 19:38:32 -0600146 CHECK(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get()));
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700147 }
148
149 TEST(TestNotNullAssignment)
150 {
151 int i = 12;
Tiagoebe7ebf2017-04-20 07:51:37 -0700152 not_null<int*> p = &i;
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700153 CHECK(helper(p));
154
155 int* q = nullptr;
156 CHECK_THROW(p = q, fail_fast);
157 }
Alexey Malov534bb4c2017-04-13 03:34:39 +0300158
159 TEST(TestNotNullRawPointerComparison)
160 {
161 int ints[2] = {42, 43};
162 int* p1 = &ints[0];
163 const int* p2 = &ints[1];
164
165 using NotNull1 = not_null<decltype(p1)>;
166 using NotNull2 = not_null<decltype(p2)>;
167
168 CHECK((NotNull1(p1) == NotNull1(p1)) == true);
169 CHECK((NotNull1(p1) == NotNull2(p2)) == false);
170
171 CHECK((NotNull1(p1) != NotNull1(p1)) == false);
172 CHECK((NotNull1(p1) != NotNull2(p2)) == true);
173
174 CHECK((NotNull1(p1) < NotNull1(p1)) == false);
175 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
176 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
177
178 CHECK((NotNull1(p1) > NotNull1(p1)) == false);
179 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
180 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
181
182 CHECK((NotNull1(p1) <= NotNull1(p1)) == true);
183 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
184 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
185
186 CHECK((NotNull1(p1) >= NotNull1(p1)) == true);
187 CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2));
188 CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1));
189 }
190
191 TEST(TestNotNullSharedPtrComparison)
192 {
193 auto sp1 = std::make_shared<int>(42);
194 auto sp2 = std::make_shared<const int>(43);
195
196 using NotNullSp1 = not_null<decltype(sp1)>;
197 using NotNullSp2 = not_null<decltype(sp2)>;
198
199 CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true);
200 CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false);
201
202 CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false);
203 CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true);
204
205 CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false);
206 CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2));
207 CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1));
208
209 CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false);
210 CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2));
211 CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1));
212
213 CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true);
214 CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2));
215 CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1));
216
217 CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true);
218 CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2));
219 CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1));
220 }
221
222 TEST(TestNotNullCustomPtrComparison)
223 {
Tiagoebe7ebf2017-04-20 07:51:37 -0700224 int ints[2] = {42, 43};
Alexey Malov534bb4c2017-04-13 03:34:39 +0300225 CustomPtr<int> p1(&ints[0]);
226 CustomPtr<const int> p2(&ints[1]);
227
228 using NotNull1 = not_null<decltype(p1)>;
229 using NotNull2 = not_null<decltype(p2)>;
230
231 CHECK((NotNull1(p1) == NotNull1(p1)) == "true");
232 CHECK((NotNull1(p1) == NotNull2(p2)) == "false");
233
234 CHECK((NotNull1(p1) != NotNull1(p1)) == "false");
235 CHECK((NotNull1(p1) != NotNull2(p2)) == "true");
236
237 CHECK((NotNull1(p1) < NotNull1(p1)) == "false");
238 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2));
239 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1));
240
241 CHECK((NotNull1(p1) > NotNull1(p1)) == "false");
242 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2));
243 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1));
244
245 CHECK((NotNull1(p1) <= NotNull1(p1)) == "true");
246 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2));
247 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1));
248
249 CHECK((NotNull1(p1) >= NotNull1(p1)) == "true");
250 CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2));
251 CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1));
252 }
Neil MacIntosha9dcbe02015-08-20 18:09:14 -0700253}
254
Tiagoebe7ebf2017-04-20 07:51:37 -0700255int main(int, const char* []) { return UnitTest::RunAllTests(); }