1 /**
2 * (c) 2019 by Mega Limited, Wellsford, New Zealand
3 *
4 * This file is part of the MEGA SDK - Client Access Engine.
5 *
6 * Applications using the MEGA API must present a valid application key
7 * and comply with the the rules set forth in the Terms of Service.
8 *
9 * The MEGA SDK is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * @copyright Simplified (2-clause) BSD License.
14 *
15 * You should have received a copy of the license along with this
16 * program.
17 */
18 #include <gtest/gtest.h>
19
20 #include <mega/logging.h>
21
22 #ifdef NOT_REALLY_NEEDED_BECAUSE_WE_EXERCISE_IT_ALL_THE_TIME_ANYWAY
23
24 #ifdef ENABLE_LOG_PERFORMANCE
25 namespace {
26
27 class MockLogger : public mega::Logger
28 {
29 public:
30
MockLogger()31 MockLogger()
32 {
33 mega::SimpleLogger::logger = this;
34 }
35
~MockLogger()36 ~MockLogger()
37 {
38 mega::SimpleLogger::logger = nullptr;
39 }
40
log(const char * time,int loglevel,const char * source,const char * message)41 void log(const char *time, int loglevel, const char *source, const char *message) override
42 {
43 EXPECT_EQ(nullptr, time);
44 EXPECT_EQ(nullptr, source);
45 EXPECT_NE(nullptr, message);
46 mLogLevel.insert(loglevel);
47 mMessage.push_back(message);
48 }
49
checkLogLevel(const int expLogLevel) const50 void checkLogLevel(const int expLogLevel) const
51 {
52 EXPECT_EQ(1, mLogLevel.size());
53 EXPECT_EQ(expLogLevel, *mLogLevel.begin());
54 }
55
56 std::vector<std::string> mMessage;
57
58 private:
59 std::set<int> mLogLevel;
60 };
61
expMsg(const std::string & file,const int line,const std::string & message)62 std::string expMsg(const std::string& file, const int line, const std::string& message)
63 {
64 return message + " ["+file + ":" + std::to_string(line) + "]";
65 }
66
67 #ifdef _WIN32
expWMsg(const std::string & file,const int line,const std::wstring & message)68 std::string expWMsg(const std::string& file, const int line, const std::wstring& message)
69 {
70 return file + ":" + std::to_string(line) + " " + std::string(message.begin(), message.end());
71 }
72 #endif
73
74 }
75
TEST(Logging,performanceMode_forStdString)76 TEST(Logging, performanceMode_forStdString)
77 {
78 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
79 {
80 MockLogger logger;
81 const std::string file = "file.cpp";
82 const int line = 13;
83 const std::string message = "some message";
84 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << message;
85 logger.checkLogLevel(level);
86 ASSERT_EQ(1, logger.mMessage.size());
87 ASSERT_EQ(expMsg(file, line, message), logger.mMessage[0]);
88 }
89 }
90
91 #ifdef _WIN32
TEST(Logging,performanceMode_forWStdString)92 TEST(Logging, performanceMode_forWStdString)
93 {
94 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
95 {
96 MockLogger logger;
97 const std::string file = "file.cpp";
98 const int line = 13;
99 const std::wstring message = L"\u039C\u03C5\u03C4\u03B9\u03BB\u03B7\u03BD\u03B1\u03AF\u03BF\u03C2\20\u0391\u03B2\u03C1\u03AC\u03C2";
100 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << message;
101 logger.checkLogLevel(level);
102 ASSERT_EQ(1, logger.mMessage.size());
103 ASSERT_EQ(expWMsg(file, line, message), logger.mMessage[0]);
104 }
105 }
106 #endif
107
TEST(Logging,performanceMode_forCString)108 TEST(Logging, performanceMode_forCString)
109 {
110 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
111 {
112 MockLogger logger;
113 const std::string file = "file.cpp";
114 const int line = 13;
115 const std::string message = "some message";
116 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << message.c_str();
117 logger.checkLogLevel(level);
118 ASSERT_EQ(1, logger.mMessage.size());
119 ASSERT_EQ(expMsg(file, line, message), logger.mMessage[0]);
120 }
121 }
122
TEST(Logging,performanceMode_forEnum)123 TEST(Logging, performanceMode_forEnum)
124 {
125 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
126 {
127 MockLogger logger;
128 const std::string file = "file.cpp";
129 const int line = 13;
130 const auto obj = mega::LogLevel::logDebug;
131 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << obj;
132 logger.checkLogLevel(level);
133 ASSERT_EQ(1, logger.mMessage.size());
134 ASSERT_EQ(expMsg(file, line, "4"), logger.mMessage[0]);
135 }
136 }
137
TEST(Logging,performanceMode_forPointer)138 TEST(Logging, performanceMode_forPointer)
139 {
140 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
141 {
142 MockLogger logger;
143 const std::string file = "file.cpp";
144 const int line = 13;
145 const double obj = 42;
146 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << &obj;
147 logger.checkLogLevel(level);
148 ASSERT_EQ(1, logger.mMessage.size());
149 ASSERT_GE(logger.mMessage[0].size(), file.size() + 5); // 5 = ':13 ' plus null terminator
150 }
151 }
152
TEST(Logging,performanceMode_forNullPointer)153 TEST(Logging, performanceMode_forNullPointer)
154 {
155 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
156 {
157 MockLogger logger;
158 const std::string file = "file.cpp";
159 const int line = 13;
160 const double* obj = nullptr;
161 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << obj;
162 logger.checkLogLevel(level);
163 ASSERT_EQ(1, logger.mMessage.size());
164 ASSERT_EQ(expMsg(file, line, "(NULL)"), logger.mMessage[0]);
165 }
166 }
167
168 namespace {
169
170 template<typename Type>
test_forIntegerNumber(const Type number)171 void test_forIntegerNumber(const Type number)
172 {
173 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
174 {
175 MockLogger logger;
176 const std::string file = "file.cpp";
177 const int line = 13;
178 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << number;
179 logger.checkLogLevel(level);
180 EXPECT_EQ(1, logger.mMessage.size());
181 std::ostringstream expected;
182 expected << number;
183 EXPECT_EQ(expMsg(file, line, expected.str()), logger.mMessage[0]);
184 }
185 }
186
187 template<typename Type>
test_forFloatingNumber(const Type number)188 void test_forFloatingNumber(const Type number)
189 {
190 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
191 {
192 MockLogger logger;
193 const std::string file = "file.cpp";
194 const int line = 13;
195 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << number;
196 logger.checkLogLevel(level);
197 EXPECT_EQ(1, logger.mMessage.size());
198 std::ostringstream expected;
199 expected << number;
200 const auto msg = expMsg(file, line, expected.str());
201 EXPECT_NE(logger.mMessage[0].find(msg), std::string::npos);
202 }
203 }
204
205 }
206
TEST(Logging,performanceMode_forInt)207 TEST(Logging, performanceMode_forInt)
208 {
209 test_forIntegerNumber<int>(0);
210 test_forIntegerNumber<int>(42);
211 test_forIntegerNumber<int>(-42);
212 test_forIntegerNumber<int>(std::numeric_limits<int>::lowest());
213 test_forIntegerNumber<int>(std::numeric_limits<int>::max());
214 }
215
TEST(Logging,performanceMode_forLong)216 TEST(Logging, performanceMode_forLong)
217 {
218 test_forIntegerNumber<long>(0);
219 test_forIntegerNumber<long>(42);
220 test_forIntegerNumber<long>(-42);
221 test_forIntegerNumber<long>(std::numeric_limits<long>::lowest());
222 test_forIntegerNumber<long>(std::numeric_limits<long>::max());
223 }
224
TEST(Logging,performanceMode_forLongLong)225 TEST(Logging, performanceMode_forLongLong)
226 {
227 test_forIntegerNumber<long long>(0);
228 test_forIntegerNumber<long long>(42);
229 test_forIntegerNumber<long long>(-42);
230 test_forIntegerNumber<long long>(std::numeric_limits<long long>::lowest());
231 test_forIntegerNumber<long long>(std::numeric_limits<long long>::max());
232 }
233
TEST(Logging,performanceMode_forUnsignedInt)234 TEST(Logging, performanceMode_forUnsignedInt)
235 {
236 test_forIntegerNumber<unsigned int>(0);
237 test_forIntegerNumber<unsigned int>(42);
238 test_forIntegerNumber<unsigned int>(std::numeric_limits<unsigned int>::lowest());
239 test_forIntegerNumber<unsigned int>(std::numeric_limits<unsigned int>::max());
240 }
241
TEST(Logging,performanceMode_forUnsignedLong)242 TEST(Logging, performanceMode_forUnsignedLong)
243 {
244 test_forIntegerNumber<unsigned long>(0);
245 test_forIntegerNumber<unsigned long>(42);
246 test_forIntegerNumber<unsigned long>(std::numeric_limits<unsigned long>::lowest());
247 test_forIntegerNumber<unsigned long>(std::numeric_limits<unsigned long>::max());
248 }
249
TEST(Logging,performanceMode_forUnsignedLongLong)250 TEST(Logging, performanceMode_forUnsignedLongLong)
251 {
252 test_forIntegerNumber<unsigned long long>(0);
253 test_forIntegerNumber<unsigned long long>(42);
254 test_forIntegerNumber<unsigned long long>(std::numeric_limits<unsigned long long>::lowest());
255 test_forIntegerNumber<unsigned long long>(std::numeric_limits<unsigned long long>::max());
256 }
257
TEST(Logging,performanceMode_forFloat)258 TEST(Logging, performanceMode_forFloat)
259 {
260 test_forFloatingNumber<float>(0.f);
261 test_forFloatingNumber<float>(42.123f);
262 test_forFloatingNumber<float>(-42.123f);
263 test_forFloatingNumber<float>(std::numeric_limits<float>::lowest());
264 test_forFloatingNumber<float>(std::numeric_limits<float>::min());
265 test_forFloatingNumber<float>(std::numeric_limits<float>::max());
266 }
267
TEST(Logging,performanceMode_forDouble)268 TEST(Logging, performanceMode_forDouble)
269 {
270 test_forFloatingNumber<double>(0.);
271 test_forFloatingNumber<double>(42.123);
272 test_forFloatingNumber<double>(-42.123);
273 test_forFloatingNumber<double>(std::numeric_limits<double>::lowest());
274 test_forFloatingNumber<double>(std::numeric_limits<double>::min());
275 test_forFloatingNumber<double>(std::numeric_limits<double>::max());
276 }
277
TEST(Logging,performanceMode_withMessageLargeThanLogBuffer)278 TEST(Logging, performanceMode_withMessageLargeThanLogBuffer)
279 {
280 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
281 {
282 MockLogger logger;
283 const std::string file = "file.cpp";
284 const int line = 13;
285 const std::string firstMessage(256 - file.size() - 5, 'X'); // 5 = ':13 ' plus null terminator
286 const std::string secondMessage = "yay";
287 const std::string message = firstMessage + secondMessage;
288 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << message;
289 logger.checkLogLevel(level);
290 ASSERT_EQ(2, logger.mMessage.size());
291 ASSERT_EQ(expMsg(file, line, message).substr(0,255), logger.mMessage[0]);
292 ASSERT_EQ(expMsg(file, line, message).substr(255), logger.mMessage[1]);
293 }
294 }
295
TEST(Logging,performanceMode_withHugeMessage)296 TEST(Logging, performanceMode_withHugeMessage)
297 {
298 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
299 {
300 MockLogger logger;
301 const std::string file = "file.cpp";
302 const int line = 13;
303 const std::string message(5000, 'X');
304 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << message;
305 logger.checkLogLevel(level);
306
307 const int totallength = 5000 + strlen(" [file.cpp:13]") + 1;
308 const size_t fullMsgCount = totallength / 255;
309 ASSERT_EQ(fullMsgCount + 1, logger.mMessage.size());
310 ASSERT_EQ(totallength % 255 - 1, logger.mMessage.back().size());
311 }
312 }
313
TEST(Logging,performanceMode_withHugeMessage_butNoLogger)314 TEST(Logging, performanceMode_withHugeMessage_butNoLogger)
315 {
316 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
317 {
318 mega::SimpleLogger::logger = nullptr;
319 const std::string file = "file.cpp";
320 const int line = 13;
321 const std::string message(5000, 'X');
322 mega::SimpleLogger{static_cast<mega::LogLevel>(level), file.c_str(), line} << message;
323 // ensure no crash or other funny business
324 }
325 }
326
327 #else
328
329 namespace {
330
331 class MockLogger : public mega::Logger
332 {
333 public:
334
MockLogger()335 MockLogger()
336 {
337 mega::SimpleLogger::logger = this;
338 }
339
~MockLogger()340 ~MockLogger()
341 {
342 mega::SimpleLogger::logger = nullptr;
343 }
344
log(const char * time,int loglevel,const char * source,const char * message)345 void log(const char *time, int loglevel, const char *source, const char *message) override
346 {
347 EXPECT_NE(nullptr, time);
348 EXPECT_NE(nullptr, source);
349 EXPECT_NE(nullptr, message);
350 mLogLevel.insert(loglevel);
351 mMessage.push_back(message);
352 }
353
checkLogLevel(const int expLogLevel) const354 void checkLogLevel(const int expLogLevel) const
355 {
356 EXPECT_EQ(1u, mLogLevel.size());
357 EXPECT_EQ(expLogLevel, *mLogLevel.begin());
358 }
359
360 std::vector<std::string> mMessage;
361
362 private:
363 std::set<int> mLogLevel;
364 };
365
366 }
367
368 #endif
369
TEST(Logging,toStr)370 TEST(Logging, toStr)
371 {
372 ASSERT_EQ(0, std::strcmp("verbose", mega::SimpleLogger::toStr(mega::LogLevel::logMax)));
373 ASSERT_EQ(0, std::strcmp("debug", mega::SimpleLogger::toStr(mega::LogLevel::logDebug)));
374 ASSERT_EQ(0, std::strcmp("info", mega::SimpleLogger::toStr(mega::LogLevel::logInfo)));
375 ASSERT_EQ(0, std::strcmp("warn", mega::SimpleLogger::toStr(mega::LogLevel::logWarning)));
376 ASSERT_EQ(0, std::strcmp("err", mega::SimpleLogger::toStr(mega::LogLevel::logError)));
377 ASSERT_EQ(0, std::strcmp("FATAL", mega::SimpleLogger::toStr(mega::LogLevel::logFatal)));
378 }
379
380 #ifdef NDEBUG
TEST(Logging,toStr_withBadLogLevel)381 TEST(Logging, toStr_withBadLogLevel)
382 {
383 ASSERT_EQ(0, std::strcmp("", mega::SimpleLogger::toStr(static_cast<mega::LogLevel>(42))));
384 }
385 #endif
386
TEST(Logging,macroVerbose)387 TEST(Logging, macroVerbose)
388 {
389 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
390 {
391 MockLogger logger;
392 mega::SimpleLogger::setLogLevel(static_cast<mega::LogLevel>(level));
393 const std::string msg = "foobar";
394 LOG_verbose << msg;
395 const auto currentLevel = mega::LogLevel::logMax;
396 if (level >= currentLevel)
397 {
398 logger.checkLogLevel(currentLevel);
399 ASSERT_EQ(1u, logger.mMessage.size());
400 EXPECT_NE(logger.mMessage[0].find(msg), std::string::npos);
401 }
402 else
403 {
404 ASSERT_EQ(0u, logger.mMessage.size());
405 }
406 }
407 }
408
TEST(Logging,macroDebug)409 TEST(Logging, macroDebug)
410 {
411 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
412 {
413 MockLogger logger;
414 mega::SimpleLogger::setLogLevel(static_cast<mega::LogLevel>(level));
415 const std::string msg = "foobar";
416 LOG_debug << msg;
417 const auto currentLevel = mega::LogLevel::logDebug;
418 if (level >= currentLevel)
419 {
420 logger.checkLogLevel(currentLevel);
421 ASSERT_EQ(1u, logger.mMessage.size());
422 EXPECT_NE(logger.mMessage[0].find(msg), std::string::npos);
423 }
424 else
425 {
426 ASSERT_EQ(0u, logger.mMessage.size());
427 }
428 }
429 }
430
TEST(Logging,macroInfo)431 TEST(Logging, macroInfo)
432 {
433 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
434 {
435 MockLogger logger;
436 mega::SimpleLogger::setLogLevel(static_cast<mega::LogLevel>(level));
437 const std::string msg = "foobar";
438 LOG_info << msg;
439 const auto currentLevel = mega::LogLevel::logInfo;
440 if (level >= currentLevel)
441 {
442 logger.checkLogLevel(currentLevel);
443 ASSERT_EQ(1u, logger.mMessage.size());
444 EXPECT_NE(logger.mMessage[0].find(msg), std::string::npos);
445 }
446 else
447 {
448 ASSERT_EQ(0u, logger.mMessage.size());
449 }
450 }
451 }
452
TEST(Logging,macroWarn)453 TEST(Logging, macroWarn)
454 {
455 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
456 {
457 MockLogger logger;
458 mega::SimpleLogger::setLogLevel(static_cast<mega::LogLevel>(level));
459 const std::string msg = "foobar";
460 LOG_warn << msg;
461 const auto currentLevel = mega::LogLevel::logWarning;
462 if (level >= currentLevel)
463 {
464 logger.checkLogLevel(currentLevel);
465 ASSERT_EQ(1u, logger.mMessage.size());
466 EXPECT_NE(logger.mMessage[0].find(msg), std::string::npos);
467 }
468 else
469 {
470 ASSERT_EQ(0u, logger.mMessage.size());
471 }
472 }
473 }
474
TEST(Logging,macroErr)475 TEST(Logging, macroErr)
476 {
477 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
478 {
479 MockLogger logger;
480 mega::SimpleLogger::setLogLevel(static_cast<mega::LogLevel>(level));
481 const std::string msg = "foobar";
482 LOG_err << msg;
483 const auto currentLevel = mega::LogLevel::logError;
484 if (level >= currentLevel)
485 {
486 logger.checkLogLevel(currentLevel);
487 ASSERT_EQ(1u, logger.mMessage.size());
488 EXPECT_NE(logger.mMessage[0].find(msg), std::string::npos);
489 }
490 else
491 {
492 ASSERT_EQ(0u, logger.mMessage.size());
493 }
494 }
495 }
496
TEST(Logging,macroFatal)497 TEST(Logging, macroFatal)
498 {
499 for (int level = 0; level <= mega::LogLevel::logMax; ++level)
500 {
501 MockLogger logger;
502 mega::SimpleLogger::setLogLevel(static_cast<mega::LogLevel>(level));
503 const std::string msg = "foobar";
504 LOG_fatal << msg;
505 logger.checkLogLevel(mega::LogLevel::logFatal);
506 ASSERT_EQ(1u, logger.mMessage.size());
507 EXPECT_NE(logger.mMessage[0].find(msg), std::string::npos);
508 }
509 }
510
511 #endif
512