/*! @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:
    xml::Optional<int> _int;
  protected:
    void initXmlMembers() {
      className("A");
      persist(_int, "int");
    }
};

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

class B1: public B {
  public:
    xml::Optional<A> _a1;
    xml::Optional<A> _a2;
    xml::Optional<A> _a3;
  protected:
    void initXmlMembers() {
      B::initXmlMembers();
      className("B1");
      persist(_a1, "a1");
      persist(_a2, "a2");
      persist(_a3, "a3");
    }
};

class OptionalSerializationTest: public CppUnit::TestFixture {
  public:
    void checkOptional() {
      std::string with("<A>\n"
                       "\t<int>13</int>\n"
                       "</A>");
      std::string without("<A/>");
      A a;
      CPPUNIT_ASSERT_EQUAL(std::string("<A>\n"
                                       "\t<int/>\n"
                                       "</A>"), a.schema());
      std::stringstream ss1a(with);
      CPPUNIT_ASSERT_NO_THROW(a.loadXml(ss1a));
      CPPUNIT_ASSERT_EQUAL(true, (bool)a._int);
      CPPUNIT_ASSERT_EQUAL(13, *a._int);
      std::stringstream ss1b;
      CPPUNIT_ASSERT_NO_THROW(a.saveXml(ss1b));
      CPPUNIT_ASSERT_EQUAL(with, ss1b.str());
      std::stringstream ss2a(without);
      CPPUNIT_ASSERT_NO_THROW(a.loadXml(ss2a));
      CPPUNIT_ASSERT_EQUAL(false, (bool)a._int);
      std::stringstream ss2b;
      CPPUNIT_ASSERT_NO_THROW(a.saveXml(ss2b));
      CPPUNIT_ASSERT_EQUAL(without, ss2b.str());
    }
    void checkMoreOptional() {
      std::string first("<B1>\n"
                        "\t<short>13</short>\n"
                        "\t<a2/>\n"
                        "\t<a3>\n"
                        "\t\t<int>42</int>\n"
                        "\t</a3>\n"
                        "</B1>");
      B1 b;
      std::stringstream ifirst(first);
      CPPUNIT_ASSERT_NO_THROW(b.loadXml(ifirst));
      CPPUNIT_ASSERT_EQUAL(false, (bool)b._long);
      CPPUNIT_ASSERT_EQUAL(true, (bool)b._short);
      CPPUNIT_ASSERT_EQUAL((short)13, *b._short);
      CPPUNIT_ASSERT_EQUAL(false, (bool)b._a1);
      CPPUNIT_ASSERT_EQUAL(true, (bool)b._a2);
      CPPUNIT_ASSERT_EQUAL(false, (bool)b._a2->_int);
      CPPUNIT_ASSERT_EQUAL(true, (bool)b._a3);
      CPPUNIT_ASSERT_EQUAL(true, (bool)b._a3->_int);
      CPPUNIT_ASSERT_EQUAL(42, *b._a3->_int);
      std::stringstream ofirst;
      CPPUNIT_ASSERT_NO_THROW(b.saveXml(ofirst));
      CPPUNIT_ASSERT_EQUAL(first, ofirst.str());
    }
    CPPUNIT_TEST_SUITE(OptionalSerializationTest);
    CPPUNIT_TEST(checkOptional);
    CPPUNIT_TEST(checkMoreOptional);
    CPPUNIT_TEST_SUITE_END();
};
CPPUNIT_TEST_SUITE_REGISTRATION(OptionalSerializationTest);

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;
 }