/* * Copyright (c) 2008, Willow Garage, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Willow Garage, Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "ros/console.h" #include "log4cxx/appenderskeleton.h" #include "log4cxx/spi/loggingevent.h" #ifdef _MSC_VER // Have to be able to encode wchar LogStrings on windows. #include "log4cxx/helpers/transcoder.h" #endif #include #include #include #include #include class TestAppender : public log4cxx::AppenderSkeleton { public: struct Info { log4cxx::LevelPtr level_; std::string message_; std::string logger_name_; }; typedef std::vector V_Info; V_Info info_; protected: virtual void append(const log4cxx::spi::LoggingEventPtr& event, log4cxx::helpers::Pool&) { Info info; info.level_ = event->getLevel(); #ifdef _MSC_VER LOG4CXX_ENCODE_CHAR(msgstr, event->getMessage()); // has to handle LogString with wchar types. info.message_ = msgstr; // msgstr gets instantiated inside the LOG4CXX_ENCODE_CHAR macro LOG4CXX_ENCODE_CHAR(loggerstr, event->getLoggerName()); // has to handle LogString with wchar types. info.logger_name_ = loggerstr; // loggerstr gets instantiated inside the LOG4CXX_ENCODE_CHAR macro #else info.message_ = event->getMessage(); info.logger_name_ = event->getLoggerName(); #endif info_.push_back( info ); } virtual void close() { } virtual bool requiresLayout() const { return false; } }; LOG4CXX_PTR_DEF(TestAppender); class TestAppenderWithThrow : public log4cxx::AppenderSkeleton { protected: virtual void append(const log4cxx::spi::LoggingEventPtr&, log4cxx::helpers::Pool&) { throw std::runtime_error("This should be caught"); } virtual void close() { } virtual bool requiresLayout() const { return false; } }; struct BasicFilter : public ros::console::FilterBase { BasicFilter(bool enabled) : enabled_(enabled) {} inline virtual bool isEnabled() { return enabled_; }; bool enabled_; }; LOG4CXX_PTR_DEF(TestAppenderWithThrow); BasicFilter g_filter(true); #define DEFINE_COND_TESTS(name, macro_base, level, log4cxx_level) \ TEST(RosConsole, name##Cond) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_COND(true, "Testing %d %d %d", 1, 2, 3); \ macro_base##_COND(false, "Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##NamedCond) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_COND_NAMED(true, "test", "Testing %d %d %d", 1, 2, 3); \ macro_base##_COND_NAMED(false, "test", "Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##StreamCond) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM_COND(true, "Testing " << 1 << " " << 2 << " " << 3); \ macro_base##_STREAM_COND(false, "Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##StreamCondNamed) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM_COND_NAMED(true, "test", "Testing " << 1 << " " << 2 << " " << 3); \ macro_base##_STREAM_COND_NAMED(false, "test", "Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } #define DEFINE_ONCE_TESTS(name, macro_base, level, log4cxx_level) \ TEST(RosConsole, name##Once) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_ONCE("Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##NamedOnce) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_ONCE_NAMED("test", "Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##StreamOnce) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM_ONCE("Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##StreamOnceNamed) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM_ONCE_NAMED("test", "Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } #define DEFINE_THROTTLE_TESTS(name, macro_base, level, log4cxx_level) \ TEST(RosConsole, name##Throttle) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_THROTTLE(0.5, "Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##NamedThrottle) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_THROTTLE_NAMED(0.5, "test", "Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##StreamThrottle) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM_THROTTLE(0.5, "Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##StreamThrottleNamed) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM_THROTTLE_NAMED(0.5, "test", "Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } #define DEFINE_FILTER_TESTS(name, macro_base, level, log4cxx_level) \ TEST(RosConsole, name##Filter) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_FILTER(&g_filter, "Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##NamedFilter) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_FILTER_NAMED(&g_filter, "test", "Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##StreamFilter) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM_FILTER(&g_filter, "Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##StreamFilterNamed) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM_FILTER_NAMED(&g_filter, "test", "Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } #define DEFINE_LEVEL_TESTS(name, macro_base, level, log4cxx_level) \ TEST(RosConsole, name) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base("Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##Named) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_NAMED("test", "Testing %d %d %d", 1, 2, 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##Stream) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM("Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ TEST(RosConsole, name##StreamNamed) \ { \ auto appender = TestAppenderPtr(new TestAppender); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->addAppender( appender ); \ macro_base##_STREAM_NAMED("test", "Testing " << 1 << " " << 2 << " " << 3); \ ASSERT_EQ((int)appender->info_.size(), 1); \ EXPECT_STREQ(appender->info_[0].message_.c_str(), "Testing 1 2 3"); \ EXPECT_EQ(appender->info_[0].level_, log4cxx_level); \ EXPECT_STREQ(appender->info_[0].logger_name_.c_str(), ROSCONSOLE_ROOT_LOGGER_NAME".rosconsole.test"); \ log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME)->removeAppender( appender ); \ } \ DEFINE_COND_TESTS(name, macro_base, level, log4cxx_level) \ DEFINE_ONCE_TESTS(name, macro_base, level, log4cxx_level) \ DEFINE_THROTTLE_TESTS(name, macro_base, level, log4cxx_level) \ DEFINE_FILTER_TESTS(name, macro_base, level, log4cxx_level) DEFINE_LEVEL_TESTS(debug, ROS_DEBUG, ros::console::levels::Debug, log4cxx::Level::getDebug()) DEFINE_LEVEL_TESTS(info, ROS_INFO, ros::console::levels::Info, log4cxx::Level::getInfo()) DEFINE_LEVEL_TESTS(warn, ROS_WARN, ros::console::levels::Warn, log4cxx::Level::getWarn()) DEFINE_LEVEL_TESTS(error, ROS_ERROR, ros::console::levels::Error, log4cxx::Level::getError()) DEFINE_LEVEL_TESTS(fatal, ROS_FATAL, ros::console::levels::Fatal, log4cxx::Level::getFatal()) TEST(RosConsole, loggingLevels) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender( appender ); int pre_count = 0; int post_count = 0; { logger->setLevel( log4cxx::Level::getInfo() ); pre_count = appender->info_.size(); ROS_DEBUG("test"); ROS_INFO("test"); ROS_WARN("test"); ROS_ERROR("test"); ROS_FATAL("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 4); logger->setLevel( log4cxx::Level::getWarn() ); pre_count = appender->info_.size(); ROS_DEBUG("test"); ROS_INFO("test"); ROS_WARN("test"); ROS_ERROR("test"); ROS_FATAL("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 3); logger->setLevel( log4cxx::Level::getError() ); pre_count = appender->info_.size(); ROS_DEBUG("test"); ROS_INFO("test"); ROS_WARN("test"); ROS_ERROR("test"); ROS_FATAL("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 2); logger->setLevel( log4cxx::Level::getFatal() ); pre_count = appender->info_.size(); ROS_DEBUG("test"); ROS_INFO("test"); ROS_WARN("test"); ROS_ERROR("test"); ROS_FATAL("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 1); logger->setLevel( log4cxx::Level::getOff() ); pre_count = appender->info_.size(); ROS_DEBUG("test"); ROS_INFO("test"); ROS_WARN("test"); ROS_ERROR("test"); ROS_FATAL("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count); } { logger->setLevel( log4cxx::Level::getInfo() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM("test"); ROS_INFO_STREAM("test"); ROS_WARN_STREAM("test"); ROS_ERROR_STREAM("test"); ROS_FATAL_STREAM("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 4); logger->setLevel( log4cxx::Level::getWarn() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM("test"); ROS_INFO_STREAM("test"); ROS_WARN_STREAM("test"); ROS_ERROR_STREAM("test"); ROS_FATAL_STREAM("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 3); logger->setLevel( log4cxx::Level::getError() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM("test"); ROS_INFO_STREAM("test"); ROS_WARN_STREAM("test"); ROS_ERROR_STREAM("test"); ROS_FATAL_STREAM("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 2); logger->setLevel( log4cxx::Level::getFatal() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM("test"); ROS_INFO_STREAM("test"); ROS_WARN_STREAM("test"); ROS_ERROR_STREAM("test"); ROS_FATAL_STREAM("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 1); logger->setLevel( log4cxx::Level::getOff() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM("test"); ROS_INFO_STREAM("test"); ROS_WARN_STREAM("test"); ROS_ERROR_STREAM("test"); ROS_FATAL_STREAM("test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count); } { logger->setLevel( log4cxx::Level::getInfo() ); pre_count = appender->info_.size(); ROS_DEBUG_NAMED("test_name", "test"); ROS_INFO_NAMED("test_name", "test"); ROS_WARN_NAMED("test_name", "test"); ROS_ERROR_NAMED("test_name", "test"); ROS_FATAL_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 4); logger->setLevel( log4cxx::Level::getWarn() ); pre_count = appender->info_.size(); ROS_DEBUG_NAMED("test_name", "test"); ROS_INFO_NAMED("test_name", "test"); ROS_WARN_NAMED("test_name", "test"); ROS_ERROR_NAMED("test_name", "test"); ROS_FATAL_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 3); logger->setLevel( log4cxx::Level::getError() ); pre_count = appender->info_.size(); ROS_DEBUG_NAMED("test_name", "test"); ROS_INFO_NAMED("test_name", "test"); ROS_WARN_NAMED("test_name", "test"); ROS_ERROR_NAMED("test_name", "test"); ROS_FATAL_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 2); logger->setLevel( log4cxx::Level::getFatal() ); pre_count = appender->info_.size(); ROS_DEBUG_NAMED("test_name", "test"); ROS_INFO_NAMED("test_name", "test"); ROS_WARN_NAMED("test_name", "test"); ROS_ERROR_NAMED("test_name", "test"); ROS_FATAL_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 1); logger->setLevel( log4cxx::Level::getOff() ); pre_count = appender->info_.size(); ROS_DEBUG_NAMED("test_name", "test"); ROS_INFO_NAMED("test_name", "test"); ROS_WARN_NAMED("test_name", "test"); ROS_ERROR_NAMED("test_name", "test"); ROS_FATAL_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count); } { logger->setLevel( log4cxx::Level::getInfo() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM_NAMED("test_name", "test"); ROS_INFO_STREAM_NAMED("test_name", "test"); ROS_WARN_STREAM_NAMED("test_name", "test"); ROS_ERROR_STREAM_NAMED("test_name", "test"); ROS_FATAL_STREAM_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 4); logger->setLevel( log4cxx::Level::getWarn() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM_NAMED("test_name", "test"); ROS_INFO_STREAM_NAMED("test_name", "test"); ROS_WARN_STREAM_NAMED("test_name", "test"); ROS_ERROR_STREAM_NAMED("test_name", "test"); ROS_FATAL_STREAM_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 3); logger->setLevel( log4cxx::Level::getError() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM_NAMED("test_name", "test"); ROS_INFO_STREAM_NAMED("test_name", "test"); ROS_WARN_STREAM_NAMED("test_name", "test"); ROS_ERROR_STREAM_NAMED("test_name", "test"); ROS_FATAL_STREAM_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 2); logger->setLevel( log4cxx::Level::getFatal() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM_NAMED("test_name", "test"); ROS_INFO_STREAM_NAMED("test_name", "test"); ROS_WARN_STREAM_NAMED("test_name", "test"); ROS_ERROR_STREAM_NAMED("test_name", "test"); ROS_FATAL_STREAM_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 1); logger->setLevel( log4cxx::Level::getOff() ); pre_count = appender->info_.size(); ROS_DEBUG_STREAM_NAMED("test_name", "test"); ROS_INFO_STREAM_NAMED("test_name", "test"); ROS_WARN_STREAM_NAMED("test_name", "test"); ROS_ERROR_STREAM_NAMED("test_name", "test"); ROS_FATAL_STREAM_NAMED("test_name", "test"); post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count); } logger->removeAppender( appender ); } TEST(RosConsole, changingLevel) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender( appender ); logger->setLevel( log4cxx::Level::getError() ); for ( int i = ros::console::levels::Debug; i < ros::console::levels::Count; ++i ) { ROS_LOG((ros::console::Level)i, ROSCONSOLE_DEFAULT_NAME, "test"); } EXPECT_EQ((int)appender->info_.size(), 2); logger->removeAppender( appender ); logger->setLevel( log4cxx::Level::getDebug() ); } TEST(RosConsole, changingLoggerLevel) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender( appender ); logger->setLevel(log4cxx::Level::getDebug()); ros::console::notifyLoggerLevelsChanged(); ROS_LOG(ros::console::levels::Debug, ROSCONSOLE_DEFAULT_NAME, "test"); logger->setLevel(log4cxx::Level::getInfo()); ros::console::notifyLoggerLevelsChanged(); ROS_LOG(ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "test"); logger->setLevel(log4cxx::Level::getWarn()); ros::console::notifyLoggerLevelsChanged(); ROS_LOG(ros::console::levels::Warn, ROSCONSOLE_DEFAULT_NAME, "test"); logger->setLevel(log4cxx::Level::getError()); ros::console::notifyLoggerLevelsChanged(); ROS_LOG(ros::console::levels::Error, ROSCONSOLE_DEFAULT_NAME, "test"); logger->setLevel(log4cxx::Level::getFatal()); ros::console::notifyLoggerLevelsChanged(); ROS_LOG(ros::console::levels::Fatal, ROSCONSOLE_DEFAULT_NAME, "test"); EXPECT_EQ((int)appender->info_.size(), 5); logger->removeAppender( appender ); logger->setLevel( log4cxx::Level::getDebug() ); } TEST(RosConsole, longPrintfStyleOutput) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender( appender ); std::stringstream ss; for (int i = 0; i < 100000; ++i ) { ss << 'a'; } ROS_INFO("%s", ss.str().c_str()); ASSERT_EQ((int)appender->info_.size(), 1); EXPECT_STREQ(appender->info_[0].message_.c_str(), ss.str().c_str()); logger->removeAppender( appender ); logger->setLevel( log4cxx::Level::getDebug() ); } TEST(RosConsole, throwingAppender) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderWithThrowPtr(new TestAppenderWithThrow); logger->addAppender( appender ); try { ROS_INFO("Hello there"); } catch (std::exception& e) { FAIL(); } logger->removeAppender( appender ); logger->setLevel( log4cxx::Level::getDebug() ); } void onceFunc() { ROS_LOG_ONCE(ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); } TEST(RosConsole, once) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); onceFunc(); onceFunc(); EXPECT_EQ(appender->info_.size(), 1ULL); logger->removeAppender(appender); } void throttleFunc() { ROS_LOG_THROTTLE(0.5, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); } TEST(RosConsole, throttle) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); ros::Time start = ros::Time::now(); while (ros::Time::now() <= start + ros::Duration(0.5)) { throttleFunc(); ros::Duration(0.01).sleep(); } throttleFunc(); EXPECT_EQ(appender->info_.size(), 2ULL); logger->removeAppender(appender); } void delayedThrottleFunc() { ROS_LOG_DELAYED_THROTTLE(0.5, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); } void delayedThrottleFunc2() { ROS_LOG_DELAYED_THROTTLE(0.5, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello2"); } TEST(RosConsole, delayedThrottle) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); ros::Time start = ros::Time::now(); while (ros::Time::now() <= start + ros::Duration(0.4)) { delayedThrottleFunc(); ros::Duration(0.01).sleep(); } EXPECT_EQ(appender->info_.size(), 0ULL); const int pre_count = appender->info_.size(); start = ros::Time::now(); while (ros::Time::now() <= start + ros::Duration(0.6)) { delayedThrottleFunc2(); ros::Duration(0.01).sleep(); } const int post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 1); logger->removeAppender(appender); } void onceStreamFunc() { ROS_LOG_STREAM_ONCE(ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); } TEST(RosConsole, onceStream) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); onceStreamFunc(); onceStreamFunc(); EXPECT_EQ(appender->info_.size(), 1ULL); logger->removeAppender(appender); } void throttleStreamFunc() { ROS_LOG_STREAM_THROTTLE(0.5, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); } TEST(RosConsole, throttleStream) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); ros::Time start = ros::Time::now(); while (ros::Time::now() <= start + ros::Duration(0.5)) { throttleStreamFunc(); ros::Duration(0.01).sleep(); } throttleStreamFunc(); EXPECT_EQ(appender->info_.size(), 2ULL); logger->removeAppender(appender); } void delayedThrottleStreamFunc() { ROS_LOG_STREAM_DELAYED_THROTTLE(0.5, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); } void delayedThrottleStreamFunc2() { ROS_LOG_STREAM_DELAYED_THROTTLE(0.5, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello2"); } TEST(RosConsole, delayedStreamThrottle) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); ros::Time start = ros::Time::now(); while (ros::Time::now() <= start + ros::Duration(0.4)) { delayedThrottleStreamFunc(); ros::Duration(0.01).sleep(); } EXPECT_EQ(appender->info_.size(), 0ULL); const int pre_count = appender->info_.size(); start = ros::Time::now(); while (ros::Time::now() <= start + ros::Duration(0.6)) { delayedThrottleStreamFunc2(); ros::Duration(0.01).sleep(); } const int post_count = appender->info_.size(); EXPECT_EQ(post_count, pre_count + 1); logger->removeAppender(appender); } TEST(RosConsole, basicFilter) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); BasicFilter trueFilter(true), falseFilter(false); ROS_LOG_FILTER(&trueFilter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); ROS_LOG_FILTER(&falseFilter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello2"); ASSERT_EQ(appender->info_.size(), 1ULL); EXPECT_STREQ(appender->info_[0].message_.c_str(), "Hello"); logger->removeAppender(appender); } TEST(RosConsole, basicFilterStream) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); BasicFilter trueFilter(true), falseFilter(false); ROS_LOG_STREAM_FILTER(&trueFilter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); ROS_LOG_STREAM_FILTER(&falseFilter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello2"); ASSERT_EQ(appender->info_.size(), 1ULL); EXPECT_STREQ(appender->info_[0].message_.c_str(), "Hello"); logger->removeAppender(appender); } struct AdvancedFilter : public ros::console::FilterBase { AdvancedFilter(bool enabled) : enabled_(enabled) , count_(0) {} using ros::console::FilterBase::isEnabled; inline virtual bool isEnabled(ros::console::FilterParams& params) { fprintf(stderr, "%s %s:%d:%s\n", params.message, params.file, params.line, params.function); ++count_; return enabled_; } bool enabled_; int count_; }; TEST(RosConsole, advancedFilter) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); AdvancedFilter trueFilter(true), falseFilter(false); ROS_LOG_FILTER(&trueFilter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); ROS_LOG_FILTER(&falseFilter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello2"); ASSERT_EQ(appender->info_.size(), 1ULL); EXPECT_STREQ(appender->info_[0].message_.c_str(), "Hello"); EXPECT_EQ(trueFilter.count_, 1); EXPECT_EQ(falseFilter.count_, 1); logger->removeAppender(appender); } TEST(RosConsole, advancedFilterStream) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); AdvancedFilter trueFilter(true), falseFilter(false); ROS_LOG_STREAM_FILTER(&trueFilter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); ROS_LOG_STREAM_FILTER(&falseFilter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello2"); ASSERT_EQ(appender->info_.size(), 1ULL); EXPECT_STREQ(appender->info_[0].message_.c_str(), "Hello"); EXPECT_EQ(trueFilter.count_, 1); EXPECT_EQ(falseFilter.count_, 1); logger->removeAppender(appender); } struct ChangeFilter : public ros::console::FilterBase { using ros::console::FilterBase::isEnabled; inline virtual bool isEnabled(ros::console::FilterParams& params) { params.out_message = "haha"; params.level = ros::console::levels::Error; return true; } }; TEST(RosConsole, changeFilter) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); ChangeFilter filter; ROS_LOG_FILTER(&filter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); ASSERT_EQ(appender->info_.size(), 1ULL); EXPECT_STREQ(appender->info_[0].message_.c_str(), "haha"); EXPECT_EQ(appender->info_[0].level_, log4cxx::Level::getError()); logger->removeAppender(appender); } TEST(RosConsole, changeFilterStream) { log4cxx::LoggerPtr logger = log4cxx::Logger::getLogger(ROSCONSOLE_DEFAULT_NAME); auto appender = TestAppenderPtr(new TestAppender); logger->addAppender(appender); ChangeFilter filter; ROS_LOG_STREAM_FILTER(&filter, ros::console::levels::Info, ROSCONSOLE_DEFAULT_NAME, "Hello"); ASSERT_EQ(appender->info_.size(), 1ULL); EXPECT_STREQ(appender->info_[0].message_.c_str(), "haha"); EXPECT_EQ(appender->info_[0].level_, log4cxx::Level::getError()); logger->removeAppender(appender); } TEST(RosConsole, formatToBufferInitialZero) { boost::shared_array buffer; size_t size = 0; ros::console::formatToBuffer(buffer, size, "Hello World %d", 5); EXPECT_EQ(size, 14U); EXPECT_STREQ(buffer.get(), "Hello World 5"); } TEST(RosConsole, formatToBufferInitialLargerThanFormat) { boost::shared_array buffer(new char[30]); size_t size = 30; ros::console::formatToBuffer(buffer, size, "Hello World %d", 5); EXPECT_EQ(size, 30U); EXPECT_STREQ(buffer.get(), "Hello World 5"); } TEST(RosConsole, formatToString) { std::string str = ros::console::formatToString("Hello World %d", 5); EXPECT_STREQ(str.c_str(), "Hello World 5"); } TEST(RosConsole, formatter) { std::string format_string; ros::console::Level level = ros::console::levels::Info; char str[32]; char file[32]; char function[32]; std::string result; // default time { std::string format_string = "${time}"; ros::console::g_formatter.tokens_.clear(); ros::console::g_formatter.init(format_string.c_str()); result = ros::console::g_formatter.getTokenStrings( &*log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME), level, str, file, function, 0); boost::regex expr("([0-9]+)\\.([0-9]+)"); EXPECT_TRUE(boost::regex_match(result, expr)); } // time format { std::string format_string = "${time:%Y %H:%M:%S}"; ros::console::g_formatter.tokens_.clear(); ros::console::g_formatter.init(format_string.c_str()); result = ros::console::g_formatter.getTokenStrings( &*log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME), level, str, file, function, 0); boost::regex expr("([0-9]{4}) ([0-9]{2}:[0-9]{2}:[0-9]{2})"); EXPECT_TRUE(boost::regex_match(result, expr)); } // default walltime { std::string format_string = "${walltime}"; ros::console::g_formatter.tokens_.clear(); ros::console::g_formatter.init(format_string.c_str()); result = ros::console::g_formatter.getTokenStrings( &*log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME), level, str, file, function, 0); boost::regex expr("([0-9]+)\\.([0-9]+)"); EXPECT_TRUE(boost::regex_match(result, expr)); } // walltime format { std::string format_string = "${walltime:%Y %H:%M:%S}"; ros::console::g_formatter.tokens_.clear(); ros::console::g_formatter.init(format_string.c_str()); result = ros::console::g_formatter.getTokenStrings( &*log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME), level, str, file, function, 0); boost::regex expr("([0-9]{4}) ([0-9]{2}:[0-9]{2}:[0-9]{2})"); EXPECT_TRUE(boost::regex_match(result, expr)); } } int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); ros::Time::init(); ROSCONSOLE_AUTOINIT; log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME)->removeAllAppenders(); log4cxx::Logger::getRootLogger()->setLevel(log4cxx::Level::getDebug()); log4cxx::Logger::getLogger(ROSCONSOLE_ROOT_LOGGER_NAME)->setLevel(log4cxx::Level::getDebug()); return RUN_ALL_TESTS(); }