1 /*  _________________________________________________________________________
2  *
3  *  UTILIB: A utility library for developing portable C++ codes.
4  *  Copyright (c) 2008 Sandia Corporation.
5  *  This software is distributed under the BSD License.
6  *  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7  *  the U.S. Government retains certain rights in this software.
8  *  For more information, see the README file in the top UTILIB directory.
9  *  _________________________________________________________________________
10  */
11 
12 #include <utilib/Serialize.h>
13 
14 #include <utilib/BasicArray.h>
15 #include <utilib/NumArray.h>
16 #include <utilib/MixedIntVars.h>
17 #include <utilib/OStreamTee.h>
18 
19 #include "CommonTestUtils.h"
20 
21 
22 // NB: we use #defines so that if a test fails, the reported line number
23 // is from the original TEST code, and not from the utility function
24 // code (the latter being very difficult to diagnose for large tests
25 // like test_pod_serializers).
26 
27 #define TEST_POD_serial_transform(TYPE, VALUE, LEN)                     \
28    if ( true ) {                                                        \
29       SerialObject::elementList_t so_list;                              \
30       TYPE init = VALUE;                                                \
31                                                                         \
32       /* serialize */                                                   \
33       TS_ASSERT_EQUALS(serial_transform(so_list, init, true), 0);       \
34       TS_ASSERT_EQUALS(so_list.size(), size_t(1));                      \
35                                                                         \
36       /* verify serial POD */                                           \
37       SerialObject &so = so_list.front();                               \
38       TS_ASSERT_EQUALS(Serializer().get_typeinfo(so.type), &typeid(TYPE)); \
39       TS_ASSERT(so.data.is_type(typeid(SerialPOD)));                    \
40       if ( ! POD_text_mode )                                            \
41          TS_ASSERT_EQUALS(so.data.expose<SerialPOD>().size(), LEN);     \
42                                                                         \
43       /* deserialize */                                                 \
44       TYPE final;                                                       \
45       TYPE test = VALUE;                                                \
46       TS_ASSERT_EQUALS(serial_transform(so_list, final, false), 0);     \
47       TS_ASSERT_EQUALS(final, test);                                    \
48    } else static_cast<void>(0)
49 
50 #define TEST_POD_serialize(TYPE, VALUE, LEN)                            \
51    if ( true ) {                                                        \
52       /* serialize */                                                   \
53       TYPE init = VALUE;                                                \
54       SerialObject so = Serialize(init, POD_text_mode);                 \
55                                                                         \
56       /* verify serial POD */                                           \
57       TS_ASSERT_EQUALS(Serializer().get_typeinfo(so.type), &typeid(TYPE)); \
58       TS_ASSERT(so.data.is_type(typeid(SerialPOD)));                    \
59       if ( ! POD_text_mode )                                            \
60          TS_ASSERT_EQUALS(so.data.expose<SerialPOD>().size(), LEN);     \
61                                                                         \
62       /* deserialize */                                                 \
63       TYPE final = Deserialize(so).expose<TYPE >();                     \
64       TYPE test = VALUE;                                                \
65       TS_ASSERT_EQUALS(final, test);                                    \
66    } else static_cast<void>(0)
67 
68 
69 /// Composite test given type, value, and the expected serialized length
70 #define TEST_POD_LEN(TYPE, VALUE, LEN)                  \
71       if ( true ) {                                     \
72          TEST_POD_serial_transform(TYPE, VALUE, LEN);   \
73          TEST_POD_serialize(TYPE, VALUE, LEN);          \
74       } else static_cast<void>(0)
75 
76 #define TEST_POD(TYPE, VALUE) TEST_POD_LEN(TYPE, VALUE, sizeof(TYPE))
77 
78 
79 #define TEST_STL_serial_transform(TYPE, VALUE, ADAPTOR, CMP)            \
80    if ( true ){                                                         \
81       SerialObject::elementList_t so_list;                              \
82       TYPE init = VALUE;                                                \
83                                                                         \
84       /* serialize */                                                   \
85       TS_ASSERT_EQUALS(serial_transform(so_list, init, true), 0);       \
86       TS_ASSERT_EQUALS(so_list.size(), size_t(1));                      \
87                                                                         \
88       /* verify serialized STL */                                       \
89       SerialObject &so = so_list.front();                               \
90       TS_ASSERT_EQUALS(Serializer().get_typeinfo(so.type), &typeid(TYPE)); \
91       TS_ASSERT(so.data.is_type(typeid(SerialObject::elementList_t)));  \
92       const SerialObject::elementList_t &el =                           \
93          so.data.expose<SerialObject::elementList_t>();                 \
94       if ( ADAPTOR )                                                    \
95       {                                                                 \
96          TS_ASSERT_EQUALS(el.size(), size_t(1));                        \
97          TS_ASSERT( el.front().data.is_type                             \
98                     (typeid(SerialObject::elementList_t)) );            \
99          TS_ASSERT_EQUALS( el.front().data.expose                       \
100                            <SerialObject::elementList_t>().size(),      \
101                            VALUE.size() );                              \
102       }                                                                 \
103       else                                                              \
104          TS_ASSERT_EQUALS( el.size(), VALUE.size() );                   \
105                                                                         \
106       /* deserialize */                                                 \
107       TYPE final;                                                       \
108       TS_ASSERT_EQUALS(serial_transform(so_list, final, false), 0);     \
109       CMP(final, VALUE);                                                \
110    } else static_cast<void>(0)
111 
112 #define TEST_STL_serialize(TYPE, VALUE, ADAPTOR, CMP)                   \
113    if ( true ) {                                                        \
114       /* serialize */                                                   \
115       TYPE init = VALUE;                                                \
116       SerialObject so = Serialize(init);                                \
117                                                                         \
118       /* verify serial POD */                                           \
119       TS_ASSERT_EQUALS(Serializer().get_typeinfo(so.type), &typeid(TYPE)); \
120       TS_ASSERT(so.data.is_type(typeid(SerialObject::elementList_t)));  \
121       const SerialObject::elementList_t &el =                           \
122          so.data.expose<SerialObject::elementList_t>();                 \
123       if ( ADAPTOR )                                                    \
124       {                                                                 \
125          TS_ASSERT_EQUALS(el.size(), size_t(1));                        \
126          TS_ASSERT( el.front().data.is_type                             \
127                     (typeid(SerialObject::elementList_t)) );            \
128          TS_ASSERT_EQUALS( el.front().data.expose                       \
129                            <SerialObject::elementList_t>().size(),      \
130                            VALUE.size() );                              \
131       }                                                                 \
132       else                                                              \
133          TS_ASSERT_EQUALS( el.size(), VALUE.size() );                   \
134                                                                         \
135       /* deserialize */                                                 \
136       CMP(Deserialize(so).expose<TYPE >(), VALUE);                      \
137    } else static_cast<void>(0)
138 
139 
140 /// Composite test given type, value
141 #define TEST_STL(TYPE, VALUE, ADAPTOR, CMP)                     \
142    if ( true ) {                                                \
143       TEST_STL_serial_transform(TYPE, VALUE, ADAPTOR, CMP);     \
144       TEST_STL_serialize(TYPE, VALUE, ADAPTOR, CMP);            \
145    } else static_cast<void>(0)
146 
147 #define TEST_STL_driver_1(TYPE, A, B, C)                \
148    if ( true ) {                                        \
149       TYPE val;                                         \
150       TEST_STL(TYPE, val, false, TS_ASSERT_EQUALS);     \
151                                                         \
152       val.insert(val.end(), A);                         \
153       val.insert(val.end(), B);                         \
154       val.insert(val.end(), C);                         \
155       TEST_STL(TYPE, val, false, TS_ASSERT_EQUALS);     \
156    } else static_cast<void>(0)
157 
158 #define TEST_STL_driver_2(TYPE, A, B, C, FCN, ADAPTOR)  \
159    if ( true ) {                                        \
160       TYPE val;                                         \
161       TEST_STL(TYPE, val, ADAPTOR, TS_ASSERT_EQUALS);   \
162                                                         \
163       val.FCN(A);                                       \
164       val.FCN(B);                                       \
165       val.FCN(C);                                       \
166       TEST_STL(TYPE, val, ADAPTOR, TS_ASSERT_EQUALS);   \
167    } else static_cast<void>(0)
168 
169 
170 
171 #define TEST_OBJ_serial_transform(TYPE, VALUE, CMP)                     \
172    if ( true ){                                                         \
173       SerialObject::elementList_t so_list;                              \
174       TYPE init = VALUE;                                                \
175                                                                         \
176       /* serialize */                                                   \
177       TS_ASSERT_EQUALS(serial_transform(so_list, init, true), 0);       \
178       TS_ASSERT_EQUALS(so_list.size(), size_t(1));                      \
179                                                                         \
180       /* verify serialized OBJ */                                       \
181       SerialObject &so = so_list.front();                               \
182       TS_ASSERT_EQUALS(Serializer().get_typeinfo(so.type), &typeid(TYPE)); \
183       TS_ASSERT(so.data.is_type(typeid(SerialObject::elementList_t)));  \
184                                                                         \
185       /* deserialize */                                                 \
186       TYPE final;                                                       \
187       TS_ASSERT_EQUALS(serial_transform(so_list, final, false), 0);     \
188       CMP(final, VALUE);                                                \
189    } else static_cast<void>(0)
190 
191 #define TEST_OBJ_serialize(TYPE, VALUE, CMP)                            \
192    if ( true ) {                                                        \
193       /* serialize */                                                   \
194       TYPE init = VALUE;                                                \
195       SerialObject so = Serialize(init);                                \
196                                                                         \
197       /* verify serial POD */                                           \
198       TS_ASSERT_EQUALS(Serializer().get_typeinfo(so.type), &typeid(TYPE)); \
199       TS_ASSERT(so.data.is_type(typeid(SerialObject::elementList_t)));  \
200                                                                         \
201       /* deserialize */                                                 \
202       CMP(Deserialize(so).expose<TYPE >(), VALUE);                      \
203    } else static_cast<void>(0)
204 
205 
206 /// Composite test given type, value
207 #define TEST_OBJ(TYPE, VALUE)                                   \
208    if ( true ) {                                                \
209       TEST_OBJ_serial_transform(TYPE, VALUE, TS_ASSERT_EQUALS); \
210       TEST_OBJ_serialize(TYPE, VALUE, TS_ASSERT_EQUALS);        \
211    } else static_cast<void>(0)
212 
213 
214 namespace {
215 
216 template<typename T>
PQueue_Equals(std::priority_queue<T> a,std::priority_queue<T> b)217 void PQueue_Equals(std::priority_queue<T> a, std::priority_queue<T> b)
218 {
219    while ( ! a.empty() && ! b.empty() )
220    {
221       TS_ASSERT_EQUALS(a.top(), b.top());
222       a.pop();
223       b.pop();
224    }
225    TS_ASSERT(a.empty());
226    TS_ASSERT(b.empty());
227 }
228 
NullInitializer(utilib::Any & data)229 void NullInitializer(utilib::Any& data)
230 { data.clear(); }
231 
232 class UnknownClass {};
233 
234 class AnotherClass {};
235 
236 } // namespace (local)
237 
238 
239 
240 namespace utilib {
241 namespace unittest { class Test_Serialize; }
242 
243 class utilib::unittest::Test_Serialize : public CxxTest::TestSuite
244 {
245 public:
246 
setUp()247    void setUp()
248    {
249       // As this TestSuite serializes and then deserializes data, it is
250       // important that a serialization failure terminates the test.
251       CxxTest::setAbortTestOnFail(true);
252    }
253 
test_empty_any()254    void test_empty_any()
255    {
256       // This should serialize as 'void'
257       utilib::Any a;
258 
259       /* test 1: serial_transform */
260       {
261          SerialObject::elementList_t so_list;
262          TS_ASSERT_EQUALS(serial_transform(so_list, a, true), 0);
263          TS_ASSERT_EQUALS(so_list.size(), size_t(1));
264 
265          SerialObject &so = so_list.front();
266          TS_ASSERT_EQUALS(so.type, size_t(0));
267          TS_ASSERT(so.data.empty());
268 
269          /* deserialize */
270          utilib::Any b = 1;
271          TS_ASSERT_EQUALS(serial_transform(so_list, b, false), 0);
272          TS_ASSERT(b.empty());
273       }
274 
275       /* test 2: Serialize/Deserialize */
276       {
277          SerialObject so = Serialize(a);
278 
279          // void is the only type that is strictly guaranteed a specific
280          // type number
281          TS_ASSERT_EQUALS(so.type, size_t(0));
282          TS_ASSERT(so.data.empty());
283 
284          TS_ASSERT(Deserialize(so).empty());
285       }
286    }
287 
288 
289    /// Test all POD serializers [with both serial_transform() and
290    /// Serialize() / Deserialize() interfaces]
test_pod_serializers_1()291    void test_pod_serializers_1()
292    {
293       bool POD_text_mode = false;
294 
295       TEST_POD(short, 0);
296       TEST_POD(short, 42);
297       TEST_POD(short, -21);
298 
299       TEST_POD(signed short, 0);
300       TEST_POD(signed short, 42);
301       TEST_POD(signed short, -21);
302 
303       TEST_POD(unsigned short, 0);
304       TEST_POD(unsigned short, 42);
305 
306       TEST_POD(int, 0);
307       TEST_POD(int, 42);
308       TEST_POD(int, -21);
309       TEST_POD(int, INT_MAX);
310       TEST_POD(int, INT_MIN);
311 
312       TEST_POD(signed int, 0);
313       TEST_POD(signed int, 42);
314       TEST_POD(signed int, -21);
315 
316       TEST_POD(unsigned int, 0);
317       TEST_POD(unsigned int, 42);
318 
319       TEST_POD(long, 0);
320       TEST_POD(long, 42);
321       TEST_POD(long, -21);
322       TEST_POD(long, LONG_MAX);
323       TEST_POD(long, LONG_MIN);
324 
325       TEST_POD(signed long, 0);
326       TEST_POD(signed long, 42);
327       TEST_POD(signed long, -21);
328 
329       TEST_POD(unsigned long, 0);
330       TEST_POD(unsigned long, 42);
331    }
332 
test_pod_serializers_2()333    void test_pod_serializers_2()
334    {
335       bool POD_text_mode = false;
336 
337       TEST_POD(float, 0);
338       TEST_POD(float, 3.1415f);
339 
340       TEST_POD(double, 0);
341       TEST_POD(double, 3.1415);
342 
343       TEST_POD(long double, 0);
344       TEST_POD(long double, 3.1415l);
345 
346       TEST_POD(bool, true);
347       TEST_POD(bool, false);
348 
349       TEST_POD(char, 'A');
350       TEST_POD(char, '\n');
351       TEST_POD(char, 127);
352 
353       TEST_POD(signed char, 0);
354       TEST_POD(signed char, 42);
355       TEST_POD(signed char, -21);
356 
357       TEST_POD(unsigned char, 0);
358       TEST_POD(unsigned char, 42);
359 
360       TEST_POD(wchar_t, 'A');
361       TEST_POD(wchar_t, '\n');
362 
363       TEST_POD_LEN(std::string, "", size_t(0));
364       TEST_POD_LEN(std::string, "hello, world", size_t(12));
365    }
366 
367 
368    /// Test all POD text serializers [with both serial_transform() and
369    /// Serialize() / Deserialize() interfaces]
test_pod_text_serializers_1()370    void test_pod_text_serializers_1()
371    {
372       bool POD_text_mode = true;
373 
374       TEST_POD(short, 0);
375       TEST_POD(short, 42);
376       TEST_POD(short, -21);
377 
378       TEST_POD(signed short, 0);
379       TEST_POD(signed short, 42);
380       TEST_POD(signed short, -21);
381 
382       TEST_POD(unsigned short, 0);
383       TEST_POD(unsigned short, 42);
384 
385       TEST_POD(int, 0);
386       TEST_POD(int, 42);
387       TEST_POD(int, -21);
388       TEST_POD(int, INT_MAX);
389       TEST_POD(int, INT_MIN);
390 
391       TEST_POD(signed int, 0);
392       TEST_POD(signed int, 42);
393       TEST_POD(signed int, -21);
394 
395       TEST_POD(unsigned int, 0);
396       TEST_POD(unsigned int, 42);
397 
398       TEST_POD(long, 0);
399       TEST_POD(long, 42);
400       TEST_POD(long, -21);
401       TEST_POD(long, LONG_MAX);
402       TEST_POD(long, LONG_MIN);
403 
404       TEST_POD(signed long, 0);
405       TEST_POD(signed long, 42);
406       TEST_POD(signed long, -21);
407 
408       TEST_POD(unsigned long, 0);
409       TEST_POD(unsigned long, 42);
410    }
411 
test_pod_text_serializers_2()412    void test_pod_text_serializers_2()
413    {
414       bool POD_text_mode = true;
415 
416       TEST_POD(float, 0);
417       TEST_POD(float, 3.1415f);
418 
419       TEST_POD(double, 0);
420       TEST_POD(double, 3.1415);
421 
422       TEST_POD(long double, 0);
423       TEST_POD(long double, 3.1415l);
424 
425       TEST_POD(bool, true);
426       TEST_POD(bool, false);
427 
428       TEST_POD(char, 'A');
429       TEST_POD(char, '\n');
430       TEST_POD(char, 31);
431       TEST_POD(char, 32);
432       TEST_POD(char, 126);
433       TEST_POD(char, 127);
434 
435       TEST_POD(signed char, 0);
436       TEST_POD(signed char, 42);
437       TEST_POD(signed char, -21);
438 
439       TEST_POD(unsigned char, 0);
440       TEST_POD(unsigned char, 42);
441 
442       TEST_POD(wchar_t, 'A');
443       TEST_POD(wchar_t, '\n');
444 
445       TEST_POD(std::string, "");
446       TEST_POD(std::string, "hello, world");
447    }
448 
449    /// Test all STL container serializers [with both serial_transform()
450    /// and Serialize() / Deserialize() interfaces]
test_stl_serializers_1()451    void test_stl_serializers_1()
452    {
453       // basic containers
454       TEST_STL_driver_1(std::vector<int>, 0, 42, 21);
455       TEST_STL_driver_1(std::list<int>, 0, 42, 21);
456 
457       // associative containers
458       TEST_STL_driver_1(std::set<int>, 0, 42, 21);
459       TEST_STL_driver_1(std::multiset<int>, 0, 42, 21);
460       TEST_STL_driver_1(std::multiset<int>, 0, 42, 0);
461 
462       typedef std::map<int, int>  map_t;
463       typedef std::multimap<int, int>  multimap_t;
464       typedef std::pair<const int, int>  p_t;
465       TEST_STL_driver_1( map_t, p_t(0,1), p_t(42, 43), p_t(21,20) );
466       TEST_STL_driver_1( multimap_t, p_t(0,1), p_t(42, 43), p_t(21,20) );
467       TEST_STL_driver_1( multimap_t, p_t(0,1), p_t(0, 43), p_t(0,20) );
468    }
469 
test_stl_serializers_3()470    void test_stl_serializers_3()
471    {
472       // special sequence containers
473       TEST_STL_driver_2(std::deque<int>, 0, 42, 21, push_back, false);
474       TEST_STL_driver_2(std::queue<int>, 0, 42, 21, push, true);
475       TEST_STL_driver_2(std::stack<int>, 0, 42, 21, push, true);
476 
477       // priority_queue doesn't support operator==, so we have to do
478       // this by hand
479       {
480          std::priority_queue<int> val;
481          TEST_STL(std::priority_queue<int>, val, true, PQueue_Equals);
482 
483          val.push(0);
484          val.push(42);
485          val.push(21);
486          TEST_STL(std::priority_queue<int>, val, true, PQueue_Equals);
487       }
488 
489       // test a complex container
490       {
491          typedef std::map<std::pair<int, double>, std::vector<double> >
492             complex_t;
493          complex_t val;
494          TEST_STL(complex_t, val, false, TS_ASSERT_EQUALS);
495          val[std::make_pair(0, 2)];
496          val[std::make_pair(0, 3)].push_back(1);
497          val[std::make_pair(0, 3)].push_back(10);
498          val[std::make_pair(0, 3)].push_back(5);
499          TEST_STL(complex_t, val, false, TS_ASSERT_EQUALS);
500       }
501    }
502 
test_utilib_adt()503    void test_utilib_adt()
504    {
505       utilib::Ereal<float> er = 5;
506       TEST_OBJ(utilib::Ereal<float>, er);
507       er = utilib::Ereal<float>::positive_infinity;
508       TEST_OBJ(utilib::Ereal<float>, er);
509 
510       utilib::BasicArray<double> ba;
511       TEST_OBJ(utilib::BasicArray<double>, ba);
512       ba.push_back(1.1);
513       ba.push_back(2.2);
514       ba.push_back(3.3);
515       TEST_OBJ(utilib::BasicArray<double>, ba);
516 
517       utilib::NumArray<int> na;
518       TEST_OBJ(utilib::NumArray<int>, na);
519       na.push_back(3);
520       na.push_back(5);
521       na.push_back(7);
522       TEST_OBJ(utilib::NumArray<int>, na);
523 
524       utilib::MixedIntVars miv;
525       TEST_OBJ(utilib::MixedIntVars, miv);
526       miv.Binary().resize(3);
527       miv.Binary().set(1);
528       miv.Integer().push_back(3);
529       miv.Integer().push_back(5);
530       miv.Integer().push_back(7);
531       miv.Real().push_back(3.1415);
532       miv.Real().push_back(42);
533       TEST_OBJ(utilib::MixedIntVars, miv);
534    }
535 
536 
test_print()537    void test_print()
538    {
539       std::stringstream ss;
540 
541       /*
542        * A simple POD
543        */
544       int i = 5;
545       Serialize(i, false).print(ss);
546       if ( utilib::Serialization_Manager::Endian == 0xE4 )
547       {
548          TS_ASSERT_EQUALS(ss.str(), "type = int\n   POD: 4: 5 0 0 0\n");
549       }
550       else if ( utilib::Serialization_Manager::Endian == 0x1B )
551       {
552          TS_ASSERT_EQUALS(ss.str(), "type = int\n   POD: 4: 0 0 0 5\n");
553       }
554       else
555          TS_FAIL("Unrecognized endianness");
556 
557       ss.str("");
558       Serialize(i, true).print(ss);
559       TS_ASSERT_EQUALS(ss.str(), "type = int: 5\n");
560 
561       /*
562        * A simple STL container
563        */
564 
565       std::list<int> l;
566       ss.str("");
567       Serialize(l, false).print(ss);
568       TS_ASSERT_EQUALS(ss.str(), "type = std::list<int,*>\n");
569 
570       ss.str("");
571       Serialize(l, true).print(ss);
572       TS_ASSERT_EQUALS(ss.str(), "type = std::list<int,*>\n");
573 
574       l.push_back(5);
575       l.push_back(10);
576 
577       ss.str("");
578       Serialize(l, false).print(ss);
579       if ( utilib::Serialization_Manager::Endian == 0xE4 )
580       {
581          TS_ASSERT_EQUALS(ss.str(), "type = std::list<int,*>\n"
582                           "   type = int\n      POD: 4: 5 0 0 0\n"
583                           "   type = int\n      POD: 4: 10 0 0 0\n");
584       }
585       else if ( utilib::Serialization_Manager::Endian == 0x1B )
586       {
587          TS_ASSERT_EQUALS(ss.str(), "type = std::list<int,*>\n"
588                           "   type = int\n      POD: 4: 0 0 0 5\n"
589                           "   type = int\n      POD: 4: 0 0 0 10\n");
590       }
591       else
592          TS_FAIL("Unrecognized endianness");
593 
594       ss.str("");
595       Serialize(l, true).print(ss);
596       TS_ASSERT_EQUALS( ss.str(), "type = std::list<int,*>\n"
597                         "   type = int: 5\n   type = int: 10\n" );
598 
599       /*
600        * A complex STL container
601        */
602 
603       std::map<std::pair<int,double>, std::string> cdt;
604       ss.str("");
605       Serialize(cdt, false).print(ss);
606       TS_ASSERT_EQUALS(ss.str(), "type = std::map<std::pair<int,double>,"
607                        "std::string,*,*>\n");
608 
609       ss.str("");
610       Serialize(cdt, true).print(ss);
611       TS_ASSERT_EQUALS(ss.str(), "type = std::map<std::pair<int,double>,"
612                        "std::string,*,*>\n");
613 
614       cdt[std::make_pair(1, 5)] = "";
615       cdt[std::make_pair(3, 3.14)] = "hello";
616 
617       ss.str("");
618       Serialize(cdt, true).print(ss);
619       TS_ASSERT_EQUALS
620          (ss.str(),
621           "type = std::map<std::pair<int,double>,std::string,*,*>\n"
622           "   type = std::pair<std::pair<int,double>,std::string>\n"
623           "      type = std::pair<int,double>\n"
624           "         type = int: 1\n"
625           "         type = double: 5\n"
626           "      type = std::string: \"\"\n"
627           "   type = std::pair<std::pair<int,double>,std::string>\n"
628           "      type = std::pair<int,double>\n"
629           "         type = int: 3\n"
630           "         type = double: 3.1400000000000001\n"
631           "      type = std::string: \"hello\"\n");
632 
633       /*
634        * A character
635        */
636       char c = 'A';
637       ss.str("");
638       Serialize(c, false).print(ss);
639       TS_ASSERT_EQUALS(ss.str(), "type = char\n   POD: 1: 65\n");
640 
641       ss.str("");
642       Serialize(c, true).print(ss);
643       TS_ASSERT_EQUALS(ss.str(), "type = char: 'A'\n");
644 
645       c = ' ';
646       ss.str("");
647       Serialize(c, false).print(ss);
648       TS_ASSERT_EQUALS(ss.str(), "type = char\n   POD: 1: 32\n");
649 
650       ss.str("");
651       Serialize(c, true).print(ss);
652       TS_ASSERT_EQUALS(ss.str(), "type = char: ' '\n");
653 
654       c = 31;
655       ss.str("");
656       Serialize(c, false).print(ss);
657       TS_ASSERT_EQUALS(ss.str(), "type = char\n   POD: 1: 31\n");
658 
659       ss.str("");
660       Serialize(c, true).print(ss);
661       TS_ASSERT_EQUALS(ss.str(), "type = char: 31\n");
662 
663       c = '~';
664       ss.str("");
665       Serialize(c, false).print(ss);
666       TS_ASSERT_EQUALS(ss.str(), "type = char\n   POD: 1: 126\n");
667 
668       ss.str("");
669       Serialize(c, true).print(ss);
670       TS_ASSERT_EQUALS(ss.str(), "type = char: '~'\n");
671 
672       c = 127;
673       ss.str("");
674       Serialize(c, false).print(ss);
675       TS_ASSERT_EQUALS(ss.str(), "type = char\n   POD: 1: 127\n");
676 
677       ss.str("");
678       Serialize(c, true).print(ss);
679       TS_ASSERT_EQUALS(ss.str(), "type = char: 127\n");
680 
681       ss.str("");
682       SerialObject so = Serialize(int(1));
683       so.data = utilib::Any();
684       so.print(ss);
685       std::string ref = "type = int\n   UNKNOWN DATA! ("
686          + utilib::demangledName(typeid(void)) + ")\n";
687       TS_ASSERT_EQUALS(ss.str(), ref);
688    }
689 
690 
test_typeRegistry()691    void test_typeRegistry()
692    {
693       // check for simple int
694       size_t int_key = Serializer().get_keyid("int");
695       TS_ASSERT_EQUALS(int_key, Serializer().get_keyid(typeid(int)));
696       TS_ASSERT_EQUALS("int", Serializer().get_username(int_key));
697       TS_ASSERT(Serializer().is_pod(int_key));
698       TS_ASSERT_EQUALS(Serializer().get_pod_length(int_key), (int)sizeof(int));
699       TS_ASSERT_EQUALS(Serializer().get_typeinfo(int_key), &typeid(int));
700 
701       // check for complex type
702       typedef std::map<int,double> cdt_t;
703       // declare & use the variable so it gets registered...
704       cdt_t foo;
705       Serialize(foo);
706 
707       std::string cdt_name = "std::map<int,double,*,*>";
708       size_t cdt_key = Serializer().get_keyid(typeid(cdt_t));
709       TS_ASSERT_EQUALS( cdt_name, Serializer().get_username(cdt_key) );
710       TS_ASSERT_EQUALS(cdt_key, Serializer().get_keyid(cdt_name));
711       TS_ASSERT(! Serializer().is_pod(cdt_key));
712       TS_ASSERT_EQUALS(Serializer().get_pod_length(cdt_key), -1);
713       TS_ASSERT_EQUALS(Serializer().get_typeinfo(cdt_key), &typeid(cdt_t));
714 
715       // check for unknown type
716       typedef UnknownClass u_t;
717       std::string u_name = "UnknownClass";
718       size_t u_key = 1000000;
719       TS_ASSERT_THROWS_ASSERT
720          ( Serializer().get_keyid(typeid(u_t)),
721            utilib::serializer_unknown_type &e,
722            TEST_WHAT(e, "Serialization_Manager::get_keyid(): "
723                      "unknown type_info name, \"") );
724       TS_ASSERT_EQUALS(Serializer().get_username(u_key), "");
725       TS_ASSERT_THROWS_ASSERT
726          ( Serializer().get_keyid(u_name),
727            utilib::serializer_unknown_type &e,
728            TEST_WHAT(e, "Serialization_Manager::get_keyid(): "
729                      "unknown user-defined type name, \"UnknownClass\"") );
730       TS_ASSERT(! Serializer().is_pod(u_key));
731       TS_ASSERT_EQUALS(Serializer().get_pod_length(u_key), -1);
732       TS_ASSERT( ! Serializer().get_typeinfo(u_key) );
733    }
734 
735 
test_listSerializers()736    void test_listSerializers()
737    {
738       utilib::Serialization_Manager sm;
739       std::stringstream ss;
740       sm.list_serializers(ss);
741 
742       // we need to strip out all the mangled names, as those can change
743       // across compilers/platforms.
744       std::string list = ss.str();
745       size_t start;
746       while ( (start  = list.find("[ ")) != std::string::npos )
747          list.erase(start+1, list.find(" ]") - start);
748 
749       TS_ASSERT_EQUALS(list, std::string("Known serializers:\n"
750                                          "   bool             []\n"
751                                          "   char             []\n"
752                                          "   double           []\n"
753                                          "   float            []\n"
754                                          "   int              []\n"
755                                          "   long             []\n"
756                                          "   long double      []\n"
757                                          "   short            []\n"
758                                          "   signed char      []\n"
759                                          "   std::string      []\n"
760                                          "   unsigned char    []\n"
761                                          "   unsigned int     []\n"
762                                          "   unsigned long    []\n"
763                                          "   unsigned short   []\n"
764                                          "   void             []\n"
765                                          "   wchar_t          []\n"));
766    }
767 
768 
test_POD_serializer_errors()769    void test_POD_serializer_errors()
770    {
771       SerialObject::elementList_t so_list;
772       char c = 0;
773       utilib::Any a;
774 
775       /*
776        * int
777        */
778       SerialObject so = Serialize(5);
779 
780       // make sure that the text serializer correctly handles whitespace
781       so.data.expose<SerialPOD>().set(std::string(" 2  "));
782       TS_ASSERT_EQUALS(Deserialize(so).expose<int>(), 2);
783 
784       // change the size of the int
785       so.data.expose<SerialPOD>().set(&c, sizeof(char));
786       TS_ASSERT_THROWS_ASSERT
787          ( Deserialize(so), utilib::serializer_bad_pod_size &e,
788            TEST_WHAT(e, "POD_serializer(): "
789                      "SerialPOD data size does not match destination type") );
790 
791       // change the int to text mode with an invalid string
792       so.data.expose<SerialPOD>().set(std::string("a"));
793       so_list.push_back(so);
794       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
795                        utilib::error::Serialization::BadPODTextConversion);
796       TS_ASSERT_THROWS_ASSERT
797          ( Deserialize(so), utilib::serialization_error &e,
798            TEST_WHAT(e, "Serialization_Manager::Deserialize()"
799                      ": Deserialization failed for '") );
800 
801       so.data.expose<SerialPOD>().set(std::string("1.5"));
802       so_list.push_back(so);
803       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
804                        utilib::error::Serialization::UnconvertedPODText);
805       a.clear();
806       TS_ASSERT_THROWS_ASSERT
807          ( Deserialize(so), utilib::serialization_error &e,
808            TEST_WHAT(e, "Serialization_Manager::Deserialize()"
809                      ": Deserialization failed for '") );
810 
811       /*
812        * float
813        */
814 
815       so = Serialize(3.14f);
816 
817       so.data.expose<SerialPOD>().set(std::string("  2.718  "));
818       TS_ASSERT_EQUALS(Deserialize(so).expose<float>(), 2.718f);
819 
820       so.data.expose<SerialPOD>().set(std::string("a"));
821       so_list.push_back(so);
822       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
823                        utilib::error::Serialization::BadPODTextConversion);
824       TS_ASSERT_THROWS_ASSERT
825          ( Deserialize(so), utilib::serialization_error &e,
826            TEST_WHAT(e, "Serialization_Manager::Deserialize()"
827                      ": Deserialization failed for '") );
828 
829       so.data.expose<SerialPOD>().set(std::string("1.5b"));
830       so_list.push_back(so);
831       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
832                        utilib::error::Serialization::UnconvertedPODText);
833       a.clear();
834       TS_ASSERT_THROWS_ASSERT
835          ( Deserialize(so), utilib::serialization_error &e,
836            TEST_WHAT(e, "Serialization_Manager::Deserialize()"
837                      ": Deserialization failed for '") );
838 
839       /*
840        * double
841        */
842 
843       so = Serialize(3.14);
844 
845       so.data.expose<SerialPOD>().set(std::string("  2.718  "));
846       TS_ASSERT_EQUALS(Deserialize(so).expose<double>(), 2.718);
847 
848       so.data.expose<SerialPOD>().set(std::string("a"));
849       so_list.push_back(so);
850       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
851                        utilib::error::Serialization::BadPODTextConversion);
852       TS_ASSERT_THROWS_ASSERT
853          ( Deserialize(so), utilib::serialization_error &e,
854            TEST_WHAT(e, "Serialization_Manager::Deserialize()"
855                      ": Deserialization failed for '") );
856 
857       so.data.expose<SerialPOD>().set(std::string("1.5b"));
858       so_list.push_back(so);
859       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
860                        utilib::error::Serialization::UnconvertedPODText);
861       a.clear();
862       TS_ASSERT_THROWS_ASSERT
863          ( Deserialize(so), utilib::serialization_error &e,
864            TEST_WHAT(e, "Serialization_Manager::Deserialize()"
865                      ": Deserialization failed for '") );
866 
867       /*
868        * long double
869        */
870 
871       so = Serialize(3.14l);
872 
873       so.data.expose<SerialPOD>().set(std::string("  2.718  "));
874       TS_ASSERT_EQUALS(Deserialize(so).expose<long double>(), 2.718l);
875 
876       so.data.expose<SerialPOD>().set(std::string("a"));
877       so_list.push_back(so);
878       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
879                        utilib::error::Serialization::BadPODTextConversion);
880       TS_ASSERT_THROWS_ASSERT
881          ( Deserialize(so), utilib::serialization_error &e,
882            TEST_WHAT(e, "Serialization_Manager::Deserialize()"
883                      ": Deserialization failed for '") );
884 
885       so.data.expose<SerialPOD>().set(std::string("1.5b"));
886       so_list.push_back(so);
887       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
888                        utilib::error::Serialization::UnconvertedPODText);
889       a.clear();
890       TS_ASSERT_THROWS_ASSERT
891          ( Deserialize(so), utilib::serialization_error &e,
892            TEST_WHAT(e, "Serialization_Manager::Deserialize()"
893                      ": Deserialization failed for '") );
894 
895 
896       /*
897        * std::string
898        */
899       so = Serialize(std::string(""));
900 
901       so.data.expose<SerialPOD>().set(std::string());
902       so_list.push_back(so);
903       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
904                        utilib::error::Serialization::MissingStringQuote);
905       a.clear();
906 
907       so.data.expose<SerialPOD>().set(std::string("A"));
908       so_list.push_back(so);
909       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
910                        utilib::error::Serialization::MissingStringQuote);
911       a.clear();
912 
913       so.data.expose<SerialPOD>().set(std::string("\""));
914       so_list.push_back(so);
915       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
916                        utilib::error::Serialization::MissingStringQuote);
917       a.clear();
918 
919       so.data.expose<SerialPOD>().set(std::string("\"a"));
920       so_list.push_back(so);
921       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
922                        utilib::error::Serialization::MissingStringQuote);
923       a.clear();
924 
925       /*
926        * char
927        */
928 
929       so = Serialize('a');
930 
931       so.data.expose<SerialPOD>().set(std::string());
932       so_list.push_back(so);
933       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
934                        utilib::error::Serialization::BadPODData);
935       a.clear();
936 
937       so.data.expose<SerialPOD>().set(std::string("'A"));
938       so_list.push_back(so);
939       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
940                        utilib::error::Serialization::BadPODData);
941       a.clear();
942 
943       so.data.expose<SerialPOD>().set(std::string("'Ab"));
944       so_list.push_back(so);
945       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
946                        utilib::error::Serialization::BadPODData);
947       a.clear();
948 
949       so.data.expose<SerialPOD>().set(std::string("257"));
950       so_list.push_back(so);
951       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
952                        utilib::error::Serialization::BadPODTextConversion);
953       a.clear();
954 
955       so.data.expose<SerialPOD>().set(std::string("\"a\""));
956       so_list.push_back(so);
957       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
958                        utilib::error::Serialization::BadPODTextConversion);
959       a.clear();
960 
961       so.data.expose<SerialPOD>().set(std::string("32a"));
962       so_list.push_back(so);
963       TS_ASSERT_EQUALS(serial_transform(so_list, a, false),
964                        utilib::error::Serialization::UnconvertedPODText);
965       a.clear();
966    }
967 
test_serialization_errors()968    void test_serialization_errors()
969    {
970       // This is going to work with a non-global serializer, so we will
971       // bypass the normal Serialize(), Deserialize(), and
972       // serial_transform functions...
973 
974       utilib::Serialization_Manager sm;
975       SerialObject::elementList_t so_list;
976 
977       // Attempt to serialize an unregistered class
978       UnknownClass uc;
979       utilib::AnyFixedRef data = uc;
980       TS_ASSERT_THROWS_ASSERT
981          ( sm.transform_impl(data.type(), so_list, data, true),
982            utilib::serializer_unknown_type &e,
983            TEST_WHAT(e, "Serialization_Manager::transform_impl(): "
984                      "cannot serialize unknown type '") );
985 
986       // Attempt to deserialize an empty list
987       TS_ASSERT_THROWS_ASSERT
988          ( sm.transform_impl(data.type(), so_list, data, false),
989            utilib::serialization_error &e,
990            TEST_WHAT(e, "Serialization_Manager::transform_impl(): "
991                      "SerialObject missing required element.") );
992 
993 
994       // Register a completely bogus serialization
995       sm.register_serializer<UnknownClass>( "MyClass", NULL, NULL, -1, NULL );
996 
997       // Still cannot serialize
998       TS_ASSERT_THROWS_ASSERT
999          ( sm.transform_impl(data.type(), so_list, data, true),
1000            utilib::serialization_error &e,
1001            TEST_WHAT(e, "Serialization_Manager::transform_impl(): "
1002                      "NULL serialization function for type ") );
1003       // ...nor deserialize
1004       TS_ASSERT_THROWS_ASSERT
1005          ( sm.transform_impl(data.type(), so_list, data, false),
1006            utilib::serialization_error &e,
1007            TEST_WHAT(e, "Serialization_Manager::transform_impl(): "
1008                      "NULL initialization function for id ") );
1009 
1010       // try to re-register with a valid initializer...
1011       utilib::OStreamTee tee(std::cerr);
1012       std::stringstream ref;
1013       ref << "WARNING: Serialization_Manager::register_serializer():  "
1014          "discarding duplicate registration for '" <<
1015          utilib::mangledName(typeid(UnknownClass)) << "'" << std::endl;
1016       TS_ASSERT_EQUALS( sm.register_serializer<UnknownClass>
1017                         ( "MyClass", NULL, &NullInitializer ),
1018                         utilib::error::Serialization::DuplicateRegistration );
1019       TS_ASSERT_EQUALS(tee.out.str(), ref.str())
1020 
1021       // OK, how about an invalid initializer?
1022       sm = utilib::Serialization_Manager();
1023       sm.register_serializer<UnknownClass>
1024          ( "MyClass", NULL, &NullInitializer );
1025 
1026       // ...still can't deserialize
1027       tee.out.str("");
1028       ref.str("");
1029       ref << "WARNING: Serialization_Manager::transform_impl(): initialization function for " <<
1030          utilib::mangledName(typeid(UnknownClass)) << " resulted in an empty Any." << std::endl << "         This will likely cause random segmentation faults." << std::endl;
1031       TS_ASSERT_THROWS_ASSERT
1032          ( sm.transform_impl(data.type(), so_list, data, false),
1033            utilib::serialization_error &e,
1034            TEST_WHAT(e, "Serialization_Manager::transform_impl(): "
1035                      "NULL deserialization function for id ") );
1036       TS_ASSERT_EQUALS(tee.out.str(), ref.str())
1037 
1038       // OK, how about a reasonable initializer?
1039       sm = utilib::Serialization_Manager();
1040       sm.register_serializer<UnknownClass>
1041          ( "MyClass", NULL,
1042            &utilib::Serialization_Manager::DefaultInitializer<UnknownClass> );
1043 
1044       // ...still can't deserialize
1045       TS_ASSERT_THROWS_ASSERT
1046          ( sm.transform_impl(data.type(), so_list, data, false),
1047            utilib::serialization_error &e,
1048            TEST_WHAT(e, "Serialization_Manager::transform_impl(): "
1049                      "NULL deserialization function for id ") );
1050 
1051       // what about conflicting usernames?
1052       sm.register_serializer<AnotherClass>
1053          ( "MyClass", NULL,
1054            &utilib::Serialization_Manager::DefaultInitializer<UnknownClass> );
1055 
1056       tee.out.str("");
1057       ref.str("");
1058       ref << "WARNING: Serialization_Manager::resolve_user_name(): "
1059           << std::endl << "     Multiple mangled type names map to the same "
1060          "user-defined name.  It is" << std::endl << "     likely that you "
1061          "forgot to register a name or a serialization function" << std::endl
1062           << "     for a template argument.  If you attempt to serialize "
1063          "either type," << std::endl << "     you will get an exception."
1064           << std::endl << "  User name: MyClass" << std::endl << "  Mangled: "
1065           << utilib::mangledName(typeid(UnknownClass)) << std::endl <<
1066          "           "
1067           << utilib::mangledName(typeid(AnotherClass)) << std::endl;
1068 
1069       TS_ASSERT_THROWS_ASSERT
1070          ( sm.get_keyid("MyClass"), utilib::serializer_unknown_type &e,
1071            TEST_WHAT(e, "Serialization_Manager::get_keyid(): "
1072                      "user-defined type name, \"MyClass\" "
1073                      "maps to multiple types") );
1074       TS_ASSERT_EQUALS(tee.out.str(), ref.str())
1075 
1076       TS_ASSERT_THROWS_ASSERT
1077          ( sm.transform_impl(data.type(), so_list, data, true),
1078            utilib::serialization_error &e,
1079            TEST_WHAT(e, "Serialization_Manager::transform_impl(): attempt "
1080                      "to serialize an object with a nonunique username."));
1081 
1082       TS_ASSERT_THROWS_ASSERT
1083          ( sm.transform_impl(data.type(), so_list, data, false),
1084            utilib::serialization_error &e,
1085            TEST_WHAT(e, "Serialization_Manager::transform_impl(): attempt "
1086                      "to deserialize an object with a nonunique username."));
1087 
1088       // create an invalid type id
1089       so_list.front().type+=2;
1090       TS_ASSERT_THROWS_ASSERT
1091          ( sm.transform_impl(data.type(), so_list, data, false),
1092            utilib::serialization_error &e,
1093            TEST_WHAT(e, "Serialization_Manager::transform_impl(): "
1094                      "SerialObject contains unknown type id.") );
1095    }
1096 };
1097 
1098 } // namespace utilib
1099