1 //
2 // Boost.Pointer Container
3 //
4 //  Copyright Thorsten Ottosen 2003-2005. Use, modification and
5 //  distribution is subject to the Boost Software License, Version
6 //  1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 //  http://www.boost.org/LICENSE_1_0.txt)
8 //
9 // For more information, see http://www.boost.org/libs/ptr_container/
10 //
11 
12 #include <boost/config.hpp>
13 #ifdef BOOST_MSVC
14 #pragma warning( disable: 4996 )
15 #endif
16 
17 #include <boost/test/unit_test.hpp>
18 #include <boost/archive/text_oarchive.hpp>
19 #include <boost/archive/text_iarchive.hpp>
20 #include <boost/archive/xml_iarchive.hpp>
21 #include <boost/archive/xml_oarchive.hpp>
22 #include <boost/functional/hash.hpp>
23 #include <boost/ptr_container/ptr_container.hpp>
24 #include <boost/ptr_container/serialize_ptr_container.hpp>
25 #include <boost/serialization/export.hpp>
26 #include <boost/serialization/base_object.hpp>
27 #include <boost/serialization/utility.hpp>
28 #include <boost/serialization/string.hpp>
29 #include <fstream>
30 #include <string>
31 #include <cstdio>
32 
33 //
34 // serialization helper: we can't save a non-const object
35 //
36 template< class T >
as_const(T const & r)37 inline T const& as_const( T const& r )
38 {
39     return r;
40 }
41 
42 //
43 // used to customize tests for circular_buffer
44 //
45 template< class Cont >
46 struct set_capacity
47 {
operator ()set_capacity48     void operator()( Cont& ) const
49     { }
50 };
51 
52 template<class T>
53 struct set_capacity< boost::ptr_circular_buffer<T> >
54 {
operator ()set_capacity55     void operator()( boost::ptr_circular_buffer<T>& c ) const
56     {
57         c.set_capacity( 100u );
58     }
59 };
60 
61 //
62 // class hierarchy
63 //
64 struct Base
65 {
66     friend class boost::serialization::access;
67 
68     int i;
69 
70 
71     template< class Archive >
serializeBase72     void serialize( Archive& ar, const unsigned int /*version*/ )
73     {
74         ar & boost::serialization::make_nvp( "i", i );
75     }
76 
BaseBase77     Base() : i(42)
78     { }
79 
BaseBase80     Base( int i ) : i(i)
81     { }
82 
~BaseBase83     virtual ~Base()
84     { }
85 };
86 
operator <(const Base & l,const Base & r)87 inline bool operator<( const Base& l, const Base& r )
88 {
89     return l.i < r.i;
90 }
91 
operator ==(const Base & l,const Base & r)92 inline bool operator==( const Base& l, const Base& r )
93 {
94     return l.i == r.i;
95 }
96 
hash_value(const Base & b)97 inline std::size_t hash_value( const Base& b )
98 {
99     return boost::hash_value( b.i );
100 }
101 
102 struct Derived : Base
103 {
104     int i2;
105 
106     template< class Archive >
serializeDerived107     void serialize( Archive& ar, const unsigned int /*version*/ )
108     {
109         ar & boost::serialization::make_nvp( "Base",
110                  boost::serialization::base_object<Base>( *this ) );
111         ar & boost::serialization::make_nvp( "i2", i2 );
112     }
113 
DerivedDerived114     Derived() : Base(42), i2(42)
115     { }
116 
DerivedDerived117     explicit Derived( int i2 ) : Base(0), i2(i2)
118     { }
119 };
120 
121 BOOST_CLASS_EXPORT_GUID( Derived, "Derived" )
122 
123 //
124 // test of containers
125 //
126 //
127 
128 template< class C, class T >
add(C & c,T * r,unsigned)129 void add( C& c, T* r, unsigned /*n*/ )
130 {
131     c.insert( c.end(), r );
132 }
133 
134 template< class U, class T >
add(boost::ptr_array<U,2> & c,T * r,unsigned n)135 void add( boost::ptr_array<U,2>& c, T* r, unsigned n )
136 {
137     c.replace( n, r );
138 }
139 
140 template< class Cont, class OArchive, class IArchive >
test_serialization_helper()141 void test_serialization_helper()
142 {
143     Cont vec;
144     set_capacity<Cont>()( vec );
145     add( vec, new Base( -1 ), 0u );
146     add( vec, new Derived( 1 ), 1u );
147     BOOST_CHECK_EQUAL( vec.size(), 2u );
148 
149     std::string fn = std::tmpnam( 0 );
150 
151     {
152         std::ofstream ofs( fn.c_str() );
153         OArchive oa(ofs);
154         oa << boost::serialization::make_nvp( "container", as_const(vec) );
155     }
156 
157     Cont vec2;
158 
159     {
160         std::ifstream ifs( fn.c_str(), std::ios::binary );
161         IArchive ia(ifs);
162         ia >> boost::serialization::make_nvp( "container", vec2 );
163     }
164 
165     std::remove( fn.c_str() );
166 
167     BOOST_CHECK_EQUAL( vec.size(), vec2.size() );
168     BOOST_CHECK_EQUAL( (*vec2.begin()).i, -1 );
169     BOOST_CHECK_EQUAL( (*++vec2.begin()).i, 0 );
170 
171     typename Cont::iterator i = vec2.begin();
172     ++i;
173     Derived* d = dynamic_cast<Derived*>( &*i );
174     BOOST_CHECK_EQUAL( d->i2, 1 );
175 
176 }
177 
178 template< class Cont, class OArchive, class IArchive >
test_serialization_unordered_set_helper()179 void test_serialization_unordered_set_helper()
180 {
181     Cont vec;
182     set_capacity<Cont>()( vec );
183     add( vec, new Base( -1 ), 0u );
184     add( vec, new Derived( 1 ), 1u );
185     BOOST_CHECK_EQUAL( vec.size(), 2u );
186 
187     std::string fn = std::tmpnam( 0 );
188 
189     {
190         std::ofstream ofs( fn.c_str() );
191         OArchive oa(ofs);
192         oa << boost::serialization::make_nvp( "container", as_const(vec) );
193     }
194 
195     Cont vec2;
196 
197     {
198         std::ifstream ifs( fn.c_str(), std::ios::binary );
199         IArchive ia(ifs);
200         ia >> boost::serialization::make_nvp( "container", vec2 );
201     }
202 
203     std::remove( fn.c_str() );
204 
205     BOOST_CHECK_EQUAL( vec.size(), vec2.size() );
206     BOOST_CHECK_EQUAL( (*vec2.begin()).i, -1 );
207     BOOST_CHECK_EQUAL( (*++vec2.begin()).i, 0 );
208 }
209 
210 template< class Map, class OArchive, class IArchive >
test_serialization_map_helper()211 void test_serialization_map_helper()
212 {
213     Map m;
214     std::string key1("key1"), key2("key2");
215     m.insert( key1, new Base( -1 ) );
216     m.insert( key2, new Derived( 1 ) );
217     BOOST_CHECK_EQUAL( m.size(), 2u );
218 
219     std::string fn = std::tmpnam( 0 );
220 
221     {
222         std::ofstream ofs( fn.c_str() );
223         OArchive oa(ofs);
224         oa << boost::serialization::make_nvp( "container", as_const(m) );
225     }
226 
227     Map m2;
228 
229     {
230         std::ifstream ifs( fn.c_str(), std::ios::binary );
231         IArchive ia(ifs);
232         ia >> boost::serialization::make_nvp( "container", m2 );
233     }
234 
235     std::remove( fn.c_str() );
236 
237     BOOST_CHECK_EQUAL( m.size(), m2.size() );
238     BOOST_CHECK_EQUAL( m2.find(key1)->second->i, -1 );
239     BOOST_CHECK_EQUAL( m2.find(key2)->second->i, 0 );
240 
241     typename Map::iterator i = m2.find(key2);
242     Derived* d = dynamic_cast<Derived*>( i->second );
243     BOOST_CHECK_EQUAL( d->i2, 1 );
244 }
245 
246 //
247 // basic test of hierarchy
248 //
test_hierarchy()249 void test_hierarchy()
250 {
251     Base* p = new Derived();
252 
253     std::string fn = std::tmpnam( 0 );
254 
255     {
256         std::ofstream ofs( fn.c_str() );
257         boost::archive::text_oarchive oa(ofs);
258         oa << as_const(p);
259     }
260 
261     Base* d = 0;
262 
263     {
264         std::ifstream ifs( fn.c_str(), std::ios::binary );
265         boost::archive::text_iarchive ia(ifs);
266         ia >> d;
267     }
268 
269     std::remove( fn.c_str() );
270 
271     BOOST_CHECK_EQUAL( p->i, d->i );
272     BOOST_CHECK( p != d );
273     BOOST_CHECK( dynamic_cast<Derived*>( d ) );
274     delete p;
275     delete d;
276 }
277 
278 //
279 // test initializer
280 //
test_serialization()281 void test_serialization()
282 {
283     test_hierarchy();
284     test_serialization_helper< boost::ptr_deque<Base>,
285                                boost::archive::text_oarchive,
286                                boost::archive::text_iarchive >();
287     test_serialization_helper< boost::ptr_list<Base>,
288                                boost::archive::text_oarchive,
289                                boost::archive::text_iarchive>();
290     test_serialization_helper< boost::ptr_vector<Base>,
291                                boost::archive::text_oarchive,
292                                boost::archive::text_iarchive>();
293     test_serialization_helper< boost::ptr_vector<Base>,
294                                boost::archive::xml_oarchive,
295                                boost::archive::xml_iarchive>();
296     test_serialization_helper< boost::ptr_circular_buffer<Base>,
297                                boost::archive::text_oarchive,
298                                boost::archive::text_iarchive>();
299     test_serialization_helper< boost::ptr_circular_buffer<Base>,
300                                boost::archive::xml_oarchive,
301                                boost::archive::xml_iarchive>();
302     test_serialization_helper< boost::ptr_array<Base,2>,
303                                boost::archive::text_oarchive,
304                                boost::archive::text_iarchive>();
305     test_serialization_helper< boost::ptr_set<Base>,
306                                boost::archive::text_oarchive,
307                                boost::archive::text_iarchive>();
308     test_serialization_helper< boost::ptr_multiset<Base>,
309                                boost::archive::text_oarchive,
310                                boost::archive::text_iarchive>();
311 
312     test_serialization_unordered_set_helper< boost::ptr_unordered_set<Base>,
313                                              boost::archive::text_oarchive,
314                                              boost::archive::text_iarchive>();
315    test_serialization_unordered_set_helper<boost::ptr_unordered_multiset<Base>,
316                                            boost::archive::text_oarchive,
317                                            boost::archive::text_iarchive>();
318 
319     test_serialization_map_helper< boost::ptr_map<std::string,Base>,
320                                    boost::archive::text_oarchive,
321                                    boost::archive::text_iarchive>();
322     test_serialization_map_helper< boost::ptr_multimap<std::string,Base>,
323                                    boost::archive::text_oarchive,
324                                    boost::archive::text_iarchive>();
325 
326     test_serialization_map_helper< boost::ptr_map<std::string,Base>,
327                                    boost::archive::xml_oarchive,
328                                    boost::archive::xml_iarchive>();
329     test_serialization_map_helper< boost::ptr_multimap<std::string,Base>,
330                                    boost::archive::xml_oarchive,
331                                    boost::archive::xml_iarchive>();
332 
333     test_serialization_map_helper< boost::ptr_unordered_map<std::string,Base>,
334                                    boost::archive::text_oarchive,
335                                    boost::archive::text_iarchive>();
336     test_serialization_map_helper< boost::ptr_unordered_multimap<std::string,Base>,
337                                    boost::archive::text_oarchive,
338                                    boost::archive::text_iarchive>();
339 
340     test_serialization_map_helper< boost::ptr_unordered_map<std::string,Base>,
341                                    boost::archive::xml_oarchive,
342                                    boost::archive::xml_iarchive>();
343     test_serialization_map_helper< boost::ptr_unordered_multimap<std::string,Base>,
344                                    boost::archive::xml_oarchive,
345                                    boost::archive::xml_iarchive>();
346 
347 }
348 
349 
350 using boost::unit_test::test_suite;
351 
init_unit_test_suite(int argc,char * argv[])352 test_suite* init_unit_test_suite( int argc, char* argv[] )
353 {
354     test_suite* test = BOOST_TEST_SUITE( "Pointer Container Test Suite" );
355 
356     test->add( BOOST_TEST_CASE( &test_serialization ) );
357 
358     return test;
359 }
360