1 /* 2 * Copyright (C) 2017 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 #ifndef ANDROID_HARDWARE_BROADCASTRADIO_VTS_MOCK_TIMEOUT 17 #define ANDROID_HARDWARE_BROADCASTRADIO_VTS_MOCK_TIMEOUT 18 19 #include <gmock/gmock.h> 20 #include <thread> 21 22 #ifndef EGMOCK_VERBOSE 23 #define EGMOCK_VERBOSE 0 24 #endif 25 26 /** 27 * Print log message. 28 * 29 * INTERNAL IMPLEMENTATION - don't use in user code. 30 */ 31 #if EGMOCK_VERBOSE 32 #define EGMOCK_LOG_(...) ALOGV("egmock: " __VA_ARGS__) 33 #else 34 #define EGMOCK_LOG_(...) 35 #endif 36 37 /** 38 * Common helper objects for gmock timeout extension. 39 * 40 * INTERNAL IMPLEMENTATION - don't use in user code. 41 */ 42 #define EGMOCK_TIMEOUT_METHOD_DEF_(Method, ...) \ 43 std::atomic<bool> egmock_called_##Method; \ 44 std::mutex egmock_mut_##Method; \ 45 std::condition_variable egmock_cond_##Method; 46 47 /** 48 * Function similar to comma operator, to make it possible to return any value returned by mocked 49 * function (which may be void) and discard the result of the other operation (notification about 50 * a call). 51 * 52 * We need to invoke the mocked function (which result is returned) before the notification (which 53 * result is dropped) - that's exactly the opposite of comma operator. 54 * 55 * INTERNAL IMPLEMENTATION - don't use in user code. 56 */ 57 template <typename T> 58 static T EGMockFlippedComma_(std::function<T()> returned, std::function<void()> discarded) { 59 auto ret = returned(); 60 discarded(); 61 return ret; 62 } 63 64 template <> 65 inline void EGMockFlippedComma_(std::function<void()> returned, std::function<void()> discarded) { 66 returned(); 67 discarded(); 68 } 69 70 /** 71 * Common method body for gmock timeout extension. 72 * 73 * INTERNAL IMPLEMENTATION - don't use in user code. 74 */ 75 #define EGMOCK_TIMEOUT_METHOD_BODY_(Method, ...) \ 76 auto invokeMock = [&]() { return egmock_##Method(__VA_ARGS__); }; \ 77 auto notify = [&]() { \ 78 std::lock_guard<std::mutex> lk(egmock_mut_##Method); \ 79 EGMOCK_LOG_(#Method " called"); \ 80 egmock_called_##Method = true; \ 81 egmock_cond_##Method.notify_all(); \ 82 }; \ 83 return EGMockFlippedComma_<decltype(invokeMock())>(invokeMock, notify); 84 85 /** 86 * Gmock MOCK_METHOD0 timeout-capable extension. 87 */ 88 #define MOCK_TIMEOUT_METHOD0(Method, ...) \ 89 MOCK_METHOD0(egmock_##Method, __VA_ARGS__); \ 90 EGMOCK_TIMEOUT_METHOD_DEF_(Method); \ 91 virtual GMOCK_RESULT_(, __VA_ARGS__) Method() { EGMOCK_TIMEOUT_METHOD_BODY_(Method); } 92 93 /** 94 * Gmock MOCK_METHOD1 timeout-capable extension. 95 */ 96 #define MOCK_TIMEOUT_METHOD1(Method, ...) \ 97 MOCK_METHOD1(egmock_##Method, __VA_ARGS__); \ 98 EGMOCK_TIMEOUT_METHOD_DEF_(Method); \ 99 virtual GMOCK_RESULT_(, __VA_ARGS__) Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1) { \ 100 EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1); \ 101 } 102 103 /** 104 * Gmock MOCK_METHOD2 timeout-capable extension. 105 */ 106 #define MOCK_TIMEOUT_METHOD2(Method, ...) \ 107 MOCK_METHOD2(egmock_##Method, __VA_ARGS__); \ 108 EGMOCK_TIMEOUT_METHOD_DEF_(Method); \ 109 virtual GMOCK_RESULT_(, __VA_ARGS__) \ 110 Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1, GMOCK_ARG_(, 2, __VA_ARGS__) egmock_a2) { \ 111 EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1, egmock_a2); \ 112 } 113 114 /** 115 * Gmock EXPECT_CALL timeout-capable extension. 116 * 117 * It has slightly different syntax from the original macro, to make method name accessible. 118 * So, instead of typing 119 * EXPECT_CALL(account, charge(100, Currency::USD)); 120 * you need to inline arguments 121 * EXPECT_TIMEOUT_CALL(account, charge, 100, Currency::USD); 122 */ 123 #define EXPECT_TIMEOUT_CALL(obj, Method, ...) \ 124 EGMOCK_LOG_(#Method " expected to call"); \ 125 (obj).egmock_called_##Method = false; \ 126 EXPECT_CALL(obj, egmock_##Method(__VA_ARGS__)) 127 128 /** 129 * Waits for an earlier EXPECT_TIMEOUT_CALL to execute. 130 * 131 * It does not fully support special constraints of the EXPECT_CALL clause, just proceeds when the 132 * first call to a given method comes. For example, in the following code: 133 * EXPECT_TIMEOUT_CALL(account, charge, 100, _); 134 * account.charge(50, Currency::USD); 135 * EXPECT_TIMEOUT_CALL_WAIT(account, charge, 500ms); 136 * the wait clause will just continue, as the charge method was called. 137 * 138 * @param obj object for a call 139 * @param Method the method to wait for 140 * @param timeout the maximum time for waiting 141 */ 142 #define EXPECT_TIMEOUT_CALL_WAIT(obj, Method, timeout) \ 143 { \ 144 EGMOCK_LOG_("waiting for " #Method " call"); \ 145 std::unique_lock<std::mutex> lk((obj).egmock_mut_##Method); \ 146 if (!(obj).egmock_called_##Method) { \ 147 auto status = (obj).egmock_cond_##Method.wait_for(lk, timeout); \ 148 EXPECT_EQ(std::cv_status::no_timeout, status); \ 149 } \ 150 } 151 152 #endif // ANDROID_HARDWARE_BROADCASTRADIO_VTS_MOCK_TIMEOUT 153