/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2010-2012 University of Bonn. All rights reserved.
 * 
 *
 *   This file is part of MoleCuilder.
 *
 *    MoleCuilder is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    MoleCuilder is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MoleCuilder.  If not, see .
 */
/*
 * FormulaUnitTest.cpp
 *
 *  Created on: Jul 21, 2010
 *      Author: crueger
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include 
#include 
#include 
#include 
#include "Formula.hpp"
#include "World.hpp"
#include "FormulaUnitTest.hpp"
#ifdef HAVE_TESTRUNNER
#include "UnitTestMain.hpp"
#endif /*HAVE_TESTRUNNER*/
CPPUNIT_TEST_SUITE_REGISTRATION( FormulaUnittest );
void FormulaUnittest::setUp()
{
  // failing asserts should be thrown
  ASSERT_DO(Assert::Throw);
}
void FormulaUnittest::tearDown()
{
  World::purgeInstance();
}
void FormulaUnittest::baseTest(){
  Formula formula;
  CPPUNIT_ASSERT_EQUAL(formula.getElementCount(),(unsigned int)0);
  CPPUNIT_ASSERT(formula.begin()==formula.end());
  // test some one letter element names
  formula += "H";
  CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)1);
  CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula.getElementCount(),(unsigned int)1);
  CPPUNIT_ASSERT(formula.begin()!=formula.end());
  formula += "H";
  CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)2);
  CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula.getElementCount(),(unsigned int)1);
  CPPUNIT_ASSERT(formula.begin()!=formula.end());
  formula += "O";
  CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)2);
  CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)1);
  CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula.getElementCount(),(unsigned int)2);
  CPPUNIT_ASSERT(formula.begin()!=formula.end());
  // test copy constructor
  Formula formula2=formula;
  CPPUNIT_ASSERT_EQUAL(formula2["H"],(unsigned int)2);
  CPPUNIT_ASSERT_EQUAL(formula2["O"],(unsigned int)1);
  CPPUNIT_ASSERT_EQUAL(formula2["C"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula2.getElementCount(),(unsigned int)2);
  CPPUNIT_ASSERT(formula2.begin()!=formula2.end());
  // test Assignment operator
  formula2=Formula();
  CPPUNIT_ASSERT_EQUAL(formula2["H"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula2["O"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula2["C"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula2.getElementCount(),(unsigned int)0);
  CPPUNIT_ASSERT(formula2.begin()==formula2.end());
  // test comparison
  CPPUNIT_ASSERT(formula!=formula2);
  Formula formula3;
  formula3 += "H";
  formula3 += "H";
  formula3 += "O";
  CPPUNIT_ASSERT(formula==formula3);
  // inequality
  formula3 += "O";
  CPPUNIT_ASSERT(formula!=formula3);
  // after removing it should be fine again
  formula3 -= "O";
  CPPUNIT_ASSERT(formula==formula3);
  // add something from the far end, to test resizing
  formula3 += "Rh";
  CPPUNIT_ASSERT(formula!=formula3);
  formula3 -= "Rh";
  CPPUNIT_ASSERT(formula==formula3);
  // removal of elements
  formula -= "H";
  CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)1);
  CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)1);
  CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula.getElementCount(),(unsigned int)2);
  CPPUNIT_ASSERT(formula.begin()!=formula.end());
  formula -= "O";
  CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)1);
  CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula.getElementCount(),(unsigned int)1);
  CPPUNIT_ASSERT(formula.begin()!=formula.end());
  formula -= "H";
  CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  CPPUNIT_ASSERT_EQUAL(formula.getElementCount(),(unsigned int)0);
  CPPUNIT_ASSERT(formula.begin()==formula.end());
}
void FormulaUnittest::parseTest(){
  {
    Formula formula("");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  }
  {
    Formula formula("H");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)1);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  }
  {
    Formula formula("H2");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  }
  {
    Formula formula("H2O");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)1);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  }
  {
    Formula formula("CH3COOH");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)4);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  }
  {
    Formula formula("CH3COONa");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)3);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["Na"],(unsigned int)1);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  }
  {
    Formula formula("NaCH3COO");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)3);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["Na"],(unsigned int)1);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  }
  {
    Formula formula("Na2CO3");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)3);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)1);
    CPPUNIT_ASSERT_EQUAL(formula["Na"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  }
  {
    Formula formula("CH2(COOH)2");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)4);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)4);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)3);
    CPPUNIT_ASSERT_EQUAL(formula["Na"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
  }
  {
    Formula formula("K4[Fe(CN)6]");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)6);
    CPPUNIT_ASSERT_EQUAL(formula["Na"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["K"],(unsigned int)4);
    CPPUNIT_ASSERT_EQUAL(formula["Fe"],(unsigned int)1);
    CPPUNIT_ASSERT_EQUAL(formula["N"],(unsigned int)6);
  }
  {
    Formula formula("[CrCl3(H2O)3]");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)6);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)3);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["Na"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["Cr"],(unsigned int)1);
    CPPUNIT_ASSERT_EQUAL(formula["Cl"],(unsigned int)3);
  }
  {
    Formula formula("Mg3[Fe(CN)6]2");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)12);
    CPPUNIT_ASSERT_EQUAL(formula["Na"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["Mg"],(unsigned int)3);
    CPPUNIT_ASSERT_EQUAL(formula["Fe"],(unsigned int)2);
    CPPUNIT_ASSERT_EQUAL(formula["N"],(unsigned int)12);
  }
  {
    Formula formula("Na[Fe((HO2CCH2)2NCH2CH2N(CH2CO2H)2)]");
    CPPUNIT_ASSERT_EQUAL(formula["H"],(unsigned int)16);
    CPPUNIT_ASSERT_EQUAL(formula["O"],(unsigned int)8);
    CPPUNIT_ASSERT_EQUAL(formula["C"],(unsigned int)10);
    CPPUNIT_ASSERT_EQUAL(formula["Na"],(unsigned int)1);
    CPPUNIT_ASSERT_EQUAL(formula["He"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["Mg"],(unsigned int)0);
    CPPUNIT_ASSERT_EQUAL(formula["Fe"],(unsigned int)1);
    CPPUNIT_ASSERT_EQUAL(formula["N"],(unsigned int)2);
  }
  {
    CPPUNIT_ASSERT_THROW(Formula formula("74107"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("  "),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("nAcL"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("NAcL"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("Na Cl"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("1NaCl"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("Mag"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("AgCl)"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("(Na"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("(Mag)"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("MgCl2)"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("((MgCl2)"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("(MgCl2))"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("(MgCl2]"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("[MgCl2)"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("N(aCl"),FormulaStringParseException);
    CPPUNIT_ASSERT_THROW(Formula formula("Na()Cl"),FormulaStringParseException);
  }
}