/*
* tests/atomspace/AtomTableUTest.cxtest
*
* Copyright (C) 2002-2007 Novamente LLC
* Copyright (C) 2008 by OpenCog Foundation
* Copyright (C) 2015 Linas Vepstas
* All Rights Reserved
*
* Written by Welter Silva <welter@vettalabs.com>
* Gustavo Gama <gama@vettalabs.com>
*
* 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 <iostream>
#include <fstream>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/atom_types/NameServer.h>
#include <opencog/atoms/value/FloatValue.h>
#include <opencog/atoms/base/Link.h>
#include <opencog/atoms/base/Node.h>
#include <opencog/guile/SchemeEval.h>
#include <opencog/util/Logger.h>
#include <opencog/util/platform.h>
#include "../query/test-types.h"
using namespace opencog;
using namespace std;
const char* gpnNames[] = {"GPN1", "GPN2", "GPN3", "GPN4", "GNP5", "GNP6"};
int numberOfExpectedMatches[] = {26, 26, 26, 1, 1, 1};
class AtomTableUTest : public CxxTest::TestSuite
{
private:
AtomSpacePtr table;
AtomSpacePtr atomSpace;
public:
AtomTableUTest() {
// Uncomment to enable logging
//logger().setLevel(Logger::DEBUG);
//logger().setPrintToStdoutFlag(true);
#include "../query/test-types.cc"
atomSpace = createAtomSpace();
table = atomSpace;
}
~AtomTableUTest() {
}
void setUp()
{
atomSpace->clear();
}
void tearDown() {
atomSpace->clear();
}
void testSimple()
{
Handle time = table->add_atom(createNode(TIME_NODE, "1"));
Handle word = table->add_atom(createNode(NUMBER_NODE, "1"));
Handle sense = table->add_atom(createNode(CONCEPT_NODE, "28675194"));
HandleSeq os;
os.push_back(time);
os.push_back(word);
os.push_back(sense);
table->add_atom(createLink(std::move(os), INHERITANCE_LINK));
table->barrier();
}
void testHolds()
{
Handle h(createNode(NUMBER_NODE, "1"));
Handle word = table->add_atom(h);
TS_ASSERT(word->getAtomSpace() == table.get());
}
void testIsCleared()
{
atomSpace->clear();
TS_ASSERT(0 == table->get_size());
Handle word = table->add_atom(createNode(NUMBER_NODE, "1"));
TS_ASSERT(1 == table->get_size());
}
void doRecursiveAdd(Type list_type)
{
Handle hn1(createNode(NUMBER_NODE, "1"));
Handle hn2(createNode(NUMBER_NODE, "2"));
Handle hn3(createNode(NUMBER_NODE, "3"));
Handle hn4(createNode(NUMBER_NODE, "4"));
Handle hnp(createNode(PREDICATE_NODE, "diequalized"));
// The unordered link will get tested second,
// and will get a scrambled set of UUID's.
Handle hll;
if (list_type == LIST_LINK)
hll = createLink(list_type, hn1, hn2, hn3, hn4);
else if (list_type == SET_LINK)
hll = createLink(list_type, hn4, hn1, hn2, hn3);
else
hll = createLink(list_type, hn4, hn2, hn3, hn1);
Handle hle(createLink(EVALUATION_LINK, hnp, hll));
// Add the link. All the outgoing atoms should get added too.
Handle hlet = table->add_atom(hle);
const HandleSeq& hs = hlet->getOutgoingSet();
const HandleSeq& hsl = hs[1]->getOutgoingSet();
// Now test resolution. Given the version of the atom that is
// not yet in the atomspace, we should be able to find the one
// that is in the atomspace.
Handle hle_resolved(table->get_atom(hle));
TS_ASSERT(*((Handle)hlet) == *((Handle)hle_resolved));
Handle hnp_resolved(table->get_atom(hnp));
TS_ASSERT(*((Handle)hs[0]) == *((Handle)hnp_resolved));
Handle hll_resolved(table->get_atom(hll));
TS_ASSERT(*((Handle)hs[1]) == *((Handle)hll_resolved));
// The remainder of the test assumes an ordered link,
// so that atoms get stored in known locations. Can't
// run this part if its unordered.
if (not nameserver().isA(list_type, ORDERED_LINK))
return;
Handle hn1_resolved(table->get_atom(hn1));
TS_ASSERT(*((Handle)hsl[0]) == *((Handle)hn1_resolved));
Handle hn2_resolved(table->get_atom(hn2));
TS_ASSERT(*((Handle)hsl[1]) == *((Handle)hn2_resolved));
Handle hn3_resolved(table->get_atom(hn3));
TS_ASSERT(*((Handle)hsl[2]) == *((Handle)hn3_resolved));
Handle hn4_resolved(table->get_atom(hn4));
TS_ASSERT(*((Handle)hsl[3]) == *((Handle)hn4_resolved));
}
void testRecursiveAdd()
{
// Once for an ordered link type, and again for an unordered
// type. Unordered links get special handling.
doRecursiveAdd(LIST_LINK);
doRecursiveAdd(SET_LINK);
doRecursiveAdd(SIMILARITY_LINK);
doRecursiveAdd(LIST_LINK);
}
/* test the fix for the bug triggered whenever we had a link
* pointing to the same atom twice (or more). */
void testDoubleLink()
{
Handle n1(createNode(NUMBER_NODE, "1"));
Handle n2(createNode(NUMBER_NODE, "2"));
Handle hn1 = table->add_atom(n1);
Handle hn2 = table->add_atom(n2);
HandleSeq os;
os.push_back(hn1); os.push_back(hn1); os.push_back(hn2);
Handle l1(createLink(std::move(os), LIST_LINK));
Handle hl1 = table->add_atom(l1);
// Now, remove hn1 from the table ...
table->extract_atom(hn1, true);
// Number nodes are handled differently, in the atomspace. Try
// again, with concept nodes.
Handle h3(createNode(CONCEPT_NODE, "3"));
os.clear();
os.push_back(h3);
os.push_back(h3);
Handle l33 = table->add_atom(createLink(std::move(os), LIST_LINK));
HandleSeq hs = l33->getOutgoingSet();
printf("hs1 & hs2 ptr's: %p %p\n", hs[0].operator->(), hs[1].operator->());
TS_ASSERT_EQUALS(hs[0], hs[1]);
}
void testSimpleWithCustomAtomTypes()
{
nameserver().beginTypeDecls("custom types");
Type MY_NUMBER_NODE = nameserver().declType(NUMBER_NODE, "MyNumberNode");
Type MY_CONCEPT_NODE = nameserver().declType(CONCEPT_NODE, "MyConceptNode");
Type MY_INHERITANCE_LINK = nameserver().declType(INHERITANCE_LINK, "MyInheritanceLink");
nameserver().endTypeDecls();
logger().debug("MY_NUMBER_NODE = %u, MY_CONCEPT_NODE = %u, MY_INHERITANCE_LINK = %u\n", MY_NUMBER_NODE, MY_CONCEPT_NODE, MY_INHERITANCE_LINK);
Handle wp = createNode(MY_NUMBER_NODE, "1");
Handle word = table->add_atom(wp);
Handle sp = createNode(MY_CONCEPT_NODE, "28675194");
Handle sense = table->add_atom(sp);
Handle lp = createLink(MY_INHERITANCE_LINK, word, sense);
Handle lh = table->add_atom(lp);
TS_ASSERT(table->get_node(MY_NUMBER_NODE, "1") != Handle::UNDEFINED);
TS_ASSERT(table->get_node(MY_CONCEPT_NODE, "28675194") != Handle::UNDEFINED);
HandleSeq os;
os.push_back(word);
os.push_back(sense);
TS_ASSERT(table->get_link(MY_INHERITANCE_LINK, std::move(os)) != Handle::UNDEFINED);
}
};