xref: /aosp_15_r20/external/pigweed/pw_rpc_transport/hdlc_framing_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 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 
15 #include "pw_rpc_transport/hdlc_framing.h"
16 
17 #include <algorithm>
18 #include <array>
19 
20 #include "pw_bytes/span.h"
21 #include "pw_status/status.h"
22 #include "pw_unit_test/framework.h"
23 
24 namespace pw::rpc {
25 namespace {
26 
TEST(HdlcRpc,EncodeThenDecode)27 TEST(HdlcRpc, EncodeThenDecode) {
28   constexpr size_t kMaxPacketSize = 256;
29   constexpr size_t kPacketSize = 100;
30   constexpr size_t kMaxFrameSize = 20;
31   // Expecting six frames due to HDLC overhead.
32   constexpr size_t kNumFramesExpected = 6;
33 
34   HdlcRpcPacketEncoder<kMaxPacketSize> encoder;
35   std::array<std::byte, kPacketSize> packet{};
36 
37   struct EncodeState {
38     size_t num_frames = 0;
39     size_t offset = 0;
40     std::array<std::byte, 2 * kMaxPacketSize> encoded{};
41   } state;
42 
43   std::fill(packet.begin(), packet.end(), std::byte{0x42});
44   ASSERT_EQ(encoder.Encode(packet,
45                            kMaxFrameSize,
46                            [&state](RpcFrame& frame) {
47                              state.num_frames++;
48                              EXPECT_TRUE(frame.header.empty());
49                              std::copy(frame.payload.begin(),
50                                        frame.payload.end(),
51                                        state.encoded.begin() + state.offset);
52                              state.offset += frame.payload.size();
53                              return OkStatus();
54                            }),
55             OkStatus());
56 
57   EXPECT_EQ(state.num_frames, kNumFramesExpected);
58 
59   std::array<std::byte, kMaxPacketSize> decoded{};
60   HdlcRpcPacketDecoder<kMaxPacketSize> decoder;
61 
62   ASSERT_EQ(decoder.Decode(state.encoded,
63                            [&decoded](ConstByteSpan packet_to_decode) {
64                              std::copy(packet_to_decode.begin(),
65                                        packet_to_decode.end(),
66                                        decoded.begin());
67                            }),
68             OkStatus());
69 
70   EXPECT_TRUE(std::equal(packet.begin(), packet.end(), decoded.begin()));
71 }
72 
TEST(HdlcRpc,PacketTooLong)73 TEST(HdlcRpc, PacketTooLong) {
74   constexpr size_t kMaxPacketSize = 256;
75   constexpr size_t kMaxFrameSize = 100;
76 
77   std::array<std::byte, kMaxPacketSize + 1> packet{};
78   HdlcRpcPacketEncoder<kMaxPacketSize> encoder;
79 
80   EXPECT_EQ(encoder.Encode(
81                 packet, kMaxFrameSize, [](RpcFrame&) { return OkStatus(); }),
82             Status::FailedPrecondition());
83 }
84 
TEST(HdlcRpcFrame,MaxFrameSizeIsZero)85 TEST(HdlcRpcFrame, MaxFrameSizeIsZero) {
86   constexpr size_t kMaxPacketSize = 256;
87   constexpr size_t kMaxFrameSize = 0;
88 
89   std::array<std::byte, kMaxPacketSize> packet{};
90   HdlcRpcPacketEncoder<kMaxPacketSize> encoder;
91 
92   EXPECT_EQ(encoder.Encode(
93                 packet, kMaxFrameSize, [](RpcFrame&) { return OkStatus(); }),
94             Status::FailedPrecondition());
95 }
96 
TEST(HdlcRpcFrame,MaxSizeHdlcPayload)97 TEST(HdlcRpcFrame, MaxSizeHdlcPayload) {
98   constexpr size_t kMaxPacketSize = 256;
99   constexpr size_t kPacketSize = 256;
100   constexpr size_t kMaxFrameSize = 20;
101   constexpr auto kHdlcEscapeByte = std::byte{0x7e};
102 
103   std::array<std::byte, kPacketSize> packet{};
104   std::fill(packet.begin(), packet.end(), kHdlcEscapeByte);
105 
106   struct EncodeState {
107     size_t offset = 0;
108     std::array<std::byte, 2 * kMaxPacketSize + kHdlcProtocolOverheadBytes>
109         encoded{};
110   } state;
111 
112   HdlcRpcPacketEncoder<kMaxPacketSize> encoder;
113   ASSERT_EQ(encoder.Encode(packet,
114                            kMaxFrameSize,
115                            [&state](RpcFrame& frame) {
116                              EXPECT_TRUE(frame.header.empty());
117                              std::copy(frame.payload.begin(),
118                                        frame.payload.end(),
119                                        state.encoded.begin() + state.offset);
120                              state.offset += frame.payload.size();
121                              return OkStatus();
122                            }),
123             OkStatus());
124 
125   std::array<std::byte, kMaxPacketSize> decoded{};
126   HdlcRpcPacketDecoder<kMaxPacketSize> decoder;
127 
128   ASSERT_EQ(decoder.Decode(state.encoded,
129                            [&decoded](ConstByteSpan packet_to_decode) {
130                              std::copy(packet_to_decode.begin(),
131                                        packet_to_decode.end(),
132                                        decoded.begin());
133                            }),
134             OkStatus());
135 
136   EXPECT_TRUE(std::equal(packet.begin(), packet.end(), decoded.begin()));
137 }
138 
TEST(HdlcRpc,CallbackErrorPropagation)139 TEST(HdlcRpc, CallbackErrorPropagation) {
140   constexpr size_t kMaxPacketSize = 256;
141   constexpr size_t kPacketSize = 256;
142   constexpr size_t kMaxFrameSize = 20;
143 
144   std::array<std::byte, kPacketSize> packet{};
145   std::fill(packet.begin(), packet.end(), std::byte{0x42});
146 
147   HdlcRpcPacketEncoder<kMaxPacketSize> encoder;
148   EXPECT_EQ(
149       encoder.Encode(packet,
150                      kMaxFrameSize,
151                      [](RpcFrame&) { return Status::PermissionDenied(); }),
152       Status::PermissionDenied());
153 }
154 
TEST(HdlcRpcFrame,OneByteAtTimeDecoding)155 TEST(HdlcRpcFrame, OneByteAtTimeDecoding) {
156   constexpr size_t kMaxPacketSize = 256;
157   constexpr size_t kPacketSize = 100;
158   constexpr size_t kMaxFrameSize = 8;
159 
160   HdlcRpcPacketEncoder<kMaxPacketSize> encoder;
161   std::array<std::byte, kPacketSize> packet{};
162   std::vector<std::byte> encoded;
163 
164   std::fill(packet.begin(), packet.end(), std::byte{0x42});
165   ASSERT_EQ(encoder.Encode(packet,
166                            kMaxFrameSize,
167                            [&encoded](RpcFrame& frame) {
168                              std::copy(frame.payload.begin(),
169                                        frame.payload.end(),
170                                        std::back_inserter(encoded));
171                              return OkStatus();
172                            }),
173             OkStatus());
174 
175   std::array<std::byte, kMaxPacketSize> decoded{};
176   HdlcRpcPacketDecoder<kMaxPacketSize> decoder;
177 
178   for (std::byte b : encoded) {
179     auto buffer_span = span(&b, 1);
180     ASSERT_EQ(decoder.Decode(buffer_span,
181                              [&decoded](ConstByteSpan packet_to_decode) {
182                                std::copy(packet_to_decode.begin(),
183                                          packet_to_decode.end(),
184                                          decoded.begin());
185                              }),
186               OkStatus());
187   }
188 
189   EXPECT_TRUE(std::equal(packet.begin(), packet.end(), decoded.begin()));
190 }
191 
192 }  // namespace
193 }  // namespace pw::rpc
194