diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 812b8ab5e9fb1e08aaf1723e60651aa4a34a6fc9..f02b6972e4c0baf8b761ec97e6aac2c65350f0e6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -62,14 +62,14 @@ code_style_octave: stage: test script: - mh_style -v - - mh_style --octave ./src ./doc + - make style_octave allow_failure: true code_style_cpp: tags: [ docker ] stage: test script: - - clang-format-11 --dry-run --verbose --Werror $(find test/ src/ -type f -iname "*.cpp" -o -iname "*.h" -o -iname "*.h.in") + - make style_cpp allow_failure: true unit_tests: @@ -79,30 +79,21 @@ unit_tests: - octave -v - make test -package_tests: - tags: [ docker ] - stage: test - script: - - octave -v - - make pkg-test - # Linting with miss_hit linting_octave: tags: [ docker ] stage: test script: - - mh_lint --octave ./ + - make linting_octave + allow_failure: true # linting with clang-tidy and include-what-you-use linting_cpp: tags: [ docker ] stage: test script: - - cd src - - ./configure - - cd ../build - - cmake -D LINTING=On .. - - cmake --build . + - make linting_cpp + allow_failure: true # trigger the integration tests trigger_inttest: @@ -111,7 +102,7 @@ trigger_inttest: script: ## Determine the octaveinttest branch... - # ... use an f-branch if posible... + # ... sync'ed f-branch (f-bar on octavelib requires f-bar on octaveinttest)... - if echo "$CI_COMMIT_REF_NAME" | grep -c "^f-" ; then OCTAVEINT_REF=$CI_COMMIT_REF_NAME ; fi; diff --git a/ChangeLog b/CHANGELOG.md similarity index 86% rename from ChangeLog rename to CHANGELOG.md index 112d008ea737b3aff591b06155dd37f31f09b3bb..585a63db0bbb212bc533b222ade04db9359aadbb 100644 --- a/ChangeLog +++ b/CHANGELOG.md @@ -23,4 +23,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### -- Everything. +- Minimal working example with basic connection functionality. diff --git a/CMakeLists.txt b/CMakeLists.txt index 8382a5160e698c43881afdce2a6659a807e61204..ac4b6f47b13f07cb0fe906c3501dddb9bbaee8f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -47,33 +47,81 @@ string(REGEX REPLACE ";grpc\\+?\\+?_unsecure" "" CONAN_PKG_LIBS ####################################################### option(AUTOFORMATTING "call clang-format at configure time" ON) if(AUTOFORMATTING) - file(GLOB format_sources src/*.cpp) - execute_process(COMMAND clang-format -i --verbose ${format_sources} + find_program(clang_format NAMES clang-format-11 clang-format) + file(GLOB_RECURSE format_sources src/*.cpp) + execute_process(COMMAND ${clang_format} -i --verbose ${format_sources} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) endif() ####################################################### -### Compile *.mex files +### Build utility library "maoxdb" ####################################################### -add_subdirectory(src) -set(PKG_INST_DIR "${PROJECT_SOURCE_DIR}/inst") +# The library will be called maoxdb until we find a better name. The name is not very important +# though, since the library is used only internally. + +# OCTINCLUDEDIR +execute_process(COMMAND mkoctfile -p OCTINCLUDEDIR + OUTPUT_VARIABLE OCTINCLUDEDIR + ) +string(REGEX REPLACE "\n" "" OCTINCLUDEDIR "${OCTINCLUDEDIR}") +# OCTLIBDIR +execute_process(COMMAND mkoctfile -p OCTLIBDIR + OUTPUT_VARIABLE OCTLIBDIR + ) +string(REGEX REPLACE "\n" "" OCTLIBDIR "${OCTLIBDIR}") +# OCTLIBS +execute_process(COMMAND mkoctfile -p OCTAVE_LIBS + OUTPUT_VARIABLE OCTLIBS + ) +string(REGEX REPLACE "\n" "" OCTLIBS "${OCTLIBS}") +string(REGEX REPLACE " " ";" OCTLIBS "${OCTLIBS}") + +set(MAOXDB_DIR "${PROJECT_SOURCE_DIR}/src/lib") +add_library(maoxdb STATIC "${MAOXDB_DIR}/maoxdb.cpp") +set_target_properties(maoxdb PROPERTIES PUBLIC_HEADER "${MAOXDB_DIR}/maoxdb.hpp") +target_compile_options(maoxdb PRIVATE "-I${OCTINCLUDEDIR}" "-fPIC") +get_property(_MAOX_LIB_DIR TARGET maoxdb PROPERTY LIBRARY_OUTPUT_DIRECTORY) +# message("_MAOX_LIB_DIR: ${_MAOX_LIB_DIR}") + +####################################################### +### Compile into *.mex files +####################################################### +# Only files in src/private will be compiled. This is to separate the non-mex files in src/lib; if +# this is to change, the GLOB_RECURSE code needs to be changed. + +# Absolute paths to the cpp files. +file(GLOB_RECURSE OCTAVE_CAOSDB_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/private/*.cpp) +message("OCTAVE_CAOSDB_SRC: ${OCTAVE_CAOSDB_SRC}") +set(PKG_INST_DIR "${PROJECT_SOURCE_DIR}/inst") file(MAKE_DIRECTORY ${PKG_INST_DIR}) -string(REGEX REPLACE ";" ";-I" _MKOCTFILE_INCLUDES "-I${CONAN_INCLUDE_DIRS}") -string(REGEX REPLACE ";" ";-L" _MKOCTFILE_LIB_DIRS "-L${CONAN_LIB_DIRS}") -string(REGEX REPLACE ";" ";-l" _MKOCTFILE_LIBS "-l${CONAN_LIBS}") + +# Options for mex compilation +string(REGEX REPLACE ";" ";-I" _MKOCTFILE_INCLUDES "-I${CONAN_INCLUDE_DIRS};${MAOXDB_DIR}") +string(REGEX REPLACE ";" ";-L" _MKOCTFILE_LIB_DIRS "-L${CONAN_LIB_DIRS};${_MAOX_LIB_DIR}") +string(REGEX REPLACE ";" ";-l" _MKOCTFILE_LIBS "-l${CONAN_LIBS};maoxdb") string(REGEX REPLACE ";" ":" _MKOCTFILE_RPATH "${CONAN_LIB_DIRS}") -set(_MKOCTFILE_OPTIONS "-o" "${PKG_INST_DIR}/caosdb.mex" "-Wl,-rpath,${_MKOCTFILE_RPATH}" "--mex" "-std=gnu++17" +set(_MKOCTFILE_OPTIONS "-Wl,-rpath,${_MKOCTFILE_RPATH}" "--mex" "-std=gnu++17" "-L/usr/local/lib" ${_MKOCTFILE_INCLUDES} ${_MKOCTFILE_LIB_DIRS} ${_MKOCTFILE_LIBS}) -add_custom_command(OUTPUT ${PKG_INST_DIR}/caosdb.mex - COMMAND mkoctfile - ARGS ${_MKOCTFILE_OPTIONS} ${OCTAVE_CAOSDB_SRC} - DEPENDS ${OCTAVE_CAOSDB_SRC} - ) -add_custom_target(caosdb.mex ALL - SOURCES ${PKG_INST_DIR}/caosdb.mex) +add_custom_target(mex ALL + DEPENDS maoxdb) +file(GLOB_RECURSE _CPP_SOURCES RELATIVE "${PROJECT_SOURCE_DIR}/src" src/private/*.cpp) +foreach(sourcefile ${_CPP_SOURCES}) + string(REGEX REPLACE ".cpp$" ".mex" _mex_ext_file ${sourcefile}) + string(REGEX REPLACE "/" "__" _target_name "${sourcefile}") + set(_mex_ext_file "${PKG_INST_DIR}/${_mex_ext_file}") + set(_mkoct_output "-o;${_mex_ext_file}") + set(_abs_source "${PROJECT_SOURCE_DIR}/src/${sourcefile}") + add_custom_command(OUTPUT ${_mex_ext_file} + COMMAND mkoctfile + ARGS ${_MKOCTFILE_OPTIONS} ${_mkoct_output} ${_abs_source} + MAIN_DEPENDENCY ${_abs_source} + ) + add_custom_target(${_target_name} DEPENDS ${_mex_ext_file}) + add_dependencies(mex ${_target_name}) +endforeach(sourcefile) ####################################################### @@ -81,29 +129,23 @@ add_custom_target(caosdb.mex ALL ####################################################### option(LINTING "clang-tidy and iwyu" OFF) if(LINTING) - execute_process(COMMAND mkoctfile -p OCTINCLUDEDIR - OUTPUT_VARIABLE _OCTINCLUDEDIR - ) - string(REGEX REPLACE "\n" "" _OCTINCLUDEDIR "${_OCTINCLUDEDIR}") - - find_program(clang_tidy NAMES clang-tidy clang-tidy-11) + find_program(clang_tidy NAMES clang-tidy-11 clang-tidy) if(NOT clang_tidy) message(WARNING "clang-tidy: Not found") else() message(STATUS "clang-tidy: ${clang_tidy}") set(_CMAKE_CXX_CLANG_TIDY "--warnings-as-errors=*" - "--header-filter=caosdb/.*[^\\\(\.pb\.h\\\)]$" "--fix") set(_CMAKE_CXX_CLANG_TIDY_CHECKS "--checks=*,-fuchsia-*,-llvmlibc-*,-llvm-else-after-return,-readability-else-after-return,-cppcoreguidelines-pro-type-vararg,-hicpp-vararg,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cert-err58-cpp") add_custom_command( - TARGET caosdb.mex + TARGET mex COMMAND ${clang_tidy} ARGS ${_CMAKE_CXX_CLANG_TIDY} ${_CMAKE_CXX_CLANG_TIDY_CHECKS} ${OCTAVE_CAOSDB_SRC} "--" ${_MKOCTFILE_INCLUDES} "-I/usr/include" - "-I${_OCTINCLUDEDIR}" "-std=c++17" + "-I${OCTINCLUDEDIR}" "-std=c++17" DEPENDS ${OCTAVE_CAOSDB_SRC}) endif() @@ -119,9 +161,9 @@ if(LINTING) "-Xiwyu" "--cxx17ns") add_custom_command( - TARGET caosdb.mex + TARGET mex COMMAND ${iwyu} - ARGS ${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE} "-I${_OCTINCLUDEDIR}" + ARGS ${_CMAKE_CXX_INCLUDE_WHAT_YOU_USE} "-I${OCTINCLUDEDIR}" "-std=c++17" "-I/usr/include" ${_MKOCTFILE_INCLUDES} ${OCTAVE_CAOSDB_SRC} "||" "true" DEPENDS ${OCTAVE_CAOSDB_SRC}) @@ -131,4 +173,55 @@ else() message(STATUS "LINTING is OFF") endif() - +############################################################################### +# Tests # +############################################################################### + +option(TEST "Unit test with gtest" OFF) +if(TEST) + # cmake tests suffers from not being able to define dependencies, see + # https://stackoverflow.com/questions/733475, so we disable it for now. + # enable_testing() + add_custom_target(test + echo "[EE] \\`make test\\` does not exist, did you mean \\`make test_detailed\\`?" + COMMAND exit 1) + # append all the test cases here (file name without the ".cpp" suffix) + set(test_cases + test_utilities + ) + # add special cmake functions for gtest, (although they are not used yet, see above) + include(GoogleTest) + # `make testfiles` just builds the tests, `make test_detailed` builds and runs the tests + add_custom_target(testfiles) + add_custom_target(test_detailed DEPENDS testfiles) + # 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") + foreach (i RANGE "${len_test_cases}") + list(GET test_cases ${i} test_case_name) + # Once cmake 3.14 is available everywhere, use the new `foreach` instead. + # foreach (test_case_name "${test_cases}") + message(STATUS "test_case_name: ${test_case_name}") + add_executable(${test_case_name} EXCLUDE_FROM_ALL test/${test_case_name}.cpp) + add_custom_target("test_${test_case_name}" "${test_case_name}" DEPENDS "${test_case_name}") + add_dependencies(test_detailed "test_${test_case_name}") + # set(libcaosdb_TEST_SRC + # "${CMAKE_CURRENT_SOURCE_DIR}/${test_case_name}.cpp ${libcaosdb_TEST_SRC}") + target_include_directories(${test_case_name} PUBLIC + ${OCTINCLUDEDIR} + ${MAOXDB_DIR}) + target_link_libraries(${test_case_name} PUBLIC + maoxdb ${CONAN_LIBS_CAOSDB} ${CONAN_LIBS_GTEST} ${CONAN_LIBS_BOOST}) + target_link_directories(${test_case_name} PUBLIC ${OCTLIBDIR}) + target_link_options(${test_case_name} PUBLIC ${OCTLIBS}) + message(STATUS "CMAKE_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}") + gtest_discover_tests(${test_case_name} + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + TEST_LIST test_list + ) + message(STATUS "tests for ${test_case_name}: ${test_list}") + add_dependencies(testfiles ${test_case_name}) + endforeach () +else() + message(STATUS "TEST is OFF") +endif(TEST) diff --git a/Makefile b/Makefile index e3d9d8d9070566cf48463b6dc534db354daaff07..0ca33357d62d985e77167fd6ee39b6592faa2904 100644 --- a/Makefile +++ b/Makefile @@ -33,24 +33,63 @@ help: doc: cd doc && $(MAKE) html +############################################################################### +# Styling # +############################################################################### + +style: style_octave style_cpp .PHONY: style -style: - mh_style --fix --octave src doc +style_octave: + mh_style --octave src doc test || echo "You may want to run `make style_fix`." +.PHONY: style_octave + +style_cpp: + clang-format-11 --dry-run --verbose --Werror $(shell find test/ src/ -type f -iname "*.cpp" -o -iname "*.hpp" -o -iname "*.h" -o -iname "*.h.in") || echo "You may want to run `make style_fix`." +.PHONY: style_cpp + +style_fix: + mh_style --fix --octave src doc test + clang-format-11 -i --verbose --Werror $(shell find test/ src/ -type f -iname "*.cpp" -o -iname "*.hpp" -o -iname "*.h" -o -iname "*.h.in") +.PHONY: style_fix + +############################################################################### +# Linting # +############################################################################### + +linting: linting_octave linting_cpp +.PHONY: linting + +linting_octave: + mh_lint --octave ./ +.PHONY: linting_octave + +linting_cpp: + cd src \ + && ./configure \ + && cd ../build \ + && cmake -D LINTING=On .. \ + && cmake --build . +.PHONY: linting_cpp + +############################################################################### +# Tests # +############################################################################### + +test: install + $(MAKE) -C test test .PHONY: test -test: - cd test && octave Run_Test.m -.PHONY: pkg-test -pkg-test: install - octave --eval "pkg load caosdb; caosdb --version" +############################################################################### +# Packaging and Installation # +############################################################################### .PHONY: pkg pkg: dist/caosdb.tar.gz .PHONY: install install: pkg - octave --eval "pkg -verbose install dist/caosdb.tar.gz" + octave --eval "pkg install -verbose dist/caosdb.tar.gz" .PHONY: caosdb.tar.gz dist/caosdb.tar.gz: dist/ diff --git a/README_SETUP.md b/README_SETUP.md index 688d7c97a0f88a355b55e37b7e2094842ddf1770..32c9d1a8b038085056248fca7d50d3d4874d58a9 100644 --- a/README_SETUP.md +++ b/README_SETUP.md @@ -5,7 +5,8 @@ This package requires the following software: - conan: `pip install conan` -- libcaosdb: See https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib for further instructions. +- libcaosdb installed with Conan: See https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib for + further instructions. - For running this library, a valid libcaosdb configuration is needed, for example a `.caosdb_client.json` file in your home directory or current working directory. Please look at [`README_SETUP.md` in caosdb-cpplib](https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib/-/blob/main/README_SETUP.md) for more information. @@ -21,11 +22,13 @@ This package requires the following software: ## Run Unit Tests -We use the standard test framework of octave. +We use the standard test framework of Octave. -See [this articel](https://wiki.octave.org/Tests) for a primer and use +See [this article](https://wiki.octave.org/Tests) for a primer and use [this](https://octave.org/doc/interpreter/Test-Functions.html) as a reference. +Additionally we use the [MOxUnit](https://github.com/MOxUnit/MOxUnit) framework. + ## Code Formatting Code formatting is done with the @@ -50,21 +53,3 @@ static website. If you rather would like to use the native, - `sphinx` - `sphinx-autoapi` - `recommonmark` - -### Writing Documentation - -- Example for texinfo documentation: - https://github.com/gnu-octave/octave/blob/default/scripts/geometry/inpolygon.m -- Extract documentation from file: - `[txt, form] = get_help_text_from_file(make_absolute_filename('pkg/inst/some_function.m'))` -- Generate HTML documentation from single file: - ```octave -pkg uninstall caosdb -pkg install caosdb.tar.gz -pkg load caosdb -html_help_text('some_function', './htdocs/some.html', 'octave-forge', pkgname="caosdb") -``` -- Generate HTML documentation for a package: - ```octave -generate_package_html('caosdb', 'htdocs', 'octave-forge') -``` diff --git a/conanfile.txt b/conanfile.txt index e89a593b5f6388ac539975c6ae0ed808a900ecc3..37cf6d6b0f6a357663ea5c06f847e5c84b0207d0 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -1,5 +1,5 @@ [requires] -caosdb/0.0.5 +caosdb/[>=0.0.6] [generators] cmake diff --git a/doc/Development.rst b/doc/Development.rst new file mode 100644 index 0000000000000000000000000000000000000000..fca47d741ad4cf19b66d31719f101e3d4225d875 --- /dev/null +++ b/doc/Development.rst @@ -0,0 +1,31 @@ +Development +=========== + +Structure +--------- + +The sources for functions and classes are in ``src/``. Private functions (mostly C++ source files +which are to be compiled into ``*.mex``) are implemented in ``private/_some_function.*``. + + + +Writing Documentation +--------------------- + +- Example for texinfo documentation: + https://github.com/gnu-octave/octave/blob/default/scripts/geometry/inpolygon.m +- Extract documentation from file: + ``[txt, form] = get_help_text_from_file(make_absolute_filename('pkg/inst/some_function.m'))`` +- Generate HTML documentation from single file: + + .. code-block:: octave + + pkg uninstall caosdb + pkg install caosdb.tar.gz + pkg load caosdb + html_help_text('some_function', './htdocs/some.html', 'octave-forge', pkgname="caosdb") +- Generate HTML documentation for a package: + + .. code-block:: octave + + generate_package_html('caosdb', 'htdocs', 'octave-forge') diff --git a/doc/Makefile b/doc/Makefile index f985ba9f353c51c2d399d4bef6a05f623af81ce2..5f1840a185541ad9699c4ad79cb721d1295a3a34 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -42,7 +42,7 @@ doc-help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile octavedoc +%: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) octavedoc: diff --git a/doc/conf.py b/doc/conf.py index b7c2ef8ec1d1614793f15cd97a2d74876318a9d1..514d7de89df4d982d8f25d114f5d7787a33843be 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -91,7 +91,7 @@ html_theme = "sphinx_rtd_theme" # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [ - '_static', + # '_static', '_build_octave', ] diff --git a/doc/index.rst b/doc/index.rst index 0b144d0adc5de915e739e7a12e778195947ada34..6ccd2939ebe461fa4cb92af557b63c8e430dfbdb 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -38,6 +38,7 @@ This is work in progress. :caption: Contents: Welcome <self> + Development api/index * :ref:`genindex` diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 908c635c0eb62381f0a334549dda94bd3affe6bd..0000000000000000000000000000000000000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# -# 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/>. -# - -set(OCTAVE_CAOSDB_SRC - ${CMAKE_CURRENT_SOURCE_DIR}/caosdb.cpp - ) - -# pass variable to parent scope -set(OCTAVE_CAOSDB_SRC ${OCTAVE_CAOSDB_SRC} PARENT_SCOPE) diff --git a/src/Caosdb.m b/src/Caosdb.m index 7345ca240266d0d738377d564a35dda6c4ce6434..a94720905d6e188423457373bf895ffdbd5615ff 100644 --- a/src/Caosdb.m +++ b/src/Caosdb.m @@ -1,8 +1,8 @@ -% (C) Copyright 2021 IndiScale GmbH <info@indiscale.com> -% (C) Copyright 2021 Timm FItschen <t.fitschen@indiscale.com> -% % This file is a part of the CaosDB Project. % +% Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> +% Copyright (C) 2021 Daniel Hornung <d.hornung@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 @@ -17,8 +17,8 @@ % along with this program. If not, see <https://www.gnu.org/licenses/>. % -*- texinfo -*- -% @deftypefn {Loadable Function} {} caosdb ([@var{OPTIONS}]) -% This is the main function of the CaosDB client for Octave. +% @deftypefn {Class} {} Caosdb () +% This is the main class of the CaosDB client for Octave. % % Print usage help and return: % @example @@ -40,3 +40,34 @@ %!demo %! ## Print Help: %! caosdb --help; +classdef Caosdb < handle + properties + connection = "" % Will use the default connection + end + + methods + + function obj = Caosdb(connection) + if nargin == 0 + connection = ""; + end + obj.connection = connection; + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % info % + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + function res = info(obj) + disp(["connection: >", obj.connection, "<"]); + try + info_result = maox_info(obj.connection); + res = info_result; + catch + % disp("some error!"); + % disp(lasterror()); + rethrow(lasterror()); + end + end + + end +end diff --git a/src/caosdb_exec.m b/src/caosdb_exec.m new file mode 100644 index 0000000000000000000000000000000000000000..3bcf273b0ff908ff1197ec0e1b40223e726dfd5e --- /dev/null +++ b/src/caosdb_exec.m @@ -0,0 +1,29 @@ +% This file is a part of the CaosDB Project. +% +% Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> +% Copyright (C) 2021 Daniel Hornung <d.hornung@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/>. + +% -*- texinfo -*- +% @deftypefn {Function File} {@var{out} =} caosdb_exec (arg) +% @cindex index term +% Calls the equivalkent of the @code{caosdb} command line interface executable. Mostly, this can +% output the version of libcaosdb. +% +% Typical arguments are @code{"--version"} or @code{"--test-connection"}. +% @end deftypefn +function out = caosdb_exec(arg) + out = maox_caosdb(arg); +end diff --git a/src/configure b/src/configure index 8574639dfbc8ebc2407bdd0b56dab904220ce8bb..5266b64232c56de3c21ca84025c79bf4cbab5646 100755 --- a/src/configure +++ b/src/configure @@ -9,6 +9,7 @@ INST_DIR="$(realpath ../inst)" echo "Octave CaosDB INST_DIR: $INST_DIR" rm -r "${INST_DIR}" || true mkdir -p "${INST_DIR}" +mkdir -p "${INST_DIR}/private" BUILD_DIR="$(realpath ../build)" echo "Octave CaosDB BUILD_DIR: $BUILD_DIR" diff --git a/src/lib/maoxdb.cpp b/src/lib/maoxdb.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c8ffce7d00402178dacd7e09ffcbce56b52d25a --- /dev/null +++ b/src/lib/maoxdb.cpp @@ -0,0 +1,56 @@ +/* + * ** header v3.0 + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2021 Daniel Hornung <d.hornung@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/>. + * + * ** end header + */ + +/** + * Mostly utility functions for MEX files interacting with libcaosdb. + */ + +#include "maoxdb.hpp" +#include "mex.h" +#include "caosdb/status_code.h" + +namespace maoxdb { +using std::string; + +/** + * Extract useful strings from an Exception: ID and description. + */ +std::pair<string, string> +exceptionToMessage(const caosdb::exceptions::Exception &exc) { + + string id = std::to_string(exc.GetCode()); + string text = + caosdb::get_status_description(exc.GetCode()) + "\n" + exc.what(); + + return std::pair<string, string>(id, text); +} + +/** + * Just throw the error. + */ +void throwOctException(const caosdb::exceptions::Exception &exc) { + std::pair<string, string> excContent = exceptionToMessage(exc); + mexErrMsgIdAndTxt(excContent.first.c_str(), excContent.second.c_str()); +} + +} // namespace maoxdb diff --git a/src/lib/maoxdb.hpp b/src/lib/maoxdb.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e2f0154bb8a5b29c6353f7fe932a9a3bc60edcf9 --- /dev/null +++ b/src/lib/maoxdb.hpp @@ -0,0 +1,72 @@ +#ifndef MAOXDB_H // NOLINT +#define MAOXDB_H + +#include "caosdb/exceptions.h" +#include "caosdb/status_code.h" +#include "mex.h" +#include <string> + +// Macros ///////////////////////////////////////////////////////////////////// + + +// Utility functions ////////////////////////////////////////////////////////// +namespace maoxdb { + +using std::string; + +template <typename T> auto mxScalar(T value, mxClassID class_id) -> mxArray * { + mxArray *array = mxCreateNumericMatrix(1, 1, class_id, mxREAL); + auto *data = static_cast<T *>(mxGetData(array)); + data[0] = value; + return array; +} + +// Convenience shortcut functions + +inline auto mxScalarUINT64(UINT64_T value) -> mxArray * { + return mxScalar<UINT64_T>(value, mxUINT64_CLASS); +} +inline auto mxScalarINT64(INT64_T value) -> mxArray * { + return mxScalar<INT64_T>(value, mxINT64_CLASS); +} +inline auto mxScalarDOUBLE(double value) -> mxArray * { + return mxScalar<double>(value, mxDOUBLE_CLASS); +} +inline auto mxScalarLOGICAL(bool value) -> mxArray * { + return mxScalar<UINT8_T>(static_cast<unsigned char>(value), mxLOGICAL_CLASS); +} + +/** + * @brief Handle a CaosDB Exception and transform into error code and message. + * + * @details This function does all the processing to transform the information + * in an Exception object into a form that can conveniently be handled by Octave + * via the mexErrMsgIdAndTxt function. + * + * @param exc The Exception object. + * + * @return pair<string msgId, string msgText> The message ID and message text + * which can be passed to Octave. + * + * @note Additional utility functions should be easy to implement when the + * libcaosdb error handling changes. + */ +auto +exceptionToMessage(const caosdb::exceptions::Exception &exc) -> std::pair<string, string>; + +/** + * @brief Throw a CaosDB Exception inside Octave. + * + * @details This function does all the processing to transform the information + * in an Exception object into a form that is accepted by Octave's error + * handling.d + * + * Internally, this function uses the exceptionToMessage function. + * + * @param exc The Exception object. + */ +void throwOctException(const caosdb::exceptions::Exception &exc); + +} // namespace maoxdb + +#endif /* MAOXDB_H */ diff --git a/src/caosdb.cpp b/src/private/maox_caosdb.cpp similarity index 91% rename from src/caosdb.cpp rename to src/private/maox_caosdb.cpp index 5fbc38a7d49affa1f15553c636102a2f7f1e4372..88d408cc1d3b4576e49b0930dc1cdc253f8f3f53 100644 --- a/src/caosdb.cpp +++ b/src/private/maox_caosdb.cpp @@ -2,7 +2,6 @@ #include "caosdb/constants.h" // for LIBCAOSDB_VERSION_MAJOR, LIBCAOSDB_VE... #include "caosdb/info.h" // for VersionInfo #include "mex.h" // for mxArray, mexFunction -#include "mexproto.h" // for mexPrintf, mxCreateString, mxGetChars #include <cstring> // for strcmp #include <memory> // for unique_ptr, __shared_ptr_access, shar... #include <string> // for allocator, char_traits, operator+ @@ -16,7 +15,7 @@ void print_usage() { mexPrintf("\nUsage: caosdb [OPTIONS]\n\n"); mexPrintf("Options:\n"); mexPrintf(" --help Print this help and return.\n"); - mexPrintf(" --version Print the version of OcataveCaosDB and " + mexPrintf(" --version Print the version of OctaveCaosDB and " "libcaosdb and return.\n"); mexPrintf( " --test-connection Test the default connection and return.\n"); @@ -47,7 +46,7 @@ void mexFunction(int /*nlhs*/, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { if (nrhs == 1) { - auto const *first_arg = mxGetChars(prhs[0]); + auto const *first_arg = mxArrayToString(prhs[0]); if (strcmp(first_arg, "--version") == 0) { const auto *version = print_version(); plhs[0] = mxCreateString(version); diff --git a/src/private/maox_info.cpp b/src/private/maox_info.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6712d9e310235570d2b3c21fe8115978a4b039e3 --- /dev/null +++ b/src/private/maox_info.cpp @@ -0,0 +1,70 @@ +#include "caosdb/connection.h" // for Connection, ConnectionManager +#include "caosdb/constants.h" // for LIBCAOSDB_VERSION_MAJOR, LIBCAOSDB_VE... +#include "caosdb/exceptions.h" // for all error handling +#include "caosdb/info.h" // for VersionInfo +#include "maoxdb.hpp" // caosDB utils for mex files +#include "mex.h" // for mxArray, mexFunction +#include <cstring> // for strcmp +#include <memory> // for unique_ptr, __shared_ptr_access, shar... +#include <string> // for allocator, char_traits, operator+ + +using caosdb::connection::Connection; +using caosdb::connection::ConnectionManager; +using std::string; + +auto info(const string &connection_name) -> mxArray *; + +/** + * The implementation of the info retrieval. + */ +auto info(string const &connection_name) -> mxArray * { + std::shared_ptr<Connection> connection = nullptr; + if (connection_name.empty()) { + connection = ConnectionManager::GetDefaultConnection(); + } else { + connection = ConnectionManager::GetConnection(connection_name); + } + const auto &version_info = connection->RetrieveVersionInfo(); + const char *keys[] = {"major", "minor", "patch", "pre_release", // NOLINT + "build"}; + std::array<mwSize, 2> dims = {1, 1}; + mxArray *info_struct = mxCreateStructArray(2, dims.data(), 5, keys); // NOLINT + + mxSetField(info_struct, 0, "major", + maoxdb::mxScalarUINT64(version_info.GetMajor())); + mxSetField(info_struct, 0, "minor", + maoxdb::mxScalarUINT64(version_info.GetMinor())); + mxSetField(info_struct, 0, "patch", + maoxdb::mxScalarUINT64(version_info.GetPatch())); + mxSetField(info_struct, 0, "pre_release", + mxCreateString(version_info.GetPreRelease().c_str())); + mxSetField(info_struct, 0, "build", + mxCreateString(version_info.GetBuild().c_str())); + return info_struct; +} + +/** + * @brief Get info about the server + * + * @details At the moment, this is just the version of the server. + * + * @param connection_name A string with the connection name. May be omitted or + * an empty string. + * + * @return return type + */ +void mexFunction(int /*nlhs*/, mxArray *plhs[], int nrhs, + const mxArray *prhs[]) { + + string conn_name; + if (nrhs >= 1 && mxGetNumberOfElements(prhs[0]) > 0) { + conn_name = mxArrayToString(prhs[0]); + } + try { + auto *info_struct = info(conn_name); + plhs[0] = info_struct; + } catch (const caosdb::exceptions::Exception &exc) { + mexPrintf("Some exception!"); + maoxdb::throwOctException(exc); + } +} diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..2993b098fd36c233b1404cc9137faf5453694404 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,61 @@ +# ** header v3.0 +# This file is a part of the CaosDB Project. +# +# Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2021 Daniel Hornung <d.hornung@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/>. +# +# ** end header + +# This Makefile depends on an installation with the base dir's Makefile. +# +# Specifically, the libraries must have be installed with Conan. + +.PHONY: help +help: + @echo "Targets:" + @echo " pkg - create tar.gz archive of the octave package." + @echo " style - auto-format the source files." + @echo " test - run unit tests." + @echo " doc - create the documentation." + + +############################################################################### +# Tests # +############################################################################### + +test: test_octave test_cpp +.PHONY: test + +test_octave: + octave Run_Test.m +.PHONY: test_octave + + +# && make test || echo "Test(s) failed."; exit 1 +test_cpp: + $(eval BUILD_DIR ::= $(shell mktemp -d build_XXXXXXXX)) + cd $(BUILD_DIR) \ + && conan install ../.. -s "compiler.libcxx=libstdc++11" \ + && cmake -D TEST=On ../.. \ + && make test_detailed \ + || (echo "Test(s) failed."; exit 1) +# Exit with error if tests fail. +# && make test || make test_detailed || echo "Test(s) failed." ; exit 1 + +# Cleanup if everything went fine. + rm -r $(BUILD_DIR) +.PHONY: test_cpp + diff --git a/test/Run_Test.m b/test/Run_Test.m index a1b6c1b1905e66871dc92a4aa6af06c408b6d239..e72e71a9cbc169647ccd1de253d9c7f178d89be9 100644 --- a/test/Run_Test.m +++ b/test/Run_Test.m @@ -16,6 +16,8 @@ % 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/>. -pkg install ..; pkg load caosdb; -moxunit_runtests -verbose test_caosdb.m +test_result = moxunit_runtests("-verbose", "test_unittest.m"); +if not(test_result) + exit(1) +end diff --git a/test/test_caosdb.m b/test/test_caosdb.m deleted file mode 100644 index 6ce8788081c534b8efc72bae0ff76aae8cce3cee..0000000000000000000000000000000000000000 --- a/test/test_caosdb.m +++ /dev/null @@ -1,10 +0,0 @@ -function test_suite=test_caosdb - try % assignment of 'localfunctions' is necessary in Matlab >= 2016 - test_functions=localfunctions(); - catch % no problem; early Matlab versions can use initTestSuite fine - end - initTestSuite; - -function test_print_version - v = caosdb("--version") - assertEqual(v, "v0.1 (libcaosdb v0.0.5)") diff --git a/test/test_unittest.m b/test/test_unittest.m new file mode 100644 index 0000000000000000000000000000000000000000..a4e38bd63e3fe3a6009c69419d83b7542dd04a94 --- /dev/null +++ b/test/test_unittest.m @@ -0,0 +1,42 @@ +% This file is a part of the CaosDB Project. +% +% Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> +% Copyright (C) 2021 Daniel Hornung <d.hornung@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/>. + +function test_suite=test_unittest() + try % assignment of 'localfunctions' is necessary in Matlab >= 2016 + test_functions=localfunctions(); + catch % no problem; early Matlab versions can use initTestSuite fine + end + initTestSuite; +end + +% Only tests which don't need a connection to a server. +function test_local() + % default connection + c1 = Caosdb(); + assertEqual(c1.connection, "") + % class with explicit connection + c2 = Caosdb("local-caosdb-admin"); + assertEqual(c2.connection, "local-caosdb-admin"); + + % TODO(daniel) Re-write s.th. version >= 0.0.6 (or whatever minimal + % version will be valid then) is checked. + + % Only get the local versions. + % version = caosdb_exec("--version"); + % assertEqual(version, "v0.1 (libcaosdb v0.0.7)"); +end diff --git a/test/test_utilities.cpp b/test/test_utilities.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1c42a2c375d7d669b0767e8fa319b1f874615396 --- /dev/null +++ b/test/test_utilities.cpp @@ -0,0 +1,125 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2021 Daniel Hornung <d.hornung@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/exceptions.h" +#include "maoxdb.hpp" +#include "mex.h" +// #include "mexproto.h" +#include <gtest/gtest.h> +#include <limits> +#include <string> +#include <vector> + +namespace maoxdb { + +/////////////////////////////////////////////////////////////////////////////// +// Helper functions // +/////////////////////////////////////////////////////////////////////////////// + +/* + * These functions test if the value can be converted to a mex scalar. + */ +void test_scalar_uint64(UINT64_T value) { + mxArray *scalar = mxScalarUINT64(value); + EXPECT_TRUE(mxIsUint64(scalar)); + EXPECT_EQ(mxGetNumberOfElements(scalar), 1); + EXPECT_EQ(*((UINT64_T *) mxGetData(scalar)), value); +} + +void test_scalar_int64(INT64_T value) { + mxArray *scalar = mxScalarINT64(value); + EXPECT_TRUE(mxIsInt64(scalar)); + EXPECT_EQ(mxGetNumberOfElements(scalar), 1); + EXPECT_EQ(*((INT64_T *) mxGetData(scalar)), value); +} + +void test_scalar_double(double value) { + mxArray *scalar = mxScalarDOUBLE(value); + EXPECT_TRUE(mxIsDouble(scalar)); + EXPECT_EQ(mxGetNumberOfElements(scalar), 1); + EXPECT_EQ(*((double *) mxGetData(scalar)), value); +} + +void test_scalar_logical(bool value) { + mxArray *scalar = mxScalarLOGICAL(value); + EXPECT_TRUE(mxIsLogical(scalar)); + EXPECT_EQ(mxGetNumberOfElements(scalar), 1); + EXPECT_EQ(*((bool *) mxGetData(scalar)), value); +} + +/** + * Generate a vector with useful values for testing. + */ +template<typename T> +auto values() -> std::vector<T> { + std::vector<T> values = + {0, 1, + std::numeric_limits<T>::max(), + std::numeric_limits<T>::min(), + std::numeric_limits<T>::lowest(), + std::numeric_limits<T>::epsilon() // 0 for integers, but who cares? + }; + return values; +} + +/////////////////////////////////////////////////////////////////////////////// +// Actual tests // +/////////////////////////////////////////////////////////////////////////////// + +/** + * Test if construction of scalar mex arrays works + */ +TEST(test_utilities, scalar_arrays) { + auto values_uint64 = values<UINT64_T>(); + for (auto value : values_uint64) { + test_scalar_uint64(value); + } + + auto values_int64 = values<INT64_T>(); + for (auto value : values_int64) { + test_scalar_int64(value); + } + + auto values_double = values<double>(); + for (auto value : values_double) { + test_scalar_double(value); + } + + std::vector<bool> values_logical = {true, false}; + for (auto value : values_logical) { + test_scalar_logical(value); + } +} + +/** + * Test exception handling + */ + +TEST(test_utilities, exception_handling) { + caosdb::exceptions::AuthenticationError exc("Authentication failed."); + auto strings = exceptionToMessage(exc); + EXPECT_EQ(strings.first, std::string("16")); + EXPECT_EQ(strings.second, + std::string("The attempt to execute this transaction has not been " + "executed at all because the authentication did not " + "succeed.\nAuthentication failed.")); +} + +} // maoxdb