1// Copyright 2014 The Android Open Source Project
2//
3// This software is licensed under the terms of the GNU General Public
4// License version 2, as published by the Free Software Foundation, and
5// may be copied, distributed, and modified under those terms.
6//
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10// GNU General Public License for more details.
11
12#include "android/base/Log.h"
13
14#include <errno.h>
15#include <stdio.h>
16#include <string.h>
17
18#include <gtest/gtest.h>
19
20namespace android {
21namespace base {
22
23// Create a severity level which is guaranteed to never generate a log
24// message. See LogOnlyEvaluatesArgumentsIfNeeded for usage.
25const LogSeverity LOG_INVISIBLE = -10000;
26
27class LogTest : public ::testing::Test, android::base::testing::LogOutput {
28public:
29    LogTest() : mFatal(false) {
30        mSavedOutput = ::android::base::testing::LogOutput::setNewOutput(this);
31        mExpected[0] = '\0';
32        mBuffer[0] = '\x7f';
33        mBuffer[1] = '\0';
34    }
35
36    ~LogTest() {
37        ::android::base::testing::LogOutput::setNewOutput(mSavedOutput);
38    }
39
40    void setExpected(LogSeverity severity, int line, const char* suffix) {
41        mExpectedParams.file = __FILE__;
42        mExpectedParams.lineno = line;
43        mExpectedParams.severity = severity;
44        snprintf(mExpected, sizeof(mExpected), "%s", suffix);
45    }
46
47    // LogOutput override
48    void logMessage(const LogParams& params,
49                    const char* message,
50                    size_t messageLen) {
51        mParams = params;
52        if (messageLen > sizeof(mBuffer) - 1)
53            messageLen = sizeof(mBuffer) - 1;
54        ::memcpy(mBuffer, message, messageLen);
55        mBuffer[messageLen] = '\0';
56        mFatal = (params.severity >= LOG_FATAL);
57    }
58
59protected:
60    ::android::base::testing::LogOutput* mSavedOutput;
61    LogParams mParams;
62    LogParams mExpectedParams;
63    char mExpected[1024];
64    char mBuffer[1024];
65    bool mFatal;
66};
67
68class CheckTest : public LogTest {
69};
70
71#if ENABLE_DCHECK != 0
72class DCheckEnabledTest : public LogTest {
73public:
74    DCheckEnabledTest() : LogTest() {
75        // Ensure DCHECKS() always run.
76        mSavedLevel = setDcheckLevel(true);
77    }
78
79    ~DCheckEnabledTest() {
80        setDcheckLevel(mSavedLevel);
81    }
82private:
83    bool mSavedLevel;
84};
85#endif  // ENABLE_DCHECK == 0
86
87#if ENABLE_DCHECK != 2
88class DCheckDisabledTest : public LogTest {
89public:
90    DCheckDisabledTest() : LogTest() {
91        mSavedLevel = setDcheckLevel(false);
92    }
93
94    ~DCheckDisabledTest() {
95        setDcheckLevel(mSavedLevel);
96    }
97private:
98    bool mSavedLevel;
99};
100#endif  // ENABLE_DCHECK != 2
101
102class PLogTest : public LogTest {
103public:
104    PLogTest() : LogTest(), mForcedErrno(-1000) {}
105
106    void setForcedErrno(int errnoCode) {
107        mForcedErrno = errnoCode;
108    }
109
110    void setExpectedErrno(LogSeverity severity,
111                          int line,
112                          int errnoCode,
113                          const char* suffix) {
114        mExpectedParams.file = __FILE__;
115        mExpectedParams.lineno = line;
116        mExpectedParams.severity = severity;
117        snprintf(mExpected,
118                 sizeof(mExpected),
119                 "%sError message: %s",
120                 suffix,
121                 strerror(errnoCode));
122    }
123
124    void logMessage(const LogParams& params,
125                    const char* message,
126                    size_t messageLen) {
127        LogTest::logMessage(params, message, messageLen);
128
129        if (mForcedErrno != -1000)
130            errno = mForcedErrno;
131    }
132
133protected:
134    int mForcedErrno;
135};
136
137#define STRINGIFY(x) STRINGIFY_(x)
138#define STRINGIFY_(x) #x
139
140#define EXPECTED_STRING_PREFIX(prefix, line) \
141  prefix ":" __FILE__ ":" STRINGIFY(line) ": "
142
143#define CHECK_EXPECTATIONS() \
144    EXPECT_STREQ(mExpectedParams.file, mParams.file); \
145    EXPECT_EQ(mExpectedParams.lineno, mParams.lineno); \
146    EXPECT_EQ(mExpectedParams.severity, mParams.severity); \
147    EXPECT_STREQ(mExpected, mBuffer)
148
149// Helper function used to set a boolean |flag|, then return |string|.
150static const char* setFlag(bool* flag, const char* string) {
151    *flag = true;
152    return string;
153}
154
155TEST(LogString, EmptyString) {
156    LogString ls("");
157    EXPECT_STREQ("", ls.string());
158}
159
160TEST(LogString, SimpleString) {
161    LogString ls("Hello");
162    EXPECT_STREQ("Hello", ls.string());
163}
164
165TEST(LogString, FormattedString) {
166    LogString ls("%d plus %d equals %d", 12, 23, 35);
167    EXPECT_STREQ("12 plus 23 equals 35", ls.string());
168}
169
170TEST_F(LogTest, LogInfoEmpty) {
171    setExpected(LOG_INFO, __LINE__ + 1, "");
172    LOG(INFO);
173    CHECK_EXPECTATIONS();
174}
175
176TEST_F(LogTest, LogInfoWithString) {
177    static const char kString[] = "Hello World!";
178    setExpected(LOG_INFO, __LINE__ + 1, kString);
179    LOG(INFO) << kString;
180    CHECK_EXPECTATIONS();
181}
182
183TEST_F(LogTest, LogInfoWithTwoStrings) {
184    setExpected(LOG_INFO, __LINE__ + 1, "Hello Globe!");
185    LOG(INFO) << "Hello " << "Globe!";
186    CHECK_EXPECTATIONS();
187}
188
189TEST_F(LogTest, LogInfoWithLogString) {
190    LogString ls("Hello You!");
191    setExpected(LOG_INFO, __LINE__ + 1, ls.string());
192    LOG(INFO) << ls;
193    CHECK_EXPECTATIONS();
194}
195
196TEST_F(LogTest, LogWarning) {
197    static const char kWarning[] = "Elvis has left the building!";
198    setExpected(LOG_WARNING, __LINE__ + 1, kWarning);
199    LOG(WARNING) << kWarning;
200    CHECK_EXPECTATIONS();
201}
202
203TEST_F(LogTest, LogError) {
204    static const char kError[] = "Bad Bad Robot!";
205    setExpected(LOG_ERROR, __LINE__ + 1, kError);
206    LOG(ERROR) << kError;
207
208    CHECK_EXPECTATIONS();
209}
210
211TEST_F(LogTest, LogFatal) {
212    static const char kFatalMessage[] = "I'm dying";
213    setExpected(LOG_FATAL, __LINE__ + 1, kFatalMessage);
214    LOG(FATAL) << kFatalMessage;
215    CHECK_EXPECTATIONS();
216    EXPECT_TRUE(mFatal);
217}
218
219TEST_F(LogTest, LogEvaluatesArgumentsIfNeeded) {
220    // Use LOG_FATAL since it is always active.
221    bool flag = false;
222    setExpected(LOG_FATAL, __LINE__ + 1, "PANIC: Flag was set!");
223    LOG(FATAL) << "PANIC: " << setFlag(&flag, "Flag was set!");
224    CHECK_EXPECTATIONS();
225    EXPECT_TRUE(mFatal);
226    EXPECT_TRUE(flag);
227}
228
229TEST_F(LogTest, LogOnlyEvaluatesArgumentsIfNeeded) {
230    bool flag = false;
231    LOG(INVISIBLE) << setFlag(&flag, "Flag was set!");
232    EXPECT_FALSE(flag);
233}
234
235
236// TODO(digit): Convert this to a real death test when this is supported
237// by our version of GTest.
238TEST_F(CheckTest, CheckFalse) {
239    setExpected(LOG_FATAL, __LINE__ + 1, "Check failed: false. ");
240    CHECK(false);
241    CHECK_EXPECTATIONS();
242}
243
244TEST_F(CheckTest, CheckFalseEvaluatesArguments) {
245    bool flag = false;
246    setExpected(LOG_FATAL, __LINE__ + 1, "Check failed: false. Flag was set!");
247    CHECK(false) << setFlag(&flag, "Flag was set!");
248    EXPECT_TRUE(flag);
249    CHECK_EXPECTATIONS();
250}
251
252TEST_F(CheckTest, CheckTrue) {
253    CHECK(true);
254    EXPECT_FALSE(mFatal);
255}
256
257TEST_F(CheckTest, CheckTrueDoesNotEvaluateArguments) {
258    bool flag = false;
259    CHECK(true) << setFlag(&flag, "Flag was set!");
260    EXPECT_FALSE(flag);
261    EXPECT_FALSE(mFatal);
262}
263
264#if ENABLE_DCHECK != 0
265TEST_F(DCheckEnabledTest, DCheckIsOnReturnsTrue) {
266    EXPECT_TRUE(DCHECK_IS_ON());
267}
268
269TEST_F(DCheckEnabledTest, DCheckFalse) {
270    bool flag = false;
271    setExpected(LOG_FATAL, __LINE__ + 1, "Check failed: false. Flag was set!");
272    DCHECK(false) << setFlag(&flag, "Flag was set!");
273    CHECK_EXPECTATIONS();
274}
275
276TEST_F(DCheckEnabledTest, DCheckTrue) {
277    bool flag = false;
278    DCHECK(true) << setFlag(&flag, "Flag was set!");
279    EXPECT_FALSE(flag);
280    EXPECT_FALSE(mFatal);
281}
282#endif  // ENABLE_DCHECK != 0
283
284#if ENABLE_DCHECK != 2
285TEST_F(DCheckDisabledTest, DCheckIsOnReturnsFalse) {
286    EXPECT_FALSE(DCHECK_IS_ON());
287}
288
289TEST_F(DCheckDisabledTest, DCheckFalse) {
290    bool flag = false;
291    DCHECK(false) << setFlag(&flag, "Flag was set!");
292    EXPECT_FALSE(flag);
293    EXPECT_FALSE(mFatal);
294}
295
296TEST_F(DCheckDisabledTest, DCheckTrue) {
297    DCHECK(true);
298}
299#endif  // ENABLE_DCHECK != 2
300
301TEST_F(PLogTest, PLogInfoEmpty) {
302    setExpectedErrno(LOG_INFO, __LINE__ + 2, EINVAL, "");
303    errno = EINVAL;
304    PLOG(INFO);
305    CHECK_EXPECTATIONS();
306}
307
308TEST_F(PLogTest, PLogInfoPreservesErrno) {
309    // Select a value that is unlikely to ever be raised by the logging
310    // machinery.
311    const int kErrnoCode = ENOEXEC;
312    setForcedErrno(EINVAL);
313    setExpectedErrno(LOG_INFO, __LINE__ + 2, kErrnoCode, "Hi");
314    errno = kErrnoCode;
315    PLOG(INFO) << "Hi";
316    EXPECT_EQ(kErrnoCode, errno);
317    CHECK_EXPECTATIONS();
318}
319
320}  // namespace base
321}  // namespace android
322