Skip to content
Snippets Groups Projects
Verified Commit 5f4577fa authored by Timm Fitschen's avatar Timm Fitschen
Browse files

WIP: first c-interface stub

parent 89ab719c
No related branches found
No related tags found
1 merge request!1Minimal c interface
Pipeline #10209 failed
......@@ -24,8 +24,8 @@ set(libcaosdb_VERSION 0.0.4)
project(libcaosdb
VERSION ${libcaosdb_VERSION}
DESCRIPTION "C++ client libraries for CaosDB"
LANGUAGES CXX)
DESCRIPTION "C and C++ client libraries for CaosDB"
LANGUAGES CXX C)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
......@@ -116,28 +116,76 @@ add_custom_command(
${PROTO_FILES}
DEPENDS ${PROTO_FILES})
###############################################################################
### Set up main targets
### * [caosdb_grpc] - only in Debug builds. Otherwise this library is compiled
### into caosdb libraray
### * caosdb (links to caosdb_grpc) - The main library.
### * cxxcaosdbcli - A C++ test client.
### * ccaosdb - A C-Wrapper of the C++ caosdb library.
### * ccaosdbcli - A plain C test client.
###############################################################################
if("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
add_library(caosdb_grpc STATIC ${GRPC_GENERATED})
add_library(caosdb STATIC ${libcaosdb_INCL} ${libcaosdb_SRC})
target_link_libraries(caosdb caosdb_grpc)
set(LIBCAOSDB caosdb caosdb_grpc)
target_include_directories(caosdb_grpc PUBLIC
$<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
$<INSTALL_INTERFACE:include>
${CONAN_INCLUDE_DIRS}
)
else()
add_library(caosdb
STATIC ${libcaosdb_INCL} ${libcaosdb_SRC} ${GRPC_GENERATED})
set(LIBCAOSDB caosdb)
endif()
add_executable(caosdbcli src/caosdbcli.cpp)
target_link_libraries(caosdb
${CONAN_LIBS}
)
target_include_directories(caosdb PUBLIC
$<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
$<INSTALL_INTERFACE:include>
${CONAN_INCLUDE_DIRS}
)
add_library(ccaosdb STATIC src/ccaosdb.cpp)
target_link_libraries(ccaosdb
${LIBCAOSDB}
${CONAN_LIBS}
)
add_executable(ccaosdbcli src/ccaosdbcli.c)
target_include_directories(ccaosdbcli PUBLIC
$<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
$<INSTALL_INTERFACE:include>
${CONAN_INCLUDE_DIRS}
)
target_link_libraries(ccaosdbcli
ccaosdb
${CONAN_LIBS}
)
target_link_libraries(caosdbcli
add_executable(cxxcaosdbcli src/cxxcaosdbcli.cpp)
target_include_directories(cxxcaosdbcli PUBLIC
$<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
$<INSTALL_INTERFACE:include>
${CONAN_INCLUDE_DIRS}
)
target_link_libraries(cxxcaosdbcli
${LIBCAOSDB}
${CONAN_LIBS}
)
#######################################################
### LINTING with CLANG-TIDY and INCLUDE-WHAT-YOU-USE
#######################################################
......@@ -165,9 +213,12 @@ if(_LINTING)
set_target_properties(caosdb PROPERTIES
CXX_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}"
)
set_target_properties(caosdbcli PROPERTIES
set_target_properties(cxxcaosdbcli PROPERTIES
CXX_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}"
)
set_target_properties(ccaosdbcli PROPERTIES
C_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}"
)
endif()
find_program(clang_tidy NAMES clang-tidy clang-tidy-11)
......@@ -189,9 +240,12 @@ if(_LINTING)
set_target_properties(caosdb PROPERTIES
CXX_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_CHECKS}"
)
set_target_properties(caosdbcli PROPERTIES
set_target_properties(cxxcaosdbcli PROPERTIES
CXX_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_CHECKS}"
)
set_target_properties(ccaosdbcli PROPERTIES
C_CLANG_TIDY "${_CMAKE_CXX_CLANG_TIDY};${_CMAKE_CXX_CLANG_TIDY_CHECKS}"
)
endif()
endif()
......@@ -212,32 +266,6 @@ endif()
set(libcaosdb_INCLUDE_DEST "include/caosdb")
set(libcaosdb_LIB_DEST "lib")
target_include_directories(caosdb PUBLIC
# headers to include when building from source
$<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
# headers to include when installing (implicitly prefixes with ${CMAKE_INSTALL_PREFIX}).
$<INSTALL_INTERFACE:include>
)
if("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
target_include_directories(caosdb_grpc PUBLIC
# headers to include when building from source
$<BUILD_INTERFACE:${libcaosdb_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${libcaosdb_BINARY_DIR}/include>
# headers to include when installing (implicitly prefixes with ${CMAKE_INSTALL_PREFIX}).
$<INSTALL_INTERFACE:include>
)
endif()
target_include_directories(caosdbcli PUBLIC
${libcaosdb_SOURCE_DIR}/include>
${libcaosdb_BINARY_DIR}/include>
${CONAN_INCLUDE_DIRS}
)
set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local/")
install(
# targets to install
......@@ -290,7 +318,10 @@ if(AUTOFORMATTING)
file(GLOB format_test_sources test/*.cpp test/*.h)
execute_process(COMMAND clang-format -i --verbose ${libcaosdb_INCL}
${libcaosdb_SRC} ${libcaosdb_TEST_SRC}
${PROJECT_SOURCE_DIR}/src/caosdbcli.cpp
${PROJECT_SOURCE_DIR}/src/cxxcaosdbcli.cpp
${PROJECT_SOURCE_DIR}/src/ccaosdbcli.c
${PROJECT_SOURCE_DIR}/src/ccaosdb.cpp
${PROJECT_SOURCE_DIR}/include/ccaosdb.h
${format_test_sources}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
endif()
......@@ -22,11 +22,15 @@
#ifndef CAOSDB_CONSTANTS_H
#define CAOSDB_CONSTANTS_H
#ifdef __cplusplus
namespace caosdb {
#endif
// clang-format off
constexpr int LIBCAOSDB_VERSION_MAJOR = @libcaosdb_VERSION_MAJOR@;
constexpr int LIBCAOSDB_VERSION_MINOR = @libcaosdb_VERSION_MINOR@;
constexpr int LIBCAOSDB_VERSION_PATCH = @libcaosdb_VERSION_PATCH@;
const int LIBCAOSDB_VERSION_MAJOR = @libcaosdb_VERSION_MAJOR@;
const int LIBCAOSDB_VERSION_MINOR = @libcaosdb_VERSION_MINOR@;
const int LIBCAOSDB_VERSION_PATCH = @libcaosdb_VERSION_PATCH@;
// clang-format on
#ifdef __cplusplus
} // namespace caosdb
#endif
#endif
......@@ -21,14 +21,23 @@
#ifndef CAOSDB_UTILS_H
#define CAOSDB_UTILS_H
#include <cassert>
#include <iostream>
#include <string_view>
#include <fstream>
#include <string>
#include <cstdlib>
#include <boost/json.hpp>
#include <boost/beast/core/detail/base64.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
namespace caosdb::utils {
using boost::filesystem::exists;
using boost::filesystem::ifstream;
using boost::filesystem::path;
using boost::json::stream_parser;
using boost::json::value;
/**
* @brief Read a text file into a string and return the file's content.
......@@ -50,18 +59,25 @@ inline auto load_string_file(const std::string &path) -> std::string {
return result;
}
inline auto get_env_var(const char *key, const char *fall_back) -> const
char * {
const char *val = getenv(key);
if (val == nullptr) {
return fall_back;
} else {
return val;
}
}
/**
* @brief Return the value of an environment variable or - if undefined - the
* fall_back value.
*/
inline auto get_env_var(const std::string &key, const std::string &fall_back)
-> std::string {
const char *val = getenv(key.c_str());
if (val == nullptr) {
return fall_back;
}
-> const std::string {
const char *val = get_env_var(key.c_str(), fall_back.c_str());
auto result = std::string(val);
auto const result = std::string(val);
return result;
}
......@@ -79,5 +95,24 @@ inline auto base64_encode(const std::string &plain) -> std::string {
return std::string(encoded, encoded + size_encoded);
}
inline auto load_json_file(const path &json_file) -> value {
assert(exists(json_file));
constexpr auto buffer_size = std::size_t(4096);
auto stream = ifstream(json_file);
stream.exceptions(std::ios_base::badbit);
stream_parser parser;
auto result = std::string();
auto buffer = std::string(buffer_size, '\0');
while (stream.read(&buffer[0], buffer_size)) {
parser.write(buffer.c_str(), stream.gcount());
}
parser.write(buffer.c_str(), stream.gcount());
assert(parser.done());
return parser.release();
}
} // namespace caosdb::utils
#endif
#ifdef __cplusplus
extern "C" {
#else
#include <stdbool.h>
#endif
/**
* A wrapper of the C++ CaosDBConnection class.
*
* We use a wrapper for future extensibility and in order to have a minimal
* capability for type checking in C even though the C++ class
* CaosDBConnection is opaque in C.
*/
typedef struct {
void *wrapped_connection;
} caosdb_connection_connection;
/**
* A wrapper of the C++ CaosDBConnectionConfig class.
*
* We use a wrapper for future extensibility and in order to have a minimal
* capability for type checking in C even though the C++ class
* CaosDBConnection is opaque in C.
*/
typedef struct {
void *wrapped_connection_config;
} caosdb_connection_connection_config;
/**
* A wrapper of the C++ VersionInfo class.
*
* We use a wrapper for future extensibility and in order to have a minimal
* capability for type checking in C even though the C++ class
* CaosDBConnection is opaque in C.
*/
typedef struct {
void *wrapped_version_info;
} caosdb_info_version_info;
/**
* Return the environment variable of the given name.
*
* If the environment variable is not set, return the fall_back instead.
*/
const char *caosdb_utils_get_env_var(const char *name, const char *fall_back);
/**
* Create a connection config.
*
* The config is needed to instantiate a connection.
*
* The config is ready to be used but you might want use
* caosdb_connection_config_add_cacert and
* caosdb_connection_config_add_plain_authenticator to specify more options of
* the connection.
*/
int caosdb_connection_create_config(caosdb_connection_connection_config *config,
const char *host, const int port,
const bool tls);
/**
* Add a public certificate of a trusted certificate authority to an
* existing, tls-enabled connection configuration.
*
* @param cacert path to a pem-file.
*/
int caosdb_connection_config_add_cacert(
caosdb_connection_connection_config *config, const char *cacert);
/**
* Add a plain text authenticator to an existing, tls enabled connection
* configuration.
*/
int caosdb_connection_config_add_plain_authenticator(
caosdb_connection_connection_config *config, const char *username,
const char *password);
/**
* Create a connection instance.
*
* The connection is needed to create transactions and to initiate any other
* interaction with a CaosDB server.
*/
int caosdb_connection_create_connection(
caosdb_connection_connection *connection,
const caosdb_connection_connection_config *config);
/**
* Request the version of the server.
*/
int caosdb_connection_get_version_info(
caosdb_info_version_info *version_info,
const caosdb_connection_connection *connection);
#ifdef __cplusplus
}
#endif
#include "caosdb/utils.h"
#include "caosdb/constants.h"
#include "ccaosdb.h"
extern "C" {
const int LIBCAOSDB_VERSION_MINOR = caosdb::LIBCAOSDB_VERSION_MAJOR;
const int LIBCAOSDB_VERSION_MAJOR = caosdb::LIBCAOSDB_VERSION_MINOR;
const int LIBCAOSDB_VERSION_PATCH = caosdb::LIBCAOSDB_VERSION_PATCH;
const char *caosdb_utils_get_env_var(const char *name, const char *fall_back) {
return caosdb::utils::get_env_var(name, fall_back);
}
// int caosdb_connection_create_config(caosdb_connection_config *config, const
// char *host, const int port, const bool tls);
// int caosdb_connection_config_add_cacert(caosdb_connection_config *config,
// const char *cacert);
// int caosdb_connection_config_add_plain_authenticator(caosdb_connection_config
// *config, const char *username, const char *password);
// int caosdb_connection_create_connection(caosdb_connection *connection, const
// caosdb_connection_config *config);
}
#include "ccaosdb.h"
#include "caosdb/constants.h"
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf(
"CaosDB C client (libcaosdb %d.%d.%d)\nWe don't miss the H of caos.\n\n",
LIBCAOSDB_VERSION_MAJOR, LIBCAOSDB_VERSION_MINOR, LIBCAOSDB_VERSION_PATCH);
const char *host =
caosdb_utils_get_env_var("CAOSDB_SERVER_HOST", "localhost");
const char *port_str = caosdb_utils_get_env_var("CAOSDB_SERVER_HOST", "8443");
char *end = NULL;
const int port = (int)strtol(port_str, &end, 10);
printf("Connecting to host: %s:%d\n", host, port);
return 0;
}
......@@ -33,8 +33,8 @@
#include "caosdb/transaction.h" // for Transaction, UniqueResult
auto main() -> int {
std::cout << "CaosDB (libcaosdb " << caosdb::LIBCAOSDB_VERSION_MINOR << "."
std::cout << "CaosDB C++ client (libcaosdb "
<< caosdb::LIBCAOSDB_VERSION_MINOR << "."
<< caosdb::LIBCAOSDB_VERSION_MINOR << "."
<< caosdb::LIBCAOSDB_VERSION_PATCH << ")\n"
<< "We don't miss the H of caos.\n"
......@@ -42,13 +42,14 @@ auto main() -> int {
const auto pem_file =
caosdb::utils::get_env_var("CAOSDB_SERVER_CERT", std::string());
const auto host =
const auto *const host =
caosdb::utils::get_env_var("CAOSDB_SERVER_HOST", "localhost");
const auto port_str =
const auto *const port_str =
caosdb::utils::get_env_var("CAOSDB_SERVER_GRPC_PORT_HTTPS", "8443");
const auto port = std::stoi(port_str);
const auto user = caosdb::utils::get_env_var("CAOSDB_USER", "admin");
const auto password = caosdb::utils::get_env_var("CAOSDB_PASSWORD", "caosdb");
const auto *const user = caosdb::utils::get_env_var("CAOSDB_USER", "admin");
const auto *const password =
caosdb::utils::get_env_var("CAOSDB_PASSWORD", "caosdb");
// setup the connection
auto auth =
......
......@@ -24,6 +24,7 @@ set(test_cases
test_info
test_transaction
test_utils
test_ccaosdb
)
###################################################
......@@ -38,6 +39,7 @@ set(_CMAKE_CXX_CLANG_TIDY_TEST_CHECKS
# add special cmake functions for gtest
include(GoogleTest)
# loop over all test cases and add them to the test runner
list(LENGTH test_cases len_test_cases)
math(EXPR len_test_cases "${len_test_cases} - 1")
......@@ -47,9 +49,9 @@ foreach (i RANGE "${len_test_cases}")
set(libcaosdb_TEST_SRC "${CMAKE_CURRENT_SOURCE_DIR}/${test_case_name}.cpp
${libcaosdb_TEST_SRC}")
target_link_libraries(${test_case_name}
PRIVATE ${LIBCAOSDB} ${CONAN_LIBS_GTEST} ${CONAN_LIBS_BOOST})
PRIVATE ${LIBCAOSDB} ccaosdb ${CONAN_LIBS_GTEST} ${CONAN_LIBS_BOOST})
target_include_directories(${test_case_name}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
if(_LINTING)
set_target_properties(${test_case_name}
PROPERTIES
......@@ -57,10 +59,18 @@ foreach (i RANGE "${len_test_cases}")
CXX_INCLUDE_WHAT_YOU_USE "${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE}")
endif()
gtest_discover_tests(${test_case_name}
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
PROPERTIES
LABELS "caosdb-cpplib-unit-tests")
endforeach ()
# copy test data to build dir
set(TEST_DATA_DIR "${CMAKE_CURRENT_SOURCE_DIR}/test_data")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/caosdb_test_utility.h.in
${CMAKE_CURRENT_BINARY_DIR}/caosdb_test_utility.h)
###################################################
### Set up test coverage repor (Gcov + Lcov)
......@@ -75,12 +85,12 @@ if (LCOV_PATH)
NAME unit_test_coverage
EXECUTABLE ctest -L caosdb-cpplib-unit-tests
EXCLUDE "${CMAKE_BINARY_DIR}/*"
DEPENDENCIES caosdb ${test_cases}
DEPENDENCIES caosdb ccaosdb ${test_cases}
LCOV_ARGS --rc lcov_branch_coverage=1 --no-external
GENHTML_ARGS --rc lcov_branch_coverage=1
)
message(STATUS "Adding COMPILE_FLAGS for coverage: ${COVERAGE_COMPILER_FLAGS}")
set_target_properties(caosdb PROPERTIES
set_target_properties(caosdb ccaosdb PROPERTIES
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}")
else ()
message(WARNING "Could not generate code coverage report. Please install lcov.")
......
......@@ -43,3 +43,5 @@
}, \
exeption_type)
#endif
const std::string TEST_DATA_DIR = "@TEST_DATA_DIR@";
/*
*
* 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 <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
#include "ccaosdb.h" // for caosdb_utils_get_env_var
TEST(test_ccaosdb, test_get_env_var) {
const char *const some_var =
caosdb_utils_get_env_var("SOME_ENV_VAR", "fall-back");
EXPECT_EQ("fall-back", some_var);
}
{
"this": [ "is", "a", "test" ],
"it" : "tests",
"numbers": [ 1, 2, 3.3 ],
"null values": null,
"arrays and objects":
{ "see?": [ true, false ] }
}
......@@ -20,17 +20,37 @@
*
*/
#include "caosdb/utils.h"
#include <string>
#include <gtest/gtest-message.h>
#include <gtest/gtest-test-part.h>
#include "gtest/gtest_pred_impl.h"
#include <boost/beast/core/detail/base64.hpp>
#include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteA...
#include <gtest/gtest_pred_impl.h> // for Test, EXPECT_EQ, TestInfo
#include <boost/beast/core/detail/base64.hpp> // for encoded_size
#include <string> // for allocator, string, ope...
#include "boost/json/object.hpp" // for object
#include "boost/json/value.hpp" // for value
#include "caosdb/utils.h" // for base64_encode, load_js...
#include "caosdb_test_utility.h" // for TEST_DATA_DIR
#include "gmock/gmock-matchers.h" // for ElementsAre, EXPECT_THAT
namespace caosdb::utils {
using ::testing::ElementsAre;
TEST(test_utils, base64_encode) {
auto test_plain = std::string("admin:caosdb");
auto test_encoded = std::string("YWRtaW46Y2Fvc2Ri");
ASSERT_EQ(12, test_plain.size());
ASSERT_EQ(16, boost::beast::detail::base64::encoded_size(test_plain.size()));
ASSERT_EQ(test_encoded, caosdb::utils::base64_encode(test_plain));
EXPECT_EQ(12, test_plain.size());
EXPECT_EQ(16, boost::beast::detail::base64::encoded_size(test_plain.size()));
EXPECT_EQ(test_encoded, base64_encode(test_plain));
}
TEST(test_utils, test_load_json_file) {
auto json = load_json_file(TEST_DATA_DIR + "/test.json").as_object();
EXPECT_EQ(json["it"], "tests");
EXPECT_EQ(json["null values"], nullptr);
EXPECT_THAT(json["this"].as_array(), ElementsAre("is", "a", "test"));
EXPECT_THAT(json["numbers"].as_array(), ElementsAre(1, 2, 3.3));
auto sub = json["arrays and objects"].as_object();
EXPECT_THAT(sub["see?"].as_array(), ElementsAre(true, false));
}
} // namespace caosdb::utils
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment