/*! @file

    @id $Id: serialization_test.cxx 31 2009-04-28 07:36:07Z  $
*/
//       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>
#include <cppunit/XmlOutputter.h>
#include <fstream>

class A: public xml::Serialize {
  public:
    int _int;
    unsigned _unsigned;
    bool operator<(const A& o) const {
      return _int<o._int || _int==o._int && _unsigned<o._unsigned;
    }
  protected:
    void initXmlMembers() {
      className("A");
      persist(_int, "int");
      persist(_unsigned, "unsigned");
    }
};

class B: public xml::Serialize {
  public:
    long _long;
    short _short;
  protected:
    void initXmlMembers() {
      className("B");
      persist(_long, "long");
      persist(_short, "short");
    }
};

class B2: public B {
  public:
    double _double;
  protected:
    void initXmlMembers() {
      B::initXmlMembers();
      className("B2");
      persist(_double, "double");
    }
};

class C: public xml::Serialize {
  public:
    xml::Map<A, B2> _map;
  protected:
    void initXmlMembers() {
      className("C");
      persist(_map, "map");
    }
};

class C2: public C {
  public:
    xml::Set<std::string> _set;
  protected:
    void initXmlMembers() {
      C::initXmlMembers();
      className("C2");
      persist(_set, "set");
    }
};

class D: public xml::Serialize {
  public:
    xml::Vector<C2> _vector;
  protected:
    void initXmlMembers() {
      className("D");
      persist(_vector, "vector");
    }
};

class ContainerSerializationTest: public CppUnit::TestFixture {
  public:
    void checkContainers() {
      // instanciate all container to find template compilation errors
      xml::Deque<int> c1;
      xml::List<int> c2;
      xml::Map<int, int> c3;
      xml::MultiMap<int, int> c4;
      xml::MultiSet<int> c5;
      //xml::PriorityQueue<int> c6;
      //xml::Queue<int> c7;
      xml::Set<int> c8;
      //xml::Stack<int> c9;
      xml::Vector<int> c10;
      // no test
      std::string file("<D>\n"
                       "\t<vector>\n"
                       "\t\t<C2>\n"
                       "\t\t\t<map>\n"
                       "\t\t\t\t<A>\n"
                       "\t\t\t\t\t<int>-13</int>\n"
                       "\t\t\t\t\t<unsigned>13</unsigned>\n"
                       "\t\t\t\t</A>\n"
                       "\t\t\t\t<B2>\n"
                       "\t\t\t\t\t<long>1234567890</long>\n"
                       "\t\t\t\t\t<short>123</short>\n"
                       "\t\t\t\t\t<double>1.234</double>\n"
                       "\t\t\t\t</B2>\n"
                       "\t\t\t\t<A>\n"
                       "\t\t\t\t\t<int>-1</int>\n"
                       "\t\t\t\t\t<unsigned>2</unsigned>\n"
                       "\t\t\t\t</A>\n"
                       "\t\t\t\t<B2>\n"
                       "\t\t\t\t\t<long>451236789</long>\n"
                       "\t\t\t\t\t<short>43</short>\n"
                       "\t\t\t\t\t<double>15.34</double>\n"
                       "\t\t\t\t</B2>\n"
                       "\t\t\t</map>\n"
                       "\t\t\t<set>\n"
                       "\t\t\t\t<item>Hello</item>\n"
                       "\t\t\t\t<item>World</item>\n"
                       "\t\t\t</set>\n"
                       "\t\t</C2>\n"
                       "\t\t<C2>\n"
                       "\t\t\t<map/>\n"
                       "\t\t\t<set/>\n"
                       "\t\t</C2>\n"
                       "\t</vector>\n"
                       "</D>");
      std::stringstream ss(file);
      D d;
      CPPUNIT_ASSERT_EQUAL(std::string("<D>\n"
                                       "\t<vector>\n"
                                       "\t\t<C2>\n"
                                       "\t\t\t<map>\n"
                                       "\t\t\t\t<A>\n"
                                       "\t\t\t\t\t<int/>\n"
                                       "\t\t\t\t\t<unsigned/>\n"
                                       "\t\t\t\t</A>\n"
                                       "\t\t\t\t<B2>\n"
                                       "\t\t\t\t\t<long/>\n"
                                       "\t\t\t\t\t<short/>\n"
                                       "\t\t\t\t\t<double/>\n"
                                       "\t\t\t\t</B2>\n"
                                       "\t\t\t</map>\n"
                                       "\t\t\t<set>\n"
                                       "\t\t\t\t<item/>\n"
                                       "\t\t\t</set>\n"
                                       "\t\t</C2>\n"
                                       "\t</vector>\n"
                                       "</D>"),
                           d.schema());
      CPPUNIT_ASSERT_NO_THROW(d.loadXml(ss));
      std::stringstream ss2;
      CPPUNIT_ASSERT_NO_THROW(d.saveXml(ss2));
      CPPUNIT_ASSERT_EQUAL(file, ss2.str());
    }
    CPPUNIT_TEST_SUITE(ContainerSerializationTest);
    CPPUNIT_TEST(checkContainers);
    CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(ContainerSerializationTest);

int main(int argc, char** argv) try {
  std::ofstream ofs((*argv+std::string(".xml")).c_str());
  CppUnit::TextUi::TestRunner runner;
  runner.setOutputter(new CppUnit::XmlOutputter(&runner.result(), ofs));
  runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
  return runner.run() ? 0 : 1;
 } catch (std::exception& e) {
  std::cerr<<"***Exception: "<<e.what()<<std::endl;
  return 1;
 }
