// Copyright 2023 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. #include "pw_rpc_transport/hdlc_framing.h" #include #include #include "pw_bytes/span.h" #include "pw_status/status.h" #include "pw_unit_test/framework.h" namespace pw::rpc { namespace { TEST(HdlcRpc, EncodeThenDecode) { constexpr size_t kMaxPacketSize = 256; constexpr size_t kPacketSize = 100; constexpr size_t kMaxFrameSize = 20; // Expecting six frames due to HDLC overhead. constexpr size_t kNumFramesExpected = 6; HdlcRpcPacketEncoder encoder; std::array packet{}; struct EncodeState { size_t num_frames = 0; size_t offset = 0; std::array encoded{}; } state; std::fill(packet.begin(), packet.end(), std::byte{0x42}); ASSERT_EQ(encoder.Encode(packet, kMaxFrameSize, [&state](RpcFrame& frame) { state.num_frames++; EXPECT_TRUE(frame.header.empty()); std::copy(frame.payload.begin(), frame.payload.end(), state.encoded.begin() + state.offset); state.offset += frame.payload.size(); return OkStatus(); }), OkStatus()); EXPECT_EQ(state.num_frames, kNumFramesExpected); std::array decoded{}; HdlcRpcPacketDecoder decoder; ASSERT_EQ(decoder.Decode(state.encoded, [&decoded](ConstByteSpan packet_to_decode) { std::copy(packet_to_decode.begin(), packet_to_decode.end(), decoded.begin()); }), OkStatus()); EXPECT_TRUE(std::equal(packet.begin(), packet.end(), decoded.begin())); } TEST(HdlcRpc, PacketTooLong) { constexpr size_t kMaxPacketSize = 256; constexpr size_t kMaxFrameSize = 100; std::array packet{}; HdlcRpcPacketEncoder encoder; EXPECT_EQ(encoder.Encode( packet, kMaxFrameSize, [](RpcFrame&) { return OkStatus(); }), Status::FailedPrecondition()); } TEST(HdlcRpcFrame, MaxFrameSizeIsZero) { constexpr size_t kMaxPacketSize = 256; constexpr size_t kMaxFrameSize = 0; std::array packet{}; HdlcRpcPacketEncoder encoder; EXPECT_EQ(encoder.Encode( packet, kMaxFrameSize, [](RpcFrame&) { return OkStatus(); }), Status::FailedPrecondition()); } TEST(HdlcRpcFrame, MaxSizeHdlcPayload) { constexpr size_t kMaxPacketSize = 256; constexpr size_t kPacketSize = 256; constexpr size_t kMaxFrameSize = 20; constexpr auto kHdlcEscapeByte = std::byte{0x7e}; std::array packet{}; std::fill(packet.begin(), packet.end(), kHdlcEscapeByte); struct EncodeState { size_t offset = 0; std::array encoded{}; } state; HdlcRpcPacketEncoder encoder; ASSERT_EQ(encoder.Encode(packet, kMaxFrameSize, [&state](RpcFrame& frame) { EXPECT_TRUE(frame.header.empty()); std::copy(frame.payload.begin(), frame.payload.end(), state.encoded.begin() + state.offset); state.offset += frame.payload.size(); return OkStatus(); }), OkStatus()); std::array decoded{}; HdlcRpcPacketDecoder decoder; ASSERT_EQ(decoder.Decode(state.encoded, [&decoded](ConstByteSpan packet_to_decode) { std::copy(packet_to_decode.begin(), packet_to_decode.end(), decoded.begin()); }), OkStatus()); EXPECT_TRUE(std::equal(packet.begin(), packet.end(), decoded.begin())); } TEST(HdlcRpc, CallbackErrorPropagation) { constexpr size_t kMaxPacketSize = 256; constexpr size_t kPacketSize = 256; constexpr size_t kMaxFrameSize = 20; std::array packet{}; std::fill(packet.begin(), packet.end(), std::byte{0x42}); HdlcRpcPacketEncoder encoder; EXPECT_EQ( encoder.Encode(packet, kMaxFrameSize, [](RpcFrame&) { return Status::PermissionDenied(); }), Status::PermissionDenied()); } TEST(HdlcRpcFrame, OneByteAtTimeDecoding) { constexpr size_t kMaxPacketSize = 256; constexpr size_t kPacketSize = 100; constexpr size_t kMaxFrameSize = 8; HdlcRpcPacketEncoder encoder; std::array packet{}; std::vector encoded; std::fill(packet.begin(), packet.end(), std::byte{0x42}); ASSERT_EQ(encoder.Encode(packet, kMaxFrameSize, [&encoded](RpcFrame& frame) { std::copy(frame.payload.begin(), frame.payload.end(), std::back_inserter(encoded)); return OkStatus(); }), OkStatus()); std::array decoded{}; HdlcRpcPacketDecoder decoder; for (std::byte b : encoded) { auto buffer_span = span(&b, 1); ASSERT_EQ(decoder.Decode(buffer_span, [&decoded](ConstByteSpan packet_to_decode) { std::copy(packet_to_decode.begin(), packet_to_decode.end(), decoded.begin()); }), OkStatus()); } EXPECT_TRUE(std::equal(packet.begin(), packet.end(), decoded.begin())); } } // namespace } // namespace pw::rpc