/*
* tests/atomspace/RemoveUTest.cxxtest
*
* Copyright (C) 2014 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/atoms/base/Atom.h>
#include <opencog/atoms/base/Link.h>
#include <opencog/atomspace/AtomSpace.h>
using namespace opencog;
// Test support atom removal in multiple atomspaces.
// See also MultiSpace.cxxtest for basic multi-atomspace tests.
//
class RemoveUTest : public CxxTest::TestSuite
{
private:
AtomSpacePtr asp1;
AtomSpacePtr asp2;
public:
RemoveUTest()
{
logger().set_print_to_stdout_flag(true);
}
void setUp()
{
asp1 = createAtomSpace();
asp2 = createAtomSpace(asp1);
// Testing is performed on a write-through configuration.
asp2->clear_copy_on_write();
}
void tearDown() {}
void testSimple();
void testDangling();
void testRecursive();
void testCross();
void testReCross();
void testRepeat();
void testHeads();
void testTails();
};
// Simple test of removal in multiple atomspaces.
void RemoveUTest::testSimple()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
AtomSpace& as1(*asp1.get());
AtomSpace& as2(*asp2.get());
TS_ASSERT(as1.get_size() == 0);
TS_ASSERT(as2.get_size() == 0);
// Create atoms in different atomspaces
Handle hna = as1.add_node(CONCEPT_NODE, "node a");
Handle hnb = as1.add_node(CONCEPT_NODE, "node b");
Handle hli = as2.add_link(LIST_LINK, hna, hnb);
TS_ASSERT(as1.get_size() == 2);
TS_ASSERT(as2.get_size() == 3);
// Verify the link is sane
LinkPtr pli(LinkCast(hli));
TS_ASSERT(pli->get_arity() == 2);
TS_ASSERT(pli->getOutgoingAtom(0) == hna);
TS_ASSERT(pli->getOutgoingAtom(1) == hnb);
// Simple removal of hli should leave everything unaffeced.
as2.extract_atom(hli);
TS_ASSERT(as1.get_size() == 2);
TS_ASSERT(as2.get_size() == 2);
// Handle hli should still point to valid atoms
LinkPtr li(LinkCast(hli));
TS_ASSERT(li->get_arity() == 2);
TS_ASSERT(li->getOutgoingAtom(0) == hna);
TS_ASSERT(li->getOutgoingAtom(1) == hnb);
as1.clear();
as2.clear();
logger().info("END TEST: %s", __FUNCTION__);
}
// Test remove with a dangling link.
void RemoveUTest::testDangling()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
AtomSpace& as1(*asp1.get());
TS_ASSERT(as1.get_size() == 0);
// Create atoms in different atomspaces
Handle hna = as1.add_node(CONCEPT_NODE, "node a");
Handle hnb = as1.add_node(CONCEPT_NODE, "node b");
Handle hli(createLink(LIST_LINK, hna, hnb));
TS_ASSERT(as1.get_size() == 2);
// Verify the link is sane
LinkPtr pli(LinkCast(hli));
TS_ASSERT(pli->get_arity() == 2);
TS_ASSERT(pli->getOutgoingAtom(0) == hna);
TS_ASSERT(pli->getOutgoingAtom(1) == hnb);
// Recursive removal of hna should blow away hli.
as1.extract_atom(hna, true);
TS_ASSERT(as1.get_size() == 1);
// Both hna and hli should still point to valid atoms
LinkPtr li(LinkCast(hli));
TS_ASSERT(li->get_arity() == 2);
TS_ASSERT(li->getOutgoingAtom(0) == hna);
TS_ASSERT(li->getOutgoingAtom(1) == hnb);
as1.clear();
logger().info("END TEST: %s", __FUNCTION__);
}
// Test recursive remove across atomspaces.
void RemoveUTest::testRecursive()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
AtomSpace& as1(*asp1.get());
AtomSpace& as2(*asp2.get());
TS_ASSERT(as1.get_size() == 0);
TS_ASSERT(as2.get_size() == 0);
// Create atoms in different atomspaces
Handle hna = as1.add_node(CONCEPT_NODE, "node a");
Handle hnb = as1.add_node(CONCEPT_NODE, "node b");
Handle hli = as2.add_link(LIST_LINK, hna, hnb);
TS_ASSERT(as1.get_size() == 2);
TS_ASSERT(as2.get_size() == 3);
// Verify the link is sane
LinkPtr pli(LinkCast(hli));
TS_ASSERT(pli->get_arity() == 2);
TS_ASSERT(pli->getOutgoingAtom(0) == hna);
TS_ASSERT(pli->getOutgoingAtom(1) == hnb);
// Recursive removal of hna should blow away hli.
as1.extract_atom(hna, true);
TS_ASSERT(as1.get_size() == 1);
TS_ASSERT(as2.get_size() == 1);
// Both hna and hli should still point to valid atoms
LinkPtr li(LinkCast(hli));
TS_ASSERT(li->get_arity() == 2);
TS_ASSERT(li->getOutgoingAtom(0) == hna);
TS_ASSERT(li->getOutgoingAtom(1) == hnb);
as1.clear();
as2.clear();
logger().info("END TEST: %s", __FUNCTION__);
}
// Test recursive remove across atomspaces.
void RemoveUTest::testCross()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
AtomSpace& as1(*asp1.get());
AtomSpace& as2(*asp2.get());
TS_ASSERT(as1.get_size() == 0);
TS_ASSERT(as2.get_size() == 0);
// Create atoms in different atomspaces
Handle hna = as1.add_node(CONCEPT_NODE, "node a");
Handle hnb = as2.add_node(CONCEPT_NODE, "node b");
Handle hli = as2.add_link(LIST_LINK, hna, hnb);
TS_ASSERT(as1.get_size() == 1);
TS_ASSERT(as2.get_size() == 3);
// Verify the link is sane
LinkPtr pli(LinkCast(hli));
TS_ASSERT(pli->get_arity() == 2);
TS_ASSERT(pli->getOutgoingAtom(0) == hna);
TS_ASSERT(pli->getOutgoingAtom(1) == hnb);
// Recursive removal of hna should blow away hli.
as1.extract_atom(hna, true);
TS_ASSERT(as1.get_size() == 0);
TS_ASSERT(as2.get_size() == 1);
// Both hna and hli should still point to valid atoms
LinkPtr li(LinkCast(hli));
TS_ASSERT(li->get_arity() == 2);
TS_ASSERT(li->getOutgoingAtom(0) == hna);
TS_ASSERT(li->getOutgoingAtom(1) == hnb);
as1.clear();
as2.clear();
logger().info("END TEST: %s", __FUNCTION__);
}
// Test recursive remove across atomspaces.
void RemoveUTest::testReCross()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
AtomSpace& as1(*asp1.get());
AtomSpace& as2(*asp2.get());
TS_ASSERT(as1.get_size() == 0);
TS_ASSERT(as2.get_size() == 0);
// Create atoms in different atomspaces
Handle hna = as1.add_node(CONCEPT_NODE, "node a");
Handle hnb = as2.add_node(CONCEPT_NODE, "node b");
Handle hli = as2.add_link(LIST_LINK, hna, hnb);
TS_ASSERT(as1.get_size() == 1);
TS_ASSERT(as2.get_size() == 3);
// Verify the link is sane
LinkPtr pli(LinkCast(hli));
TS_ASSERT(pli->get_arity() == 2);
TS_ASSERT(pli->getOutgoingAtom(0) == hna);
TS_ASSERT(pli->getOutgoingAtom(1) == hnb);
// Recursive removal of hnb should blow away hli.
as2.extract_atom(hnb, true);
TS_ASSERT(as1.get_size() == 1);
TS_ASSERT(as2.get_size() == 1);
// Both hna and hli should still point to valid atoms
LinkPtr li(LinkCast(hli));
TS_ASSERT(li->get_arity() == 2);
TS_ASSERT(li->getOutgoingAtom(0) == hna);
TS_ASSERT(li->getOutgoingAtom(1) == hnb);
as1.clear();
as2.clear();
logger().info("END TEST: %s", __FUNCTION__);
}
// Test recursive remove across atomspaces.
void RemoveUTest::testRepeat()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
AtomSpace& as1(*asp1.get());
AtomSpace& as2(*asp2.get());
TS_ASSERT(as1.get_size() == 0);
TS_ASSERT(as2.get_size() == 0);
// Create atoms in different atomspaces
Handle hna = as1.add_node(CONCEPT_NODE, "node a");
Handle hnb = as1.add_node(CONCEPT_NODE, "node b");
Handle hli = as2.add_link(LIST_LINK, hna, hnb);
Handle hlili = as2.add_link(LIST_LINK, hli, hli);
TS_ASSERT(as1.get_size() == 2);
TS_ASSERT(as2.get_size() == 4);
// Verify the link is sane
LinkPtr pli(LinkCast(hli));
TS_ASSERT(pli->get_arity() == 2);
TS_ASSERT(pli->getOutgoingAtom(0) == hna);
TS_ASSERT(pli->getOutgoingAtom(1) == hnb);
// Recursive removal of hna should blow away hli.
as1.extract_atom(hna, true);
TS_ASSERT(as1.get_size() == 1);
TS_ASSERT(as2.get_size() == 1);
// Both hna and hli should still point to valid atoms
LinkPtr li(LinkCast(hli));
TS_ASSERT(li->get_arity() == 2);
TS_ASSERT(li->getOutgoingAtom(0) == hna);
TS_ASSERT(li->getOutgoingAtom(1) == hnb);
LinkPtr lli(LinkCast(hlili));
TS_ASSERT(lli->get_arity() == 2);
TS_ASSERT(lli->getOutgoingAtom(0) == hli);
TS_ASSERT(lli->getOutgoingAtom(1) == hli);
as1.clear();
as2.clear();
logger().info("END TEST: %s", __FUNCTION__);
}
// Test recursive remove across atomspaces.
void RemoveUTest::testHeads()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
AtomSpace& as1(*asp1.get());
AtomSpace& as2(*asp2.get());
TS_ASSERT(as1.get_size() == 0);
TS_ASSERT(as2.get_size() == 0);
// Create atoms in different atomspaces
Handle hna = as1.add_node(CONCEPT_NODE, "node a");
Handle hnb = as1.add_node(CONCEPT_NODE, "node b");
Handle hli = as1.add_link(LIST_LINK, hna, hnb);
Handle ho = as2.add_link(LIST_LINK, hna, hnb);
TS_ASSERT(ho == hli);
Handle ha = as1.add_link(LIST_LINK, hna, hnb, hnb);
Handle haha = as1.add_link(LIST_LINK, hna, hnb, hnb, hnb);
Handle hwa = as1.add_link(LIST_LINK, hli, hnb);
as2.add_link(LIST_LINK, hna, hna, hnb);
as2.add_link(LIST_LINK, hna, hna, hna, hnb);
as2.add_link(LIST_LINK, ho, hna, hna);
Handle hoo = as2.add_link(LIST_LINK, ho, ho, ho, ho);
Handle hoho = as2.add_link(LIST_LINK, ho, hoo, hna, ha);
Handle hohox = as2.add_link(LIST_LINK, hoho, ho, hoo, hnb, haha);
Handle hohoy = as2.add_link(LIST_LINK, hna, hoho, ho, hoo, hohox, hwa);
TS_ASSERT(as1.get_size() == 6);
TS_ASSERT(as2.get_size() == 13);
// Verify the link is sane
LinkPtr pli(LinkCast(hli));
TS_ASSERT(pli->get_arity() == 2);
TS_ASSERT(pli->getOutgoingAtom(0) == hna);
TS_ASSERT(pli->getOutgoingAtom(1) == hnb);
// Recursive removal of hna should blow away hli.
as1.extract_atom(hna, true);
TS_ASSERT(as1.get_size() == 1);
TS_ASSERT(as2.get_size() == 1);
// Both hna and hli should still point to valid atoms
LinkPtr li(LinkCast(hli));
TS_ASSERT(li->get_arity() == 2);
TS_ASSERT(li->getOutgoingAtom(0) == hna);
TS_ASSERT(li->getOutgoingAtom(1) == hnb);
as1.clear();
as2.clear();
logger().info("END TEST: %s", __FUNCTION__);
}
// Test recursive remove across atomspaces.
void RemoveUTest::testTails()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
AtomSpace& as1(*asp1.get());
AtomSpace& as2(*asp2.get());
TS_ASSERT(as1.get_size() == 0);
TS_ASSERT(as2.get_size() == 0);
// Create atoms in different atomspaces
Handle hna = as1.add_node(CONCEPT_NODE, "node a");
Handle hnb = as1.add_node(CONCEPT_NODE, "node b");
Handle hli = as1.add_link(LIST_LINK, hna, hnb);
Handle ho = as2.add_link(LIST_LINK, hna, hnb);
TS_ASSERT(ho == hli);
Handle ha = as1.add_link(LIST_LINK, hna, hnb, hnb);
Handle haha = as1.add_link(LIST_LINK, hna, hnb, hnb, hnb);
Handle hwa = as1.add_link(LIST_LINK, hli, hnb);
as2.add_link(LIST_LINK, hna, hna, hnb);
as2.add_link(LIST_LINK, hna, hna, hna, hnb);
as2.add_link(LIST_LINK, ho, hna, hna);
Handle hoo = as2.add_link(LIST_LINK, ho, ho, ho, ho);
Handle hoho = as2.add_link(LIST_LINK, ho, hoo, hna, ha);
Handle hohox = as2.add_link(LIST_LINK, hoho, ho, hoo, hnb, haha);
Handle hohoy = as2.add_link(LIST_LINK, hna, hoho, ho, hoo, hohox, hwa);
TS_ASSERT(as1.get_size() == 6);
TS_ASSERT(as2.get_size() == 13);
as2.extract_atom(hoo, true);
TS_ASSERT(as1.get_size() == 6);
TS_ASSERT(as2.get_size() == 9);
as1.clear();
as2.clear();
logger().info("END TEST: %s", __FUNCTION__);
}