OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace-storage / tests / persist / json / SexTunnelUTest.cxxtest

188 lines · cxxtest ref:
/*
 * SexTunnelUTest.cxxtest
 * Test s-expression tunneling through JSON
 *
 * Copyright (c) 2025 Linas Vepstas
 * SPDX-License-Identifier: AGPL-3.0-or-later
 *
 * 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/util/Logger.h>
#include <opencog/atomspace/AtomSpace.h>
#include <opencog/atoms/base/Node.h>
#include <opencog/atoms/base/Link.h>
#include <opencog/atoms/value/FloatValue.h>
#include <opencog/atoms/value/StringValue.h>

#include "opencog/persist/json/Json.h"

using namespace opencog;

class SexTunnelUTest : public CxxTest::TestSuite
{
private:
	AtomSpacePtr as;

public:
	SexTunnelUTest()
	{
		logger().set_print_to_stdout_flag(true);
		as = createAtomSpace();
	}

	void setUp() { as->clear(); }
	void tearDown() {}

	void test_simple_node();
	void test_simple_link();
	void test_escaped_quotes();
	void test_nested_expression();
	void test_regular_json_still_works();
	void test_value_float();
	void test_value_string();
};

// Test simple node in s-expression format
void SexTunnelUTest::test_simple_node()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	std::string json = R"jsn({"atomese": "(Concept \"test\")"})jsn";
	Handle h = Json::decode_atom(json);

	TS_ASSERT(h != nullptr);
	TS_ASSERT_EQUALS(h->get_type(), CONCEPT_NODE);
	TS_ASSERT_EQUALS(h->get_name(), "test");

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

// Test simple link in s-expression format
void SexTunnelUTest::test_simple_link()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	std::string json = R"jsn({"atomese": "(List (Concept \"a\") (Concept \"b\"))"})jsn";
	Handle h = Json::decode_atom(json);

	TS_ASSERT(h != nullptr);
	TS_ASSERT_EQUALS(h->get_type(), LIST_LINK);
	TS_ASSERT_EQUALS(h->get_arity(), 2);

	HandleSeq oset = h->getOutgoingSet();
	TS_ASSERT_EQUALS(oset[0]->get_name(), "a");
	TS_ASSERT_EQUALS(oset[1]->get_name(), "b");

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

// Test s-expression with escaped quotes
void SexTunnelUTest::test_escaped_quotes()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	std::string json = R"jsn({"atomese": "(Evaluation (Predicate \"foo\") (List (Concept \"bar\")))"})jsn";
	Handle h = Json::decode_atom(json);

	TS_ASSERT(h != nullptr);
	TS_ASSERT_EQUALS(h->get_type(), EVALUATION_LINK);
	TS_ASSERT_EQUALS(h->get_arity(), 2);

	HandleSeq oset = h->getOutgoingSet();
	TS_ASSERT_EQUALS(oset[0]->get_type(), PREDICATE_NODE);
	TS_ASSERT_EQUALS(oset[0]->get_name(), "foo");
	TS_ASSERT_EQUALS(oset[1]->get_type(), LIST_LINK);

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

// Test nested expression
void SexTunnelUTest::test_nested_expression()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	std::string json = R"jsn({"atomese": "(Inheritance (Concept \"cat\") (Concept \"mammal\"))"})jsn";
	Handle h = Json::decode_atom(json);

	TS_ASSERT(h != nullptr);
	TS_ASSERT_EQUALS(h->get_type(), INHERITANCE_LINK);

	HandleSeq oset = h->getOutgoingSet();
	TS_ASSERT_EQUALS(oset[0]->get_name(), "cat");
	TS_ASSERT_EQUALS(oset[1]->get_name(), "mammal");

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

// Test that regular JSON format still works
void SexTunnelUTest::test_regular_json_still_works()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	std::string json = R"({"type": "ConceptNode", "name": "regular"})";
	Handle h = Json::decode_atom(json);

	TS_ASSERT(h != nullptr);
	TS_ASSERT_EQUALS(h->get_type(), CONCEPT_NODE);
	TS_ASSERT_EQUALS(h->get_name(), "regular");

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

// Test FloatValue in s-expression format
void SexTunnelUTest::test_value_float()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	std::string json = R"jsn({"atomese": "(FloatValue 1.5 2.5 3.5)"})jsn";
	size_t lo = 0, ro = json.size();
	ValuePtr v = Json::decode_value(json, lo, ro);

	TS_ASSERT(v != nullptr);
	TS_ASSERT_EQUALS(v->get_type(), FLOAT_VALUE);

	FloatValuePtr fv = FloatValueCast(v);
	TS_ASSERT(fv != nullptr);
	TS_ASSERT_EQUALS(fv->value().size(), 3);
	TS_ASSERT_DELTA(fv->value()[0], 1.5, 0.001);
	TS_ASSERT_DELTA(fv->value()[1], 2.5, 0.001);
	TS_ASSERT_DELTA(fv->value()[2], 3.5, 0.001);

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

// Test StringValue in s-expression format
void SexTunnelUTest::test_value_string()
{
	logger().info("BEGIN TEST: %s", __FUNCTION__);

	std::string json = R"jsn({"atomese": "(StringValue \"hello\" \"world\")"})jsn";
	size_t lo = 0, ro = json.size();
	ValuePtr v = Json::decode_value(json, lo, ro);

	TS_ASSERT(v != nullptr);
	TS_ASSERT_EQUALS(v->get_type(), STRING_VALUE);

	StringValuePtr sv = StringValueCast(v);
	TS_ASSERT(sv != nullptr);
	TS_ASSERT_EQUALS(sv->value().size(), 2);
	TS_ASSERT_EQUALS(sv->value()[0], "hello");
	TS_ASSERT_EQUALS(sv->value()[1], "world");

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