OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomspace-storage / tests / persist / sexpr / FastLoadUTest.cxxtest

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