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 
17 #pragma once
18 
19 #include <gtest/gtest.h>
20 #include <functional>
21 #include <tuple>
22 #include <type_traits>
23 #include <utility>
24 
25 namespace {
26 namespace detail {
27 template <typename>
28 struct functionArgSaver;
29 
30 // Provides a std::function that takes one argument, and a buffer
31 // wherein the function will store its argument. The buffer has
32 // the same type as the argument, but with const and reference
33 // modifiers removed.
34 template <typename ArgT>
35 struct functionArgSaver<std::function<void(ArgT)>> final {
36     using StorageT = typename std::remove_const<
37         typename std::remove_reference<ArgT>::type>::type;
38 
39     std::function<void(ArgT)> saveArgs = [this](ArgT arg) {
40         this->saved_values = arg;
41     };
42 
43     StorageT saved_values;
44 };
45 
46 // Provides a std::function that takes two arguments, and a buffer
47 // wherein the function will store its arguments. The buffer is a
48 // std::pair, whose elements have the same types as the arguments
49 // (but with const and reference modifiers removed).
50 template <typename Arg1T, typename Arg2T>
51 struct functionArgSaver<std::function<void(Arg1T, Arg2T)>> final {
52     using StorageT =
53         std::pair<typename std::remove_const<
54                       typename std::remove_reference<Arg1T>::type>::type,
55                   typename std::remove_const<
56                       typename std::remove_reference<Arg2T>::type>::type>;
57 
58     std::function<void(Arg1T, Arg2T)> saveArgs = [this](Arg1T arg1,
59                                                         Arg2T arg2) {
60         this->saved_values = {arg1, arg2};
61     };
62 
63     StorageT saved_values;
64 };
65 
66 // Provides a std::function that takes three or more arguments, and a
67 // buffer wherein the function will store its arguments. The buffer is a
68 // std::tuple whose elements have the same types as the arguments (but
69 // with const and reference modifiers removed).
70 template <typename... ArgT>
71 struct functionArgSaver<std::function<void(ArgT...)>> final {
72     using StorageT = std::tuple<typename std::remove_const<
73         typename std::remove_reference<ArgT>::type>::type...>;
74 
75     std::function<void(ArgT...)> saveArgs = [this](ArgT... arg) {
76         this->saved_values = {arg...};
77     };
78 
79     StorageT saved_values;
80 };
81 
82 // Invokes |method| on |object|, providing |method| a CallbackT as the
83 // final argument. Returns a copy of the parameters that |method| provided
84 // to CallbackT. (The parameters are returned by value.)
85 template <typename CallbackT, typename MethodT, typename ObjectT,
86           typename... ArgT>
87 typename functionArgSaver<CallbackT>::StorageT invokeMethod(
88     MethodT method, ObjectT object, ArgT&&... methodArg) {
89     functionArgSaver<CallbackT> result_buffer;
90     const auto& res = ((*object).*method)(std::forward<ArgT>(methodArg)...,
91                                           result_buffer.saveArgs);
92     EXPECT_TRUE(res.isOk());
93     return result_buffer.saved_values;
94 }
95 }  // namespace detail
96 }  // namespace
97 
98 // Invokes |method| on |strong_pointer|, passing provided arguments through to
99 // |method|.
100 //
101 // Returns either:
102 // - A copy of the result callback parameter (for callbacks with a single
103 //   parameter), OR
104 // - A pair containing a copy of the result callback parameters (for callbacks
105 //   with two parameters), OR
106 // - A tuple containing a copy of the result callback paramters (for callbacks
107 //   with three or more parameters).
108 //
109 // Example usage:
110 //   EXPECT_EQ(WifiStatusCode::SUCCESS,
111 //       HIDL_INVOKE(strong_pointer, methodReturningWifiStatus).code);
112 //   EXPECT_EQ(WifiStatusCode::SUCCESS,
113 //       HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndOneMore)
114 //         .first.code);
115 //   EXPECT_EQ(WifiStatusCode::SUCCESS, std::get<0>(
116 //       HIDL_INVOKE(strong_pointer, methodReturningWifiStatusAndTwoMore))
117 //         .code);
118 #define HIDL_INVOKE(strong_pointer, method, ...)                              \
119     (detail::invokeMethod<                                                    \
120         std::remove_reference<decltype(*strong_pointer)>::type::method##_cb>( \
121         &std::remove_reference<decltype(*strong_pointer)>::type::method,      \
122         strong_pointer, ##__VA_ARGS__))
123