/* * * This file is a part of the CaosDB Project. * * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com> * Copyright (C) 2021 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 "caosdb/configuration.h" #include "caosdb/status_code.h" // for StatusCode #include "caosdb_test_utility.h" // for EXPECT_THROW_MESSAGE, TEST_DATA_DIR #include "ccaosdb.h" // for caosdb_utility_get_env_var #include <cstring> // for strcmp #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 <iostream> #include <string> // for allocator class test_ccaosdb : public ::testing::Test { protected: void SetUp() override { caosdb::configuration::ConfigurationManager::Clear(); caosdb::configuration::ConfigurationManager::LoadSingleJSONConfiguration( TEST_DATA_DIR + "/test_caosdb_client.json"); } void TearDown() override { caosdb::configuration::ConfigurationManager::Clear(); } }; TEST_F(test_ccaosdb, test_get_env_var) { const char *const some_var = caosdb_utility_get_env_var("SOME_ENV_VAR", "fall-back"); EXPECT_EQ("fall-back", some_var); } TEST_F(test_ccaosdb, test_other_client_error) { EXPECT_EQ(caosdb_status_code_OTHER_CLIENT_ERROR(), caosdb::StatusCode::OTHER_CLIENT_ERROR); } TEST_F(test_ccaosdb, test_get_default_connection) { caosdb_connection_connection out; caosdb_connection_connection_manager_get_default_connection(&out); EXPECT_TRUE(out.wrapped_connection); } TEST_F(test_ccaosdb, test_get_connection) { caosdb_connection_connection out; caosdb_connection_connection_manager_get_connection(&out, "local-caosdb-admin"); EXPECT_TRUE(out.wrapped_connection); } TEST_F(test_ccaosdb, test_execute_transaction) { caosdb_connection_connection connection; caosdb_connection_connection_manager_get_connection(&connection, "local-caosdb-admin"); caosdb_transaction_transaction transaction; caosdb_connection_connection_create_transaction(&connection, &transaction); EXPECT_TRUE(transaction.wrapped_transaction); int return_code(caosdb_transaction_transaction_retrieve_by_id(&transaction, "some_id")); EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON); return_code = caosdb_transaction_transaction_execute(&transaction); EXPECT_EQ(return_code, caosdb::StatusCode::CONNECTION_ERROR); return_code = caosdb_transaction_delete_transaction(&transaction); EXPECT_EQ(return_code, 0); caosdb_transaction_transaction multi_transaction; caosdb_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 = caosdb_transaction_transaction_retrieve_by_ids(&multi_transaction, ids, 3); EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON); return_code = caosdb_transaction_delete_transaction(&multi_transaction); EXPECT_EQ(return_code, 0); } TEST_F(test_ccaosdb, test_multi_retrieve) { std::cout << "Entering test_multi_retrieve ..." << std::endl; caosdb_connection_connection connection; caosdb_connection_connection_manager_get_connection(&connection, "local-caosdb-admin"); std::cout << "Creating transaction" << std::endl; caosdb_transaction_transaction multi_transaction; caosdb_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 std::cout << "Adding mutli retrieval ..." << std::endl; int return_code(caosdb_transaction_transaction_retrieve_by_ids(&multi_transaction, ids, 3)); EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON); std::cout << "Deleting transaction ..." << std::endl; return_code = caosdb_transaction_delete_transaction(&multi_transaction); EXPECT_EQ(return_code, 0); } TEST_F(test_ccaosdb, test_query) { caosdb_connection_connection connection; caosdb_connection_connection_manager_get_connection(&connection, "local-caosdb-admin"); caosdb_transaction_transaction transaction; caosdb_connection_connection_create_transaction(&connection, &transaction); int return_code(caosdb_transaction_transaction_query(&transaction, "FIND ENTITY WITH id=123")); EXPECT_EQ(return_code, caosdb::StatusCode::GO_ON); return_code = caosdb_transaction_delete_transaction(&transaction); EXPECT_EQ(return_code, 0); } TEST_F(test_ccaosdb, test_entity) { caosdb_entity_entity entity; int return_code(caosdb_entity_create_entity(&entity)); EXPECT_EQ(return_code, 0); // cannot be created again without deletion return_code = caosdb_entity_create_entity(&entity); EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); // deletion and re-creation is ok return_code = caosdb_entity_delete_entity(&entity); EXPECT_EQ(return_code, 0); return_code = caosdb_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 = caosdb_entity_entity_set_name(&entity, "length"); EXPECT_EQ(return_code, 0); char out[255] = {"a"}; // NOLINT return_code = caosdb_entity_entity_get_name(&entity, out); EXPECT_EQ(return_code, 0); EXPECT_EQ(strcmp(out, "length"), 0); // TODO(fspreck) // caosdb_entity_entity_set_role(&entity, "Property"); // caosdb_entity_entity_get_role(&entity, out); // EXPECT_EQ(strcmp(out, "Property"), 0); caosdb_entity_entity_set_description(&entity, "The length of an object"); caosdb_entity_entity_get_description(&entity, out); EXPECT_EQ(strcmp(out, "The length of an object"), 0); // TODO(fspreck) // caosdb_entity_entity_set_datatype(&entity, "DOUBLE"); // caosdb_entity_entity_get_datatype(&entity, out); // EXPECT_EQ(strcmp(out, "DOUBLE"), 0); caosdb_entity_entity_set_unit(&entity, "m"); caosdb_entity_entity_get_unit(&entity, out); EXPECT_EQ(strcmp(out, "m"), 0); // TODO(fspreck) // caosdb_entity_entity_set_value(&entity, "5.0"); // caosdb_entity_entity_get_value(&entity, out); // EXPECT_EQ(strcmp(out, "5.0"), 0); return_code = caosdb_entity_delete_entity(&entity); EXPECT_EQ(return_code, 0); } TEST_F(test_ccaosdb, test_parent) { caosdb_entity_parent parent; int return_code(caosdb_entity_create_parent(&parent)); EXPECT_EQ(return_code, 0); caosdb_entity_parent_set_id(&parent, "some_id"); caosdb_entity_parent_set_name(&parent, "some_name"); char out[255] = {"a"}; // NOLINT caosdb_entity_parent_get_id(&parent, out); EXPECT_EQ(strcmp(out, "some_id"), 0); caosdb_entity_parent_get_name(&parent, out); EXPECT_EQ(strcmp(out, "some_name"), 0); return_code = caosdb_entity_delete_parent(&parent); EXPECT_EQ(return_code, 0); } TEST_F(test_ccaosdb, test_property) { caosdb_entity_property property; int return_code(caosdb_entity_create_property(&property)); EXPECT_EQ(return_code, 0); caosdb_entity_property_set_id(&property, "some_id"); caosdb_entity_property_set_name(&property, "some_name"); // TODO(fspreck) // caosdb_entity_property_set_datatype(&property, "some_datatype"); // TODO(fspreck) // caosdb_entity_property_set_importance(&property, "some_importance"); caosdb_entity_property_set_unit(&property, "some_unit"); // TODO(fspreck) // caosdb_entity_property_set_value(&property, "some_value"); char out[255] = {"a"}; // NOLINT caosdb_entity_property_get_id(&property, out); EXPECT_EQ(strcmp(out, "some_id"), 0); caosdb_entity_property_get_name(&property, out); EXPECT_EQ(strcmp(out, "some_name"), 0); // TODO(fspreck) // caosdb_entity_property_get_datatype(&property, out); // EXPECT_EQ(strcmp(out, "some_datatype"), 0); // TODO(fspreck) // caosdb_entity_property_get_importance(&property, out); // EXPECT_EQ(strcmp(out, "some_importance"), 0); caosdb_entity_property_get_unit(&property, out); EXPECT_EQ(strcmp(out, "some_unit"), 0); // TODO(fspreck) // caosdb_entity_property_get_value(&property, out); // EXPECT_EQ(strcmp(out, "some_value"), 0); return_code = caosdb_entity_delete_property(&property); EXPECT_EQ(return_code, 0); } TEST_F(test_ccaosdb, test_entity_with_parent_and_property) { std::cout << "Creating objects ... " << std::endl; caosdb_entity_parent input_parent; int return_code(caosdb_entity_create_parent(&input_parent)); EXPECT_EQ(return_code, 0); caosdb_entity_parent_set_id(&input_parent, "parent_id"); caosdb_entity_parent_set_name(&input_parent, "parent_name"); caosdb_entity_property input_property; return_code = caosdb_entity_create_property(&input_property); EXPECT_EQ(return_code, 0); caosdb_entity_property_set_id(&input_property, "property_id"); caosdb_entity_property_set_name(&input_property, "property_name"); // TODO(fspreck) // caosdb_entity_property_set_datatype(&input_property, "property_datatype"); // TODO(fspreck) // caosdb_entity_property_set_value(&input_property, "property_value"); caosdb_entity_entity entity; return_code = caosdb_entity_create_entity(&entity); EXPECT_EQ(return_code, 0); std::cout << "Appending parent and property ..." << std::endl; return_code = caosdb_entity_entity_append_parent(&entity, &input_parent); EXPECT_EQ(return_code, 0); return_code = caosdb_entity_entity_append_property(&entity, &input_property); EXPECT_EQ(return_code, 0); std::cout << "Counting parents and properties ..." << std::endl; int count[] = {0}; // NOLINT return_code = caosdb_entity_entity_get_parents_size(&entity, count); EXPECT_EQ(return_code, 0); EXPECT_EQ(*count, 1); return_code = caosdb_entity_entity_get_properties_size(&entity, count); EXPECT_EQ(return_code, 0); EXPECT_EQ(*count, 1); char in[255] = {"a"}; // NOLINT char out[255] = {"b"}; // NOLINT std::cout << "Comparing ..." << std::endl; // cannot assign an already assigned property return_code = caosdb_entity_entity_get_property(&entity, &input_property, 0); EXPECT_EQ(return_code, caosdb::StatusCode::EXTERN_C_ASSIGNMENT_ERROR); caosdb_entity_property output_property; return_code = caosdb_entity_entity_get_property(&entity, &output_property, 0); std::cout << "Got output property." << std::endl; EXPECT_EQ(return_code, 0); caosdb_entity_property_get_id(&input_property, in); std::cout << "Got input id." << std::endl; caosdb_entity_property_get_id(&output_property, out); std::cout << "Got output id." << std::endl; EXPECT_EQ(strcmp(in, out), 0); caosdb_entity_property_get_name(&input_property, in); caosdb_entity_property_get_name(&output_property, out); EXPECT_EQ(strcmp(in, out), 0); // TODO(fspreck) // caosdb_entity_property_get_datatype(&input_property, in); // caosdb_entity_property_get_datatype(&output_property, out); // EXPECT_EQ(strcmp(in, out), 0); // TODO(fspreck) // caosdb_entity_property_get_value(&input_property, in); // caosdb_entity_property_get_value(&output_property, out); // EXPECT_EQ(strcmp(in, out), 0); std::cout << "Comparing parent..." << std::endl; caosdb_entity_parent output_parent; return_code = caosdb_entity_entity_get_parent(&entity, &output_parent, 0); std::cout << "Got output parent." << std::endl; EXPECT_EQ(return_code, 0); caosdb_entity_parent_get_id(&input_parent, in); caosdb_entity_parent_get_id(&output_parent, out); EXPECT_EQ(strcmp(in, out), 0); caosdb_entity_parent_get_name(&input_parent, in); caosdb_entity_parent_get_name(&output_parent, out); EXPECT_EQ(strcmp(in, out), 0); // Delete everything std::cout << "Deleting ..." << std::endl; return_code = caosdb_entity_delete_parent(&input_parent); EXPECT_EQ(return_code, 0); return_code = caosdb_entity_delete_property(&input_property); EXPECT_EQ(return_code, 0); return_code = caosdb_entity_delete_entity(&entity); 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 = caosdb_entity_delete_parent(&output_parent); EXPECT_EQ(return_code, 0); return_code = caosdb_entity_delete_property(&output_property); EXPECT_EQ(return_code, 0); } TEST_F(test_ccaosdb, test_remove_property) { caosdb_entity_entity entity; int return_code(caosdb_entity_create_entity(&entity)); EXPECT_EQ(return_code, 0); // Create two properties with names caosdb_entity_property in_prop_1; return_code = caosdb_entity_create_property(&in_prop_1); EXPECT_EQ(return_code, 0); return_code = caosdb_entity_property_set_name(&in_prop_1, "Property 1"); EXPECT_EQ(return_code, 0); caosdb_entity_property in_prop_2; return_code = caosdb_entity_create_property(&in_prop_2); EXPECT_EQ(return_code, 0); return_code = caosdb_entity_property_set_name(&in_prop_2, "Property 2"); EXPECT_EQ(return_code, 0); // Append them return_code = caosdb_entity_entity_append_property(&entity, &in_prop_1); EXPECT_EQ(return_code, 0); return_code = caosdb_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 = caosdb_entity_entity_get_properties_size(&entity, count); EXPECT_EQ(return_code, 0); EXPECT_EQ(*count, 2); return_code = caosdb_entity_entity_remove_property(&entity, 0); EXPECT_EQ(return_code, 0); return_code = caosdb_entity_entity_get_properties_size(&entity, count); EXPECT_EQ(return_code, 0); EXPECT_EQ(*count, 1); caosdb_entity_property out_prop; return_code = caosdb_entity_entity_get_property(&entity, &out_prop, 0); EXPECT_EQ(return_code, 0); char in[255] = {"a"}; // NOLINT char out[255] = {"b"}; // NOLINT // Deleted the first property, so the second one should remain. return_code = caosdb_entity_property_get_name(&in_prop_2, in); EXPECT_EQ(return_code, 0); return_code = caosdb_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 = caosdb_entity_delete_property(&in_prop_2); EXPECT_EQ(return_code, 0); return_code = caosdb_entity_delete_property(&in_prop_1); EXPECT_EQ(return_code, 0); return_code = caosdb_entity_delete_entity(&entity); EXPECT_EQ(return_code, 0); }