/*
* tests/query/CacheHitUTest.cxxtest
*
* Copyright (C) 2014, 2015, 2021 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 CacheHitUTest: public CxxTest::TestSuite
{
private:
AtomSpacePtr as;
SchemeEval* eval;
public:
CacheHitUTest(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 "\")");
}
~CacheHitUTest()
{
// 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 add_cruft(char);
void test_hit(void);
};
void CacheHitUTest::tearDown(void)
{
}
void CacheHitUTest::setUp(void)
{
}
void CacheHitUTest::add_cruft(char junk)
{
char buf[8192];
snprintf(buf, 8192,
" (EvaluationLink"
" (PredicateNode \"*-word-shape pair-*\")"
" (ConceptNode \"d\")"
" (EvaluationLink"
" (PredicateNode \"*-shape-*\")"
" (ConceptNode \"%c\")"
" (Connector (ConceptNode \"e\") (Sex \"-\"))"
" (Connector (ConceptNode \"j\") (Sex \"+\"))"
" (Connector (ConceptNode \"g\") (Sex \"+\"))"
" (Connector (VariableNode \"$connector-word\") (Sex \"+\"))"
" (Connector (ConceptNode \"!\") (Sex \"+\"))"
" ))", junk);
eval->eval(buf);
}
/*
* Verify that a cache hit does not result in a crash.
*
* This bug can be hard to trigger, as it depends on the order
* in which the search is performed, and the search order depends
* on how the atoms lay out in RAM. So the actual test strategy
* is to loop: in each loop, clear the atomspace, add some cruft
* to scramble the memory order, and then run the test. This
* eventually results in a core dump, when the patch in pull req
* opencog/atomspace#2803 is not applied.
*
* There are three places where the search can start, and so,
* if memory really is randomized, it should not take more than
* about 6-8 iterations of the loop before the bug is hit.
*/
void CacheHitUTest::test_hit(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
for (char c='0'; c<'Z'; c++)
{
printf("Start iteration %c\n", c);
as->clear();
eval->eval(
" (EvaluationLink"
" (PredicateNode \"*-word-shape pair-*\")"
" (Concept \"b\")"
" (EvaluationLink"
" (PredicateNode \"*-shape-*\")"
" (Concept \"b\")"
" (Connector (Concept \"###LEFT-WALL###\") (Sex \"-\"))"
" (Connector (VariableNode \"$connector-word\") (Sex \"-\"))"
" (Connector (Concept \"a\") (Sex \"+\"))))"
""
" (define var (Variable \"$api-right-star\"))"
" (define term "
" (EvaluationLink"
" (PredicateNode \"*-word-shape pair-*\")"
" (ConceptNode \"b\")"
" (VariableNode \"$api-right-star\")))"
""
" (define b (CollectionOf (Query (TypedVariable var (Type \"Evaluation\")) term term)))"
);
for (char j='0'; j<c; j++)
add_cruft(j);
Handle crash = eval->eval_h("(cog-execute! b)");
// std::cout << "Answer: " << crash->to_string() << std::endl;
TS_ASSERT_EQUALS(1, crash->get_arity());
// Create the expected answer, and compare
Handle expected = eval->eval_h(
"(SetLink"
" (EvaluationLink"
" (PredicateNode \"*-word-shape pair-*\")"
" (ConceptNode \"b\")"
" (EvaluationLink"
" (PredicateNode \"*-shape-*\")"
" (ConceptNode \"b\")"
" (Connector (ConceptNode \"###LEFT-WALL###\") (Sex \"-\"))"
" (Connector (VariableNode \"$connector-word\") (Sex \"-\"))"
" (Connector (ConceptNode \"a\") (Sex \"+\")))))"
);
TS_ASSERT_EQUALS(expected, crash);
}
logger().debug("END TEST: %s", __FUNCTION__);
}