1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ #include < rcpputils/filesystem_helper.hpp>
16+ #include < rcpputils/get_env.hpp>
1517#include < rcutils/allocator.h>
18+ #include < rcutils/env.h>
1619#include < rcutils/error_handling.h>
1720#include < rcutils/logging.h>
18- #include " rcl_logging_spdlog/logging_interface.h"
21+
22+ #include < limits.h>
23+ #include < fstream>
24+ #include < string>
25+
26+ #include " fixtures.hpp"
1927#include " gtest/gtest.h"
28+ #include " rcl_logging_spdlog/logging_interface.h"
2029
21- static void * bad_malloc (size_t , void *)
30+ namespace fs = rcpputils::fs;
31+
32+ const int logger_levels[] =
2233{
23- return nullptr ;
24- }
34+ RCUTILS_LOG_SEVERITY_UNSET,
35+ RCUTILS_LOG_SEVERITY_DEBUG,
36+ RCUTILS_LOG_SEVERITY_INFO,
37+ RCUTILS_LOG_SEVERITY_WARN,
38+ RCUTILS_LOG_SEVERITY_ERROR,
39+ RCUTILS_LOG_SEVERITY_FATAL,
40+ };
41+
42+ // This is a helper class that resets an environment
43+ // variable when leaving scope
44+ class RestoreEnvVar
45+ {
46+ public:
47+ explicit RestoreEnvVar (const std::string & name)
48+ : name_(name),
49+ value_(rcpputils::get_env_var(name.c_str()))
50+ {
51+ }
52+
53+ ~RestoreEnvVar ()
54+ {
55+ if (!rcutils_set_env (name_.c_str (), value_.c_str ())) {
56+ std::cerr << " Failed to restore value of environment variable: " << name_ << std::endl;
57+ }
58+ }
2559
26- TEST (logging_interface, init_invalid)
60+ private:
61+ const std::string name_;
62+ const std::string value_;
63+ };
64+
65+ // TODO(cottsay): Remove when ros2/rcpputils#63 is resolved
66+ static fs::path current_path ()
2767{
28- rcutils_allocator_t allocator = rcutils_get_default_allocator ();
29- rcutils_allocator_t bad_allocator = rcutils_get_default_allocator ();
30- rcutils_allocator_t invalid_allocator = rcutils_get_zero_initialized_allocator ();
31- bad_allocator.allocate = bad_malloc;
68+ #ifdef _WIN32
69+ #ifdef UNICODE
70+ #error "rcpputils::fs does not support Unicode paths"
71+ #endif
72+ char cwd[MAX_PATH];
73+ if (nullptr == _getcwd (cwd, MAX_PATH)) {
74+ #else
75+ char cwd[PATH_MAX];
76+ if (nullptr == getcwd (cwd, PATH_MAX)) {
77+ #endif
78+ std::error_code ec{errno, std::system_category ()};
79+ errno = 0 ;
80+ throw std::system_error{ec, " cannot get current working directory" };
81+ }
3282
83+ return fs::path (cwd);
84+ }
85+
86+ TEST_F (LoggingTest, init_invalid)
87+ {
3388 // Config files are not supported by spdlog
3489 EXPECT_EQ (2 , rcl_logging_external_initialize (" anything" , allocator));
3590 rcutils_reset_error ();
@@ -39,12 +94,71 @@ TEST(logging_interface, init_invalid)
3994 rcutils_reset_error ();
4095}
4196
42- TEST (logging_interface, full_cycle)
97+ TEST_F (LoggingTest, init_failure)
98+ {
99+ RestoreEnvVar home_var (" HOME" );
100+ RestoreEnvVar userprofile_var (" USERPROFILE" );
101+
102+ // No home directory to write log to
103+ ASSERT_EQ (true , rcutils_set_env (" HOME" , nullptr ));
104+ ASSERT_EQ (true , rcutils_set_env (" USERPROFILE" , nullptr ));
105+ EXPECT_EQ (2 , rcl_logging_external_initialize (nullptr , allocator));
106+ rcutils_reset_error ();
107+
108+ // Force failure to create directories
109+ fs::path fake_home = current_path () / " fake_home_dir" ;
110+ ASSERT_TRUE (fs::create_directories (fake_home));
111+ ASSERT_EQ (true , rcutils_set_env (" HOME" , fake_home.string ().c_str ()));
112+
113+ // ...fail to create .ros dir
114+ fs::path ros_dir = fake_home / " .ros" ;
115+ std::fstream (ros_dir.string (), std::ios_base::out).close ();
116+ EXPECT_EQ (2 , rcl_logging_external_initialize (nullptr , allocator));
117+ ASSERT_TRUE (fs::remove (ros_dir));
118+
119+ // ...fail to create .ros/log dir
120+ ASSERT_TRUE (fs::create_directories (ros_dir));
121+ fs::path ros_log_dir = ros_dir / " log" ;
122+ std::fstream (ros_log_dir.string (), std::ios_base::out).close ();
123+ EXPECT_EQ (2 , rcl_logging_external_initialize (nullptr , allocator));
124+ ASSERT_TRUE (fs::remove (ros_log_dir));
125+ ASSERT_TRUE (fs::remove (ros_dir));
126+
127+ ASSERT_TRUE (fs::remove (fake_home));
128+ }
129+
130+ TEST_F (LoggingTest, full_cycle)
43131{
44- rcutils_allocator_t allocator = rcutils_get_default_allocator ( );
132+ ASSERT_EQ ( 0 , rcl_logging_external_initialize ( nullptr , allocator) );
45133
134+ // Make sure we can call initialize more than once
46135 ASSERT_EQ (0 , rcl_logging_external_initialize (nullptr , allocator));
47- EXPECT_EQ (0 , rcl_logging_external_set_logger_level (nullptr , RCUTILS_LOG_SEVERITY_INFO));
48- rcl_logging_external_log (RCUTILS_LOG_SEVERITY_INFO, nullptr , " Log Message" );
136+
137+ std::stringstream expected_log;
138+ for (int level : logger_levels) {
139+ EXPECT_EQ (0 , rcl_logging_external_set_logger_level (nullptr , level));
140+
141+ for (int severity : logger_levels) {
142+ std::stringstream ss;
143+ ss << " Message of severity " << severity << " at level " << level;
144+ rcl_logging_external_log (severity, nullptr , ss.str ().c_str ());
145+
146+ if (severity >= level) {
147+ expected_log << ss.str () << std::endl;
148+ } else if (severity == 0 && level == 10 ) {
149+ // This is a special case - not sure what the right behavior is
150+ expected_log << ss.str () << std::endl;
151+ }
152+ }
153+ }
154+
49155 EXPECT_EQ (0 , rcl_logging_external_shutdown ());
156+
157+ std::string log_file_path = find_single_log ().string ();
158+ std::ifstream log_file (log_file_path);
159+ std::stringstream actual_log;
160+ actual_log << log_file.rdbuf ();
161+ EXPECT_EQ (
162+ expected_log.str (),
163+ actual_log.str ()) << " Unexpected log contents in " << log_file_path;
50164}
0 commit comments