diff --git a/inc/dmod.h b/inc/dmod.h index 32d0ba4a..9b0180ac 100644 --- a/inc/dmod.h +++ b/inc/dmod.h @@ -116,6 +116,7 @@ DMOD_BUILTIN_API( Dmod, 1.0, Dmod_Context_t*, _LoadModule, (const char* FilePath * Call this also after changing the module search path configuration. */ DMOD_BUILTIN_API( Dmod, 1.0, void , _InvalidateModuleSearchPaths, (void) ); +DMOD_BUILTIN_API( Dmod, 1.0, bool , _ModuleExists, (const char* ModuleName) ); DMOD_BUILTIN_API( Dmod, 1.0, bool , _FindModuleFile, (const char* ModuleName, const char* ArchName, char* outFilePath, size_t MaxLength) ); DMOD_BUILTIN_API( Dmod, 1.0, bool , _FindMatch, (const char* PartialName, char* outModuleName, size_t MaxLength) ); DMOD_BUILTIN_API( Dmod, 1.0, Dmod_Context_t*, _LoadModuleByName, (const char* ModuleName) ); diff --git a/src/system/dmod_system.c b/src/system/dmod_system.c index faefbe14..f5d922f0 100644 --- a/src/system/dmod_system.c +++ b/src/system/dmod_system.c @@ -580,6 +580,28 @@ Dmod_Context_t* Dmod_LoadFromPackage( const char* PackageName, const char* Modul return context; } +/** + * @brief Check if a module exists in known locations + * + * This function searches all module search paths (including packages) to check + * if a module with the given name exists. It uses the same search logic as + * module loading but does not attempt to load the module. + * + * @param ModuleName Name of the module to check + * + * @return True if module exists, false otherwise + */ +bool Dmod_ModuleExists(const char* ModuleName) +{ + if( ModuleName == NULL ) + { + return false; + } + + char filePath[256]; + return Dmod_FindModuleFile(ModuleName, NULL, filePath, sizeof(filePath)); +} + /** * @brief Find module file in repositories * diff --git a/tests/system/if/CMakeLists.txt b/tests/system/if/CMakeLists.txt index c7ca4821..4d9427c7 100644 --- a/tests/system/if/CMakeLists.txt +++ b/tests/system/if/CMakeLists.txt @@ -16,6 +16,7 @@ set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_module_log_level.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_log_step.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_str_merge.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_module_exists.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests_dmod_reboot.cpp PARENT_SCOPE ) diff --git a/tests/system/if/tests_dmod_module_exists.cpp b/tests/system/if/tests_dmod_module_exists.cpp new file mode 100644 index 00000000..c1534ea1 --- /dev/null +++ b/tests/system/if/tests_dmod_module_exists.cpp @@ -0,0 +1,76 @@ +/** + * MIT License + * + * Copyright (c) 2025 patryk.kubiak90@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * @brief Tests for Dmod_ModuleExists function + * @date 24 Oct 2026 + * + * @file tests_dmod_module_exists.cpp + * @version 0.1 + */ +#define DMOD_PRIVATE +#include +#include "dmod.h" + +/** + * @brief Test for Dmod_ModuleExists with NULL module name + */ +TEST(DmodModuleExistsTest, NullModuleName) +{ + bool result = Dmod_ModuleExists(NULL); + ASSERT_FALSE(result); +} + +/** + * @brief Test for Dmod_ModuleExists with empty module name + */ +TEST(DmodModuleExistsTest, EmptyModuleName) +{ + bool result = Dmod_ModuleExists(""); + ASSERT_FALSE(result); +} + +/** + * @brief Test for Dmod_ModuleExists with non-existent module + */ +TEST(DmodModuleExistsTest, NonExistentModule) +{ + bool result = Dmod_ModuleExists("definitely_nonexistent_module_12345"); + ASSERT_FALSE(result); +} + +/** + * @brief Test for Dmod_ModuleExists with existing module + * + * This test verifies the function doesn't crash with a valid module name. + * The result depends on whether dmsystem is available in the search paths. + */ +TEST(DmodModuleExistsTest, ExistingModule) +{ + char outPath[256]; + bool foundViaFind = Dmod_FindModuleFile("dmsystem", NULL, outPath, sizeof(outPath)); + + bool result = Dmod_ModuleExists("dmsystem"); + + // Dmod_ModuleExists should return the same result as Dmod_FindModuleFile + ASSERT_EQ(result, foundViaFind); +}