diff --git a/.ci/ci-script.sh b/.ci/ci-script.sh index 6791119a8bd7..8e4d80792e69 100755 --- a/.ci/ci-script.sh +++ b/.ci/ci-script.sh @@ -27,15 +27,31 @@ set -ex -PARALLEL="-j2" +CMAKE_BUILD_TYPE="RelWithDebInfo" +GENERATOR="Ninja" +VERBOSE="-v" +KEEPGOING="-k0" + +if [ "$GENERATOR" = "Unix Makefiles" ]; +then + VERBOSE="VERBOSE=1"; + KEEPGOING="-k" +fi; + +if [ -z "${MAKEFLAGS+x}" ]; +then + MAKEFLAGS="-j2 $VERBOSE" +fi target_build() { # to get as much of the issues into the log as possible - cmake --build "$BUILD_DIR" -- $PARALLEL -v || cmake --build "$BUILD_DIR" -- -j1 -v -k0 + cmake --build "$BUILD_DIR" -- $MAKEFLAGS || cmake --build "$BUILD_DIR" -- -j1 $VERBOSE $KEEPGOING + + ctest --output-on-failure || ctest --rerun-failed -V -VV # and now check that it installs where told and only there. - cmake --build "$BUILD_DIR" --target install -- $PARALLEL -v || cmake --build "$BUILD_DIR" --target install -- -j1 -v -k0 + cmake --build "$BUILD_DIR" --target install -- $MAKEFLAGS || cmake --build "$BUILD_DIR" --target install -- -j1 $VERBOSE $KEEPGOING } target_usermanual() @@ -48,25 +64,29 @@ target_usermanual() # ls -lah doc/usermanual/darktable-usermanual.pdf } -du -hcs "$SRC_DIR" -du -hcs "$BUILD_DIR" -du -hcs "$INSTALL_PREFIX" +diskspace() +{ + df + du -hcs "$SRC_DIR" + du -hcs "$BUILD_DIR" + du -hcs "$INSTALL_PREFIX" +} + +diskspace cd "$BUILD_DIR" -cmake -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" -GNinja -DCMAKE_BUILD_TYPE=RelWithDebInfo $ECO -DVALIDATE_APPDATA_FILE=On "$SRC_DIR" || (cat "$BUILD_DIR"/CMakeFiles/CMakeOutput.log; cat "$BUILD_DIR"/CMakeFiles/CMakeError.log) +cmake -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" -G"$GENERATOR" -DCMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" $ECO -DVALIDATE_APPDATA_FILE=ON -DBUILD_TESTING=ON "$SRC_DIR" || (cat "$BUILD_DIR"/CMakeFiles/CMakeOutput.log; cat "$BUILD_DIR"/CMakeFiles/CMakeError.log) case "$TARGET" in - "usermanual") - target_usermanual - ;; "build") target_build ;; + "usermanual") + target_usermanual + ;; *) exit 1 ;; esac -du -hcs "$SRC_DIR" -du -hcs "$BUILD_DIR" -du -hcs "$INSTALL_PREFIX" +diskspace diff --git a/.travis.yml b/.travis.yml index 4120c624ee8b..5c0e8630dd92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,7 +72,7 @@ matrix: env: CC=gcc-9 CXX=g++-9 TARGET=usermanual ECO="-DTESTBUILD_OPENCL_PROGRAMS=OFF" # EXTRA_TMPFS="--tmpfs /tmp" script: - - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run --read-only --volume $TRAVIS_BUILD_DIR:$SRC_DIR:ro --tmpfs $BUILD_DIR --workdir $BUILD_DIR --tmpfs $INSTALL_PREFIX $EXTRA_TMPFS --env CC --env CXX --env CFLAGS --env CXXFLAGS --env SRC_DIR --env BUILD_DIR --env INSTALL_PREFIX --env TARGET --env ECO darktable/darktable sh -c "$SRC_DIR/.ci/ci-script.sh"; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker run --read-only --volume $TRAVIS_BUILD_DIR:$SRC_DIR:ro --tmpfs $BUILD_DIR:exec --workdir $BUILD_DIR --tmpfs $INSTALL_PREFIX $EXTRA_TMPFS --env CC --env CXX --env CFLAGS --env CXXFLAGS --env SRC_DIR --env BUILD_DIR --env INSTALL_PREFIX --env TARGET --env ECO darktable/darktable sh -c "$SRC_DIR/.ci/ci-script.sh"; fi - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export SRC_DIR="$TRAVIS_BUILD_DIR"; export BUILD_DIR="$SRC_DIR/build"; diff --git a/CMakeLists.txt b/CMakeLists.txt index 4af31937a178..7fc3f9e95498 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -434,6 +434,12 @@ if(NOT SOURCE_PACKAGE AND NOT (CMAKE_VERSION VERSION_LESS 3.3) AND DEFINED ENV{_ endif() endif() +if(BUILD_TESTING) + find_package(cmocka 1.1.0 CONFIG REQUIRED) + include(AddCMockaTest) + include(AddCMockaMockTest) +endif(BUILD_TESTING) + # # Test SSE level # diff --git a/DefineOptions.cmake b/DefineOptions.cmake index 5ada5322cf94..1dcad14b885e 100644 --- a/DefineOptions.cmake +++ b/DefineOptions.cmake @@ -25,7 +25,6 @@ option(BUILD_PRINT "Build the print module" ON) option(BUILD_RS_IDENTIFY "Build the darktable-rs-identify debug aid" ON) option(BUILD_SSE2_CODEPATHS "(EXPERIMENTAL OPTION, DO NOT DISABLE) Building SSE2-optimized codepaths" ON) option(VALIDATE_APPDATA_FILE "Use appstream-util (if found) to validate the .appdata file" OFF) -option(BUILD_TESTS "Build tests in src/tests/, runnable from the build/ directory" OFF) option(BUILD_BATTERY_INDICATOR "Add an icon to the top toolbar showing the state of a laptop battery" OFF) option(BUILD_MSYS2_INSTALL "Build an MSYS2 version of the install, aka for Windows platform, but without dependency installs" OFF) option(BUILD_NOISE_TOOLS "Build tools for generating noise proifles" OFF) diff --git a/cmake/modules/AddCMockaMockTest.cmake b/cmake/modules/AddCMockaMockTest.cmake new file mode 100644 index 000000000000..78cebb86931a --- /dev/null +++ b/cmake/modules/AddCMockaMockTest.cmake @@ -0,0 +1,56 @@ +# MIT License +# +# Copyright (c) 2018 Kamil Lorenc +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +## Add unit test with mocking support +# \param name unit test name (excluding extension and 'test_' prefix) +# \param SOURCES optional list of source files to include in test executable +# (beside test_${name}.c) +# \param MOCKS optional list of functions to be mocked in executable +# \param COMPILE_OPTIONS optional list of options for the compiler +# \param LINK_LIBRARIES optional list of libraries to link (used as +# -l${LINK_LIBRARIES}) +# \param LINK_OPTIONS optional list of options to be passed to linker +function(add_cmocka_mock_test name) + # parse arguments passed to the function + set(options ) + set(oneValueArgs ) + set(multiValueArgs SOURCES MOCKS COMPILE_OPTIONS LINK_LIBRARIES LINK_OPTIONS) + cmake_parse_arguments(ADD_MOCKED_TEST "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN} ) + + # create link flags for mocks + set(link_flags "") + foreach (mock ${ADD_MOCKED_TEST_MOCKS}) + set(link_flags "${link_flags} -Wl,--wrap=${mock}") + endforeach(mock) + + # define test + add_cmocka_test(${name} + SOURCES ${ADD_MOCKED_TEST_SOURCES} + COMPILE_OPTIONS ${DEFAULT_C_COMPILE_FLAGS} + ${ADD_MOCKED_TEST_COMPILE_OPTIONS} + LINK_LIBRARIES ${ADD_MOCKED_TEST_LINK_LIBRARIES} + LINK_OPTIONS ${link_flags} ${ADD_MOCKED_TEST_LINK_OPTIONS}) + + # allow using includes from src/ directory + target_include_directories(${name} PRIVATE ${CMAKE_SOURCE_DIR}/src) +endfunction(add_cmocka_mock_test) diff --git a/cmake/modules/AddCMockaTest.cmake b/cmake/modules/AddCMockaTest.cmake new file mode 100644 index 000000000000..83307410422c --- /dev/null +++ b/cmake/modules/AddCMockaTest.cmake @@ -0,0 +1,142 @@ +# +# Copyright (c) 2007 Daniel Gollub +# Copyright (c) 2007-2018 Andreas Schneider +# Copyright (c) 2018 Anderson Toshiyuki Sasaki +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +#.rst: +# AddCMockaTest +# ------------- +# +# This file provides a function to add a test +# +# Functions provided +# ------------------ +# +# :: +# +# add_cmocka_test(target_name +# SOURCES src1 src2 ... srcN +# [COMPILE_OPTIONS opt1 opt2 ... optN] +# [LINK_LIBRARIES lib1 lib2 ... libN] +# [LINK_OPTIONS lopt1 lop2 .. loptN] +# ) +# +# ``target_name``: +# Required, expects the name of the test which will be used to define a target +# +# ``SOURCES``: +# Required, expects one or more source files names +# +# ``COMPILE_OPTIONS``: +# Optional, expects one or more options to be passed to the compiler +# +# ``LINK_LIBRARIES``: +# Optional, expects one or more libraries to be linked with the test +# executable. +# +# ``LINK_OPTIONS``: +# Optional, expects one or more options to be passed to the linker +# +# +# Example: +# +# .. code-block:: cmake +# +# add_cmocka_test(my_test +# SOURCES my_test.c other_source.c +# COMPILE_OPTIONS -g -Wall +# LINK_LIBRARIES mylib +# LINK_OPTIONS -Wl,--enable-syscall-fixup +# ) +# +# Where ``my_test`` is the name of the test, ``my_test.c`` and +# ``other_source.c`` are sources for the binary, ``-g -Wall`` are compiler +# options to be used, ``mylib`` is a target of a library to be linked, and +# ``-Wl,--enable-syscall-fixup`` is an option passed to the linker. +# + +enable_testing() +include(CTest) + +if (CMAKE_CROSSCOMPILING) + if (WIN32) + find_program(WINE_EXECUTABLE + NAMES wine) + set(TARGET_SYSTEM_EMULATOR ${WINE_EXECUTABLE} CACHE INTERNAL "") + endif() +endif() + +function(ADD_CMOCKA_TEST _TARGET_NAME) + + set(one_value_arguments + ) + + set(multi_value_arguments + SOURCES + COMPILE_OPTIONS + LINK_LIBRARIES + LINK_OPTIONS + ) + + cmake_parse_arguments(_add_cmocka_test + "" + "${one_value_arguments}" + "${multi_value_arguments}" + ${ARGN} + ) + + if (NOT DEFINED _add_cmocka_test_SOURCES) + message(FATAL_ERROR "No sources provided for target ${_TARGET_NAME}") + endif() + + add_executable(${_TARGET_NAME} ${_add_cmocka_test_SOURCES}) + + if (DEFINED _add_cmocka_test_COMPILE_OPTIONS) + target_compile_options(${_TARGET_NAME} + PRIVATE ${_add_cmocka_test_COMPILE_OPTIONS} + ) + endif() + + if (DEFINED _add_cmocka_test_LINK_LIBRARIES) + target_link_libraries(${_TARGET_NAME} + PRIVATE ${_add_cmocka_test_LINK_LIBRARIES} + ) + endif() + + if (DEFINED _add_cmocka_test_LINK_OPTIONS) + set_target_properties(${_TARGET_NAME} + PROPERTIES LINK_FLAGS + ${_add_cmocka_test_LINK_OPTIONS} + ) + endif() + + add_test(NAME ${_TARGET_NAME} + COMMAND ${TARGET_SYSTEM_EMULATOR} ${_TARGET_NAME}) + +endfunction (ADD_CMOCKA_TEST) + +function(ADD_CMOCKA_TEST_ENVIRONMENT _TARGET_NAME) + if (WIN32 OR CYGWIN OR MINGW OR MSVC) + file(TO_NATIVE_PATH "${cmocka-library_BINARY_DIR}" CMOCKA_DLL_PATH) + + if (TARGET_SYSTEM_EMULATOR) + set(DLL_PATH_ENV "WINEPATH=${CMOCKA_DLL_PATH};$ENV{WINEPATH}") + else() + set(DLL_PATH_ENV "PATH=${CMOCKA_DLL_PATH};$ENV{PATH}") + endif() + # + # IMPORTANT NOTE: The set_tests_properties(), below, internally + # stores its name/value pairs with a semicolon delimiter. + # because of this we must protect the semicolons in the path + # + string(REPLACE ";" "\\;" DLL_PATH_ENV "${DLL_PATH_ENV}") + + set_tests_properties(${_TARGET_NAME} + PROPERTIES + ENVIRONMENT + "${DLL_PATH_ENV}") + endif() +endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bbd5faa2500a..bdd90a170c47 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -876,9 +876,9 @@ endif(BUILD_CMSTEST) add_subdirectory(chart) # have some test programs for unit testing, ... -if(BUILD_TESTS) +if(BUILD_TESTING) add_subdirectory(tests) -endif(BUILD_TESTS) +endif(BUILD_TESTING) # # build darktable executable diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index f5b8295887a5..c7367bd7343e 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,9 +1,4 @@ -include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..) -include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) - add_executable(darktable-test-variables variables.c) - -set_target_properties(darktable-test-variables PROPERTIES INSTALL_RPATH "$ORIGIN/../") -set_target_properties(darktable-test-variables PROPERTIES LINKER_LANGUAGE C) target_link_libraries(darktable-test-variables lib_darktable) +add_subdirectory(unittests) diff --git a/src/tests/unittests/CMakeLists.txt b/src/tests/unittests/CMakeLists.txt new file mode 100644 index 000000000000..29b47cf096b9 --- /dev/null +++ b/src/tests/unittests/CMakeLists.txt @@ -0,0 +1,8 @@ +add_cmocka_test(test_sample + SOURCES test_sample.c + LINK_LIBRARIES cmocka) + +add_cmocka_mock_test(test_filmicrgb + SOURCES test_filmicrgb.c + LINK_LIBRARIES lib_darktable cmocka + MOCKS dt_iop_color_picker_reset) diff --git a/src/tests/unittests/test_filmicrgb.c b/src/tests/unittests/test_filmicrgb.c new file mode 100644 index 000000000000..0925e6c3ca14 --- /dev/null +++ b/src/tests/unittests/test_filmicrgb.c @@ -0,0 +1,65 @@ +/* + This file is part of darktable, + copyright (c) 2020 Martin Burri. + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +*/ +#include +#include +#include +#include +#include + +#include + +#include "iop/filmicrgb.c" + +// epsilon for floating point comparison (TODO: take more sophisticated value): +#define E 1e-6f + + +/* + * MOCKED FUNCTIONS + */ + +void __wrap_dt_iop_color_picker_reset(dt_iop_module_t *module, gboolean update) +{ + check_expected_ptr(module); + check_expected(update); +} + + +/* + * TEST FUNCTIONS + */ + +static void test_sample(void **state) +{ + expect_value(__wrap_dt_iop_color_picker_reset, module, NULL); + expect_value(__wrap_dt_iop_color_picker_reset, update, TRUE); + gui_focus(NULL, 0); +} + + +/* + * MAIN FUNCTION + */ +int main() +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_sample) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/src/tests/unittests/test_sample.c b/src/tests/unittests/test_sample.c new file mode 100644 index 000000000000..02ca21680266 --- /dev/null +++ b/src/tests/unittests/test_sample.c @@ -0,0 +1,38 @@ +/* + This file is part of darktable, + copyright (c) 2020 Martin Burri. + + darktable is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + darktable 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with darktable. If not, see . +*/ +#include +#include +#include +#include +#include + +#include + +static void test_sample(void **state) +{ + // most efficient test: does just nothing :-) +} + +int main() +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_sample) + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +}