Tomasz Wasilczyk | c9ba646 | 2017-07-07 13:28:00 -0700 | [diff] [blame^] | 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_V1_1_MOCK_TIMEOUT |
| 17 | #define ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT |
| 18 | |
| 19 | #include <gmock/gmock.h> |
| 20 | #include <thread> |
| 21 | |
| 22 | /** |
| 23 | * Common helper objects for gmock timeout extension. |
| 24 | * |
| 25 | * INTERNAL IMPLEMENTATION - don't use in user code. |
| 26 | */ |
| 27 | #define EGMOCK_TIMEOUT_METHOD_DEF_(Method, ...) \ |
| 28 | std::atomic<bool> egmock_called_##Method; \ |
| 29 | std::mutex egmock_mut_##Method; \ |
| 30 | std::condition_variable egmock_cond_##Method; |
| 31 | |
| 32 | /** |
| 33 | * Common method body for gmock timeout extension. |
| 34 | * |
| 35 | * INTERNAL IMPLEMENTATION - don't use in user code. |
| 36 | */ |
| 37 | #define EGMOCK_TIMEOUT_METHOD_BODY_(Method, ...) \ |
| 38 | auto ret = egmock_##Method(__VA_ARGS__); \ |
| 39 | { \ |
| 40 | std::lock_guard<std::mutex> lk(egmock_mut_##Method); \ |
| 41 | egmock_called_##Method = true; \ |
| 42 | egmock_cond_##Method.notify_all(); \ |
| 43 | } \ |
| 44 | return ret; |
| 45 | |
| 46 | /** |
| 47 | * Gmock MOCK_METHOD1 timeout-capable extension. |
| 48 | */ |
| 49 | #define MOCK_TIMEOUT_METHOD1(Method, ...) \ |
| 50 | MOCK_METHOD1(egmock_##Method, __VA_ARGS__); \ |
| 51 | EGMOCK_TIMEOUT_METHOD_DEF_(Method); \ |
| 52 | virtual GMOCK_RESULT_(, __VA_ARGS__) Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1) { \ |
| 53 | EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1); \ |
| 54 | } |
| 55 | |
| 56 | /** |
| 57 | * Gmock MOCK_METHOD2 timeout-capable extension. |
| 58 | */ |
| 59 | #define MOCK_TIMEOUT_METHOD2(Method, ...) \ |
| 60 | MOCK_METHOD2(egmock_##Method, __VA_ARGS__); \ |
| 61 | EGMOCK_TIMEOUT_METHOD_DEF_(Method); \ |
| 62 | virtual GMOCK_RESULT_(, __VA_ARGS__) \ |
| 63 | Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1, GMOCK_ARG_(, 2, __VA_ARGS__) egmock_a2) { \ |
| 64 | EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1, egmock_a2); \ |
| 65 | } |
| 66 | |
| 67 | /** |
| 68 | * Gmock EXPECT_CALL timeout-capable extension. |
| 69 | * |
| 70 | * It has slightly different syntax from the original macro, to make method name accessible. |
| 71 | * So, instead of typing |
| 72 | * EXPECT_CALL(account, charge(100, Currency::USD)); |
| 73 | * you need to inline arguments |
| 74 | * EXPECT_TIMEOUT_CALL(account, charge, 100, Currency::USD); |
| 75 | */ |
| 76 | #define EXPECT_TIMEOUT_CALL(obj, Method, ...) \ |
| 77 | (obj).egmock_called_##Method = false; \ |
| 78 | EXPECT_CALL(obj, egmock_##Method(__VA_ARGS__)) |
| 79 | |
| 80 | /** |
| 81 | * Waits for an earlier EXPECT_TIMEOUT_CALL to execute. |
| 82 | * |
| 83 | * It does not fully support special constraints of the EXPECT_CALL clause, just proceeds when the |
| 84 | * first call to a given method comes. For example, in the following code: |
| 85 | * EXPECT_TIMEOUT_CALL(account, charge, 100, _); |
| 86 | * account.charge(50, Currency::USD); |
| 87 | * EXPECT_TIMEOUT_CALL_WAIT(account, charge, 500ms); |
| 88 | * the wait clause will just continue, as the charge method was called. |
| 89 | * |
| 90 | * @param obj object for a call |
| 91 | * @param Method the method to wait for |
| 92 | * @param timeout the maximum time for waiting |
| 93 | */ |
| 94 | #define EXPECT_TIMEOUT_CALL_WAIT(obj, Method, timeout) \ |
| 95 | { \ |
| 96 | std::unique_lock<std::mutex> lk((obj).egmock_mut_##Method); \ |
| 97 | if (!(obj).egmock_called_##Method) { \ |
| 98 | auto status = (obj).egmock_cond_##Method.wait_for(lk, timeout); \ |
| 99 | EXPECT_EQ(std::cv_status::no_timeout, status); \ |
| 100 | } \ |
| 101 | } |
| 102 | |
| 103 | #endif // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT |