OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace / tests / atoms / HashUTest.cxxtest

219 lines · cxxtest ref:
/*
 * tests/atoms/HashUTest.cxxtest
 *
 * Copyright (C) 2018 OpenCog Foundation
 * 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/atoms/base/Atom.h>
#include <opencog/atoms/base/Node.h>
#include <opencog/atoms/base/Link.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/scope/ScopeLink.h>

#include <cxxtest/TestSuite.h>

using namespace opencog;

#define an _asp->add_node
#define al _asp->add_link

// Test Atom::compute_hash(), in particular whether 2 different atoms
// have different hashes. Atom hash collisions are impossible to
// completely eliminate, but we can avoid obviously pathological ones.
//
class HashUTest :  public CxxTest::TestSuite
{
private:
	AtomSpacePtr _asp;
	SchemeEval* _eval;

public:
	HashUTest() : _asp(createAtomSpace()), _eval(SchemeEval::get_scheme_evaluator(_asp))
	{
		logger().set_timestamp_flag(false);
		logger().set_print_to_stdout_flag(true);

		_eval->eval("(add-to-load-path \"" PROJECT_SOURCE_DIR "\")");
		_eval->eval("(load-from-path \"tests/atoms/hash.scm\")");
	}

	void setUp() {}

	void tearDown() {}

	// Test hash collisions of scope links
	void test_scope_compute_hash_1();
	void test_scope_compute_hash_2();
	void test_scope_compute_hash_3();
	void test_scope_compute_hash_4();
	void test_scope_compute_hash_5();

	// Test hash collisions of non-scope links
	void test_sequential_compute_hash();
	void test_times_plus_compute_hash();

	// Test that unordered links have the same hash regardless of the
	// order of their outgoing set. These do not have their own ctors,
	// and so are more easily messed up by uncareful edits to
	// atom_types.script.
	void test_equallink();
	void test_andor();
};

void HashUTest::test_scope_compute_hash_1()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	Handle bl1 = _eval->eval_h("bl-1"),
		bl2 = _eval->eval_h("bl-2");

	TS_ASSERT_DIFFERS(bl1.value(), bl2.value());

	logger().info("END TEST: %s", __FUNCTION__);
}

void HashUTest::test_scope_compute_hash_2()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	Handle gl1 = _eval->eval_h("gl-1"),
		gl2 = _eval->eval_h("gl-2");

	TS_ASSERT_DIFFERS(gl1.value(), gl2.value());

	logger().info("END TEST: %s", __FUNCTION__);
}

void HashUTest::test_scope_compute_hash_3(){
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	Handle h1 = _eval->eval_h("ll-1");
	Handle h2 = _eval->eval_h("ll-2");
	TS_ASSERT_DIFFERS(h1.value(), h2.value());

	h1 = _eval->eval_h("ll-3");
	h2 = _eval->eval_h("ll-4");
	TS_ASSERT_DIFFERS(h1.value(), h2.value());

	h1 = _eval->eval_h("ll-5");
	h2 = _eval->eval_h("ll-6");
	TS_ASSERT_DIFFERS(h1.value(), h2.value());

	logger().info("END TEST: %s", __FUNCTION__);
}

void HashUTest::test_scope_compute_hash_4()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	Handle bl3 = _eval->eval_h("bl-3"),
		bl4 = _eval->eval_h("bl-4");

	TS_ASSERT_DIFFERS(bl3.value(), bl4.value());

	logger().info("END TEST: %s", __FUNCTION__);
}

void HashUTest::test_scope_compute_hash_5()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	Handle bl5 = _eval->eval_h("bl-5"),
		bl6 = _eval->eval_h("bl-6");

	TS_ASSERT_DIFFERS(bl5.value(), bl6.value());

	logger().info("END TEST: %s", __FUNCTION__);
}

void HashUTest::test_sequential_compute_hash()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	Handle sal = _eval->eval_h("sal"),
		sol = _eval->eval_h("sol");

	TS_ASSERT_DIFFERS(sal.value(), sol.value());

	logger().info("END TEST: %s", __FUNCTION__);
}

void HashUTest::test_times_plus_compute_hash()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	Handle tl = _eval->eval_h("tl"),
		pl = _eval->eval_h("pl");

	TS_ASSERT_DIFFERS(tl.value(), pl.value());

	logger().info("END TEST: %s", __FUNCTION__);
}

void
HashUTest::test_equallink()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	// This test fails, if someone monkeys with the atom_types.script
	// file and gets it wrong.
	Handle X = an(VARIABLE_NODE, "$X");
	Handle Y = an(VARIABLE_NODE, "$Y");
	Handle EqXY = al(EQUAL_LINK, X, Y);
	Handle EqYX = al(EQUAL_LINK, Y, X);

	TS_ASSERT_EQUALS(EqXY.value(), EqYX.value());

	// ----------------------------
	// Should be symmetric, as well.
	Handle IdXY = al(IDENTICAL_LINK, X, Y);
	Handle IdYX = al(IDENTICAL_LINK, Y, X);

	TS_ASSERT_EQUALS(IdXY.value(), IdYX.value());

	// ----------------------------
	Handle EqvXY = al(EQUIVALENCE_LINK, X, Y);
	Handle EqvYX = al(EQUIVALENCE_LINK, Y, X);

	TS_ASSERT_EQUALS(EqvXY.value(), EqvYX.value());
}

void
HashUTest::test_andor()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	// This test fails, if someone monkeys with the atom_types.script
	// file and gets it wrong.
	Handle X = an(VARIABLE_NODE, "$X");
	Handle Y = an(VARIABLE_NODE, "$Y");
	Handle AndXY = al(AND_LINK, X, Y);
	Handle AndYX = al(AND_LINK, Y, X);

	TS_ASSERT_EQUALS(AndXY.value(), AndYX.value());

	// ----------------------------
	// Should be symmetric, as well.
	Handle OrXY = al(OR_LINK, X, Y);
	Handle OrYX = al(OR_LINK, Y, X);

	TS_ASSERT_EQUALS(OrXY.value(), OrYX.value());
}