/*
* tests/query/FiniteStateMachineUTest.cxxtest
*
* Copyright (C) 2015 Linas Vepstas
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License v3 as
* published by the Free Software Foundation and including the exceptions
* at http://opencog.org/wiki/Licenses
*
* This program 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 Affero General Public License
* along with this program; if not, write to:
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <opencog/guile/SchemeEval.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/util/Logger.h>
using namespace opencog;
class FiniteStateMachineUTest: public CxxTest::TestSuite
{
private:
AtomSpacePtr as;
SchemeEval* eval;
public:
FiniteStateMachineUTest(void)
{
logger().set_level(Logger::DEBUG);
logger().set_print_to_stdout_flag(true);
as = createAtomSpace();
eval = SchemeEval::get_scheme_evaluator(as);
eval->eval("(add-to-load-path \"" PROJECT_SOURCE_DIR "\")");
}
~FiniteStateMachineUTest()
{
// Erase the log file if no assertions failed.
if (!CxxTest::TestTracker::tracker().suiteFailed())
std::remove(logger().get_filename().c_str());
}
void setUp(void);
void tearDown(void);
Handle get_state(Handle);
void do_test_basic(void);
void test_basic_rw(void);
void test_basic_overlay(void);
};
void FiniteStateMachineUTest::tearDown(void)
{
as->clear();
}
void FiniteStateMachineUTest::setUp(void)
{
as->clear();
eval->eval("(load-from-path \"tests/query/finite-state-machine.scm\")");
}
#define getarity(hand) hand->get_arity()
Handle FiniteStateMachineUTest::get_state(Handle set_link)
{
Handle and_link = set_link->getOutgoingAtom(0);
Handle list_link = and_link->getOutgoingAtom(0);
return list_link->getOutgoingAtom(1);
}
/*
* FiniteStateMachine most basic unit test.
*/
void FiniteStateMachineUTest::do_test_basic(void)
{
// We expect the incoming set to have an arity of 3: once for the
// real, actual state, and once for each of the two VariableNodes.
Handle istate = eval->eval_h("(AnchorNode \"Current State\")");
TS_ASSERT_EQUALS(3, istate->getIncomingSetSize());
// Set up the three possible state handles.
// (Excluding the initial state).
HandleSeq states;
Handle green = eval->eval_h("(ConceptNode \"green\")");
states.push_back(green);
Handle yellow = eval->eval_h("(ConceptNode \"yellow\")");
states.push_back(yellow);
Handle red = eval->eval_h("(ConceptNode \"red\")");
states.push_back(red);
// Take one step of the finite state machine.
printf("Going to take one step\n");
Handle first = eval->eval_h("(cog-execute! (CollectionOf take-one-step))");
printf("First state found:\n%s\n", first->to_short_string().c_str());
TS_ASSERT_EQUALS(1, getarity(first));
// After the first step, we expect a green light.
TS_ASSERT_EQUALS(green, get_state(first));
// We expect the incoming set to have an arity of 3: once for the
// real, actual state, and once for each of the two VariableNodes.
Handle state = eval->eval_h("(AnchorNode \"Current State\")");
TS_ASSERT_EQUALS(3, state->getIncomingSetSize());
for (int i=1; i<21; i++)
{
printf("Going to take one step; %d\n", i);
Handle next = eval->eval_h("(cog-execute! (CollectionOf take-one-step))");
TS_ASSERT_EQUALS(1, getarity(next));
TS_ASSERT_EQUALS(states[i%3], get_state(next));
}
}
void FiniteStateMachineUTest::test_basic_rw(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
do_test_basic();
logger().debug("END TEST: %s", __FUNCTION__);
}
void FiniteStateMachineUTest::test_basic_overlay(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
// Mark base-space as readonly; create a read-write overlay.
as->set_read_only();
AtomSpacePtr save = as;
as = createAtomSpace(as);
SchemeEval* seval = eval;
eval = SchemeEval::get_scheme_evaluator(as);
// Testing is performed in a write-through mode.
as->clear_copy_on_write();
do_test_basic();
eval = seval;
as = save;
as->set_read_write();
logger().debug("END TEST: %s", __FUNCTION__);
}