• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 ///////////////////////////////////////////////////////////////////////////////
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>
18 
19 #include <gsl/gsl>
20 
21 #include <memory>
22 #include <string>
23 #include <vector>
24 
25 using namespace gsl;
26 
27 struct MyBase
28 {
29 };
30 struct MyDerived : public MyBase
31 {
32 };
33 struct Unrelated
34 {
35 };
36 
37 // stand-in for a user-defined ref-counted class
38 template <typename T>
39 struct RefCounted
40 {
RefCountedRefCounted41     RefCounted(T* p) : p_(p) {}
operator T*RefCounted42     operator T*() { return p_; }
43     T* p_;
44 };
45 
46 // user defined smart pointer with comparison operators returning non bool value
47 template <typename T>
48 struct CustomPtr
49 {
CustomPtrCustomPtr50     CustomPtr(T* p) : p_(p) {}
operator T*CustomPtr51     operator T*() { return p_; }
operator !=CustomPtr52     bool operator!=(std::nullptr_t) const { return p_ != nullptr; }
53     T* p_ = nullptr;
54 };
55 
56 template <typename T, typename U>
operator ==(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)57 std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs)
58 {
59     return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true"
60                                                                                           : "false";
61 }
62 
63 template <typename T, typename U>
operator !=(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)64 std::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 
70 template <typename T, typename U>
operator <(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)71 std::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 
77 template <typename T, typename U>
operator >(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)78 std::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 
84 template <typename T, typename U>
operator <=(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)85 std::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 
91 template <typename T, typename U>
operator >=(CustomPtr<T> const & lhs,CustomPtr<U> const & rhs)92 std::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 
98 struct 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 
helper(not_null<int * > p)107 bool helper(not_null<int*> p) { return *p == 12; }
108 
109 TEST_CASE("TestNotNullConstructors")
110 {
111 #ifdef CONFIRM_COMPILATION_ERRORS
112     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;
117 
118     // 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});
122 #endif
123     int i = 12;
124     auto rp = RefCounted<int>(&i);
125     not_null<int*> p(rp);
126     CHECK(p.get() == &i);
127 
128     not_null<std::shared_ptr<int>> x(
129         std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable
130 }
131 
132 TEST_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 
155 TEST_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 
165 TEST_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 
194 TEST_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 
224 TEST_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 
255 TEST_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 }
286