/** * @file basic_test.cpp * @brief Minimal unit tests using standard library assert() only. * * Tests each module: Logger, ConfigManager, DataManager, Utils, * DataProcessor, and CommandLineAdapter. */ #include #include #include #include #include // Include all module headers #include "logger.hpp" #include "configmanager.hpp" #include "datamanager.hpp" #include "utils.hpp" #include "processor.hpp" #include "adapter.hpp" /// @brief Test the Logger module. static void test_logger() { Logger logger(LogLevel::DEBUG); assert(logger.level() == LogLevel::DEBUG); // Changing level should work logger.setLevel(LogLevel::WARN); assert(logger.level() == LogLevel::WARN); // Logging at a lower level should not crash; we just test no throw logger.debug("this should be suppressed"); logger.info("this should be suppressed"); logger.warn("this should appear"); logger.error("this should appear"); std::cout << "[PASS] test_logger\n"; } /// @brief Test the ConfigManager module. static void test_configmanager() { // Create a temporary config file in memory using stringstream // We'll use loadFrom with a real file path; write a small tmp file { std::ofstream tmp("test_config.txt"); tmp << "# Comment line\n" << "app.name = MyApp\n" << "log.level = 2\n" << "enable.cache = true\n" << " empty.value = \n"; } ConfigManager cfg; bool ok = cfg.loadFrom("test_config.txt"); assert(ok); assert(cfg.getString("app.name") == "MyApp"); assert(cfg.getInt("log.level") == 2); assert(cfg.getBool("enable.cache") == true); assert(cfg.hasKey("app.name")); assert(!cfg.hasKey("nonexistent")); // Test default values assert(cfg.getString("missing", "default") == "default"); assert(cfg.getInt("missing", 42) == 42); assert(cfg.getBool("missing", true) == true); // Clean up std::remove("test_config.txt"); std::cout << "[PASS] test_configmanager\n"; } /// @brief Test the DataManager module. static void test_datamanager() { DataManager dm; assert(dm.size() == 0); dm.store("key1", std::any(42)); assert(dm.exists("key1")); assert(dm.size() == 1); auto val = dm.load("key1"); assert(val != nullptr); assert(std::any_cast(*val) == 42); bool removed = dm.remove("key1"); assert(removed); assert(!dm.exists("key1")); assert(dm.size() == 0); dm.clear(); assert(dm.size() == 0); std::cout << "[PASS] test_datamanager\n"; } /// @brief Test the Utils module. static void test_utils() { std::string s = " hello world "; utils::trim(s); assert(s == "hello world"); auto parts = utils::split("a,b,c", ','); assert(parts.size() == 3); assert(parts[0] == "a"); assert(parts[1] == "b"); assert(parts[2] == "c"); std::string mixed = "HeLLo"; utils::toLower(mixed); assert(mixed == "hello"); assert(!utils::currentTimestamp().empty()); assert(utils::fileName("/path/to/file.txt") == "file.txt"); assert(utils::fileExtension("/path/to/file.txt") == "txt"); assert(utils::fileExtension("noext") == ""); std::cout << "[PASS] test_utils\n"; } /// @brief Test the DataProcessor module. static void test_processor() { auto logger = std::make_shared(LogLevel::ERROR); DataProcessor proc(logger); ProcessResult res = proc.process(std::any(123)); assert(res.success); assert(res.code == 0); // Ensure output_data contains the input pass-through assert(std::any_cast(res.output_data) == 123); std::cout << "[PASS] test_processor\n"; } /// @brief Test the CommandLineAdapter module. static void test_adapter() { { const char* argv[] = {"app", "--help"}; CommandLineAdapter a(2, const_cast(argv)); CommandLineArgs args = a.parse(); assert(args.show_help); assert(!args.show_version); assert(!args.has_errors); } { const char* argv[] = {"app", "--version"}; CommandLineAdapter a(2, const_cast(argv)); CommandLineArgs args = a.parse(); assert(args.show_version); assert(!args.show_help); assert(!args.has_errors); } { const char* argv[] = {"app", "--config", "my.cfg"}; CommandLineAdapter a(3, const_cast(argv)); CommandLineArgs args = a.parse(); assert(!args.has_errors); assert(args.config_path == "my.cfg"); } { const char* argv[] = {"app", "--unknown"}; CommandLineAdapter a(2, const_cast(argv)); CommandLineArgs args = a.parse(); assert(args.has_errors); assert(!args.error_msg.empty()); } std::cout << "[PASS] test_adapter\n"; } /** * @brief Main test runner. * @return 0 on success, 1 on any assertion failure. */ int main() { std::cout << "=== Running ModularApp Unit Tests ===\n"; test_logger(); test_configmanager(); test_datamanager(); test_utils(); test_processor(); test_adapter(); std::cout << "=== ALL TESTS PASSED ===\n"; return 0; }