xref: /aosp_15_r20/external/pigweed/pw_hdlc/encoder_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2020 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_hdlc/encoder.h"
16 
17 #include <algorithm>
18 #include <array>
19 #include <cstddef>
20 #include <cstring>
21 
22 #include "pw_bytes/array.h"
23 #include "pw_hdlc/encoded_size.h"
24 #include "pw_hdlc/internal/protocol.h"
25 #include "pw_stream/memory_stream.h"
26 #include "pw_unit_test/framework.h"
27 
28 using std::byte;
29 
30 namespace pw::hdlc {
31 namespace {
32 
33 constexpr uint8_t kAddress = 0x7B;  // 123
34 constexpr uint8_t kEncodedAddress = (kAddress << 1) | 1;
35 
36 #define EXPECT_ENCODER_WROTE(...)                                           \
37   do {                                                                      \
38     constexpr auto expected_data = (__VA_ARGS__);                           \
39     EXPECT_EQ(writer_.bytes_written(), expected_data.size());               \
40     EXPECT_EQ(                                                              \
41         std::memcmp(                                                        \
42             writer_.data(), expected_data.data(), writer_.bytes_written()), \
43         0);                                                                 \
44   } while (0)
45 
46 class WriteUnnumberedFrame : public ::testing::Test {
47  protected:
WriteUnnumberedFrame()48   WriteUnnumberedFrame() : buffer_{}, writer_(buffer_) {}
49 
50   // Allocate a buffer that will fit any 7-byte payload.
51   std::array<byte, MaxEncodedFrameSize(7)> buffer_;
52   stream::MemoryWriter writer_;
53 };
54 
55 constexpr byte kUnnumberedControl = byte{0x3};
56 
TEST_F(WriteUnnumberedFrame,EmptyPayload)57 TEST_F(WriteUnnumberedFrame, EmptyPayload) {
58   ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, span<byte>(), writer_));
59   EXPECT_ENCODER_WROTE(bytes::Concat(
60       kFlag, kEncodedAddress, kUnnumberedControl, uint32_t{0x832d343f}, kFlag));
61 }
62 
TEST_F(WriteUnnumberedFrame,OneBytePayload)63 TEST_F(WriteUnnumberedFrame, OneBytePayload) {
64   ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::String("A"), writer_));
65   EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
66                                      kEncodedAddress,
67                                      kUnnumberedControl,
68                                      'A',
69                                      uint32_t{0x653c9e82},
70                                      kFlag));
71 }
72 
TEST_F(WriteUnnumberedFrame,OneBytePayload_Escape0x7d)73 TEST_F(WriteUnnumberedFrame, OneBytePayload_Escape0x7d) {
74   ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::Array<0x7d>(), writer_));
75   EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
76                                      kEncodedAddress,
77                                      kUnnumberedControl,
78                                      kEscape,
79                                      byte{0x7d} ^ byte{0x20},
80                                      uint32_t{0x4a53e205},
81                                      kFlag));
82 }
83 
TEST_F(WriteUnnumberedFrame,OneBytePayload_Escape0x7E)84 TEST_F(WriteUnnumberedFrame, OneBytePayload_Escape0x7E) {
85   ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::Array<0x7e>(), writer_));
86   EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
87                                      kEncodedAddress,
88                                      kUnnumberedControl,
89                                      kEscape,
90                                      byte{0x7e} ^ byte{0x20},
91                                      uint32_t{0xd35ab3bf},
92                                      kFlag));
93 }
94 
TEST_F(WriteUnnumberedFrame,AddressNeedsEscaping)95 TEST_F(WriteUnnumberedFrame, AddressNeedsEscaping) {
96   // Becomes 0x7d when encoded.
97   constexpr uint8_t kEscapeRequiredAddress = 0x7d >> 1;
98   ASSERT_EQ(OkStatus(),
99             WriteUIFrame(kEscapeRequiredAddress, bytes::String("A"), writer_));
100   EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
101                                      kEscape,
102                                      byte{0x5d},
103                                      kUnnumberedControl,
104                                      'A',
105                                      uint32_t{0x899E00D4},
106                                      kFlag));
107 }
108 
TEST_F(WriteUnnumberedFrame,Crc32NeedsEscaping)109 TEST_F(WriteUnnumberedFrame, Crc32NeedsEscaping) {
110   ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::String("aa"), writer_));
111 
112   // The CRC-32 of {kEncodedAddress, kUnnumberedControl, "aa"} is 0x7ee04473, so
113   // the 0x7e must be escaped.
114   constexpr auto expected_crc32 = bytes::Array<0x73, 0x44, 0xe0, 0x7d, 0x5e>();
115   EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
116                                      kEncodedAddress,
117                                      kUnnumberedControl,
118                                      bytes::String("aa"),
119                                      expected_crc32,
120                                      kFlag));
121 }
122 
TEST_F(WriteUnnumberedFrame,MultiplePayloads)123 TEST_F(WriteUnnumberedFrame, MultiplePayloads) {
124   ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::String("ABC"), writer_));
125   ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::String("DEF"), writer_));
126   EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
127                                      kEncodedAddress,
128                                      kUnnumberedControl,
129                                      bytes::String("ABC"),
130                                      uint32_t{0x72410ee4},
131                                      kFlag,
132                                      kFlag,
133                                      kEncodedAddress,
134                                      kUnnumberedControl,
135                                      bytes::String("DEF"),
136                                      uint32_t{0x4ba1ae47},
137                                      kFlag));
138 }
139 
TEST_F(WriteUnnumberedFrame,PayloadWithNoEscapes)140 TEST_F(WriteUnnumberedFrame, PayloadWithNoEscapes) {
141   ASSERT_EQ(
142       OkStatus(),
143       WriteUIFrame(kAddress, bytes::String("1995 toyota corolla"), writer_));
144 
145   EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
146                                      kEncodedAddress,
147                                      kUnnumberedControl,
148                                      bytes::String("1995 toyota corolla"),
149                                      uint32_t{0x53ee911c},
150                                      kFlag));
151 }
152 
TEST_F(WriteUnnumberedFrame,MultibyteAddress)153 TEST_F(WriteUnnumberedFrame, MultibyteAddress) {
154   ASSERT_EQ(OkStatus(), WriteUIFrame(0x3fff, bytes::String("abc"), writer_));
155 
156   EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
157                                      bytes::String("\xfe\xff"),
158                                      kUnnumberedControl,
159                                      bytes::String("abc"),
160                                      uint32_t{0x8cee2978},
161                                      kFlag));
162 }
163 
TEST_F(WriteUnnumberedFrame,PayloadWithMultipleEscapes)164 TEST_F(WriteUnnumberedFrame, PayloadWithMultipleEscapes) {
165   ASSERT_EQ(
166       OkStatus(),
167       WriteUIFrame(kAddress,
168                    bytes::Array<0x7E, 0x7B, 0x61, 0x62, 0x63, 0x7D, 0x7E>(),
169                    writer_));
170   EXPECT_ENCODER_WROTE(bytes::Concat(
171       kFlag,
172       kEncodedAddress,
173       kUnnumberedControl,
174       bytes::
175           Array<0x7D, 0x5E, 0x7B, 0x61, 0x62, 0x63, 0x7D, 0x5D, 0x7D, 0x5E>(),
176       uint32_t{0x1563a4e6},
177       kFlag));
178 }
179 
TEST_F(WriteUnnumberedFrame,PayloadTooLarge_WritesNothing)180 TEST_F(WriteUnnumberedFrame, PayloadTooLarge_WritesNothing) {
181   constexpr auto data = bytes::Initialized<sizeof(buffer_)>(0x7e);
182   EXPECT_EQ(Status::ResourceExhausted(), WriteUIFrame(kAddress, data, writer_));
183   EXPECT_EQ(0u, writer_.bytes_written());
184 }
185 
186 class ErrorWriter : public stream::NonSeekableWriter {
187  private:
DoWrite(ConstByteSpan)188   Status DoWrite(ConstByteSpan) override { return Status::Unimplemented(); }
189 };
190 
TEST(WriteUIFrame,WriterError)191 TEST(WriteUIFrame, WriterError) {
192   ErrorWriter writer;
193   EXPECT_EQ(Status::Unimplemented(),
194             WriteUIFrame(kAddress, bytes::Array<0x01>(), writer));
195 }
196 
197 }  // namespace
198 }  // namespace pw::hdlc
199