From e7f4b7ebbc9108ab4ae46d30c6ab122d98732c8e Mon Sep 17 00:00:00 2001 From: Oliver Ruebel Date: Wed, 15 Jan 2025 11:30:52 -0800 Subject: [PATCH] Add unit tests for Utils.hpp (#137) --- src/Utils.hpp | 14 +++++- tests/CMakeLists.txt | 1 + tests/testUtilsFunctions.cpp | 91 ++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 tests/testUtilsFunctions.cpp diff --git a/src/Utils.hpp b/src/Utils.hpp index 7271a5f7..eb113fc7 100644 --- a/src/Utils.hpp +++ b/src/Utils.hpp @@ -101,11 +101,16 @@ static inline std::string mergePaths(const std::string& path1, while (start < path2.size() && path2[start] == '/') { start++; } + // Get path2 without trailing slashes + std::string path2Clean = path2.substr(start); + while (!path2Clean.empty() && path2Clean.back() == '/' && path2Clean != "/") { + path2Clean.pop_back(); + } // Append path2 to path1 with a "/" in between - if (!result.empty()) { + if (!result.empty() && !path2Clean.empty()) { result += '/'; } - result += path2.substr(start); + result += path2Clean; // Remove any potential occurrences of "//" and replace with "/" size_t pos = result.find("//"); @@ -114,6 +119,11 @@ static inline std::string mergePaths(const std::string& path1, pos = result.find("//", pos); } + // Remove trailing "/" from final result if not root path + while (!result.empty() && result.back() == '/' && result != "/") { + result.pop_back(); + } + return result; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c11a2242..c5288219 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,6 +22,7 @@ add_executable(aqnwb_test testRecordingWorkflow.cpp testRegisteredType.cpp testTimeSeries.cpp + testUtilsFunctions.cpp testVectorData.cpp examples/test_HDF5IO_examples.cpp examples/test_example.cpp diff --git a/tests/testUtilsFunctions.cpp b/tests/testUtilsFunctions.cpp new file mode 100644 index 00000000..3a538f5f --- /dev/null +++ b/tests/testUtilsFunctions.cpp @@ -0,0 +1,91 @@ +#include + +#include "testUtils.hpp" + +#include "Utils.hpp" + +TEST_CASE("Test UUID generation", "[utils]") +{ + // Test that generated UUIDs are valid + std::string uuid = AQNWB::generateUuid(); + + // UUID format regex (8-4-4-4-12 hex digits) + std::regex uuidRegex( + "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"); + + SECTION("UUID format is valid") + { + REQUIRE(std::regex_match(uuid, uuidRegex)); + } + + SECTION("UUIDs are unique") + { + std::string uuid2 = AQNWB::generateUuid(); + REQUIRE(uuid != uuid2); + } +} + +TEST_CASE("Test current time format", "[utils]") +{ + std::string time = AQNWB::getCurrentTime(); + + // ISO 8601 format regex with timezone offset + std::regex timeRegex( + "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{6}[+-]\\d{2}:\\d{2}$"); + + SECTION("Time format is valid ISO 8601") + { + REQUIRE(std::regex_match(time, timeRegex)); + } +} + +TEST_CASE("Test IO creation", "[utils]") +{ + std::string testFile = getTestFilePath("test_createIO.h5"); + + SECTION("Create HDF5 IO") + { + REQUIRE_NOTHROW(AQNWB::createIO("HDF5", testFile)); + auto io = AQNWB::createIO("HDF5", testFile); + REQUIRE(io != nullptr); + } + + SECTION("Invalid IO type throws") + { + REQUIRE_THROWS_AS(AQNWB::createIO("INVALID", testFile), + std::invalid_argument); + } +} + +TEST_CASE("Test path merging", "[utils]") +{ + SECTION("Basic path merging") + { + REQUIRE(AQNWB::mergePaths("path1", "path2") == "path1/path2"); + REQUIRE(AQNWB::mergePaths("/path1", "path2") == "/path1/path2"); + REQUIRE(AQNWB::mergePaths("path1/", "/path2") == "path1/path2"); + REQUIRE(AQNWB::mergePaths("/path1/", "/path2/") == "/path1/path2"); + REQUIRE(AQNWB::mergePaths("/path1/", "path2/") == "/path1/path2"); + } + + SECTION("Handle empty paths") + { + REQUIRE(AQNWB::mergePaths("", "path2") == "path2"); + REQUIRE(AQNWB::mergePaths("path1", "") == "path1"); + REQUIRE(AQNWB::mergePaths("", "") == ""); + REQUIRE(AQNWB::mergePaths("/", "") == "/"); + } + + SECTION("Handle root paths") + { + REQUIRE(AQNWB::mergePaths("/", "path2") == "/path2"); + REQUIRE(AQNWB::mergePaths("/", "/path2") == "/path2"); + REQUIRE(AQNWB::mergePaths("/", "/") == "/"); + } + + SECTION("Remove duplicate slashes") + { + REQUIRE(AQNWB::mergePaths("path1//", "//path2") == "path1/path2"); + REQUIRE(AQNWB::mergePaths("path1///", "///path2") == "path1/path2"); + } +}