/*
 * 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 .
 */
/*
 * MoleculeDescriptorTest.cpp
 *
 *  Created on: Mar 4, 2010
 *      Author: crueger
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "World.hpp"
#include "molecule.hpp"
#include "MoleculeDescriptorUnitTest.hpp"
#ifdef HAVE_TESTRUNNER
#include "UnitTestMain.hpp"
#endif /*HAVE_TESTRUNNER*/
/********************************************** Test classes **************************************/
// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( MoleculeDescriptorTest );
// set up and tear down
void MoleculeDescriptorTest::setUp(){
  World::getInstance();
  for(int i=0;igetId();
  }
}
void MoleculeDescriptorTest::tearDown(){
  World::purgeInstance();
}
// some helper functions
static bool hasAllMolecules(
    std::vector &molecules,
    moleculeId_t ids[MOLECULE_COUNT],
    std::set excluded = std::set())
{
  for(int i=0;i::const_iterator iter;
      bool res=false;
      for(iter=molecules.begin();iter!=molecules.end();++iter){
        res |= (*iter)->getId() == id;
      }
      if(!res) {
        cout << "Molecule " << id << " missing in returned list" << endl;
        return false;
      }
    }
  }
  return true;
}
static bool hasNoDuplicateMolecules(std::vector &molecules){
  std::set found;
  std::vector::const_iterator iter;
  for(iter=molecules.begin();iter!=molecules.end();++iter){
    int id = (*iter)->getId();
    if(found.count(id))
      return false;
    found.insert(id);
  }
  return true;
}
void MoleculeDescriptorTest::MoleculeBaseSetsTest(){
  std::vector allMolecules =
      const_cast(World::getInstance()).getAllMolecules(AllMolecules());
  CPPUNIT_ASSERT_EQUAL( true , hasAllMolecules(allMolecules,moleculeIds));
  CPPUNIT_ASSERT_EQUAL( true , hasNoDuplicateMolecules(allMolecules));
  std::vector noMolecules =
      const_cast(World::getInstance()).getAllMolecules(NoMolecules());
  CPPUNIT_ASSERT_EQUAL( true , noMolecules.empty());
}
void MoleculeDescriptorTest::MoleculeIdTest(){
  // test Molecules from boundaries and middle of the set
  const molecule* testMolecule;
  testMolecule = const_cast(World::getInstance()).
      getMolecule(MoleculeById(moleculeIds[0]));
  CPPUNIT_ASSERT(testMolecule);
  CPPUNIT_ASSERT_EQUAL( moleculeIds[0], testMolecule->getId());
  testMolecule = const_cast(World::getInstance()).
      getMolecule(MoleculeById(moleculeIds[MOLECULE_COUNT/2]));
  CPPUNIT_ASSERT(testMolecule);
  CPPUNIT_ASSERT_EQUAL( moleculeIds[MOLECULE_COUNT/2], testMolecule->getId());
  testMolecule = const_cast(World::getInstance()).
      getMolecule(MoleculeById(moleculeIds[MOLECULE_COUNT-1]));
  CPPUNIT_ASSERT(testMolecule);
  CPPUNIT_ASSERT_EQUAL( moleculeIds[MOLECULE_COUNT-1], testMolecule->getId());
  // find some ID that has not been created
  moleculeId_t outsideId=0;
  bool res = false;
  for(outsideId=0;!res;++outsideId) {
    res = true;
    for(int i = 0; i < MOLECULE_COUNT; ++i){
      res &= moleculeIds[i]!=outsideId;
    }
  }
  // test from outside of set
  testMolecule = const_cast(World::getInstance()).
      getMolecule(MoleculeById(outsideId));
  CPPUNIT_ASSERT(!testMolecule);
}
void MoleculeDescriptorTest::MoleculeCalcTest(){
  // test some elementary set operations
  {
    std::vector testMolecules =
        const_cast(World::getInstance()).getAllMolecules(AllMolecules()||NoMolecules());
    CPPUNIT_ASSERT_EQUAL( true , hasAllMolecules(testMolecules,moleculeIds));
    CPPUNIT_ASSERT_EQUAL( true , hasNoDuplicateMolecules(testMolecules));
  }
  {
    std::vector testMolecules =
        const_cast(World::getInstance()).getAllMolecules(NoMolecules()||AllMolecules());
    CPPUNIT_ASSERT_EQUAL( true , hasAllMolecules(testMolecules,moleculeIds));
    CPPUNIT_ASSERT_EQUAL( true , hasNoDuplicateMolecules(testMolecules));
  }
  {
    std::vector testMolecules =
        const_cast(World::getInstance()).getAllMolecules(NoMolecules()&&AllMolecules());
    CPPUNIT_ASSERT_EQUAL( true , testMolecules.empty());
  }
  {
    std::vector testMolecules =
        const_cast(World::getInstance()).getAllMolecules(AllMolecules()&&NoMolecules());
    CPPUNIT_ASSERT_EQUAL( true , testMolecules.empty());
  }
  {
    std::vector testMolecules =
        const_cast(World::getInstance()).getAllMolecules(!AllMolecules());
    CPPUNIT_ASSERT_EQUAL( true , testMolecules.empty());
  }
  {
    std::vector testMolecules =
        const_cast(World::getInstance()).getAllMolecules(!NoMolecules());
    CPPUNIT_ASSERT_EQUAL( true , hasAllMolecules(testMolecules,moleculeIds));
    CPPUNIT_ASSERT_EQUAL( true , hasNoDuplicateMolecules(testMolecules));
  }
  // exclude and include some molecules
  {
    std::vector testMolecules =
        const_cast(World::getInstance()).getAllMolecules(AllMolecules()&&(!MoleculeById(moleculeIds[MOLECULE_COUNT/2])));
    std::set excluded;
    excluded.insert(moleculeIds[MOLECULE_COUNT/2]);
    CPPUNIT_ASSERT_EQUAL( true , hasAllMolecules(testMolecules,moleculeIds,excluded));
    CPPUNIT_ASSERT_EQUAL( true , hasNoDuplicateMolecules(testMolecules));
    CPPUNIT_ASSERT_EQUAL( (size_t)(MOLECULE_COUNT-1), testMolecules.size());
  }
  {
    std::vector testMolecules =
        const_cast(World::getInstance()).getAllMolecules(NoMolecules()||(MoleculeById(moleculeIds[MOLECULE_COUNT/2])));
    CPPUNIT_ASSERT_EQUAL( (size_t)1, testMolecules.size());
    CPPUNIT_ASSERT_EQUAL( moleculeIds[MOLECULE_COUNT/2], testMolecules[0]->getId());
  }
}
void MoleculeDescriptorTest::MoleculeNameTest()
{
  const molecule* testMolecule;
  // name each molecule
  for(int i=1;i<=MOLECULE_COUNT;++i)
    molecules[i-1]->setName(toString(i));
  // retrieve each
  for(int i=1;i<=MOLECULE_COUNT;++i) {
    testMolecule = const_cast(World::getInstance()).
        getMolecule(MoleculeByName(toString(i)));
    CPPUNIT_ASSERT_EQUAL( moleculeIds[i-1], testMolecule->getId());
  }
  // check for non-present name
  testMolecule = const_cast(World::getInstance()).
      getMolecule(MoleculeByName("not present"));
  CPPUNIT_ASSERT(!testMolecule);
}
void MoleculeDescriptorTest::MoleculeOrderTest()
{
  const molecule* testMolecule;
  // test in normal order: 1, 2, ...
  for(int i=1;i<=MOLECULE_COUNT;++i){
    testMolecule = const_cast(World::getInstance()).
        getMolecule(MoleculeByOrder(i));
    CPPUNIT_ASSERT_EQUAL( moleculeIds[i-1], testMolecule->getId());
  }
  // test in reverse order: -1, -2, ...
  for(int i=1; i<= MOLECULE_COUNT;++i){
    testMolecule = const_cast(World::getInstance()).
        getMolecule(MoleculeByOrder(-i));
    CPPUNIT_ASSERT_EQUAL( moleculeIds[(int)MOLECULE_COUNT-i], testMolecule->getId());
  }
  // test from outside of set
  testMolecule = const_cast(World::getInstance()).
      getMolecule(MoleculeByOrder(MOLECULE_COUNT+1));
  CPPUNIT_ASSERT(!testMolecule);
  testMolecule = const_cast(World::getInstance()).
      getMolecule(MoleculeByOrder(-MOLECULE_COUNT-1));
  CPPUNIT_ASSERT(!testMolecule);
}