/*
* FastLoadUTest.cxxtest
*
* Copyright (c) 2020 OpenCog Foundation
* 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 <iomanip>
#include <opencog/atoms/value/FloatValue.h>
#include <opencog/atoms/value/LinkValue.h>
#include <opencog/persist/file/fast_load.h>
#include <opencog/persist/sexpr/Sexpr.h>
using namespace opencog;
class FastLoadUTest : public CxxTest::TestSuite {
private:
AtomSpacePtr _asp;
public:
FastLoadUTest() {
logger().set_print_to_stdout_flag(true);
_asp = createAtomSpace();
}
void setUp() { _asp->clear(); }
void tearDown() {}
void test_expr_parse();
void test_quoted_node();
void test_pattern_parse();
void test_dense_parse();
void test_dense_loop();
void test_value();
void test_value_mix();
void test_null_value();
void test_escapes();
};
// Test parseExpression
void FastLoadUTest::test_expr_parse()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
std::string in = R"((Evaluation (Predicate "is_a") (List (Concept "Earth") (Concept "Planet"))))";
Handle h = parseExpression(in, _asp);
TS_ASSERT_EQUALS(5, _asp->get_size());
TS_ASSERT_EQUALS(2, h->getOutgoingSet().size());
logger().info("END TEST: %s", __FUNCTION__);
}
// Test parseExpression
void FastLoadUTest::test_quoted_node()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
std::stringstream ss;
ss << "(Concept " << std::quoted(R"("f""o"""o"!!!"")") << ")";
std::string in = ss.str();
printf("Input string %s\n", in.c_str());
Handle h = parseExpression(in, _asp);
printf("Parsed Atom h=%s\n", h->to_short_string().c_str());
Handle expected = _asp->get_node(CONCEPT_NODE, R"("f""o"""o"!!!"")");
TS_ASSERT (expected != nullptr);
printf("Got %s\n", expected->to_short_string().c_str());
TS_ASSERT_EQUALS(h, expected);
logger().info("END TEST: %s", __FUNCTION__);
}
void FastLoadUTest::test_pattern_parse()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
std::string input_sym = "(Meet\n"
" (VariableList\n"
" (TypedVariable (Variable \"$a\") (Type 'Concept)))\n"
" (Evaluation (Predicate \"test\")\n"
" (List (Variable \"$a\") (Concept \"A\"))))";
std::string input_not_sym = "(Meet\n"
" (VariableList\n"
" (TypedVariable (Variable \"$a\") (Type \"Concept\")))\n"
" (Evaluation (Predicate \"test\")\n"
" (List (Variable \"$a\") (Concept \"A\"))))";
_asp->clear();
Handle h = parseExpression(input_sym, _asp);
// This test adds 9 atoms. Pluse one: (Predicate "*-IsKeyFlag-*")
TS_ASSERT_EQUALS(10, _asp->get_size());
TS_ASSERT_EQUALS(2, h->getOutgoingSet().size());
_asp->clear();
h = parseExpression(input_not_sym, _asp);
TS_ASSERT_EQUALS(10, _asp->get_size());
TS_ASSERT_EQUALS(2, h->getOutgoingSet().size());
logger().info("END TEST: %s", __FUNCTION__);
}
void FastLoadUTest::test_dense_parse()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
std::string in = R"#((SetLink (NumberNode "4.1415930000000003")(SchemaNode "? EE-ee-wow third ? wheel")(SchemaNode "EE-ee-wow fromNode")(SchemaNode "EE-ee-wow toNode")) (SetLink (NumberNode "0.141593")(SchemaNode "? AA-aa-wow third ? wheel")(SchemaNode "AA-aa-wow fromNode")(SchemaNode "AA-aa-wow toNode")) (SetLink (SchemaNode "CC-cc-wow toNode")(SchemaNode "? CC-cc-wow third ? wheel")(SchemaNode "CC-cc-wow fromNode")(NumberNode "2.1415929999999999")) (SetLink (SchemaNode "BB-bb-wow toNode")(SchemaNode "BB-bb-wow fromNode")(SchemaNode "? BB-bb-wow third ? wheel")(NumberNode "1.1415930000000001")) (SetLink (SchemaNode "DD-dd-wow fromNode")(SchemaNode "DD-dd-wow toNode")(NumberNode "3.1415929999999999")(SchemaNode "? DD-dd-wow third ? wheel")) (PredicateNode "*-TruthValueKey-*"))#";
_asp->clear();
parseExpression(in, _asp);
TS_ASSERT_EQUALS(26, _asp->get_size());
logger().info("END TEST: %s", __FUNCTION__);
}
void FastLoadUTest::test_dense_loop()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
std::string expr = R"#(((SetLink (NumberNode "4.1415930000000003")(SchemaNode "? EE-ee-wow third ? wheel")(SchemaNode "EE-ee-wow fromNode")(SchemaNode "EE-ee-wow toNode")) (SetLink (NumberNode "0.141593")(SchemaNode "? AA-aa-wow third ? wheel")(SchemaNode "AA-aa-wow fromNode")(SchemaNode "AA-aa-wow toNode")) (SetLink (SchemaNode "CC-cc-wow toNode")(SchemaNode "? CC-cc-wow third ? wheel")(SchemaNode "CC-cc-wow fromNode")(NumberNode "2.1415929999999999")) (SetLink (SchemaNode "BB-bb-wow toNode")(SchemaNode "BB-bb-wow fromNode")(SchemaNode "? BB-bb-wow third ? wheel")(NumberNode "1.1415930000000001")) (SetLink (SchemaNode "DD-dd-wow fromNode")(SchemaNode "DD-dd-wow toNode")(NumberNode "3.1415929999999999")(SchemaNode "? DD-dd-wow third ? wheel")) (PredicateNode "*-TruthValueKey-*")))#";
int expect[] = {146, 137, 147, 146, 146, 34};
_asp->clear();
size_t l = expr.find('(') + 1; // skip the first paren.
size_t end = expr.rfind(')'); // trim tailing paren.
size_t r = end;
int nex = 0;
while (true)
{
int pcnt = Sexpr::get_next_expr(expr, l, r, 0);
if (l == r) break;
if (0 < pcnt) break;
std::string subex = expr.substr(l,r-l);
TS_ASSERT_EQUALS(subex.length(), expect[nex]);
// advance to next.
l = r+1;
r = end;
nex++;
}
TS_ASSERT_EQUALS(6, nex);
logger().info("END TEST: %s", __FUNCTION__);
}
void FastLoadUTest::test_value()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
std::string in = "(LinkValue\n(Predicate \"is_a\")(List "
"(Concept \"Earth\")\t (Concept \"Planet\")))";
size_t pos = 0;
ValuePtr vp = Sexpr::decode_value(in, pos);
TS_ASSERT_EQUALS(vp->get_type(), LINK_VALUE);
const std::vector<ValuePtr>& lks = LinkValueCast(vp)->value();
TS_ASSERT_EQUALS(2, lks.size());
TS_ASSERT_EQUALS(lks[0]->get_type(), PREDICATE_NODE);
TS_ASSERT_EQUALS(lks[1]->get_type(), LIST_LINK);
Handle lk = HandleCast(lks[1]);
TS_ASSERT_EQUALS(2, lk->get_arity());
HandleSeq oset = lk->getOutgoingSet();
TS_ASSERT_EQUALS(oset[0]->get_type(), CONCEPT_NODE);
TS_ASSERT_EQUALS(oset[1]->get_type(), CONCEPT_NODE);
logger().info("END TEST: %s", __FUNCTION__);
}
void FastLoadUTest::test_value_mix()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
std::string in = "(LinkValue\n(Type 'Number)"
"(FloatValue 1596144865))";
size_t pos = 0;
ValuePtr vp = Sexpr::decode_value(in, pos);
TS_ASSERT_EQUALS(vp->get_type(), LINK_VALUE);
const std::vector<ValuePtr>& lks = LinkValueCast(vp)->value();
TS_ASSERT_EQUALS(2, lks.size());
TS_ASSERT_EQUALS(lks[0]->get_type(), TYPE_NODE);
TS_ASSERT_EQUALS(lks[1]->get_type(), FLOAT_VALUE);
Handle lk = HandleCast(lks[0]);
TS_ASSERT_EQUALS("NumberNode", lk->get_name());
FloatValuePtr fvp = FloatValueCast(lks[1]);
TS_ASSERT_EQUALS(fvp->value().size(), 1);
logger().info("END TEST: %s", __FUNCTION__);
}
void FastLoadUTest::test_null_value()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
std::string in = "#f)) (Concept \"foo\")";
// No exceptions should be thrown, there should be no errors.
size_t pos = 0;
ValuePtr vp = Sexpr::decode_value(in, pos);
TS_ASSERT_EQUALS(vp, nullptr);
TS_ASSERT_EQUALS(pos, 2);
// -------------
in = "#f";
// No exceptions should be thrown, there should be no errors.
pos = 0;
vp = Sexpr::decode_value(in, pos);
TS_ASSERT_EQUALS(vp, nullptr);
TS_ASSERT_EQUALS(pos, 2);
logger().info("END TEST: %s", __FUNCTION__);
}
// Test parseExpression
void FastLoadUTest::test_escapes()
{
logger().info("BEGIN TEST: %s", __FUNCTION__);
std::string in = R"((List (Concept "Zek.\\") (Concept "Planet")))";
printf("Going to parse >>%s<<\n", in.c_str());
Handle h = parseExpression(in, _asp);
TS_ASSERT_EQUALS(3, _asp->get_size());
TS_ASSERT_EQUALS(2, h->getOutgoingSet().size());
in = R"((List (Concept "Zek.\\;\"\n\r\a\b\"") (Concept "Planet")))";
printf("Going to parse >>%s<<\n", in.c_str());
h = parseExpression(in, _asp);
TS_ASSERT_EQUALS(5, _asp->get_size());
TS_ASSERT_EQUALS(2, h->getOutgoingSet().size());
in = R"((List (Concept "Zek.\\;\"\t\t\v\f\"") (Concept "Planet")) )";
printf("Going to parse >>%s<<\n", in.c_str());
h = parseExpression(in, _asp);
TS_ASSERT_EQUALS(7, _asp->get_size());
TS_ASSERT_EQUALS(2, h->getOutgoingSet().size());
in = R"((List (Concept "Zek.\\;\"\t\"\b\a\"") (Concept "Planet")); backspace bell)";
printf("Going to parse >>%s<<\n", in.c_str());
h = parseExpression(in, _asp);
TS_ASSERT_EQUALS(9, _asp->get_size());
TS_ASSERT_EQUALS(2, h->getOutgoingSet().size());
in = R"((List (Concept "Zek.\\;\t;;(\a)\"") (Concept "Planet")) ; what)";
printf("Going to parse >>%s<<\n", in.c_str());
h = parseExpression(in, _asp);
TS_ASSERT_EQUALS(11, _asp->get_size());
TS_ASSERT_EQUALS(2, h->getOutgoingSet().size());
in = R"((List (Concept "Zek.\\;\"\t\"\b\a\"") (Concept "Planet")) (Concept "more") ; more more)";
printf("Going to parse >>%s<<\n", in.c_str());
h = parseExpression(in, _asp);
TS_ASSERT_EQUALS(12, _asp->get_size());
TS_ASSERT_EQUALS(CONCEPT_NODE, h->get_type());
logger().info("END TEST: %s", __FUNCTION__);
}