diff --git a/src/agents/query_engine/MettaParserActions.cc b/src/agents/query_engine/MettaParserActions.cc index 0ef74b17..aa473166 100644 --- a/src/agents/query_engine/MettaParserActions.cc +++ b/src/agents/query_engine/MettaParserActions.cc @@ -129,6 +129,7 @@ void MettaParserActions::expression_end(bool toplevel, const string& metta_expre targets, this->proxy->get_context(), this->proxy->parameters.get(PatternMatchingQueryProxy::POSITIVE_IMPORTANCE_FLAG), + this->proxy->parameters.get(PatternMatchingQueryProxy::UNIQUE_VALUE_FLAG), this->proxy->parameters.get(BaseQueryProxy::USE_LINK_TEMPLATE_CACHE))); } } else if ((this->current_expression_type == AND) || (this->current_expression_type == OR)) { diff --git a/src/agents/query_engine/PatternMatchingQueryProcessor.cc b/src/agents/query_engine/PatternMatchingQueryProcessor.cc index 06bfa974..b6b51417 100644 --- a/src/agents/query_engine/PatternMatchingQueryProcessor.cc +++ b/src/agents/query_engine/PatternMatchingQueryProcessor.cc @@ -342,6 +342,7 @@ shared_ptr PatternMatchingQueryProcessor::build_link_template( targets, proxy->get_context(), proxy->parameters.get(PatternMatchingQueryProxy::POSITIVE_IMPORTANCE_FLAG), + proxy->parameters.get(PatternMatchingQueryProxy::UNIQUE_VALUE_FLAG), proxy->parameters.get(BaseQueryProxy::USE_LINK_TEMPLATE_CACHE)); return link_template; } diff --git a/src/agents/query_engine/PatternMatchingQueryProxy.cc b/src/agents/query_engine/PatternMatchingQueryProxy.cc index 58972e34..0460fc4d 100644 --- a/src/agents/query_engine/PatternMatchingQueryProxy.cc +++ b/src/agents/query_engine/PatternMatchingQueryProxy.cc @@ -13,6 +13,7 @@ using namespace query_engine; string PatternMatchingQueryProxy::COUNT = "count"; string PatternMatchingQueryProxy::POSITIVE_IMPORTANCE_FLAG = "positive_importance_flag"; +string PatternMatchingQueryProxy::UNIQUE_VALUE_FLAG = "unique_value_flag"; string PatternMatchingQueryProxy::COUNT_FLAG = "count_flag"; PatternMatchingQueryProxy::PatternMatchingQueryProxy() { @@ -31,6 +32,7 @@ PatternMatchingQueryProxy::PatternMatchingQueryProxy(const vector& token void PatternMatchingQueryProxy::set_default_parameters() { this->parameters[POSITIVE_IMPORTANCE_FLAG] = false; + this->parameters[UNIQUE_VALUE_FLAG] = false; this->parameters[COUNT_FLAG] = false; } diff --git a/src/agents/query_engine/PatternMatchingQueryProxy.h b/src/agents/query_engine/PatternMatchingQueryProxy.h index bfc4e036..65ebd944 100644 --- a/src/agents/query_engine/PatternMatchingQueryProxy.h +++ b/src/agents/query_engine/PatternMatchingQueryProxy.h @@ -32,10 +32,19 @@ class PatternMatchingQueryProxy : public BaseQueryProxy { static string COUNT; // Delivery of the final result of a count_only query // Query command's optional parameters - static string POSITIVE_IMPORTANCE_FLAG; // Indicates that only answres whose importance > 0 + static string POSITIVE_IMPORTANCE_FLAG; // Indicates that only answers whose importance > 0 // are supposed to be returned - static string COUNT_FLAG; // indicates that this query is supposed to count the results and not + static string UNIQUE_VALUE_FLAG; // When true, QueryAnswers won't be allowed to have the same + // handle assigned to different values. For instance, if a + // variable V1 is assigned to a handle H1, if this parameter + // is true then it's assured that no other variable will be + // assigned with the same value H1. When this parameter is + // false (which is the default value, btw), it's possible + // to have a QueryAnswer with an assignment like this, for + // example: V1: H1, V2: H2, V3, H1. + + static string COUNT_FLAG; // Indicates that this query is supposed to count the results and not // actually provide the query answers (i.e. no QueryAnswer is sent // from the command executor and the caller of the query). diff --git a/src/agents/query_engine/query_element/LinkTemplate.cc b/src/agents/query_engine/query_element/LinkTemplate.cc index 17958e3a..8f3996d6 100644 --- a/src/agents/query_engine/query_element/LinkTemplate.cc +++ b/src/agents/query_engine/query_element/LinkTemplate.cc @@ -21,11 +21,13 @@ LinkTemplate::LinkTemplate(const string& type, const vector>& targets, const string& context, bool positive_importance_flag, + bool unique_value_flag, bool use_cache) : link_schema(type, targets.size()) { this->targets = targets; this->context = context; this->positive_importance_flag = positive_importance_flag; + this->unique_value_flag = unique_value_flag; this->use_cache = use_cache; this->inner_flag = true; this->arity = targets.size(); @@ -134,6 +136,7 @@ void LinkTemplate::processor_method(shared_ptr monitor) { LinkTemplate::fetched_links_cache().set(link_schema_handle, handles); } LOG_DEBUG("Positive importance flag: " + string(this->positive_importance_flag ? "true" : "false")); + LOG_DEBUG("Unique value flag: " + string(this->unique_value_flag ? "true" : "false")); LOG_INFO("Fetched " + std::to_string(handles->size()) + " atoms in " + link_schema_handle); vector> tagged_handles; @@ -147,7 +150,7 @@ void LinkTemplate::processor_method(shared_ptr monitor) { } unsigned int pending = tagged_handles.size(); unsigned int cursor = 0; - Assignment assignment; + Assignment assignment(this->unique_value_flag); unsigned int count_matched = 0; while ((pending > 0) && !monitor->stopped()) { pair tagged_handle = tagged_handles[cursor++]; diff --git a/src/agents/query_engine/query_element/LinkTemplate.h b/src/agents/query_engine/query_element/LinkTemplate.h index 4e23f3ce..a4e50980 100644 --- a/src/agents/query_engine/query_element/LinkTemplate.h +++ b/src/agents/query_engine/query_element/LinkTemplate.h @@ -54,6 +54,7 @@ class LinkTemplate : public QueryElement { vector> targets; string context; bool positive_importance_flag; + bool unique_value_flag; bool use_cache; bool inner_flag; LinkSchema link_schema; @@ -73,6 +74,7 @@ class LinkTemplate : public QueryElement { const vector>& targets, const string& context, bool positive_importance_flag, + bool unique_value_flag, bool use_cache); void build(); diff --git a/src/commons/Assignment.cc b/src/commons/Assignment.cc index 5078679a..4784593c 100644 --- a/src/commons/Assignment.cc +++ b/src/commons/Assignment.cc @@ -9,7 +9,9 @@ using namespace commons; string Assignment::EMPTY_VALUE = ""; -Assignment::Assignment() {} +Assignment::Assignment(bool unique_assignment_flag) { + this->unique_assignment_flag = unique_assignment_flag; +} Assignment::~Assignment() {} @@ -41,11 +43,21 @@ bool Assignment::is_compatible(const Assignment& other) { return false; } } + if (this->unique_assignment_flag) { + for (auto other_pair : other.table) { + if ((pair.second == other_pair.second) && (pair.first != other_pair.first)) { + return false; + } + } + } } return true; } -void Assignment::copy_from(const Assignment& other) { this->table = other.table; } +void Assignment::copy_from(const Assignment& other) { + this->table = other.table; + this->unique_assignment_flag = other.unique_assignment_flag; +} void Assignment::add_assignments(const Assignment& other) { for (auto pair : other.table) { @@ -84,4 +96,13 @@ string Assignment::to_string() { void Assignment::clear() { this->table.clear(); } -bool Assignment::operator==(const Assignment& other) const { return (this->table == other.table); } +bool Assignment::operator==(const Assignment& other) const { + return (this->table == other.table) && + (this->unique_assignment_flag == other.unique_assignment_flag); +} + +Assignment& Assignment::operator=(const Assignment& other) { + this->table = other.table; + this->unique_assignment_flag = other.unique_assignment_flag; + return *this; +} diff --git a/src/commons/Assignment.h b/src/commons/Assignment.h index b348c4eb..84aab877 100644 --- a/src/commons/Assignment.h +++ b/src/commons/Assignment.h @@ -25,8 +25,11 @@ class Assignment { public: /** * Basic constructor. + * + * @param unique_assignment_flag When true, enforces the assignment of different values for different + * variables. */ - Assignment(); + Assignment(bool unique_assignment_flag = false); /** * Destructor. @@ -116,6 +119,11 @@ class Assignment { */ bool operator==(const Assignment& other) const; + /** + * Deep copy + */ + Assignment& operator=(const Assignment& other); + /** * Clear all assignments. */ @@ -125,6 +133,7 @@ class Assignment { private: static string EMPTY_VALUE; + bool unique_assignment_flag; }; } // namespace commons diff --git a/src/commons/processor/BUILD b/src/commons/processor/BUILD new file mode 100644 index 00000000..16cd2140 --- /dev/null +++ b/src/commons/processor/BUILD @@ -0,0 +1,17 @@ +load("@rules_cc//cc:cc_library.bzl", "cc_library") + +package(default_visibility = ["//visibility:public"]) + +cc_library( + name = "processor_lib", + srcs = [ + "Processor.cc", + ], + hdrs = [ + "Processor.h", + ], + includes = ["."], + deps = [ + "//commons:commons_lib", + ], +) diff --git a/src/commons/processor/Processor.cc b/src/commons/processor/Processor.cc new file mode 100644 index 00000000..40741206 --- /dev/null +++ b/src/commons/processor/Processor.cc @@ -0,0 +1,79 @@ +#include "Processor.h" + +#include "Utils.h" + +using namespace commons; +using namespace processor; + +// ------------------------------------------------------------------------------------------------- +// Public methods + +Processor::Processor(const string& id) { + if (id == "") { + Utils::error("Invalid empty id for processor"); + } + this->current_state = WAITING_SETUP; + this->id = id; +} + +Processor::~Processor() { + if (this->current_state != FINISHED) { + // This doesn't throw an exception + Utils::error("Destroying processor " + this->id + " without explicitly stopping it.", false); + } +} + +void Processor::setup() { + lock_guard semaphore(this->api_mutex); + check_state("setup", WAITING_SETUP); + this->current_state = WAITING_START; +} + +void Processor::start() { + lock_guard semaphore(this->api_mutex); + check_state("start", WAITING_START); + this->current_state = WAITING_STOP; +} + +void Processor::stop() { + lock_guard semaphore(this->api_mutex); + check_state("stop", WAITING_STOP); + this->current_state = FINISHED; +} + +bool Processor::is_setup() { + lock_guard semaphore(this->api_mutex); + return (this->current_state > WAITING_SETUP); +} + +bool Processor::is_finished() { + lock_guard semaphore(this->api_mutex); + return (this->current_state == FINISHED); +} + +string Processor::to_string() { return this->id; } + +// ------------------------------------------------------------------------------------------------- +// Private methods + +void Processor::check_state(const string& action, State state) { + if (this->current_state != state) { + string error_message = "Invalid attempt to " + action + " processor " + this->id + ". "; + if (this->current_state == WAITING_SETUP) { + error_message += "Processor is not setup."; + } else if (this->current_state == WAITING_START) { + if (action == "setup") { + error_message += "Processor is already setup."; + } else { + error_message += "Processor is not running."; + } + } else if (this->current_state == WAITING_STOP) { + error_message += "Processor is already running."; + } else if (this->current_state == FINISHED) { + error_message += "Processor is finished."; + } else { + error_message += "Processor is in unexpected state: " + this->current_state; + } + Utils::error(error_message); + } +} diff --git a/src/commons/processor/Processor.h b/src/commons/processor/Processor.h new file mode 100644 index 00000000..798cc5ed --- /dev/null +++ b/src/commons/processor/Processor.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +using namespace std; + +namespace processor { + +/** + * + */ +class Processor { + public: + enum State { UNDEFINED = 0, WAITING_SETUP, WAITING_START, WAITING_STOP, FINISHED }; + + Processor(const string& id); + ~Processor(); + virtual void setup(); + virtual void start(); + virtual void stop(); + bool is_setup(); + bool is_finished(); + string to_string(); + + private: + void check_state(const string& action, State state); + + State current_state; + string id; + mutex api_mutex; +}; + +} // namespace processor diff --git a/src/tests/cpp/BUILD b/src/tests/cpp/BUILD index 217d2ed9..dbaf81b3 100644 --- a/src/tests/cpp/BUILD +++ b/src/tests/cpp/BUILD @@ -611,6 +611,22 @@ cc_test( ], ) +cc_test( + name = "processor_test", + size = "small", + srcs = ["processor_test.cc"], + copts = [ + "-Iexternal/gtest/googletest/include", + "-Iexternal/gtest/googletest", + ], + linkstatic = 1, + deps = [ + "//commons:commons_lib", + "//commons/processor:processor_lib", + "@com_github_google_googletest//:gtest_main", + ], +) + cc_test( name = "atom_space_test", size = "small", diff --git a/src/tests/cpp/iterator_test.cc b/src/tests/cpp/iterator_test.cc index 9764c1cd..f0cc63d1 100644 --- a/src/tests/cpp/iterator_test.cc +++ b/src/tests/cpp/iterator_test.cc @@ -84,7 +84,7 @@ TEST(Iterator, link_template_integration) { auto human = make_shared(symbol, "\"human\""); LinkTemplate* link_template = - new LinkTemplate("Expression", {similarity, human, v1}, "", false, false); + new LinkTemplate("Expression", {similarity, human, v1}, "", false, false, false); link_template->build(); Iterator query_answer_iterator(link_template->get_source_element()); diff --git a/src/tests/cpp/link_template_test.cc b/src/tests/cpp/link_template_test.cc index a915bb79..30bea8f1 100644 --- a/src/tests/cpp/link_template_test.cc +++ b/src/tests/cpp/link_template_test.cc @@ -30,7 +30,7 @@ TEST(LinkTemplate, basics) { similarity->handle = Hasher::node_handle(symbol, "Similarity"); auto human = make_shared(symbol, "\"human\""); - LinkTemplate link_template1("Expression", {similarity, human, v1}, "", false, false); + LinkTemplate link_template1("Expression", {similarity, human, v1}, "", false, false, false); link_template1.build(); link_template1.get_source_element()->subsequent_id = server_node_id; link_template1.get_source_element()->setup_buffers(); diff --git a/src/tests/cpp/nested_link_template_test.cc b/src/tests/cpp/nested_link_template_test.cc index c3793e6b..086568da 100644 --- a/src/tests/cpp/nested_link_template_test.cc +++ b/src/tests/cpp/nested_link_template_test.cc @@ -28,10 +28,10 @@ TEST(LinkTemplate, basics) { auto odd_link = make_shared(symbol, "OddLink"); LinkTemplate* inner_template_ptr = - new LinkTemplate(expression, {similarity, v1, v2}, "", false, false); + new LinkTemplate(expression, {similarity, v1, v2}, "", false, false, false); shared_ptr inner_template(inner_template_ptr); LinkTemplate* outter_template_ptr = - new LinkTemplate(expression, {odd_link, inner_template}, "", false, false); + new LinkTemplate(expression, {odd_link, inner_template}, "", false, false, false); outter_template_ptr->build(); Iterator iterator(outter_template_ptr->get_source_element()); @@ -59,13 +59,13 @@ TEST(LinkTemplate, nested_variables) { auto human = make_shared(symbol, "\"human\""); LinkTemplate* inner_template_ptr = - new LinkTemplate(expression, {similarity, v1, v2}, "", false, false); + new LinkTemplate(expression, {similarity, v1, v2}, "", false, false, false); shared_ptr inner_template(inner_template_ptr); LinkTemplate* outter_template = - new LinkTemplate(expression, {odd_link, inner_template}, "", false, false); + new LinkTemplate(expression, {odd_link, inner_template}, "", false, false, false); outter_template->build(); LinkTemplate* human_template = - new LinkTemplate(expression, {similarity, v1, human}, "", false, false); + new LinkTemplate(expression, {similarity, v1, human}, "", false, false, false); human_template->build(); auto and_operator = make_shared>(array, 2>( {human_template->get_source_element(), outter_template->get_source_element()})); diff --git a/src/tests/cpp/pattern_matching_query_test.cc b/src/tests/cpp/pattern_matching_query_test.cc index eb3f6070..f8fddea5 100644 --- a/src/tests/cpp/pattern_matching_query_test.cc +++ b/src/tests/cpp/pattern_matching_query_test.cc @@ -52,7 +52,8 @@ void check_query(const string& query_tag, bool update_attention_broker, bool unique_assignment, bool positive_importance, - bool error_flag) { + bool error_flag, + bool unique_value_flag) { LOG_INFO("==================== Query tag: " + query_tag); shared_ptr proxy1(new PatternMatchingQueryProxy(query, context)); @@ -60,6 +61,7 @@ void check_query(const string& query_tag, proxy1->parameters[BaseQueryProxy::ATTENTION_UPDATE_FLAG] = update_attention_broker; proxy1->parameters[BaseQueryProxy::POPULATE_METTA_MAPPING] = false; proxy1->parameters[PatternMatchingQueryProxy::POSITIVE_IMPORTANCE_FLAG] = positive_importance; + proxy1->parameters[PatternMatchingQueryProxy::UNIQUE_VALUE_FLAG] = unique_value_flag; LOG_INFO("proxy1: " + proxy1->to_string()); shared_ptr proxy2(new PatternMatchingQueryProxy(query, context)); @@ -67,6 +69,7 @@ void check_query(const string& query_tag, proxy2->parameters[BaseQueryProxy::ATTENTION_UPDATE_FLAG] = update_attention_broker; proxy2->parameters[PatternMatchingQueryProxy::COUNT_FLAG] = true; proxy2->parameters[PatternMatchingQueryProxy::POSITIVE_IMPORTANCE_FLAG] = positive_importance; + proxy2->parameters[PatternMatchingQueryProxy::UNIQUE_VALUE_FLAG] = unique_value_flag; LOG_INFO("proxy2: " + proxy2->to_string()); vector metta_query = {metta_expression}; @@ -76,6 +79,7 @@ void check_query(const string& query_tag, proxy3->parameters[BaseQueryProxy::ATTENTION_UPDATE_FLAG] = update_attention_broker; proxy3->parameters[BaseQueryProxy::POPULATE_METTA_MAPPING] = false; proxy3->parameters[PatternMatchingQueryProxy::POSITIVE_IMPORTANCE_FLAG] = positive_importance; + proxy3->parameters[PatternMatchingQueryProxy::UNIQUE_VALUE_FLAG] = unique_value_flag; LOG_INFO("proxy3: " + proxy3->to_string()); unsigned int count = 0; @@ -93,6 +97,9 @@ void check_query(const string& query_tag, } if (query_answer) { LOG_INFO(">>>>>>>>>> " << query_answer->assignment.to_string()); + for (auto pair : query_answer->assignment.table) { + LOG_INFO(">>>>>>>>>>>>>> " << pair.first << " " << handle_to_atom(pair.second)); + } count++; } } @@ -198,7 +205,14 @@ TEST(PatternMatchingQuery, queries) { "VARIABLE", "v3" }; string q4m = "(and (Similarity $v1 $v2) (Similarity $v2 $v3))"; - int q4_expected_count = 26; // TODO: FIX THIS count should be == 1 + int q4_expected_count = 12; // TODO: FIX THIS count should be == 3? + // The point is that different permutations + // are being returned, e.g. (human, monkey, chimp) + // and (chimp, human, monkey). These repetitions + // doesn't violate the current query parameters + // we have to avoid repetitions (UNIQUE_ASSIGNMENT + // and UNIQUE_VALUE) but we may want to avoid them, + // I'm not sure. Perhaps a third optional parameter? vector q5 = { "OR", "2", @@ -243,23 +257,24 @@ TEST(PatternMatchingQuery, queries) { int q7_expected_count = 4; // Regular queries - check_query("q1", q1, q1m, q1_expected_count, client_bus, "PatternMatchingQuery.queries", false, false, false, false); - check_query("q2", q2, q2m, q2_expected_count, client_bus, "PatternMatchingQuery.queries", false, false, false, false); - check_query("q3", q3, q3m, q3_expected_count, client_bus, "PatternMatchingQuery.queries", false, false, false, false); - check_query("q4", q4, q4m, q4_expected_count, client_bus, "PatternMatchingQuery.queries", false, false, false, false); - check_query("q5", q5, q5m, q5_expected_count, client_bus, "PatternMatchingQuery.queries", false, false, false, false); - check_query("q6", q6, q6m, q6_expected_count, client_bus, "PatternMatchingQuery.queries", false, true, false, false); - check_query("q7", q7, q7m, q7_expected_count, client_bus, "PatternMatchingQuery.queries", false, true, false, false); + check_query("q1", q1, q1m, q1_expected_count, client_bus, "PatternMatchingQuery.queries", false, false, false, false, false); + check_query("q2", q2, q2m, q2_expected_count, client_bus, "PatternMatchingQuery.queries", false, false, false, false, false); + check_query("q3", q3, q3m, q3_expected_count, client_bus, "PatternMatchingQuery.queries", false, false, false, false, false); + check_query("q4", q4, q4m, q4_expected_count, client_bus, "PatternMatchingQuery.queries", false, true, false, false, true); + check_query("q4", q4, q4m, 26, client_bus, "PatternMatchingQuery.queries", false, false, false, false, false); + check_query("q5", q5, q5m, q5_expected_count, client_bus, "PatternMatchingQuery.queries", false, false, false, false, false); + check_query("q6", q6, q6m, q6_expected_count, client_bus, "PatternMatchingQuery.queries", false, true, false, false, false); + check_query("q7", q7, q7m, q7_expected_count, client_bus, "PatternMatchingQuery.queries", false, true, false, false, false); // Importance filtering // XXX AttentionBroker is being revised so its dynamics is a bit unpredictable right now // XXX so we're disabling the following test cases for while because they rely on these // XXX dynamics. - //check_query("filtered q2", q2, q2m, q2_expected_count, client_bus, "PatternMatchingQuery.queries", true, false, false, false); - //check_query("filtered q1", q1, q1m, 3, client_bus, "PatternMatchingQuery.queries", false, false, true, false); + //check_query("filtered q2", q2, q2m, q2_expected_count, client_bus, "PatternMatchingQuery.queries", true, false, false, false, false); + //check_query("filtered q1", q1, q1m, 3, client_bus, "PatternMatchingQuery.queries", false, false, true, false, false); // Remote exception - check_query("invalid", {"BLAH"}, "", 0, client_bus, "PatternMatchingQuery.queries", false, false, false, true); + check_query("invalid", {"BLAH"}, "", 0, client_bus, "PatternMatchingQuery.queries", false, false, false, true, false); // Metta expression in QueryAnswer shared_ptr proxy(new PatternMatchingQueryProxy(q3, "PatternMatchingQuery.queries")); diff --git a/src/tests/cpp/processor_test.cc b/src/tests/cpp/processor_test.cc new file mode 100644 index 00000000..35aa24dd --- /dev/null +++ b/src/tests/cpp/processor_test.cc @@ -0,0 +1,45 @@ +#include "Processor.h" + +#include + +using namespace std; +using namespace processor; + +TEST(ProcessorTest, basics) { + Processor p1("blah"); + EXPECT_THROW(Processor p2(""), runtime_error); + EXPECT_EQ(p1.to_string(), "blah"); + + EXPECT_FALSE(p1.is_setup()); + EXPECT_FALSE(p1.is_finished()); + + EXPECT_THROW(p1.start(), runtime_error); + EXPECT_THROW(p1.stop(), runtime_error); + EXPECT_FALSE(p1.is_setup()); + EXPECT_FALSE(p1.is_finished()); + p1.setup(); + EXPECT_TRUE(p1.is_setup()); + EXPECT_FALSE(p1.is_finished()); + + EXPECT_THROW(p1.setup(), runtime_error); + EXPECT_THROW(p1.stop(), runtime_error); + EXPECT_TRUE(p1.is_setup()); + EXPECT_FALSE(p1.is_finished()); + p1.start(); + EXPECT_TRUE(p1.is_setup()); + EXPECT_FALSE(p1.is_finished()); + + EXPECT_THROW(p1.setup(), runtime_error); + EXPECT_THROW(p1.start(), runtime_error); + EXPECT_TRUE(p1.is_setup()); + EXPECT_FALSE(p1.is_finished()); + p1.stop(); + EXPECT_TRUE(p1.is_setup()); + EXPECT_TRUE(p1.is_finished()); + + EXPECT_THROW(p1.setup(), runtime_error); + EXPECT_THROW(p1.start(), runtime_error); + EXPECT_THROW(p1.stop(), runtime_error); + EXPECT_TRUE(p1.is_setup()); + EXPECT_TRUE(p1.is_finished()); +} diff --git a/src/tests/cpp/query_answer_test.cc b/src/tests/cpp/query_answer_test.cc index b68ce0c2..26ac379b 100644 --- a/src/tests/cpp/query_answer_test.cc +++ b/src/tests/cpp/query_answer_test.cc @@ -20,8 +20,8 @@ TEST(QueryAnswer, assignments_basics) { EXPECT_TRUE(mapping1.assign("v2", "2")); EXPECT_FALSE(mapping1.assign("v2", "3")); Assignment mapping2; - EXPECT_TRUE(mapping1.assign("v1", "1")); - EXPECT_TRUE(mapping1.assign("v3", "3")); + EXPECT_TRUE(mapping2.assign("v1", "1")); + EXPECT_TRUE(mapping2.assign("v3", "3")); Assignment mapping3; EXPECT_TRUE(mapping3.assign("v1", "1")); EXPECT_TRUE(mapping3.assign("v2", "3")); @@ -77,6 +77,41 @@ TEST(QueryAnswer, assignments_basics) { EXPECT_TRUE(mapping4.to_string() != ""); } +TEST(QueryAnswer, unique_assignment_flag) { + Assignment mapping1(true); + EXPECT_TRUE(mapping1.assign("v1", "1")); + EXPECT_TRUE(mapping1.assign("v2", "2")); + Assignment mapping2(true); + EXPECT_TRUE(mapping2.assign("v1", "1")); + EXPECT_TRUE(mapping2.assign("v3", "3")); + Assignment mapping3(true); + EXPECT_TRUE(mapping3.assign("v1", "1")); + EXPECT_TRUE(mapping3.assign("v2", "3")); + Assignment mapping4(true); + EXPECT_TRUE(mapping4.assign("v4", "4")); + EXPECT_TRUE(mapping4.assign("v1", "1")); + + EXPECT_TRUE(mapping1.is_compatible(mapping1)); + EXPECT_TRUE(mapping1.is_compatible(mapping2)); + EXPECT_FALSE(mapping1.is_compatible(mapping3)); + EXPECT_TRUE(mapping1.is_compatible(mapping4)); + + EXPECT_TRUE(mapping2.is_compatible(mapping1)); + EXPECT_TRUE(mapping2.is_compatible(mapping2)); + EXPECT_FALSE(mapping2.is_compatible(mapping3)); + EXPECT_TRUE(mapping2.is_compatible(mapping4)); + + EXPECT_FALSE(mapping3.is_compatible(mapping1)); + EXPECT_FALSE(mapping3.is_compatible(mapping2)); + EXPECT_TRUE(mapping3.is_compatible(mapping3)); + EXPECT_TRUE(mapping3.is_compatible(mapping4)); + + EXPECT_TRUE(mapping4.is_compatible(mapping1)); + EXPECT_TRUE(mapping4.is_compatible(mapping2)); + EXPECT_TRUE(mapping4.is_compatible(mapping3)); + EXPECT_TRUE(mapping4.is_compatible(mapping4)); +} + TEST(QueryAnswer, assignments_equal) { Assignment mapping1; EXPECT_TRUE(mapping1.assign("v1", "1"));