/*
* Project: MoleCuilder
* Description: creates and alters molecular systems
* Copyright (C) 2010-2012 University of Bonn. All rights reserved.
* Copyright (C) 2013 Frederik Heber. 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 .
*/
/*
* ActionSequenceUnitTest.cpp
*
* Created on: Dec 17, 2009
* Author: crueger
*/
// include config.h
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include "ActionSequenceUnitTest.hpp"
#include "Actions/Action.hpp"
#include "Actions/ActionQueue.hpp"
#include "Actions/ActionSequence.hpp"
#include "Actions/MakroAction.hpp"
#include "stubs/DummyUI.hpp"
using namespace MoleCuilder;
#ifdef HAVE_TESTRUNNER
#include "UnitTestMain.hpp"
#endif /*HAVE_TESTRUNNER*/
/********************************************** Test classes **************************************/
// Registers the fixture into the 'registry'
CPPUNIT_TEST_SUITE_REGISTRATION( ActionSequenceTest );
/* some neccessary stubs for tests */
class canUndoActionStub : public Action
{
public:
canUndoActionStub(const ActionTrait &_trait):
Action(_trait){}
virtual ~canUndoActionStub(){}
virtual Dialog* fillDialog(Dialog *dialog){
ASSERT(dialog,"No Dialog given when filling action dialog");
return dialog;
}
virtual ActionState::ptr performCall(){
return Action::success;
}
virtual ActionState::ptr performUndo(ActionState::ptr){
return Action::success;
}
virtual ActionState::ptr performRedo(ActionState::ptr){
return Action::success;
}
virtual bool canUndo(){
return true;
}
virtual bool shouldUndo(){
return true;
}
Action* clone(enum QueryOptions flag = Interactive) const
{
return new canUndoActionStub(Traits);
}
void prepare(enum QueryOptions flag = Interactive)
{}
void outputAsCLI(std::ostream &ost) const
{}
void outputAsPython(std::ostream &ost, const std::string &prefix) const
{}
void setOptionValue(const std::string &_token, const std::string &_value)
{}
};
class cannotUndoActionStub : public Action
{
public:
cannotUndoActionStub(const ActionTrait &_trait) :
Action(_trait){}
virtual ~cannotUndoActionStub(){}
virtual Dialog* fillDialog(Dialog *dialog){
ASSERT(dialog,"No Dialog given when filling action dialog");
return dialog;
}
virtual ActionState::ptr performCall(){
return Action::success;
}
virtual ActionState::ptr performUndo(ActionState::ptr){
return Action::success;
}
virtual ActionState::ptr performRedo(ActionState::ptr){
return Action::success;
}
virtual bool canUndo(){
return false;
}
virtual bool shouldUndo(){
return true;
}
Action* clone(enum QueryOptions flag = Interactive) const
{
return new cannotUndoActionStub(Traits);
}
void prepare(enum QueryOptions flag = Interactive)
{}
void outputAsCLI(std::ostream &ost) const
{}
void outputAsPython(std::ostream &ost, const std::string &prefix) const
{}
void setOptionValue(const std::string &_token, const std::string &_value)
{}
};
class wasCalledActionStub : public Action
{
public:
wasCalledActionStub(const ActionTrait &_trait) :
Action(_trait),
called(false)
{}
virtual ~wasCalledActionStub(){}
virtual Dialog* fillDialog(Dialog *dialog){
return dialog;
}
virtual ActionState::ptr performCall(){
called = true;
return Action::success;
}
virtual ActionState::ptr performUndo(ActionState::ptr){
called = false;
return Action::success;
}
virtual ActionState::ptr performRedo(ActionState::ptr){
called = true;
return Action::success;
}
virtual bool canUndo(){
return true;
}
virtual bool shouldUndo(){
return true;
}
Action* clone(enum QueryOptions flag = Interactive) const
{
return new wasCalledActionStub(Traits);
}
void prepare(enum QueryOptions flag = Interactive)
{}
void outputAsCLI(std::ostream &ost) const
{}
void outputAsPython(std::ostream &ost, const std::string &prefix) const
{}
void setOptionValue(const std::string &_token, const std::string &_value)
{}
bool wasCalled(){
return called;
}
private:
bool called;
};
void ActionSequenceTest::setUp(){
hasDescriptor = false;
// setup ActionHistory
ActionQueue::getInstance();
// TODO: find a way to really reset the factory to a clean state in tear-down
if(!hasDescriptor){
UIFactory::registerFactory(new DummyUIFactory::description());
hasDescriptor = true;
}
UIFactory::makeUserInterface("Dummy");
// create some necessary stubs used in this test
ActionTrait canUndoTrait("canUndoActionStub");
ActionTrait cannotUndoTrait("cannotUndoActionStub");
positive1 = new canUndoActionStub(canUndoTrait);
positive2 = new canUndoActionStub(canUndoTrait);
negative1 = new cannotUndoActionStub(cannotUndoTrait);
negative2 = new cannotUndoActionStub(cannotUndoTrait);
ActionTrait wasCalledTrait("wasCalledActionStub");
shouldCall1 = new wasCalledActionStub(wasCalledTrait);
shouldCall2 = new wasCalledActionStub(wasCalledTrait);
shouldNotCall1 = new wasCalledActionStub(wasCalledTrait);
shouldNotCall2 = new wasCalledActionStub(wasCalledTrait);
}
void ActionSequenceTest::tearDown(){
delete positive1;
delete positive2;
delete negative1;
delete negative2;
delete shouldCall1;
delete shouldCall2;
delete shouldNotCall1;
delete shouldNotCall2;
ActionQueue::purgeInstance();
{
UIFactory::purgeInstance();
hasDescriptor = false;
}
}
void ActionSequenceTest::canUndoTest(){
// first section:
{
// test some combinations
{
ActionSequence *sequence = new ActionSequence();
sequence->addAction(positive1->clone());
sequence->addAction(positive2->clone());
CPPUNIT_ASSERT_EQUAL( true, sequence->canUndo() );
delete sequence;
}
{
ActionSequence *sequence = new ActionSequence();
sequence->addAction(positive1->clone());
sequence->addAction(negative2->clone());
CPPUNIT_ASSERT_EQUAL( false, sequence->canUndo() );
delete sequence;
}
{
ActionSequence *sequence = new ActionSequence();
sequence->addAction(negative1->clone());
sequence->addAction(positive2->clone());
CPPUNIT_ASSERT_EQUAL( false, sequence->canUndo() );
delete sequence;
}
{
ActionSequence *sequence = new ActionSequence();
sequence->addAction(negative1->clone());
sequence->addAction(negative2->clone());
CPPUNIT_ASSERT_EQUAL( false, sequence->canUndo() );
delete sequence;
}
}
// second section:
{
// empty sequence can be undone
ActionSequence *sequence = new ActionSequence();
CPPUNIT_ASSERT_EQUAL( true, sequence->canUndo() );
// if only a positive action is contained it can be undone
sequence->addAction(positive1->clone());
CPPUNIT_ASSERT_EQUAL( true, sequence->canUndo() );
// the single negative action should block the process
sequence->addAction(negative1->clone());
CPPUNIT_ASSERT_EQUAL( false, sequence->canUndo() );
// after removing the negative action all is well again
delete sequence->removeLastAction();
CPPUNIT_ASSERT_EQUAL( true, sequence->canUndo() );
delete sequence;
}
}
void ActionSequenceTest::doesCallTest(){
ActionSequence *sequence = new ActionSequence();
sequence->addAction(shouldCall1->clone());
sequence->addAction(shouldCall2->clone());
sequence->addAction(shouldNotCall1->clone());
sequence->addAction(shouldNotCall2->clone());
delete sequence->removeLastAction();
delete sequence->removeLastAction();
sequence->callAll();
ActionSequence::actionSet::const_iterator iter = sequence->actions.begin();
CPPUNIT_ASSERT_EQUAL(true,dynamic_cast(*iter++)->wasCalled());
CPPUNIT_ASSERT_EQUAL(true,dynamic_cast(*iter++)->wasCalled());
CPPUNIT_ASSERT( iter == sequence->actions.end() );
delete sequence;
}
void ActionSequenceTest::doesUndoTest(){
ActionSequence *sequence = new ActionSequence();
ActionTrait wasCalledTrait("wasCalledActionStub");
sequence->addAction(new wasCalledActionStub(wasCalledTrait));
sequence->addAction(new wasCalledActionStub(wasCalledTrait));
ActionTrait MakroTrait("Test MakroAction");
MakroAction act(MakroTrait,*sequence);
// wasCalledActionStub *wasCalled1 =
// static_cast(act.actions.actions.front());
// wasCalledActionStub *wasCalled2 =
// static_cast(act.actions.actions.back());
act.call();
CPPUNIT_ASSERT_EQUAL(true,
static_cast(act.actions.actions.front())->wasCalled());
CPPUNIT_ASSERT_EQUAL(true,
static_cast(act.actions.actions.back())->wasCalled());
ActionQueue::getInstance().undoLast();
CPPUNIT_ASSERT_EQUAL(false,
static_cast(act.actions.actions.front())->wasCalled());
CPPUNIT_ASSERT_EQUAL(false,
static_cast(act.actions.actions.back())->wasCalled());
delete sequence;
}