blob: d72b6e5dac61f450004b208673c55037faa2102f [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2020 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Tests the generated pw_rpc code."""
from pathlib import Path
import os
import subprocess
import tempfile
import unittest
TEST_PROTO_FILE = b"""\
syntax = "proto3";
package pw.rpc.test;
message TestRequest {
float integer = 1;
}
message TestResponse {
int32 value = 1;
}
message TestStreamResponse {
bytes chunk = 1;
}
message Empty {}
service TestService {
rpc TestRpc(TestRequest) returns (TestResponse) {}
rpc TestStreamRpc(Empty) returns (stream TestStreamResponse) {}
}
"""
EXPECTED_NANOPB_CODE = """\
#pragma once
#include <cstddef>
#include <cstdint>
#include "pw_rpc/internal/service.h"
#include "test.pb.h"
namespace pw::rpc::test {
class TestService : public ::pw::rpc::internal::Service {
public:
using ServerContext = ::pw::rpc::ServerContext;
template <typename T> using ServerWriter = ::pw::rpc::ServerWriter<T>;
constexpr TestService() : ::pw::rpc::internal::Service(kServiceId, kMethods) {}
TestService(const TestService&) = delete;
TestService& operator=(const TestService&) = delete;
static ::pw::Status TestRpc(
ServerContext& ctx,
const pw_rpc_test_TestRequest& request,
pw_rpc_test_TestResponse& response);
static ::pw::Status TestStreamRpc(
ServerContext& ctx,
const pw_rpc_test_Empty& request,
ServerWriter<pw_rpc_test_TestStreamResponse>& writer);
private:
// 65599 hash of "TestService".
static constexpr uint32_t kServiceId = 0x105b6ac8;
static constexpr char* kServiceName = "TestService";
static constexpr std::array<::pw::rpc::internal::Method, 2> kMethods = {
::pw::rpc::internal::Method::Unary<TestRpc>(
0xbc924054, // 65599 hash of "TestRpc"
pw_rpc_test_TestRequest_fields,
pw_rpc_test_TestResponse_fields),
::pw::rpc::internal::Method::ServerStreaming<TestStreamRpc>(
0xd97a28fa, // 65599 hash of "TestStreamRpc"
pw_rpc_test_Empty_fields,
pw_rpc_test_TestStreamResponse_fields),
};
};
} // namespace pw::rpc::test
"""
class TestNanopbCodegen(unittest.TestCase):
"""Test case for nanopb code generation."""
def setUp(self):
self._output_dir = tempfile.TemporaryDirectory()
def tearDown(self):
self._output_dir.cleanup()
def test_nanopb_codegen(self):
root = Path(os.getenv('PW_ROOT'))
proto_dir = root / 'pw_rpc' / 'pw_rpc_test_protos'
proto_file = proto_dir / 'test.proto'
venv_bin = 'Scripts' if os.name == 'nt' else 'bin'
plugin = root / '.python3-env' / venv_bin / 'pw_rpc_codegen'
command = (
'protoc',
f'-I{proto_dir}',
proto_file,
'--plugin',
f'protoc-gen-custom={plugin}',
'--custom_out',
self._output_dir.name,
)
subprocess.run(command)
generated_files = os.listdir(self._output_dir.name)
self.assertEqual(len(generated_files), 1)
self.assertEqual(generated_files[0], 'test_rpc.pb.h')
# Read the generated file, ignoring its preamble.
generated_code = Path(self._output_dir.name,
generated_files[0]).read_text()
generated_code = generated_code[generated_code.index('#pragma'):]
self.assertEqual(generated_code, EXPECTED_NANOPB_CODE)