1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "android-base/logging.h" 18 19#include <libgen.h> 20 21#if defined(_WIN32) 22#include <signal.h> 23#endif 24 25#include <regex> 26#include <string> 27 28#include "android-base/file.h" 29#include "android-base/stringprintf.h" 30#include "android-base/test_utils.h" 31 32#include <gtest/gtest.h> 33 34#ifdef __ANDROID__ 35#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name) 36#else 37#define HOST_TEST(suite, name) TEST(suite, name) 38#endif 39 40class CapturedStderr { 41 public: 42 CapturedStderr() : old_stderr_(-1) { 43 init(); 44 } 45 46 ~CapturedStderr() { 47 reset(); 48 } 49 50 int fd() const { 51 return temp_file_.fd; 52 } 53 54 private: 55 void init() { 56#if defined(_WIN32) 57 // On Windows, stderr is often buffered, so make sure it is unbuffered so 58 // that we can immediately read back what was written to stderr. 59 ASSERT_EQ(0, setvbuf(stderr, NULL, _IONBF, 0)); 60#endif 61 old_stderr_ = dup(STDERR_FILENO); 62 ASSERT_NE(-1, old_stderr_); 63 ASSERT_NE(-1, dup2(fd(), STDERR_FILENO)); 64 } 65 66 void reset() { 67 ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO)); 68 ASSERT_EQ(0, close(old_stderr_)); 69 // Note: cannot restore prior setvbuf() setting. 70 } 71 72 TemporaryFile temp_file_; 73 int old_stderr_; 74}; 75 76#if defined(_WIN32) 77static void ExitSignalAbortHandler(int) { 78 _exit(3); 79} 80#endif 81 82static void SuppressAbortUI() { 83#if defined(_WIN32) 84 // We really just want to call _set_abort_behavior(0, _CALL_REPORTFAULT) to 85 // suppress the Windows Error Reporting dialog box, but that API is not 86 // available in the OS-supplied C Runtime, msvcrt.dll, that we currently 87 // use (it is available in the Visual Studio C runtime). 88 // 89 // Instead, we setup a SIGABRT handler, which is called in abort() right 90 // before calling Windows Error Reporting. In the handler, we exit the 91 // process just like abort() does. 92 ASSERT_NE(SIG_ERR, signal(SIGABRT, ExitSignalAbortHandler)); 93#endif 94} 95 96TEST(logging, CHECK) { 97 ASSERT_DEATH({SuppressAbortUI(); CHECK(false);}, "Check failed: false "); 98 CHECK(true); 99 100 ASSERT_DEATH({SuppressAbortUI(); CHECK_EQ(0, 1);}, "Check failed: 0 == 1 "); 101 CHECK_EQ(0, 0); 102 103 ASSERT_DEATH({SuppressAbortUI(); CHECK_STREQ("foo", "bar");}, 104 R"(Check failed: "foo" == "bar")"); 105 CHECK_STREQ("foo", "foo"); 106 107 // Test whether CHECK() and CHECK_STREQ() have a dangling if with no else. 108 bool flag = false; 109 if (true) 110 CHECK(true); 111 else 112 flag = true; 113 EXPECT_FALSE(flag) << "CHECK macro probably has a dangling if with no else"; 114 115 flag = false; 116 if (true) 117 CHECK_STREQ("foo", "foo"); 118 else 119 flag = true; 120 EXPECT_FALSE(flag) << "CHECK_STREQ probably has a dangling if with no else"; 121} 122 123std::string make_log_pattern(android::base::LogSeverity severity, 124 const char* message) { 125 static const char* log_characters = "VDIWEF"; 126 char log_char = log_characters[severity]; 127 std::string holder(__FILE__); 128 return android::base::StringPrintf( 129 "%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ %s:[[:digit:]]+] %s", 130 log_char, basename(&holder[0]), message); 131} 132 133TEST(logging, LOG) { 134 ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar"); 135 136 // We can't usefully check the output of any of these on Windows because we 137 // don't have std::regex, but we can at least make sure we printed at least as 138 // many characters are in the log message. 139 { 140 CapturedStderr cap; 141 LOG(WARNING) << "foobar"; 142 ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET)); 143 144 std::string output; 145 android::base::ReadFdToString(cap.fd(), &output); 146 ASSERT_GT(output.length(), strlen("foobar")); 147 148#if !defined(_WIN32) 149 std::regex message_regex( 150 make_log_pattern(android::base::WARNING, "foobar")); 151 ASSERT_TRUE(std::regex_search(output, message_regex)) << output; 152#endif 153 } 154 155 { 156 CapturedStderr cap; 157 LOG(INFO) << "foobar"; 158 ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET)); 159 160 std::string output; 161 android::base::ReadFdToString(cap.fd(), &output); 162 ASSERT_GT(output.length(), strlen("foobar")); 163 164#if !defined(_WIN32) 165 std::regex message_regex( 166 make_log_pattern(android::base::INFO, "foobar")); 167 ASSERT_TRUE(std::regex_search(output, message_regex)) << output; 168#endif 169 } 170 171 { 172 CapturedStderr cap; 173 LOG(DEBUG) << "foobar"; 174 ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET)); 175 176 std::string output; 177 android::base::ReadFdToString(cap.fd(), &output); 178 ASSERT_TRUE(output.empty()); 179 } 180 181 { 182 android::base::ScopedLogSeverity severity(android::base::DEBUG); 183 CapturedStderr cap; 184 LOG(DEBUG) << "foobar"; 185 ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET)); 186 187 std::string output; 188 android::base::ReadFdToString(cap.fd(), &output); 189 ASSERT_GT(output.length(), strlen("foobar")); 190 191#if !defined(_WIN32) 192 std::regex message_regex( 193 make_log_pattern(android::base::DEBUG, "foobar")); 194 ASSERT_TRUE(std::regex_search(output, message_regex)) << output; 195#endif 196 } 197 198 // Test whether LOG() saves and restores errno. 199 { 200 CapturedStderr cap; 201 errno = 12345; 202 LOG(INFO) << (errno = 67890); 203 EXPECT_EQ(12345, errno) << "errno was not restored"; 204 205 ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET)); 206 207 std::string output; 208 android::base::ReadFdToString(cap.fd(), &output); 209 EXPECT_NE(nullptr, strstr(output.c_str(), "67890")) << output; 210 211#if !defined(_WIN32) 212 std::regex message_regex( 213 make_log_pattern(android::base::INFO, "67890")); 214 ASSERT_TRUE(std::regex_search(output, message_regex)) << output; 215#endif 216 } 217 218 // Test whether LOG() has a dangling if with no else. 219 { 220 CapturedStderr cap; 221 222 // Do the test two ways: once where we hypothesize that LOG()'s if 223 // will evaluate to true (when severity is high enough) and once when we 224 // expect it to evaluate to false (when severity is not high enough). 225 bool flag = false; 226 if (true) 227 LOG(INFO) << "foobar"; 228 else 229 flag = true; 230 231 EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else"; 232 233 flag = false; 234 if (true) 235 LOG(VERBOSE) << "foobar"; 236 else 237 flag = true; 238 239 EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else"; 240 } 241} 242 243TEST(logging, PLOG) { 244 { 245 CapturedStderr cap; 246 errno = ENOENT; 247 PLOG(INFO) << "foobar"; 248 ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET)); 249 250 std::string output; 251 android::base::ReadFdToString(cap.fd(), &output); 252 ASSERT_GT(output.length(), strlen("foobar")); 253 254#if !defined(_WIN32) 255 std::regex message_regex(make_log_pattern( 256 android::base::INFO, "foobar: No such file or directory")); 257 ASSERT_TRUE(std::regex_search(output, message_regex)) << output; 258#endif 259 } 260} 261 262TEST(logging, UNIMPLEMENTED) { 263 { 264 CapturedStderr cap; 265 errno = ENOENT; 266 UNIMPLEMENTED(ERROR); 267 ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET)); 268 269 std::string output; 270 android::base::ReadFdToString(cap.fd(), &output); 271 ASSERT_GT(output.length(), strlen("unimplemented")); 272 273#if !defined(_WIN32) 274 std::string expected_message = 275 android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__); 276 std::regex message_regex( 277 make_log_pattern(android::base::ERROR, expected_message.c_str())); 278 ASSERT_TRUE(std::regex_search(output, message_regex)) << output; 279#endif 280 } 281} 282