1 /* Copyright 2017-2021 PaGMO development team
2 
3 This file is part of the PaGMO library.
4 
5 The PaGMO library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8   * the GNU Lesser General Public License as published by the Free
9     Software Foundation; either version 3 of the License, or (at your
10     option) any later version.
11 
12 or
13 
14   * the GNU General Public License as published by the Free Software
15     Foundation; either version 3 of the License, or (at your option) any
16     later version.
17 
18 or both in parallel, as here.
19 
20 The PaGMO library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the PaGMO library.  If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #if defined(_MSC_VER)
30 
31 // Disable warnings from MSVC.
32 #pragma warning(disable : 4822)
33 
34 #endif
35 
36 #define BOOST_TEST_MODULE r_policy_test
37 #define BOOST_TEST_DYN_LINK
38 #include <boost/test/unit_test.hpp>
39 
40 #include <initializer_list>
41 #include <iostream>
42 #include <limits>
43 #include <memory>
44 #include <sstream>
45 #include <stdexcept>
46 #include <string>
47 #include <type_traits>
48 #include <typeindex>
49 #include <typeinfo>
50 #include <utility>
51 
52 #include <boost/algorithm/string/predicate.hpp>
53 #include <boost/lexical_cast.hpp>
54 
55 #include <pagmo/detail/type_name.hpp>
56 #include <pagmo/r_policies/fair_replace.hpp>
57 #include <pagmo/r_policy.hpp>
58 #include <pagmo/s11n.hpp>
59 #include <pagmo/types.hpp>
60 
61 using namespace pagmo;
62 
BOOST_AUTO_TEST_CASE(type_traits_tests)63 BOOST_AUTO_TEST_CASE(type_traits_tests)
64 {
65     BOOST_CHECK(!is_udrp<void>::value);
66     BOOST_CHECK(!is_udrp<int>::value);
67     BOOST_CHECK(!is_udrp<double>::value);
68 
69     struct udrp00 {
70         individuals_group_t replace(const individuals_group_t &, const vector_double::size_type &,
71                                     const vector_double::size_type &, const vector_double::size_type &,
72                                     const vector_double::size_type &, const vector_double::size_type &,
73                                     const vector_double &, const individuals_group_t &) const;
74     };
75 
76     BOOST_CHECK(is_udrp<udrp00>::value);
77     BOOST_CHECK(!is_udrp<const udrp00>::value);
78     BOOST_CHECK(!is_udrp<const udrp00 &>::value);
79     BOOST_CHECK(!is_udrp<udrp00 &>::value);
80 
81     struct no_udrp00 {
82         void replace(const individuals_group_t &, const vector_double::size_type &, const vector_double::size_type &,
83                      const vector_double::size_type &, const vector_double::size_type &,
84                      const vector_double::size_type &, const vector_double &, const individuals_group_t &) const;
85     };
86 
87     BOOST_CHECK(!is_udrp<no_udrp00>::value);
88 
89     struct no_udrp01 {
90         individuals_group_t replace(const individuals_group_t &, const vector_double::size_type &,
91                                     const vector_double::size_type &, const vector_double::size_type &,
92                                     const vector_double::size_type &, const vector_double::size_type &,
93                                     const vector_double &, const individuals_group_t &);
94     };
95 
96     BOOST_CHECK(!is_udrp<no_udrp01>::value);
97 
98     struct no_udrp02 {
99         no_udrp02() = delete;
100         individuals_group_t replace(const individuals_group_t &, const vector_double::size_type &,
101                                     const vector_double::size_type &, const vector_double::size_type &,
102                                     const vector_double::size_type &, const vector_double::size_type &,
103                                     const vector_double &, const individuals_group_t &) const;
104     };
105 
106     BOOST_CHECK(!is_udrp<no_udrp02>::value);
107 }
108 
109 struct udrp1 {
replaceudrp1110     individuals_group_t replace(const individuals_group_t &inds, const vector_double::size_type &,
111                                 const vector_double::size_type &, const vector_double::size_type &,
112                                 const vector_double::size_type &, const vector_double::size_type &,
113                                 const vector_double &, const individuals_group_t &) const
114     {
115         return inds;
116     }
117     std::string foo = "hello world";
118 };
119 
120 struct udrp2 {
121     udrp2() = default;
udrp2udrp2122     udrp2(const udrp2 &other) : foo{new std::string{*other.foo}} {}
123     udrp2(udrp2 &&) = default;
replaceudrp2124     individuals_group_t replace(const individuals_group_t &inds, const vector_double::size_type &,
125                                 const vector_double::size_type &, const vector_double::size_type &,
126                                 const vector_double::size_type &, const vector_double::size_type &,
127                                 const vector_double &, const individuals_group_t &) const
128     {
129         return inds;
130     }
get_nameudrp2131     std::string get_name() const
132     {
133         return "frobniz";
134     }
135     std::unique_ptr<std::string> foo = std::unique_ptr<std::string>{new std::string{"hello world"}};
136 };
137 
BOOST_AUTO_TEST_CASE(basic_tests)138 BOOST_AUTO_TEST_CASE(basic_tests)
139 {
140     r_policy r;
141 
142     BOOST_CHECK(r.is<fair_replace>());
143     BOOST_CHECK(!r.is<udrp1>());
144 
145     BOOST_CHECK(r.extract<fair_replace>() != nullptr);
146     BOOST_CHECK(r.extract<udrp1>() == nullptr);
147 
148     BOOST_CHECK(static_cast<const r_policy &>(r).extract<fair_replace>() != nullptr);
149     BOOST_CHECK(static_cast<const r_policy &>(r).extract<udrp1>() == nullptr);
150 
151     BOOST_CHECK(r.get_name() == "Fair replace");
152     BOOST_CHECK(!r.get_extra_info().empty());
153 
154     BOOST_CHECK(r_policy(udrp1{}).get_extra_info().empty());
155     BOOST_CHECK(r_policy(udrp1{}).get_name() == detail::type_name<udrp1>());
156 
157     // Constructors, assignments.
158     // Generic constructor with copy.
159     udrp1 r1;
160     r_policy r_pol1{r1};
161     BOOST_CHECK(r1.foo == "hello world");
162     BOOST_CHECK(r_pol1.extract<udrp1>()->foo == "hello world");
163     // Generic constructor with move.
164     udrp2 r2;
165     r_policy r_pol2{std::move(r2)};
166     BOOST_CHECK(r2.foo.get() == nullptr);
167     BOOST_CHECK(r_pol2.extract<udrp2>()->foo.get() != nullptr);
168     BOOST_CHECK(*r_pol2.extract<udrp2>()->foo == "hello world");
169     // Copy constructor.
170     udrp2 r3;
171     r_policy r_pol3{r3}, r_pol4{r_pol3};
172     BOOST_CHECK(*r_pol4.extract<udrp2>()->foo == "hello world");
173     BOOST_CHECK(r_pol4.extract<udrp2>()->foo.get() != r_pol3.extract<udrp2>()->foo.get());
174     BOOST_CHECK(r_pol4.get_name() == "frobniz");
175     // Move constructor.
176     r_policy r_pol5{std::move(r_pol4)};
177     BOOST_CHECK(*r_pol5.extract<udrp2>()->foo == "hello world");
178     BOOST_CHECK(r_pol5.get_name() == "frobniz");
179     // Revive r_pol4 via copy assignment.
180     r_pol4 = r_pol5;
181     BOOST_CHECK(*r_pol4.extract<udrp2>()->foo == "hello world");
182     BOOST_CHECK(r_pol4.get_name() == "frobniz");
183     // Revive r_pol4 via move assignment.
184     r_policy r_pol6{std::move(r_pol4)};
185     r_pol4 = std::move(r_pol5);
186     BOOST_CHECK(*r_pol4.extract<udrp2>()->foo == "hello world");
187     BOOST_CHECK(r_pol4.get_name() == "frobniz");
188     // Self move-assignment.
189     r_pol4 = std::move(*&r_pol4);
190     BOOST_CHECK(*r_pol4.extract<udrp2>()->foo == "hello world");
191     BOOST_CHECK(r_pol4.get_name() == "frobniz");
192 
193     // Minimal iostream test.
194     {
195         std::ostringstream oss;
196         oss << r;
197         BOOST_CHECK(!oss.str().empty());
198     }
199 
200     // Minimal serialization test.
201     {
202         std::string before;
203         std::stringstream ss;
204         {
205             before = boost::lexical_cast<std::string>(r);
206             boost::archive::binary_oarchive oarchive(ss);
207             oarchive << r;
208         }
209         r = r_policy{udrp1{}};
210         BOOST_CHECK(r.is<udrp1>());
211         BOOST_CHECK(before != boost::lexical_cast<std::string>(r));
212         {
213             boost::archive::binary_iarchive iarchive(ss);
214             iarchive >> r;
215         }
216         BOOST_CHECK(before == boost::lexical_cast<std::string>(r));
217         BOOST_CHECK(r.is<fair_replace>());
218     }
219 
220     std::cout << r_policy{} << '\n';
221 }
222 
BOOST_AUTO_TEST_CASE(optional_tests)223 BOOST_AUTO_TEST_CASE(optional_tests)
224 {
225     // get_name().
226     struct udrp_00 {
227         individuals_group_t replace(const individuals_group_t &inds, const vector_double::size_type &,
228                                     const vector_double::size_type &, const vector_double::size_type &,
229                                     const vector_double::size_type &, const vector_double::size_type &,
230                                     const vector_double &, const individuals_group_t &) const
231         {
232             return inds;
233         }
234         std::string get_name() const
235         {
236             return "frobniz";
237         }
238     };
239     BOOST_CHECK_EQUAL(r_policy{udrp_00{}}.get_name(), "frobniz");
240     struct udrp_01 {
241         individuals_group_t replace(const individuals_group_t &inds, const vector_double::size_type &,
242                                     const vector_double::size_type &, const vector_double::size_type &,
243                                     const vector_double::size_type &, const vector_double::size_type &,
244                                     const vector_double &, const individuals_group_t &) const
245         {
246             return inds;
247         }
248         // Missing const.
249         std::string get_name()
250         {
251             return "frobniz";
252         }
253     };
254     BOOST_CHECK(r_policy{udrp_01{}}.get_name() != "frobniz");
255 
256     // get_extra_info().
257     struct udrp_02 {
258         individuals_group_t replace(const individuals_group_t &inds, const vector_double::size_type &,
259                                     const vector_double::size_type &, const vector_double::size_type &,
260                                     const vector_double::size_type &, const vector_double::size_type &,
261                                     const vector_double &, const individuals_group_t &) const
262         {
263             return inds;
264         }
265         std::string get_extra_info() const
266         {
267             return "frobniz";
268         }
269     };
270     BOOST_CHECK_EQUAL(r_policy{udrp_02{}}.get_extra_info(), "frobniz");
271     struct udrp_03 {
272         individuals_group_t replace(const individuals_group_t &inds, const vector_double::size_type &,
273                                     const vector_double::size_type &, const vector_double::size_type &,
274                                     const vector_double::size_type &, const vector_double::size_type &,
275                                     const vector_double &, const individuals_group_t &) const
276         {
277             return inds;
278         }
279         // Missing const.
280         std::string get_extra_info()
281         {
282             return "frobniz";
283         }
284     };
285     BOOST_CHECK(r_policy{udrp_03{}}.get_extra_info().empty());
286 }
287 
BOOST_AUTO_TEST_CASE(stream_operator)288 BOOST_AUTO_TEST_CASE(stream_operator)
289 {
290     struct udrp_00 {
291         individuals_group_t replace(const individuals_group_t &inds, const vector_double::size_type &,
292                                     const vector_double::size_type &, const vector_double::size_type &,
293                                     const vector_double::size_type &, const vector_double::size_type &,
294                                     const vector_double &, const individuals_group_t &) const
295         {
296             return inds;
297         }
298     };
299     {
300         std::ostringstream oss;
301         oss << r_policy{udrp_00{}};
302         BOOST_CHECK(!oss.str().empty());
303     }
304     struct udrp_01 {
305         individuals_group_t replace(const individuals_group_t &inds, const vector_double::size_type &,
306                                     const vector_double::size_type &, const vector_double::size_type &,
307                                     const vector_double::size_type &, const vector_double::size_type &,
308                                     const vector_double &, const individuals_group_t &) const
309         {
310             return inds;
311         }
312         std::string get_extra_info() const
313         {
314             return "bartoppo";
315         }
316     };
317     {
318         std::ostringstream oss;
319         oss << r_policy{udrp_01{}};
320         const auto st = oss.str();
321         BOOST_CHECK(boost::contains(st, "bartoppo"));
322         BOOST_CHECK(boost::contains(st, "Extra info:"));
323     }
324 }
325 
BOOST_AUTO_TEST_CASE(replace)326 BOOST_AUTO_TEST_CASE(replace)
327 {
328     r_policy r0;
329 
330     BOOST_CHECK_EXCEPTION(r0.replace(individuals_group_t{{0}, {}, {}}, 0, 0, 0, 0, 0, {}, individuals_group_t{}),
331                           std::invalid_argument, [](const std::invalid_argument &ia) {
332                               return boost::contains(
333                                   ia.what(),
334                                   "an invalid group of individuals was passed to a replacement policy of type 'Fair "
335                                   "replace': the sets of individuals IDs, decision vectors and fitness vectors "
336                                   "must all have the same sizes, but instead their sizes are 1, 0 and 0");
337                           });
338 
339     BOOST_CHECK_EXCEPTION(r0.replace(individuals_group_t{{0}, {{1.}}, {{1.}}}, 0, 0, 0, 0, 0, {},
340                                      individuals_group_t{{0}, {{1.}, {1.}}, {{1.}}}),
341                           std::invalid_argument, [](const std::invalid_argument &ia) {
342                               return boost::contains(
343                                   ia.what(),
344                                   "an invalid group of migrants was passed to a replacement policy of type 'Fair "
345                                   "replace': the sets of migrants IDs, decision vectors and fitness vectors "
346                                   "must all have the same sizes, but instead their sizes are 1, 2 and 1");
347                           });
348 
349     BOOST_CHECK_EXCEPTION(
350         r0.replace(individuals_group_t{{0}, {{1.}}, {{1.}}}, 0, 0, 0, 0, 0, {},
351                    individuals_group_t{{0}, {{1.}}, {{1.}}}),
352         std::invalid_argument, [](const std::invalid_argument &ia) {
353             return boost::contains(
354                 ia.what(), "a problem dimension of zero was passed to a replacement policy of type 'Fair replace'");
355         });
356 
357     BOOST_CHECK_EXCEPTION(r0.replace(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 2, 0, 0, 0, {},
358                                      individuals_group_t{{0}, {{1.}}, {{1.}}}),
359                           std::invalid_argument, [](const std::invalid_argument &ia) {
360                               return boost::contains(
361                                   ia.what(), "the integer dimension (2) passed to a replacement policy of type "
362                                              "'Fair replace' is larger than the supplied problem dimension (1)");
363                           });
364 
365     BOOST_CHECK_EXCEPTION(
366         r0.replace(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0, 0, 0, 0, {},
367                    individuals_group_t{{0}, {{1.}}, {{1.}}}),
368         std::invalid_argument, [](const std::invalid_argument &ia) {
369             return boost::contains(
370                 ia.what(),
371                 "an invalid number of objectives (0) was passed to a replacement policy of type 'Fair replace'");
372         });
373 
374     BOOST_CHECK_EXCEPTION(
375         r0.replace(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0, std::numeric_limits<vector_double::size_type>::max(),
376                    0, 0, {}, individuals_group_t{{0}, {{1.}}, {{1.}}}),
377         std::invalid_argument, [](const std::invalid_argument &ia) {
378             return boost::contains(ia.what(),
379                                    "the number of objectives ("
380                                        + std::to_string(std::numeric_limits<vector_double::size_type>::max())
381                                        + ") passed to a replacement policy of type 'Fair replace' is too large");
382         });
383 
384     BOOST_CHECK_EXCEPTION(r0.replace(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0, 1,
385                                      std::numeric_limits<vector_double::size_type>::max(), 0, {},
386                                      individuals_group_t{{0}, {{1.}}, {{1.}}}),
387                           std::invalid_argument, [](const std::invalid_argument &ia) {
388                               return boost::contains(
389                                   ia.what(),
390                                   "the number of equality constraints ("
391                                       + std::to_string(std::numeric_limits<vector_double::size_type>::max())
392                                       + ") passed to a replacement policy of type 'Fair replace' is too large");
393                           });
394 
395     BOOST_CHECK_EXCEPTION(
396         r0.replace(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0, 1, 0,
397                    std::numeric_limits<vector_double::size_type>::max(), {}, individuals_group_t{{0}, {{1.}}, {{1.}}}),
398         std::invalid_argument, [](const std::invalid_argument &ia) {
399             return boost::contains(ia.what(),
400                                    "the number of inequality constraints ("
401                                        + std::to_string(std::numeric_limits<vector_double::size_type>::max())
402                                        + ") passed to a replacement policy of type 'Fair replace' is too large");
403         });
404 
405     BOOST_CHECK_EXCEPTION(r0.replace(individuals_group_t{{0}, {{1.}}, {{1.}}}, 1, 0, 1, 1, 1, {},
406                                      individuals_group_t{{0}, {{1.}}, {{1.}}}),
407                           std::invalid_argument, [](const std::invalid_argument &ia) {
408                               return boost::contains(
409                                   ia.what(),
410                                   "the vector of tolerances passed to a replacement policy of type 'Fair replace' has "
411                                   "a dimension (0) which is inconsistent with the total number of constraints (2)");
412                           });
413 
414     BOOST_CHECK_EXCEPTION(r0.replace(individuals_group_t{{0, 1}, {{1.}, {}}, {{1.}, {1.}}}, 1, 0, 1, 0, 0, {},
415                                      individuals_group_t{{0}, {{1.}}, {{1.}}}),
416                           std::invalid_argument, [](const std::invalid_argument &ia) {
417                               return boost::contains(
418                                   ia.what(), "not all the individuals passed to a replacement policy of type 'Fair "
419                                              "replace' have the expected dimension (1)");
420                           });
421 
422     BOOST_CHECK_EXCEPTION(r0.replace(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {}}}, 1, 0, 1, 0, 0, {},
423                                      individuals_group_t{{0}, {{1.}}, {{1.}}}),
424                           std::invalid_argument, [](const std::invalid_argument &ia) {
425                               return boost::contains(
426                                   ia.what(), "not all the individuals passed to a replacement policy of type 'Fair "
427                                              "replace' have the expected fitness dimension (1)");
428                           });
429 
430     BOOST_CHECK_EXCEPTION(r0.replace(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}, 1, 0, 1, 0, 0, {},
431                                      individuals_group_t{{0, 1}, {{1.}, {}}, {{1.}, {1.}}}),
432                           std::invalid_argument, [](const std::invalid_argument &ia) {
433                               return boost::contains(ia.what(),
434                                                      "not all the migrants passed to a replacement policy of type "
435                                                      "'Fair replace' have the expected dimension (1)");
436                           });
437 
438     BOOST_CHECK_EXCEPTION(r0.replace(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}, 1, 0, 1, 0, 0, {},
439                                      individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {}}}),
440                           std::invalid_argument, [](const std::invalid_argument &ia) {
441                               return boost::contains(ia.what(),
442                                                      "not all the migrants passed to a replacement policy of type "
443                                                      "'Fair replace' have the expected fitness dimension (1)");
444                           });
445 
446     struct fail_0 {
447         individuals_group_t replace(const individuals_group_t &, const vector_double::size_type &,
448                                     const vector_double::size_type &, const vector_double::size_type &,
449                                     const vector_double::size_type &, const vector_double::size_type &,
450                                     const vector_double &, const individuals_group_t &) const
451         {
452             return individuals_group_t{{0}, {}, {}};
453         }
454         std::string get_name() const
455         {
456             return "fail_0";
457         }
458     };
459 
460     BOOST_CHECK_EXCEPTION(r_policy{fail_0{}}.replace(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}, 1, 0, 1,
461                                                      0, 0, {}, individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}),
462                           std::invalid_argument, [](const std::invalid_argument &ia) {
463                               return boost::contains(
464                                   ia.what(),
465                                   "an invalid group of individuals was returned by a replacement policy of type "
466                                   "'fail_0': the sets of individuals IDs, decision vectors and fitness vectors "
467                                   "must all have the same sizes, but instead their sizes are 1, 0 and 0");
468                           });
469 
470     struct fail_1 {
471         individuals_group_t replace(const individuals_group_t &, const vector_double::size_type &,
472                                     const vector_double::size_type &, const vector_double::size_type &,
473                                     const vector_double::size_type &, const vector_double::size_type &,
474                                     const vector_double &, const individuals_group_t &) const
475         {
476             return individuals_group_t{{0, 1}, {{1}, {}}, {{1}, {1}}};
477         }
478         std::string get_name() const
479         {
480             return "fail_1";
481         }
482     };
483 
484     BOOST_CHECK_EXCEPTION(r_policy{fail_1{}}.replace(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}, 1, 0, 1,
485                                                      0, 0, {}, individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}),
486                           std::invalid_argument, [](const std::invalid_argument &ia) {
487                               return boost::contains(ia.what(),
488                                                      "not all the individuals returned by a replacement "
489                                                      "policy of type 'fail_1' have the expected dimension (1)");
490                           });
491 
492     struct fail_2 {
493         individuals_group_t replace(const individuals_group_t &, const vector_double::size_type &,
494                                     const vector_double::size_type &, const vector_double::size_type &,
495                                     const vector_double::size_type &, const vector_double::size_type &,
496                                     const vector_double &, const individuals_group_t &) const
497         {
498             return individuals_group_t{{0, 1}, {{1}, {1}}, {{1}, {}}};
499         }
500         std::string get_name() const
501         {
502             return "fail_2";
503         }
504     };
505 
506     BOOST_CHECK_EXCEPTION(r_policy{fail_2{}}.replace(individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}, 1, 0, 1,
507                                                      0, 0, {}, individuals_group_t{{0, 1}, {{1.}, {1.}}, {{1.}, {1.}}}),
508                           std::invalid_argument, [](const std::invalid_argument &ia) {
509                               return boost::contains(ia.what(),
510                                                      "not all the individuals returned by a replacement policy of type "
511                                                      "'fail_2' have the expected fitness dimension (1)");
512                           });
513 }
514 
515 struct udrp_a {
replaceudrp_a516     individuals_group_t replace(const individuals_group_t &inds, const vector_double::size_type &,
517                                 const vector_double::size_type &, const vector_double::size_type &,
518                                 const vector_double::size_type &, const vector_double::size_type &,
519                                 const vector_double &, const individuals_group_t &) const
520     {
521         return inds;
522     }
get_nameudrp_a523     std::string get_name() const
524     {
525         return "abba";
526     }
get_extra_infoudrp_a527     std::string get_extra_info() const
528     {
529         return "dabba";
530     }
531     template <typename Archive>
serializeudrp_a532     void serialize(Archive &ar, unsigned)
533     {
534         ar &state;
535     }
536     int state = 42;
537 };
538 
539 PAGMO_S11N_R_POLICY_EXPORT(udrp_a)
540 
541 // Serialization tests.
BOOST_AUTO_TEST_CASE(s11n)542 BOOST_AUTO_TEST_CASE(s11n)
543 {
544     r_policy r_pol0{udrp_a{}};
545     BOOST_CHECK(r_pol0.extract<udrp_a>()->state == 42);
546     r_pol0.extract<udrp_a>()->state = -42;
547     // Store the string representation.
548     std::stringstream ss;
549     auto before = boost::lexical_cast<std::string>(r_pol0);
550     // Now serialize, deserialize and compare the result.
551     {
552         boost::archive::binary_oarchive oarchive(ss);
553         oarchive << r_pol0;
554     }
555     // Change the content of p before deserializing.
556     r_pol0 = r_policy{};
557     {
558         boost::archive::binary_iarchive iarchive(ss);
559         iarchive >> r_pol0;
560     }
561     auto after = boost::lexical_cast<std::string>(r_pol0);
562     BOOST_CHECK_EQUAL(before, after);
563     BOOST_CHECK(r_pol0.is<udrp_a>());
564     BOOST_CHECK(r_pol0.extract<udrp_a>()->state = -42);
565 }
566 
BOOST_AUTO_TEST_CASE(is_valid)567 BOOST_AUTO_TEST_CASE(is_valid)
568 {
569     r_policy p0;
570     BOOST_CHECK(p0.is_valid());
571     r_policy p1(std::move(p0));
572     BOOST_CHECK(!p0.is_valid());
573     p0 = r_policy{udrp_a{}};
574     BOOST_CHECK(p0.is_valid());
575     p1 = std::move(p0);
576     BOOST_CHECK(!p0.is_valid());
577     p0 = r_policy{udrp_a{}};
578     BOOST_CHECK(p0.is_valid());
579 }
580 
BOOST_AUTO_TEST_CASE(generic_assignment)581 BOOST_AUTO_TEST_CASE(generic_assignment)
582 {
583     r_policy p0;
584     BOOST_CHECK(p0.is<fair_replace>());
585     BOOST_CHECK(&(p0 = udrp_a{}) == &p0);
586     BOOST_CHECK(p0.is_valid());
587     BOOST_CHECK(p0.is<udrp_a>());
588     p0 = udrp1{};
589     BOOST_CHECK(p0.is<udrp1>());
590     BOOST_CHECK((!std::is_assignable<r_policy, void>::value));
591     BOOST_CHECK((!std::is_assignable<r_policy, int &>::value));
592     BOOST_CHECK((!std::is_assignable<r_policy, const int &>::value));
593     BOOST_CHECK((!std::is_assignable<r_policy, int &&>::value));
594 }
595 
BOOST_AUTO_TEST_CASE(type_index)596 BOOST_AUTO_TEST_CASE(type_index)
597 {
598     r_policy p0;
599     BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(fair_replace)));
600     p0 = r_policy{udrp1{}};
601     BOOST_CHECK(p0.get_type_index() == std::type_index(typeid(udrp1)));
602 }
603 
BOOST_AUTO_TEST_CASE(get_ptr)604 BOOST_AUTO_TEST_CASE(get_ptr)
605 {
606     r_policy p0;
607     BOOST_CHECK(p0.get_ptr() == p0.extract<fair_replace>());
608     BOOST_CHECK(static_cast<const r_policy &>(p0).get_ptr()
609                 == static_cast<const r_policy &>(p0).extract<fair_replace>());
610     p0 = r_policy{udrp1{}};
611     BOOST_CHECK(p0.get_ptr() == p0.extract<udrp1>());
612     BOOST_CHECK(static_cast<const r_policy &>(p0).get_ptr() == static_cast<const r_policy &>(p0).extract<udrp1>());
613 }
614