blob: b78d52f8bcd52baa4780eb5c5061bcfc9285b12d [file] [log] [blame]
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// test_reset_object_address.cpp
// (C) Copyright 2002 Robert Ramey - http://www.rrsd.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)
#include <sstream>
#include <cassert>
#include <cstdlib> // for rand()
#include <cstddef> // size_t
#include <boost/config.hpp>
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{
using ::rand;
using ::size_t;
}
#endif
#include "test_tools.hpp"
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/polymorphic_text_oarchive.hpp>
#include <boost/archive/polymorphic_text_iarchive.hpp>
#include <boost/serialization/list.hpp>
#include <boost/serialization/access.hpp>
// Someday, maybe all tests will be converted to the unit test framework.
// but for now use the text execution monitor to be consistent with all
// the other tests.
// simple test of untracked value
#include "A.hpp"
#include "A.ipp"
void test1(){
std::stringstream ss;
const A a;
{
boost::archive::text_oarchive oa(ss);
oa << a;
}
A a1;
{
boost::archive::text_iarchive ia(ss);
// load to temporary
A a2;
ia >> a2;
BOOST_CHECK_EQUAL(a, a2);
// move to final destination
a1 = a2;
ia.reset_object_address(& a1, & a2);
}
BOOST_CHECK_EQUAL(a, a1);
}
// simple test of tracked value
class B {
friend class boost::serialization::access;
int m_i;
template<class Archive>
void serialize(Archive &ar, const unsigned int /*file_version*/){
ar & m_i;
}
public:
bool operator==(const B & rhs) const {
return m_i == rhs.m_i;
}
B() :
m_i(std::rand())
{}
};
//BOOST_TEST_DONT_PRINT_LOG_VALUE( B )
void test2(){
std::stringstream ss;
B const b;
B const * const b_ptr = & b;
BOOST_CHECK_EQUAL(& b, b_ptr);
{
boost::archive::text_oarchive oa(ss);
oa << b;
oa << b_ptr;
}
B b1;
B * b1_ptr;
{
boost::archive::text_iarchive ia(ss);
// load to temporary
B b2;
ia >> b2;
BOOST_CHECK_EQUAL(b, b2);
// move to final destination
b1 = b2;
ia.reset_object_address(& b1, & b2);
ia >> b1_ptr;
}
BOOST_CHECK_EQUAL(b, b1);
BOOST_CHECK_EQUAL(& b1, b1_ptr);
}
// check that nested member values are properly moved
class D {
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int /*file_version*/){
ar & m_b;
}
public:
B m_b;
bool operator==(const D & rhs) const {
return m_b == rhs.m_b;
}
D(){}
};
//BOOST_TEST_DONT_PRINT_LOG_VALUE( D )
void test3(){
std::stringstream ss;
D const d;
B const * const b_ptr = & d.m_b;
{
boost::archive::text_oarchive oa(ss);
oa << d;
oa << b_ptr;
}
D d1;
B * b1_ptr;
{
boost::archive::text_iarchive ia(ss);
D d2;
ia >> d2;
d1 = d2;
ia.reset_object_address(& d1, & d2);
ia >> b1_ptr;
}
BOOST_CHECK_EQUAL(d, d1);
BOOST_CHECK_EQUAL(* b_ptr, * b1_ptr);
}
// check that data pointed to by pointer members is NOT moved
class E {
int m_i;
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &ar, const unsigned int /*file_version*/){
ar & m_i;
}
public:
bool operator==(const E &rhs) const {
return m_i == rhs.m_i;
}
E() :
m_i(std::rand())
{}
E(const E & rhs) :
m_i(rhs.m_i)
{}
};
//BOOST_TEST_DONT_PRINT_LOG_VALUE( E )
// check that moves don't move stuff pointed to
class F {
friend class boost::serialization::access;
E * m_eptr;
template<class Archive>
void serialize(Archive &ar, const unsigned int /*file_version*/){
ar & m_eptr;
}
public:
bool operator==(const F &rhs) const {
return *m_eptr == *rhs.m_eptr;
}
F & operator=(const F & rhs) {
* m_eptr = * rhs.m_eptr;
return *this;
}
F(){
m_eptr = new E;
}
F(const F & rhs){
*this = rhs;
}
~F(){
delete m_eptr;
}
};
//BOOST_TEST_DONT_PRINT_LOG_VALUE( F )
void test4(){
std::stringstream ss;
const F f;
{
boost::archive::text_oarchive oa(ss);
oa << f;
}
F f1;
{
boost::archive::text_iarchive ia(ss);
F f2;
ia >> f2;
f1 = f2;
ia.reset_object_address(& f1, & f2);
}
BOOST_CHECK_EQUAL(f, f1);
}
// check that multiple moves keep track of the correct target
class G {
friend class boost::serialization::access;
A m_a1;
A m_a2;
A *m_pa2;
template<class Archive>
void save(Archive &ar, const unsigned int /*file_version*/) const {
ar << m_a1;
ar << m_a2;
ar << m_pa2;
}
template<class Archive>
void load(Archive &ar, const unsigned int /*file_version*/){
A a; // temporary A
ar >> a;
m_a1 = a;
ar.reset_object_address(& m_a1, & a);
ar >> a;
m_a2 = a;
ar.reset_object_address(& m_a2, & a);
ar & m_pa2;
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
public:
bool operator==(const G &rhs) const {
return
m_a1 == rhs.m_a1
&& m_a2 == rhs.m_a2
&& *m_pa2 == *rhs.m_pa2;
}
G & operator=(const G & rhs) {
m_a1 = rhs.m_a1;
m_a2 = rhs.m_a2;
m_pa2 = & m_a2;
return *this;
}
G(){
m_pa2 = & m_a2;
}
G(const G & rhs){
*this = rhs;
}
~G(){}
};
//BOOST_TEST_DONT_PRINT_LOG_VALUE( G )
void test5(){
std::stringstream ss;
const G g;
{
boost::archive::text_oarchive oa(ss);
oa << g;
}
G g1;
{
boost::archive::text_iarchive ia(ss);
ia >> g1;
}
BOOST_CHECK_EQUAL(g, g1);
}
// joaquin's test - this tests the case where rest_object_address
// is applied to an item which in fact is not tracked so that
// the call is in fact superfluous.
struct foo
{
int x;
private:
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive &,const unsigned int)
{
}
};
struct bar
{
foo f[2];
foo* pf[2];
private:
friend class boost::serialization::access;
BOOST_SERIALIZATION_SPLIT_MEMBER()
template<class Archive>
void save(Archive& ar,const unsigned int)const
{
for(int i=0;i<2;++i){
ar<<f[i].x;
ar<<f[i];
}
for(int j=0;j<2;++j){
ar<<pf[j];
}
}
template<class Archive>
void load(Archive& ar,const unsigned int)
{
for(int i=0;i<2;++i){
int x;
ar>>x;
f[i].x=x;
ar.reset_object_address(&f[i].x,&x);
ar>>f[i];
}
for(int j=0;j<2;++j){
ar>>pf[j];
}
}
};
int test6()
{
bar b;
b.f[0].x=0;
b.f[1].x=1;
b.pf[0]=&b.f[0];
b.pf[1]=&b.f[1];
std::ostringstream oss;
{
boost::archive::text_oarchive oa(oss);
oa<<const_cast<const bar&>(b);
}
bar b1;
b1.pf[0]=0;
b1.pf[1]=0;
std::istringstream iss(oss.str());
boost::archive::text_iarchive ia(iss);
ia>>b1;
BOOST_CHECK(b1.pf[0]==&b1.f[0]&&b1.pf[1]==&b1.f[1]);
return 0;
}
// test one of the collections
void test7(){
std::stringstream ss;
B const b;
B const * const b_ptr = & b;
BOOST_CHECK_EQUAL(& b, b_ptr);
{
std::list<const B *> l;
l.push_back(b_ptr);
boost::archive::text_oarchive oa(ss);
oa << const_cast<const std::list<const B *> &>(l);
}
B b1;
{
std::list<B *> l;
boost::archive::text_iarchive ia(ss);
ia >> l;
delete l.front(); // prevent memory leak
}
}
// test one of the collections with polymorphic archive
void test8(){
std::stringstream ss;
B const b;
B const * const b_ptr = & b;
BOOST_CHECK_EQUAL(& b, b_ptr);
{
std::list<const B *> l;
l.push_back(b_ptr);
boost::archive::polymorphic_text_oarchive oa(ss);
boost::archive::polymorphic_oarchive & poa = oa;
poa << const_cast<const std::list<const B *> &>(l);
}
B b1;
{
std::list<B *> l;
boost::archive::polymorphic_text_iarchive ia(ss);
boost::archive::polymorphic_iarchive & pia = ia;
pia >> l;
delete l.front(); // prevent memory leak
}
}
int test_main(int /* argc */, char * /* argv */[])
{
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
return EXIT_SUCCESS;
}