diff --git a/.devcontainer/Jammy.dockerfile b/.devcontainer/Jammy.dockerfile index 2b65858b..24b3b010 100644 --- a/.devcontainer/Jammy.dockerfile +++ b/.devcontainer/Jammy.dockerfile @@ -196,12 +196,6 @@ RUN mkdir -p ~/.config/fish/ && echo 'set fish_greeting; function random_message # Set Fish as Default Shell. RUN chsh -s /usr/bin/fish -# Clone Autonomy Software Repository -RUN git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git - -# Set Working Directory -WORKDIR /opt/Autonomy_Software/ - # Set Labels LABEL authors="Missouri S&T Mars Rover Design Team" LABEL maintainer="Mars Rover Design Team " diff --git a/.devcontainer/JetPack.dockerfile b/.devcontainer/JetPack.dockerfile index a33ac7e8..a7885b07 100644 --- a/.devcontainer/JetPack.dockerfile +++ b/.devcontainer/JetPack.dockerfile @@ -185,15 +185,9 @@ RUN wget -q https://github.com/MissouriMRDT/Autonomy_Packages/raw/main/gtest/arm # Set Fish as Default Shell RUN chsh -s /usr/bin/fish && mkdir -p ~/.config/fish/ && echo 'set fish_greeting' >> ~/.config/fish/config.fish -# Clone Autonomy Software Repository -RUN git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git /opt/Autonomy_Software - # Disable the VSCode server requirements check, this fixes the cross architecture issues and potentially fixes mismatching VSCode server versions. Can be unstable. RUN touch /tmp/vscode-skip-server-requirements-check -# Set Working Directory -WORKDIR /opt/Autonomy_Software/ - # Set Labels LABEL authors="Missouri S&T Mars Rover Design Team" LABEL maintainer="Mars Rover Design Team " diff --git a/.github/workflows/clang_check.yml b/.github/workflows/clang_check.yml index 650e93af..970c1d6c 100644 --- a/.github/workflows/clang_check.yml +++ b/.github/workflows/clang_check.yml @@ -30,7 +30,23 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 with: - submodules: recursive + submodules: false + + - name: Init only needed submodules (and block LiDAR) + shell: bash + run: | + set -euo pipefail + + # Only allow these submodules to ever be touched + git config --local --unset-all submodule.active || true + git config --local --add submodule.active external/threadpool + git config --local --add submodule.active external/rovecomm + + # Extra safety: make LiDAR a no-op if anything tries to update all submodules + git config --local submodule.data/LiDAR.update none + + git submodule sync --recursive + git submodule update --init --recursive external/threadpool external/rovecomm - name: Fix Dubious Ownership run: git config --global --add safe.directory /opt/Autonomy_Software diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b51bbb57..2f9b2483 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -40,12 +40,12 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi - name: Checkout repository uses: actions/checkout@v4 with: - submodules: recursive + submodules: false - name: Fix Dubious Ownership run: git config --global --add safe.directory /opt/Autonomy_Software @@ -57,16 +57,30 @@ jobs: - name: Update Branch run: | + set -euo pipefail cd /opt/Autonomy_Software/ - git fetch --force --recurse-submodules + branch=${{ steps.extract_branch.outputs.branch }} - echo $branch - git reset --hard origin/$branch - git checkout $branch - git pull --ff-only - git submodule update --force --recursive --init + echo "Using branch: $branch" + + git fetch --force origin "$branch" + git checkout -B "$branch" "origin/$branch" + git reset --hard "origin/$branch" + + # Only allow these two submodules to ever be touched + git config --local --unset-all submodule.active || true + git config --local --add submodule.active external/threadpool + git config --local --add submodule.active external/rovecomm + + # Extra safety: make LiDAR a no-op if anything tries to update all submodules + git config --local submodule.data/LiDAR.update none + + git submodule sync --recursive + git submodule update --init --recursive external/threadpool external/rovecomm + git config --global --add safe.directory /opt/Autonomy_Software/external + - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index fb35f2a4..adc8d83b 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -22,12 +22,12 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi - name: Checkout repository uses: actions/checkout@v4 with: - submodules: recursive + submodules: false ref: ${{ github.event.pull_request.head.sha }} - name: Fix Dubious Ownership @@ -40,14 +40,25 @@ jobs: - name: Update Branch run: | + set -euo pipefail cd /opt/Autonomy_Software/ - git fetch --force --recurse-submodules - branch=${{ steps.extract_branch.outputs.branch }} - echo ${{ github.event.pull_request.head.sha }} + + echo "PR SHA: ${{ github.event.pull_request.head.sha }}" + git fetch --force origin ${{ github.event.pull_request.head.sha }} + git checkout --detach ${{ github.event.pull_request.head.sha }} git reset --hard ${{ github.event.pull_request.head.sha }} - git checkout ${{ github.event.pull_request.head.sha }} - # git pull --ff-only - git submodule update --force --recursive --init + + # Only allow these submodules to ever be touched + git config --local --unset-all submodule.active || true + git config --local --add submodule.active external/threadpool + git config --local --add submodule.active external/rovecomm + + # Extra safety: make LiDAR a no-op if anything tries to update all submodules + git config --local submodule.data/LiDAR.update none + + git submodule sync --recursive + git submodule update --init --recursive external/threadpool external/rovecomm + git config --global --add safe.directory /opt/Autonomy_Software/external - name: Configure and Build @@ -56,7 +67,7 @@ jobs: if [ -d "build" ]; then rm -Rf build; fi mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTS_MODE=ON -DBUILD_CODE_COVERAGE=ON -DBUILD_COVERAGE_WATCH=OFF -DBUILD_VERBOSE_MODE=ON + cmake .. -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTS_MODE=ON -DENABLE_LIDAR_GEO_UTESTS=OFF -DBUILD_CODE_COVERAGE=ON -DBUILD_COVERAGE_WATCH=OFF -DBUILD_VERBOSE_MODE=ON make -j8 - name: Run Tests @@ -73,7 +84,8 @@ jobs: --exclude '../src/vision/aruco/TagDetector.h' --exclude '../src/vision/aruco/TagDetector.cpp' \ --exclude '../src/vision/cameras/.*' \ --exclude '../src/vision/objects/ObjectDetector.h' --exclude '../src/vision/objects/ObjectDetector.cpp' \ - --exclude 'util/vision/YOLOModel.hpp' + --exclude 'util/vision/YOLOModel.hpp' \ + --exclude '../src/algorithms/planners/GeoPlanner.h' - name: Upload Test Coverage to Codacy if: steps.run_tests.outcome == 'success' diff --git a/.github/workflows/deploy_autonomy.yml b/.github/workflows/deploy_autonomy.yml index e993fbf3..4c8b08d5 100644 --- a/.github/workflows/deploy_autonomy.yml +++ b/.github/workflows/deploy_autonomy.yml @@ -65,12 +65,12 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi - name: Checkout repository uses: actions/checkout@v4 with: - submodules: recursive + submodules: false - name: Fix Dubious Ownership run: git config --global --add safe.directory /opt/Autonomy_Software @@ -86,10 +86,21 @@ jobs: # Setup Environment cd /opt/Autonomy_Software git remote set-url origin git@github.com:MissouriMRDT/Autonomy_Software.git - git fetch --tags --force --recurse-submodules + git fetch --tags --force git checkout development git pull - git submodule update --force --recursive --init + + # Allowlist only the submodules you want in non-release jobs + git config --local --unset-all submodule.active || true + git config --local --add submodule.active external/threadpool + git config --local --add submodule.active external/rovecomm + + # Make LiDAR a no-op even if something tries "update all" + git config --local submodule.data/LiDAR.update none + + git submodule sync --recursive + git submodule update --init --recursive external/threadpool external/rovecomm + git config --global --add safe.directory /opt/Autonomy_Software/external # Find and Format Latest Tag @@ -141,7 +152,7 @@ jobs: uses: actions/checkout@v4 with: ref: development - submodules: recursive + submodules: false - name: Check for Branch id: check_branch diff --git a/.github/workflows/deploy_docker.yml b/.github/workflows/deploy_docker.yml index dc166cc4..860c5dc4 100644 --- a/.github/workflows/deploy_docker.yml +++ b/.github/workflows/deploy_docker.yml @@ -84,7 +84,7 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi # This step is used to checkout the repository. It is needed so that the package build scripts can be # checked for changes. @@ -92,7 +92,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive + submodules: false # This step is used to check if any of the package build scripts have been updated. If any of the package # build scripts have been updated, then the packages need to be rebuilt in the next job. This step outputs @@ -172,7 +172,7 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi # This step is used to checkout the repository. It is needed so that the package build scripts can be # checked for changes. @@ -180,7 +180,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive + submodules: false # This step is used to rebuild the updated package. It gets the list of packages that need to be rebuilt # from the previous job. It runs the package build script for the package that is being built. @@ -262,14 +262,14 @@ jobs: run: | cd /opt if [ ! -d "Autonomy_Software" ]; then - git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git + git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git fi - name: Checkout Repository uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive + submodules: false # --- Check if FFmpeg rebuild is needed. --- - name: Check if FFmpeg Rebuild is Needed @@ -472,7 +472,7 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi # This step is used to checkout the repository. It is needed so that the package build scripts can be # checked for changes. @@ -480,7 +480,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive + submodules: false # This step is used to check if any of the package build scripts have been updated. If any of the package # build scripts have been updated, then the packages need to be rebuilt in the next job. This step outputs @@ -559,7 +559,7 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi # This step is used to checkout the repository. It is needed so that the package build scripts can be # checked for changes. @@ -567,7 +567,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive + submodules: false # This step is used to rebuild the updated package. It gets the list of packages that need to be rebuilt # from the previous job. It runs the package build script for the package that is being built. @@ -649,14 +649,14 @@ jobs: run: | cd /opt if [ ! -d "Autonomy_Software" ]; then - git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git + git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git fi - name: Checkout Repository uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive + submodules: false # --- Check if FFmpeg rebuild is needed for ARM64 --- - name: Check if FFmpeg Rebuild is Needed @@ -839,7 +839,7 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi # This step is used to checkout the repository. It is needed so that the package build scripts can be # checked for changes. @@ -847,7 +847,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive + submodules: false # This step is used to check if any of the package build scripts have been updated. If any of the package # build scripts have been updated, then the packages need to be rebuilt in the next job. This step outputs @@ -943,7 +943,7 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi # This step is used to checkout the repository. It is needed so that the package build scripts can be # checked for changes. @@ -951,7 +951,7 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: recursive + submodules: false # This step is used to check if any of the package build scripts have been updated. If any of the package # build scripts have been updated, then the packages need to be rebuilt in the next job. This step outputs diff --git a/.github/workflows/doxygen_generate.yml b/.github/workflows/doxygen_generate.yml index 80684a6b..a9ca2f14 100644 --- a/.github/workflows/doxygen_generate.yml +++ b/.github/workflows/doxygen_generate.yml @@ -39,11 +39,27 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 with: - submodules: recursive + submodules: false - name: Fix Dubious Ownership run: git config --global --add safe.directory /opt/Autonomy_Software + - name: Init only needed submodules (and block LiDAR) + shell: bash + run: | + set -euo pipefail + + # Only allow these submodules to ever be touched + git config --local --unset-all submodule.active || true + git config --local --add submodule.active external/threadpool + git config --local --add submodule.active external/rovecomm + + # Extra safety: make LiDAR a no-op if anything tries to update all submodules + git config --local submodule.data/LiDAR.update none + + git submodule sync --recursive + git submodule update --init --recursive external/threadpool external/rovecomm + - name: Setup Pages uses: actions/configure-pages@v4 diff --git a/.github/workflows/help_requester.yml b/.github/workflows/help_requester.yml index d4b26e82..3a48e46f 100644 --- a/.github/workflows/help_requester.yml +++ b/.github/workflows/help_requester.yml @@ -13,7 +13,7 @@ jobs: - name: Checkout code uses: actions/checkout@v4 with: - submodules: recursive + submodules: false fetch-depth: 0 - name: Fetch all branches and commits diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 22dfd6ec..2c544790 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -25,12 +25,12 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi - name: Checkout repository uses: actions/checkout@v4 with: - submodules: recursive + submodules: false - name: Fix Dubious Ownership run: git config --global --add safe.directory /opt/Autonomy_Software @@ -42,13 +42,27 @@ jobs: - name: Update Branch run: | + set -euo pipefail cd /opt/Autonomy_Software/ - git fetch --force --recurse-submodules + branch=${{ steps.extract_branch.outputs.branch }} - git reset --hard origin/$branch - git checkout $branch - git pull --ff-only - git submodule update --force --recursive --init + echo "Using branch: $branch" + + git fetch --force origin "$branch" + git checkout -B "$branch" "origin/$branch" + git reset --hard "origin/$branch" + + # Only allow these two submodules to ever be touched + git config --local --unset-all submodule.active || true + git config --local --add submodule.active external/threadpool + git config --local --add submodule.active external/rovecomm + + # Extra safety: make LiDAR a no-op if anything tries to update all submodules + git config --local submodule.data/LiDAR.update none + + git submodule sync --recursive + git submodule update --init --recursive external/threadpool external/rovecomm + git config --global --add safe.directory /opt/Autonomy_Software/external - name: Build and Run Tests with CTest @@ -61,7 +75,7 @@ jobs: cd /opt/Autonomy_Software/ rm -rf build && mkdir build && cd build - cmake -DBUILD_TESTS_MODE=ON .. + cmake -DBUILD_TESTS_MODE=ON -DENABLE_LIDAR_GEO_UTESTS=OFF .. make -j8 LABEL="${{ matrix.type == 'Unit' && 'UTest' || 'ITest' }}" @@ -88,7 +102,7 @@ jobs: if: always() run: | cd /opt - if [ ! -d "Autonomy_Software" ]; then git clone --recurse-submodules -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi + if [ ! -d "Autonomy_Software" ]; then git clone -j8 https://github.com/MissouriMRDT/Autonomy_Software.git; fi - name: Checkout repository uses: actions/checkout@v4 @@ -105,13 +119,27 @@ jobs: - name: Update Branch run: | + set -euo pipefail cd /opt/Autonomy_Software/ - git fetch --force --recurse-submodules + branch=${{ steps.extract_branch.outputs.branch }} - git reset --hard origin/$branch - git checkout $branch - git pull --ff-only - git submodule update --force --recursive --init + echo "Using branch: $branch" + + git fetch --force origin "$branch" + git checkout -B "$branch" "origin/$branch" + git reset --hard "origin/$branch" + + # Only allow these two submodules to ever be touched + git config --local --unset-all submodule.active || true + git config --local --add submodule.active external/threadpool + git config --local --add submodule.active external/rovecomm + + # Extra safety: make LiDAR a no-op if anything tries to update all submodules + git config --local submodule.data/LiDAR.update none + + git submodule sync --recursive + git submodule update --init --recursive external/threadpool external/rovecomm + git config --global --add safe.directory /opt/Autonomy_Software/external - name: Build and Run Tests with CTest @@ -124,7 +152,7 @@ jobs: cd /opt/Autonomy_Software/ rm -rf build && mkdir build && cd build - cmake -DBUILD_TESTS_MODE=ON .. + cmake -DBUILD_TESTS_MODE=ON -DENABLE_LIDAR_GEO_UTESTS=OFF .. make -j1 LABEL="${{ matrix.type == 'Unit' && 'UTest' || 'ITest' }}" diff --git a/CMakeLists.txt b/CMakeLists.txt index ff86b26c..c872e4af 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,9 @@ option(BUILD_VERBOSE_MODE "Enable Verbose Makefile" OFF) ## Enable or Disable Tests Mode option(BUILD_TESTS_MODE "Enable Tests Mode" OFF) +## Allow LiDAR/GeoPlanner unit tests (can require special data/env) +option(ENABLE_LIDAR_GEO_UTESTS "Enable unit tests in LidarHandler.cc and GeoPlanner.cc" OFF) + ## Enable or Disable Examples Mode option(BUILD_EXAMPLES_MODE "Enable Examples Mode" OFF) @@ -356,6 +359,13 @@ if (BUILD_TESTS_MODE) message("-- Current Timestamp: ${CURRENT_TIMESTAMP}") if (UnitTests_LEN GREATER 0) + if (NOT ENABLE_LIDAR_GEO_UTESTS) + message("-- [ ]: LiDAR/GeoPlanner Unit Tests: Disabled (LiDARHandler.cc, GeoPlanner.cc)") + list(FILTER UTests_SRC EXCLUDE REGEX ".*/(LiDARHandler|GeoPlanner)\\.cc$") + else() + message("-- [x]: LiDAR/GeoPlanner Unit Tests: Enabled") + endif() + add_executable(${EXE_NAME}_UnitTests ${Runner_SRC} ${UTests_SRC} ${TEST_SRC}) target_link_libraries(${EXE_NAME}_UnitTests GTest::gtest GTest::gtest_main ${AUTONOMY_LIBRARIES}) diff --git a/tests/Unit/src/handlers/LiDARHandler.cc b/tests/Unit/src/handlers/LiDARHandler.cc index 0d502ef5..c1a7878a 100644 --- a/tests/Unit/src/handlers/LiDARHandler.cc +++ b/tests/Unit/src/handlers/LiDARHandler.cc @@ -1,256 +1,256 @@ -/****************************************************************************** - * @brief Unit tests for the LiDARHandler runtime query class. - * - * @file LiDARHandler.cc - * @author Eli Byrd (edbgkk@mst.edu) - * @date 2025-05-20 - * - * @copyright Copyright Mars Rover Design Team 2025 - All Rights Reserved - ******************************************************************************/ - -#include "../../../../src/handlers/LiDARHandler.h" -#include "../../../TestingBase.hh" - -/// \cond -#include -#include -#include - -/// \endcond - -/****************************************************************************** - * @brief Test fixture for LiDARHandler class. - * - * - * @author Eli Byrd (edbgkk@mst.edu) - * @date 2025-05-20 - ******************************************************************************/ -class LiDARHandlerTests : public TestingBase -{ - protected: - std::string m_szDbPath = "../data/LiDAR/data/databases/Flat_SIM.db"; - - public: - LiDARHandlerTests() = default; - ~LiDARHandlerTests() override = default; - - void TestSetup() override {} - - void TestTeardown() override {} -}; - -/****************************************************************************** - * @brief Confirm that handler opens the database correctly. - * - * - * @author Eli Byrd (edbgkk@mst.edu) - * @date 2025-05-20 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, CanInitializeWithValidDB) -{ - LiDARHandler handler; - EXPECT_TRUE(handler.OpenDB(m_szDbPath)); -} - -/****************************************************************************** - * @brief Confirm that initialization fails with nonexistent DB. - * - * @author Eli Byrd (edbgkk@mst.edu) - * @date 2025-05-20 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, FailsToInitializeInvalidDB) -{ - LiDARHandler handler; - EXPECT_FALSE(handler.OpenDB("invalid/path/to.db")); -} - -/****************************************************************************** - * @brief Confirm that handler can close the database. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, CanCloseDB) -{ - LiDARHandler handler; - EXPECT_TRUE(handler.OpenDB(m_szDbPath)); - EXPECT_TRUE(handler.CloseDB()); - EXPECT_FALSE(handler.IsDBOpen()); -} - -/****************************************************************************** - * @brief Confirm that closing without opening is safe. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, CloseDBWithoutOpenIsSafe) -{ - LiDARHandler handler; - EXPECT_TRUE(handler.CloseDB()); - EXPECT_FALSE(handler.IsDBOpen()); -} - -/****************************************************************************** - * @brief Confirm that double open closes previous and opens new DB. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, DoubleOpenClosesPrevious) -{ - LiDARHandler handler; - EXPECT_TRUE(handler.OpenDB(m_szDbPath)); - // Open again with same path, should close and reopen - EXPECT_TRUE(handler.OpenDB(m_szDbPath)); - EXPECT_TRUE(handler.IsDBOpen()); -} - -/****************************************************************************** - * @brief Confirm that double close is safe. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, DoubleCloseIsSafe) -{ - LiDARHandler handler; - EXPECT_TRUE(handler.OpenDB(m_szDbPath)); - EXPECT_TRUE(handler.CloseDB()); - EXPECT_TRUE(handler.CloseDB()); -} - -/****************************************************************************** - * @brief Query returns empty if DB not open. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, QueryWithoutOpenReturnsEmpty) -{ - LiDARHandler handler; - LiDARHandler::PointFilter filter{.dEasting = 0, .dNorthing = 0, .dRadius = 1.0}; - std::vector vResults = handler.GetLiDARData(filter); - EXPECT_TRUE(vResults.empty()); -} - -/****************************************************************************** - * @brief Query returns results if present. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, QueryReturnsResultsIfPresent) -{ - LiDARHandler handler; - ASSERT_TRUE(handler.OpenDB(m_szDbPath)); - LiDARHandler::PointFilter filter{.dEasting = 614058.84, .dNorthing = 4189968.85, .dRadius = 3.0}; - std::vector vResults = handler.GetLiDARData(filter); - // Can't guarantee DB contents, but should not crash - SUCCEED(); -} - -/****************************************************************************** - * @brief Query with classification filter. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, QueryWithClassification) -{ - LiDARHandler handler; - ASSERT_TRUE(handler.OpenDB(m_szDbPath)); - LiDARHandler::PointFilter filter{.dEasting = 614058.84, .dNorthing = 4189968.85, .dRadius = 3.0, .szClassification = std::optional("ground")}; - std::vector vResults = handler.GetLiDARData(filter); - // Should not crash, may be empty - SUCCEED(); -} - -/****************************************************************************** - * @brief Query with traversal score range filter. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, QueryWithTraversalScoreRange) -{ - LiDARHandler handler; - ASSERT_TRUE(handler.OpenDB(m_szDbPath)); - LiDARHandler::PointFilter filter{.dEasting = 614058.84, - .dNorthing = 4189968.85, - .dRadius = 3.0, - .dTraversalScore = std::optional>({0.95, 1.0})}; - std::vector vResults = handler.GetLiDARData(filter); - // Should not crash, may be empty - SUCCEED(); -} - -/****************************************************************************** - * @brief Query with all range filters. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, QueryWithAllRangeFilters) -{ - LiDARHandler handler; - ASSERT_TRUE(handler.OpenDB(m_szDbPath)); - LiDARHandler::PointFilter stFilter{ - .dEasting = 614058.84, - .dNorthing = 4189968.85, - .dRadius = 3.0, - .dNormalX = std::optional>({-1.0, 1.0}), - .dNormalY = std::optional>({-1.0, 1.0}), - .dNormalZ = std::optional>({-1.0, 1.0}), - .dSlope = std::optional>({0.0, 90.0}), - .dRoughness = std::optional>({0.0, 10.0}), - .dCurvature = std::optional>({-10.0, 10.0}), - .dTraversalScore = std::optional>({0.0, 1.0}), - }; - std::vector vResults = handler.GetLiDARData(stFilter); - SUCCEED(); -} - -/****************************************************************************** - * @brief Check thread safety of open/close/query operations. - * - * - * @author clayjay3 (claytonraycowen@gmail.com) - * @date 2025-07-14 - ******************************************************************************/ -TEST_F(LiDARHandlerTests, ThreadSafetyOpenCloseQuery) -{ - LiDARHandler handler; - std::function fnOpenClose = [&handler, this]() - { - for (int i = 0; i < 5; ++i) - { - handler.OpenDB(m_szDbPath); - handler.CloseDB(); - } - }; - std::function fnQuery = [&handler, this]() - { - for (int i = 0; i < 5; ++i) - { - handler.OpenDB(m_szDbPath); - LiDARHandler::PointFilter filter{.dEasting = 614058.84, .dNorthing = 4189968.85, .dRadius = 3.0}; - handler.GetLiDARData(filter); - handler.CloseDB(); - } - }; - std::thread thThread1(fnOpenClose); - std::thread thThread2(fnQuery); - thThread1.join(); - thThread2.join(); - SUCCEED(); -} +/****************************************************************************** + * @brief Unit tests for the LiDARHandler runtime query class. + * + * @file LiDARHandler.cc + * @author Eli Byrd (edbgkk@mst.edu) + * @date 2025-05-20 + * + * @copyright Copyright Mars Rover Design Team 2025 - All Rights Reserved + ******************************************************************************/ + +#include "../../../../src/handlers/LiDARHandler.h" +#include "../../../TestingBase.hh" + +/// \cond +#include +#include +#include + +/// \endcond + +/****************************************************************************** + * @brief Test fixture for LiDARHandler class. + * + * + * @author Eli Byrd (edbgkk@mst.edu) + * @date 2025-05-20 + ******************************************************************************/ +class LiDARHandlerTests : public TestingBase +{ + protected: + std::string m_szDbPath = "../data/LiDAR/data/databases/Flat_SIM.db"; + + public: + LiDARHandlerTests() = default; + ~LiDARHandlerTests() override = default; + + void TestSetup() override {} + + void TestTeardown() override {} +}; + +/****************************************************************************** + * @brief Confirm that handler opens the database correctly. + * + * + * @author Eli Byrd (edbgkk@mst.edu) + * @date 2025-05-20 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, CanInitializeWithValidDB) +{ + LiDARHandler handler; + EXPECT_TRUE(handler.OpenDB(m_szDbPath)); +} + +/****************************************************************************** + * @brief Confirm that initialization fails with nonexistent DB. + * + * @author Eli Byrd (edbgkk@mst.edu) + * @date 2025-05-20 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, FailsToInitializeInvalidDB) +{ + LiDARHandler handler; + EXPECT_FALSE(handler.OpenDB("invalid/path/to.db")); +} + +/****************************************************************************** + * @brief Confirm that handler can close the database. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, CanCloseDB) +{ + LiDARHandler handler; + EXPECT_TRUE(handler.OpenDB(m_szDbPath)); + EXPECT_TRUE(handler.CloseDB()); + EXPECT_FALSE(handler.IsDBOpen()); +} + +/****************************************************************************** + * @brief Confirm that closing without opening is safe. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, CloseDBWithoutOpenIsSafe) +{ + LiDARHandler handler; + EXPECT_TRUE(handler.CloseDB()); + EXPECT_FALSE(handler.IsDBOpen()); +} + +/****************************************************************************** + * @brief Confirm that double open closes previous and opens new DB. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, DoubleOpenClosesPrevious) +{ + LiDARHandler handler; + EXPECT_TRUE(handler.OpenDB(m_szDbPath)); + // Open again with same path, should close and reopen + EXPECT_TRUE(handler.OpenDB(m_szDbPath)); + EXPECT_TRUE(handler.IsDBOpen()); +} + +/****************************************************************************** + * @brief Confirm that double close is safe. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, DoubleCloseIsSafe) +{ + LiDARHandler handler; + EXPECT_TRUE(handler.OpenDB(m_szDbPath)); + EXPECT_TRUE(handler.CloseDB()); + EXPECT_TRUE(handler.CloseDB()); +} + +/****************************************************************************** + * @brief Query returns empty if DB not open. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, QueryWithoutOpenReturnsEmpty) +{ + LiDARHandler handler; + LiDARHandler::PointFilter filter{.dEasting = 0, .dNorthing = 0, .dRadius = 1.0}; + std::vector vResults = handler.GetLiDARData(filter); + EXPECT_TRUE(vResults.empty()); +} + +/****************************************************************************** + * @brief Query returns results if present. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, QueryReturnsResultsIfPresent) +{ + LiDARHandler handler; + ASSERT_TRUE(handler.OpenDB(m_szDbPath)); + LiDARHandler::PointFilter filter{.dEasting = 614058.84, .dNorthing = 4189968.85, .dRadius = 3.0}; + std::vector vResults = handler.GetLiDARData(filter); + // Can't guarantee DB contents, but should not crash + SUCCEED(); +} + +/****************************************************************************** + * @brief Query with classification filter. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, QueryWithClassification) +{ + LiDARHandler handler; + ASSERT_TRUE(handler.OpenDB(m_szDbPath)); + LiDARHandler::PointFilter filter{.dEasting = 614058.84, .dNorthing = 4189968.85, .dRadius = 3.0, .szClassification = std::optional("ground")}; + std::vector vResults = handler.GetLiDARData(filter); + // Should not crash, may be empty + SUCCEED(); +} + +/****************************************************************************** + * @brief Query with traversal score range filter. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, QueryWithTraversalScoreRange) +{ + LiDARHandler handler; + ASSERT_TRUE(handler.OpenDB(m_szDbPath)); + LiDARHandler::PointFilter filter{.dEasting = 614058.84, + .dNorthing = 4189968.85, + .dRadius = 3.0, + .dTraversalScore = std::optional>({0.95, 1.0})}; + std::vector vResults = handler.GetLiDARData(filter); + // Should not crash, may be empty + SUCCEED(); +} + +/****************************************************************************** + * @brief Query with all range filters. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, QueryWithAllRangeFilters) +{ + LiDARHandler handler; + ASSERT_TRUE(handler.OpenDB(m_szDbPath)); + LiDARHandler::PointFilter stFilter{ + .dEasting = 614058.84, + .dNorthing = 4189968.85, + .dRadius = 3.0, + .dNormalX = std::optional>({-1.0, 1.0}), + .dNormalY = std::optional>({-1.0, 1.0}), + .dNormalZ = std::optional>({-1.0, 1.0}), + .dSlope = std::optional>({0.0, 90.0}), + .dRoughness = std::optional>({0.0, 10.0}), + .dCurvature = std::optional>({-10.0, 10.0}), + .dTraversalScore = std::optional>({0.0, 1.0}), + }; + std::vector vResults = handler.GetLiDARData(stFilter); + SUCCEED(); +} + +/****************************************************************************** + * @brief Check thread safety of open/close/query operations. + * + * + * @author clayjay3 (claytonraycowen@gmail.com) + * @date 2025-07-14 + ******************************************************************************/ +TEST_F(LiDARHandlerTests, ThreadSafetyOpenCloseQuery) +{ + LiDARHandler handler; + std::function fnOpenClose = [&handler, this]() + { + for (int i = 0; i < 5; ++i) + { + handler.OpenDB(m_szDbPath); + handler.CloseDB(); + } + }; + std::function fnQuery = [&handler, this]() + { + for (int i = 0; i < 5; ++i) + { + handler.OpenDB(m_szDbPath); + LiDARHandler::PointFilter filter{.dEasting = 614058.84, .dNorthing = 4189968.85, .dRadius = 3.0}; + handler.GetLiDARData(filter); + handler.CloseDB(); + } + }; + std::thread thThread1(fnOpenClose); + std::thread thThread2(fnQuery); + thThread1.join(); + thThread2.join(); + SUCCEED(); +} \ No newline at end of file