/*
* tests/persist/cog-simple/SimpleFetchUTest.cxxtest
*
* Test atom fetch semantics. Assumes PersistUTest is passing.
* Ported over from original unit test at
* tests/persist/sql/multi-driver/SimpleFetchUTest.cxxtest
*
* Copyright (C) 2017,2019 Linas Vepstas <linasvepstas@gmail.com>
* 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 <cstdio>
#include <opencog/atoms/atom_types/atom_types.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/guile/SchemeEval.h>
#include <opencog/persist/cog-simple/CogSimpleStorage.h>
#include <opencog/atoms/value/FloatValue.h>
#include <opencog/util/Logger.h>
#include "../TestCogServer.h"
using namespace opencog;
class SimpleFetchUTest : public CxxTest::TestSuite
{
private:
std::string uri;
std::string srv_open;
AtomSpacePtr _as;
SchemeEval* eval;
DECLARE_TEST_COGSERVER
public:
SimpleFetchUTest(void);
~SimpleFetchUTest()
{
STOP_TEST_COGSERVER
// erase the log file if no assertions failed
if (!CxxTest::TestTracker::tracker().suiteFailed())
std::remove(logger().get_filename().c_str());
}
void setUp(void);
void tearDown(void);
void atomCompare(Handle, AtomPtr, std::string);
void test_stuff(void);
void xxxtest_readonly(void);
};
SimpleFetchUTest::SimpleFetchUTest(void)
{
logger().set_level(Logger::INFO);
// logger().set_level(Logger::DEBUG);
logger().set_print_to_stdout_flag(true);
// logger().set_sync_flag(true);
uri = "cog://localhost:16304";
srv_open = "(cog-open (CogSimpleStorageNode \"" + uri + "\"))\n";
INIT_TEST_COGSERVER(16304);
printf("Started CogServer\n");
}
/*
* This is called once before each test, for each test (!!)
*/
void SimpleFetchUTest::setUp(void)
{
_as = createAtomSpace();
eval = SchemeEval::get_scheme_evaluator(_as);
}
void SimpleFetchUTest::tearDown(void)
{
_as = nullptr;
}
// ============================================================
void SimpleFetchUTest::atomCompare(Handle a, AtomPtr b, std::string where)
{
printf("Check %s expect %s\n", where.c_str(), a->to_string().c_str());
TSM_ASSERT("No atom found", b != nullptr);
if (nullptr == b) return;
TSM_ASSERT_EQUALS("Type mismatch", a->get_type(), b->get_type());
NodePtr na(NodeCast(a));
NodePtr nb(NodeCast(b));
if (na and nb)
{
TSM_ASSERT_EQUALS("Name mismatch", na->get_name(), nb->get_name());
}
LinkPtr la(LinkCast(a));
LinkPtr lb(LinkCast(b));
if (la and lb)
{
TSM_ASSERT_EQUALS("Arity mismatch", la->get_arity(), lb->get_arity());
if (*la != *lb)
{
printf("Mismatching la = %s\n", la->to_string().c_str());
printf("Mismatching lb = %s\n", lb->to_string().c_str());
TSM_ASSERT_EQUALS("Link mis-match", la, lb);
}
}
FloatValuePtr ta = FloatValueCast(a->getValue(truth_key()));
FloatValuePtr tb = FloatValueCast(b->getValue(truth_key()));
if (ta or tb)
{
TSM_ASSERT("Missing truth value", ta);
TSM_ASSERT("Missing truth value", tb);
if (ta and tb)
{
TSM_ASSERT("Truth value miscompare", (*ta)==(*tb));
if (not ((*ta) == (*tb)))
{
fprintf(stderr, "Error, truth value miscompare, "
"ma=%f mb=%f ca=%f cb=%f\n",
ta->value()[0], tb->value()[0], ta->value()[1], tb->value()[1]);
}
}
}
}
// ============================================================
#define CHKERR \
TSM_ASSERT("Caught scm error during eval", \
(false == eval->eval_error())); \
if (eval->eval_error()) \
printf("Error was %s\n", eval->get_error_string().c_str());
void SimpleFetchUTest::test_stuff(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
// First, initialize the database
eval->eval("(use-modules (opencog persist))");
CHKERR;
eval->eval("(use-modules (opencog persist-cog-simple))");
CHKERR;
eval->eval(srv_open);
CHKERR;
eval->eval(R"((define tvkey (Predicate "*-TruthValueKey-*")))");
eval->eval(R"((cog-set-value! (Concept "AAA") tvkey (FloatValue 0.1 0.11)))");
eval->eval(R"((cog-set-value! (Concept "BBB") tvkey (FloatValue 0.2 0.22)))");
eval->eval("(store-atomspace)");
CHKERR;
eval->eval("(cog-close)");
CHKERR;
_as = createAtomSpace();
eval = SchemeEval::get_scheme_evaluator(_as);
CHKERR;
eval->eval(srv_open);
CHKERR;
eval->eval(R"((fetch-atom (List (Concept "AAA") (Concept "BBB"))))");
CHKERR;
// The above should NOT update the TV of (Concept "AAA")
ValuePtr tv = eval->eval_v(R"((cog-value (Concept "AAA") tvkey))");
TS_ASSERT(tv == nullptr);
// If we fetch the TV explicitly, then we should get the
// value from the database.
eval->eval(R"((fetch-atom (Concept "AAA")))");
tv = eval->eval_v(R"((cog-value (Concept "AAA") tvkey))");
ValuePtr etv = createFloatValue(std::vector<double>{0.1, 0.11});
TS_ASSERT((*tv) == (*etv));
printf("Expecting %s\n", etv->to_string().c_str());
printf("Got %s\n", tv->to_string().c_str());
// Update A.
eval->eval(R"((cog-set-value! (Concept "AAA") tvkey (FloatValue 0.3 0.33)))");
// Saving everything should not crash. It should, however,
// change the TV on (Concept "BBB") back to DEFAULT_TV.
eval->eval("(store-atomspace)");
eval->eval("(cog-close)");
_as = createAtomSpace();
eval = SchemeEval::get_scheme_evaluator(_as);
eval->eval(srv_open);
// AAA should have been updated, as above.
eval->eval(R"((fetch-atom (Concept "AAA")))");
tv = eval->eval_v(R"((cog-value (Concept "AAA") tvkey))");
etv = createFloatValue(std::vector<double>{0.3, 0.33});
TS_ASSERT((*tv) == (*etv));
printf("Expecting %s\n", etv->to_string().c_str());
printf("Got %s\n", tv->to_string().c_str());
// BBB should have been clobbered.
eval->eval(R"((fetch-atom (Concept "BBB")))");
tv = eval->eval_v(R"((cog-value (Concept "BBB") tvkey))");
TS_ASSERT(tv == nullptr);
eval->eval("(cog-close)");
logger().debug("END TEST: %s", __FUNCTION__);
}
// ============================================================
// Disable this unit test, for now. The new messaging-API style
// prevents easy solutions to the management of read-only AtomSpaces.
//
// There are three issues:
// 1) The message to be sent must already be in the AtomSpace,
// before it is marked read-only.
// 2) The (TypeNode type) must be likewise.
// 3) Read-only AtomSpaces block the set-value call/method, and so
// messages cannot be sent to atoms in a read-only AtomSpace.
//
// The concept of read-only needs to be re-examined in the light of
// message-passing interfaces. The current semantics are unclear and
// of little utility.
void SimpleFetchUTest::xxxtest_readonly(void)
{
logger().debug("BEGIN TEST: %s", __FUNCTION__);
// First, initialize the database
eval->eval("(use-modules (opencog persist) (opencog persist-cog-simple))");
eval->eval(srv_open);
eval->eval(R"((define tvkey (Predicate "*-TruthValueKey-*")))");
eval->eval(R"((cog-set-value! (Concept "AAA") tvkey (FloatValue 0.1 0.11)))");
eval->eval(R"((cog-set-value! (Concept "BBB") tvkey (FloatValue 0.2 0.22)))");
eval->eval(R"((List (Concept "AAA") (Concept "BBB")))");
eval->eval("(store-atomspace)");
eval->eval("(cog-close)");
_as = createAtomSpace();
eval = SchemeEval::get_scheme_evaluator(_as);
eval->eval(srv_open);
_as->set_read_only();
// Despite the AtomSpace being readonly, we should still be
// able to load atoms from the database.
eval->eval(R"((load-atoms-of-type 'ConceptNode))");
std::string prt = eval->eval("(cog-prt-atomspace)");
printf("Atomspace contents:\n%s\n", prt.c_str());
Handle a = eval->eval_h(R"((Concept "AAA"))");
TS_ASSERT(nullptr != a);
ValuePtr tv = eval->eval_v(R"((cog-value (Concept "AAA") tvkey))");
ValuePtr etv = createFloatValue(std::vector<double>{0.1, 0.11});
TS_ASSERT((*tv) == (*etv));
printf("Expecting %s\n", etv->to_string().c_str());
printf("Got %s\n", tv->to_string().c_str());
// No one is messing with the flag, eh?
TS_ASSERT(true == _as->get_read_only());
Handle c = _as->add_node(CONCEPT_NODE, "foobar");
TS_ASSERT(c == nullptr);
// Try to change TV on A -- should fail; should get old value.
// We should get an assert, for good measure.
// The assert is turned into an evaluator error.
TS_ASSERT(false == eval->eval_error());
eval->clear_pending();
eval->eval(R"((cog-set-value! (Concept "AAA") tvkey (FloatValue 0.3 0.33)))");
TS_ASSERT(eval->eval_error());
eval->clear_pending();
tv = eval->eval_v(R"((cog-value (Concept "AAA") tvkey))");
TS_ASSERT((*tv) == (*etv));
// Should be possible to extract, even though its read-only
TS_ASSERT(4 == _as->get_size());
eval->eval(R"((cog-extract! (Concept "AAA")))");
eval->eval(R"((cog-extract! (Concept "BBB")))");
TS_ASSERT(2 == _as->get_size());
// And re-load them again.
eval->eval(R"((load-atoms-of-type 'ConceptNode))");
TS_ASSERT(4 == _as->get_size());
TS_ASSERT(true == _as->get_read_only());
Handle d = _as->add_node(CONCEPT_NODE, "barfoo");
TS_ASSERT(d == nullptr);
TS_ASSERT(4 == _as->get_size());
eval->eval("(cog-close)");
logger().debug("END TEST: %s", __FUNCTION__);
}
/* ============================= END OF FILE ================= */