#include <QtCore/QString>
#include <QtTest/QtTest>

#include <fstream>

#include "kalkuloncore.h"


class UnittestsMain : public QObject
{
    Q_OBJECT

public:
    UnittestsMain();

private Q_SLOTS:
    void testCase1();
    void testDataObject_serialize();
    void testCRPNStackEval_serialize();

};

UnittestsMain::UnittestsMain()
{
}

void UnittestsMain::testCase1()
{
  Kalkulon::DataObject dob1(123);
  Kalkulon::DataObject dob2(120+3);

  QVERIFY2(dob1 == dob2, "Failure");
}

void UnittestsMain::testDataObject_serialize()
{
  const char* FILENAME = "testDataObject_serialize";
  std::ofstream os(FILENAME, std::ios_base::binary);
  if(os)
  {
    Kalkulon::CRPNStackEval evaluator;

    // serialize
    Kalkulon::DataObject dob1a(123);
    dob1a.serialize(os);

    Kalkulon::DataObject dob2a("Hello Kalkulon");
    dob2a.serialize(os);


    Kalkulon::DataObject dob3a = evaluator.parseEval("{1,2,3,{7,8,9},4}");
    dob3a.serialize(os);

    Kalkulon::DataObject dob4a = evaluator.parseEval("'3*#'");
    dob4a.serialize(os);

    Kalkulon::DataObject dob5a = evaluator.parseEval("'#*3'");
    dob5a.serialize(os);

    os.close();

    // deserialize
    std::ifstream is(FILENAME, std::ios_base::binary);

    Kalkulon::DataObject dob1b = Kalkulon::DataObject::deserialize(is);
    Kalkulon::DataObject dob2b = Kalkulon::DataObject::deserialize(is);
    Kalkulon::DataObject dob3b = Kalkulon::DataObject::deserialize(is);
    Kalkulon::DataObject dob4b = Kalkulon::DataObject::deserialize(is);
    Kalkulon::DataObject dob5b = Kalkulon::DataObject::deserialize(is);

    QVERIFY(dob1a == dob1b);
    QVERIFY(dob2a == dob2b);
    QVERIFY(dob3a == dob3b);
    QVERIFY(dob4a == dob4b);
    QVERIFY(dob5a == dob5b);
    QVERIFY(dob4a != dob5b);

  }
  else
    QVERIFY2(false, "cannot open file");


}

void UnittestsMain::testCRPNStackEval_serialize()
{
  const char* FILENAME = "testCRPNStackEval_serialize";
  Kalkulon::CRPNStackEval evaluator;

  evaluator.parseEval("3+5");
  evaluator.parseEval("{1,2,3,{7,8,9},4}");
  evaluator.parseEval("'3*#'");
  evaluator.parseEval("f(x)=7*x");
  evaluator.parseEval("f(5)");
  evaluator.parseEval("a=123");
  evaluator.parseEval("b()='#'");
  evaluator.parseEval("c = 2.5");
  evaluator.parseEval("d = {2.5, '#'}");
  evaluator.parseEval("e = {2.5, '#', \"abc\"}");

  QVERIFY(evaluator.serialize(FILENAME));

  Kalkulon::CRPNStackEval evaluator2;

  QVERIFY(evaluator2.deserialize(FILENAME));
  QVERIFY(evaluator.getOutIdx() == evaluator2.getOutIdx());
  QVERIFY(evaluator.symbols.size() == evaluator2.symbols.size());

  {
    // symbols
    Kalkulon::CRPNStackEval::symbols_t::const_iterator it, b, e;
    b = evaluator.symbols.begin();
    e = evaluator.symbols.end();
    for(it=b; it!=e; ++it)
    {
      std::string name = it->first;
      Kalkulon::DataObject dob = evaluator.symbols[name];
      Kalkulon::DataObject dob2 = evaluator2.symbols[name];

      QVERIFY2(dob == dob2, name.c_str());
    }
  }

  {
    // functions
    Kalkulon::CRPNStackEval::functions_t::const_iterator it, b, e;
    b = evaluator.functions.begin();
    e = evaluator.functions.end();
    for(it=b; it!=e; ++it)
    {
      std::string name = it->first;
      Kalkulon::FuncObject fob = evaluator.functions[name];
      Kalkulon::FuncObject fob2 = evaluator2.functions[name];

      QVERIFY2(fob.param_list == fob2.param_list, name.c_str());
      QVERIFY2(fob.rpn_stack == fob2.rpn_stack, name.c_str());
    }
  }



}


QTEST_APPLESS_MAIN(UnittestsMain)

#include "tst_unittestsmain.moc"
