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