OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace / tests / atomspace / RemoveUTest.cxxtest

417 lines · cxxtest ref:
/*
 * 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__);
}