better serialization, but test does not work actually
This commit is contained in:
		
							
								
								
									
										92
									
								
								doc/examples/inherit_serialization.cxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								doc/examples/inherit_serialization.cxx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| /*! @file | ||||
|  | ||||
|     @id $Id$ | ||||
| */ | ||||
| //       1         2         3         4         5         6         7         8 | ||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||
|  | ||||
| // g++ -I../../src ../../src/xml.cxx serialization.cxx | ||||
|  | ||||
| #include <xml-cxx/xml.hxx> | ||||
| #include <iostream> | ||||
| #include <sstream> | ||||
|  | ||||
| class B: public xml::Serialize { | ||||
|   public: | ||||
|     int a; | ||||
|     std::string txt; | ||||
|   protected: | ||||
|     void initXmlMembers() { | ||||
|       className("b"); | ||||
|       persist(a, "a"); | ||||
|       persist(txt, "txt"); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| class B: public xml::Serialize { | ||||
|   public: | ||||
|     int a; | ||||
|     std::string txt; | ||||
|   protected: | ||||
|     void initXmlMembers() { | ||||
|       className("b"); | ||||
|       persist(a, "a"); | ||||
|       persist(txt, "txt"); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| //! Class with external xml::Serialize | ||||
| class C { | ||||
|   public: | ||||
|     int a; | ||||
|     std::string txt; | ||||
| }; | ||||
|  | ||||
| int main(int, char**) { | ||||
|   { // Serialization as a member | ||||
|     std::stringstream ss("<a>\n" | ||||
|                          "\t<a>1234</a>\n" | ||||
|                          "\t<txt>Dies ist ein Serialisierungs-Test</txt>\n" | ||||
|                          "</a>"); | ||||
|     A a; | ||||
|     a._ser.loadXml(ss); | ||||
|     if (a.a==1234) a.a=4321; | ||||
|     a._ser.saveXml(std::cout)<<std::endl; | ||||
|   } { // Inherited Serialization | ||||
|     std::stringstream ss("<b>\n" | ||||
|                          "\t<a>1234</a>\n" | ||||
|                          "\t<txt>Dies ist ein Serialisierungs-Test</txt>\n" | ||||
|                          "</b>"); | ||||
|     B b; | ||||
|     b.loadXml(ss); | ||||
|     if (b.a==1234) b.a=4321; | ||||
|     b.saveXml(std::cout)<<std::endl; | ||||
|   } { // External xml::Serialize: "ser" must live in no longer than "c"! | ||||
|     std::stringstream ss("<c>\n" | ||||
|                          "\t<a>1234</a>\n" | ||||
|                          "\t<txt>Dies ist ein Serialisierungs-Test</txt>\n" | ||||
|                          "</c>"); | ||||
|     C c; | ||||
|     xml::Serialize ser(xml::Serialize("c") | ||||
|                        .persist(c.a, "a") | ||||
|                        .persist(c.txt, "txt")); | ||||
|     ser.loadXml(ss); | ||||
|     if (c.a==1234) c.a=4321; | ||||
|     ser.saveXml(std::cout)<<std::endl; | ||||
|   } { // Use xml::Serialize to store anything, e.g. local variables | ||||
|       // Important: "ser" must live in no longer than the variables! | ||||
|     std::stringstream ss("<d>\n" | ||||
|                          "\t<a>1234</a>\n" | ||||
|                          "\t<txt>Dies ist ein Serialisierungs-Test</txt>\n" | ||||
|                          "</d>"); | ||||
|     int a; | ||||
|     std::string txt; | ||||
|     xml::Serialize ser(xml::Serialize("d") | ||||
|                        .persist(a, "a") | ||||
|                        .persist(txt, "txt")); | ||||
|     ser.loadXml(ss); | ||||
|     if (a==1234) a=4321; | ||||
|     ser.saveXml(std::cout)<<std::endl; | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
| @@ -5,46 +5,89 @@ | ||||
| //       1         2         3         4         5         6         7         8 | ||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||
|  | ||||
| // g++ -I../../src ../../src/xml.cxx node_macros.cxx | ||||
| // g++ -I../../src ../../src/xml.cxx serialization.cxx | ||||
|  | ||||
| #include <xml-cxx/xml.hxx> | ||||
| #include <iostream> | ||||
| #include <sstream> | ||||
| /* | ||||
| template<class STREAM> class Stream: public STREAM { | ||||
|   public: | ||||
|     virtual ~Stream() {} | ||||
|     template<typename T> virtual Stream& operator%(T& o); | ||||
| }; | ||||
|  | ||||
| template<class STREAM> class IStream: public Stream<STREAM> { | ||||
|   public: | ||||
|     virtual template<typename T> IStream& operator%(T& o) { | ||||
|       operator>>(o); | ||||
|       return *this; | ||||
|     } | ||||
| }; | ||||
|  | ||||
| template<class STREAM> class OStream: public Stream<STREAM> { | ||||
|   public: | ||||
|     virtual template<typename T> OStream& operator%(T& o) { | ||||
|       operator<<(o); | ||||
|       return *this; | ||||
|     } | ||||
| }; | ||||
|     */ | ||||
|  | ||||
| template<class STREAM, typename TYPE> | ||||
|     STREAM& operator%(STREAM& s, TYPE& o); | ||||
| template<class STREAM, typename TYPE> | ||||
|     STREAM& operator%(STREAM& s, TYPE& o); | ||||
|  | ||||
| //! Class with built in xml::Serialize as member, no inheritance | ||||
| class A { | ||||
|   public: | ||||
|     A(): _ser("a") { | ||||
|       _ser.persist(a, "a"); | ||||
|       _ser.persist(txt, "txt"); | ||||
|     } | ||||
|     int a; | ||||
|     std::string txt; | ||||
|     xml::Serialize _ser; | ||||
| }; | ||||
|  | ||||
| //! Class that inherits xml::Serialize | ||||
| class B: public xml::Serialize { | ||||
|   public: | ||||
|     int a; | ||||
|     std::string txt; | ||||
|   protected: | ||||
|     void initXmlMembers() { | ||||
|       className("b"); | ||||
|       persist(a, "a"); | ||||
|       persist(txt, "txt"); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| //! Class with external xml::Serialize | ||||
| class C { | ||||
|   public: | ||||
|     int a; | ||||
|     std::string txt; | ||||
| }; | ||||
|  | ||||
| int main(int, char**) { | ||||
|   { // Serialization as a member | ||||
|     std::stringstream ss("<a>\n" | ||||
|                          "\t<a>1234</a>\n" | ||||
|                          "\t<txt>Dies ist ein Serialisierungs-Test</txt>\n" | ||||
|                          "</a>"); | ||||
|     A a; | ||||
|     a._ser.loadXml(ss); | ||||
|     if (a.a==1234) a.a=4321; | ||||
|     a._ser.saveXml(std::cout)<<std::endl; | ||||
|   } { // Inherited Serialization | ||||
|     std::stringstream ss("<b>\n" | ||||
|                          "\t<a>1234</a>\n" | ||||
|                          "\t<txt>Dies ist ein Serialisierungs-Test</txt>\n" | ||||
|                          "</b>"); | ||||
|     B b; | ||||
|     b.loadXml(ss); | ||||
|     if (b.a==1234) b.a=4321; | ||||
|     b.saveXml(std::cout)<<std::endl; | ||||
|   } { // External xml::Serialize: "ser" must live in no longer than "c"! | ||||
|     std::stringstream ss("<c>\n" | ||||
|                          "\t<a>1234</a>\n" | ||||
|                          "\t<txt>Dies ist ein Serialisierungs-Test</txt>\n" | ||||
|                          "</c>"); | ||||
|     C c; | ||||
|     xml::Serialize ser(xml::Serialize("c") | ||||
|                        .persist(c.a, "a") | ||||
|                        .persist(c.txt, "txt")); | ||||
|     ser.loadXml(ss); | ||||
|     if (c.a==1234) c.a=4321; | ||||
|     ser.saveXml(std::cout)<<std::endl; | ||||
|   } { // Use xml::Serialize to store anything, e.g. local variables | ||||
|       // Important: "ser" must live in no longer than the variables! | ||||
|     std::stringstream ss("<d>\n" | ||||
|                          "\t<a>1234</a>\n" | ||||
|                          "\t<txt>Dies ist ein Serialisierungs-Test</txt>\n" | ||||
|                          "</d>"); | ||||
|     int a; | ||||
|     std::string txt; | ||||
|     xml::Serialize ser(xml::Serialize("d") | ||||
|                        .persist(a, "a") | ||||
|                        .persist(txt, "txt")); | ||||
|     ser.loadXml(ss); | ||||
|     if (a==1234) a=4321; | ||||
|     ser.saveXml(std::cout)<<std::endl; | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
|   | ||||
| @@ -14,6 +14,8 @@ | ||||
| #include <vector> | ||||
| #include <map> | ||||
| #include <memory> | ||||
| #include <typeinfo> | ||||
| #include <stdexcept> | ||||
|  | ||||
| /*! @mainpage | ||||
|  | ||||
| @@ -82,125 +84,6 @@ | ||||
|  | ||||
|     @example address.cxx */ | ||||
|  | ||||
| /*! @defgroup serialization Class Serialization | ||||
|  | ||||
|     @section serIntro Introduction | ||||
|  | ||||
|     Boost library (http://boost.org) offers a serialization framework, | ||||
|     which is able to serialize even complex class structures, you only | ||||
|     need to overwrite one or two serialization macros. The | ||||
|     disadvantages are that a lot of macros are needed and it becomes | ||||
|     quite complex as soon as you need inheritance. Also the generated | ||||
|     XML is not very enhanced, especially for Lists and | ||||
|     optional. Editing the boost serialization code by hand is a pain. | ||||
|  | ||||
|     Classes could also be serialized using gSOAP (http://gsoap.sf.net) | ||||
|     which is designed for the SOA-Protocol. This serialization is much | ||||
|     more flexible, but it requires a pseudo C++ declaration and a C++ | ||||
|     parser/generator. Also it has very bad memory management, since it | ||||
|     is plain C internally. | ||||
|  | ||||
|     Our requirements are: | ||||
|       - No precompiler, plain C++. | ||||
|       - Automatic memory management. | ||||
|       - Nice looking XML code that is easy to edit manually. | ||||
|       - Good error messages (exception) in case of bad XML files. | ||||
|       - As few ugly overflow as possible. | ||||
|  | ||||
|     @section serActual Actual Status | ||||
|  | ||||
|     Instead of: | ||||
|  | ||||
|     @code | ||||
|     class A { | ||||
|       protected: | ||||
|         int _anInteger; | ||||
|         bool _aBool; | ||||
|         double _aDouble; | ||||
|         std::string _aString; | ||||
|         std::string _anotherString; | ||||
|         unsigned long _aLong; | ||||
|     }; | ||||
|     @endcode | ||||
|  | ||||
|     You have to write: | ||||
|  | ||||
|     @code | ||||
|     class A { | ||||
|       protected: | ||||
|         XML_DECLARE_MEMBER(int, anInteger); | ||||
|         XML_DECLARE_MEMBER(bool, aBool); | ||||
|         XML_DECLARE_MEMBER(double, aDouble); | ||||
|         XML_DECLARE_MEMBER(std::string, aString); | ||||
|         XML_DECLARE_MEMBER(std::string, anotherString); | ||||
|         XML_DECLARE_MEMBER(unsigned long, aLong); | ||||
|       private: | ||||
|         XML_INIT_BEGIN(A); | ||||
|         XML_INIT_MEMBER(A, anInteger); | ||||
|         XML_INIT_MEMBER(A, aBool); | ||||
|         XML_INIT_MEMBER(A, aDouble); | ||||
|         XML_INIT_MEMBER(A, aString); | ||||
|         XML_INIT_MEMBER(A, anotherString); | ||||
|         XML_INIT_MEMBER(A, aLong); | ||||
|         XML_INIT_END; | ||||
|     }; | ||||
|     @endcode | ||||
|  | ||||
|     You get: | ||||
|      - All the members (with @c _ as member prefix) | ||||
|      - method <code>void saveXml(std::ostream&) const</code> | ||||
|      - method <code>void loadXml(std::istream&)</code> | ||||
|  | ||||
|     @todo Up to now: Only base types plus std::string are supported, | ||||
|           no list, no inheritance is possible and no optional members. */ | ||||
| //@{ | ||||
| #define XML_DECLARE_MEMBER(TYPE, MEMBER) \ | ||||
|   void MEMBER##FromNode(xml::Node& node) { \ | ||||
|     _##MEMBER = (TYPE)dynamic_cast<xml::String&>(node[#MEMBER]);        \ | ||||
|   } \ | ||||
|   void MEMBER##ToNode(xml::Node& node) const { \ | ||||
|     std::stringstream ss; \ | ||||
|     ss<<_##MEMBER; \ | ||||
|     node[#MEMBER].text(ss.str());               \ | ||||
|   } \ | ||||
|   TYPE _##MEMBER | ||||
|  | ||||
| #define XML_INIT_BEGIN(CLASS_NAME) \ | ||||
|     const CLASS_NAME& saveXml(std::ostream& os) const { \ | ||||
|       const_cast<CLASS_NAME*>(this)->initXmlMembers(); \ | ||||
|       xml::Node node(*_xmlFactory); \ | ||||
|       for (std::vector<XmlSaveMethod>::const_iterator \ | ||||
|              it(_saveXmlMemberList.begin()); \ | ||||
|            it!=_saveXmlMemberList.end(); ++it) \ | ||||
|         (this->*(*it))(node);                  \ | ||||
|       os<<node; \ | ||||
|     } \ | ||||
|     CLASS_NAME& loadXml(std::istream& is) { \ | ||||
|       initXmlMembers(); \ | ||||
|       std::auto_ptr<xml::Node> node(_xmlFactory.read(is)); \ | ||||
|       for (std::vector<XmlLoadMethod>::const_iterator \ | ||||
|              it(_loadXmlMemberList.begin()); \ | ||||
|            it!=_loadXmlMemberList.end(); ++it) \ | ||||
|         (this->*(*it))(*node);                  \ | ||||
|     } \ | ||||
|   private: \ | ||||
|     typedef void(CLASS_NAME::*XmlSaveMethod)(xml::Node&) const; \ | ||||
|     typedef void(CLASS_NAME::*XmlLoadMethod)(xml::Node&); \ | ||||
|     std::vector<XmlSaveMethod> _saveXmlMemberList; \ | ||||
|     std::vector<XmlLoadMethod> _loadXmlMemberList; \ | ||||
|     void initXmlMembers() { \ | ||||
|       if (_xmlFactory) return; \ | ||||
|       xml::Node schema(#CLASS_NAME) | ||||
| #define XML_INIT_MEMBER(CLASS_NAME, MEMBER)        \ | ||||
|     schema<<xml::String(#MEMBER).limits(1,1);             \ | ||||
|     _saveXmlMemberList.push_back(&CLASS_NAME::MEMBER##ToNode);     \ | ||||
|     _loadXmlMemberList.push_back(&CLASS_NAME::MEMBER##FromNode) | ||||
| #define XML_INIT_END \ | ||||
|     _xmlFactory = schema;\ | ||||
|   } \ | ||||
|   xml::Factory _xmlFactory | ||||
| //@} | ||||
|  | ||||
| /*! @defgroup xmlConst XML Constant Declarations | ||||
|  | ||||
|     There are macros to help you with declaring constants. Chose a C++ | ||||
| @@ -777,7 +660,6 @@ namespace xml { | ||||
|                 wrong_node_number); | ||||
|     private: | ||||
|       friend class stream_error; | ||||
|       Factory(const Factory&); // not implemented | ||||
|       bool ws(char c) throw(); | ||||
|       std::auto_ptr<Node> read(std::istream& is, const Node& position) | ||||
|           throw(wrong_end_tag, wrong_start_tag, tag_expected, type_mismatch, | ||||
| @@ -801,5 +683,126 @@ namespace xml { | ||||
|       long _open; | ||||
|   }; | ||||
|  | ||||
|   /*! @defgroup serialization Class Serialization | ||||
|  | ||||
|       @section serIntro Introduction | ||||
|  | ||||
|       Boost library (http://boost.org) offers a serialization framework, | ||||
|       which is able to serialize even complex class structures, you only | ||||
|       need to overwrite one or two serialization macros. The | ||||
|       disadvantages are that a lot of macros are needed and it becomes | ||||
|       quite complex as soon as you need inheritance. Also the generated | ||||
|       XML is not very enhanced, especially for Lists and | ||||
|       optional. Editing the boost serialization code by hand is a pain. | ||||
|  | ||||
|       Classes could also be serialized using gSOAP (http://gsoap.sf.net) | ||||
|       which is designed for the SOA-Protocol. This serialization is much | ||||
|       more flexible, but it requires a pseudo C++ declaration and a C++ | ||||
|       parser/generator. Also it has very bad memory management, since it | ||||
|       is plain C internally. | ||||
|  | ||||
|       Our requirements are: | ||||
|       - No precompiler, plain C++. | ||||
|       - Automatic memory management. | ||||
|       - Nice looking XML code that is easy to edit manually. | ||||
|       - Good error messages (exception) in case of bad XML files. | ||||
|       - As few ugly overflow as possible. | ||||
|  | ||||
|       @section serActual Actual Status | ||||
|  | ||||
|       Instead of: | ||||
|  | ||||
|       @code | ||||
|       class A { | ||||
|       protected: | ||||
|       int _anInteger; | ||||
|       bool _aBool; | ||||
|       double _aDouble; | ||||
|       std::string _aString; | ||||
|       std::string _anotherString; | ||||
|       unsigned long _aLong; | ||||
|       }; | ||||
|       @endcode | ||||
|  | ||||
|       You have to write: | ||||
|  | ||||
|       @code | ||||
|       class A { | ||||
|       protected: | ||||
|       XML_DECLARE_MEMBER(int, anInteger); | ||||
|       XML_DECLARE_MEMBER(bool, aBool); | ||||
|       XML_DECLARE_MEMBER(double, aDouble); | ||||
|       XML_DECLARE_MEMBER(std::string, aString); | ||||
|       XML_DECLARE_MEMBER(std::string, anotherString); | ||||
|       XML_DECLARE_MEMBER(unsigned long, aLong); | ||||
|       private: | ||||
|       XML_INIT_BEGIN(A); | ||||
|       XML_INIT_MEMBER(A, anInteger); | ||||
|       XML_INIT_MEMBER(A, aBool); | ||||
|       XML_INIT_MEMBER(A, aDouble); | ||||
|       XML_INIT_MEMBER(A, aString); | ||||
|       XML_INIT_MEMBER(A, anotherString); | ||||
|       XML_INIT_MEMBER(A, aLong); | ||||
|       XML_INIT_END; | ||||
|       }; | ||||
|       @endcode | ||||
|  | ||||
|       You get: | ||||
|       - All the members (with @c _ as member prefix) | ||||
|       - method <code>void saveXml(std::ostream&) const</code> | ||||
|       - method <code>void loadXml(std::istream&)</code> | ||||
|  | ||||
|       @todo Up to now: Only base types plus std::string are supported, | ||||
|       no list, no inheritance is possible and no optional members. | ||||
|  | ||||
|       @example serialization.cxx */ | ||||
|   //@{ | ||||
|  | ||||
|   class Serialize { | ||||
|     public: | ||||
|       //! You must call Serialize::className() if you use this constructor! | ||||
|       Serialize() throw(); | ||||
|       Serialize(const std::string& className) throw(); | ||||
|       virtual ~Serialize(); | ||||
|       void className(const std::string& name) throw(); | ||||
|       template<typename TYPE> | ||||
|           Serialize& persist(TYPE& member, const std::string& name) { | ||||
|         mapName<TYPE>()[name] = &member; | ||||
|         mapMember<TYPE>()[&member] = name; | ||||
|         _xmlNames[name] = &typeid(TYPE); | ||||
|         xml::Node schema(*_xmlFactory); | ||||
|         schema<<xml::String(name).limits(1,1); | ||||
|         _xmlFactory = schema; | ||||
|         return *this; | ||||
|       } | ||||
|       std::ostream& saveXml(std::ostream& os) const throw(); | ||||
|       std::istream& loadXml(std::istream& is); | ||||
|     protected: | ||||
|       virtual void initXmlMembers(); | ||||
|     private: | ||||
|       template<typename TYPE> std::map<std::string, TYPE*>& mapName() const { | ||||
|         static std::map<std::string, TYPE*> MAP; | ||||
|         return MAP; | ||||
|       } | ||||
|       template<typename TYPE> std::map<TYPE*, std::string>& mapMember() const { | ||||
|         static std::map<TYPE*, std::string> MAP; | ||||
|         return MAP; | ||||
|       } | ||||
|       template<typename TYPE> void fromNode(TYPE* member, xml::Node& node) { | ||||
|         *member = | ||||
|           (TYPE)dynamic_cast<xml::String&>(node[mapMember<TYPE>()[member]]); | ||||
|       } | ||||
|       template<typename TYPE> void toNode(TYPE* member, xml::Node& node) const { | ||||
|         std::stringstream ss; | ||||
|         ss<<*member; | ||||
|         node[mapMember<TYPE>()[member]].text(ss.str()); | ||||
|       } | ||||
|       std::map<std::string, const std::type_info*> _xmlNames; | ||||
|       xml::Factory _xmlFactory; | ||||
|   }; | ||||
|  | ||||
|   //@} | ||||
|  | ||||
| } | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										77
									
								
								src/xml.cxx
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								src/xml.cxx
									
									
									
									
									
								
							| @@ -260,6 +260,7 @@ namespace xml { | ||||
|       same parent as the source of the copy. | ||||
|       @see xml::Node::clone() for more information on the parenting. */ | ||||
|   Node& Node::operator=(const Node& o) throw() { | ||||
|     clear(); | ||||
|     _attributes=o._attributes; | ||||
|     _name = o.name(); | ||||
|     _min = o._min; | ||||
| @@ -1006,4 +1007,80 @@ namespace xml { | ||||
|     return tag; | ||||
|   } | ||||
|  | ||||
|   //============================================================== Serialization | ||||
|  | ||||
|   //---------------------------------------------------------------------------- | ||||
|   Serialize::Serialize() throw() {} | ||||
|   Serialize::Serialize(const std::string& className) throw(): | ||||
|       _xmlFactory(xml::Node(xml::String(className).limits(1,1))) { | ||||
|   } | ||||
|   Serialize::~Serialize() {}; | ||||
|   void Serialize::className(const std::string& name) throw() { | ||||
|     _xmlFactory=xml::Node(xml::String(name).limits(1,1)); | ||||
|   } | ||||
|   std::ostream& Serialize::saveXml(std::ostream& os) const throw() { | ||||
|     if (!_xmlFactory) const_cast<Serialize*>(this)->initXmlMembers(); | ||||
|     xml::Node node(*_xmlFactory); | ||||
|     for (std::map<std::string, const std::type_info*>::const_iterator | ||||
|            it(_xmlNames.begin()); | ||||
|          it!=_xmlNames.end(); ++it) { | ||||
| #define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE)        \ | ||||
|       if (*it->second==typeid(TYPE))                \ | ||||
|         toNode(mapName<TYPE>()[it->first], node);   \ | ||||
|       else | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(std::string) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(float) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(double) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(bool) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(char) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed char) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned char) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(short) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed short) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned short) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(int) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed int) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned int) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(long) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed long) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned long) | ||||
|       throw std::runtime_error(it->second->name()); | ||||
| #undef QWERTZ_CHECK_TYPE_ZTREWQ___XXX | ||||
|     }       | ||||
|     os<<node; | ||||
|     return os; | ||||
|   } | ||||
|   std::istream& Serialize::loadXml(std::istream& is) { | ||||
|     if (!_xmlFactory) initXmlMembers(); | ||||
|     std::auto_ptr<xml::Node> node(_xmlFactory.read(is)); | ||||
|     for (std::map<std::string, const std::type_info*>::const_iterator | ||||
|            it(_xmlNames.begin()); | ||||
|          it!=_xmlNames.end(); ++it) { | ||||
| #define QWERTZ_CHECK_TYPE_ZTREWQ___XXX(TYPE)           \ | ||||
|       if (*it->second==typeid(TYPE))                   \ | ||||
|           fromNode(mapName<TYPE>()[it->first], *node); \ | ||||
|       else | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(std::string) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(float) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(double) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(bool) | ||||
|       //QWERTZ_CHECK_TYPE_ZTREWQ___XXX(char) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed char) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned char) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(short) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed short) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned short) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(int) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed int) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned int) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(long) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(signed long) | ||||
|       QWERTZ_CHECK_TYPE_ZTREWQ___XXX(unsigned long) | ||||
|       throw std::runtime_error(it->second->name()); | ||||
| #undef QWERTZ_CHECK_TYPE_ZTREWQ___XXX | ||||
|     } | ||||
|     return is; | ||||
|   } | ||||
|   void Serialize::initXmlMembers() {} | ||||
|  | ||||
| } | ||||
|   | ||||
							
								
								
									
										109
									
								
								test/serialization_test.cxx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								test/serialization_test.cxx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,109 @@ | ||||
| /*! @file | ||||
|  | ||||
|     @id $Id$ | ||||
| */ | ||||
| //       1         2         3         4         5         6         7         8 | ||||
| // 45678901234567890123456789012345678901234567890123456789012345678901234567890 | ||||
|  | ||||
| #include <xml-cxx/xml.hxx> | ||||
| #include <cppunit/TestFixture.h> | ||||
| #include <cppunit/ui/text/TestRunner.h> | ||||
| #include <cppunit/extensions/HelperMacros.h> | ||||
| #include <cppunit/extensions/TestFactoryRegistry.h> | ||||
|  | ||||
| class A: public xml::Serialization { | ||||
|   public: | ||||
|     int _anInteger; | ||||
|     bool _aBool; | ||||
|     double _aDouble; | ||||
|     std::string _aString; | ||||
|     std::string _anotherString; | ||||
|     unsigned long _aLong; | ||||
|   protected: | ||||
|     void initXmlMembers() { | ||||
|       className("A"); | ||||
|       persist(_anInteger, "anInteger"); | ||||
|       persist(_aBool, "aBool"); | ||||
|       persist(_aDouble, "aDouble"); | ||||
|       persist(_aString, "aString"); | ||||
|       persist(_anotherString, "anotherString"); | ||||
|       persist(_aLong, "aLong"); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| class SerializationTest: public CppUnit::TestFixture { | ||||
|   public: | ||||
|     std::string _file; | ||||
|     A _a; | ||||
|     void setUp() { | ||||
|       _a._anInteger = 15; | ||||
|       _a._aBool = true; | ||||
|       _a._aDouble = 123.456; | ||||
|       _a._aString = "Hello World"; | ||||
|       _a._anotherString = "This is another Text"; | ||||
|       _a._aLong = 4123674622; | ||||
|       try { | ||||
|         std::stringstream ss; | ||||
|         _a.saveXml(ss); | ||||
|         _file = ss.str(); | ||||
|       } catch (...) {} | ||||
|     } | ||||
|     void memberDeclaration() { | ||||
|       // This is more a compile time test than a runtime test. | ||||
|       A a; | ||||
|       a._anInteger = 15; | ||||
|       CPPUNIT_ASSERT_EQUAL(15, a._anInteger); | ||||
|       a._aString = "Hello World"; | ||||
|       CPPUNIT_ASSERT_EQUAL(std::string("Hello World"), a._aString); | ||||
|       std::stringstream ss; | ||||
|     } | ||||
|     void store() { | ||||
|       { | ||||
|         std::stringstream ss; | ||||
|         CPPUNIT_ASSERT_NO_THROW(_a.saveXml(ss)); | ||||
|         CPPUNIT_ASSERT_EQUAL(std::string("<A>\n" | ||||
|                                          "\t<anInteger>15</anInteger>\n" | ||||
|                                          "\t<aBool>1</aBool>\n" | ||||
|                                          "\t<aDouble>123.456</aDouble>\n" | ||||
|                                          "\t<aString>Hello World</aString>\n" | ||||
|                                          "\t<anotherString>This is" | ||||
|                                          " another Text</anotherString>\n" | ||||
|                                          "\t<aLong>4123674622</aLong>\n" | ||||
|                                          "</A>"), | ||||
|                              ss.str()); | ||||
|       } { // again - initialisation of A should be done only once | ||||
|         std::stringstream ss; | ||||
|         CPPUNIT_ASSERT_NO_THROW(_a.saveXml(ss)); | ||||
|         CPPUNIT_ASSERT_EQUAL(_file, ss.str()); | ||||
|       } | ||||
|     } | ||||
|     void restore() { | ||||
|       A a; | ||||
|       std::stringstream ss(_file); | ||||
|       CPPUNIT_ASSERT(_file.size()>0); | ||||
|       CPPUNIT_ASSERT_EQUAL(_file, ss.str()); | ||||
|       CPPUNIT_ASSERT_NO_THROW(a.loadXml(ss)); | ||||
|       CPPUNIT_ASSERT_EQUAL(15, a._anInteger); | ||||
|       CPPUNIT_ASSERT_EQUAL(true, a._aBool); | ||||
|       CPPUNIT_ASSERT_EQUAL(123.456, a._aDouble); | ||||
|       CPPUNIT_ASSERT_EQUAL(std::string("Hello World"), a._aString); | ||||
|       CPPUNIT_ASSERT_EQUAL(std::string("This is another Text"), | ||||
|                            a._anotherString); | ||||
|       CPPUNIT_ASSERT_EQUAL(4123674622ul, a._aLong); | ||||
|     } | ||||
|     CPPUNIT_TEST_SUITE(SerializationTest); | ||||
|     CPPUNIT_TEST(memberDeclaration); | ||||
|     CPPUNIT_TEST(store); | ||||
|     CPPUNIT_TEST(restore); | ||||
|     CPPUNIT_TEST_SUITE_END(); | ||||
| }; | ||||
| CPPUNIT_TEST_SUITE_REGISTRATION(SerializationTest); | ||||
|  | ||||
| int main() try { | ||||
|   CppUnit::TextUi::TestRunner runner; | ||||
|   runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest()); | ||||
|   return runner.run() ? 0 : 1; | ||||
|  } catch (std::exception& e) { | ||||
|   std::cerr<<"***Exception: "<<e.what()<<std::endl; | ||||
|   return 1; | ||||
|  } | ||||
		Reference in New Issue
	
	Block a user