xref: /aosp_15_r20/external/pigweed/pw_rpc/public/pw_rpc/internal/method_impl_tester.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <tuple>
17 #include <type_traits>
18 
19 #include "pw_rpc/internal/packet.h"
20 #include "pw_rpc/raw/internal/method.h"
21 #include "pw_unit_test/framework.h"
22 
23 namespace pw::rpc::internal {
24 
25 template <typename...>
26 struct MatchesTypes {};
27 
28 // This class tests Method implementation classes and MethodTraits
29 // specializations. It verifies that they provide the expected functions and
30 // that they correctly identify and construct the various method types.
31 //
32 // The TestService class must inherit from Service and provide the following
33 // methods with valid signatures for RPCs:
34 //
35 //   - Unary: synchronous unary RPC member function
36 //   - StaticUnary: synchronous unary RPC static member function
37 //   - AsyncUnary: asynchronous unary RPC member function
38 //   - StaticAsyncUnary: asynchronous unary RPC static member function
39 //   - ServerStreaming: server streaming RPC member function
40 //   - StaticServerStreaming: server streaming static RPC member function
41 //   - ClientStreaming: client streaming RPC member function
42 //   - StaticClientStreaming: client streaming static RPC member function
43 //   - BidirectionalStreaming: bidirectional streaming RPC member function
44 //   - StaticBidirectionalStreaming: bidirectional streaming static RPC
45 //         member function
46 //
47 template <typename MethodImpl, typename TestService>
48 class MethodImplTests {
49  public:
50   template <typename... ExtraTypes, typename... CreationArgs>
51   constexpr bool Pass(
52       const MatchesTypes<ExtraTypes...>& = {},
53       const std::tuple<CreationArgs...>& creation_args = {}) const {
54     return Matches<ExtraTypes...>().Pass() && Type().Pass() &&
55            Creation().Pass(creation_args);
56   }
57 
58  private:
59   template <typename... ExtraTypes>
60   struct Matches {
PassMatches61     constexpr bool Pass() const { return true; }
62 
63     // Test that the matches() function matches valid signatures.
64     static_assert(
65         MethodImpl::template matches<&TestService::Unary, ExtraTypes...>());
66     static_assert(MethodImpl::template matches<&TestService::StaticUnary,
67                                                ExtraTypes...>());
68 
69     static_assert(MethodImpl::template matches<&TestService::AsyncUnary,
70                                                ExtraTypes...>());
71     static_assert(MethodImpl::template matches<&TestService::StaticAsyncUnary,
72                                                ExtraTypes...>());
73 
74     static_assert(MethodImpl::template matches<&TestService::ServerStreaming,
75                                                ExtraTypes...>());
76     static_assert(
77         MethodImpl::template matches<&TestService::StaticServerStreaming,
78                                      ExtraTypes...>());
79 
80     static_assert(MethodImpl::template matches<&TestService::ClientStreaming,
81                                                ExtraTypes...>());
82     static_assert(
83         MethodImpl::template matches<&TestService::StaticClientStreaming,
84                                      ExtraTypes...>());
85 
86     static_assert(
87         MethodImpl::template matches<&TestService::BidirectionalStreaming,
88                                      ExtraTypes...>());
89     static_assert(
90         MethodImpl::template matches<&TestService::StaticBidirectionalStreaming,
91                                      ExtraTypes...>());
92 
93     // Test that the matches() function does not match the wrong method type.
94     static_assert(!MethodImpl::template matches<&TestService::UnaryWrongArg,
95                                                 ExtraTypes...>());
96     static_assert(
97         !MethodImpl::template matches<&TestService::StaticUnaryVoidReturn,
98                                       ExtraTypes...>());
99 
100     static_assert(
101         !MethodImpl::template matches<&TestService::ServerStreamingBadReturn,
102                                       ExtraTypes...>());
103     static_assert(!MethodImpl::template matches<
104                   &TestService::StaticServerStreamingMissingArg,
105                   ExtraTypes...>());
106 
107     static_assert(
108         !MethodImpl::template matches<&TestService::ClientStreamingBadReturn,
109                                       ExtraTypes...>());
110     static_assert(!MethodImpl::template matches<
111                   &TestService::StaticClientStreamingMissingArg,
112                   ExtraTypes...>());
113 
114     static_assert(!MethodImpl::template matches<
115                   &TestService::BidirectionalStreamingBadReturn,
116                   ExtraTypes...>());
117     static_assert(!MethodImpl::template matches<
118                   &TestService::StaticBidirectionalStreamingMissingArg,
119                   ExtraTypes...>());
120   };
121 
122   // Check that MethodTraits resolves to the correct value for kType.
123   struct Type {
PassType124     constexpr bool Pass() const { return true; }
125 
126     // Don't check kSynchronous for Unary since not all method implementations
127     // support synchronous unary.
128     static_assert(MethodTraits<decltype(&TestService::Unary)>::kType ==
129                   MethodType::kUnary);
130     static_assert(MethodTraits<decltype(&TestService::StaticUnary)>::kType ==
131                   MethodType::kUnary);
132     static_assert(MethodTraits<decltype(&TestService::AsyncUnary)>::kType ==
133                   MethodType::kUnary);
134     static_assert(
135         !MethodTraits<decltype(&TestService::AsyncUnary)>::kSynchronous);
136     static_assert(
137         MethodTraits<decltype(&TestService::StaticAsyncUnary)>::kType ==
138         MethodType::kUnary);
139     static_assert(
140         !MethodTraits<decltype(&TestService::StaticAsyncUnary)>::kSynchronous);
141 
142     static_assert(
143         MethodTraits<decltype(&TestService::ServerStreaming)>::kType ==
144         MethodType::kServerStreaming);
145     static_assert(
146         MethodTraits<decltype(&TestService::StaticServerStreaming)>::kType ==
147         MethodType::kServerStreaming);
148 
149     static_assert(
150         MethodTraits<decltype(&TestService::ClientStreaming)>::kType ==
151         MethodType::kClientStreaming);
152     static_assert(
153         MethodTraits<decltype(&TestService::StaticClientStreaming)>::kType ==
154         MethodType::kClientStreaming);
155 
156     static_assert(
157         MethodTraits<decltype(&TestService::BidirectionalStreaming)>::kType ==
158         MethodType::kBidirectionalStreaming);
159     static_assert(
160         MethodTraits<
161             decltype(&TestService::StaticBidirectionalStreaming)>::kType ==
162         MethodType::kBidirectionalStreaming);
163   };
164 
165   // Test method creation.
166   class Creation {
167    public:
168     template <typename... Args>
Pass(const std::tuple<Args...> & args)169     constexpr bool Pass(const std::tuple<Args...>& args) const {
170       return AsyncUnaryMethod(args).id() == 3 &&
171              StaticAsyncUnaryMethod(args).id() == 4 &&
172              ServerStreamingMethod(args).id() == 5 &&
173              StaticServerStreamingMethod(args).id() == 6 &&
174              ClientStreamingMethod(args).id() == 7 &&
175              StaticClientStreamingMethod(args).id() == 8 &&
176              BidirectionalStreamingMethod(args).id() == 9 &&
177              StaticBidirectionalStreamingMethod(args).id() == 10 &&
178              InvalidMethod().id() == 0;
179     }
180 
181    private:
182     // Do not check synchronous unary since not all method implementations
183     // support it.
184 
185     template <typename... Args>
AsyncUnaryMethod(const std::tuple<Args...> & args)186     constexpr MethodImpl AsyncUnaryMethod(
187         const std::tuple<Args...>& args) const {
188       return Call(
189           MethodImpl::template AsynchronousUnary<&TestService::AsyncUnary>,
190           3,
191           args);
192     }
193 
194     template <typename... Args>
StaticAsyncUnaryMethod(const std::tuple<Args...> & args)195     constexpr MethodImpl StaticAsyncUnaryMethod(
196         const std::tuple<Args...>& args) const {
197       return Call(MethodImpl::template AsynchronousUnary<
198                       &TestService::StaticAsyncUnary>,
199                   4,
200                   args);
201     }
202 
203     template <typename... Args>
ServerStreamingMethod(const std::tuple<Args...> & args)204     constexpr MethodImpl ServerStreamingMethod(
205         const std::tuple<Args...>& args) const {
206       return Call(
207           MethodImpl::template ServerStreaming<&TestService::ServerStreaming>,
208           5,
209           args);
210     }
211 
212     template <typename... Args>
StaticServerStreamingMethod(const std::tuple<Args...> & args)213     constexpr MethodImpl StaticServerStreamingMethod(
214         const std::tuple<Args...>& args) const {
215       return Call(MethodImpl::template ServerStreaming<
216                       &TestService::StaticServerStreaming>,
217                   6,
218                   args);
219     }
220 
221     template <typename... Args>
ClientStreamingMethod(const std::tuple<Args...> & args)222     constexpr MethodImpl ClientStreamingMethod(
223         const std::tuple<Args...>& args) const {
224       return Call(
225           MethodImpl::template ClientStreaming<&TestService::ClientStreaming>,
226           7,
227           args);
228     }
229 
230     template <typename... Args>
StaticClientStreamingMethod(const std::tuple<Args...> & args)231     constexpr MethodImpl StaticClientStreamingMethod(
232         const std::tuple<Args...>& args) const {
233       return Call(MethodImpl::template ClientStreaming<
234                       &TestService::StaticClientStreaming>,
235                   8,
236                   args);
237     }
238 
239     template <typename... Args>
BidirectionalStreamingMethod(const std::tuple<Args...> & args)240     constexpr MethodImpl BidirectionalStreamingMethod(
241         const std::tuple<Args...>& args) const {
242       return Call(MethodImpl::template BidirectionalStreaming<
243                       &TestService::BidirectionalStreaming>,
244                   9,
245                   args);
246     }
247 
248     template <typename... Args>
StaticBidirectionalStreamingMethod(const std::tuple<Args...> & args)249     constexpr MethodImpl StaticBidirectionalStreamingMethod(
250         const std::tuple<Args...>& args) const {
251       return Call(MethodImpl::template BidirectionalStreaming<
252                       &TestService::StaticBidirectionalStreaming>,
253                   10,
254                   args);
255     }
256 
257     // Test that there is an Invalid method creation function.
InvalidMethod()258     constexpr MethodImpl InvalidMethod() const { return MethodImpl::Invalid(); }
259 
260     // Invokes the method creation function with the ID and extra args.
261     template <typename Function, typename... Args>
Call(Function && function,uint32_t id,const std::tuple<Args...> & args)262     static constexpr MethodImpl Call(Function&& function,
263                                      uint32_t id,
264                                      const std::tuple<Args...>& args) {
265       return std::apply(function, std::tuple_cat(std::tuple(id), args));
266     }
267   };
268 };
269 
270 }  // namespace pw::rpc::internal
271