diff --git a/test/test_asserts.cpp b/test/test_asserts.cpp index 5721ee9..01a34cb 100644 --- a/test/test_asserts.cpp +++ b/test/test_asserts.cpp @@ -69,6 +69,26 @@ TEST(test_asserts, check_does_not_throw_if_condition_is_true) { EXPECT_NO_THROW(rcpputils::check_true(true)); } +TEST(test_asserts, assertion_exception_what_message) { + const rcpputils::AssertionException ex("assertion failed"); + EXPECT_STREQ("assertion failed", ex.what()); +} + +TEST(test_asserts, illegal_state_exception_what_message) { + const rcpputils::IllegalStateException ex("illegal state"); + EXPECT_STREQ("illegal state", ex.what()); +} + +TEST(test_asserts, assertion_exception_empty_message) { + const rcpputils::AssertionException ex(""); + EXPECT_STREQ("", ex.what()); +} + +TEST(test_asserts, illegal_state_exception_empty_message) { + const rcpputils::IllegalStateException ex(""); + EXPECT_STREQ("", ex.what()); +} + #ifndef NDEBUG TEST(test_asserts, assert_true_throws_if_condition_is_false_and_ndebug_not_set) { EXPECT_THROW(rcpputils::assert_true(false), rcpputils::AssertionException); diff --git a/test/test_env.cpp b/test/test_env.cpp index 81ca59c..b86dcd1 100644 --- a/test/test_env.cpp +++ b/test/test_env.cpp @@ -80,3 +80,11 @@ TEST(TestSetEnv, test_set_env) { "", rcpputils::get_env_var("NEW_ENV_VAR").c_str()); } + +TEST(TestSetEnv, test_set_env_empty_value) { + // Setting to empty string is distinct from unsetting. + EXPECT_TRUE(rcpputils::set_env_var("EMPTY_VALUE_VAR", "")); + EXPECT_STREQ("", rcpputils::get_env_var("EMPTY_VALUE_VAR").c_str()); + // Cleanup + EXPECT_TRUE(rcpputils::set_env_var("EMPTY_VALUE_VAR", nullptr)); +} diff --git a/test/test_filesystem_helper.cpp b/test/test_filesystem_helper.cpp index 01bcfb2..793b75d 100644 --- a/test/test_filesystem_helper.cpp +++ b/test/test_filesystem_helper.cpp @@ -16,6 +16,7 @@ #include #include +#include #include "rcpputils/filesystem_helper.hpp" #include "rcpputils/env.hpp" @@ -99,3 +100,41 @@ TEST(TestFilesystemHelper, create_temporary_directory) EXPECT_EQ(tmpdir_template_in_name.filename().string().rfind("base_", 0), 0u); } } + +TEST(TestFilesystemHelper, create_temporary_directory_default_parent) +{ + // When no parent_path is provided the function should use std::filesystem::temp_directory_path. + const auto tmpdir = rcpputils::fs::create_temporary_directory("default_parent_test"); + EXPECT_TRUE(std::filesystem::exists(tmpdir)); + EXPECT_TRUE(std::filesystem::is_directory(tmpdir)); + // The parent must be the system temp directory. + // Normalize both sides to remove any trailing separator before comparing + // (std::filesystem::temp_directory_path() appends a trailing slash on Windows + // while path::parent_path() does not). + const std::filesystem::path expected_parent = + std::filesystem::path(std::filesystem::temp_directory_path().generic_string()); + const std::filesystem::path actual_parent = + std::filesystem::path(tmpdir.parent_path().generic_string()); + EXPECT_EQ(actual_parent, expected_parent); + EXPECT_TRUE(std::filesystem::remove_all(tmpdir)); +} + +TEST(TestFilesystemHelper, create_temporary_directory_unique_per_call) +{ + // Multiple calls with the same base_name must produce different paths. + constexpr int kNumDirs = 5; + std::vector dirs; + dirs.reserve(kNumDirs); + for (int i = 0; i < kNumDirs; ++i) { + dirs.push_back(rcpputils::fs::create_temporary_directory("unique_test")); + } + // All paths must be distinct. + for (int i = 0; i < kNumDirs; ++i) { + for (int j = i + 1; j < kNumDirs; ++j) { + EXPECT_NE(dirs[i], dirs[j]); + } + } + for (const auto & d : dirs) { + std::filesystem::remove_all(d); + } +} diff --git a/test/test_process.cpp b/test/test_process.cpp index 9b276c7..74350c3 100644 --- a/test/test_process.cpp +++ b/test/test_process.cpp @@ -21,3 +21,8 @@ TEST(TestProcess, test_get_executable_name) { EXPECT_EQ("test_process", rcpputils::get_executable_name()); } + +TEST(TestProcess, test_get_executable_name_consistent) { + // Calling twice must return the same value. + EXPECT_EQ(rcpputils::get_executable_name(), rcpputils::get_executable_name()); +} diff --git a/test/test_shared_library.cpp b/test/test_shared_library.cpp index 328a33f..3b992a1 100644 --- a/test/test_shared_library.cpp +++ b/test/test_shared_library.cpp @@ -82,6 +82,47 @@ TEST(test_shared_library, failed_test) { } } +TEST(test_shared_library, has_symbol_string_overload) { + const std::string library_name = rcpputils::get_platform_library_name("dummy_shared_library"); + auto library = std::make_shared(library_name); + + // Positive: string overload delegates to const char* overload. + EXPECT_TRUE(library->has_symbol(std::string("print_name"))); + + // Negative: missing symbol via string overload. + EXPECT_FALSE(library->has_symbol(std::string("nonexistent_symbol_xyz"))); +} + +TEST(test_shared_library, get_symbol_string_overload_throws_on_missing) { + const std::string library_name = rcpputils::get_platform_library_name("dummy_shared_library"); + auto library = std::make_shared(library_name); + + EXPECT_THROW( + library->get_symbol(std::string("nonexistent_symbol_xyz")), + std::runtime_error); +} + +TEST(test_shared_library, get_library_path_non_empty) { + const std::string library_name = rcpputils::get_platform_library_name("dummy_shared_library"); + auto library = std::make_shared(library_name); + EXPECT_FALSE(library->get_library_path().empty()); +} + +TEST(test_get_platform_library_name, release_name_contains_library_name) { + const std::string name = rcpputils::get_platform_library_name("mylib", false); + EXPECT_NE(name.find("mylib"), std::string::npos); + EXPECT_FALSE(name.empty()); +} + +TEST(test_get_platform_library_name, debug_and_release_differ_or_equal) { + // On some platforms (e.g. Windows) debug builds append a 'd' suffix. + // We only verify both calls succeed and return non-empty strings. + const std::string release_name = rcpputils::get_platform_library_name("mylib", false); + const std::string debug_name = rcpputils::get_platform_library_name("mylib", true); + EXPECT_FALSE(release_name.empty()); + EXPECT_FALSE(debug_name.empty()); +} + TEST(test_get_platform_library_name, failed_test) { // create a string bigger than the internal buffer std::string str(2000, 'A'); diff --git a/test/test_thread_name.cpp b/test/test_thread_name.cpp index 53da149..4acf633 100644 --- a/test/test_thread_name.cpp +++ b/test/test_thread_name.cpp @@ -22,6 +22,19 @@ TEST(TestOsThread, set_thread_name) { EXPECT_STREQ("test_thread", rcpputils::get_thread_name().c_str()); } +TEST(TestOsThread, set_thread_name_empty) { + // Setting an empty name must not throw and get_thread_name must return empty string. + EXPECT_NO_THROW(rcpputils::set_thread_name("")); + EXPECT_STREQ("", rcpputils::get_thread_name().c_str()); +} + +TEST(TestOsThread, get_thread_name_returns_string) { + rcpputils::set_thread_name("abc"); + const std::string name = rcpputils::get_thread_name(); + EXPECT_FALSE(name.empty()); + EXPECT_STREQ("abc", name.c_str()); +} + #if defined(_WIN32) TEST(TestOsThread, no_truncation_on_windows) { rcpputils::set_thread_name("0123456789abcdef"); @@ -29,6 +42,13 @@ TEST(TestOsThread, no_truncation_on_windows) { // Should be unaffected by truncation EXPECT_STREQ("0123456789abcdef", rcpputils::get_thread_name().c_str()); } + +TEST(TestOsThread, exact_max_length_no_truncation_windows) { + // 15 chars is well within the Windows limit; no truncation expected. + const std::string name_15(15, 'x'); + rcpputils::set_thread_name(name_15); + EXPECT_EQ(rcpputils::get_thread_name(), name_15); +} #elif defined(__APPLE__) TEST(TestOsThread, truncation_on_apple) { rcpputils::set_thread_name( @@ -38,6 +58,13 @@ TEST(TestOsThread, truncation_on_apple) { EXPECT_STREQ("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde", rcpputils::get_thread_name().c_str()); } + +TEST(TestOsThread, exact_max_length_no_truncation_apple) { + // Exactly 63 chars (MAXTHREADNAMESIZE - 1): must not be truncated. + const std::string name_63(63, 'y'); + rcpputils::set_thread_name(name_63); + EXPECT_EQ(rcpputils::get_thread_name(), name_63); +} #else // posix TEST(TestOsThread, truncation_on_posix) { rcpputils::set_thread_name("0123456789abcdef"); @@ -45,4 +72,18 @@ TEST(TestOsThread, truncation_on_posix) { // Should be 15 characters and then the null terminator EXPECT_STREQ("0123456789abcde", rcpputils::get_thread_name().c_str()); } + +TEST(TestOsThread, exact_max_length_no_truncation_posix) { + // Exactly 15 chars (MAXTHREADNAMESIZE - 1): must not be truncated. + const std::string name_15(15, 'z'); + rcpputils::set_thread_name(name_15); + EXPECT_EQ(rcpputils::get_thread_name(), name_15); +} + +TEST(TestOsThread, one_less_than_max_no_truncation_posix) { + // 14 chars is under the limit; returned name must be identical. + const std::string name_14(14, 'w'); + rcpputils::set_thread_name(name_14); + EXPECT_EQ(rcpputils::get_thread_name(), name_14); +} #endif