Home | History | Annotate | Download | only in broadcastradio-vts-utils
      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