diff --git a/CMakeLists.txt b/CMakeLists.txt index ec4a305..ec7b848 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,38 +31,17 @@ if (CMAKE_CROSSCOMPILING) message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") endif() -include_directories(./include) +include_directories(${CMAKE_SOURCE_DIR}/include) +aux_source_directory(${CMAKE_SOURCE_DIR}/src SRC_LIST) -aux_source_directory(./src SRC_LIST) - -add_library(exint_static STATIC ${SRC_LIST}) add_library(exint SHARED ${SRC_LIST}) +add_library(exint_static STATIC ${SRC_LIST}) +set_target_properties(exint_static PROPERTIES OUTPUT_NAME exint) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") target_compile_options(exint PRIVATE -Wno-nonnull -fvisibility=hidden) endif() -# 设置测试文件和公共源文件 -set(TESTS_DIR "${CMAKE_SOURCE_DIR}/tests") -set(TEST_COMMON_SOURCE "${TESTS_DIR}/c_testcase.cpp") +link_libraries(pthread) -# 查找所有以 test_ 开头的文件 -file(GLOB_RECURSE TEST_FILES "${TESTS_DIR}/test_*.cpp") - -# 循环遍历每个测试文件并创建可执行文件 -foreach(TEST_FILE ${TEST_FILES}) - # 获取文件名(不带路径和扩展名) - get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE) - - # 创建可执行文件 - add_executable(${TEST_NAME} ${TEST_FILE} ${TEST_COMMON_SOURCE} ${SRC_LIST}) - - # 将可执行文件路径添加到列表中 - list(APPEND TEST_EXECUTABLES "${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME}") -endforeach() - -enable_testing() - -add_test(NAME test - COMMAND ${CMAKE_SOURCE_DIR}/scripts/unittest.py ${TEST_EXECUTABLES} -) +subdirs(tests) diff --git a/README.md b/README.md index ca5d5eb..41a16d4 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ cmake . -B build cmake --build build -j6 ``` -使用cmake及ctest进行测试: +使用cmake调用测试脚本进行测试: ```bash cmake . -B build diff --git a/include/c_testcase.h b/include/c_testcase.h index 135c19d..295d42f 100644 --- a/include/c_testcase.h +++ b/include/c_testcase.h @@ -158,11 +158,11 @@ extern "C"{ if (memcmp((expr1), (expr2), (size)) != 0) { \ printf("assertion failed: %s == %s\n", #expr1, #expr2); \ printf("\t#0: "); \ - for (int i = 0; i < (size); i++) { \ + for (size_t i = 0; i < (size); i++) { \ printf("%02X", ((uint8_t*)(expr1))[i]); \ } \ printf("\n\t#1: "); \ - for (int i = 0; i < (size); i++) { \ + for (size_t i = 0; i < (size); i++) { \ printf("%02X", ((uint8_t*)(expr2))[i]); \ } \ printf("\nfile: \"%s\", line %d, in %s\n", __FILE__, __LINE__, __ASSERT_FUNCTION);\ diff --git a/include/logging/logger.hpp b/include/logging/logger.hpp index 70b4625..b55a847 100644 --- a/include/logging/logger.hpp +++ b/include/logging/logger.hpp @@ -74,7 +74,38 @@ public: LoggerOStream operator[](Level level); LoggerOStream operator[](int level); - Logger* get_child(const std::string& name, Level level = Level::UNKNOWN); + void move_children_to(Logger& other); + + template + Logger* get_child(const std::string& name, Level level) + { + Logger* logger; + auto sep_pos = name.find(namesep); + do { + if (name.empty() || sep_pos == 0) { + logger = this; + break; + } + std::string base_name; + if (sep_pos == std::string::npos) { + base_name = name; + } else { + base_name = name.substr(0, sep_pos); + } + auto iter = logger_cache.find(base_name); + + if (iter != logger_cache.end()) { + logger = iter->second.get(); + break; + } + logger = new T_Logger(base_name, level, this); + logger_cache[base_name] = std::unique_ptr(logger); + } while (0); + auto seqlen = strlen(namesep); + if (sep_pos == std::string::npos || sep_pos + seqlen >= name.size()) + return logger; + return logger->get_child(name.substr(sep_pos + seqlen), level); + } protected: explicit Logger(const std::string& name, Level level = Level::INFO, Logger* parent = nullptr); @@ -132,16 +163,18 @@ struct Record Record(const std::string& name, Logger::Level level, const std::string& msg); }; -std::ostream& operator<<(std::ostream& os, const Logger::Level level); -Logger::Level str2level(const char* level); - -extern std::unique_ptr global_logger; - using LogLevel = Logger::Level; +std::ostream& operator<<(std::ostream& os, const Logger::Level level); +Logger::Level str2level(const char* level); +std::unique_ptr& _get_global_logger(); +Logger& get_global_logger(); +void set_global_logger(std::unique_ptr&& logger); + +template static inline Logger* get_logger(const std::string& name, LogLevel level = LogLevel::UNKNOWN) { - return global_logger->get_child(name, level); + return _get_global_logger()->get_child(name, level); } } diff --git a/scripts/bdist.sh b/scripts/bdist.sh index f89440a..88c9ca2 100755 --- a/scripts/bdist.sh +++ b/scripts/bdist.sh @@ -2,4 +2,4 @@ mkdir -p dist zip -r "dist/exint-build-$(date +%Y%m%d-%H%M%S).zip" bin/ lib/ config/\ - scripts/ README.md \ No newline at end of file + scripts/ README.md include/external_interface.h \ No newline at end of file diff --git a/scripts/sdist.sh b/scripts/sdist.sh index 4f22106..825588b 100755 --- a/scripts/sdist.sh +++ b/scripts/sdist.sh @@ -2,4 +2,4 @@ mkdir -p dist tar -czvf "dist/exint-$(date +%Y%m%d-%H%M%S).tar.gz" src/ include/ tests/ config/\ - scripts/ toolchains/ tools/ README.md CMakeLists.txt mak .gitignore + scripts/ toolchains/ README.md CMakeLists.txt mak .gitignore diff --git a/src/external_interface.cpp b/src/external_interface.cpp index 0de7f86..e0e9665 100644 --- a/src/external_interface.cpp +++ b/src/external_interface.cpp @@ -70,7 +70,7 @@ void exint_send(uint32_t type, size_t len, void* data) { event_name = "send_audio"; break; default: - break; + return; } exint_event(event_name, len, data); } diff --git a/src/logging.cpp b/src/logging.cpp index 7d46936..efed523 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -10,8 +10,23 @@ using namespace logging; -__attribute__((__init_priority__(8192))) -std::unique_ptr logging::global_logger(new Logger(LogLevel::WARN)); +std::unique_ptr& logging::_get_global_logger() +{ + static std::unique_ptr global_logger(new Logger(LogLevel::WARN)); + return global_logger; +} + +Logger& logging::get_global_logger() +{ + return *_get_global_logger(); +} + +void logging::set_global_logger(std::unique_ptr&& logger) +{ + auto& global_logger = _get_global_logger(); + global_logger->move_children_to(*logger); + global_logger = std::move(logger); +} Logger::Logger(Level level) : _parent(nullptr), _level(level) {} @@ -186,35 +201,15 @@ LoggerOStream Logger::operator[](int level) return (*this)[static_cast(level)]; } -Logger* Logger::get_child(const std::string& name, Level level) +void Logger::move_children_to(Logger& target_logger) { - Logger* logger; - auto sep_pos = name.find(namesep); - do { - if (name.empty() || sep_pos == 0) { - logger = this; - break; - } - std::string base_name; - if (sep_pos == std::string::npos) { - base_name = name; - } else { - base_name = name.substr(0, sep_pos); - } - auto iter = logger_cache.find(base_name); - - if (iter != logger_cache.end()) { - logger = iter->second.get(); - break; - } - logger = new Logger(base_name, level, this); - (*global_logger)[Level::DEBUG] << "created logger" << logger->_name << std::endl; - logger_cache[base_name] = std::unique_ptr(logger); - } while (0); - auto seqlen = strlen(namesep); - if (sep_pos == std::string::npos || sep_pos + seqlen >= name.size()) - return logger; - return logger->get_child(name.substr(sep_pos + seqlen), level); + if (logger_cache.empty()) return; + for (auto it = logger_cache.begin(); it != logger_cache.end(); ) { + // Transfer ownership of the child logger to the target_logger + it->second->_parent = &target_logger; + target_logger.logger_cache.insert(std::move(*it)); + it = logger_cache.erase(it); // Remove from current logger's cache + } } LoggerOStream::LoggerOStream(Logger& logger, Logger::Level level) @@ -311,20 +306,17 @@ void log_init(const char* level) } else if (strcasecmp(level, "env") == 0 || strcasecmp(level, "auto") == 0) { level = getenv("LOG_LEVEL"); } - if (global_logger->children_count()) { - global_logger->warn("reseting logger with children"); - } - global_logger = std::unique_ptr(new Logger(str2level(level))); + set_global_logger(std::unique_ptr(new Logger(str2level(level)))); } int log_level() { - return static_cast(global_logger->level()); + return static_cast(_get_global_logger()->level()); } void log_set_level(int level) { - global_logger->set_level(static_cast(level)); + _get_global_logger()->set_level(static_cast(level)); } void log_log(int level, const char* fmt, ...) @@ -337,10 +329,5 @@ void log_log(int level, const char* fmt, ...) void log_vlog(int level, const char* fmt, va_list args) { - if (!global_logger) { - vfprintf(stderr, fmt, args); - fputc('\n', stderr); - return; - } - global_logger->vlog(static_cast(level), fmt, args); + _get_global_logger()->vlog(static_cast(level), fmt, args); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 0000000..d44bd1e --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.15) +project(test) + +set(TESTS_DIR .) +set(TEST_COMMON_SOURCE "${TESTS_DIR}/c_testcase.cpp") + +file(GLOB_RECURSE TEST_FILES "${TESTS_DIR}/test_*.cpp") + +foreach(TEST_FILE ${TEST_FILES}) + get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE) + add_executable(${TEST_NAME} ${TEST_FILE} ${TEST_COMMON_SOURCE} ${SRC_LIST}) + list(APPEND TEST_EXECUTABLES "${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME}") +endforeach() + +add_custom_target(test + COMMAND ${CMAKE_SOURCE_DIR}/scripts/unittest.py ${TEST_EXECUTABLES} + DEPENDS ${TEST_EXECUTABLES} +) diff --git a/tests/c_testcase.cpp b/tests/c_testcase.cpp index 7f780fe..a1d6e35 100644 --- a/tests/c_testcase.cpp +++ b/tests/c_testcase.cpp @@ -132,9 +132,7 @@ static __inline void print_separator_ex(char lc, const char* str, const char* co static int collect_testcase() { for (int i = 0; i < test_case_total; ++i) { puts(test_cases[i].name); - // putchar(' '); } - putchar('\n'); return 0; } @@ -197,6 +195,15 @@ static int unittest_testcase(TestCase* tc) { int main(int argc, const char** argv) { for (int i = 1; i < argc; ++i) { const char* arg = argv[i]; + if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { + printf("usage: %s [-c] [-u NAME] [-h]\n", argv[0]); + printf("\nOptions:\n"); + printf(" -i, --interactive: run in interactive mode.\n"); + printf(" -c, --collect: list all test cases.\n"); + printf(" -u, --unittest: run a single test case.\n"); + printf(" -h, --help: show the help text.\n"); + return 0; + } if (strcmp(arg, "-i") == 0 || strcmp(arg, "--interactive") == 0) { if (interactive) return interactive(argc, argv); diff --git a/tests/test_logging.cpp b/tests/test_logging.cpp index 8ff19b2..1b47b7b 100644 --- a/tests/test_logging.cpp +++ b/tests/test_logging.cpp @@ -5,6 +5,8 @@ using namespace logging; +static auto& module_logger = *get_logger("test_logging"); + TEST_CASE(test_init) { log_info("test_init before"); log_init(NULL); @@ -23,10 +25,18 @@ TEST_CASE(test_init) { END_TEST; } +TEST_CASE(test_module_logger) +{ + module_logger.info("test_module_logger1"); + log_init("debug"); + module_logger.info("test_module_logger2"); + END_TEST; +} + TEST_CASE(test_add_stream) { std::stringstream ss; log_init(NULL); - logging::global_logger->add_stream(ss); + get_global_logger().add_stream(ss); log_info("test_stream"); auto s = ss.str(); @@ -60,7 +70,7 @@ TEST_CASE(test_add_stream) { assert_str_eq(s.c_str() + (s.length() - 26), "[FATAL] test_stream fatal\n"); ss.str(""); - logging::global_logger->log("test_stream debug"); + get_global_logger().log("test_stream debug"); s = ss.str(); assert_str_eq(s.c_str() + (s.length() - 26), "[DEBUG] test_stream debug\n"); @@ -69,7 +79,7 @@ TEST_CASE(test_add_stream) { TEST_CASE(test_log_stream) { log_init(NULL); - auto& logger = *logging::global_logger; + auto& logger = get_global_logger(); std::stringstream ss; logger.add_stream(ss); @@ -91,7 +101,7 @@ TEST_CASE(test_sub_logger) { auto sublogger = get_logger("sublogger"); assert_eq(sublogger->level(), LogLevel::INFO); assert_eq(sublogger->name(), "sublogger"); - assert_eq(sublogger->parent(), logging::global_logger.get()); + assert_eq(sublogger->parent(), &get_global_logger()); auto subsublogger = get_logger("sublogger::subsublogger"); assert_eq(subsublogger->level(), LogLevel::INFO); @@ -104,11 +114,11 @@ TEST_CASE(test_sub_logger) { auto sub1logger = get_logger("sublogger1"); assert_eq(sub1logger->level(), LogLevel::INFO); assert_eq(sub1logger->name(), "sublogger1"); - assert_eq(sub1logger->parent(), logging::global_logger.get()); + assert_eq(sub1logger->parent(), &get_global_logger()); assert_eq(sub1sub1logger->parent(), sub1logger); auto root_logger = get_logger(""); - assert_eq(root_logger, logging::global_logger.get()); + assert_eq(root_logger, &get_global_logger()); auto root_logger1 = get_logger("::"); assert_eq(root_logger1, root_logger); auto subsublogger1 = get_logger("sublogger::subsublogger"); @@ -120,12 +130,12 @@ TEST_CASE(test_sub_logger) { auto subsublogger4 = get_logger("sublogger::::::subsublogger"); assert_eq(subsublogger4, subsublogger); - global_logger->set_level(LogLevel::DEBUG); - assert_eq(global_logger->level(), LogLevel::DEBUG); + get_global_logger().set_level(LogLevel::DEBUG); + assert_eq(get_global_logger().level(), LogLevel::DEBUG); assert_eq(sublogger->level(), LogLevel::DEBUG); assert_eq(subsublogger->level(), LogLevel::DEBUG); sublogger->set_level(LogLevel::WARN); - assert_eq(global_logger->level(), LogLevel::DEBUG); + assert_eq(get_global_logger().level(), LogLevel::DEBUG); assert_eq(sublogger->level(), LogLevel::WARN); assert_eq(subsublogger->level(), LogLevel::WARN); END_TEST; diff --git a/toolchains/armv7l_linux_setup.cmake b/toolchains/armv7l_linux_setup.cmake index db2566c..a8b8fec 100644 --- a/toolchains/armv7l_linux_setup.cmake +++ b/toolchains/armv7l_linux_setup.cmake @@ -1,5 +1,5 @@ set(CMAKE_SYSTEM_NAME Linux) set(CMAKE_SYSTEM_PROCESSOR arm) -set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc) -set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++) +set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc-9) +set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++-9)