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_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_METHOD0 timeout-capable extension.
     48  */
     49 #define MOCK_TIMEOUT_METHOD0(Method, ...)       \
     50     MOCK_METHOD0(egmock_##Method, __VA_ARGS__); \
     51     EGMOCK_TIMEOUT_METHOD_DEF_(Method);         \
     52     virtual GMOCK_RESULT_(, __VA_ARGS__) Method() { EGMOCK_TIMEOUT_METHOD_BODY_(Method); }
     53 
     54 /**
     55  * Gmock MOCK_METHOD1 timeout-capable extension.
     56  */
     57 #define MOCK_TIMEOUT_METHOD1(Method, ...)                                                 \
     58     MOCK_METHOD1(egmock_##Method, __VA_ARGS__);                                           \
     59     EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                   \
     60     virtual GMOCK_RESULT_(, __VA_ARGS__) Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1) { \
     61         EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1);                                   \
     62     }
     63 
     64 /**
     65  * Gmock MOCK_METHOD2 timeout-capable extension.
     66  */
     67 #define MOCK_TIMEOUT_METHOD2(Method, ...)                                                        \
     68     MOCK_METHOD2(egmock_##Method, __VA_ARGS__);                                                  \
     69     EGMOCK_TIMEOUT_METHOD_DEF_(Method);                                                          \
     70     virtual GMOCK_RESULT_(, __VA_ARGS__)                                                         \
     71         Method(GMOCK_ARG_(, 1, __VA_ARGS__) egmock_a1, GMOCK_ARG_(, 2, __VA_ARGS__) egmock_a2) { \
     72         EGMOCK_TIMEOUT_METHOD_BODY_(Method, egmock_a1, egmock_a2);                               \
     73     }
     74 
     75 /**
     76  * Gmock EXPECT_CALL timeout-capable extension.
     77  *
     78  * It has slightly different syntax from the original macro, to make method name accessible.
     79  * So, instead of typing
     80  *     EXPECT_CALL(account, charge(100, Currency::USD));
     81  * you need to inline arguments
     82  *     EXPECT_TIMEOUT_CALL(account, charge, 100, Currency::USD);
     83  */
     84 #define EXPECT_TIMEOUT_CALL(obj, Method, ...) \
     85     (obj).egmock_called_##Method = false;     \
     86     EXPECT_CALL(obj, egmock_##Method(__VA_ARGS__))
     87 
     88 /**
     89  * Waits for an earlier EXPECT_TIMEOUT_CALL to execute.
     90  *
     91  * It does not fully support special constraints of the EXPECT_CALL clause, just proceeds when the
     92  * first call to a given method comes. For example, in the following code:
     93  *     EXPECT_TIMEOUT_CALL(account, charge, 100, _);
     94  *     account.charge(50, Currency::USD);
     95  *     EXPECT_TIMEOUT_CALL_WAIT(account, charge, 500ms);
     96  * the wait clause will just continue, as the charge method was called.
     97  *
     98  * @param obj object for a call
     99  * @param Method the method to wait for
    100  * @param timeout the maximum time for waiting
    101  */
    102 #define EXPECT_TIMEOUT_CALL_WAIT(obj, Method, timeout)                      \
    103     {                                                                       \
    104         std::unique_lock<std::mutex> lk((obj).egmock_mut_##Method);         \
    105         if (!(obj).egmock_called_##Method) {                                \
    106             auto status = (obj).egmock_cond_##Method.wait_for(lk, timeout); \
    107             EXPECT_EQ(std::cv_status::no_timeout, status);                  \
    108         }                                                                   \
    109     }
    110 
    111 #endif  // ANDROID_HARDWARE_BROADCASTRADIO_V1_1_MOCK_TIMEOUT
    112