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