/* * * This file is a part of the LinkAhead Project. * * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> * Copyright (C) 2021-2024 IndiScale GmbH <info@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * 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 Affero 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, see <https://www.gnu.org/licenses/>. * */ #include "linkahead/configuration.h" #include "linkahead/status_code.h" // for StatusCode #include "linkahead_test_utility.h" // for EXPECT_THROW_MESSAGE, TEST_DATA_DIR #include "clinkahead.h" // for linkahead_utility_get_env_fallback #include <cstdint> // for int64_t #include <cstring> // for strcmp #include <gtest/gtest.h> #include <gtest/gtest-message.h> // for Message #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl #include <gtest/gtest_pred_impl.h> // for Test, TestInfo, EXPECT_EQ, TEST #include <string> // for allocator, operator+, string,... class test_clinkahead : public ::testing::Test { protected: void SetUp() override { linkahead::configuration::ConfigurationManager::Clear(); linkahead::configuration::ConfigurationManager::LoadSingleJSONConfiguration( TEST_DATA_DIR + "/test_linkahead_client.json"); } void TearDown() override { linkahead::configuration::ConfigurationManager::Clear(); } }; TEST_F(test_clinkahead, test_get_env_fallback) { const char *const some_var = linkahead_utility_get_env_fallback("SOME_ENV_VAR", "fall-back"); EXPECT_EQ("fall-back", some_var); } TEST_F(test_clinkahead, test_other_client_error) { EXPECT_EQ(linkahead_status_code_OTHER_CLIENT_ERROR(), linkahead::StatusCode::OTHER_CLIENT_ERROR); } TEST_F(test_clinkahead, test_get_default_connection) { linkahead_connection_connection out; linkahead_connection_connection_manager_get_default_connection(&out); EXPECT_TRUE(out.wrapped_connection); } TEST_F(test_clinkahead, test_get_connection) { linkahead_connection_connection out; linkahead_connection_connection_manager_get_connection(&out, "local-linkahead-admin"); EXPECT_TRUE(out.wrapped_connection); } TEST_F(test_clinkahead, test_execute_transaction) { linkahead_connection_connection connection; linkahead_connection_connection_manager_get_connection(&connection, "local-linkahead-admin"); linkahead_transaction_transaction transaction; linkahead_connection_connection_create_transaction(&connection, &transaction); EXPECT_TRUE(transaction.wrapped_transaction); int return_code(linkahead_transaction_transaction_retrieve_by_id(&transaction, "some_id")); EXPECT_EQ(return_code, linkahead::StatusCode::GO_ON); return_code = linkahead_transaction_transaction_execute(&transaction); EXPECT_EQ(return_code, linkahead::StatusCode::CONNECTION_ERROR); return_code = linkahead_transaction_delete_transaction(&transaction); EXPECT_EQ(return_code, 0); linkahead_transaction_transaction multi_transaction; linkahead_connection_connection_create_transaction(&connection, &multi_transaction); // We explicitely want to define a C-style array here, so we disable // linting const char *ids[] = {"id1", "id2", "id3"}; // NOLINT return_code = linkahead_transaction_transaction_retrieve_by_ids(&multi_transaction, ids, 3); EXPECT_EQ(return_code, linkahead::StatusCode::GO_ON); return_code = linkahead_transaction_delete_transaction(&multi_transaction); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_multi_retrieve) { linkahead_connection_connection connection; linkahead_connection_connection_manager_get_connection(&connection, "local-linkahead-admin"); linkahead_transaction_transaction multi_transaction; linkahead_connection_connection_create_transaction(&connection, &multi_transaction); // We explicitely want to define a C-style array here, so we disable // linting const char *ids[] = {"id1", "id2", "id3"}; // NOLINT int return_code(linkahead_transaction_transaction_retrieve_by_ids(&multi_transaction, ids, 3)); EXPECT_EQ(return_code, linkahead::StatusCode::GO_ON); return_code = linkahead_transaction_delete_transaction(&multi_transaction); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_query) { linkahead_connection_connection connection; linkahead_connection_connection_manager_get_connection(&connection, "local-linkahead-admin"); linkahead_transaction_transaction transaction; linkahead_connection_connection_create_transaction(&connection, &transaction); int return_code(linkahead_transaction_transaction_query(&transaction, "FIND ENTITY WITH id=123")); EXPECT_EQ(return_code, linkahead::StatusCode::GO_ON); return_code = linkahead_transaction_delete_transaction(&transaction); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_datatype) { linkahead_entity_datatype atomic; // check that this fails int return_code(linkahead_entity_create_atomic_datatype(&atomic, "some type")); EXPECT_EQ(return_code, linkahead::StatusCode::ENUM_MAPPING_ERROR); return_code = linkahead_entity_create_atomic_datatype(&atomic, "INTEGER"); EXPECT_EQ(return_code, 0); linkahead_entity_datatype reference; return_code = linkahead_entity_create_reference_datatype(&reference, "MyType"); EXPECT_EQ(return_code, 0); linkahead_entity_datatype list_of_atomics; return_code = linkahead_entity_create_atomic_list_datatype(&list_of_atomics, "DATETIME"); EXPECT_EQ(return_code, 0); linkahead_entity_datatype list_of_references; return_code = linkahead_entity_create_reference_list_datatype(&list_of_references, "MyType"); EXPECT_EQ(return_code, 0); bool is_a(false); return_code = linkahead_entity_datatype_is_undefined(&atomic, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_atomic(&atomic, &is_a); EXPECT_EQ(return_code, 0); EXPECT_TRUE(is_a); return_code = linkahead_entity_datatype_is_reference(&atomic, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_atomic(&atomic, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_reference(&atomic, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_atomic(&reference, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_reference(&reference, &is_a); EXPECT_EQ(return_code, 0); EXPECT_TRUE(is_a); return_code = linkahead_entity_datatype_is_list_of_atomic(&reference, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_reference(&reference, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_atomic(&list_of_atomics, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_reference(&list_of_atomics, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_atomic(&list_of_atomics, &is_a); EXPECT_EQ(return_code, 0); EXPECT_TRUE(is_a); return_code = linkahead_entity_datatype_is_list_of_reference(&list_of_atomics, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_atomic(&list_of_references, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_reference(&list_of_references, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_atomic(&list_of_references, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_reference(&list_of_references, &is_a); EXPECT_EQ(return_code, 0); EXPECT_TRUE(is_a); char *name = nullptr; // NOLINT return_code = linkahead_entity_datatype_get_datatype_name(&atomic, &name); EXPECT_EQ(return_code, 0); EXPECT_STREQ(name, "INTEGER"); return_code = linkahead_entity_datatype_get_datatype_name(&reference, &name); EXPECT_EQ(return_code, 0); EXPECT_STREQ(name, "MyType"); return_code = linkahead_entity_datatype_get_datatype_name(&list_of_atomics, &name); EXPECT_EQ(return_code, 0); EXPECT_STREQ(name, "DATETIME"); return_code = linkahead_entity_datatype_get_datatype_name(&list_of_references, &name); EXPECT_EQ(return_code, 0); EXPECT_STREQ(name, "MyType"); return_code = linkahead_entity_delete_datatype(&atomic); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_datatype(&reference); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_datatype(&list_of_atomics); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_datatype(&list_of_references); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_value) { linkahead_entity_value string_value; int return_code(linkahead_entity_create_string_value(&string_value, "value")); EXPECT_EQ(return_code, 0); linkahead_entity_value int_value; return_code = linkahead_entity_create_int_value(&int_value, 27); EXPECT_EQ(return_code, 0); linkahead_entity_value bool_value; return_code = linkahead_entity_create_bool_value(&bool_value, true); EXPECT_EQ(return_code, 0); linkahead_entity_value double_value; return_code = linkahead_entity_create_double_value(&double_value, 2.7); EXPECT_EQ(return_code, 0); linkahead_entity_value string_vector_value; const char *string_values[] = {"a", "b", "c"}; // NOLINT return_code = linkahead_entity_create_string_vector_value(&string_vector_value, string_values, 3); EXPECT_EQ(return_code, 0); linkahead_entity_value int_vector_value; const int64_t int_values[] = {1, 2, 3}; // NOLINT return_code = linkahead_entity_create_int_vector_value(&int_vector_value, int_values, 3); EXPECT_EQ(return_code, 0); linkahead_entity_value double_vector_value; const double double_values[] = {1.1, 2.2, 3.3}; // NOLINT return_code = linkahead_entity_create_double_vector_value(&double_vector_value, double_values, 3); EXPECT_EQ(return_code, 0); linkahead_entity_value bool_vector_value; const bool bool_values[] = {true, false, false}; // NOLINT return_code = linkahead_entity_create_bool_vector_value(&bool_vector_value, bool_values, 3); EXPECT_EQ(return_code, 0); // One thorough check, afterwards only the ones that should be true bool is_a(false); return_code = linkahead_entity_value_is_null(&string_value, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_value_is_string(&string_value, &is_a); EXPECT_EQ(return_code, 0); EXPECT_TRUE(is_a); return_code = linkahead_entity_value_is_double(&string_value, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_value_is_integer(&string_value, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_value_is_bool(&string_value, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_value_is_vector(&string_value, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); linkahead_entity_value_is_integer(&int_value, &is_a); EXPECT_TRUE(is_a); linkahead_entity_value_is_bool(&bool_value, &is_a); EXPECT_TRUE(is_a); linkahead_entity_value_is_double(&double_value, &is_a); EXPECT_TRUE(is_a); linkahead_entity_value_is_vector(&string_vector_value, &is_a); EXPECT_TRUE(is_a); linkahead_entity_value_is_vector(&int_vector_value, &is_a); EXPECT_TRUE(is_a); linkahead_entity_value_is_vector(&double_vector_value, &is_a); EXPECT_TRUE(is_a); linkahead_entity_value_is_vector(&bool_vector_value, &is_a); EXPECT_TRUE(is_a); char *out_string = nullptr; // NOLINT return_code = linkahead_entity_value_get_as_string(&string_value, &out_string); EXPECT_EQ(return_code, 0); EXPECT_STREQ(out_string, "value"); int64_t out_int(0); return_code = linkahead_entity_value_get_as_integer(&int_value, &out_int); EXPECT_EQ(return_code, 0); EXPECT_EQ(out_int, 27); bool out_bool(false); return_code = linkahead_entity_value_get_as_bool(&bool_value, &out_bool); EXPECT_EQ(return_code, 0); EXPECT_TRUE(out_bool); double out_double(0); return_code = linkahead_entity_value_get_as_double(&double_value, &out_double); EXPECT_EQ(return_code, 0); EXPECT_EQ(out_double, 2.7); int list_length(0); return_code = linkahead_entity_value_get_as_vector_size(&string_vector_value, &list_length); EXPECT_EQ(return_code, 0); EXPECT_EQ(list_length, 3); return_code = linkahead_entity_value_get_as_vector_size(&int_vector_value, &list_length); EXPECT_EQ(return_code, 0); EXPECT_EQ(list_length, 3); return_code = linkahead_entity_value_get_as_vector_size(&double_vector_value, &list_length); EXPECT_EQ(return_code, 0); EXPECT_EQ(list_length, 3); return_code = linkahead_entity_value_get_as_vector_size(&bool_vector_value, &list_length); EXPECT_EQ(return_code, 0); EXPECT_EQ(list_length, 3); // Only check for one, rest should be covered by this + scalar values linkahead_entity_value out_val; return_code = linkahead_entity_value_get_as_vector_at(&string_vector_value, &out_val, 0); EXPECT_EQ(return_code, 0); linkahead_entity_value_get_as_string(&out_val, &out_string); EXPECT_STREQ(out_string, "a"); return_code = linkahead_entity_value_get_as_vector_at(&string_vector_value, &out_val, 1); EXPECT_EQ(return_code, 0); linkahead_entity_value_get_as_string(&out_val, &out_string); EXPECT_STREQ(out_string, "b"); return_code = linkahead_entity_value_get_as_vector_at(&string_vector_value, &out_val, 2); EXPECT_EQ(return_code, 0); linkahead_entity_value_get_as_string(&out_val, &out_string); EXPECT_STREQ(out_string, "c"); return_code = linkahead_entity_delete_value(&string_value); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&int_value); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&bool_value); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&double_value); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&string_vector_value); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&int_vector_value); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&double_vector_value); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&bool_vector_value); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_entity) { linkahead_entity_entity entity; int return_code(linkahead_entity_create_entity(&entity)); EXPECT_EQ(return_code, 0); // cannot be created again without deletion // return_code = linkahead_entity_create_entity(&entity); // EXPECT_EQ(return_code, linkahead::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); // deletion and re-creation is ok return_code = linkahead_entity_delete_entity(&entity); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_create_entity(&entity); EXPECT_EQ(return_code, 0); // In-depth check for one pair of setter and getter, just compare // the strings for the rest return_code = linkahead_entity_entity_set_name(&entity, "length"); EXPECT_EQ(return_code, 0); char *out = nullptr; // NOLINT return_code = linkahead_entity_entity_get_name(&entity, &out); EXPECT_EQ(return_code, 0); EXPECT_EQ(strcmp(out, "length"), 0); // test call without validation of result return_code = linkahead_entity_entity_set_role(&entity, "FILE"); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_entity_set_local_path( &entity, (TEST_DATA_DIR + "/test_linkahead_client.json").c_str()); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_entity_get_local_path(&entity, &out); EXPECT_EQ(return_code, 0); EXPECT_EQ(strcmp(out, (TEST_DATA_DIR + "/test_linkahead_client.json").c_str()), 0); // invalid role return_code = linkahead_entity_entity_set_role(&entity, "Role does not exist"); EXPECT_EQ(return_code, linkahead::StatusCode::ENUM_MAPPING_ERROR); linkahead_entity_entity_set_role(&entity, "PROPERTY"); linkahead_entity_entity_get_role(&entity, &out); EXPECT_EQ(strcmp(out, "PROPERTY"), 0); linkahead_entity_entity_set_description(&entity, "The length of an object"); linkahead_entity_entity_get_description(&entity, &out); EXPECT_EQ(strcmp(out, "The length of an object"), 0); linkahead_entity_datatype in_type; linkahead_entity_create_atomic_datatype(&in_type, "DOUBLE"); linkahead_entity_entity_set_datatype(&entity, &in_type); // verify that this doesn't work ... // return_code = linkahead_entity_entity_get_datatype(&entity, &in_type); // EXPECT_EQ(return_code, linkahead::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); linkahead_entity_datatype out_type; // ... but does with a clean property return_code = linkahead_entity_entity_get_datatype(&entity, &out_type); EXPECT_EQ(return_code, 0); bool is_a(false); return_code = linkahead_entity_datatype_is_atomic(&out_type, &is_a); EXPECT_EQ(return_code, 0); EXPECT_TRUE(is_a); return_code = linkahead_entity_datatype_is_reference(&out_type, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_atomic(&out_type, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_reference(&out_type, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); linkahead_entity_datatype_get_datatype_name(&out_type, &out); EXPECT_STREQ(out, "DOUBLE"); linkahead_entity_value in_value; return_code = linkahead_entity_create_double_value(&in_value, 5.0); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_entity_set_value(&entity, &in_value); EXPECT_EQ(return_code, 0); linkahead_entity_value out_value; return_code = linkahead_entity_entity_get_value(&entity, &out_value); EXPECT_EQ(return_code, 0); linkahead_entity_value_is_double(&out_value, &is_a); EXPECT_TRUE(is_a); linkahead_entity_value_is_null(&out_value, &is_a); EXPECT_FALSE(is_a); linkahead_entity_value_is_string(&out_value, &is_a); EXPECT_FALSE(is_a); linkahead_entity_value_is_bool(&out_value, &is_a); EXPECT_FALSE(is_a); linkahead_entity_value_is_integer(&out_value, &is_a); EXPECT_FALSE(is_a); linkahead_entity_value_is_vector(&out_value, &is_a); EXPECT_FALSE(is_a); double out_double(0); linkahead_entity_value_get_as_double(&out_value, &out_double); EXPECT_EQ(out_double, 5.0); // clear to re-use return_code = linkahead_entity_delete_datatype(&in_type); EXPECT_EQ(return_code, 0); linkahead_entity_create_reference_list_datatype(&in_type, "Person"); linkahead_entity_entity_set_datatype(&entity, &in_type); // works without clearing since datatype is managed by the owning entity linkahead_entity_entity_get_datatype(&entity, &out_type); return_code = linkahead_entity_datatype_is_atomic(&out_type, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_reference(&out_type, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_atomic(&out_type, &is_a); EXPECT_EQ(return_code, 0); EXPECT_FALSE(is_a); return_code = linkahead_entity_datatype_is_list_of_reference(&out_type, &is_a); EXPECT_EQ(return_code, 0); EXPECT_TRUE(is_a); linkahead_entity_datatype_get_datatype_name(&out_type, &out); EXPECT_STREQ(out, "Person"); linkahead_entity_entity_set_unit(&entity, "m"); linkahead_entity_entity_get_unit(&entity, &out); EXPECT_EQ(strcmp(out, "m"), 0); return_code = linkahead_entity_delete_entity(&entity); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_datatype(&in_type); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&in_value); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_parent) { linkahead_entity_parent parent; int return_code(linkahead_entity_create_parent(&parent)); EXPECT_EQ(return_code, 0); linkahead_entity_parent_set_id(&parent, "some_id"); linkahead_entity_parent_set_name(&parent, "some_name"); char *out = nullptr; // NOLINT linkahead_entity_parent_get_id(&parent, &out); EXPECT_EQ(strcmp(out, "some_id"), 0); linkahead_entity_parent_get_name(&parent, &out); EXPECT_EQ(strcmp(out, "some_name"), 0); return_code = linkahead_entity_delete_parent(&parent); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_property) { linkahead_entity_property property; int return_code(linkahead_entity_create_property(&property)); EXPECT_EQ(return_code, 0); linkahead_entity_property_set_id(&property, "some_id"); linkahead_entity_property_set_name(&property, "some_name"); linkahead_entity_datatype in_type; linkahead_entity_create_atomic_datatype(&in_type, "TEXT"); linkahead_entity_property_set_datatype(&property, &in_type); linkahead_entity_property_set_importance(&property, "FIX"); linkahead_entity_property_set_unit(&property, "some_unit"); linkahead_entity_value in_value; linkahead_entity_create_string_value(&in_value, "some_value"); linkahead_entity_property_set_value(&property, &in_value); char *out = nullptr; // NOLINT linkahead_entity_property_get_id(&property, &out); EXPECT_EQ(strcmp(out, "some_id"), 0); linkahead_entity_property_get_name(&property, &out); EXPECT_EQ(strcmp(out, "some_name"), 0); linkahead_entity_datatype out_type; return_code = linkahead_entity_property_get_datatype(&property, &out_type); EXPECT_EQ(return_code, 0); bool is_a(false); linkahead_entity_datatype_is_atomic(&out_type, &is_a); EXPECT_TRUE(is_a); linkahead_entity_datatype_is_reference(&out_type, &is_a); EXPECT_FALSE(is_a); linkahead_entity_datatype_is_list_of_atomic(&out_type, &is_a); EXPECT_FALSE(is_a); linkahead_entity_datatype_is_list_of_reference(&out_type, &is_a); EXPECT_FALSE(is_a); linkahead_entity_datatype_get_datatype_name(&out_type, &out); EXPECT_STREQ(out, "TEXT"); linkahead_entity_property_get_importance(&property, &out); EXPECT_EQ(strcmp(out, "FIX"), 0); linkahead_entity_property_get_unit(&property, &out); EXPECT_EQ(strcmp(out, "some_unit"), 0); linkahead_entity_value out_value; return_code = linkahead_entity_property_get_value(&property, &out_value); EXPECT_EQ(return_code, 0); linkahead_entity_value_is_string(&out_value, &is_a); EXPECT_TRUE(is_a); linkahead_entity_value_get_as_string(&out_value, &out); EXPECT_STREQ(out, "some_value"); return_code = linkahead_entity_delete_property(&property); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_datatype(&in_type); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&in_value); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_string_list_property) { linkahead_entity_property property; int return_code(linkahead_entity_create_property(&property)); EXPECT_EQ(return_code, 0); linkahead_entity_datatype in_type; return_code = linkahead_entity_create_atomic_list_datatype(&in_type, "TEXT"); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_property_set_datatype(&property, &in_type); EXPECT_EQ(return_code, 0); linkahead_entity_value in_value; const char *value_list[] = {"val0", "val1", "val2"}; // NOLINT return_code = linkahead_entity_create_string_vector_value(&in_value, value_list, 3); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_property_set_value(&property, &in_value); EXPECT_EQ(return_code, 0); linkahead_entity_datatype out_type; return_code = linkahead_entity_property_get_datatype(&property, &out_type); EXPECT_EQ(return_code, 0); bool is_a(false); linkahead_entity_datatype_is_atomic(&out_type, &is_a); EXPECT_FALSE(is_a); linkahead_entity_datatype_is_reference(&out_type, &is_a); EXPECT_FALSE(is_a); linkahead_entity_datatype_is_list_of_atomic(&out_type, &is_a); EXPECT_TRUE(is_a); linkahead_entity_datatype_is_list_of_reference(&out_type, &is_a); EXPECT_FALSE(is_a); char *out = nullptr; // NOLINT linkahead_entity_datatype_get_datatype_name(&out_type, &out); EXPECT_STREQ(out, "TEXT"); linkahead_entity_value out_value; linkahead_entity_property_get_value(&property, &out_value); linkahead_entity_value_is_vector(&out_value, &is_a); EXPECT_TRUE(is_a); int length(-1); linkahead_entity_value_get_as_vector_size(&out_value, &length); EXPECT_EQ(length, 3); linkahead_entity_value list_elt; for (int i = 0; i < length; i++) { return_code = linkahead_entity_value_get_as_vector_at(&out_value, &list_elt, i); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_value_get_as_string(&list_elt, &out); EXPECT_EQ(return_code, 0); EXPECT_STREQ(value_list[i], out); // NOLINT } return_code = linkahead_entity_delete_property(&property); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_datatype(&in_type); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&in_value); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_int_list_property) { linkahead_entity_property property; int return_code(linkahead_entity_create_property(&property)); EXPECT_EQ(return_code, 0); linkahead_entity_datatype in_type; linkahead_entity_create_atomic_list_datatype(&in_type, "INTEGER"); return_code = linkahead_entity_property_set_datatype(&property, &in_type); EXPECT_EQ(return_code, 0); const int64_t value_list[] = {1, 2, 3}; // NOLINT linkahead_entity_value in_value; linkahead_entity_create_int_vector_value(&in_value, value_list, 3); return_code = linkahead_entity_property_set_value(&property, &in_value); EXPECT_EQ(return_code, 0); linkahead_entity_datatype out_type; return_code = linkahead_entity_property_get_datatype(&property, &out_type); EXPECT_EQ(return_code, 0); bool is_a(false); linkahead_entity_datatype_is_atomic(&out_type, &is_a); EXPECT_FALSE(is_a); linkahead_entity_datatype_is_reference(&out_type, &is_a); EXPECT_FALSE(is_a); linkahead_entity_datatype_is_list_of_atomic(&out_type, &is_a); EXPECT_TRUE(is_a); linkahead_entity_datatype_is_list_of_reference(&out_type, &is_a); EXPECT_FALSE(is_a); char *out = nullptr; // NOLINT linkahead_entity_datatype_get_datatype_name(&out_type, &out); EXPECT_STREQ(out, "INTEGER"); linkahead_entity_value out_value; linkahead_entity_property_get_value(&property, &out_value); linkahead_entity_value_is_vector(&out_value, &is_a); EXPECT_TRUE(is_a); int length(-1); linkahead_entity_value_get_as_vector_size(&out_value, &length); EXPECT_EQ(length, 3); int64_t out_int = -1; linkahead_entity_value list_elt; for (int i = 0; i < length; i++) { return_code = linkahead_entity_value_get_as_vector_at(&out_value, &list_elt, i); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_value_get_as_integer(&list_elt, &out_int); EXPECT_EQ(return_code, 0); EXPECT_EQ(value_list[i], out_int); // NOLINT } return_code = linkahead_entity_delete_property(&property); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_datatype(&in_type); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&in_value); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_bool_list_property) { linkahead_entity_property property; int return_code(linkahead_entity_create_property(&property)); EXPECT_EQ(return_code, 0); linkahead_entity_datatype in_type; linkahead_entity_create_atomic_list_datatype(&in_type, "BOOLEAN"); return_code = linkahead_entity_property_set_datatype(&property, &in_type); EXPECT_EQ(return_code, 0); const bool value_list[] = {true, true, false}; // NOLINT linkahead_entity_value in_value; linkahead_entity_create_bool_vector_value(&in_value, value_list, 3); return_code = linkahead_entity_property_set_value(&property, &in_value); EXPECT_EQ(return_code, 0); linkahead_entity_datatype out_type; return_code = linkahead_entity_property_get_datatype(&property, &out_type); EXPECT_EQ(return_code, 0); bool is_a(false); linkahead_entity_datatype_is_atomic(&out_type, &is_a); EXPECT_FALSE(is_a); linkahead_entity_datatype_is_reference(&out_type, &is_a); EXPECT_FALSE(is_a); linkahead_entity_datatype_is_list_of_atomic(&out_type, &is_a); EXPECT_TRUE(is_a); linkahead_entity_datatype_is_list_of_reference(&out_type, &is_a); EXPECT_FALSE(is_a); char *out = nullptr; // NOLINT linkahead_entity_datatype_get_datatype_name(&out_type, &out); EXPECT_STREQ(out, "BOOLEAN"); linkahead_entity_value out_value; linkahead_entity_property_get_value(&property, &out_value); linkahead_entity_value_is_vector(&out_value, &is_a); EXPECT_TRUE(is_a); int length(-1); linkahead_entity_value_get_as_vector_size(&out_value, &length); EXPECT_EQ(length, 3); bool out_bool(false); linkahead_entity_value list_elt; for (int i = 0; i < length; i++) { return_code = linkahead_entity_value_get_as_vector_at(&out_value, &list_elt, i); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_value_get_as_bool(&list_elt, &out_bool); EXPECT_EQ(return_code, 0); EXPECT_EQ(value_list[i], out_bool); // NOLINT } return_code = linkahead_entity_delete_property(&property); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_datatype(&in_type); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&in_value); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_entity_with_parent_and_property) { linkahead_entity_parent input_parent; int return_code(linkahead_entity_create_parent(&input_parent)); EXPECT_EQ(return_code, 0); linkahead_entity_parent_set_id(&input_parent, "parent_id"); linkahead_entity_parent_set_name(&input_parent, "parent_name"); linkahead_entity_property input_property; return_code = linkahead_entity_create_property(&input_property); EXPECT_EQ(return_code, 0); linkahead_entity_property_set_id(&input_property, "property_id"); linkahead_entity_property_set_name(&input_property, "property_name"); linkahead_entity_datatype in_type; linkahead_entity_create_atomic_datatype(&in_type, "TEXT"); linkahead_entity_value in_value; linkahead_entity_create_string_value(&in_value, "property_value"); linkahead_entity_property_set_datatype(&input_property, &in_type); linkahead_entity_property_set_value(&input_property, &in_value); linkahead_entity_entity entity; return_code = linkahead_entity_create_entity(&entity); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_entity_append_parent(&entity, &input_parent); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_entity_append_property(&entity, &input_property); EXPECT_EQ(return_code, 0); int count[] = {0}; // NOLINT return_code = linkahead_entity_entity_get_parents_size(&entity, count); EXPECT_EQ(return_code, 0); EXPECT_EQ(*count, 1); return_code = linkahead_entity_entity_get_properties_size(&entity, count); EXPECT_EQ(return_code, 0); EXPECT_EQ(*count, 1); char *in = nullptr; // NOLINT char *out = nullptr; // NOLINT // cannot assign an already assigned property // return_code = linkahead_entity_entity_get_property(&entity, &input_property, 0); // EXPECT_EQ(return_code, linkahead::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); linkahead_entity_property output_property; return_code = linkahead_entity_entity_get_property(&entity, &output_property, 0); EXPECT_EQ(return_code, 0); linkahead_entity_property_get_id(&input_property, &in); linkahead_entity_property_get_id(&output_property, &out); EXPECT_EQ(strcmp(in, out), 0); linkahead_entity_property_get_name(&input_property, &in); linkahead_entity_property_get_name(&output_property, &out); EXPECT_EQ(strcmp(in, out), 0); linkahead_entity_datatype out_type; linkahead_entity_property_get_datatype(&output_property, &out_type); bool in_is(false); bool out_is(false); linkahead_entity_datatype_is_atomic(&in_type, &in_is); linkahead_entity_datatype_is_atomic(&out_type, &out_is); EXPECT_EQ(in_is, out_is); linkahead_entity_datatype_is_reference(&in_type, &in_is); linkahead_entity_datatype_is_reference(&out_type, &out_is); EXPECT_EQ(in_is, out_is); linkahead_entity_datatype_is_list_of_atomic(&in_type, &in_is); linkahead_entity_datatype_is_list_of_atomic(&out_type, &out_is); EXPECT_EQ(in_is, out_is); linkahead_entity_datatype_is_list_of_reference(&in_type, &in_is); linkahead_entity_datatype_is_list_of_reference(&out_type, &out_is); EXPECT_EQ(in_is, out_is); linkahead_entity_datatype_get_datatype_name(&in_type, &in); linkahead_entity_datatype_get_datatype_name(&out_type, &out); EXPECT_STREQ(in, out); linkahead_entity_value out_value; linkahead_entity_property_get_value(&output_property, &out_value); linkahead_entity_value_is_string(&in_value, &in_is); EXPECT_TRUE(in_is); linkahead_entity_value_is_string(&out_value, &out_is); EXPECT_TRUE(out_is); linkahead_entity_value_get_as_string(&in_value, &in); linkahead_entity_value_get_as_string(&out_value, &out); EXPECT_STREQ(in, out); linkahead_entity_parent output_parent; return_code = linkahead_entity_entity_get_parent(&entity, &output_parent, 0); EXPECT_EQ(return_code, 0); linkahead_entity_parent_get_id(&input_parent, &in); linkahead_entity_parent_get_id(&output_parent, &out); EXPECT_EQ(strcmp(in, out), 0); linkahead_entity_parent_get_name(&input_parent, &in); linkahead_entity_parent_get_name(&output_parent, &out); EXPECT_EQ(strcmp(in, out), 0); // Delete everything return_code = linkahead_entity_delete_parent(&input_parent); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_property(&input_property); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_entity(&entity); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_datatype(&in_type); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_value(&in_value); EXPECT_EQ(return_code, 0); // This tests the `_deletable` flag. The wrapped cpp objects of // `output_parent` and `output_property` are owned by the entity, so // they have been deleted together with the entity. With a wrong // `_deletable` flag, the following would cause segfaults. // return_code = linkahead_entity_delete_parent(&output_parent); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_property(&output_property); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_remove_property) { linkahead_entity_entity entity; int return_code(linkahead_entity_create_entity(&entity)); EXPECT_EQ(return_code, 0); // Create two properties with names linkahead_entity_property in_prop_1; return_code = linkahead_entity_create_property(&in_prop_1); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_property_set_name(&in_prop_1, "Property 1"); EXPECT_EQ(return_code, 0); linkahead_entity_property in_prop_2; return_code = linkahead_entity_create_property(&in_prop_2); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_property_set_name(&in_prop_2, "Property 2"); EXPECT_EQ(return_code, 0); // Append them return_code = linkahead_entity_entity_append_property(&entity, &in_prop_1); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_entity_append_property(&entity, &in_prop_2); EXPECT_EQ(return_code, 0); // Delete one and see that the number of properties decreases by one int count[] = {0}; // NOLINT return_code = linkahead_entity_entity_get_properties_size(&entity, count); EXPECT_EQ(return_code, 0); EXPECT_EQ(*count, 2); return_code = linkahead_entity_entity_remove_property(&entity, 0); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_entity_get_properties_size(&entity, count); EXPECT_EQ(return_code, 0); EXPECT_EQ(*count, 1); linkahead_entity_property out_prop; return_code = linkahead_entity_entity_get_property(&entity, &out_prop, 0); EXPECT_EQ(return_code, 0); char *in = nullptr; // NOLINT char *out = nullptr; // NOLINT // Deleted the first property, so the second one should remain. return_code = linkahead_entity_property_get_name(&in_prop_2, &in); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_property_get_name(&out_prop, &out); EXPECT_EQ(return_code, 0); EXPECT_EQ(strcmp(in, out), 0); // Delete everything we have created return_code = linkahead_entity_delete_property(&in_prop_2); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_property(&in_prop_1); EXPECT_EQ(return_code, 0); return_code = linkahead_entity_delete_entity(&entity); EXPECT_EQ(return_code, 0); } TEST_F(test_clinkahead, test_insert_update_delete) { // Only test adding to a transaction. Excution and results are // tested in integration tests. linkahead_connection_connection connection; linkahead_connection_connection_manager_get_default_connection(&connection); linkahead_transaction_transaction insert_transaction; linkahead_connection_connection_create_transaction(&connection, &insert_transaction); linkahead_entity_entity entity; linkahead_entity_create_entity(&entity); linkahead_entity_entity_set_name(&entity, "some_name"); linkahead_entity_entity_set_local_path(&entity, "some_name"); linkahead_entity_entity_set_file_path(&entity, "some_name"); auto return_code = linkahead_transaction_transaction_insert_entity(&insert_transaction, &entity); EXPECT_EQ(return_code, linkahead::StatusCode::GO_ON); linkahead_transaction_transaction update_transaction; linkahead_connection_connection_create_transaction(&connection, &update_transaction); return_code = linkahead_transaction_transaction_update_entity(&update_transaction, &entity); // No ID, so this should be an error EXPECT_EQ(return_code, linkahead::StatusCode::ORIGINAL_ENTITY_MISSING_ID); linkahead_transaction_transaction delete_transaction; linkahead_connection_connection_create_transaction(&connection, &delete_transaction); return_code = linkahead_transaction_transaction_delete_by_id(&delete_transaction, "some_id"); // Could add further deletions EXPECT_EQ(return_code, linkahead::StatusCode::GO_ON); linkahead_entity_delete_entity(&entity); linkahead_transaction_delete_transaction(&insert_transaction); linkahead_transaction_delete_transaction(&update_transaction); linkahead_transaction_delete_transaction(&delete_transaction); }