• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
2 // test_variant.cpp
3 // test of non-intrusive serialization of variant types
4 //
5 // copyright (c) 2005
6 // troy d. straszheim <troy@resophonic.com>
7 // http://www.resophonic.com
8 //
9 // Use, modification and distribution is subject to the Boost Software
10 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12 //
13 // See http://www.boost.org for updates, documentation, and revision history.
14 //
15 // thanks to Robert Ramey and Peter Dimov.
16 //
17 
18 #include <cstddef> // NULL
19 #include <cstdio> // remove
20 #include <fstream>
21 #include <boost/config.hpp>
22 #include <boost/math/special_functions/next.hpp> // float_distance
23 #if defined(BOOST_NO_STDC_NAMESPACE)
24 namespace std{
25     using ::remove;
26 }
27 #endif
28 
29 #include <boost/type_traits/is_same.hpp>
30 #include <boost/mpl/eval_if.hpp>
31 #include <boost/mpl/identity.hpp>
32 #include <boost/serialization/throw_exception.hpp>
33 
34 #if defined(_MSC_VER) && (_MSC_VER <= 1020)
35 #  pragma warning (disable : 4786) // too long name, harmless warning
36 #endif
37 
38 #include "test_tools.hpp"
39 
40 #include <boost/archive/archive_exception.hpp>
41 
42 #include <boost/serialization/nvp.hpp>
43 #include <boost/serialization/variant.hpp>
44 
45 #include "A.hpp"
46 #include "A.ipp"
47 
48 class are_equal
49     : public boost::static_visitor<bool>
50 {
51 public:
52     // note extra rigamorole for compilers which don't support
53     // partial function template ordering - specfically msvc 6.x
54     struct same {
55         template<class T, class U>
invokeare_equal::same56         static bool invoke(const T & t, const U & u){
57             return t == u;
58         }
59     };
60 
61     struct not_same {
62         template<class T, class U>
invokeare_equal::not_same63         static bool invoke(const T &, const U &){
64             return false;
65         }
66     };
67 
68     template <class T, class U>
operator ()(const T & t,const U & u) const69     bool operator()( const T & t, const U & u) const
70     {
71         typedef typename boost::mpl::eval_if<boost::is_same<T, U>,
72             boost::mpl::identity<same>,
73             boost::mpl::identity<not_same>
74         >::type type;
75         return type::invoke(t, u);
76     }
77 
operator ()(const float & lhs,const float & rhs) const78     bool operator()( const float & lhs, const float & rhs ) const
79     {
80         return std::abs( boost::math::float_distance(lhs, rhs)) < 2;
81     }
operator ()(const double & lhs,const double & rhs) const82     bool operator()( const double & lhs, const double & rhs ) const
83     {
84         return std::abs( boost::math::float_distance(lhs, rhs)) < 2;
85     }
86 };
87 
88 template <class T>
test_type(const T & gets_written)89 void test_type(const T& gets_written){
90    const char * testfile = boost::archive::tmpnam(NULL);
91    BOOST_REQUIRE(testfile != NULL);
92    {
93       test_ostream os(testfile, TEST_STREAM_FLAGS);
94       test_oarchive oa(os, TEST_ARCHIVE_FLAGS);
95       oa << boost::serialization::make_nvp("written", gets_written);
96    }
97 
98    T got_read;
99    {
100       test_istream is(testfile, TEST_STREAM_FLAGS);
101       test_iarchive ia(is, TEST_ARCHIVE_FLAGS);
102       ia >> boost::serialization::make_nvp("written", got_read);
103    }
104    BOOST_CHECK(boost::apply_visitor(are_equal(), gets_written, got_read));
105 
106    std::remove(testfile);
107 }
108 
109 // this verifies that if you try to read in a variant from a file
110 // whose "which" is illegal for the one in memory (that is, you're
111 // reading in to a different variant than you wrote out to) the load()
112 // operation will throw.  One could concievably add checking for
113 // sequence length as well, but this would add size to the archive for
114 // dubious benefit.
115 //
do_bad_read()116 void do_bad_read()
117 {
118     // Compiling this test invokes and ICE on msvc 6
119     // So, we'll just to skip it for this compiler
120     #if defined(_MSC_VER) && (_MSC_VER <= 1020)
121         boost::variant<bool, float, int, std::string> big_variant;
122         big_variant = std::string("adrenochrome");
123 
124         const char * testfile = boost::archive::tmpnam(NULL);
125         BOOST_REQUIRE(testfile != NULL);
126         {
127             test_ostream os(testfile, TEST_STREAM_FLAGS);
128             test_oarchive oa(os, TEST_ARCHIVE_FLAGS);
129             oa << BOOST_SERIALIZATION_NVP(big_variant);
130         }
131         boost::variant<bool, float, int> little_variant;
132         {
133             test_istream is(testfile, TEST_STREAM_FLAGS);
134             test_iarchive ia(is, TEST_ARCHIVE_FLAGS);
135             bool exception_invoked = false;
136             BOOST_TRY {
137                 ia >> BOOST_SERIALIZATION_NVP(little_variant);
138             } BOOST_CATCH (boost::archive::archive_exception const& e) {
139                 BOOST_CHECK(boost::archive::archive_exception::unsupported_version == e.code);
140                 exception_invoked = true;
141             }
142             BOOST_CATCH_END
143             BOOST_CHECK(exception_invoked);
144         }
145     #endif
146 }
147 
148 struct H {
149     int i;
150 };
151 
152 namespace boost {
153 namespace serialization {
154 
155 template<class Archive>
serialize(Archive & ar,H & h,const unsigned int)156 void serialize(Archive &ar, H & h, const unsigned int /*file_version*/){
157     ar & boost::serialization::make_nvp("h", h.i);
158 }
159 
160 } // namespace serialization
161 } // namespace boost
162 
operator ==(H const & lhs,H const & rhs)163 inline bool operator==(H const & lhs, H const & rhs) {
164     return lhs.i == rhs.i;
165 }
166 
operator !=(H const & lhs,H const & rhs)167 inline bool operator!=(H const & lhs, H const & rhs) {
168     return !(lhs == rhs);
169 }
170 
operator <(H const & lhs,H const & rhs)171 inline bool operator<(H const & lhs, H const & rhs) {
172     return lhs.i < rhs.i;
173 }
174 
hash_value(H const & val)175 inline std::size_t hash_value(H const & val) {
176     return val.i;
177 }
178 
test_pointer()179 void test_pointer(){
180     const char * testfile = boost::archive::tmpnam(NULL);
181     BOOST_REQUIRE(testfile != NULL);
182     typedef boost::variant<H, int> variant_t;
183     H const h = {5};
184     variant_t v(h);
185     {
186         test_ostream os(testfile, TEST_STREAM_FLAGS);
187         test_oarchive oa(os, TEST_ARCHIVE_FLAGS);
188         oa << boost::serialization::make_nvp("written", v);
189         const H * h_ptr = & boost::strict_get<H const &>(v);
190         oa << boost::serialization::make_nvp("written", h_ptr);
191     }
192     variant_t v2;
193     {
194         test_istream is(testfile, TEST_STREAM_FLAGS);
195         test_iarchive ia(is, TEST_ARCHIVE_FLAGS);
196         ia >> boost::serialization::make_nvp("written", v2);
197         H * h2_ptr;
198         ia >> boost::serialization::make_nvp("written", h2_ptr);
199         BOOST_CHECK_EQUAL(h, boost::strict_get<H const>(v2));
200         BOOST_CHECK_EQUAL(h2_ptr, & boost::strict_get<H const &>(v2));
201     }
202     BOOST_CHECK_EQUAL(v, v2);
203 }
204 
205 #include <boost/serialization/map.hpp>
206 #include <boost/serialization/set.hpp>
207 
208 // test a pointer to an object contained into a variant that is an
209 // element of a set
test_variant_set()210 void test_variant_set()
211 {
212     const char * testfile = boost::archive::tmpnam(NULL);
213     BOOST_REQUIRE(testfile != NULL);
214     typedef boost::variant<H, int> variant_t;
215     typedef std::set<variant_t> uset_t;
216     uset_t set;
217     {
218         test_ostream os(testfile, TEST_STREAM_FLAGS);
219         test_oarchive oa(os, TEST_ARCHIVE_FLAGS);
220         H const h = {5};
221         variant_t v(h);
222         set.insert(v);
223         oa << boost::serialization::make_nvp("written", set);
224         H const * const h_ptr = boost::strict_get<H const>(&(*set.begin()));
225         oa << boost::serialization::make_nvp("written", h_ptr);
226     }
227     uset_t set2;
228     {
229         test_istream is(testfile, TEST_STREAM_FLAGS);
230         test_iarchive ia(is, TEST_ARCHIVE_FLAGS);
231         ia >> boost::serialization::make_nvp("written", set2);
232         H * h_ptr;
233         ia >> boost::serialization::make_nvp("written", h_ptr);
234         const H * h_ptr2 = & boost::strict_get<H const>(*set2.begin());
235         BOOST_CHECK_EQUAL(h_ptr, h_ptr2);
236     }
237     BOOST_CHECK_EQUAL(set, set2);
238 }
239 
240 // test a pointer to an object contained into a variant that is an
241 // element of a map
test_variant_map()242 void test_variant_map()
243 {
244     const char * testfile = boost::archive::tmpnam(NULL);
245     BOOST_REQUIRE(testfile != NULL);
246     typedef boost::variant<H, int> variant_t;
247     typedef std::map<int, variant_t> map_t;
248     map_t map;
249     {
250         test_ostream os(testfile, TEST_STREAM_FLAGS);
251         test_oarchive oa(os, TEST_ARCHIVE_FLAGS);
252         H const h = {5};
253         variant_t v(h);
254         map[0] = v;
255         BOOST_ASSERT(1 == map.size());
256         oa << boost::serialization::make_nvp("written", map);
257         H const * const h_ptr = boost::strict_get<H const>(&map[0]);
258         BOOST_CHECK_EQUAL(h_ptr, boost::strict_get<H const>(&map[0]));
259         oa << boost::serialization::make_nvp("written", h_ptr);
260     }
261     map_t map2;
262     {
263         test_istream is(testfile, TEST_STREAM_FLAGS);
264         test_iarchive ia(is, TEST_ARCHIVE_FLAGS);
265         ia >> boost::serialization::make_nvp("written", map2);
266         BOOST_ASSERT(1 == map2.size());
267         H * h_ptr;
268         ia >> boost::serialization::make_nvp("written", h_ptr);
269         H const * const h_ptr2 = boost::strict_get<H const>(&map2[0]);
270         BOOST_CHECK_EQUAL(h_ptr, h_ptr2);
271     }
272     BOOST_CHECK_EQUAL(map, map2);
273 }
274 
test_main(int,char * [])275 int test_main( int /* argc */, char* /* argv */[] )
276 {
277     {
278         boost::variant<bool, int, float, double, A, std::string> v;
279         v = false;
280         test_type(v);
281         v = 1;
282         test_type(v);
283         v = (float) 2.3;
284         test_type(v);
285         v = (double) 6.4;
286         test_type(v);
287         v = std::string("we can't stop here, this is Bat Country");
288         test_type(v);
289         v = A();
290         test_type(v);
291     }
292     test_pointer();
293     test_variant_set();
294     test_variant_map();
295     do_bad_read();
296     return EXIT_SUCCESS;
297 }
298 
299 // EOF
300