• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
40 class CapturedStderr {
41  public:
CapturedStderr()42   CapturedStderr() : old_stderr_(-1) {
43     init();
44   }
45 
~CapturedStderr()46   ~CapturedStderr() {
47     reset();
48   }
49 
fd() const50   int fd() const {
51     return temp_file_.fd;
52   }
53 
54  private:
init()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 
reset()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)
ExitSignalAbortHandler(int)77 static void ExitSignalAbortHandler(int) {
78   _exit(3);
79 }
80 #endif
81 
SuppressAbortUI()82 static 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 
TEST(logging,CHECK)96 TEST(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 
make_log_pattern(android::base::LogSeverity severity,const char * message)123 std::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 
TEST(logging,LOG)133 TEST(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 
TEST(logging,PLOG)243 TEST(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 
TEST(logging,UNIMPLEMENTED)262 TEST(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