From c9f092e8e9909745390ef193382d4a079ef75db7 Mon Sep 17 00:00:00 2001 From: Francisco Paisana Date: Wed, 27 Nov 2019 17:32:57 +0000 Subject: [PATCH] created a nullsink and a TESTASSERT for C --- lib/include/srslte/common/test_common.h | 75 +++++++++++++++++++++++- lib/test/common/CMakeLists.txt | 4 ++ lib/test/common/test_common_test.cc | 78 +++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 lib/test/common/test_common_test.cc diff --git a/lib/include/srslte/common/test_common.h b/lib/include/srslte/common/test_common.h index 3f1a3764b..b4a1cf4b0 100644 --- a/lib/include/srslte/common/test_common.h +++ b/lib/include/srslte/common/test_common.h @@ -22,9 +22,12 @@ #ifndef SRSLTE_TEST_COMMON_H #define SRSLTE_TEST_COMMON_H +#include "srslte/config.h" + +#ifdef __cplusplus + #include "srslte/common/log.h" #include "srslte/common/log_filter.h" -#include "srslte/config.h" #include namespace srslte { @@ -96,6 +99,62 @@ private: }; srslte::log* scoped_tester_log::current_log = nullptr; +// specialization of scoped_tester_log to store last logged message +class nullsink_log : public scoped_tester_log +{ +public: + explicit nullsink_log(std::string layer) : scoped_tester_log(std::move(layer)) {} + + void debug(const char* message, ...) override __attribute__((format(printf, 2, 3))) + { + va_list args; + va_start(args, message); + log_va_list(LOG_LEVEL_DEBUG, message, args); + } + + void info(const char* message, ...) override __attribute__((format(printf, 2, 3))) + { + va_list args; + va_start(args, message); + log_va_list(LOG_LEVEL_INFO, message, args); + } + + void warning(const char* message, ...) override __attribute__((format(printf, 2, 3))) + { + warn_counter++; + va_list args; + va_start(args, message); + log_va_list(LOG_LEVEL_WARNING, message, args); + } + + void error(const char* message, ...) override __attribute__((format(printf, 2, 3))) + { + error_counter++; + va_list args; + va_start(args, message); + log_va_list(LOG_LEVEL_ERROR, message, args); + if (exit_on_error) { + exit(-1); + } + } + + srslte::LOG_LEVEL_ENUM last_log_level = LOG_LEVEL_NONE; + std::string last_log_msg; + +private: + void log_va_list(srslte::LOG_LEVEL_ENUM loglevel, const char* message, va_list argp) + { + last_log_level = loglevel; + if (level >= loglevel) { + char args_msg[char_buff_size]; + if (vsnprintf(args_msg, char_buff_size, message, argp) > 0) { + last_log_msg = args_msg; + } + } + va_end(argp); + } +}; + } // namespace srslte #define TESTERROR(fmt, ...) \ @@ -126,4 +185,18 @@ srslte::log* scoped_tester_log::current_log = nullptr; #define TESTASSERT(cond) CONDERROR((not(cond)), "[%s][Line %d] Fail at \"%s\"\n", __FUNCTION__, __LINE__, (#cond)) +#else // if C + +#include + +#define TESTASSERT(cond) \ + do { \ + if (!(cond)) { \ + printf("[%s][Line %d] Fail at \"%s\"\n", __FUNCTION__, __LINE__, (#cond)); \ + return -1; \ + } \ + } while (0) + +#endif // __cplusplus + #endif // SRSLTE_TEST_COMMON_H diff --git a/lib/test/common/CMakeLists.txt b/lib/test/common/CMakeLists.txt index 4dd18601c..5f4b5873a 100644 --- a/lib/test/common/CMakeLists.txt +++ b/lib/test/common/CMakeLists.txt @@ -85,3 +85,7 @@ add_test(timer_test timer_test) add_executable(network_utils_test network_utils_test.cc) target_link_libraries(network_utils_test srslte_common ${SCTP_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) add_test(network_utils_test network_utils_test) + +add_executable(test_common_test test_common_test.cc) +target_link_libraries(test_common_test srslte_common) +add_test(test_common_test test_common_test) \ No newline at end of file diff --git a/lib/test/common/test_common_test.cc b/lib/test/common/test_common_test.cc new file mode 100644 index 000000000..ac8e0d197 --- /dev/null +++ b/lib/test/common/test_common_test.cc @@ -0,0 +1,78 @@ +/* + * Copyright 2013-2019 Software Radio Systems Limited + * + * This file is part of srsLTE. + * + * srsLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "srslte/common/test_common.h" + +int test_nullsink_log() +{ + // Description: Test nullsink_log that only stores the last log message in a local std::string that can be checked + // This logger is useful to confirm that a certain action produced an expected error/warning, + // without contaminating the console/log file + srslte::nullsink_log null_logger{"TEST"}; + + TESTASSERT(srslte::scoped_tester_log::get_instance() == &null_logger); + + TESTASSERT(null_logger.error_counter == 0); + TESTASSERT(null_logger.last_log_level == srslte::LOG_LEVEL_NONE); + TESTASSERT(null_logger.last_log_msg.empty()); + null_logger.error("ERROR MESSAGE"); // This message should not be seen in the console + TESTASSERT(null_logger.error_counter == 1); + TESTASSERT(null_logger.last_log_level == srslte::LOG_LEVEL_ERROR); + TESTASSERT(null_logger.last_log_msg == "ERROR MESSAGE"); + + return SRSLTE_SUCCESS; +} + +int test_log_scoping() +{ + // Description: Test whether we can use different global TEST loggers in different scopes + // on scope exit the previous logger should be recovered + // This behavior is useful for the cases we have one generic logger for all tests, but in a specific test + // we want to use a different one + srslte::nullsink_log logger1("TEST1"); + TESTASSERT(srslte::scoped_tester_log::get_instance() == &logger1); + + logger1.error("message1"); + logger1.error("message2"); + TESTASSERT(logger1.last_log_msg == "message2"); + + { + // the global test log should be overwriten here, and used by TESTASSERT macro + srslte::nullsink_log logger2("TEST2"); + TESTASSERT(srslte::scoped_tester_log::get_instance() == &logger2); + TESTASSERT(logger2.error_counter == 0); + logger2.error("error message in logger2\n"); + TESTASSERT(logger2.last_log_msg == "error message in logger2\n"); + TESTASSERT(logger2.error_counter == 1); + } + // the last logger should be recovered + + TESTASSERT(srslte::scoped_tester_log::get_instance() == &logger1); + TESTASSERT(logger1.error_counter == 2); + return 0; +} + +int main() +{ + TESTASSERT(test_nullsink_log() == 0); + TESTASSERT(test_log_scoping() == 0); + return 0; +}