From 3ceb1de9663c47d5a42dac3ac8b2dfee22302611 Mon Sep 17 00:00:00 2001 From: Becheler <8360330+Becheler@users.noreply.github.com> Date: Sun, 4 May 2025 12:05:56 +0000 Subject: [PATCH] stash --- .devcontainer/Dockerfile-alpine | 20 -- .devcontainer/Dockerfile-ubuntu | 21 -- .devcontainer/devcontainer.json | 43 +-- .devcontainer/docker-alpine | 38 ++ .devcontainer/docker-ubuntu | 45 +++ .devcontainer/onCreateCommand.sh | 11 - .vscode/extensions.json | 18 +- .vscode/launch.json | 26 -- .vscode/setup_compiler_env.sh | 43 +++ .vscode/setup_packager.sh | 57 +++ .vscode/tasks.json | 327 ++++++++++-------- CMakeLists.txt | 12 +- CmakePresets.json | 81 +++++ conan/conan.conf | 18 - conan/profiles/linux-armv8-gcc12-debug | 7 - conan/profiles/linux-armv8-gcc12-release | 7 - conan/profiles/linux-armv8-gcc13-debug | 7 - conan/profiles/linux-x86-gcc12-debug | 7 - conan/profiles/linux-x86-gcc13-debug | 7 - conan/profiles/macos-armv8-appleclang13 | 14 - conanfile.py | 2 +- docs/4-tutorials.md | 6 +- example/CMakeLists.txt | 5 +- example/coalescence_binary_tree_1.cpp | 4 +- example/coalescence_binary_tree_2.cpp | 5 +- example/coalescence_binary_tree_3.cpp | 5 +- example/coalescence_binary_tree_4.cpp | 5 +- example/expressive_4.cpp | 2 +- example/geography_graph_1.cpp | 31 +- mrdox/CMakeLists.txt | 41 --- mrdox/coalescence.cpp | 5 - mrdox/config.yaml | 4 - mrdox/demography.cpp | 5 - mrdox/expressive.cpp | 5 - mrdox/geography.cpp | 5 - mrdox/io.cpp | 5 - .../quetzal/coalescence/graph/binary_tree.hpp | 4 +- .../quetzal/geography/graph/from_grid.hpp | 2 +- template/CMakeLists.txt | 40 --- template/data/bio1.tif | Bin 3948 -> 0 bytes template/data/bio12.tif | Bin 3965 -> 0 bytes template/data/elevation.tif | Bin 3965 -> 0 bytes template/data/suitability.tif | Bin 3950 -> 0 bytes template/main.cpp | 74 ---- test/CMakeLists.txt | 71 +--- test/integration_test/CMakeLists.txt | 49 +++ test/unit_test/CMakeLists.txt | 63 ++++ test/unit_test/FuzzyPartition_test.cpp | 54 ++- test/unit_test/Partitioner_test.cpp | 58 +++- test/unit_test/coalescence_test.cpp | 47 +-- test/unit_test/demography_test.cpp | 121 +++---- test/unit_test/expressive_test.cpp | 25 +- test/unit_test/geography_graph_test.cpp | 38 +- test/unit_test/geography_test.cpp | 102 +++--- test/unit_test/merger_test.cpp | 23 +- .../unit_test/newick_extended_parser_test.cpp | 166 +++++---- test/unit_test/newick_generator_test.cpp | 173 +-------- test/unit_test/newick_parser_test.cpp | 154 ++++----- test/unit_test/occupancy_spectrum_test.cpp | 20 +- test/unit_test/phylogeny_test.cpp | 12 +- test/unit_test/polymorphism_test.cpp | 97 ++---- test/unit_test/random_test.cpp | 28 +- test/unit_test/tree_binary_test.cpp | 201 +++++------ vcpkg.json | 19 + vcpkg_configuration.json | 19 + 65 files changed, 1164 insertions(+), 1440 deletions(-) delete mode 100644 .devcontainer/Dockerfile-alpine delete mode 100644 .devcontainer/Dockerfile-ubuntu create mode 100644 .devcontainer/docker-alpine create mode 100644 .devcontainer/docker-ubuntu delete mode 100755 .devcontainer/onCreateCommand.sh delete mode 100644 .vscode/launch.json create mode 100755 .vscode/setup_compiler_env.sh create mode 100755 .vscode/setup_packager.sh create mode 100644 CmakePresets.json delete mode 100644 conan/conan.conf delete mode 100644 conan/profiles/linux-armv8-gcc12-debug delete mode 100644 conan/profiles/linux-armv8-gcc12-release delete mode 100644 conan/profiles/linux-armv8-gcc13-debug delete mode 100644 conan/profiles/linux-x86-gcc12-debug delete mode 100644 conan/profiles/linux-x86-gcc13-debug delete mode 100644 conan/profiles/macos-armv8-appleclang13 delete mode 100644 mrdox/CMakeLists.txt delete mode 100644 mrdox/coalescence.cpp delete mode 100644 mrdox/config.yaml delete mode 100644 mrdox/demography.cpp delete mode 100644 mrdox/expressive.cpp delete mode 100644 mrdox/geography.cpp delete mode 100644 mrdox/io.cpp delete mode 100644 template/CMakeLists.txt delete mode 100644 template/data/bio1.tif delete mode 100644 template/data/bio12.tif delete mode 100644 template/data/elevation.tif delete mode 100644 template/data/suitability.tif delete mode 100644 template/main.cpp create mode 100644 test/integration_test/CMakeLists.txt create mode 100644 test/unit_test/CMakeLists.txt create mode 100644 vcpkg.json create mode 100644 vcpkg_configuration.json diff --git a/.devcontainer/Dockerfile-alpine b/.devcontainer/Dockerfile-alpine deleted file mode 100644 index 7433858f..00000000 --- a/.devcontainer/Dockerfile-alpine +++ /dev/null @@ -1,20 +0,0 @@ -FROM alpine:3.18 AS build - -LABEL maintainer="Arnaud Becheler" \ - description="Development Environment for Quetzal-CoaTL" - -WORKDIR /app - -# Installs build tools, see https://pkgs.alpinelinux.org/packages -RUN apk update && \ - apk add --no-cache \ - bash \ - perl \ - linux-headers \ - build-base=0.5-r3 \ - cmake=3.26.5-r0 \ - python3=3.11.6-r0 \ - py3-pip=23.1.2-r0 \ - git - -RUN pip install conan==2.0.13 \ No newline at end of file diff --git a/.devcontainer/Dockerfile-ubuntu b/.devcontainer/Dockerfile-ubuntu deleted file mode 100644 index 7540055e..00000000 --- a/.devcontainer/Dockerfile-ubuntu +++ /dev/null @@ -1,21 +0,0 @@ -FROM ubuntu:24.04 - -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt-get update -y -RUN apt-get install -y --no-install-recommends\ - vim \ - git \ - gcc-13 \ - g++-13 \ - clangd \ - build-essential \ - cmake \ - unzip \ - tar \ - ca-certificates \ - doxygen \ - graphviz \ - pipx - -RUN pipx ensurepath && pipx install conan==2.0.13 \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 36f60ce7..6bfc8c24 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,41 +6,24 @@ "workspaceFolder": "/app", "build": { "context": "..", - "dockerfile": "Dockerfile-ubuntu" + "dockerfile": "docker-ubuntu" }, - "onCreateCommand": "chmod +x .devcontainer/onCreateCommand.sh && ./.devcontainer/onCreateCommand.sh", "remoteUser": "root", "features": {}, "customizations": { - "vscode": { + "vscode": + { "extensions": [ - // Clangd: code complete, compile error, clang-format etc - "llvm-vs-code-extensions.vscode-clangd", - // Format all files in the workspace - "jbockle.jbockle-format-files", - // Cmake syntax highlighting - "twxs.cmake", - // Check grammar in text and Markdown - "znck.grammarly", - // Spelling check in code - "streetsidesoftware.code-spell-checker" + "Codeium.codeium", + // Extension for command variables in tasks.json. + "rioj7.command-variable", + // Adds a "Task Runner" view to run project tasks. + "SanaAjani.taskrunnercode", + // Bundle extensions + "ms-vscode.cpptools-extension-pack" ], - "settings": { - "clangd.path": "/usr/bin/clangd", - "clangd.arguments": [ - "--compile-commands-dir=${workspaceFolder}/build", - "-std=c++23" - ], - "clang-format.executable": "clang-format", - "clang-format.style": "file", - "clang-format.fallbackStyle": "Microsoft", - "clang-format.formatOnSave": true, - "clang-format.formatOnType": true, - "clang-format.arguments": [ - "-assume-filename=${workspaceFolder}/.clang-format" - ], - "formatFiles.excludedFolders": [ "node_modules", ".vscode", ".git", "dist", ".chrome", ".cache", "build"] - } } - } + }, + "postCreateCommand": "chmod +x ${containerWorkspaceFolder}/.vscode/*.sh" + } \ No newline at end of file diff --git a/.devcontainer/docker-alpine b/.devcontainer/docker-alpine new file mode 100644 index 00000000..b4b892e6 --- /dev/null +++ b/.devcontainer/docker-alpine @@ -0,0 +1,38 @@ +FROM alpine:3.20 + +WORKDIR /opt + +# Install necessary packages and dependencies +RUN apk update && apk add --no-cache \ + ninja-build \ + cmake \ + musl-dev \ + linux-headers \ + bash \ + gcc \ + g++ \ + clang \ + clang-extra-tools \ + vim \ + git \ + build-base \ + cmake \ + pkgconfig \ + ninja \ + curl \ + zip \ + unzip \ + tar \ + ca-certificates \ + doxygen \ + graphviz + +RUN apk add --no-cache python3 py3-pip && \ + pip install --no-cache-dir --break-system-packages pipx && \ + pipx ensurepath && \ + pipx install conan + +ENV PATH="/opt/vcpkg:$PATH" + + # Clean up +RUN rm -rf /var/cache/apk/* \ No newline at end of file diff --git a/.devcontainer/docker-ubuntu b/.devcontainer/docker-ubuntu new file mode 100644 index 00000000..3c8ca461 --- /dev/null +++ b/.devcontainer/docker-ubuntu @@ -0,0 +1,45 @@ +FROM ubuntu:24.04 + +WORKDIR /opt + +ARG DEBIAN_FRONTEND=noninteractive + +RUN apt-get update -y +RUN apt-get install -y --no-install-recommends\ + gcc-14 \ + g++-14 \ + clang-18 \ + clang-tools-18 \ + vim \ + git \ + curl \ + bash \ + clangd \ + build-essential \ + pkg-config \ + ninja-build \ + zip \ + unzip \ + tar \ + ca-certificates \ + doxygen \ + graphviz \ + mscgen \ + dia \ + pipx && \ + rm -rf /var/lib/apt/lists/*. + +# Install a modern CMake (≥3.20) via pip, which bundles the Ninja Multi-Config support +RUN pipx ensurepath && pipx install cmake conan + +# Install vcpkg package manager + +ENV VCPKG_FORCE_SYSTEM_BINARIES=1 + +RUN git clone --depth 1 https://github.com/microsoft/vcpkg.git && \ + cd vcpkg && \ + ./bootstrap-vcpkg.sh -disableMetrics -useSystemBinaries + +RUN apt-get update && apt-get install -y \ + autoconf autoconf-archive bison flex automake libtool pkg-config && \ + rm -rf /var/lib/apt/lists/* \ No newline at end of file diff --git a/.devcontainer/onCreateCommand.sh b/.devcontainer/onCreateCommand.sh deleted file mode 100755 index 227d3107..00000000 --- a/.devcontainer/onCreateCommand.sh +++ /dev/null @@ -1,11 +0,0 @@ -conan install conanfile.py \ - --profile:build=conan/profiles/linux-armv8-gcc12-release \ - --profile:host=conan/profiles/linux-armv8-gcc12-release \ - --build=missing \ - --output-folder=build - -conan install conanfile.py \ - --profile:build=conan/profiles/linux-armv8-gcc12-debug \ - --profile:host=conan/profiles/linux-armv8-gcc12-debug \ - --build=missing \ - --output-folder=build \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 4ddeeddf..933c580c 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,21 +1,5 @@ { "recommendations": [ - // Dev Containers "ms-vscode-remote.remote-containers", - // Docker Explorer view to VS Code - "ms-azuretools.vscode-docker", - // Understanding of complex code - //"lvm-vs-code-extensions.vscode-clangd" - // Bundle the 4 next extensions - // "ms-vscode.cpptools-extension-pack", - // 1. Semantic colorization - // "ms-vscode.cpptools-themes", - // 2. Intellisense - // "ms-vscode.cpptools", - // 3. CMake syntax - // "twxs.cmake", - // 4. Cmake workflow - // "ms-vscode.cmake-tool", - ] -} \ No newline at end of file +} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 494eb667..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,26 +0,0 @@ -// Debugger settings: File used by Visual Studio Code to define debug configurations. -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Launch Main", - "type": "cppdbg", - "request": "launch", - "program": "${workspaceFolder}/main.out", - "args": [], - "stopAtEntry": false, - "cwd": "${workspaceFolder}", - "environment": [], - "externalConsole": false, - "MIMode": "gdb", - "setupCommands": [ - { - "description": "Enable pretty-printing for gdb", - "text": "-enable-pretty-printing", - "ignoreFailures": true - } - ], - "preLaunchTask": "Build Main" - } - ] -} \ No newline at end of file diff --git a/.vscode/setup_compiler_env.sh b/.vscode/setup_compiler_env.sh new file mode 100755 index 00000000..b7ee4d67 --- /dev/null +++ b/.vscode/setup_compiler_env.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# Exit on any error +set -e + +# Color definitions for pretty print +GREEN="\033[0;32m" +YELLOW="\033[0;33m" +CYAN="\033[0;36m" +RED="\033[0;31m" +RESET="\033[0m" + +# Input arguments +COMPILER=$1 +BUILD_MODE=$2 + +# Extract base and version from the compiler +BASE="${COMPILER%-*}" +VERSION="${COMPILER#*-}" + +# Set CC and CXX based on the compiler +if [[ "$BASE" == "clang" ]]; then + export CC="/usr/bin/$COMPILER" + export CXX="${CC/clang/clang++}" +elif [[ "$BASE" == "gcc" ]]; then + export CC="/usr/bin/$COMPILER" + export CXX="${CC/gcc/g++}" +else + echo -e "${RED}Error: Unsupported compiler '${COMPILER}'${RESET}" + exit 1 +fi + +# Set the build type +export CMAKE_BUILD_TYPE="$BUILD_MODE" + +# Pretty print the compiler environment +echo -e "${YELLOW}=== Compiler Environment Setup ===${RESET}" +echo -e "${CYAN}Compiler Base: ${GREEN}$BASE${RESET}" +echo -e "${CYAN}Compiler Version: ${GREEN}$VERSION${RESET}" +echo -e "${CYAN}Build Mode: ${GREEN}$CMAKE_BUILD_TYPE${RESET}" +echo -e "${CYAN}CC: ${GREEN}$CC${RESET}" +echo -e "${CYAN}CXX: ${GREEN}$CXX${RESET}" +echo -e "${YELLOW}===================================${RESET}" diff --git a/.vscode/setup_packager.sh b/.vscode/setup_packager.sh new file mode 100755 index 00000000..fbf89915 --- /dev/null +++ b/.vscode/setup_packager.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# Color definitions for pretty print +GREEN="\033[0;32m" +YELLOW="\033[0;33m" +CYAN="\033[0;36m" +MAGENTA="\033[0;35m" +RED="\033[0;31m" +GREY="\033[2m" +RESET="\033[0m" + +# Input arguments +COMPILER=$1 +BUILD_MODE=$2 +STD_VERSION=$3 +PACKAGER=$4 + +BASE="${COMPILER%-*}" +VERSION="${COMPILER#*-}" + +# Pretty print the build configuration +echo -e "${YELLOW}=== Package Manager Setup =========${RESET}" +echo -e "${CYAN}Compiler Base: ${GREEN}${BASE}${RESET}" +echo -e "${CYAN}Compiler Version: ${GREEN}${VERSION}${RESET}" +echo -e "${CYAN}Build Mode: ${GREEN}${BUILD_MODE}${RESET}" +echo -e "${CYAN}C++ Standard: ${GREEN}${STD_VERSION}${RESET}" +echo -e "${CYAN}Package Manager: ${GREEN}${PACKAGER}${RESET}" +echo -e "${YELLOW}===================================${RESET}" + +# Check the package manager and execute corresponding commands +if [[ "$PACKAGER" == "vcpkg" ]]; then + echo -e "[INFO] Setting up vcpkg..." + if [ "$(uname -m)" != "x86_64" ]; then + echo -e "${MAGENTA}[INFO] Non-x86 platform detected.${RESET}" + echo -e "[INFO] VCPKG_FORCE_SYSTEM_BINARIES set to ${VCPKG_FORCE_SYSTEM_BINARIES}." + fi + echo -e "[COMMAND] vcpkg --version" + echo -e "${GREY}$(/opt/vcpkg/vcpkg --version)${RESET}" + echo -e "[INFO] vcpkg installation verification completed successfully.${RESET}" +elif [[ "$PACKAGER" == "conan" ]]; then + echo -e "${MAGENTA}Setting up conan...${RESET}" + if ! conan profile detect > /dev/null 2>&1; then + if [[ ! -f ~/.conan2/profiles/default ]]; then + conan profile detect > /dev/null 2>&1 + fi + fi + conan install . -b missing -of build/conan \ + -s compiler="$BASE" \ + -s compiler.version="$VERSION" \ + -s build_type="$BUILD_MODE" \ + -s compiler.cppstd="$STD_VERSION" +else + echo -e "${RED}Error: Unknown package manager '${PACKAGER}'${RESET}" + exit 1 +fi + +echo -e "${GREEN}=== Package Manager Setup Complete ===${RESET}" \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e2f89c8a..b3a3fb64 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,150 +1,181 @@ -// Build instructions -// tasks.json allows to define and chain arbitrary shell commands or programs together and run them from the VS Code UI. { - "version": "2.0.0", - "tasks": [ - { - "label": "Clean Build Folder", - "type": "shell", - "command": "rm -r ${workspaceFolder}/build", - "problemMatcher": [], - }, - // TEST RELEASE - { - "label": "Configure Conan (Release)", - "type": "shell", - "command": "conan install conanfile.py --profile:build=conan/profiles/linux-armv8-gcc12-release --profile:host=conan/profiles/linux-armv8-gcc12-release --build=missing --output-folder=build", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": [], - }, - { - "label": "Configure CMake (Release)", - "type": "shell", - "command": "cmake -B ${workspaceFolder}/build -S . -DCMAKE_BUILD_TYPE=Release --toolchain ${workspaceFolder}/build/conan_toolchain.cmake", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": ["Configure Conan (Release)"], - }, - { - "label": "Build Unit Tests (Release)", - "type": "shell", - "command": "cmake --build ${workspaceFolder}/build --config Release", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": ["Configure CMake (Release)"], - }, - { - "label": "Run Unit Tests (Release)", - "type": "shell", - "command": "cd ${workspaceFolder}/build && ctest -C Release --rerun-failed --output-on-failure", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "problemMatcher": [], - "dependsOn": ["Build Unit Tests (Release)"], - }, - // TEST DEBUG - { - "label": "Configure Conan (Debug)", - "type": "shell", - "command": "conan install conanfile.py --profile:build=conan/profiles/linux-armv8-gcc12-debug --profile:host=conan/profiles/linux-armv8-gcc12-debug --build=missing --output-folder=build", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": [], - }, - { - "label": "Configure CMake (Debug)", - "type": "shell", - "command": "cmake -B ${workspaceFolder}/build -S . -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTS=ON --toolchain ${workspaceFolder}/build/conan_toolchain.cmake", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": ["Configure Conan (Debug)"], - }, - { - "label": "Build Unit Tests (Debug)", - "type": "shell", - "command": "cmake --build ${workspaceFolder}/build --config Debug", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": ["Configure CMake (Debug)"], - }, - { - "label": "Run Unit Tests (Debug)", - "type": "shell", - "command": "cd ${workspaceFolder}/build && ctest -C Debug --rerun-failed --output-on-failure", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "problemMatcher": [], - "dependsOn": ["Build Unit Tests (Debug)"], - }, - // TEMPLATE PROJECT - { - "label": "Configure CMake Template (Debug)", - "type": "shell", - "command": "cmake -B ${workspaceFolder}/build -S . -DCMAKE_BUILD_TYPE=Debug --toolchain ${workspaceFolder}/build/conan_toolchain.cmake", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": ["Configure Conan (Debug)"], - }, - { - "label": "Build Template Project (Debug)", - "type": "shell", - "command": "cd ${workspaceFolder}/build && cmake --build . ", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": ["Configure CMake Template (Debug)"], - }, - { - "label": "Run Template Project (Debug)", - "type": "shell", - "command": "cd ${workspaceFolder}/build/template && ./main ", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": ["Build Template Project (Debug)"], - "problemMatcher": [], - }, - // DOCUMENTATION - { - "label": "Make Docs", - "type": "shell", - "command": "cd ${workspaceFolder}/build && make docs ", - "group": "test", - "presentation": { - "reveal": "always", - "panel": "shared" - }, - "dependsOn": ["Run Unit Tests (Debug)"], - }, - ] + "version": "2.0.0", + "tasks": [ + { + "label": "Run All Tests", + "type": "shell", + "command": "cd ${workspaceFolder}/build/${input:packager} && ctest -C ${input:build_mode} --rerun-failed --output-on-failure", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "problemMatcher": [], + "dependsOn": [ + "Build All Tests" + ], + }, + { + "label": "Make Docs", + "type": "shell", + "command": "cd ${workspaceFolder}/build/${input:packager} && ninja docs ", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "dependsOn": [ + "Run All Tests" + ], + }, + { + "label": "Clean Project", + "type": "shell", + "command": "rm -rf ${workspaceFolder}/build ${workspaceFolder}/CMakeUserPresets.json", + "problemMatcher": [] + }, + { + "label": "Build All Tests", + "type": "shell", + "command": "cmake --build --preset ${input:packager}-${input:build_mode} -- -j1", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "dependsOn": [ + "Configure CMake" + ], + }, + { + "label": "Setup Compiler Environment", + "type": "shell", + "command": "${workspaceFolder}/.vscode/setup_compiler_env.sh", + "group": "none", + "hidden": true, + "args": [ + "${input:compiler}", + "${input:build_mode}" + ], + "problemMatcher": [], + "presentation": { + "reveal": "always", + "echo": false, + "focus": true, + "panel": "shared" + } + }, + { + "label": "Setup Package Manager", + "type": "shell", + "command": "${workspaceFolder}/.vscode/setup_packager.sh", + "args": [ + "${input:compiler}", + "${input:build_mode}", + "${input:std_version}", + "${input:packager}" + ], + "problemMatcher": [], + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "dependsOn": [ + "Setup Compiler Environment" + ] + }, + { + "label": "Configure CMake", + "type": "shell", + "command": "cmake --preset ${input:packager} -D CMAKE_BUILD_TYPE=${input:build_mode} -DCMAKE_CXX_STANDARD=${input:std_version}", + "group": "test", + "presentation": { + "reveal": "always", + "panel": "shared" + }, + "dependsOn": [ + "Setup Package Manager" + ], + } + ], + "inputs": [ + { + "id": "compiler", + "type": "command", + "command": "extension.commandvariable.pickStringRemember", + "args": { + "variable": "compiler_remembered", + "options": [ + "gcc-14", + "gcc-13", + "clang-18" + ], + "description": "Pick a compiler", + "default": "clang-18" + } + }, + { + "id": "build_mode", + "type": "command", + "command": "extension.commandvariable.pickStringRemember", + "args": { + "variable": "build_mode_remembered", + "options": [ + "Debug", + "Release" + ], + "description": "Pick a build mode", + "default": "Debug" + } + }, + { + "id": "std_version", + "type": "command", + "command": "extension.commandvariable.pickStringRemember", + "args": { + "variable": "std_version_remembered", + "options": [ + "20", + "23" + ], + "description": "Pick a C++ Standard version", + "default": "23" + } + }, + { + "id": "packager", + "type": "command", + "command": "extension.commandvariable.pickStringRemember", + "args": { + "key": "packager", + "options": [ + [ + "vcpkg", + { + "packager": "vcpkg", + "pmcommand": "/opt/vcpkg/vcpkg --version" + } + ], + [ + "conan", + { + "packager": "conan", + "pmcommand": "conan install . -b missing -of build/conan -s compiler=$BASE -s compiler.version=$VERSION -s build_type=${input:build_type} -s compiler.cppstd=${input:std_version}" + } + ] + ], + "description": "Pick a Package Manager", + "default": "vcpkg" + } + }, + { + "id": "pmcommand", + "description": "Package Manager Command", + "type": "command", + "command": "extension.commandvariable.pickStringRemember", + "args": { + "key": "pmcommand" + } + }, + ] } \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 31833d1a..1261d90f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,19 +20,13 @@ add_subdirectory(src) # generate project documentation add_subdirectory(docs) -# generate project documentation -add_subdirectory(mrdox) - -# add template project -add_subdirectory(template) - # We default to build tests if option -D CMAKE_BUILD_TESTS=ON not provided (no FORCE, so the previous value, if set, stays) -set(BUILD_TESTS OFF CACHE STRING "Build module test") +# set(BUILD_TESTS ON CACHE STRING "Build module test") -if(BUILD_TESTS) +# if(BUILD_TESTS) enable_testing() # add unit tests add_subdirectory(test) # add usage example add_subdirectory(example) -endif() \ No newline at end of file +# endif() \ No newline at end of file diff --git a/CmakePresets.json b/CmakePresets.json new file mode 100644 index 00000000..a7f1d67d --- /dev/null +++ b/CmakePresets.json @@ -0,0 +1,81 @@ +{ + "version": 4, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + "configurePresets": [ + { + "name": "default", + "displayName": "Default Config", + "generator": "Ninja Multi-Config", + "binaryDir": "${sourceDir}/build/${presetName}" + }, + { + "name": "vcpkg", + "inherits": ["default"], + "description": "Build using vcpkg toolchain", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "/opt/vcpkg/scripts/buildsystems/vcpkg.cmake" + } + }, + { + "name": "conan", + "inherits": ["default"], + "description": "Build using Conan toolchain", + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/build/conan/conan_toolchain.cmake" + } + } + ], + "buildPresets": [ + { + "name": "vcpkg-Debug", + "configurePreset": "vcpkg", + "description": "Build with vcpkg in Debug mode", + "configuration": "Debug" + }, + { + "name": "vcpkg-Release", + "configurePreset": "vcpkg", + "description": "Build with vcpkg in Release mode", + "configuration": "Release" + }, + { + "name": "conan-Debug", + "configurePreset": "conan", + "description": "Build with Conan in Debug mode", + "configuration": "Debug" + }, + { + "name": "conan-Release", + "configurePreset": "conan", + "description": "Build with Conan in Release mode", + "configuration": "Release" + } + ], + "testPresets": [ + { + "name": "vcpkg-Debug-test", + "configurePreset": "vcpkg", + "configuration": "Debug" + }, + { + "name": "vcpkg-Release-test", + "configurePreset": "vcpkg", + "configuration": "Release" + }, + { + "name": "conan-Debug-test", + "configurePreset": "conan", + "configuration": "Debug" + }, + { + "name": "conan-Release-test", + "configurePreset": "conan", + "configuration": "Release" + } + ] + } + \ No newline at end of file diff --git a/conan/conan.conf b/conan/conan.conf deleted file mode 100644 index 1ebfdce3..00000000 --- a/conan/conan.conf +++ /dev/null @@ -1,18 +0,0 @@ -[general] -# Specify the default profile to use when creating packages -default_profile = default - -# Set default values for Conan settings -[settings_defaults] -os=Linux -arch=x86_64 -compiler=gcc -compiler.version=13 -compiler.libcxx=libstdc++11 - -# Set default options for packages -[options] -# the package should be built as a static library (non-shared). -my_package:shared=False -# the package should be built with optimizations enabled. -my_package:optimize=True \ No newline at end of file diff --git a/conan/profiles/linux-armv8-gcc12-debug b/conan/profiles/linux-armv8-gcc12-debug deleted file mode 100644 index cd8bf089..00000000 --- a/conan/profiles/linux-armv8-gcc12-debug +++ /dev/null @@ -1,7 +0,0 @@ -[settings] -os=Linux -arch=armv8 -compiler=gcc -compiler.version=12 -compiler.libcxx=libstdc++11 -build_type=Debug \ No newline at end of file diff --git a/conan/profiles/linux-armv8-gcc12-release b/conan/profiles/linux-armv8-gcc12-release deleted file mode 100644 index 8a3169c4..00000000 --- a/conan/profiles/linux-armv8-gcc12-release +++ /dev/null @@ -1,7 +0,0 @@ -[settings] -os=Linux -arch=armv8 -compiler=gcc -compiler.version=12 -compiler.libcxx=libstdc++11 -build_type=Release \ No newline at end of file diff --git a/conan/profiles/linux-armv8-gcc13-debug b/conan/profiles/linux-armv8-gcc13-debug deleted file mode 100644 index 6b9a0df8..00000000 --- a/conan/profiles/linux-armv8-gcc13-debug +++ /dev/null @@ -1,7 +0,0 @@ -[settings] -os=Linux -arch=armv8 -compiler=gcc -compiler.version=13 -compiler.libcxx=libstdc++11 -build_type=Debug \ No newline at end of file diff --git a/conan/profiles/linux-x86-gcc12-debug b/conan/profiles/linux-x86-gcc12-debug deleted file mode 100644 index fbc4890b..00000000 --- a/conan/profiles/linux-x86-gcc12-debug +++ /dev/null @@ -1,7 +0,0 @@ -[settings] -os=Linux -arch=x86_64 -compiler=gcc -compiler.version=12 -compiler.libcxx=libstdc++11 -build_type=Debug \ No newline at end of file diff --git a/conan/profiles/linux-x86-gcc13-debug b/conan/profiles/linux-x86-gcc13-debug deleted file mode 100644 index 2a2cb6e4..00000000 --- a/conan/profiles/linux-x86-gcc13-debug +++ /dev/null @@ -1,7 +0,0 @@ -[settings] -os=Linux -arch=x86_64 -compiler=gcc -compiler.version=13 -compiler.libcxx=libstdc++11 -build_type=Debug \ No newline at end of file diff --git a/conan/profiles/macos-armv8-appleclang13 b/conan/profiles/macos-armv8-appleclang13 deleted file mode 100644 index 7609463c..00000000 --- a/conan/profiles/macos-armv8-appleclang13 +++ /dev/null @@ -1,14 +0,0 @@ -[settings] -os=Macos -os_build=Macos -arch=armv8 -arch_build=armv8 -compiler=apple-clang -compiler.version=13 -compiler.libcxx=libc++ -compiler.cppstd=20 -build_type=Release -[options] -[conf] -[build_requires] -[env] \ No newline at end of file diff --git a/conanfile.py b/conanfile.py index b8cd4d1f..b1cd81c9 100644 --- a/conanfile.py +++ b/conanfile.py @@ -37,7 +37,7 @@ def package_id(self): self.info.clear() def requirements(self): - self.requires("boost/1.86.0") + self.requires("boost/1.85.0") self.requires("gdal/3.8.3") self.requires("range-v3/0.12.0") self.requires("mp-units/2.2.1") diff --git a/docs/4-tutorials.md b/docs/4-tutorials.md index 26aab6b4..86d4ea12 100644 --- a/docs/4-tutorials.md +++ b/docs/4-tutorials.md @@ -767,7 +767,7 @@ This involves identifying the cells of the raster to map `location_type` values ## Graph from landscape -The provided code snippet contains the logic for constructing a spatial graph from a `quetzal::geography::landscape`. +In the parlance of quetzal, a `quetzal::geography::landscape` is just multiple aligned `quetzal::geography::raster` defined for different spatial quantities: since their grid structure are identical, the logic relating to spatial graph construction is unchanged. The provided code snippet contains the logic for constructing a spatial graph from a `quetzal::geography::landscape`. This involves identifying the cells of the landscape to map `location_type` values to the vertices, and defining edges based on the desired connectivity. @@ -781,7 +781,7 @@ This involves identifying the cells of the landscape to map `location_type` valu ## Graph from abstract grid -The provided code snippet contains the logic for constructing a spatial graph from a user-defined abstract grid. +The provided code snippet demonstrates how to construct a spatial graph from a user-defined abstract grid. This approach is useful when you either don't have or prefer not to use a geospatial file alongside your code, for example if you don't care about spatial quantities. This involves identifying the height and width of the space to define linearly-indexed vertices, and defining edges based on the desired connectivity. @@ -1174,7 +1174,7 @@ By initializing the graph with default values, you maintain flexibility, allowin Here, we demonstrate how to directly initialize the edge properties during graph creation. This approach is particularly useful when working with large graphs, where manually updating each edge later would be inefficient. By initializing the properties in place, you can ensure that each edge has the correct values from the start. -This method requires defining a user-specific Edge Property class, which includes a default constructor to allow for proper instantiation. Doing so enables you to efficiently assign properties such as dispersal probabilities or weights directly to the graph’s edges during the initial setup, streamlining the overall process. +This method requires defining a user-specific Edge Property class, which includes a constructor to allow for proper instantiation. Doing so enables you to efficiently assign properties such as dispersal probabilities or weights directly to the graph’s edges during the initial setup, streamlining the overall process. **Input** diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 48074330..85d767f3 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -5,6 +5,7 @@ cmake_minimum_required(VERSION 3.12) set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) # Global approach Gdal +find_package(LIBKML) find_package(GDAL REQUIRED) # range-v3 @@ -14,7 +15,7 @@ find_package(range-v3) find_package(mp-units CONFIG REQUIRED) # Include Boost as an imported target: 1.73 important for compilation with gcc 10 and C++20 -find_package(Boost 1.79 REQUIRED COMPONENTS unit_test_framework filesystem serialization) +find_package(Boost 1.79 REQUIRED COMPONENTS filesystem serialization) if(Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) # Find Boost headers only ENDIF() @@ -36,7 +37,7 @@ foreach(testSrc ${SRCS}) # Ignore warnings about subtle ABI change target_compile_options(${testName} PUBLIC "-Wno-psabi") # Link to Boost libraries AND other targets and dependencies - target_link_libraries(${testName} quetzal::quetzal boost::boost GDAL::GDAL range-v3::range-v3 mp-units::mp-units) + target_link_libraries(${testName} quetzal::quetzal Boost::boost GDAL::GDAL range-v3::range-v3 mp-units::mp-units) # Specifies include directories to use when compiling a given target target_include_directories( ${testName} PRIVATE diff --git a/example/coalescence_binary_tree_1.cpp b/example/coalescence_binary_tree_1.cpp index dd1bdc7e..589f47b2 100644 --- a/example/coalescence_binary_tree_1.cpp +++ b/example/coalescence_binary_tree_1.cpp @@ -34,7 +34,9 @@ int main() assert(tree.has_predecessor(root) == false); assert(tree.predecessor(c) == root); assert(tree.has_successors(root) == true); - assert(std::ranges::none_of(tree.successors(c), [&](const auto &v) { return tree.has_successors(v); })); + for (auto v : tree.successors(c)) { + assert(! tree.has_successors(v)); + } std::cout << "Degree of inner vertex c is " << tree.degree(c) << std::endl; } diff --git a/example/coalescence_binary_tree_2.cpp b/example/coalescence_binary_tree_2.cpp index 8bc5a1f8..04497333 100644 --- a/example/coalescence_binary_tree_2.cpp +++ b/example/coalescence_binary_tree_2.cpp @@ -44,8 +44,9 @@ int main() assert(tree.has_predecessor(root) == false); assert(tree.predecessor(c) == root); assert(tree.has_successors(root) == true); - assert(std::ranges::none_of(tree.successors(c), [&](const auto &v) { return tree.has_successors(v); })); - + for (auto v : tree.successors(c)) { + assert(! tree.has_successors(v)); + } std::cout << "Degree of inner vertex c is " << tree.degree(c) << std::endl; // Root vertex field values were assigned diff --git a/example/coalescence_binary_tree_3.cpp b/example/coalescence_binary_tree_3.cpp index cdfa0542..920076ed 100644 --- a/example/coalescence_binary_tree_3.cpp +++ b/example/coalescence_binary_tree_3.cpp @@ -38,8 +38,9 @@ int main() assert(tree.has_predecessor(root) == false); assert(tree.predecessor(c) == root); assert(tree.has_successors(root) == true); - assert(std::ranges::none_of(tree.successors(c), [&](const auto &v) { return tree.has_successors(v); })); - + for (auto v : tree.successors(c)) { + assert(! tree.has_successors(v)); + } std::cout << "Degree of inner vertex c is " << tree.degree(c) << std::endl; // Edges from the root were assigned at construction diff --git a/example/coalescence_binary_tree_4.cpp b/example/coalescence_binary_tree_4.cpp index 40222884..e116b2d1 100644 --- a/example/coalescence_binary_tree_4.cpp +++ b/example/coalescence_binary_tree_4.cpp @@ -48,8 +48,9 @@ int main() assert(tree.has_predecessor(root) == false); assert(tree.predecessor(c) == root); assert(tree.has_successors(root) == true); - assert(std::ranges::none_of(tree.successors(c), [&](const auto &v) { return tree.has_successors(v); })); - + for (auto v : tree.successors(c)) { + assert(! tree.has_successors(v)); + } std::cout << "Degree of inner vertex c is " << tree.degree(c) << std::endl; // Root vertex field values were assigned at construction diff --git a/example/expressive_4.cpp b/example/expressive_4.cpp index 9396725f..c8cc05b3 100644 --- a/example/expressive_4.cpp +++ b/example/expressive_4.cpp @@ -30,7 +30,7 @@ int main() // We need to make choices here concerning how NA are handled auto suit = expressive::use([&](location_type x, time_type t) { return s_view(x, t).value_or(0.0); }); - auto elev = expressive::use([&](location_type x, time_type t) { return s_view(x, t).value_or(0.0); }); + auto elev = expressive::use([&](location_type x, time_type t) { return e_view(x, t).value_or(0.0); }); std::random_device rd; // a seed source for the random number engine std::mt19937 gen(rd()); // mersenne_twister_engine seeded with rd() diff --git a/example/geography_graph_1.cpp b/example/geography_graph_1.cpp index 5b7fdfc0..b9ed1f41 100644 --- a/example/geography_graph_1.cpp +++ b/example/geography_graph_1.cpp @@ -24,36 +24,11 @@ int main() using edge_info = geo::no_property; // Few of the possible assumptions combinations - auto graph1 = geo::from_grid(land, vertex_info(), edge_info(), geo::connect_fully(), geo::isotropy(), geo::mirror()); auto graph2 = geo::from_grid(land, vertex_info(), edge_info(), geo::connect_4_neighbors(), geo::isotropy(), geo::sink()); auto graph3 = geo::from_grid(land, vertex_info(), edge_info(), geo::connect_8_neighbors(), geo::anisotropy(), geo::torus()); - // Checking the numbers of edges is consistent with our assumptions - - int w = land.width(); - int h = land.height(); - - int n1 = graph1.num_vertices(); - int e1 = n1 * ( n1 - 1 ) / 2 ; // typical undirected complete graph - assert( n1 == land.num_locations() ); - assert( e1 == graph1.num_edges() ); - std::cout << "Graph 1 has " << n1 << " vertices, " << e1 << " edges." << std::endl; - - int n2 = graph2.num_vertices(); - int e2 = h * ( w - 1 ) // horizontal edges - + w * ( h - 1 ) // vertical edges - + 2 * ( w + h - 2 ) ; // border vertices connected to the outland - assert( n2 == n1 + 1 ) ; // outland sink vertex added - assert( e2 == graph2.num_edges() ); - std::cout << "Graph 2 has " << n2 << " vertices, " << e2 << " edges." << std::endl; - - int n3 = graph3.num_vertices(); - int a = h * ( w - 1 ) // horizontal edges - + w * ( h - 1 ) // vertical edges - + 2 * ( w - 1 ) * ( h - 1 ) ; // intercardinal for internal vertices only - int e3 = 2 * a + 2 * (w + h - 2); - assert( n3 == n1 ); // no vertex added - assert( e3 == graph3.num_edges() ); - std::cout << "Graph 3 has " << n3 << " vertices, " << e3 << " edges." << std::endl; + std::cout << "Graph 1 has " << graph1.num_vertices() << " vertices, " << graph1.num_edges() << " edges." << std::endl; + std::cout << "Graph 2 has " << graph2.num_vertices() << " vertices, " << graph2.num_edges() << " edges." << std::endl; + std::cout << "Graph 3 has " << graph3.num_vertices() << " vertices, " << graph3.num_edges() << " edges." << std::endl; } diff --git a/mrdox/CMakeLists.txt b/mrdox/CMakeLists.txt deleted file mode 100644 index e726cf01..00000000 --- a/mrdox/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# requires cxx_std_20 new in CMake 3.12 -cmake_minimum_required(VERSION 3.12) - -# Tell find_package() to first search using Config mode before falling back to Module mode (for conan) -set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) - -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -# Global approach Gdal -find_package(GDAL REQUIRED) - -# range-v3 -find_package(range-v3) - -# mp-units -find_package(mp-units CONFIG REQUIRED) - -# Include Boost as an imported target: 1.73 important for compilation with gcc 10 and C++20 -find_package(Boost 1.79 REQUIRED COMPONENTS unit_test_framework filesystem serialization) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) # Find Boost headers only -ENDIF() - -file(GLOB SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp) -foreach(testSrc ${SRCS}) - # Extract the filename without an extension (NAME_WE) - get_filename_component(testName ${testSrc} NAME_WE) - # Add compile target - add_executable(${testName} ${testSrc}) - # Require the standard - target_compile_features(${testName} PUBLIC cxx_std_23) - # Ignore warnings about subtle ABI change - target_compile_options(${testName} PUBLIC "-Wno-psabi") - # Link to Boost libraries AND other targets and dependencies - target_link_libraries(${testName} quetzal::quetzal boost::boost GDAL::GDAL range-v3::range-v3 mp-units::mp-units) - # Specifies include directories to use when compiling a given target - target_include_directories( - ${testName} PRIVATE - $ - $) -endforeach(testSrc) diff --git a/mrdox/coalescence.cpp b/mrdox/coalescence.cpp deleted file mode 100644 index 98891c63..00000000 --- a/mrdox/coalescence.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "quetzal/coalescence.hpp" - -int main(){ - return 0; -} \ No newline at end of file diff --git a/mrdox/config.yaml b/mrdox/config.yaml deleted file mode 100644 index f3f70c94..00000000 --- a/mrdox/config.yaml +++ /dev/null @@ -1,4 +0,0 @@ -concurrency: 1 # number of threads to use -source-root: ../ # source files relative to the mrdox.yml file -multipage: false # generate multiple pages -verbose: true # print verbose output \ No newline at end of file diff --git a/mrdox/demography.cpp b/mrdox/demography.cpp deleted file mode 100644 index d8cf9929..00000000 --- a/mrdox/demography.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "quetzal/demography.hpp" - -int main(){ - return 0; -} \ No newline at end of file diff --git a/mrdox/expressive.cpp b/mrdox/expressive.cpp deleted file mode 100644 index e67959ec..00000000 --- a/mrdox/expressive.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "quetzal/expressive.hpp" - -int main(){ - return 0; -} \ No newline at end of file diff --git a/mrdox/geography.cpp b/mrdox/geography.cpp deleted file mode 100644 index 9ad71b01..00000000 --- a/mrdox/geography.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "quetzal/geography.hpp" - -int main(){ - return 0; -} \ No newline at end of file diff --git a/mrdox/io.cpp b/mrdox/io.cpp deleted file mode 100644 index 5a11f6ac..00000000 --- a/mrdox/io.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "quetzal/io.hpp" - -int main(){ - return 0; -} \ No newline at end of file diff --git a/src/include/quetzal/coalescence/graph/binary_tree.hpp b/src/include/quetzal/coalescence/graph/binary_tree.hpp index a00d930d..008dd81e 100644 --- a/src/include/quetzal/coalescence/graph/binary_tree.hpp +++ b/src/include/quetzal/coalescence/graph/binary_tree.hpp @@ -14,6 +14,7 @@ #include #include +#include #include @@ -29,6 +30,7 @@ namespace quetzal::coalescence { + using no_property = boost::no_property; namespace detail @@ -239,7 +241,7 @@ template class binary_tree_common return boost::make_iterator_range(out_edges(u, _graph)) | boost::adaptors::transformed([this](auto it) { return target(it, _graph); }); } - + /// @brief Evaluate if vertex \f$u\f$ is a left successor. /// @param u The vertex to be evaluated /// @return True if u is a left successoir, false otherwise. diff --git a/src/include/quetzal/geography/graph/from_grid.hpp b/src/include/quetzal/geography/graph/from_grid.hpp index b694dbe4..a5791719 100644 --- a/src/include/quetzal/geography/graph/from_grid.hpp +++ b/src/include/quetzal/geography/graph/from_grid.hpp @@ -54,7 +54,7 @@ auto from_grid(SpatialGrid const &grid, VertexProperty const &v, EdgeProperty co for(auto edge : graph.edges()){ if constexpr (std::constructible_from){ graph[edge] = EdgeProperty(edge.source(), edge.target(), grid); - } else { + } else { static_assert(std::is_default_constructible_v); graph[edge] = e; } diff --git a/template/CMakeLists.txt b/template/CMakeLists.txt deleted file mode 100644 index ed5535b4..00000000 --- a/template/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -# requires cxx_std_20 new in CMake 3.12 -cmake_minimum_required(VERSION 3.12) - -# Tell find_package() to first search using Config mode before falling back to Module mode (for conan) -set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) - -# Global approach Gdal -find_package(GDAL REQUIRED) - -# range-v3 -find_package(range-v3) - -# mp-units -find_package(mp-units CONFIG REQUIRED) - -# Include Boost as an imported target: 1.73 important for compilation with gcc 10 and C++20 -find_package(Boost 1.79 REQUIRED COMPONENTS unit_test_framework filesystem serialization) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) # Find Boost headers only -ENDIF() - -# Copy the data required by I/O examples -file(COPY data DESTINATION ${CMAKE_BINARY_DIR}/template) - -# Create director to store the examples output (for future doc) -file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/template/output) - -# Add compile target -add_executable(main main.cpp) -# Require the standard -target_compile_features(main PUBLIC cxx_std_20) -# Ignore warnings about subtle ABI change -target_compile_options(main PUBLIC "-Wno-psabi") -# Link to Boost libraries AND other targets and dependencies -target_link_libraries(main quetzal::quetzal boost::boost GDAL::GDAL range-v3::range-v3 mp-units::mp-units) -# Specifies include directories to use when compiling a given target -target_include_directories( - main PRIVATE - $ - $) diff --git a/template/data/bio1.tif b/template/data/bio1.tif deleted file mode 100644 index 2b09500677bc9b5bb57f2784b0f6ecb97dc03a7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3948 zcmbW4e@q<5702iJaU5`_fWZ)q$r)2(Kwj_6?9R@}nB0{ME;itc!45_#zDqF0rnq*D zTS6=4dl%4rCmplT&+AGe zLV*rDvcmakuzwkhMh>u(;l2|=JBk9^1NLMvYCbA2*#0w7=m-dL&^Zcr7F_cS@YO%g zulX*FEd3u1_cnfux42yum3v!#4Zc=iNrJ;sT;963#c{ybvUhWCb&ad0yt<~mw0cja ztG2vyXJxMAu&?Fd_h3xUEx`(xNbyG9;eUBP=Bf&J!$gubEGW}7RTbs}u=0hLHdU0xFg;Q_OwC80d~zktn7V0AP&G z{f!7ff-7)qnJ-|VrV>U1pg@R3G^}x<2!)6U5@94jbOJC9$Up@A!WihTm`SP-OrbIX z6s8eW8XJ&5`rA$<2?jOcMcg9>2 z6f>%Fjxoo=g?TEC96*9l32Rto&`^T22=ZyH1_eT4vZO#mC=6rs zrmPGjp}Rv*QlQ8<)CDz<;(>|)4K6@}V8#`yYKl2cBMFcI5|9j8hQz3hMUYV=2~{Tn zB1C}|PNoW3?h2s`z$`S%6j+@!Oe08#u_{1AU`ZBG)tJkW64S~wq5uT~-7RaHjEO9$ z7C}agD433dNnB_|lU1sS<(7pmK$t|JpnzmV3$>91NC+Yc@aM9u$f{x~k<^v3 zEI>nW2}nW^j1kzLEt>^MK%eT*AlQ-!==T4{QM@sHlZnsilZdGQW?HLnsE`0$@K4n|3(D))`(BEa*EP)VEn?6ECm4%Ia8xsdG~xQ9;t zJ=T(bSKPgFIeph?ckJiUligM4*Y)JZpxc9Yws-gvj$Ff`%xzPN(lei3X@9uq_>22H ze!g#KMqb{D?doTLs;F-}+8^EJ9vb-(dwt;So3C!T8=|ebw#ZnnH`(Wyt%%i zC^_b}&wu^ys*kUp-uc_7Q|=Ev;Shdr-rv3%9BWHNa~CGQm~cLR>f}CUVD`X(?ZrQj z^uJxvx3+9FzG!%8&blM}(O{o{b@we%I5A_NysLWuu;<;LM}9aF%BdbcU*Ge=(EA^% zb+4s9ojR4!e#mw_)^_b5*qWL8T|8Ak-Zk^9ZC$Snd1V{C*KF$Zj>lP7pZ8{EykvbV zvmh1C?QiKEwfT#(FZ%0>V{Do+`Yb> z9H;nn_++Cu&6Cs+XwO~st^Sc4;~o3PTH_j?9XgkF``gLl_{>|GM^5>h)<2oz@l8L6 z8bcp^|589?SHyKSHK(jBb-CRg?_75mzWmgs{bgOF$^PcvuA`xb)Y_D*ImZGsQ*F~_ z&)e7hY!;ot-Ds{XF0=7ybMK1Mzm61Tc&}Y?WaRsl%5-;9RZY?{%X>9zc8jqUC_mm` z*gJyWKRtVk#VDzdG=2H-$xw0|O|$gh&%KGh%sd!8>wCO6GuS^^n&3T9g;%^X;dw6U r*^;*1NwJe}{Y8I?x#U!HxkU6ERz63H+)j3Z38oH`WXj&$(Z50bcS6HwgaAZ0cZu-21X9pNiQc(t?OKZBsK3! zlx#5m53qk9vPy2SGvK{Lp+w07_A0R74Oyn5+5mR&utjPDAPzW9V9$eRPJyp+d4A?| zb7tm$E43$^-9^5}+Kui_fsM6GvnwjSmA;Bf-?EA|es7h} z|D-?Ly*040VFS#m*~Oa5xuWWva?CVAiV6+a|A+Cgw=4{RQKD!}rx+2gp~(KevRP}u zRKODccSXdgs4OXY_^Gf}XdEky>KF^msU8tw784pUp{YV)LSVwNri;iJVN3u3v0#G_b*nF_$bj4N2f5npbmz*s+QB&?kQ6^yD;yxyz^WN@HsiVy^2MmUOMH^Vpp z04AuSa!Ltf5C)GJhu_QrU|`M^0dJ4&ZDzrUKp+Jn#s%V-kSO$QWT{c`#xyHi98cRHh;v8DdsOV1ow+ zYd~D3I;A)YF2i^L0FJnVFeip8F^a6}S!w_b2tc8NGK#e*%8Qu^BMKov(mEG{X_Q2< z8D>Qgz(A^|AdV=)LT9(D2ms(1D_qkF5}b1qMPixr0x*ci6i!qM!H8(sG;;wENYxE4 z7+g^Jqu3BL7u4Va5k*%yf)oc`L=+3I`t?Ttr6{SdAQqnG0rcfd%X<#uzr1L{W3YG6VoP)O&$-At)A9y#rkU2GO|! zOmHJd1Y;2cG3x>#fIKY z0T=|fgJ7nsL{$-s9EX_-fIu3BQyk78$WtmJvpK793ZOz)RY(ykFvVPpLg8Vu005z3 zILnQW$T*85$1$sL0tTU~0@6SP8XG8Gw=D~RKuA@%3dIIG8YsWFAc_jZ8%{}jK!X|` ze&N~zC=%1HYl`QlaqB*_qy0HM<%64}D?GPm<*A-NPLg8a7XkFv(7?kT+GzN}AWPpl zW&67!n3Zf(-}fza*oQ*Ke8SXSl3F)5zP{k_^9G*hXl0dm#fq_$zShFXr7aggL}5i!N1>k z@#On${?3?Vm0RS-KQ7MfUY4>$N^QP>e$oT;^1I4c1{U=UmP?<%`q#p@KOL;LZrizC zvc5TY^!oeNnNQ#Cyke<7_QIAY-~Q+3k*#yTj7{ygCv>fC+VFYh>Zb39lAZV7SJILA zMbnS+iGh)xmS^z?AFs5Fxb*K+F8|wkpzxK<+;Z$m&q>K_Y0qum((##PU~lsE?1`%v z8;fc#)$JTb^OrrkyZxxUp>4sTfz-akZ~kTT(wv<5x^177x78btY?lb>CQOPcfyz4cYNozIUf$5$~fq_ z`g(rHrOrt@*zY`(Z-2Qr=@GjuKUZ__y4?4YBu`$$wxpZ`t~v9ACpQ%~4|;kF=Gd;E z_h-fAj*EM;(o0*DrB1uca^!ip=e3p{BkM!;HZSPu-6GCu}ZT z=nt!kEOp8G{>~q+rmi@2!7t0=$1bel-GS3zWXL5Q!L)rP zd9KF2=d?j@`-h%~s?U!0x#Q>djj!;vS|(ftzwLM2UFJG1O{T|<{gSUr?W^xy5TDb( zy5y-{p5Eft*kc_Jy2nUEW|};H{+a#XTnpOL7s_94w$|JTI%2ZqE3WSCTh4CXAGpwy z=Cnvd8C}cr$~|8n8E@Tjj~sYsQ~SWR%ME+wfW>X?{Xs2oj4b*tA;BtJEN_fBgN611 z=W$oeNP3WUp1E`|tuy_JgT={BH`Z*3++1HHdtkKw^mjhINsZllls>1QCmS%RnnTfyhD>GV!o~V^!|jp=3z2# NdEn6cy}$c~<-d5VKmh;% diff --git a/template/data/elevation.tif b/template/data/elevation.tif deleted file mode 100644 index 0b4c9a82f1029d214880e74147708319d6e14c15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3965 zcmbVPeNa@_6@PCRmR%rZSrLe0SP%^#$>Y8I?x#U!HxkU6ERz63H+)j3Z38oH`WXj&$(Z50bcS6HwgaAZ0cZu-21X9pNiQc(t?OKZBsK3! zlx#5m53qk9vPy2SGvK{Lp+w07_A0R74Oyn5+5mR&utjPDAPzW9V9$eRPJyp+d4A?| zb7tm$E43$^-9^5}+Kui_fsM6GvnwjSmA;Bf-?EA|es7h} z|D-?Ly*040VFS#m*~Oa5xuWWva?CVAiV6+a|A+Cgw=4{RQKD!}rx+2gp~(KevRP}u zRKODccSXdgs4OXY_^Gf}XdEky>KF^msU8tw784pUp{YV)LSVwNri;iJVN3u3v0#G_b*nF_$bj4N2f5npbmz*s+QB&?kQ6^yD;yxyz^WN@HsiVy^2MmUOMH^Vpp z04AuSa!Ltf5C)GJhu_QrU|`M^0dJ4&ZDzrUKp+Jn#s%V-kSO$QWT{c`#xyHi98cRHh;v8DdsOV1ow+ zYd~D3I;A)YF2i^L0FJnVFeip8F^a6}S!w_b2tc8NGK#e*%8Qu^BMKov(mEG{X_Q2< z8D>Qgz(A^|AdV=)LT9(D2ms(1D_qkF5}b1qMPixr0x*ci6i!qM!H8(sG;;wENYxE4 z7+g^Jqu3BL7u4Va5k*%yf)oc`L=+3I`t?Ttr6{SdAQqnG0rcfd%X<#uzr1L{W3YG6VoP)O&$-At)A9y#rkU2GO|! zOmHJd1Y;2cG3x>#fIKY z0T=|fgJ7nsL{$-s9EX_-fIu3BQyk78$WtmJvpK793ZOz)RY(ykFvVPpLg8Vu005z3 zILnQW$T*85$1$sL0tTU~0@6SP8XG8Gw=D~RKuA@%3dIIG8YsWFAc_jZ8%{}jK!X|` ze&N~zC=%1HYl`QlaqB*_qy0HM<%64}D?GPm<*A-NPLg8a7XkFv(7?kT+GzN}AWPpl zW&67!n3Zf(-}fza*oQ*Ke8SXSl3F)5zP{k_^9G*hXl0dm#fq_$zShFXr7aggL}5i!N1>k z@#On${?3?Vm0RS-KQ7MfUY4>$N^QP>e$oT;^1I4c1{U=UmP?<%`q#p@KOL;LZrizC zvc5TY^!oeNnNQ#Cyke<7_QIAY-~Q+3k*#yTj7{ygCv>fC+VFYh>Zb39lAZV7SJILA zMbnS+iGh)xmS^z?AFs5Fxb*K+F8|wkpzxK<+;Z$m&q>K_Y0qum((##PU~lsE?1`%v z8;fc#)$JTb^OrrkyZxxUp>4sTfz-akZ~kTT(wv<5x^177x78btY?lb>CQOPcfyz4cYNozIUf$5$~fq_ z`g(rHrOrt@*zY`(Z-2Qr=@GjuKUZ__y4?4YBu`$$wxpZ`t~v9ACpQ%~4|;kF=Gd;E z_h-fAj*EM;(o0*DrB1uca^!ip=e3p{BkM!;HZSPu-6GCu}ZT z=nt!kEOp8G{>~q+rmi@2!7t0=$1bel-GS3zWXL5Q!L)rP zd9KF2=d?j@`-h%~s?U!0x#Q>djj!;vS|(ftzwLM2UFJG1O{T|<{gSUr?W^xy5TDb( zy5y-{p5Eft*kc_Jy2nUEW|};H{+a#XTnpOL7s_94w$|JTI%2ZqE3WSCTh4CXAGpwy z=Cnvd8C}cr$~|8n8E@Tjj~sYsQ~SWR%ME+wfW>X?{Xs2oj4b*tA;BtJEN_fBgN611 z=W$oeNP3WUp1E`|tuy_JgT={BH`Z*3++1HHdtkKw^mjhINsZllls>1QCmS%RnnTfyhD>GV!o~V^!|jp=3z2# NdEn6cy}$c~<-d5VKmh;% diff --git a/template/data/suitability.tif b/template/data/suitability.tif deleted file mode 100644 index 3d16cd004e8110cbafa78ed345a594421c793a8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3950 zcmbW4O=uHA6vrn?t!<4}Y5h1T#CRx3yWN@Dot=d=ZD>l_Vq0lat*07o#G*+{o1=(U zAq7D^3EmW{0V&#o2f>RV73@vWlY+M%MGD1}#W!gKZL+)Boh)zXWoG`fZ-4uCnP*w& zQ4>O_4WU2?1;7h|1@`zs@LQm7Q;hBQi+PQE{9}QJvbM1mq2s&#LUUr*7i*r}opTe! zr}t>bz;7%rHWou+Dw(8(>a8lZP_`ZS7GW*mnxSwX2WVU@~!GI9td}WeS;iOC%Dr z3fWvFpUGu=qN#KuZKcvye`<0#F<}jl4@V>OncVDc7*nHh9P1X7-BbgKk$sXb6Mpq& z)=168bOoD4C92L1O7(0P*6S{lN+**8m%Ls-Igsifvo5Bs(S0FD=4Qn0PG#q>&rQ!3 zrf2fe__gU7Jn7-?tC?Z{%s?W^Oel$BGLx8uYgFY_3YvQWw$O0Y5gMuc&}tHm_=g4( zNob(d6;24&h+#6S8%zqCdjPi3h%+?m9~$)!4J4A#gpw%+F$mKcXH3Ufikf=_w$!LI zHO)UY%|A7eNKz9@s+gvMxuIgNnnaG8djz)BG-qn{zp6DasP3N{NF=EVrLJh4QL1rM zr8+UBa?L#gTWY#9HReCpn15;@k)$S+MByB324^bAsw($gbC1B58gr&*_@`$0rv?&9 zYC=gB6;q0V8B;MPQn}_Hfh{$|nHu*`jr*qt5=m-8Nfp?37@TlbXUq`P>c1h?yEXR+ zY^iZ)Y92P7)w?y*KQ)j@QWHw5a7Z>&gJd(fW=iFndjz)BOlN9Xtt4Bldw-!&DJ33?|KkkeS^;KpB%2n1uBnp}UR6bBrK?_9=lyCvGaWv4hT7*&5SpNU`TyxV( zQH&odw+Jof3Qx~0&58B;UZp1zmj_c3uH8X@mF2h>>wfnv?!}sie)f2=_v~NXiv^#r z$GzB}BOf}xY>k)JKYi_JySiC=6nauxc)eEIcrjY~eD+G|$FFZMm$w#6o!__PUTp2a NtzIt%6=$y(`w#i8P#XXM diff --git a/template/main.cpp b/template/main.cpp deleted file mode 100644 index 1bbb5a95..00000000 --- a/template/main.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "quetzal/quetzal.hpp" - -#include -#include -#include - -int main() -{ - // Load the suitability and elevation maps - auto file1 = std::filesystem::current_path() / "data/suitability.tif"; - auto file2 = std::filesystem::current_path() / "data/elevation.tif"; - - // The rasters 10 bands are indexed by the year they represent: 2001 ... 2010 - std::vector times(10); - std::iota(times.begin(), times.end(), 2001); - - // Initialize the landscape: for each spatial variable a string key and a file value, for all a time series. - auto landscape = quetzal::geography::landscape<>::from_file({{"suit", file1}, {"DEM", file2}}, times); - std::cout << landscape << std::endl; - - // Declares some type aliases to shorten notation - using location_type = quetzal::geography::landscape<>::location_descriptor; - using time_type = quetzal::geography::landscape<>::time_descriptor; - - // lightweight functors for suitability and digital elevation models that return empty optionals where NA are - // encounters - auto suit_view = landscape["suit"].to_view(); - auto elev_view = landscape["DEM"].to_view(); - - // We need to make choices here concerning how NA are handled - auto suit = quetzal::expressive::use([&](location_type x, time_type t) { return suit_view(x, t).value_or(0.0); }); - auto elev = quetzal::expressive::use([&](location_type x, time_type t) { return elev_view(x, t).value_or(0.0); }); - - std::random_device rd; // a seed source for the random number engine - std::mt19937 gen(rd()); // mersenne_twister_engine seeded with rd() - - // Small-scale ice-free shelters for the species randomly pop above the snow cover at high-altitude (>123m) - auto nunatak_suitability = [&](location_type x, time_type t) { - std::bernoulli_distribution d(0.1); // give "false" 9/10 of the time - bool is_nunatak = d(gen); - return (elev(x, t) >= 123.0) ? static_cast(is_nunatak) * suit(x, t) : suit(x, t); - }; - - // To allow dispersal across ocean, we can compose expressions: - auto capacity_with_rafting = [&](location_type x, time_type t) { - std::bernoulli_distribution d(0.1); // give "false" 9/10 of the time - if (suit(x, t) == 0.0 and elev(x, t) == 0.0) // ocean cell case: - return static_cast(d(gen)) * 2; // will (rarely) allow 2 individuals to survive in the ocean cell - else if (suit(x, 0) == 0.0 and elev(x, t) > 0.0) // unsuitable continental cell case: - return 0.0; // suitability is minimal, so should be the capacity - else // habitable continental cells: - return nunatak_suitability(x, t); // evaluates suitability simulating nunataks - }; - - // Account for different dispersal modes - auto friction_with_rafting = [&](location_type x, time_type t) { - if (suit(x, t) == 0.0 and elev(x, t) == 0.0) // ocean cell case: - return 0.0; // the raft should move freely on the water - else if (suit(x, 0) == 0.0 and elev(x, t) > 0.0) // hostile continental cell case: - return 1.00; // max friction as the cell is not attractive - else // favorable continental cell case: - return 1.0 - suit(x, 0); // higher the suitability, easier the travel - }; - - // Expressions can be evaluated with a location_type and a time_type argument: - auto x = *landscape.locations().begin(); - auto t = *landscape.times().begin(); - - std::cout << "Friction f( x = " << x << ", t = " << t << " ) = " << friction_with_rafting(x, t) << std::endl; - std::cout << "Carrying capacity K( x = " << x << ", t = " << t << " ) = " << capacity_with_rafting(x, t) - << std::endl; - - // Spatial graph -} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 30489a41..dabe1c28 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,71 +1,4 @@ cmake_minimum_required(VERSION 3.19) -set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) - -message("Compiler Version: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") - -# Include Boost as an imported target: 1.73 important for compilation with gcc 10 and C++20 -find_package(Boost 1.79 REQUIRED COMPONENTS unit_test_framework filesystem serialization) -if(Boost_FOUND) - include_directories(${Boost_INCLUDE_DIRS}) # Find Boost headers only -ENDIF() - -# Global approach Gdal -find_package(GDAL REQUIRED) - -# range-v3 -find_package(range-v3) - -# mp-units -find_package(mp-units CONFIG REQUIRED) - -# Copy the data required -file(COPY data DESTINATION ${CMAKE_BINARY_DIR}/test) - -### UNIT TEST -file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} unit_test/*.cpp) -foreach(testSrc ${TEST_SRCS}) - # Extract the filename without an extension (NAME_WE) - get_filename_component(testName ${testSrc} NAME_WE) - # Add compile target - add_executable(${testName} ${testSrc}) - # Require the standard - target_compile_features(${testName} PRIVATE cxx_std_23) - # Ignore warnings about subtle ABI change - target_compile_options(${testName} PUBLIC "-Wno-psabi") - # Link to targets and dependencies - target_link_libraries(${testName} quetzal::quetzal boost::boost GDAL::GDAL range-v3::range-v3 mp-units::mp-units) - # Specifies include directories to use when compiling the target - target_include_directories( - ${testName} PRIVATE - $ - $) - # Add it to test execution - add_test( - NAME ${testName} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test - COMMAND ${testName} ) -endforeach(testSrc) - -# ### INTEGRATION TESTS -# file(GLOB INTEGRATION_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} integration_test/*.cpp) -# foreach(testSrc ${INTEGRATION_SRCS}) -# # Extract the filename without an extension (NAME_WE) -# get_filename_component(testName ${testSrc} NAME_WE) -# # Add compile target -# add_executable(${testName} ${testSrc}) -# # Require the standard -# target_compile_features(${testName} PRIVATE cxx_std_20) -# # Link to targets and dependencies -# target_link_libraries(${testName} quetzal::quetzal boost::boost GDAL::GDAL range-v3::range-v3) -# # Specifies include directories to use when compiling the target -# target_include_directories( -# ${testName} PRIVATE -# $ -# $) -# # Add it to test execution -# add_test( -# NAME ${testName} -# WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test -# COMMAND ${testName} ${CMAKE_CURRENT_SOURCE_DIR}/data/europe_temp.tif) -# endforeach(testSrc) +add_subdirectory(unit_test) +add_subdirectory(integration_test) \ No newline at end of file diff --git a/test/integration_test/CMakeLists.txt b/test/integration_test/CMakeLists.txt new file mode 100644 index 00000000..a7989900 --- /dev/null +++ b/test/integration_test/CMakeLists.txt @@ -0,0 +1,49 @@ +cmake_minimum_required(VERSION 3.19) + +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) + +message("Compiler Version: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") + +# Include Boost as an imported target: 1.73 important for compilation with gcc 10 and C++20 +find_package(Boost 1.79 REQUIRED COMPONENTS filesystem serialization) +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) # Find Boost headers only +ENDIF() + +# Global approach Gdal +find_package(LIBKML) +message(STATUS "LIBKML_FOUND: ${LIBKML_FOUND}") + +find_package(GDAL REQUIRED) + +# range-v3 +find_package(range-v3) + +# mp-units +find_package(mp-units CONFIG REQUIRED) + +# Copy the data required +file(COPY ${CMAKE_SOURCE_DIR}/test/data DESTINATION ${CMAKE_BINARY_DIR}/test) + +# ### INTEGRATION TESTS +file(GLOB INTEGRATION_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} integration_test/*.cpp) +foreach(testSrc ${INTEGRATION_SRCS}) + # Extract the filename without an extension (NAME_WE) + get_filename_component(testName ${testSrc} NAME_WE) + # Add compile target + add_executable(${testName} ${testSrc}) + # Require the standard + target_compile_features(${testName} PRIVATE cxx_std_20) + # Link to targets and dependencies + target_link_libraries(${testName} quetzal::quetzal boost::boost GDAL::GDAL range-v3::range-v3) + # Specifies include directories to use when compiling the target + target_include_directories( + ${testName} PRIVATE + $ + $) + # Add it to test executionx + add_test( + NAME ${testName} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test + COMMAND ${testName} ${CMAKE_CURRENT_SOURCE_DIR}/data/europe_temp.tif) +endforeach(testSrc) diff --git a/test/unit_test/CMakeLists.txt b/test/unit_test/CMakeLists.txt new file mode 100644 index 00000000..4911b8bc --- /dev/null +++ b/test/unit_test/CMakeLists.txt @@ -0,0 +1,63 @@ +cmake_minimum_required(VERSION 3.19) + +set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) + +message("Compiler Version: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") + +# Include Boost as an imported target: 1.73 important for compilation with gcc 10 and C++20 +find_package(Boost 1.79 REQUIRED COMPONENTS filesystem serialization) +if(Boost_FOUND) + include_directories(${Boost_INCLUDE_DIRS}) # Find Boost headers only +ENDIF() + +# Global approach Gdal +find_package(LIBKML) +message(STATUS "LIBKML_FOUND: ${LIBKML_FOUND}") + +find_package(GDAL REQUIRED) + +# range-v3 +find_package(range-v3) + +# mp-units +find_package(mp-units CONFIG REQUIRED) + +# Copy the data required +file(COPY ${PROJECT_SOURCE_DIR}/test/data DESTINATION ${CMAKE_BINARY_DIR}/test) + +### UNIT TEST +file(GLOB TEST_SRCS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} unit_test/*.cpp) +foreach(testSrc ${TEST_SRCS}) + # Extract the filename without an extension (NAME_WE) + get_filename_component(testName ${testSrc} NAME_WE) + # Add compile target + add_executable(${testName} ${testSrc}) + # Require the standard + target_compile_features(${testName} PRIVATE cxx_std_23) + # Ignore warnings about subtle ABI change + target_compile_options(${testName} PUBLIC "-Wno-psabi") + # Link to targets and dependencies + target_link_libraries(${testName} + PRIVATE + quetzal::quetzal + Boost::boost + GDAL::GDAL + range-v3::range-v3 + mp-units::mp-units + GTest::gtest + GTest::gtest_main + GTest::gmock + GTest::gmock_main + ) + + # Specifies include directories to use when compiling the target + target_include_directories( + ${testName} PRIVATE + $ + $) + # Add it to test execution + add_test( + NAME ${testName} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test + COMMAND ${testName} ) +endforeach(testSrc) \ No newline at end of file diff --git a/test/unit_test/FuzzyPartition_test.cpp b/test/unit_test/FuzzyPartition_test.cpp index 8a9cd795..bbb82d2d 100644 --- a/test/unit_test/FuzzyPartition_test.cpp +++ b/test/unit_test/FuzzyPartition_test.cpp @@ -6,37 +6,53 @@ * * ***************************************************************************/ -// g++ -o FuzzyPartition_test FuzzyPartition_test.cpp -std=c++14 -Wall +#include #include "quetzal/polymorphism/fuzzy_transfer_distance.hpp" -#include "assert.h" -#include -#include -#include -#include +using quetzal::polymorphism::fuzzy_transfer_distance::FuzzyPartition; +using quetzal::polymorphism::fuzzy_transfer_distance::RestrictedGrowthString; -int main() +TEST(FuzzyPartitionTest, construction) { - using quetzal::polymorphism::fuzzy_transfer_distance::FuzzyPartition; - using quetzal::polymorphism::fuzzy_transfer_distance::RestrictedGrowthString; - std::map> coeffs = { {0, {0.0, 0.1, 0.9, 0.0}}, {1, {0.4, 0.1, 0.2, 0.3}}, {2, {0.0, 0.3, 0.6, 0.1}}}; FuzzyPartition A(coeffs); - assert(A.elements() == std::set({0, 1, 2})); - assert(A.clusters() == std::set({0, 1, 2, 3})); - assert(A.nElements() == 3); - assert(A.nClusters() == 4); + EXPECT_EQ(A.elements(), std::set({0, 1, 2})); + EXPECT_EQ(A.clusters(), std::set({0, 1, 2, 3})); + EXPECT_EQ(A.nElements(), 3); + EXPECT_EQ(A.nClusters(), 4); +} + +TEST(FuzzyPartitionTest, merging_clusters) +{ + std::map> coeffs = { + {0, {0.0, 0.1, 0.9, 0.0}}, {1, {0.4, 0.1, 0.2, 0.3}}, {2, {0.0, 0.3, 0.6, 0.1}}}; - auto B = A; + FuzzyPartition A(coeffs); RestrictedGrowthString RGS({0, 0, 1, 2}); - B.merge_clusters(RGS); // merging cluster 1 and 2, summing membership coefficients - assert(B == FuzzyPartition({{0, {0.1, 0.9, 0.0}}, {1, {0.5, 0.2, 0.3}}, {2, {0.3, 0.6, 0.1}}})); + A.merge_clusters(RGS); // merging cluster 1 and 2, summing membership coefficients + EXPECT_EQ(A, FuzzyPartition({{0, {0.1, 0.9, 0.0}}, {1, {0.5, 0.2, 0.3}}, {2, {0.3, 0.6, 0.1}}})); +} + +TEST(FuzzyPartitionTest, fuzzy_transfer_distance) +{ + std::map> coeffs1 = { + {0, {0.0, 0.1, 0.9, 0.0}}, {1, {0.4, 0.1, 0.2, 0.3}}, {2, {0.0, 0.3, 0.6, 0.1}}}; + std::map> coeffs2 = { + {0, {0.1, 0.9, 0.0}}, {1, {0.5, 0.2, 0.3}}, {2, {0.3, 0.6, 0.1}}}; + + FuzzyPartition A(coeffs1); + FuzzyPartition B(coeffs2); double d = A.fuzzy_transfer_distance(B); - assert(d == 0.4); + EXPECT_DOUBLE_EQ(d, 0.4); +} - return 0; +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } + diff --git a/test/unit_test/Partitioner_test.cpp b/test/unit_test/Partitioner_test.cpp index 6510fcfc..7610b0d5 100644 --- a/test/unit_test/Partitioner_test.cpp +++ b/test/unit_test/Partitioner_test.cpp @@ -6,15 +6,15 @@ * * ***************************************************************************/ -// g++ -o Partitioner_test Partitioner_test.cpp -std=c++14 -Wall - -#include "quetzal/polymorphism/fuzzy_transfer_distance.hpp" +#include "gtest/gtest.h" #include "assert.h" #include #include -int main() +#include "quetzal/polymorphism/fuzzy_transfer_distance.hpp" + +TEST(PartitionerTest, construct_all_m_blocks_partitions_of_the_set_by_algorithm_u) { using quetzal::polymorphism::fuzzy_transfer_distance::Partitioner; using quetzal::polymorphism::fuzzy_transfer_distance::RestrictedGrowthString; @@ -24,11 +24,11 @@ int main() Partitioner partitioner(set); auto const &three_blocks_partitions = partitioner.construct_all_m_blocks_partitions_of_the_set_by_algorithm_u(3); - assert(three_blocks_partitions.size() == 25); + ASSERT_EQ(three_blocks_partitions.size(), 25); for (auto const &it : three_blocks_partitions) { - assert(it.size() == 5); + ASSERT_EQ(it.size(), 5); } // http://www.computing-wisdom.com/computingreadings/fasc3b.pdf : page 28, 7.2.1.5 @@ -45,7 +45,13 @@ int main() expected_three_blocks_partitions.emplace_back(it); } - assert(three_blocks_partitions == expected_three_blocks_partitions); + ASSERT_EQ(three_blocks_partitions, expected_three_blocks_partitions); +} + +TEST(PartitionerTest, construct_all_m_blocks_partitions_of_the_set_by_algorithm_u_set_size_4) +{ + using quetzal::polymorphism::fuzzy_transfer_distance::Partitioner; + using quetzal::polymorphism::fuzzy_transfer_distance::RestrictedGrowthString; std::vector other = {1, 2, 3, 4}; Partitioner partitioner2(other); @@ -58,19 +64,39 @@ int main() [0, 1, 2, 1] [0, 1, 2, 0] */ - assert(ps.size() == 6); + ASSERT_EQ(ps.size(), 6); +} - // Test cause of weird results... - Partitioner partitioner3(std::set({1, 2, 3, 4})); +TEST(PartitionerTest, construct_all_m_blocks_partitions_of_the_set_by_algorithm_u_set_size_4_sorted) +{ + using quetzal::polymorphism::fuzzy_transfer_distance::Partitioner; + using quetzal::polymorphism::fuzzy_transfer_distance::RestrictedGrowthString; + + std::set other = {1, 2, 3, 4}; + Partitioner partitioner3(other); auto all = partitioner3.construct_all_m_blocks_partitions_of_the_set_by_algorithm_u(3); - assert(all.size() == 6); + ASSERT_EQ(all.size(), 6); +} + +TEST(PartitionerTest, construct_all_m_blocks_partitions_of_the_set_by_algorithm_u_set_size_3) +{ + using quetzal::polymorphism::fuzzy_transfer_distance::Partitioner; + using quetzal::polymorphism::fuzzy_transfer_distance::RestrictedGrowthString; - // limit cases - Partitioner partitioner4(std::set({1, 2, 3})); + std::set other = {1, 2, 3}; + Partitioner partitioner4(other); auto all2 = partitioner4.construct_all_m_blocks_partitions_of_the_set_by_algorithm_u(3); - assert(all2.size() == 1); + ASSERT_EQ(all2.size(), 1); +} + +TEST(PartitionerTest, construct_all_m_blocks_partitions_of_the_set_by_algorithm_u_set_size_4_nb_blocks_4) +{ + using quetzal::polymorphism::fuzzy_transfer_distance::Partitioner; + using quetzal::polymorphism::fuzzy_transfer_distance::RestrictedGrowthString; - Partitioner partitioner5(std::set({1, 2, 3, 4})); + std::set other = {1, 2, 3, 4}; + Partitioner partitioner5(other); auto all3 = partitioner5.construct_all_m_blocks_partitions_of_the_set_by_algorithm_u(4); - assert(all3.size() == 1); + ASSERT_EQ(all3.size(), 1); } + diff --git a/test/unit_test/coalescence_test.cpp b/test/unit_test/coalescence_test.cpp index 68df1ab6..bccc95bd 100644 --- a/test/unit_test/coalescence_test.cpp +++ b/test/unit_test/coalescence_test.cpp @@ -1,21 +1,7 @@ -// Copyright 2021 Arnaud Becheler - -/*********************************************************************** * This program 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 2 of the License, or * (at your option) any later version. * - * * - ***************************************************************************/ - -#define BOOST_TEST_MODULE coalescence_test - -#include +#include #include -namespace utf = boost::unit_test; - -BOOST_AUTO_TEST_SUITE(coalescence_algorithms) - -BOOST_AUTO_TEST_CASE(binary_merge) +TEST(coalescence_algorithms, binary_merge) { using node_type = int; std::vector nodes = {1, 1, 1, 1}; @@ -30,7 +16,7 @@ BOOST_AUTO_TEST_CASE(binary_merge) std::copy(nodes.begin(), last, std::ostream_iterator(std::cout, " ")); } -BOOST_AUTO_TEST_CASE(simultaneous_multiple_merge) +TEST(coalescence_algorithms, simultaneous_multiple_merge) { using node_type = int; std::vector nodes = {1, 1, 1, 1, 1}; @@ -42,11 +28,7 @@ BOOST_AUTO_TEST_CASE(simultaneous_multiple_merge) std::copy(nodes.begin(), last, std::ostream_iterator(std::cout, " ")); } -BOOST_AUTO_TEST_SUITE_END() - -BOOST_AUTO_TEST_SUITE(coalescence_containers) - -BOOST_AUTO_TEST_CASE(forest) +TEST(coalescence_containers, forest) { using position_type = int; using tree_type = std::string; @@ -76,7 +58,7 @@ BOOST_AUTO_TEST_CASE(forest) print(forest); } -BOOST_AUTO_TEST_CASE(forest_init) +TEST(coalescence_containers, forest_init) { using position_type = int; using tree_type = int; @@ -95,7 +77,7 @@ BOOST_AUTO_TEST_CASE(forest_init) d = std::move(c); } -BOOST_AUTO_TEST_CASE(forest_insert) +TEST(coalescence_containers, forest_insert) { // \remark These are very basic types sufficient for testing, but have little to see with coalescence. using position_type = int; @@ -110,16 +92,16 @@ BOOST_AUTO_TEST_CASE(forest_insert) std::vector v{"quercus_robur", "salix_nigra"}; forest.insert(3, std::move(v)); auto it = forest.insert(4, string("salix_nigra")); - BOOST_CHECK_EQUAL(it->first, 4); - BOOST_CHECK_EQUAL(forest.nb_trees(), 6); - BOOST_CHECK_EQUAL(forest.nb_trees(3), 2); + EXPECT_EQ(it->first, 4); + EXPECT_EQ(forest.nb_trees(), 6); + EXPECT_EQ(forest.nb_trees(3), 2); for (auto const &it : forest) { std::cout << "Position " << it.first << " : " << it.second << std::endl; } } -BOOST_AUTO_TEST_CASE(tree_init) +TEST(coalescence_containers, tree_init) { using quetzal::coalescence::container::Tree; using std::string; @@ -138,7 +120,7 @@ BOOST_AUTO_TEST_CASE(tree_init) Tree e(std::move(cell)); // cell should not be used anymore ! } -BOOST_AUTO_TEST_CASE(tree_DFS) +TEST(coalescence_containers, tree_DFS) { using quetzal::coalescence::container::Tree; using std::string; @@ -161,10 +143,10 @@ BOOST_AUTO_TEST_CASE(tree_DFS) std::vector v; auto f = [&v](string s) { v.push_back(s); }; root.visit_leaves_cells_by_DFS(f); - BOOST_TEST(v == expected); + EXPECT_EQ(v, expected); } -BOOST_AUTO_TEST_CASE(tree_preorder_DFS) +TEST(coalescence_containers, tree_preorder_DFS) { using quetzal::coalescence::container::Tree; using std::string; @@ -186,7 +168,6 @@ BOOST_AUTO_TEST_CASE(tree_preorder_DFS) std::vector v; auto f = [&v](string s) { v.push_back(s); }; root.visit_cells_by_pre_order_DFS(f); - BOOST_TEST(v == expected); + EXPECT_EQ(v, expected); } -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_test/demography_test.cpp b/test/unit_test/demography_test.cpp index 3e40e5dc..b174a6e2 100644 --- a/test/unit_test/demography_test.cpp +++ b/test/unit_test/demography_test.cpp @@ -5,11 +5,7 @@ *Software Foundation; either version 2 of the License, or * (at your option) any later version. * * * ***************************************************************************/ -#define BOOST_TEST_MODULE demography_test - -#include -namespace utf = boost::unit_test; - +#include #include struct transition_matrix @@ -25,11 +21,7 @@ struct transition_matrix } }; -BOOST_AUTO_TEST_SUITE(demography) - -// Allows for arbitrary coordinate type and arbitrary origin date. -// Does not require to reserve all the necessary space before hand. -BOOST_AUTO_TEST_CASE(population_size_default) +TEST(population_size_default, test_population_size_default) { // Data types declaration using coord_type = std::string; @@ -41,15 +33,15 @@ BOOST_AUTO_TEST_CASE(population_size_default) size_type N0 = 12; quetzal::demography::PopulationSizeHashMapImplementation N; - BOOST_TEST(!N.is_defined(x0, t0)); + EXPECT_FALSE(N.is_defined(x0, t0)); // Set first population size N.set(x0, t0, N0); - BOOST_TEST(N.is_defined(x0, t0)); - BOOST_CHECK_EQUAL(N.get(x0, t0), N0); - BOOST_CHECK_EQUAL(N.definition_space(t0).size(), 1); + EXPECT_TRUE(N.is_defined(x0, t0)); + EXPECT_EQ(N.get(x0, t0), N0); + EXPECT_EQ(N.definition_space(t0).size(), 1); // Set second population time N.set("B", t0, 2 * N0); - BOOST_CHECK_EQUAL(N.definition_space(t0).size(), 2); + EXPECT_EQ(N.definition_space(t0).size(), 2); // Retrieve definition space (demes with population size > 0) auto X = N.definition_space(t0); std::cout << "Distribution area at time t0: {"; @@ -57,7 +49,7 @@ BOOST_AUTO_TEST_CASE(population_size_default) std::cout << "}\n" << std::endl; } -BOOST_AUTO_TEST_CASE(population_size_on_disk) +TEST(population_size_on_disk, test_population_size_on_disk) { // Data types declaration using coord_type = std::string; @@ -69,20 +61,20 @@ BOOST_AUTO_TEST_CASE(population_size_on_disk) size_type N0 = 12; quetzal::demography::PopulationSizeOnDiskImplementation N; - BOOST_TEST(!N.is_defined(x0, t0)); + EXPECT_FALSE(N.is_defined(x0, t0)); // Set first population size N.set(x0, t0, N0); - BOOST_TEST(N.is_defined(x0, t0)); - BOOST_CHECK_EQUAL(N.get(x0, t0), N0); - BOOST_CHECK_EQUAL(N.definition_space(t0).size(), 1); + EXPECT_TRUE(N.is_defined(x0, t0)); + EXPECT_EQ(N.get(x0, t0), N0); + EXPECT_EQ(N.definition_space(t0).size(), 1); // Set second population time N.set("B", t0, 2 * N0); - BOOST_CHECK_EQUAL(N.definition_space(t0).size(), 2); + EXPECT_EQ(N.definition_space(t0).size(), 2); // Retrieve definition space (demes with population size > 0) auto X = N.definition_space(t0); } -BOOST_AUTO_TEST_CASE(population_size_on_disk_moving_windows) +TEST(population_size_on_disk_moving_windows, test_population_size_on_disk_moving_windows) { // Data types declaration using coord_type = int; @@ -94,25 +86,25 @@ BOOST_AUTO_TEST_CASE(population_size_on_disk_moving_windows) size_type N0 = 1; quetzal::demography::PopulationSizeOnDiskImplementation N; - BOOST_TEST(!N.is_defined(x0, t0)); + EXPECT_FALSE(N.is_defined(x0, t0)); // Set first population size N.set(x0, t0, N0); - BOOST_TEST(N.is_defined(x0, t0)); - BOOST_CHECK_EQUAL(N.get(x0, t0), N0); - BOOST_CHECK_EQUAL(N.definition_space(t0).size(), 1); + EXPECT_TRUE(N.is_defined(x0, t0)); + EXPECT_EQ(N.get(x0, t0), N0); + EXPECT_EQ(N.definition_space(t0).size(), 1); // Set other population sizes for (unsigned int i = 1; i <= 10; ++i) { N.set(i, i, 2 * N.get(i - 1, i - 1)); } - BOOST_CHECK_EQUAL(N.definition_space(10).size(), 1); - BOOST_CHECK_EQUAL(N.get(10, 10), 1024); - BOOST_CHECK_EQUAL(N.get(1, 1), 2); - BOOST_CHECK_EQUAL(N.get(0, 0), 1); - BOOST_CHECK_EQUAL(N.get(5, 5), 32); + EXPECT_EQ(N.definition_space(10).size(), 1); + EXPECT_EQ(N.get(10, 10), 1024); + EXPECT_EQ(N.get(1, 1), 2); + EXPECT_EQ(N.get(0, 0), 1); + EXPECT_EQ(N.get(5, 5), 32); } -BOOST_AUTO_TEST_CASE(flow) +TEST(flow, test_flow) { using coord_type = std::string; using time_type = unsigned int; @@ -124,12 +116,12 @@ BOOST_AUTO_TEST_CASE(flow) quetzal::demography::FlowHashMapImplementation Phi; - BOOST_TEST(!Phi.flow_to_is_defined(i, t)); + EXPECT_FALSE(Phi.flow_to_is_defined(i, t)); Phi.set_flow_from_to(i, j, t, 12); Phi.add_to_flow_from_to(j, j, t, 1); - BOOST_TEST(Phi.flow_to_is_defined(j, t)); - BOOST_TEST(Phi.flow_from_to(i, j, t) == 12); - BOOST_TEST(Phi.flow_from_to(j, j, t) == 1); + EXPECT_TRUE(Phi.flow_to_is_defined(j, t)); + EXPECT_EQ(Phi.flow_from_to(i, j, t), 12); + EXPECT_EQ(Phi.flow_from_to(j, j, t), 1); std::cout << "Flows converging to " << j << " at time t=" << t << ":" << std::endl; for (auto const &it : Phi.flow_to(j, t)) @@ -138,7 +130,7 @@ BOOST_AUTO_TEST_CASE(flow) } } -BOOST_AUTO_TEST_CASE(flow_on_disk_implementation) +TEST(flow_on_disk_implementation, test_flow_on_disk_implementation) { using coord_type = std::string; using time_type = unsigned int; @@ -150,12 +142,12 @@ BOOST_AUTO_TEST_CASE(flow_on_disk_implementation) quetzal::demography::FlowOnDiskImplementation Phi; - BOOST_TEST(!Phi.flow_to_is_defined(i, t)); + EXPECT_FALSE(Phi.flow_to_is_defined(i, t)); Phi.set_flow_from_to(i, j, t, 12); Phi.add_to_flow_from_to(j, j, t, 1); - BOOST_TEST(Phi.flow_to_is_defined(j, t)); - BOOST_TEST(Phi.flow_from_to(i, j, t) == 12); - BOOST_TEST(Phi.flow_from_to(j, j, t) == 1); + EXPECT_TRUE(Phi.flow_to_is_defined(j, t)); + EXPECT_EQ(Phi.flow_from_to(i, j, t), 12); + EXPECT_EQ(Phi.flow_from_to(j, j, t), 1); std::cout << "Flows converging to " << j << " at time t=" << t << ":" << std::endl; for (auto const &it : Phi.flow_to(j, t)) @@ -164,7 +156,7 @@ BOOST_AUTO_TEST_CASE(flow_on_disk_implementation) } } -BOOST_AUTO_TEST_CASE(flow_on_disk_implementation_moving_windows) +TEST(flow_on_disk_implementation_moving_windows, test_flow_on_disk_implementation_moving_windows) { std::cout << "here" << std::endl; using coord_type = unsigned int; @@ -184,19 +176,19 @@ BOOST_AUTO_TEST_CASE(flow_on_disk_implementation_moving_windows) } } - BOOST_TEST(Phi.flow_to_is_defined(5, 5)); - BOOST_TEST(Phi.flow_from_to(5, 5, 5) == 15); - BOOST_TEST(Phi.flow_from_to(2, 4, 5) == 11); - BOOST_TEST(Phi.flow_from_to(0, 0, 4) == 4); - BOOST_TEST(Phi.flow_from_to(0, 0, 3) == 3); - BOOST_TEST(Phi.flow_from_to(0, 0, 2) == 2); - BOOST_TEST(Phi.flow_from_to(0, 0, 1) == 1); - BOOST_TEST(Phi.flow_from_to(0, 0, 0) == 0); - BOOST_TEST(Phi.flow_from_to(1, 2, 5) == 8); - BOOST_TEST(Phi.flow_from_to(0, 0, 0) == 0); + EXPECT_TRUE(Phi.flow_to_is_defined(5, 5)); + EXPECT_EQ(Phi.flow_from_to(5, 5, 5), 15); + EXPECT_EQ(Phi.flow_from_to(2, 4, 5), 11); + EXPECT_EQ(Phi.flow_from_to(0, 0, 4), 4); + EXPECT_EQ(Phi.flow_from_to(0, 0, 3), 3); + EXPECT_EQ(Phi.flow_from_to(0, 0, 2), 2); + EXPECT_EQ(Phi.flow_from_to(0, 0, 1), 1); + EXPECT_EQ(Phi.flow_from_to(0, 0, 0), 0); + EXPECT_EQ(Phi.flow_from_to(1, 2, 5), 8); + EXPECT_EQ(Phi.flow_from_to(0, 0, 0), 0); } -BOOST_AUTO_TEST_CASE(individual_based_history_default_storage) +TEST(individual_based_history_default_storage, test_individual_based_history_default_storage) { //! [individual_based_history_default_storage example] // Here we simulate a population oscillation between 2 demes: -1 and 1 @@ -210,27 +202,4 @@ BOOST_AUTO_TEST_CASE(individual_based_history_default_storage) // Declare an individual-based history where each gene copy is dispersed independently using quetzal::demography::demographic_policy::individual_based; // Declare memory should be allocated only on demand: ideal for very short histories - using quetzal::demography::memory_policy::on_RAM; - // 10 individuals introduced at x=1, t=0 - quetzal::demography::History history(x_0, N_0, nb_generations); - // Declare a growth function - auto N = history.get_functor_N(); // light copiable for capture - auto growth = [N](auto &gen, coord_type x, auto t) { return 2 * N(x, t); }; - // Dispersal kernel, samples arrival location in {-1,1} - auto sample_location = [](auto &gen, coord_type x) { - std::bernoulli_distribution d(0.5); - if (d(gen)) - { - x = -x; - } - return x; - }; - // Expand the history - history.simulate_forward(growth, sample_location, gen); - // Print the migration history - std::cout << "\nKnowing an indiviual was in deme 1 at t=2, simulate its location at time t=1?\n"; - std::cout << "Location at time 1: " << history.backward_kernel(1, 2, gen) << std::endl; - //! [individual_based_history_default_storage example] -} -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_test/expressive_test.cpp b/test/unit_test/expressive_test.cpp index 5979a787..c2f2f396 100644 --- a/test/unit_test/expressive_test.cpp +++ b/test/unit_test/expressive_test.cpp @@ -5,41 +5,38 @@ *Software Foundation; either version 2 of the License, or * (at your option) any later version. * * * ***************************************************************************/ -#define BOOST_TEST_MODULE expressive_test - -#include -namespace utf = boost::unit_test; +#include #include -BOOST_AUTO_TEST_SUITE(expressive) +using namespace quetzal::expressive; -BOOST_AUTO_TEST_CASE(using_lambdas_and_literals) +TEST(Expressive, UsingLambdasAndLiterals) { using quetzal::expressive::use; + using quetzal::expressive::literal_factory; - quetzal::expressive::literal_factory lit; + literal_factory lit; auto g = lit(5); auto f = [](int a, int b) { return a + b; }; auto h = use(f) + g; - assert(h(2, 3) == 10); - - BOOST_CHECK_EQUAL(h(2, 3), 10); + EXPECT_EQ(h(2, 3), 10); } -BOOST_AUTO_TEST_CASE(composing_functors) +TEST(Expressive, ComposingFunctors) { using quetzal::expressive::use; + using quetzal::expressive::compose; // NxN -> N -> string auto inner = use([](int a, int b) { return a + b; }); auto outer = use([](int) { return "c"; }); - auto composed = quetzal::expressive::compose(outer, inner); + auto composed = compose(outer, inner); - BOOST_CHECK_EQUAL(composed(1, 2), "c"); + EXPECT_EQ(composed(1, 2), "c"); } -BOOST_AUTO_TEST_SUITE_END() + diff --git a/test/unit_test/geography_graph_test.cpp b/test/unit_test/geography_graph_test.cpp index a44a767f..d709f786 100644 --- a/test/unit_test/geography_graph_test.cpp +++ b/test/unit_test/geography_graph_test.cpp @@ -6,8 +6,7 @@ * * ***************************************************************************/ -#define BOOST_TEST_MODULE geography_test -#include +#include #include @@ -16,9 +15,7 @@ namespace geo = quetzal::geography; -BOOST_AUTO_TEST_SUITE(geography_graph) - -BOOST_AUTO_TEST_CASE(expected_number_edges) +TEST(geography_graph, expected_number_edges) { auto file1 = std::filesystem::current_path() / "data/bio1.tif"; auto file2 = std::filesystem::current_path() / "data/bio12.tif"; @@ -53,46 +50,43 @@ BOOST_AUTO_TEST_CASE(expected_number_edges) int n1 = graph1.num_vertices(); int e1 = n1 * ( n1 - 1 ) / 2 ; // typical undirected complete graph - BOOST_CHECK_EQUAL( n1 , land.num_locations() ); - BOOST_CHECK_EQUAL( e1 , graph1.num_edges() ); + EXPECT_EQ( n1 , land.num_locations() ); + EXPECT_EQ( e1 , graph1.num_edges() ); int n2 = graph2.num_vertices(); int e2 = e1 + 2 * ( w + h - 2 ) ; // border vertices connected to the outland - a sink vertex - BOOST_CHECK_EQUAL( n2 , n1 + 1 ); // sink vertex added - BOOST_CHECK_EQUAL( e2 , graph2.num_edges() ); + EXPECT_EQ( n2 , n1 + 1 ); // sink vertex added + EXPECT_EQ( e2 , graph2.num_edges() ); int n3 = graph3.num_vertices(); int e3 = 2 * e1 + 2 * ( w + h - 2 ); // number of land edges are doubled with anisotropy - BOOST_CHECK_EQUAL( n3 , n2 ); // sink vertex added - BOOST_CHECK_EQUAL( e3 , graph3.num_edges() ); + EXPECT_EQ( n3 , n2 ); // sink vertex added + EXPECT_EQ( e3 , graph3.num_edges() ); int n4 = graph4.num_vertices(); int e4 = h * ( w - 1 ) // horizontal edges + w * ( h - 1 ) // vertical edges + h // torus joining West to East + w - 2 ; // torus joining North to South - BOOST_CHECK_EQUAL( n4 , n1 ); // no vertex added - BOOST_CHECK_EQUAL( e4 , graph4.num_edges() ); + EXPECT_EQ( n4 , n1 ); // no vertex added + EXPECT_EQ( e4 , graph4.num_edges() ); int n5 = graph5.num_vertices(); int e5 = h * ( w - 1 ) // horizontal edges + w * ( h - 1 ) // vertical edges + 2 * ( w - 1 ) * ( h - 1 ) ; // intercardinal for internal vertices only - BOOST_CHECK_EQUAL( n5 , n1 ); // no vertex added - BOOST_CHECK_EQUAL( e5 , graph5.num_edges() ); + EXPECT_EQ( n5 , n1 ); // no vertex added + EXPECT_EQ( e5 , graph5.num_edges() ); int n6 = graph6.num_vertices(); int e6 = 2* e5; - BOOST_CHECK_EQUAL( n5 , n1 ); // no vertex added - BOOST_CHECK_EQUAL( e6 , graph6.num_edges() ); + EXPECT_EQ( n5 , n1 ); // no vertex added + EXPECT_EQ( e6 , graph6.num_edges() ); int n7 = graph7.num_vertices(); int e7 = 2 * e5 + 2 * (w + h - 2); - std::cout << n7 << " " << e7 << " " << graph7.num_edges() << std::endl; - - BOOST_CHECK_EQUAL( n7 , n1 ); // no vertex added - BOOST_CHECK_EQUAL( e7 , graph7.num_edges() ); + EXPECT_EQ( n7 , n1 ); // no vertex added + EXPECT_EQ( e7 , graph7.num_edges() ); } -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_test/geography_test.cpp b/test/unit_test/geography_test.cpp index 6fc83eb6..e888ef54 100644 --- a/test/unit_test/geography_test.cpp +++ b/test/unit_test/geography_test.cpp @@ -1,13 +1,4 @@ -// Copyright 2018 Arnaud Becheler - -/*********************************************************************** * This program 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 2 of the License, or * (at your option) any later version. * - * * - ***************************************************************************/ - -#define BOOST_TEST_MODULE geography_test -#include +#include #include @@ -15,11 +6,9 @@ #include #include -namespace utf = boost::unit_test; - -BOOST_AUTO_TEST_SUITE(geography) +namespace utf = ::testing; -BOOST_AUTO_TEST_CASE(gdalcppTest) +TEST(GeographyTest, gdalcppTest) { auto file = std::filesystem::current_path() / "data/bio1.tif"; @@ -35,20 +24,20 @@ BOOST_AUTO_TEST_CASE(gdalcppTest) auto v = data.affine_transformation_coefficients(); } -BOOST_AUTO_TEST_CASE(resolution) +TEST(GeographyTest, resolution) { using decimal_degree = double; decimal_degree lat_resolution = 2.0; decimal_degree lon_resolution = 1.0; quetzal::geography::resolution res(lat_resolution, lon_resolution); - BOOST_TEST(res.lat() == lat_resolution); - BOOST_TEST(res.lon() == lon_resolution); + EXPECT_EQ(res.lat(), lat_resolution); + EXPECT_EQ(res.lon(), lon_resolution); auto copy = res; copy.lon(2.0); - assert(copy != res); + EXPECT_NE(copy, res); } -BOOST_AUTO_TEST_CASE(coordinates) +TEST(GeographyTest, coordinates) { using namespace mp_units; using namespace mp_units::si::unit_symbols; @@ -56,16 +45,16 @@ BOOST_AUTO_TEST_CASE(coordinates) coord_type paris(48.856614, 2.3522219000000177); coord_type moscow(55.7522200, 37.6155600); bool b = paris < moscow; - BOOST_TEST(b); + EXPECT_TRUE(b); auto computed = paris.great_circle_distance_to(moscow); auto expected = 2486.22 * km ; auto EPSILON = 1.0 * km; // a 1-km error is acceptable. auto diff = expected - computed; - BOOST_TEST(diff < EPSILON); - BOOST_TEST(-diff < EPSILON); + EXPECT_LT(diff, EPSILON); + EXPECT_LT(-diff, EPSILON); } -BOOST_AUTO_TEST_CASE(extent) +TEST(GeographyTest, extent) { using decimal_degree = double; using extent_type = quetzal::geography::extent; @@ -74,16 +63,16 @@ BOOST_AUTO_TEST_CASE(extent) decimal_degree moscow_lat = 55.7522; decimal_degree moscow_lon = 37.6155; extent_type extent(paris_lat, moscow_lat, paris_lon, moscow_lon); - BOOST_CHECK_EQUAL(extent.lat_min(), paris_lat); - BOOST_CHECK_EQUAL(extent.lat_max(), moscow_lat); - BOOST_CHECK_EQUAL(extent.lon_min(), paris_lon); - BOOST_CHECK_EQUAL(extent.lon_max(), moscow_lon); + EXPECT_EQ(extent.lat_min(), paris_lat); + EXPECT_EQ(extent.lat_max(), moscow_lat); + EXPECT_EQ(extent.lon_min(), paris_lon); + EXPECT_EQ(extent.lon_max(), moscow_lon); auto copy = extent; copy.lat_min(0.0); - assert(copy != extent); + EXPECT_NE(copy, extent); } -BOOST_AUTO_TEST_CASE(raster) +TEST(GeographyTest, raster) { using time_type = unsigned int; using raster_type = quetzal::geography::raster; @@ -93,14 +82,14 @@ BOOST_AUTO_TEST_CASE(raster) auto bio1 = raster_type::from_file(file, {2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010}); - BOOST_CHECK_EQUAL(bio1.times().size(), 10); - BOOST_CHECK_EQUAL(bio1.locations().size(), 9); - BOOST_CHECK_EQUAL(bio1.origin(), raster_type::latlon(52., -5.)); + EXPECT_EQ(bio1.times().size(), 10); + EXPECT_EQ(bio1.locations().size(), 9); + EXPECT_EQ(bio1.origin(), raster_type::latlon(52., -5.)); auto f = bio1.to_view(); auto x = bio1.to_descriptor( bio1.origin() ); auto t = bio1.times().front(); - // BOOST_TEST( f( x, t ).has_value() ); + // EXPECT_TRUE( f( x, t ).has_value() ); auto space = bio1.locations() | ranges::views::transform([&](auto i) { return bio1.to_latlon(i); }) | @@ -153,8 +142,8 @@ BOOST_AUTO_TEST_CASE(raster) // Corners latlon expected_top_left(52., -5.); latlon expected_bottom_right(37., 10.); - BOOST_TEST(bio1.contains(expected_top_left)); - BOOST_TEST(!bio1.contains(expected_bottom_right)); + EXPECT_TRUE(bio1.contains(expected_top_left)); + EXPECT_FALSE(bio1.contains(expected_bottom_right)); // In boxes latlon in_box_0(51., -4.5); @@ -174,24 +163,24 @@ BOOST_AUTO_TEST_CASE(raster) latlon E_c2_c5_limit(47., 10.); // In boxes - BOOST_TEST(bio1.to_centroid(in_box_0) == c0); - BOOST_TEST(bio1.to_centroid(in_box_1) == c1); - BOOST_TEST(bio1.to_centroid(in_box_6) == c6); - BOOST_TEST(bio1.to_centroid(in_box_8) == c8); + EXPECT_EQ(bio1.to_centroid(in_box_0), c0); + EXPECT_EQ(bio1.to_centroid(in_box_1), c1); + EXPECT_EQ(bio1.to_centroid(in_box_6), c6); + EXPECT_EQ(bio1.to_centroid(in_box_8), c8); // At boxes limits - BOOST_TEST(bio1.to_centroid(W_c0_limit) == c0); - BOOST_TEST(bio1.to_centroid(N_c0_limit) == c0); - BOOST_TEST(bio1.to_centroid(c0_c3_limit) == c3); - BOOST_TEST(bio1.to_centroid(W_c0_c3_limit) == c3); - BOOST_TEST(bio1.to_centroid(c0_c1_c3_c4_limit) == c4); + EXPECT_EQ(bio1.to_centroid(W_c0_limit), c0); + EXPECT_EQ(bio1.to_centroid(N_c0_limit), c0); + EXPECT_EQ(bio1.to_centroid(c0_c3_limit), c3); + EXPECT_EQ(bio1.to_centroid(W_c0_c3_limit), c3); + EXPECT_EQ(bio1.to_centroid(c0_c1_c3_c4_limit), c4); // Out of all boxes // bio1.to_centroid(out_north); // assertion raised // bio1.to_centroid(E_c2_c5_limit); // assertion raised } -BOOST_AUTO_TEST_CASE(landscape) +TEST(GeographyTest, landscape) { using time_type = int; using landscape_type = quetzal::geography::landscape; @@ -205,33 +194,22 @@ BOOST_AUTO_TEST_CASE(landscape) auto env = landscape_type::from_file({{"bio1", file1}, {"bio12", file2}}, {2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010}); - BOOST_CHECK_EQUAL(env.num_variables(), 2); + EXPECT_EQ(env.num_variables(), 2); landscape_type::latlon Bordeaux(44.5, 0.34); - BOOST_TEST(env.contains(Bordeaux)); - BOOST_TEST(env.contains(env.to_centroid(Bordeaux))); + EXPECT_TRUE(env.contains(Bordeaux)); + EXPECT_TRUE(env.contains(env.to_centroid(Bordeaux))); const auto &f = env["bio1"].to_view(); const auto &g = env["bio12"].to_view(); - BOOST_CHECK_EQUAL(env.times().size(), 10); - BOOST_TEST(env.locations().size() < 100); + EXPECT_EQ(env.times().size(), 10); + EXPECT_LT(env.locations().size(), 100); for (auto t : env.times()) { for (auto x : env.locations()) { - f(x, t).has_value(); - // g(x, t).has_value(); - } - } - } - - catch (const std::exception &ex) - { - BOOST_ERROR(ex.what()); - } -} + EXPECT_TRUE(f(x, t).has_value()); -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_test/merger_test.cpp b/test/unit_test/merger_test.cpp index dba3c119..30351729 100644 --- a/test/unit_test/merger_test.cpp +++ b/test/unit_test/merger_test.cpp @@ -5,17 +5,13 @@ *Software Foundation; either version 2 of the License, or * (at your option) any later version. * * * ***************************************************************************/ -#define BOOST_TEST_MODULE merger_test -#include -namespace utf = boost::unit_test; +#include #include #include -BOOST_AUTO_TEST_SUITE(mergers) - -BOOST_AUTO_TEST_CASE(binary_merger_with_strings) +TEST(BinaryMerger, WithStrings) { // will produce binary trees using quetzal::coalescence::merger_policy::BinaryMerger; @@ -38,10 +34,10 @@ BOOST_AUTO_TEST_CASE(binary_merger_with_strings) // print the remaining lineages std::copy(nodes.begin(), last, std::ostream_iterator(std::cout, "\t")); std::cout << std::endl; - BOOST_CHECK_EQUAL(std::distance(nodes.begin(), last), total_number_of_tips - 1); + ASSERT_EQ(std::distance(nodes.begin(), last), total_number_of_tips - 1); } -BOOST_AUTO_TEST_CASE(simultaneous_multiple_merger_on_the_fly_number_of_tips) +TEST(SimultaneousMultipleMerger, OnTheFlyNumberOfTips) { // nodes data are integers counting the number of tips of the subtrees using node_type = int; @@ -66,10 +62,10 @@ BOOST_AUTO_TEST_CASE(simultaneous_multiple_merger_on_the_fly_number_of_tips) std::cout << std::endl; last = SMM::merge(nodes.begin(), last, N, gen); } - BOOST_CHECK_EQUAL(*first, total_number_of_tips); + ASSERT_EQ(*first, total_number_of_tips); } -BOOST_AUTO_TEST_CASE(simultaneous_multiple_merger_on_the_fly_with_strings) +TEST(SimultaneousMultipleMerger, OnTheFlyWithStrings) { // let's play with strings as node data using node_type = std::string; @@ -99,4 +95,9 @@ BOOST_AUTO_TEST_CASE(simultaneous_multiple_merger_on_the_fly_with_strings) } } -BOOST_AUTO_TEST_SUITE_END() +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/test/unit_test/newick_extended_parser_test.cpp b/test/unit_test/newick_extended_parser_test.cpp index 6762f4a1..1f0cca58 100644 --- a/test/unit_test/newick_extended_parser_test.cpp +++ b/test/unit_test/newick_extended_parser_test.cpp @@ -1,125 +1,121 @@ -// Copyright 2021 Arnaud Becheler - -/*********************************************************************** * This program 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 2 of the License, or * (at your option) any later version. * - * * - ***************************************************************************/ - -#define BOOST_TEST_MODULE newick_parser_test - -#include -namespace utf = boost::unit_test; +#include #include "quetzal/io/newick/extended/to_network.hpp" -#include +#include namespace x3 = boost::spirit::x3; -struct FixtureCases +class FixtureCases : public ::testing::Test { - // Set up fixture - FixtureCases() +protected: + void SetUp() override { - BOOST_TEST_MESSAGE("setup fixture Newick cases"); + name_cases = {"a34", "A856BC", "k56aH"}; - this->name_cases = {"a34", "A856BC", "k56aH"}; + length_cases = {":1", ":999", ":0.001"}; - this->length_cases = {":1", ":999", ":0.001"}; + leaf_cases = {"", "A", "B897kj"}; - this->leaf_cases = {"", "A", "B897kj"}; - - this->branch_cases = { + branch_cases = { "leaf", "(in,ternal)", "leaf:10.0", "(in,ternal):50.0", }; - this->internal_cases = {"(,)", "(A,B)F", "(A:10,B:10)F"}; - - this->subtree_cases = {"leaf", - "(in,ternal)", - "(,,(,))", - "(A,B,(C,D))", - "(A,B,(C,D)E)F", - "(:0.1,:0.2,(:0.3,:0.4):0.5)", - "(:0.1,:0.2,(:0.3,:0.4):0.5)", - "(A:0.1,B:0.2,(C:0.3,D:0.4):0.5)", - "(A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F", - "((B:0.2,(C:0.3,D:0.4)E:0.5)F:0.1)A"}; - - this->tree_standard_cases = {";", - "(,);", - "(,,(,));", - "(A,B,(C,D));", - "(A,B,(C,D)E)F;", - "(:0.1,:0.2,(:0.3,:0.4):0.5);", - "(:0.1,:0.2,(:0.3,:0.4):0.5):0.0;", - "(A:0.1,B:0.2,(C:0.3,D:0.4):0.5);", - "(A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F;", - "((B:0.2,(C:0.3,D:0.4)E:0.5)F:0.1)A;"}; - - this->network_cases = {"((1, ((2, (3, (4)Y#H1)g)e, (((Y#H1, 5)h, 6)f)X#H2)c)a, ((X#H2, 7)d, 8)b)r;", - "(A,B,((C,(Y)x#H1)c,(x#H1,D)d)e)f"}; - } - - // Tear down fixture - ~FixtureCases() - { - BOOST_TEST_MESSAGE("teardown fixture Newick cases"); + internal_cases = {"(,)", "(A,B)F", "(A:10,B:10)F"}; + + subtree_cases = {"leaf", + "(in,ternal)", + "(,,(,))", + "(A,B,(C,D))", + "(A,B,(C,D)E)F", + "(:0.1,:0.2,(:0.3,:0.4):0.5)", + "(:0.1,:0.2,(:0.3,:0.4):0.5)", + "(A:0.1,B:0.2,(C:0.3,D:0.4):0.5)", + "(A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F", + "((B:0.2,(C:0.3,D:0.4)E:0.5)F:0.1)A"}; + + tree_standard_cases = {";", + "(,);", + "(,,(,));", + "(A,B,(C,D));", + "(A,B,(C,D)E)F;", + "(:0.1,:0.2,(:0.3,:0.4):0.5);", + "(:0.1,:0.2,(:0.3,:0.4):0.5):0.0;", + "(A:0.1,B:0.2,(C:0.3,D:0.4):0.5);", + "(A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F;", + "((B:0.2,(C:0.3,D:0.4)E:0.5)F:0.1)A;"}; + + network_cases = {"((1, ((2, (3, (4)Y#H1)g)e, (((Y#H1, 5)h, 6)f)X#H2)c)a, ((X#H2, 7)d, 8)b)r;", + "(A,B,((C,(Y)x#H1)c,(x#H1,D)d)e)f"}; } - // Member data of fixture - std::vector name_cases; - std::vector length_cases; - std::vector leaf_cases; - std::vector branch_cases; - std::vector internal_cases; - std::vector subtree_cases; - std::vector tree_standard_cases; - std::vector network_cases; + void TearDown() override {} -}; // end FixtureHomozygoteParents + std::vector name_cases; + std::vector length_cases; + std::vector leaf_cases; + std::vector branch_cases; + std::vector internal_cases; + std::vector subtree_cases; + std::vector tree_standard_cases; + std::vector network_cases; +}; -// Generic test function -auto test(const auto &cases, auto parser) +TEST_F(FixtureCases, name_grammar) { - for (const auto &input : cases) + for (const auto &input : name_cases) { auto iter = input.begin(); auto iter_end = input.end(); - bool r = x3::parse(iter, iter_end, parser); - BOOST_CHECK(r && iter == iter_end); + bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::name); + EXPECT_TRUE(r && iter == iter_end); } } -BOOST_AUTO_TEST_SUITE(newick_parser) - -BOOST_FIXTURE_TEST_CASE(name_grammar, FixtureCases) -{ - test(name_cases, quetzal::format::newick::parser::name); -} - -BOOST_FIXTURE_TEST_CASE(length_grammar, FixtureCases) +TEST_F(FixtureCases, length_grammar) { - test(length_cases, quetzal::format::newick::parser::length); + for (const auto &input : length_cases) + { + auto iter = input.begin(); + auto iter_end = input.end(); + bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::length); + EXPECT_TRUE(r && iter == iter_end); + } } -BOOST_FIXTURE_TEST_CASE(leaf_grammar, FixtureCases) +TEST_F(FixtureCases, leaf_grammar) { - test(leaf_cases, quetzal::format::newick::parser::leaf); + for (const auto &input : leaf_cases) + { + auto iter = input.begin(); + auto iter_end = input.end(); + bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::leaf); + EXPECT_TRUE(r && iter == iter_end); + } } -BOOST_FIXTURE_TEST_CASE(tree_standard_grammar, FixtureCases) +TEST_F(FixtureCases, tree_standard_grammar) { - test(tree_standard_cases, quetzal::format::newick::parser::tree); + for (const auto &input : tree_standard_cases) + { + auto iter = input.begin(); + auto iter_end = input.end(); + bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::tree); + EXPECT_TRUE(r && iter == iter_end); + } } -// BOOST_FIXTURE_TEST_CASE(tree_exotic_grammar, FixtureCases) +// TEST_F(FixtureCases, tree_exotic_grammar) // { -// test(tree_exotic_cases, quetzal::format::newick::parser::tree); +// for (const auto& input : tree_exotic_cases) +// { +// auto iter = input.begin(); +// auto iter_end = input.end(); +// bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::tree); +// EXPECT_TRUE(r && iter == iter_end); +// } // } -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_test/newick_generator_test.cpp b/test/unit_test/newick_generator_test.cpp index 69922f75..fcfd7338 100644 --- a/test/unit_test/newick_generator_test.cpp +++ b/test/unit_test/newick_generator_test.cpp @@ -6,10 +6,7 @@ * * ***************************************************************************/ -#define BOOST_TEST_MODULE newick_generator_test - -#include -namespace utf = boost::unit_test; +#include #include #include @@ -18,89 +15,7 @@ namespace utf = boost::unit_test; #include #include -BOOST_AUTO_TEST_SUITE(newick_formatting) - -BOOST_AUTO_TEST_CASE(newick_filters) -{ - namespace fmt = quetzal::format::newick; - namespace detail = fmt::detail; - - std::string s1 = "(A:5,B:5)r;"; - std::string s2 = "(A:5,B[Comment]:5)r;"; - std::string s3 = "(A:5,B[Comment[Nested]]:5)r;"; - - // Testing policies - BOOST_CHECK(detail::is_balanced::check(s2)); - BOOST_CHECK(detail::is_balanced::check(s3)); - - BOOST_CHECK(detail::is_balanced::check("(A:5,B[Comment:5r;") == false); - BOOST_CHECK(detail::is_balanced::check("(A:5,B[Comment:5))r;") == false); - - BOOST_CHECK_EQUAL(fmt::remove_comments_of_depth<0>::edit(s2), s2); - BOOST_CHECK_EQUAL(fmt::remove_comments_of_depth<1>::edit(s3), s1); - BOOST_CHECK_EQUAL(fmt::remove_comments_of_depth<2>::edit(s3), s2); -} - -/// @brief "Legacy" tree for testing -struct Node -{ - Node *parent = nullptr; - Node *left = nullptr; - Node *right = nullptr; - char data; - - template void depth_first_search(Op1 pre_order, Op2 in_order, Op3 post_order) - { - pre_order(*this); - if (this->left != nullptr && this->right != nullptr) - { - this->left->depth_first_search(pre_order, in_order, post_order); - in_order(); - this->right->depth_first_search(pre_order, in_order, post_order); - } - post_order(*this); - } -}; - -struct Fixture_simple_tree -{ - Fixture_simple_tree() - { - BOOST_TEST_MESSAGE("setup fixture simple tree"); - /* Topology : - * a - * / \ - * / c - * / / \ - * b d e - */ - - a.data = 'a'; - b.data = 'b'; - c.data = 'c'; - d.data = 'd'; - e.data = 'e'; - - a.left = &b; - b.parent = &a; - a.right = &c; - c.parent = &a; - c.left = &d; - d.parent = &c; - c.right = &e; - e.parent = &c; - } - - ~Fixture_simple_tree() - { - BOOST_TEST_MESSAGE("teardown fixture simple tree"); - } - - Node a, b, c, d, e; - -}; // end FixtureHomozygoteParents - -BOOST_FIXTURE_TEST_CASE(external_tree_no_label, Fixture_simple_tree) +TEST(NewickGeneratorTest, ExternalTreeNoLabel) { namespace newick = quetzal::format::newick; @@ -120,10 +35,10 @@ BOOST_FIXTURE_TEST_CASE(external_tree_no_label, Fixture_simple_tree) // We retrieve the formatted string auto result = generator.take_result(); - BOOST_CHECK_EQUAL(result, "(,(,));"); + EXPECT_EQ(result, "(,(,));"); } -BOOST_FIXTURE_TEST_CASE(external_tree_print_label, Fixture_simple_tree) +TEST(NewickGeneratorTest, ExternalTreePrintLabel) { namespace newick = quetzal::format::newick; @@ -145,10 +60,10 @@ BOOST_FIXTURE_TEST_CASE(external_tree_print_label, Fixture_simple_tree) // We retrieve the formatted string auto result = generator.take_result(); - BOOST_CHECK_EQUAL(result, "(b,(d,e)c)a;"); + EXPECT_EQ(result, "(b,(d,e)c)a;"); } -BOOST_FIXTURE_TEST_CASE(external_randomized_labels, Fixture_simple_tree) +TEST(NewickGeneratorTest, ExternalRandomizedLabels) { namespace newick = quetzal::format::newick; @@ -178,7 +93,7 @@ BOOST_FIXTURE_TEST_CASE(external_randomized_labels, Fixture_simple_tree) std::cout << generator.take_result() << std::endl; } -BOOST_FIXTURE_TEST_CASE(external_tree_align_format, Fixture_simple_tree) +TEST(NewickGeneratorTest, ExternalTreeAlignFormat) { namespace newick = quetzal::format::newick; @@ -199,7 +114,7 @@ BOOST_FIXTURE_TEST_CASE(external_tree_align_format, Fixture_simple_tree) // We retrieve the formatted string auto result = generator.take_result(); - BOOST_CHECK_EQUAL(result, "(b[my]:0.1,(d[my]:0.1,e[my]:0.1)c[my]:0.1)a[my]:0.0;"); + EXPECT_EQ(result, "(b[my]:0.1,(d[my]:0.1,e[my]:0.1)c[my]:0.1)a[my]:0.0;"); // Enables the use of nested comments // using flavor = quetzal::format::newick::PAUP; @@ -207,75 +122,9 @@ BOOST_FIXTURE_TEST_CASE(external_tree_align_format, Fixture_simple_tree) // TODO: using flavor = quetzal::format::newick::PHYLIP; } -BOOST_FIXTURE_TEST_CASE(legacy_k_ary_comparison, Fixture_simple_tree) +int main(int argc, char **argv) { - namespace newick = quetzal::format::newick; - using Flavor = quetzal::format::newick::TreeAlign; - - // LEGACY - - // Interfacing Quetzal generator with non-quetzal tree types - std::predicate auto has_parent = [](const Node &n) { return n.parent; }; - std::predicate auto has_children = [](const Node &n) { return n.left && n.right; }; - - // We are not interested into formatting the branch_length or label information - newick::Formattable auto no_branch_length = [](const Node &n) { return ""; }; - newick::Formattable auto print_label = [](const Node &n) { return ""; }; - - // We configure a generator passing it the interfaces - auto generator = newick::generator(has_parent, has_children, print_label, no_branch_length, Flavor()); - - // We expose its interface to the user-defined class DFS algorithm - a.depth_first_search(generator.pre_order(), generator.in_order(), generator.post_order()); - - // We retrieve the formatted string - std::string const legacy = generator.take_result(); - BOOST_CHECK_EQUAL(legacy, "(,(,)):0.0;"); - - // NOW WITH BGL GRAPHS - using tree_type = quetzal::coalescence::k_ary_tree; - - enum - { - a, - b, - c, - d, - e, - N - }; - tree_type tree(N); - tree.add_edges(a, {b, c}); - tree.add_edges(c, {d, e}); - - // Generate the newick string - auto quetzal = newick::generate_from(tree, a, Flavor()); - BOOST_CHECK_EQUAL(quetzal, "(,(,)):0.0;"); - - BOOST_CHECK_EQUAL(legacy, quetzal); -} - -struct vertex_t -{ - std::string bar; -}; -struct edge_t -{ - double foo; -}; - -BOOST_AUTO_TEST_CASE(k_ary_tree_default_property) -{ - namespace newick = quetzal::format::newick; - // Default generate trees with string/double as properties - auto [tree, root] = newick::to_k_ary_tree<>("(ant:17, (bat:31, cow:22):7, dog:22, (elk:33, fox:12):40);"); - // Generate the newick string - using Flavor = quetzal::format::newick::TreeAlign; - // auto s = newick::generate_from(tree, Flavor()); - // // Convert back, default would be no_property, so need something - // auto [other_tree, other_root] = newick::to_k_ary_tree(s); - // // Should be isomorphic - // BOOST_TEST(tree.is_isomorphic(other_root)); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_test/newick_parser_test.cpp b/test/unit_test/newick_parser_test.cpp index 634aa6f6..97a6170c 100644 --- a/test/unit_test/newick_parser_test.cpp +++ b/test/unit_test/newick_parser_test.cpp @@ -1,80 +1,62 @@ -// Copyright 2021 Arnaud Becheler - -/*********************************************************************** * This program 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 2 of the License, or * (at your option) any later version. * - * * - ***************************************************************************/ - -#define BOOST_TEST_MODULE newick_parser_test - -#include -namespace utf = boost::unit_test; +#include #include "quetzal/io/newick/parser.hpp" #include +#include +#include namespace x3 = boost::spirit::x3; -struct FixtureCases +class NewickParserTest : public ::testing::Test { - // Set up fixture - FixtureCases() +protected: + void SetUp() override { - BOOST_TEST_MESSAGE("setup fixture Newick cases"); - - this->name_cases = {"a34", "A856BC", "k56aH"}; + name_cases = {"a34", "A856BC", "k56aH"}; - this->length_cases = {":1", ":999", ":0.001"}; + length_cases = {":1", ":999", ":0.001"}; - this->leaf_cases = {"", "A", "B897kj"}; + leaf_cases = {"", "A", "B897kj"}; - this->branch_cases = { + branch_cases = { "leaf", "(in,ternal)", "leaf:10.0", "(in,ternal):50.0", }; - this->internal_cases = {"(,)", "(A,B)F", "(A:10,B:10)F"}; - - this->subtree_cases = {"leaf", - "(in,ternal)", - "(,,(,))", - "(A,B,(C,D))", - "(A,B,(C,D)E)F", - "(:0.1,:0.2,(:0.3,:0.4):0.5)", - "(:0.1,:0.2,(:0.3,:0.4):0.5)", - "(A:0.1,B:0.2,(C:0.3,D:0.4):0.5)", - "(A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F", - "((B:0.2,(C:0.3,D:0.4)E:0.5)F:0.1)A"}; - - this->tree_standard_cases = {";", - "(,);", - "(,,(,));", - "(A,B,(C,D));", - "(A,B,(C,D)E)F;", - "(:0.1,:0.2,(:0.3,:0.4):0.5);", - "(:0.1,:0.2,(:0.3,:0.4):0.5):0.0;", - "(A:0.1,B:0.2,(C:0.3,D:0.4):0.5);", - "(A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F;", - "((B:0.2,(C:0.3,D:0.4)E:0.5)F:0.1)A;"}; - - this->tree_exotic_cases = {"(Space In,Leaf)Name", "(Special,Symbol)%;"}; - - this->tree_must_fail_cases = { - - }; + internal_cases = {"(,)", "(A,B)F", "(A:10,B:10)F"}; + + subtree_cases = {"leaf", + "(in,ternal)", + "(,,(,))", + "(A,B,(C,D))", + "(A,B,(C,D)E)F", + "(:0.1,:0.2,(:0.3,:0.4):0.5)", + "(:0.1,:0.2,(:0.3,:0.4):0.5)", + "(A:0.1,B:0.2,(C:0.3,D:0.4):0.5)", + "(A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F", + "((B:0.2,(C:0.3,D:0.4)E:0.5)F:0.1)A"}; + + tree_standard_cases = {";", + "(,);", + "(,,(,));", + "(A,B,(C,D));", + "(A,B,(C,D)E)F;", + "(:0.1,:0.2,(:0.3,:0.4):0.5);", + "(:0.1,:0.2,(:0.3,:0.4):0.5):0.0;", + "(A:0.1,B:0.2,(C:0.3,D:0.4):0.5);", + "(A:0.1,B:0.2,(C:0.3,D:0.4)E:0.5)F;", + "((B:0.2,(C:0.3,D:0.4)E:0.5)F:0.1)A;"}; + + tree_exotic_cases = {"(Space In,Leaf)Name", "(Special,Symbol)%;"}; + + tree_must_fail_cases = {}; } - // Tear down fixture - ~FixtureCases() - { - BOOST_TEST_MESSAGE("teardown fixture Newick cases"); - } + void TearDown() override {} - // Member data of fixture std::vector name_cases; std::vector length_cases; std::vector leaf_cases; @@ -84,46 +66,60 @@ struct FixtureCases std::vector tree_standard_cases; std::vector tree_exotic_cases; std::vector tree_must_fail_cases; +}; -}; // end FixtureHomozygoteParents - -// Generic test function -auto test(const auto &cases, auto parser) +TEST_F(NewickParserTest, name_grammar) { - for (const auto &input : cases) + for (const auto &input : name_cases) { auto iter = input.begin(); auto iter_end = input.end(); - bool r = x3::parse(iter, iter_end, parser); - BOOST_CHECK(r && iter == iter_end); + bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::name); + EXPECT_TRUE(r && iter == iter_end); } } -BOOST_AUTO_TEST_SUITE(newick_parser) - -BOOST_FIXTURE_TEST_CASE(name_grammar, FixtureCases) -{ - test(name_cases, quetzal::format::newick::parser::name); -} - -BOOST_FIXTURE_TEST_CASE(length_grammar, FixtureCases) +TEST_F(NewickParserTest, length_grammar) { - test(length_cases, quetzal::format::newick::parser::length); + for (const auto &input : length_cases) + { + auto iter = input.begin(); + auto iter_end = input.end(); + bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::length); + EXPECT_TRUE(r && iter == iter_end); + } } -BOOST_FIXTURE_TEST_CASE(leaf_grammar, FixtureCases) +TEST_F(NewickParserTest, leaf_grammar) { - test(leaf_cases, quetzal::format::newick::parser::leaf); + for (const auto &input : leaf_cases) + { + auto iter = input.begin(); + auto iter_end = input.end(); + bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::leaf); + EXPECT_TRUE(r && iter == iter_end); + } } -BOOST_FIXTURE_TEST_CASE(tree_standard_grammar, FixtureCases) +TEST_F(NewickParserTest, tree_standard_grammar) { - test(tree_standard_cases, quetzal::format::newick::parser::tree); + for (const auto &input : tree_standard_cases) + { + auto iter = input.begin(); + auto iter_end = input.end(); + bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::tree); + EXPECT_TRUE(r && iter == iter_end); + } } -// BOOST_FIXTURE_TEST_CASE(tree_exotic_grammar, FixtureCases) +// TEST_F(NewickParserTest, tree_exotic_grammar) // { -// test(tree_exotic_cases, quetzal::format::newick::parser::tree); +// for (const auto& input : tree_exotic_cases) +// { +// auto iter = input.begin(); +// auto iter_end = input.end(); +// bool r = x3::parse(iter, iter_end, quetzal::format::newick::parser::tree); +// EXPECT_TRUE(r && iter == iter_end); +// } // } -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_test/occupancy_spectrum_test.cpp b/test/unit_test/occupancy_spectrum_test.cpp index f49ed7ea..c3589803 100644 --- a/test/unit_test/occupancy_spectrum_test.cpp +++ b/test/unit_test/occupancy_spectrum_test.cpp @@ -5,16 +5,10 @@ *Software Foundation; either version 2 of the License, or * (at your option) any later version. * * * ***************************************************************************/ -#define BOOST_TEST_MODULE occupancy_spectrum_test - -#include -namespace utf = boost::unit_test; - +#include #include -BOOST_AUTO_TEST_SUITE(occupancy_spectrum) - -BOOST_AUTO_TEST_CASE(occupancy_spectrum_support) +TEST(occupancy_spectrum, support) { // Type declaration using quetzal::coalescence::occupancy_spectrum::OccupancySpectrum; @@ -28,7 +22,7 @@ BOOST_AUTO_TEST_CASE(occupancy_spectrum_support) support.generate(editor); } -BOOST_AUTO_TEST_CASE(occupancy_spectrum__distribution_init) +TEST(occupancy_spectrum, distribution_init) { using quetzal::coalescence::occupancy_spectrum::ProbabilityDistribution; // initialization by default constructor @@ -45,7 +39,7 @@ BOOST_AUTO_TEST_CASE(occupancy_spectrum__distribution_init) ProbabilityDistribution<> e = std::move(c); // c should not be used anymore ! } -BOOST_AUTO_TEST_CASE(occupancy_spectrum_distribution) +TEST(occupancy_spectrum, distribution) { using quetzal::coalescence::occupancy_spectrum::ProbabilityDistribution; int n = 5; @@ -86,7 +80,7 @@ BOOST_AUTO_TEST_CASE(occupancy_spectrum_distribution) std::cout << "Combined strategies:\n" << dist4 << "\n" << std::endl; } -BOOST_AUTO_TEST_CASE(memoize) +TEST(occupancy_spectrum, memoize) { std::mt19937 g; // build and copy sample @@ -96,7 +90,7 @@ BOOST_AUTO_TEST_CASE(memoize) (void)spectrum_b; } -BOOST_AUTO_TEST_CASE(spectrum_creation_policy) +TEST(occupancy_spectrum, spectrum_creation_policy) { std::mt19937 g; @@ -114,4 +108,4 @@ BOOST_AUTO_TEST_CASE(spectrum_creation_policy) std::cout << it << " "; } } -BOOST_AUTO_TEST_SUITE_END() + diff --git a/test/unit_test/phylogeny_test.cpp b/test/unit_test/phylogeny_test.cpp index b657a206..a08bce6f 100644 --- a/test/unit_test/phylogeny_test.cpp +++ b/test/unit_test/phylogeny_test.cpp @@ -6,16 +6,11 @@ * * ***************************************************************************/ -#define BOOST_TEST_MODULE coalescence_test - -#include -namespace utf = boost::unit_test; +#include #include -BOOST_AUTO_TEST_SUITE(phylogenetics) - -BOOST_AUTO_TEST_CASE(network) +TEST(Phylogenetics, Network) { using quetzal::coalescence::container::Network; using std::string; @@ -62,9 +57,8 @@ BOOST_AUTO_TEST_CASE(network) std::vector v; auto functor = [&v](string s) { v.push_back(s); }; // root.visit_cells_by_pre_order_DFS(functor); - // BOOST_TEST(v == expected); + // EXPECT_EQ(v, expected); // root.to_newick(); } -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_test/polymorphism_test.cpp b/test/unit_test/polymorphism_test.cpp index 3fd8600b..248b9573 100644 --- a/test/unit_test/polymorphism_test.cpp +++ b/test/unit_test/polymorphism_test.cpp @@ -6,59 +6,14 @@ * * ***************************************************************************/ -#define BOOST_TEST_MODULE polymorphism_test - -#include - -// #include // percent -// #include // percent +#include #include -namespace utf = boost::unit_test; - -// using namespace units; +namespace utf = ::testing; -BOOST_AUTO_TEST_SUITE(statistics) - -BOOST_AUTO_TEST_CASE(tajimasD) +TEST(polymorphism_statistics, tajimasD) { - // // @note Quetzal is not bound to specific data structures, so tests are easily defined - // // - // // @see example in - // https://ocw.mit.edu/courses/hst-508-quantitative-genomics-fall-2005/0900020a633e85338e9510495c2e01a6_tajimad1.pdf - // using variant_matrix_type = std::map>; - // variant_matrix_type data - // { - // {subj0, {"ATAATAAAAA", "AATAATAAAA", "AAATAAAAAA", "AATAAAAAAA", "A"}, - // {subj1, {"AAAAAAAATA", "AATAATAAAA", "AAATAAAAAA", "AAAAAAAAAA", "A"}, - // {subj2, {"AAAATAAAAA", "TATAATAAAA", "AAATATAAAA", "AAAAAAAAAA", "A"}, - // {subj3, {"AAAAAAAAAA", "AATAATAAAA", "AAATAAATAA", "ATAAAAAAAA", "A"}, - // {subj4, {"AAAATAAAAA", "AAATATAAAA", "AAATAAAAAA", "AAAAAAAAAA", "A"}, - // {subj5, {"AAAATAAAAA", "AAAAATAAAA", "AAAAAAAAAA", "AAAAATAAAA", "A"}, - // {subj6, {"AAAAAATAAA", "AATAATAAAA", "AAATAAAAAA", "AAAAAAAAAA", "A"}, - // {subj7, {"AAAAAAAAAA", "AAAAATAAAA", "AAATAAAAAA", "AAAAAAAAAT", "A"}, - // {subj8, {"AAAAAAAAAA", "AAAAAAAAAA", "AAATAAAAAA", "AAAAAAAAAA", "A"}, - // {subj9, {"AAAAAAAAAA", "AAAAATAAAA", "AAATAATAAA", "AAAAAAAAAA", "A"} - // } - // - // // Expose iterators interface to statistics algorithms: - // get_subject = [](){return it.first}; - // // Compute statistics - // polymophism stats(data); - // - // BOOST_CHECK_EQUAL(polymophism.nb_sequences), 10); - // BOOST_CHECK_EQUAL(polymophism.nb_sites), 41); - // - // BOOST_CHECK_EQUAL(polymophism.tajimasD.mean_pairwise_difference.value()), 3.888889); - // BOOST_CHECK_EQUAL(polymophism.tajimasD.number_of_segregating_sites.value()), 16); - // BOOST_CHECK_EQUAL(polymophism.tajimasD.fraction_of_segregating_sites.value()), 16/41); - // - - // - // BOOST_CHECK_EQUAL(polymophism.tajimasD.value(), -1.446172); - // std::cout << polymophism.tajimasD.meaning() << std::endl; - // double mean_pairwise_difference = 3.888889; int nb_segregating_sites = 16; int nb_sequences = 10; @@ -66,31 +21,25 @@ BOOST_AUTO_TEST_CASE(tajimasD) // Compute stats using quetzal::polymorphism::statistics::tajimasD; auto stat = tajimasD(mean_pairwise_difference, nb_segregating_sites, nb_sequences); - // - // // Define test metrics - // auto error = [](auto computed, auto expected){return computed - expected;}; - // auto tolerance = [](auto expected){return dimensionless(1 * expected / expected);}; - // - // // Expected values - // auto a1 = 2.828968; - // auto a2 = 1.539768; - // auto b1 = 0.407407; - // auto b2 = 0.279012; - // auto c1 = 0.053922; - // auto c2 = 0.047227; - // auto e1 = 0.019061; - // auto e2 = 0.004949; - // auto D = -1.446172; - // - // BOOST_CHECK_SMALL(error(stat.a1(), a1), tolerance(a1).number()); - // BOOST_CHECK_SMALL(error(stat.a2(), a2), tolerance(a2).number()); - // BOOST_CHECK_SMALL(error(stat.b1(), b1), tolerance(b1).number() ) ; - // BOOST_CHECK_SMALL(error(stat.b2(), b2), tolerance(b2).number() ) ; - // BOOST_CHECK_SMALL(error(stat.c1(), c1), tolerance(c1).number() ) ; - // BOOST_CHECK_SMALL(error(stat.c2(), c2), tolerance(c2).number() ) ; - // BOOST_CHECK_SMALL(error(stat.e1(), e1), tolerance(e1).number() ) ; - // BOOST_CHECK_SMALL(error(stat.e2(), e2), tolerance(e2).number() ) ; - // BOOST_CHECK_SMALL(error(stat.D() , D), tolerance( D).number() ) ; + + auto a1 = 2.828968; + auto a2 = 1.539768; + auto b1 = 0.407407; + auto b2 = 0.279012; + auto c1 = 0.053922; + auto c2 = 0.047227; + auto e1 = 0.019061; + auto e2 = 0.004949; + auto D = -1.446172; + + EXPECT_NEAR(stat.a1(), a1, 1e-5); + EXPECT_NEAR(stat.a2(), a2, 1e-5); + EXPECT_NEAR(stat.b1(), b1, 1e-5); + EXPECT_NEAR(stat.b2(), b2, 1e-5); + EXPECT_NEAR(stat.c1(), c1, 1e-5); + EXPECT_NEAR(stat.c2(), c2, 1e-5); + EXPECT_NEAR(stat.e1(), e1, 1e-5); + EXPECT_NEAR(stat.e2(), e2, 1e-5); + EXPECT_NEAR(stat.D(), D, 1e-5); } -BOOST_AUTO_TEST_SUITE_END() diff --git a/test/unit_test/random_test.cpp b/test/unit_test/random_test.cpp index 15efe2e5..cee05b88 100644 --- a/test/unit_test/random_test.cpp +++ b/test/unit_test/random_test.cpp @@ -5,17 +5,12 @@ *Software Foundation; either version 2 of the License, or * (at your option) any later version. * * * ***************************************************************************/ -#define BOOST_TEST_MODULE random_test +#include +#include -#include -namespace utf = boost::unit_test; - -#include #include -BOOST_AUTO_TEST_SUITE(random_suite) - -BOOST_AUTO_TEST_CASE(discrete_distribution) +TEST(RandomTest, DiscreteDistribution) { using quetzal::utils::random::DiscreteDistribution; std::mt19937 gen; @@ -31,7 +26,7 @@ BOOST_AUTO_TEST_CASE(discrete_distribution) } } -BOOST_AUTO_TEST_CASE(discrete_distribution_init) +TEST(RandomTest, DiscreteDistributionInit) { std::mt19937 gen; using quetzal::utils::random::DiscreteDistribution; @@ -60,7 +55,7 @@ BOOST_AUTO_TEST_CASE(discrete_distribution_init) std::cout << fourth(gen) << std::endl; } -BOOST_AUTO_TEST_CASE(time_transition_kernel_init) +TEST(RandomTest, TimeTransitionKernelInit) { using State = int; @@ -95,7 +90,7 @@ BOOST_AUTO_TEST_CASE(time_transition_kernel_init) std::cout << B(gen, x, t) << std::endl; } -BOOST_AUTO_TEST_CASE(time_transition_kernel) +TEST(RandomTest, TimeTransitionKernel) { using deme_ID_type = int; using time_type = int; @@ -120,7 +115,7 @@ BOOST_AUTO_TEST_CASE(time_transition_kernel) } } -BOOST_AUTO_TEST_CASE(transition_kernel_init) +TEST(RandomTest, TransitionKernelInit) { using state_type = int; using distribution_type = std::discrete_distribution; @@ -149,7 +144,7 @@ BOOST_AUTO_TEST_CASE(transition_kernel_init) kernel_type B(1, std::move(d)); } -BOOST_AUTO_TEST_CASE(transition_kernel) +TEST(RandomTest, TransitionKernel) { using deme_ID_type = int; using law_type = std::discrete_distribution; @@ -173,4 +168,9 @@ BOOST_AUTO_TEST_CASE(transition_kernel) } } -BOOST_AUTO_TEST_SUITE_END() +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + diff --git a/test/unit_test/tree_binary_test.cpp b/test/unit_test/tree_binary_test.cpp index 4093c40d..9f25e53c 100644 --- a/test/unit_test/tree_binary_test.cpp +++ b/test/unit_test/tree_binary_test.cpp @@ -1,54 +1,12 @@ -// Copyright 2021 Arnaud Becheler +#include -/*********************************************************************** * This program 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 2 of the License, or * (at your option) any later version. * - * * - ***************************************************************************/ - -#define BOOST_TEST_MODULE binary_tree_test -#include -#include -#include -#include - -namespace utf = boost::unit_test; +#include #include -#include -template struct tree_visitor +namespace quetzal::coalescence { - void operator()(Order stage, Vertex v) - { - switch (stage) - { - case boost::visit::pre: - std::cout << "Pre " << v << std::endl; - break; - case boost::visit::in: - std::cout << "In " << v << std::endl; - break; - case boost::visit::post: - std::cout << "Post " << v << std::endl; - break; - default: - std::cout << "Oops" << std::endl; - } - } -}; - -BOOST_AUTO_TEST_SUITE(binary_tree) - -/* Topology : - * a - * / \ - * / c - * / / \ - * b d e - */ - -BOOST_AUTO_TEST_CASE(no_property_binary_interface) +TEST(binary_tree, no_property_binary_interface) { // default tree with no edge/vertex properties attached using tree_type = quetzal::coalescence::binary_tree; @@ -66,22 +24,40 @@ BOOST_AUTO_TEST_CASE(no_property_binary_interface) auto [cd_edge, ce_edge] = tree.add_edges(c, d, e); auto root = tree.find_root_from(e); - BOOST_CHECK(root == a); - BOOST_CHECK(tree.degree(c) == 3); - BOOST_CHECK(tree.in_degree(c) == 1); - BOOST_CHECK(tree.out_degree(c) == 2); - BOOST_CHECK(tree.has_predecessor(root) == false); - BOOST_CHECK(tree.predecessor(c) == root); - BOOST_CHECK(tree.has_successors(root) == true); + ASSERT_EQ(root, a); + ASSERT_EQ(tree.degree(c), 3); + ASSERT_EQ(tree.in_degree(c), 1); + ASSERT_EQ(tree.out_degree(c), 2); + ASSERT_EQ(tree.has_predecessor(root), false); + ASSERT_EQ(tree.predecessor(c), root); + ASSERT_EQ(tree.has_successors(root), true); auto have_children = [&tree = std::as_const(tree)](auto v) { return tree.has_successors(v); }; - BOOST_CHECK(!ranges::all_of(tree.successors(c), have_children)); + ASSERT_FALSE(ranges::all_of(tree.successors(c), have_children)); - using vertex_descriptor = boost::graph_traits::vertex_descriptor; - tree_visitor visitor; + struct tree_visitor + { + void operator()(boost::visit order, vertex_descriptor v) + { + switch (order) + { + case boost::visit::pre: + std::cout << "Pre " << v << std::endl; + break; + case boost::visit::in: + std::cout << "In " << v << std::endl; + break; + case boost::visit::post: + std::cout << "Post " << v << std::endl; + break; + default: + std::cout << "Oops" << std::endl; + } + } + } visitor; tree.depth_first_search(a, visitor); } -BOOST_AUTO_TEST_CASE(simple_vertex_properties) +TEST(binary_tree, simple_vertex_properties) { // tree with string vertices but no edge properties using vertex_properties = std::string; @@ -97,22 +73,21 @@ BOOST_AUTO_TEST_CASE(simple_vertex_properties) vertex_descriptor e = tree.add_vertex("e"); // Read - BOOST_CHECK(tree[a] == "a"); + ASSERT_EQ(tree[a], "a"); // Write tree[a] = tree[b]; - BOOST_CHECK(tree[a] == "b"); + ASSERT_EQ(tree[a], "b"); } -struct vertex_info -{ - std::string whatever; - int othervalue; -}; - -BOOST_AUTO_TEST_CASE(structure_vertex_properties) +TEST(binary_tree, structure_vertex_properties) { // tree with string & int vertices but no edge properties + struct vertex_info + { + std::string whatever; + int othervalue; + }; using tree_type = quetzal::coalescence::binary_tree; using vertex_descriptor = tree_type::vertex_descriptor; @@ -125,17 +100,17 @@ BOOST_AUTO_TEST_CASE(structure_vertex_properties) vertex_descriptor e = tree.add_vertex(vertex_info{"e", 4}); // Read - BOOST_CHECK(tree[e].whatever == "e"); - BOOST_CHECK(tree[e].othervalue == 4); + ASSERT_EQ(tree[e].whatever, "e"); + ASSERT_EQ(tree[e].othervalue, 4); // Write tree[e] = {"new", 5}; - BOOST_TEST(tree[e].whatever == "new"); - BOOST_CHECK(tree[e].othervalue == 5); + ASSERT_EQ(tree[e].whatever, "new"); + ASSERT_EQ(tree[e].othervalue, 5); } -BOOST_AUTO_TEST_CASE(simple_edge_properties) +TEST(binary_tree, simple_edge_properties) { // tree with string edges but no vertex properties attached using vertex_properties = boost::no_property; @@ -157,21 +132,19 @@ BOOST_AUTO_TEST_CASE(simple_edge_properties) tree.add_edges(ac_edge.second, {d, edge_properties{"c->d"}}, {e, edge_properties{"c->e"}}); tree[ab_edge] = "a...b"; - BOOST_CHECK(tree[ab_edge] == "a...b"); + ASSERT_EQ(tree[ab_edge], "a...b"); } -struct edge_info -{ - std::string whatever; - int othervalue; -}; - -BOOST_AUTO_TEST_CASE(struct_edge_properties) +TEST(binary_tree, struct_edge_properties) { // default tree with no edge/vertex properties attached using vertex_properties = boost::no_property; - using edge_properties = edge_info; - using tree_type = quetzal::coalescence::binary_tree; + struct edge_info + { + std::string whatever; + int othervalue; + }; + using tree_type = quetzal::coalescence::binary_tree; using vertex_descriptor = tree_type::vertex_descriptor; tree_type tree; @@ -184,23 +157,33 @@ BOOST_AUTO_TEST_CASE(struct_edge_properties) vertex_descriptor e = tree.add_vertex(); // Pass info to build new edges - auto [ab_edge, ac_edge] = tree.add_edges(a, {b, edge_properties{"a->b", 10}}, {c, edge_properties{"a->c", 11}}); + auto [ab_edge, ac_edge] = tree.add_edges(a, {b, edge_info{"a->b", 10}}, {c, edge_info{"a->c", 11}}); auto [cd_edge, ce_edge] = - tree.add_edges(ac_edge.second, {d, edge_properties{"c->d", 12}}, {e, edge_properties{"c->e", 13}}); + tree.add_edges(ac_edge.second, {d, edge_info{"c->d", 12}}, {e, edge_info{"c->e", 13}}); // Read edge info - BOOST_CHECK(tree[ab_edge].whatever == "a->b"); - BOOST_CHECK(tree[ab_edge].othervalue == 10); + ASSERT_EQ(tree[ab_edge].whatever, "a->b"); + ASSERT_EQ(tree[ab_edge].othervalue, 10); // Write edge info tree[ab_edge] = {"yolo", 99}; - BOOST_CHECK(tree[ab_edge].whatever == "yolo"); - BOOST_CHECK(tree[ab_edge].othervalue == 99); + ASSERT_EQ(tree[ab_edge].whatever, "yolo"); + ASSERT_EQ(tree[ab_edge].othervalue, 99); } -BOOST_AUTO_TEST_CASE(struct_both_properties) +TEST(binary_tree, struct_both_properties) { // default tree with no edge/vertex properties attached + struct vertex_info + { + std::string whatever; + int othervalue; + }; + struct edge_info + { + std::string whatever; + int othervalue; + }; using tree_type = quetzal::coalescence::binary_tree; using vertex_descriptor = tree_type::vertex_descriptor; @@ -217,25 +200,25 @@ BOOST_AUTO_TEST_CASE(struct_both_properties) auto [cd_edge, ce_edge] = tree.add_edges(ac_edge.second, {d, edge_info{"c->d", 12}}, {e, edge_info{"c->e", 13}}); // Read vertices - BOOST_CHECK(tree[e].whatever == "e"); - BOOST_CHECK(tree[e].othervalue == 4); + ASSERT_EQ(tree[e].whatever, "e"); + ASSERT_EQ(tree[e].othervalue, 4); // Write vertices tree[e] = {"new", 5}; - BOOST_CHECK(tree[e].whatever == "new"); - BOOST_CHECK(tree[e].othervalue == 5); + ASSERT_EQ(tree[e].whatever, "new"); + ASSERT_EQ(tree[e].othervalue, 5); // Read edge info - BOOST_CHECK(tree[ab_edge].whatever == "a->b"); - BOOST_CHECK(tree[ab_edge].othervalue == 10); + ASSERT_EQ(tree[ab_edge].whatever, "a->b"); + ASSERT_EQ(tree[ab_edge].othervalue, 10); // Write edge info tree[ab_edge] = {"yolo", 99}; - BOOST_CHECK(tree[ab_edge].whatever == "yolo"); - BOOST_CHECK(tree[ab_edge].othervalue == 99); + ASSERT_EQ(tree[ab_edge].whatever, "yolo"); + ASSERT_EQ(tree[ab_edge].othervalue, 99); } -BOOST_AUTO_TEST_CASE(random_binary_tree) +TEST(binary_tree, random_binary_tree) { std::random_device rd; @@ -246,12 +229,20 @@ BOOST_AUTO_TEST_CASE(random_binary_tree) auto [tree1, root1] = quetzal::coalescence::get_random_binary_tree(nb_leaves, gen); auto [tree2, root2] = quetzal::coalescence::get_random_binary_tree(nb_leaves, gen); - BOOST_CHECK(tree1.has_predecessor(root1) == false); - BOOST_CHECK(tree1.degree(root1) == 2); + ASSERT_EQ(tree1.has_predecessor(root1), false); + ASSERT_EQ(tree1.degree(root1), 2); + + struct tree_visitor + { + void operator()(boost::visit order, vertex_descriptor v) + { + switch (order) + { + case boost::visit::pre: + std::cout << "Pre " << v << std::endl; + break; + case boost::visit::in: + std::cout << "In " << v << std::endl; + break; + case boost::visit::post: - using vertex_descriptor = boost::graph_traits< - quetzal::coalescence::binary_tree>::vertex_descriptor; - tree_visitor visitor; - tree1.depth_first_search(root1, visitor); -} -BOOST_AUTO_TEST_SUITE_END() diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 00000000..852ab42f --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,19 @@ +{ + "name": "my-project", + "version": "0.1.0", + "dependencies": [ + "libkml", + { + "name": "gdal", + "default-features": false, + "features": ["recommended-features"] + }, + "gtest", + "boost-graph", + "boost-serialization", + "boost-filesystem", + "boost-ublas", + "mp-units", + "range-v3" + ] + } \ No newline at end of file diff --git a/vcpkg_configuration.json b/vcpkg_configuration.json new file mode 100644 index 00000000..b93771a1 --- /dev/null +++ b/vcpkg_configuration.json @@ -0,0 +1,19 @@ +{ + "default-registry": { + "kind": "git", + "repository": "https://github.com/Microsoft/vcpkg", + "baseline": "3265c187c74914aa5569b75355badebfdbab7987" + }, + "registries": [ + { + "kind": "git", + "repository": "https://github.com/Microsoft/vcpkg", + "baseline": "ce613c41372b23b1f51333815feb3edd87ef8a8b", + "packages": [ "boost*", "boost-*" ] + } + ], + "build-settings": { + "default-library-linkage": "dynamic", + "allow-compiler-and-linker-flags": true + } +}