/*
* tests/query/SequenceUTest.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/atoms/grant/StateLink.h>
#include <opencog/util/Logger.h>
#include <opencog/atoms/value/BoolValue.h>
using namespace opencog;
class SequenceUTest: public CxxTest::TestSuite
{
private:
AtomSpacePtr as;
SchemeEval* eval;
public:
SequenceUTest(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 "\")");
}
~SequenceUTest()
{
// 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);
void test_sequence(void);
void test_presence(void);
void test_fallback(void);
void test_pass_presence(void);
void test_trivial(void);
void test_or_put(void);
};
void SequenceUTest::tearDown(void)
{
}
void SequenceUTest::setUp(void)
{
}
/*
* Basic SequenceLink unit test.
*/
void SequenceUTest::test_sequence(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/query/sequence.scm\")");
// This should throw an exception from scheme.
// Disable logging so as to avoid the hopeless spew of errors.
logger().set_level(Logger::NONE);
bool caught_exception = false;
try
{
eval->eval_v("(cog-execute! (off-road))");
}
catch (const RuntimeException &e)
{
caught_exception = true;
}
TS_ASSERT_EQUALS(true, caught_exception);
logger().set_level(Logger::DEBUG);
// This should not throw any exceptions.
ValuePtr vp = eval->eval_v("(cog-execute! (traffic-lights))");
BoolValuePtr bvp = BoolValueCast(vp);
TS_ASSERT(not bvp->get_bit(0));
// Check the number of green lights and red lights that were
// evaluated. The pattern has two green lights and one red
// light... The GPN's count how many times these are hit, and
// the counts should be correct.
std::string sngreen = eval->eval("num-green");
std::string snred = eval->eval("num-red");
int ngreen = atoi(sngreen.c_str());
int nred = atoi(snred.c_str());
TS_ASSERT_EQUALS(2, ngreen);
TS_ASSERT_EQUALS(1, nred);
// ----------------------------------------------------------
// There are two green lights here; the BoolValue should be "true".
vp = eval->eval_v("(cog-execute! (all-green))");
bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0));
// Should have seen two more green lights, and no reds.
sngreen = eval->eval("num-green");
snred = eval->eval("num-red");
ngreen = atoi(sngreen.c_str());
nred = atoi(snred.c_str());
TS_ASSERT_EQUALS(4, ngreen);
TS_ASSERT_EQUALS(1, nred);
// ----------------------------------------------------------
// There are four green lights here; the third one is wrapped
// by a NotLink. That should halt the pregression, and return
// false.
vp = eval->eval_v("(cog-execute! (anti-green))");
bvp = BoolValueCast(vp);
TS_ASSERT(not bvp->get_bit(0));
// Should have seen three more green lights, and no reds.
sngreen = eval->eval("num-green");
snred = eval->eval("num-red");
ngreen = atoi(sngreen.c_str());
nred = atoi(snred.c_str());
TS_ASSERT_EQUALS(7, ngreen);
TS_ASSERT_EQUALS(1, nred);
logger().debug("END TEST: %s", __FUNCTION__);
}
void SequenceUTest::test_presence(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/query/seq-presence.scm\")");
ValuePtr vp = eval->eval_v("(cog-execute! empty-sequence)");
BoolValuePtr bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0));
logger().debug("END TEST: %s", __FUNCTION__);
}
/*
* SequentialOrLink unit test.
*/
void SequenceUTest::test_fallback(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/query/sequence.scm\")");
// This should not throw any exceptions.
ValuePtr vp = eval->eval_v("(cog-execute! drag-race)");
BoolValuePtr bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0));
// Check the number of green lights and red lights that were
// evaluated. The pattern has two green lights and one red
// light... The GPN's count how many times these are hit, and
// the counts should be correct.
std::string sngreen = eval->eval("num-green");
std::string snred = eval->eval("num-red");
int ngreen = atoi(sngreen.c_str());
int nred = atoi(snred.c_str());
TS_ASSERT_EQUALS(1, ngreen);
TS_ASSERT_EQUALS(3, nred);
logger().debug("END TEST: %s", __FUNCTION__);
}
void SequenceUTest::test_pass_presence(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/query/seq-absence.scm\")");
ValuePtr vp = eval->eval_v("(cog-execute! or-presence)");
BoolValuePtr bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0));
std::string sntrig = eval->eval("trig");
int ntrig = atoi(sntrig.c_str());
TS_ASSERT_EQUALS(1, ntrig);
// -------------------------------------------------------
vp = eval->eval_v("(cog-execute! and-absence)");
bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0));
sntrig = eval->eval("trig");
ntrig = atoi(sntrig.c_str());
TS_ASSERT_EQUALS(2, ntrig);
// -------------------------------------------------------
vp = eval->eval_v("(cog-execute! and-not-present)");
bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0));
sntrig = eval->eval("trig");
ntrig = atoi(sntrig.c_str());
TS_ASSERT_EQUALS(3, ntrig);
// -------------------------------------------------------
vp = eval->eval_v("(cog-execute! or-not-absent)");
bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0));
sntrig = eval->eval("trig");
ntrig = atoi(sntrig.c_str());
TS_ASSERT_EQUALS(4, ntrig);
// -------------------------------------------------------
// and now, all the above should fail...
eval->eval_h("(EvaluationLink (PredicateNode \"visible\")"
"(ListLink (ConceptNode \"yes it is\")))");
int no_change = 4;
// ----
vp = eval->eval_v("(cog-execute! or-presence)");
bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0)); // return true
ntrig = atoi(eval->eval("trig").c_str());
TS_ASSERT_EQUALS(no_change, ntrig);
// ----
vp = eval->eval_v("(cog-execute! and-absence)");
bvp = BoolValueCast(vp);
TS_ASSERT(not bvp->get_bit(0)); // return false
ntrig = atoi(eval->eval("trig").c_str());
TS_ASSERT_EQUALS(no_change, ntrig);
#if BROKEN_FIXME_XXX
// The below is a valid test, and it should pass; however, the
// pattern matcher fails on these two. Since I'm too lazy to fix,
// just right now, I'm just gonna stub these out instead.
// ----
vp = eval->eval_v("(cog-execute! and-not-present)");
bvp = BoolValueCast(vp);
TS_ASSERT(not bvp->get_bit(0)); // return false
ntrig = atoi(eval->eval("trig").c_str());
TS_ASSERT_EQUALS(no_change, ntrig);
// ----
vp = eval->eval_v("(cog-execute! or-not-absent)");
bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0)); // return true
ntrig = atoi(eval->eval("trig").c_str());
TS_ASSERT_EQUALS(no_change, ntrig);
#endif
// ----
logger().debug("END TEST: %s", __FUNCTION__);
}
/*
* Trivial SequenceLink unit test.
* Actually, this is testing QueryLink, as a surrogate for a trivial
* SequenceLink. This trivial case was failing yesterday... :-/
*/
void SequenceUTest::test_trivial(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/query/seq-trivial.scm\")");
Handle result = eval->eval_h("(cog-execute! (CollectionOf get-something))");
TS_ASSERT_EQUALS(result->get_arity(), 1);
result = eval->eval_h("(cog-execute! (CollectionOf get-nothing))");
TS_ASSERT_EQUALS(result->get_arity(), 0);
result = eval->eval_h("(cog-execute! (CollectionOf get-not-true))");
TS_ASSERT_EQUALS(result->get_arity(), 0);
result = eval->eval_h("(cog-execute! (CollectionOf get-not-false))");
TS_ASSERT_EQUALS(result->get_arity(), 1);
logger().debug("END TEST: %s", __FUNCTION__);
}
// This is an interesting test case .. the PutLink writes atoms to the
// main atomspace, instead of a temporary scratch space!
void SequenceUTest::test_or_put(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
eval->eval("(load-from-path \"tests/query/seq-absence.scm\")");
// ----
// Insert eval link to prevent it from tripping.
eval->eval_h(
"(EvaluationLink (PredicateNode \"yes-visible\")"
" (ListLink (ConceptNode \"is-vis\")))");
ValuePtr vp = eval->eval_v("(cog-execute! or-visible-put)");
BoolValuePtr bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0));
// Check the state. Should have a list of length 1,
// with a variable only; that is, the state was NOT set.
Handle iset = eval->eval_h(
"(cdr (cog-incoming-set (AnchorNode \"state\")))");
TS_ASSERT_EQUALS(iset, Handle::UNDEFINED);
// ----
vp = eval->eval_v("(cog-execute! or-put)");
bvp = BoolValueCast(vp);
TS_ASSERT(bvp->get_bit(0));
// Check the state.
Handle not_viz = eval->eval_h("(ConceptNode \"not-vis\")");
Handle stateh = eval->eval_h("(AnchorNode \"state\")");
Handle state = StateLink::get_state(stateh);
TS_ASSERT_EQUALS(state, not_viz);
// ----
logger().debug("END TEST: %s", __FUNCTION__);
}