1*9356374aSAndroid Build Coastguard Worker // Copyright 2022 The Abseil Authors. 2*9356374aSAndroid Build Coastguard Worker // 3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); 4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License. 5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at 6*9356374aSAndroid Build Coastguard Worker // 7*9356374aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0 8*9356374aSAndroid Build Coastguard Worker // 9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software 10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, 11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and 13*9356374aSAndroid Build Coastguard Worker // limitations under the License. 14*9356374aSAndroid Build Coastguard Worker // 15*9356374aSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------- 16*9356374aSAndroid Build Coastguard Worker // File: log/scoped_mock_log.h 17*9356374aSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------- 18*9356374aSAndroid Build Coastguard Worker // 19*9356374aSAndroid Build Coastguard Worker // This header declares `class absl::ScopedMockLog`, for use in testing. 20*9356374aSAndroid Build Coastguard Worker 21*9356374aSAndroid Build Coastguard Worker #ifndef ABSL_LOG_SCOPED_MOCK_LOG_H_ 22*9356374aSAndroid Build Coastguard Worker #define ABSL_LOG_SCOPED_MOCK_LOG_H_ 23*9356374aSAndroid Build Coastguard Worker 24*9356374aSAndroid Build Coastguard Worker #include <atomic> 25*9356374aSAndroid Build Coastguard Worker #include <string> 26*9356374aSAndroid Build Coastguard Worker 27*9356374aSAndroid Build Coastguard Worker #include "gmock/gmock.h" 28*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h" 29*9356374aSAndroid Build Coastguard Worker #include "absl/base/log_severity.h" 30*9356374aSAndroid Build Coastguard Worker #include "absl/log/log_entry.h" 31*9356374aSAndroid Build Coastguard Worker #include "absl/log/log_sink.h" 32*9356374aSAndroid Build Coastguard Worker 33*9356374aSAndroid Build Coastguard Worker namespace absl { 34*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN 35*9356374aSAndroid Build Coastguard Worker 36*9356374aSAndroid Build Coastguard Worker // MockLogDefault 37*9356374aSAndroid Build Coastguard Worker // 38*9356374aSAndroid Build Coastguard Worker // Controls how ScopedMockLog responds to unexpected calls by default. 39*9356374aSAndroid Build Coastguard Worker enum class MockLogDefault { kIgnoreUnexpected, kDisallowUnexpected }; 40*9356374aSAndroid Build Coastguard Worker 41*9356374aSAndroid Build Coastguard Worker // ScopedMockLog 42*9356374aSAndroid Build Coastguard Worker // 43*9356374aSAndroid Build Coastguard Worker // ScopedMockLog is a LogSink that intercepts LOG() messages issued during its 44*9356374aSAndroid Build Coastguard Worker // lifespan. 45*9356374aSAndroid Build Coastguard Worker // 46*9356374aSAndroid Build Coastguard Worker // Using this together with GoogleTest, it's easy to test how a piece of code 47*9356374aSAndroid Build Coastguard Worker // calls LOG(). The typical usage, noting the distinction between 48*9356374aSAndroid Build Coastguard Worker // "uninteresting" and "unexpected", looks like this: 49*9356374aSAndroid Build Coastguard Worker // 50*9356374aSAndroid Build Coastguard Worker // using ::testing::_; 51*9356374aSAndroid Build Coastguard Worker // using ::testing::AnyNumber; 52*9356374aSAndroid Build Coastguard Worker // using ::testing::EndsWith; 53*9356374aSAndroid Build Coastguard Worker // using ::testing::kDoNotCaptureLogsYet; 54*9356374aSAndroid Build Coastguard Worker // using ::testing::Lt; 55*9356374aSAndroid Build Coastguard Worker // 56*9356374aSAndroid Build Coastguard Worker // TEST(FooTest, LogsCorrectly) { 57*9356374aSAndroid Build Coastguard Worker // // Simple robust setup, ignores unexpected logs. 58*9356374aSAndroid Build Coastguard Worker // absl::ScopedMockLog log; 59*9356374aSAndroid Build Coastguard Worker // 60*9356374aSAndroid Build Coastguard Worker // // We expect the WARNING "Something bad!" exactly twice. 61*9356374aSAndroid Build Coastguard Worker // EXPECT_CALL(log, Log(absl::LogSeverity::kWarning, _, "Something bad!")) 62*9356374aSAndroid Build Coastguard Worker // .Times(2); 63*9356374aSAndroid Build Coastguard Worker // 64*9356374aSAndroid Build Coastguard Worker // // But we want no messages from foo.cc. 65*9356374aSAndroid Build Coastguard Worker // EXPECT_CALL(log, Log(_, EndsWith("/foo.cc"), _)).Times(0); 66*9356374aSAndroid Build Coastguard Worker // 67*9356374aSAndroid Build Coastguard Worker // log.StartCapturingLogs(); // Call this after done setting expectations. 68*9356374aSAndroid Build Coastguard Worker // Foo(); // Exercises the code under test. 69*9356374aSAndroid Build Coastguard Worker // } 70*9356374aSAndroid Build Coastguard Worker // 71*9356374aSAndroid Build Coastguard Worker // TEST(BarTest, LogsExactlyCorrectly) { 72*9356374aSAndroid Build Coastguard Worker // // Strict checking, fails for unexpected logs. 73*9356374aSAndroid Build Coastguard Worker // absl::ScopedMockLog log(absl::MockLogDefault::kDisallowUnexpected); 74*9356374aSAndroid Build Coastguard Worker // 75*9356374aSAndroid Build Coastguard Worker // // ... but ignore low severity messages 76*9356374aSAndroid Build Coastguard Worker // EXPECT_CALL(log, Log(Lt(absl::LogSeverity::kWarning), _, _)) 77*9356374aSAndroid Build Coastguard Worker // .Times(AnyNumber()); 78*9356374aSAndroid Build Coastguard Worker // 79*9356374aSAndroid Build Coastguard Worker // // We expect the ERROR "Something bad!" exactly once. 80*9356374aSAndroid Build Coastguard Worker // EXPECT_CALL(log, Log(absl::LogSeverity::kError, EndsWith("/foo.cc"), 81*9356374aSAndroid Build Coastguard Worker // "Something bad!")) 82*9356374aSAndroid Build Coastguard Worker // .Times(1); 83*9356374aSAndroid Build Coastguard Worker // 84*9356374aSAndroid Build Coastguard Worker // log.StartCapturingLogs(); // Call this after done setting expectations. 85*9356374aSAndroid Build Coastguard Worker // Bar(); // Exercises the code under test. 86*9356374aSAndroid Build Coastguard Worker // } 87*9356374aSAndroid Build Coastguard Worker // 88*9356374aSAndroid Build Coastguard Worker // Note that in a multi-threaded environment, all LOG() messages from a single 89*9356374aSAndroid Build Coastguard Worker // thread will be handled in sequence, but that cannot be guaranteed for 90*9356374aSAndroid Build Coastguard Worker // messages from different threads. In fact, if the same or multiple 91*9356374aSAndroid Build Coastguard Worker // expectations are matched on two threads concurrently, their actions will be 92*9356374aSAndroid Build Coastguard Worker // executed concurrently as well and may interleave. 93*9356374aSAndroid Build Coastguard Worker class ScopedMockLog final { 94*9356374aSAndroid Build Coastguard Worker public: 95*9356374aSAndroid Build Coastguard Worker // ScopedMockLog::ScopedMockLog() 96*9356374aSAndroid Build Coastguard Worker // 97*9356374aSAndroid Build Coastguard Worker // Sets up the log and adds default expectations. 98*9356374aSAndroid Build Coastguard Worker explicit ScopedMockLog( 99*9356374aSAndroid Build Coastguard Worker MockLogDefault default_exp = MockLogDefault::kIgnoreUnexpected); 100*9356374aSAndroid Build Coastguard Worker ScopedMockLog(const ScopedMockLog&) = delete; 101*9356374aSAndroid Build Coastguard Worker ScopedMockLog& operator=(const ScopedMockLog&) = delete; 102*9356374aSAndroid Build Coastguard Worker 103*9356374aSAndroid Build Coastguard Worker // ScopedMockLog::~ScopedMockLog() 104*9356374aSAndroid Build Coastguard Worker // 105*9356374aSAndroid Build Coastguard Worker // Stops intercepting logs and destroys this ScopedMockLog. 106*9356374aSAndroid Build Coastguard Worker ~ScopedMockLog(); 107*9356374aSAndroid Build Coastguard Worker 108*9356374aSAndroid Build Coastguard Worker // ScopedMockLog::StartCapturingLogs() 109*9356374aSAndroid Build Coastguard Worker // 110*9356374aSAndroid Build Coastguard Worker // Starts log capturing if the object isn't already doing so. Otherwise 111*9356374aSAndroid Build Coastguard Worker // crashes. 112*9356374aSAndroid Build Coastguard Worker // 113*9356374aSAndroid Build Coastguard Worker // Usually this method is called in the same thread that created this 114*9356374aSAndroid Build Coastguard Worker // ScopedMockLog. It is the user's responsibility to not call this method if 115*9356374aSAndroid Build Coastguard Worker // another thread may be calling it or StopCapturingLogs() at the same time. 116*9356374aSAndroid Build Coastguard Worker // It is undefined behavior to add expectations while capturing logs is 117*9356374aSAndroid Build Coastguard Worker // enabled. 118*9356374aSAndroid Build Coastguard Worker void StartCapturingLogs(); 119*9356374aSAndroid Build Coastguard Worker 120*9356374aSAndroid Build Coastguard Worker // ScopedMockLog::StopCapturingLogs() 121*9356374aSAndroid Build Coastguard Worker // 122*9356374aSAndroid Build Coastguard Worker // Stops log capturing if the object is capturing logs. Otherwise crashes. 123*9356374aSAndroid Build Coastguard Worker // 124*9356374aSAndroid Build Coastguard Worker // Usually this method is called in the same thread that created this object. 125*9356374aSAndroid Build Coastguard Worker // It is the user's responsibility to not call this method if another thread 126*9356374aSAndroid Build Coastguard Worker // may be calling it or StartCapturingLogs() at the same time. 127*9356374aSAndroid Build Coastguard Worker // 128*9356374aSAndroid Build Coastguard Worker // It is UB to add expectations, while capturing logs is enabled. 129*9356374aSAndroid Build Coastguard Worker void StopCapturingLogs(); 130*9356374aSAndroid Build Coastguard Worker 131*9356374aSAndroid Build Coastguard Worker // ScopedMockLog::UseAsLocalSink() 132*9356374aSAndroid Build Coastguard Worker // 133*9356374aSAndroid Build Coastguard Worker // Each `ScopedMockLog` is implemented with an `absl::LogSink`; this method 134*9356374aSAndroid Build Coastguard Worker // returns a reference to that sink (e.g. for use with 135*9356374aSAndroid Build Coastguard Worker // `LOG(...).ToSinkOnly()`) and marks the `ScopedMockLog` as having been used 136*9356374aSAndroid Build Coastguard Worker // even if `StartCapturingLogs` is never called. 137*9356374aSAndroid Build Coastguard Worker absl::LogSink& UseAsLocalSink(); 138*9356374aSAndroid Build Coastguard Worker 139*9356374aSAndroid Build Coastguard Worker // Implements the mock method: 140*9356374aSAndroid Build Coastguard Worker // 141*9356374aSAndroid Build Coastguard Worker // void Log(LogSeverity severity, absl::string_view file_path, 142*9356374aSAndroid Build Coastguard Worker // absl::string_view message); 143*9356374aSAndroid Build Coastguard Worker // 144*9356374aSAndroid Build Coastguard Worker // The second argument to Log() is the full path of the source file in 145*9356374aSAndroid Build Coastguard Worker // which the LOG() was issued. 146*9356374aSAndroid Build Coastguard Worker // 147*9356374aSAndroid Build Coastguard Worker // This is a shorthand form, which should be used by most users. Use the 148*9356374aSAndroid Build Coastguard Worker // `Send` mock only if you want to add expectations for other log message 149*9356374aSAndroid Build Coastguard Worker // attributes. 150*9356374aSAndroid Build Coastguard Worker MOCK_METHOD(void, Log, 151*9356374aSAndroid Build Coastguard Worker (absl::LogSeverity severity, const std::string& file_path, 152*9356374aSAndroid Build Coastguard Worker const std::string& message)); 153*9356374aSAndroid Build Coastguard Worker 154*9356374aSAndroid Build Coastguard Worker // Implements the mock method: 155*9356374aSAndroid Build Coastguard Worker // 156*9356374aSAndroid Build Coastguard Worker // void Send(const absl::LogEntry& entry); 157*9356374aSAndroid Build Coastguard Worker // 158*9356374aSAndroid Build Coastguard Worker // This is the most generic form of mock that can be specified. Use this mock 159*9356374aSAndroid Build Coastguard Worker // only if you want to add expectations for log message attributes different 160*9356374aSAndroid Build Coastguard Worker // from the log message text, log message path and log message severity. 161*9356374aSAndroid Build Coastguard Worker // 162*9356374aSAndroid Build Coastguard Worker // If no expectations are specified for this mock, the default action is to 163*9356374aSAndroid Build Coastguard Worker // forward the call to the `Log` mock. 164*9356374aSAndroid Build Coastguard Worker MOCK_METHOD(void, Send, (const absl::LogEntry&)); 165*9356374aSAndroid Build Coastguard Worker 166*9356374aSAndroid Build Coastguard Worker // Implements the mock method: 167*9356374aSAndroid Build Coastguard Worker // 168*9356374aSAndroid Build Coastguard Worker // void Flush(); 169*9356374aSAndroid Build Coastguard Worker // 170*9356374aSAndroid Build Coastguard Worker // Use this mock only if you want to add expectations for log flush calls. 171*9356374aSAndroid Build Coastguard Worker MOCK_METHOD(void, Flush, ()); 172*9356374aSAndroid Build Coastguard Worker 173*9356374aSAndroid Build Coastguard Worker private: 174*9356374aSAndroid Build Coastguard Worker class ForwardingSink final : public absl::LogSink { 175*9356374aSAndroid Build Coastguard Worker public: ForwardingSink(ScopedMockLog * sml)176*9356374aSAndroid Build Coastguard Worker explicit ForwardingSink(ScopedMockLog* sml) : sml_(sml) {} 177*9356374aSAndroid Build Coastguard Worker ForwardingSink(const ForwardingSink&) = delete; 178*9356374aSAndroid Build Coastguard Worker ForwardingSink& operator=(const ForwardingSink&) = delete; Send(const absl::LogEntry & entry)179*9356374aSAndroid Build Coastguard Worker void Send(const absl::LogEntry& entry) override { sml_->Send(entry); } Flush()180*9356374aSAndroid Build Coastguard Worker void Flush() override { sml_->Flush(); } 181*9356374aSAndroid Build Coastguard Worker 182*9356374aSAndroid Build Coastguard Worker private: 183*9356374aSAndroid Build Coastguard Worker ScopedMockLog* sml_; 184*9356374aSAndroid Build Coastguard Worker }; 185*9356374aSAndroid Build Coastguard Worker 186*9356374aSAndroid Build Coastguard Worker ForwardingSink sink_; 187*9356374aSAndroid Build Coastguard Worker bool is_capturing_logs_; 188*9356374aSAndroid Build Coastguard Worker // Until C++20, the default constructor leaves the underlying value wrapped in 189*9356374aSAndroid Build Coastguard Worker // std::atomic uninitialized, so all constructors should be sure to initialize 190*9356374aSAndroid Build Coastguard Worker // is_triggered_. 191*9356374aSAndroid Build Coastguard Worker std::atomic<bool> is_triggered_; 192*9356374aSAndroid Build Coastguard Worker }; 193*9356374aSAndroid Build Coastguard Worker 194*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END 195*9356374aSAndroid Build Coastguard Worker } // namespace absl 196*9356374aSAndroid Build Coastguard Worker 197*9356374aSAndroid Build Coastguard Worker #endif // ABSL_LOG_SCOPED_MOCK_LOG_H_ 198