2 # Copyright 2020 The Pigweed Authors
4 # Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 # use this file except in compliance with the License. You may obtain a copy of
8 # https://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 # License for the specific language governing permissions and limitations under
15 """Tests the generated pw_rpc code."""
17 from pathlib import Path
23 TEST_PROTO_FILE = b"""\
32 message TestResponse {
36 message TestStreamResponse {
43 rpc TestRpc(TestRequest) returns (TestResponse) {}
44 rpc TestStreamRpc(Empty) returns (stream TestStreamResponse) {}
48 EXPECTED_NANOPB_CODE = """\
54 #include <type_traits>
56 #include "pw_rpc/internal/method.h"
57 #include "pw_rpc/server_context.h"
58 #include "pw_rpc/service.h"
61 namespace pw::rpc::internal {
64 class ServiceMethodTraits;
66 } // namespace pw::rpc::internal
68 namespace pw::rpc::test {
71 template <typename Implementation>
72 class TestService : public ::pw::rpc::Service {
74 using ServerContext = ::pw::rpc::ServerContext;
76 using ServerWriter = ::pw::rpc::ServerWriter<T>;
78 constexpr TestService()
79 : ::pw::rpc::Service(kServiceId, kMethods) {}
81 TestService(const TestService&) = delete;
82 TestService& operator=(const TestService&) = delete;
84 static constexpr const char* name() { return "TestService"; }
86 // Used by ServiceMethodTraits to identify a base service.
87 constexpr void _PwRpcInternalGeneratedBase() const {}
90 // Hash of "pw.rpc.test.TestService".
91 static constexpr uint32_t kServiceId = 0xcc0f6de0;
93 static ::pw::Status Invoke_TestRpc(
94 ::pw::rpc::internal::ServerCall& call,
95 const pw_rpc_test_TestRequest& request,
96 pw_rpc_test_TestResponse& response) {
97 return static_cast<Implementation&>(call.service())
98 .TestRpc(call.context(), request, response);
101 static void Invoke_TestStreamRpc(
102 ::pw::rpc::internal::ServerCall& call,
103 const pw_rpc_test_TestRequest& request,
104 ServerWriter<pw_rpc_test_TestStreamResponse>& writer) {
105 static_cast<Implementation&>(call.service())
106 .TestStreamRpc(call.context(), request, writer);
109 static constexpr std::array<::pw::rpc::internal::Method, 2> kMethods = {
110 ::pw::rpc::internal::Method::Unary<Invoke_TestRpc>(
111 0xbc924054, // Hash of "TestRpc"
112 pw_rpc_test_TestRequest_fields,
113 pw_rpc_test_TestResponse_fields),
114 ::pw::rpc::internal::Method::ServerStreaming<Invoke_TestStreamRpc>(
115 0xd97a28fa, // Hash of "TestStreamRpc"
116 pw_rpc_test_TestRequest_fields,
117 pw_rpc_test_TestStreamResponse_fields),
120 template <auto impl_method>
121 static constexpr const ::pw::rpc::internal::Method* MethodFor() {
122 if constexpr (std::is_same_v<decltype(impl_method), decltype(&Implementation::TestRpc)>) {
123 if constexpr (impl_method == &Implementation::TestRpc) {
124 return &std::get<0>(kMethods);
127 if constexpr (std::is_same_v<decltype(impl_method), decltype(&Implementation::TestStreamRpc)>) {
128 if constexpr (impl_method == &Implementation::TestStreamRpc) {
129 return &std::get<1>(kMethods);
136 friend class ::pw::rpc::internal::ServiceMethodTraits;
139 } // namespace generated
140 } // namespace pw::rpc::test
144 class TestNanopbCodegen(unittest.TestCase):
145 """Test case for nanopb code generation."""
147 self._output_dir = tempfile.TemporaryDirectory()
150 self._output_dir.cleanup()
152 def test_nanopb_codegen(self):
153 root = Path(os.getenv('PW_ROOT'))
154 proto_dir = root / 'pw_rpc' / 'pw_rpc_test_protos'
155 proto_file = proto_dir / 'test.proto'
157 venv_bin = 'Scripts' if os.name == 'nt' else 'bin'
158 plugin = root / '.python3-env' / venv_bin / 'pw_rpc_codegen'
165 f'protoc-gen-custom={plugin}',
167 self._output_dir.name,
170 subprocess.run(command)
172 generated_files = os.listdir(self._output_dir.name)
173 self.assertEqual(len(generated_files), 1)
174 self.assertEqual(generated_files[0], 'test.rpc.pb.h')
176 # Read the generated file, ignoring its preamble.
177 generated_code = Path(self._output_dir.name,
178 generated_files[0]).read_text()
179 generated_code = generated_code[generated_code.index('#pragma'):]
181 self.assertEqual(generated_code, EXPECTED_NANOPB_CODE)