1 | ////////////////////////////////////////////////////////////////////////////// |
2 | // |
3 | // (C) Copyright Howard Hinnant 2009 |
4 | // (C) Copyright Ion Gaztanaga 2014-2014. |
5 | // |
6 | // Distributed under the Boost Software License, Version 1.0. |
7 | // (See accompanying file LICENSE_1_0.txt or copy at |
8 | // http://www.boost.org/LICENSE_1_0.txt) |
9 | // |
10 | // See http://www.boost.org/libs/move for documentation. |
11 | // |
12 | ////////////////////////////////////////////////////////////////////////////// |
13 | #include <boost/move/utility_core.hpp> |
14 | #include <boost/move/unique_ptr.hpp> |
15 | #include <boost/core/lightweight_test.hpp> |
16 | |
17 | ////////////////////////////////////////////// |
18 | // |
19 | // The initial implementation of these tests |
20 | // was written by Howard Hinnant. |
21 | // |
22 | // These test were later refactored grouping |
23 | // and porting them to Boost.Move. |
24 | // |
25 | // Many thanks to Howard for releasing his C++03 |
26 | // unique_ptr implementation with such detailed |
27 | // test cases. |
28 | // |
29 | ////////////////////////////////////////////// |
30 | |
31 | #include "unique_ptr_test_utils_beg.hpp" |
32 | |
33 | namespace bml = ::boost::movelib; |
34 | namespace bmupmu = ::boost::move_upmu; |
35 | |
36 | //////////////////////////////// |
37 | // unique_ptr_ctor_move_defdel |
38 | //////////////////////////////// |
39 | |
40 | namespace unique_ptr_ctor_move_defdel{ |
41 | |
42 | // test converting move ctor. Should only require a MoveConstructible deleter, or if |
43 | // deleter is a reference, not even that. |
44 | |
45 | void test() |
46 | { |
47 | //Single unique_ptr |
48 | reset_counters(); |
49 | { |
50 | bml::unique_ptr<A> s(new A); |
51 | A* p = s.get(); |
52 | bml::unique_ptr<A> s2(boost::move(t&: s)); |
53 | BOOST_TEST(s2.get() == p); |
54 | BOOST_TEST(s.get() == 0); |
55 | BOOST_TEST(A::count == 1); |
56 | } |
57 | BOOST_TEST(A::count == 0); |
58 | //Unbounded array unique_ptr |
59 | reset_counters(); |
60 | { |
61 | bml::unique_ptr<A[]> s(new A[2]); |
62 | A* p = s.get(); |
63 | bml::unique_ptr<A[]> s2(boost::move(t&: s)); |
64 | BOOST_TEST(s2.get() == p); |
65 | BOOST_TEST(s.get() == 0); |
66 | BOOST_TEST(A::count == 2); |
67 | } |
68 | BOOST_TEST(A::count == 0); |
69 | //Bounded array unique_ptr |
70 | reset_counters(); |
71 | { |
72 | bml::unique_ptr<A[2]> s(new A[2]); |
73 | A* p = s.get(); |
74 | bml::unique_ptr<A[2]> s2(boost::move(t&: s)); |
75 | BOOST_TEST(s2.get() == p); |
76 | BOOST_TEST(s.get() == 0); |
77 | BOOST_TEST(A::count == 2); |
78 | } |
79 | BOOST_TEST(A::count == 0); |
80 | } |
81 | |
82 | } //namespace unique_ptr_ctor_move_defdel{ |
83 | |
84 | //////////////////////////////// |
85 | // unique_ptr_ctor_move_movedel |
86 | //////////////////////////////// |
87 | |
88 | namespace unique_ptr_ctor_move_movedel{ |
89 | |
90 | // test converting move ctor. Should only require a MoveConstructible deleter, or if |
91 | // deleter is a reference, not even that. |
92 | |
93 | void test() |
94 | { |
95 | //Single unique_ptr |
96 | reset_counters(); |
97 | { |
98 | bml::unique_ptr<A, move_constr_deleter<A> > s(new A); |
99 | A* p = s.get(); |
100 | bml::unique_ptr<A, move_constr_deleter<A> > s2 = boost::move(t&: s); |
101 | BOOST_TEST(s2.get() == p); |
102 | BOOST_TEST(s.get() == 0); |
103 | BOOST_TEST(A::count == 1); |
104 | BOOST_TEST(s2.get_deleter().state() == 5); |
105 | BOOST_TEST(s.get_deleter().state() == 0); |
106 | } |
107 | BOOST_TEST(A::count == 0); |
108 | //Unbounded array unique_ptr |
109 | reset_counters(); |
110 | { |
111 | bml::unique_ptr<A[], move_constr_deleter<A[]> > s(new A[2]); |
112 | A* p = s.get(); |
113 | bml::unique_ptr<A[], move_constr_deleter<A[]> > s2 = boost::move(t&: s); |
114 | BOOST_TEST(s2.get() == p); |
115 | BOOST_TEST(s.get() == 0); |
116 | BOOST_TEST(A::count == 2); |
117 | BOOST_TEST(s2.get_deleter().state() == 5); |
118 | BOOST_TEST(s.get_deleter().state() == 0); |
119 | } |
120 | BOOST_TEST(A::count == 0); |
121 | //Bounded array unique_ptr |
122 | reset_counters(); |
123 | { |
124 | bml::unique_ptr<A[2]> s(new A[2]); |
125 | A* p = s.get(); |
126 | bml::unique_ptr<A[2]> s2 = boost::move(t&: s); |
127 | BOOST_TEST(s2.get() == p); |
128 | BOOST_TEST(s.get() == 0); |
129 | BOOST_TEST(A::count == 2); |
130 | } |
131 | BOOST_TEST(A::count == 0); |
132 | } |
133 | |
134 | } //namespace unique_ptr_ctor_move_movedel{ |
135 | |
136 | //////////////////////////////// |
137 | // unique_ptr_ctor_move_dfctrdelref |
138 | //////////////////////////////// |
139 | |
140 | namespace unique_ptr_ctor_move_dfctrdelref{ |
141 | |
142 | // test converting move ctor. Should only require a MoveConstructible deleter, or if |
143 | // deleter is a reference, not even that. |
144 | |
145 | void test() |
146 | { |
147 | //Single unique_ptr |
148 | reset_counters(); |
149 | { |
150 | def_constr_deleter<A> d; |
151 | bml::unique_ptr<A, def_constr_deleter<A>&> s(new A, d); |
152 | A* p = s.get(); |
153 | bml::unique_ptr<A, def_constr_deleter<A>&> s2 = boost::move(t&: s); |
154 | BOOST_TEST(s2.get() == p); |
155 | BOOST_TEST(s.get() == 0); |
156 | BOOST_TEST(A::count == 1); |
157 | d.set_state(6); |
158 | BOOST_TEST(s2.get_deleter().state() == d.state()); |
159 | BOOST_TEST(s.get_deleter().state() == d.state()); |
160 | } |
161 | BOOST_TEST(A::count == 0); |
162 | //Unbounded array unique_ptr |
163 | reset_counters(); |
164 | { |
165 | def_constr_deleter<A[]> d; |
166 | bml::unique_ptr<A[], def_constr_deleter<A[]>&> s(new A[2], d); |
167 | A* p = s.get(); |
168 | bml::unique_ptr<A[], def_constr_deleter<A[]>&> s2 = boost::move(t&: s); |
169 | BOOST_TEST(s2.get() == p); |
170 | BOOST_TEST(s.get() == 0); |
171 | BOOST_TEST(A::count == 2); |
172 | d.set_state(6); |
173 | BOOST_TEST(s2.get_deleter().state() == d.state()); |
174 | BOOST_TEST(s.get_deleter().state() == d.state()); |
175 | } |
176 | BOOST_TEST(A::count == 0); |
177 | //Bounded array unique_ptr |
178 | reset_counters(); |
179 | { |
180 | def_constr_deleter<A[2]> d; |
181 | bml::unique_ptr<A[2], def_constr_deleter<A[2]>&> s(new A[2], d); |
182 | A* p = s.get(); |
183 | bml::unique_ptr<A[2], def_constr_deleter<A[2]>&> s2(boost::move(t&: s)); |
184 | BOOST_TEST(s2.get() == p); |
185 | BOOST_TEST(s.get() == 0); |
186 | BOOST_TEST(A::count == 2); |
187 | d.set_state(6); |
188 | BOOST_TEST(s2.get_deleter().state() == d.state()); |
189 | BOOST_TEST(s.get_deleter().state() == d.state()); |
190 | } |
191 | BOOST_TEST(A::count == 0); |
192 | } |
193 | |
194 | } //namespace unique_ptr_ctor_move_dfctrdelref{ |
195 | |
196 | //////////////////////////////// |
197 | // unique_ptr_ctor_move_convert_defdel |
198 | //////////////////////////////// |
199 | |
200 | namespace unique_ptr_ctor_move_convert_defdel{ |
201 | |
202 | // test converting move ctor. Should only require a MoveConstructible deleter, or if |
203 | // deleter is a reference, not even that. |
204 | |
205 | void test() |
206 | { |
207 | //Single unique_ptr |
208 | reset_counters(); |
209 | { |
210 | bml::unique_ptr<B> s(new B); |
211 | A* p = s.get(); |
212 | bml::unique_ptr<A> s2(boost::move(t&: s)); |
213 | BOOST_TEST(s2.get() == p); |
214 | BOOST_TEST(s.get() == 0); |
215 | BOOST_TEST(A::count == 1); |
216 | BOOST_TEST(B::count == 1); |
217 | } |
218 | BOOST_TEST(A::count == 0); |
219 | BOOST_TEST(B::count == 0); |
220 | //Unbounded array unique_ptr |
221 | reset_counters(); |
222 | { |
223 | bml::unique_ptr<A[]> s(new A[2]); |
224 | A* p = s.get(); |
225 | bml::unique_ptr<const volatile A[]> s2(boost::move(t&: s)); |
226 | BOOST_TEST(s2.get() == p); |
227 | BOOST_TEST(s.get() == 0); |
228 | BOOST_TEST(A::count == 2); |
229 | } |
230 | BOOST_TEST(A::count == 0); |
231 | |
232 | //Bounded array unique_ptr |
233 | reset_counters(); |
234 | { |
235 | bml::unique_ptr<A[2]> s(new A[2]); |
236 | A* p = s.get(); |
237 | bml::unique_ptr<const volatile A[2]> s2(boost::move(t&: s)); |
238 | BOOST_TEST(s2.get() == p); |
239 | BOOST_TEST(s.get() == 0); |
240 | BOOST_TEST(A::count == 2); |
241 | } |
242 | BOOST_TEST(A::count == 0); |
243 | { |
244 | bml::unique_ptr<A[2]> s(new A[2]); |
245 | A* p = s.get(); |
246 | bml::unique_ptr<const volatile A[]> s2(boost::move(t&: s)); |
247 | BOOST_TEST(s2.get() == p); |
248 | BOOST_TEST(s.get() == 0); |
249 | BOOST_TEST(A::count == 2); |
250 | } |
251 | BOOST_TEST(A::count == 0); |
252 | } |
253 | |
254 | } //namespace unique_ptr_ctor_move_convert_defdel{ |
255 | |
256 | //////////////////////////////// |
257 | // unique_ptr_ctor_move_convert_movedel |
258 | //////////////////////////////// |
259 | |
260 | namespace unique_ptr_ctor_move_convert_movedel{ |
261 | |
262 | // test converting move ctor. Should only require a MoveConstructible deleter, or if |
263 | // deleter is a reference, not even that. |
264 | |
265 | void test() |
266 | { |
267 | //Single unique_ptr |
268 | reset_counters(); |
269 | BOOST_MOVE_STATIC_ASSERT((bmupmu::is_convertible<B, A>::value)); |
270 | { |
271 | bml::unique_ptr<B, move_constr_deleter<B> > s(new B); |
272 | A* p = s.get(); |
273 | bml::unique_ptr<A, move_constr_deleter<A> > s2(boost::move(t&: s)); |
274 | BOOST_TEST(s2.get() == p); |
275 | BOOST_TEST(s.get() == 0); |
276 | BOOST_TEST(A::count == 1); |
277 | BOOST_TEST(B::count == 1); |
278 | BOOST_TEST(s2.get_deleter().state() == 5); |
279 | BOOST_TEST(s.get_deleter().state() == 0); |
280 | } |
281 | BOOST_TEST(A::count == 0); |
282 | BOOST_TEST(B::count == 0); |
283 | //Unbounded array unique_ptr |
284 | reset_counters(); |
285 | { |
286 | bml::unique_ptr<const A[], move_constr_deleter<const A[]> > s(new const A[2]); |
287 | const A* p = s.get(); |
288 | bml::unique_ptr<const volatile A[], move_constr_deleter<const volatile A[]> > s2(boost::move(t&: s)); |
289 | BOOST_TEST(s2.get() == p); |
290 | BOOST_TEST(s.get() == 0); |
291 | BOOST_TEST(A::count == 2); |
292 | BOOST_TEST(s2.get_deleter().state() == 5); |
293 | BOOST_TEST(s.get_deleter().state() == 0); |
294 | } |
295 | BOOST_TEST(A::count == 0); |
296 | BOOST_TEST(B::count == 0); |
297 | //Bounded array unique_ptr |
298 | reset_counters(); |
299 | { |
300 | bml::unique_ptr<const A[2], move_constr_deleter<const A[2]> > s(new const A[2]); |
301 | const A* p = s.get(); |
302 | bml::unique_ptr<const volatile A[2], move_constr_deleter<const volatile A[2]> > s2(boost::move(t&: s)); |
303 | BOOST_TEST(s2.get() == p); |
304 | BOOST_TEST(s.get() == 0); |
305 | BOOST_TEST(A::count == 2); |
306 | BOOST_TEST(s2.get_deleter().state() == 5); |
307 | BOOST_TEST(s.get_deleter().state() == 0); |
308 | } |
309 | BOOST_TEST(A::count == 0); |
310 | BOOST_TEST(B::count == 0); |
311 | { |
312 | bml::unique_ptr<const A[2], move_constr_deleter<const A[2]> > s(new const A[2]); |
313 | const A* p = s.get(); |
314 | bml::unique_ptr<const volatile A[], move_constr_deleter<const volatile A[]> > s2(boost::move(t&: s)); |
315 | BOOST_TEST(s2.get() == p); |
316 | BOOST_TEST(s.get() == 0); |
317 | BOOST_TEST(A::count == 2); |
318 | BOOST_TEST(s2.get_deleter().state() == 5); |
319 | BOOST_TEST(s.get_deleter().state() == 0); |
320 | } |
321 | BOOST_TEST(A::count == 0); |
322 | BOOST_TEST(B::count == 0); |
323 | } |
324 | |
325 | } //namespace unique_ptr_ctor_move_convert_movedel{ |
326 | |
327 | //////////////////////////////// |
328 | // unique_ptr_ctor_move_convert_dfctrdelref |
329 | //////////////////////////////// |
330 | |
331 | namespace unique_ptr_ctor_move_convert_dfctrdelref{ |
332 | |
333 | // test converting move ctor. Should only require a MoveConstructible deleter, or if |
334 | // deleter is a reference, not even that. |
335 | |
336 | void test() |
337 | { |
338 | //Single unique_ptr |
339 | reset_counters(); |
340 | { |
341 | def_constr_deleter<A> d; |
342 | bml::unique_ptr<B, def_constr_deleter<A>&> s(new B, d); |
343 | A* p = s.get(); |
344 | bml::unique_ptr<A, def_constr_deleter<A>&> s2(boost::move(t&: s)); |
345 | BOOST_TEST(s2.get() == p); |
346 | BOOST_TEST(s.get() == 0); |
347 | BOOST_TEST(A::count == 1); |
348 | BOOST_TEST(B::count == 1); |
349 | d.set_state(6); |
350 | BOOST_TEST(s2.get_deleter().state() == d.state()); |
351 | BOOST_TEST(s.get_deleter().state() == d.state()); |
352 | } |
353 | BOOST_TEST(A::count == 0); |
354 | BOOST_TEST(B::count == 0); |
355 | //Unbounded array unique_ptr |
356 | reset_counters(); |
357 | { |
358 | def_constr_deleter<volatile A[]> d; |
359 | bml::unique_ptr<A[], def_constr_deleter<volatile A[]>&> s(new A[2], d); |
360 | A* p = s.get(); |
361 | bml::unique_ptr<volatile A[], def_constr_deleter<volatile A[]>&> s2(boost::move(t&: s)); |
362 | BOOST_TEST(s2.get() == p); |
363 | BOOST_TEST(s.get() == 0); |
364 | BOOST_TEST(A::count == 2); |
365 | d.set_state(6); |
366 | BOOST_TEST(s2.get_deleter().state() == d.state()); |
367 | BOOST_TEST(s.get_deleter().state() == d.state()); |
368 | } |
369 | BOOST_TEST(A::count == 0); |
370 | //Bounded array unique_ptr |
371 | reset_counters(); |
372 | { |
373 | def_constr_deleter<volatile A[2]> d; |
374 | bml::unique_ptr<A[2], def_constr_deleter<volatile A[2]>&> s(new A[2], d); |
375 | A* p = s.get(); |
376 | bml::unique_ptr<volatile A[2], def_constr_deleter<volatile A[2]>&> s2(boost::move(t&: s)); |
377 | BOOST_TEST(s2.get() == p); |
378 | BOOST_TEST(s.get() == 0); |
379 | BOOST_TEST(A::count == 2); |
380 | d.set_state(6); |
381 | BOOST_TEST(s2.get_deleter().state() == d.state()); |
382 | BOOST_TEST(s.get_deleter().state() == d.state()); |
383 | } |
384 | BOOST_TEST(A::count == 0); |
385 | { |
386 | def_constr_deleter<volatile A[]> d; |
387 | bml::unique_ptr<A[2], def_constr_deleter<volatile A[]>&> s(new A[2], d); |
388 | A* p = s.get(); |
389 | bml::unique_ptr<volatile A[], def_constr_deleter<volatile A[]>&> s2(boost::move(t&: s)); |
390 | BOOST_TEST(s2.get() == p); |
391 | BOOST_TEST(s.get() == 0); |
392 | BOOST_TEST(A::count == 2); |
393 | d.set_state(6); |
394 | BOOST_TEST(s2.get_deleter().state() == d.state()); |
395 | BOOST_TEST(s.get_deleter().state() == d.state()); |
396 | } |
397 | BOOST_TEST(A::count == 0); |
398 | } |
399 | |
400 | } //namespace unique_ptr_ctor_move_convert_dfctrdelref{ |
401 | |
402 | //////////////////////////////// |
403 | // unique_ptr_ctor_move_sourcesink |
404 | //////////////////////////////// |
405 | |
406 | namespace unique_ptr_ctor_move_sourcesink{ |
407 | |
408 | // test move ctor. Should only require a MoveConstructible deleter, or if |
409 | // deleter is a reference, not even that. |
410 | |
411 | bml::unique_ptr<A> source1() |
412 | { return bml::unique_ptr<A>(new A); } |
413 | |
414 | bml::unique_ptr<A[]> source1_unbounded_array() |
415 | { return bml::unique_ptr<A[]> (new A[2]); } |
416 | |
417 | bml::unique_ptr<A[2]> source1_bounded_array() |
418 | { return bml::unique_ptr<A[2]> (new A[2]); } |
419 | |
420 | void sink1(bml::unique_ptr<A>) |
421 | {} |
422 | |
423 | void sink1_unbounded_array(bml::unique_ptr<A[]>) |
424 | {} |
425 | |
426 | void sink1_bounded_array(bml::unique_ptr<A[2]>) |
427 | {} |
428 | |
429 | bml::unique_ptr<A, move_constr_deleter<A> > source2() |
430 | { return bml::unique_ptr<A, move_constr_deleter<A> > (new A); } |
431 | |
432 | bml::unique_ptr<A[], move_constr_deleter<A[]> > source2_unbounded_array() |
433 | { return bml::unique_ptr<A[], move_constr_deleter<A[]> >(new A[2]); } |
434 | |
435 | bml::unique_ptr<A[2], move_constr_deleter<A[2]> > source2_bounded_array() |
436 | { return bml::unique_ptr<A[2], move_constr_deleter<A[2]> >(new A[2]); } |
437 | |
438 | void sink2(bml::unique_ptr<A, move_constr_deleter<A> >) |
439 | {} |
440 | |
441 | void sink2_unbounded_array(bml::unique_ptr<A[], move_constr_deleter<A[]> >) |
442 | {} |
443 | |
444 | void sink2_bounded_array(bml::unique_ptr<A[2], move_constr_deleter<A[2]> >) |
445 | {} |
446 | |
447 | bml::unique_ptr<A, def_constr_deleter<A>&> source3() |
448 | { |
449 | static def_constr_deleter<A> d; |
450 | return bml::unique_ptr<A, def_constr_deleter<A>&>(new A, d); |
451 | } |
452 | |
453 | bml::unique_ptr<A[], def_constr_deleter<A[]>&> source3_unbounded_array() |
454 | { |
455 | static def_constr_deleter<A[]> d; |
456 | return bml::unique_ptr<A[], def_constr_deleter<A[]>&>(new A[2], d); |
457 | } |
458 | |
459 | bml::unique_ptr<A[2], def_constr_deleter<A[2]>&> source3_bounded_array() |
460 | { |
461 | static def_constr_deleter<A[2]> d; |
462 | return bml::unique_ptr<A[2], def_constr_deleter<A[2]>&>(new A[2], d); |
463 | } |
464 | |
465 | void sink3(bml::unique_ptr<A, def_constr_deleter<A>&> ) |
466 | {} |
467 | |
468 | void sink3_unbounded_array(bml::unique_ptr<A[], def_constr_deleter<A[]>&> ) |
469 | {} |
470 | |
471 | void sink3_bounded_array(bml::unique_ptr<A[2], def_constr_deleter<A[2]>&> ) |
472 | {} |
473 | |
474 | void test() |
475 | { |
476 | //Single unique_ptr |
477 | reset_counters(); |
478 | sink1(source1()); |
479 | sink2(source2()); |
480 | sink3(source3()); |
481 | BOOST_TEST(A::count == 0); |
482 | //Unbounded array unique_ptr |
483 | reset_counters(); |
484 | sink1_unbounded_array(source1_unbounded_array()); |
485 | sink2_unbounded_array(source2_unbounded_array()); |
486 | sink3_unbounded_array(source3_unbounded_array()); |
487 | BOOST_TEST(A::count == 0); |
488 | //Bbounded array unique_ptr |
489 | reset_counters(); |
490 | sink1_bounded_array(source1_bounded_array()); |
491 | sink2_bounded_array(source2_bounded_array()); |
492 | sink3_bounded_array(source3_bounded_array()); |
493 | BOOST_TEST(A::count == 0); |
494 | } |
495 | |
496 | } //namespace unique_ptr_ctor_move_sourcesink{ |
497 | |
498 | //////////////////////////////// |
499 | // main |
500 | //////////////////////////////// |
501 | int main() |
502 | { |
503 | //Move Constructor |
504 | unique_ptr_ctor_move_defdel::test(); |
505 | unique_ptr_ctor_move_movedel::test(); |
506 | unique_ptr_ctor_move_dfctrdelref::test(); |
507 | unique_ptr_ctor_move_convert_defdel::test(); |
508 | unique_ptr_ctor_move_convert_movedel::test(); |
509 | unique_ptr_ctor_move_convert_dfctrdelref::test(); |
510 | unique_ptr_ctor_move_sourcesink::test(); |
511 | |
512 | //Test results |
513 | return boost::report_errors(); |
514 | } |
515 | |
516 | #include "unique_ptr_test_utils_end.hpp" |
517 | |