1 // Copyright 2020 The Pigweed Authors
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
7 // https://www.apache.org/licenses/LICENSE-2.0
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
15 #include "pw_hdlc/encoder.h"
21 #include "gtest/gtest.h"
22 #include "pw_bytes/array.h"
23 #include "pw_hdlc/internal/encoder.h"
24 #include "pw_hdlc_private/protocol.h"
25 #include "pw_stream/memory_stream.h"
32 constexpr uint8_t kAddress = 0x7B; // 123
34 #define EXPECT_ENCODER_WROTE(...) \
36 constexpr auto expected_data = (__VA_ARGS__); \
37 EXPECT_EQ(writer_.bytes_written(), expected_data.size()); \
40 writer_.data(), expected_data.data(), writer_.bytes_written()), \
44 class WriteUnnumberedFrame : public ::testing::Test {
46 WriteUnnumberedFrame() : writer_(buffer_) {}
48 stream::MemoryWriter writer_;
49 std::array<byte, 32> buffer_;
52 constexpr byte kUnnumberedControl = byte{0x3};
54 TEST_F(WriteUnnumberedFrame, EmptyPayload) {
55 ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, std::span<byte>(), writer_));
56 EXPECT_ENCODER_WROTE(bytes::Concat(
57 kFlag, kAddress, kUnnumberedControl, uint32_t{0x141BE378}, kFlag));
60 TEST_F(WriteUnnumberedFrame, OneBytePayload) {
61 ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::String("A"), writer_));
62 EXPECT_ENCODER_WROTE(bytes::Concat(
63 kFlag, kAddress, kUnnumberedControl, 'A', uint32_t{0x8D137C66}, kFlag));
66 TEST_F(WriteUnnumberedFrame, OneBytePayload_Escape0x7d) {
67 ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::Array<0x7d>(), writer_));
68 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
72 byte{0x7d} ^ byte{0x20},
77 TEST_F(WriteUnnumberedFrame, OneBytePayload_Escape0x7E) {
78 ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::Array<0x7e>(), writer_));
79 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
83 byte{0x7e} ^ byte{0x20},
88 TEST_F(WriteUnnumberedFrame, AddressNeedsEscaping) {
89 ASSERT_EQ(OkStatus(), WriteUIFrame(0x7d, bytes::String("A"), writer_));
90 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
99 TEST_F(WriteUnnumberedFrame, Crc32NeedsEscaping) {
100 ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::String("a"), writer_));
102 // The CRC-32 is 0xB67D5CAE, so the 0x7D must be escaped.
103 constexpr auto expected_crc32 = bytes::Array<0xae, 0x5c, 0x7d, 0x5d, 0xb6>();
104 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
112 TEST_F(WriteUnnumberedFrame, MultiplePayloads) {
113 ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::String("ABC"), writer_));
114 ASSERT_EQ(OkStatus(), WriteUIFrame(kAddress, bytes::String("DEF"), writer_));
115 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
118 bytes::String("ABC"),
119 uint32_t{0x06575377},
124 bytes::String("DEF"),
125 uint32_t{0x3FB7F3D4},
129 TEST_F(WriteUnnumberedFrame, PayloadWithNoEscapes) {
132 WriteUIFrame(kAddress, bytes::String("1995 toyota corolla"), writer_));
134 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
137 bytes::String("1995 toyota corolla"),
138 uint32_t{0x56560172},
142 TEST_F(WriteUnnumberedFrame, PayloadWithMultipleEscapes) {
145 WriteUIFrame(kAddress,
146 bytes::Array<0x7E, 0x7B, 0x61, 0x62, 0x63, 0x7D, 0x7E>(),
148 EXPECT_ENCODER_WROTE(bytes::Concat(
153 Array<0x7D, 0x5E, 0x7B, 0x61, 0x62, 0x63, 0x7D, 0x5D, 0x7D, 0x5E>(),
154 uint32_t{0x950257BD},
158 TEST_F(WriteUnnumberedFrame, PayloadTooLarge_WritesNothing) {
159 constexpr auto data = bytes::Initialized<sizeof(buffer_)>(0x7e);
160 EXPECT_EQ(Status::ResourceExhausted(), WriteUIFrame(kAddress, data, writer_));
161 EXPECT_EQ(0u, writer_.bytes_written());
164 class ErrorWriter : public stream::Writer {
166 Status DoWrite(ConstByteSpan) override { return Status::Unimplemented(); }
169 TEST(WriteUnnumberedFrame, WriterError) {
171 EXPECT_EQ(Status::Unimplemented(),
172 WriteUIFrame(kAddress, bytes::Array<0x01>(), writer));
180 constexpr uint8_t kEscapeAddress = 0x7d;
182 TEST(Encoder, MaxEncodedSize_EmptyPayload) {
183 EXPECT_EQ(9u, Encoder::MaxEncodedSize(kAddress, {}));
184 EXPECT_EQ(10u, Encoder::MaxEncodedSize(kEscapeAddress, {}));
187 TEST(Encoder, MaxEncodedSize_PayloadWithoutEscapes) {
188 constexpr auto data = bytes::Array<0x00, 0x01, 0x02, 0x03>();
189 EXPECT_EQ(13u, Encoder::MaxEncodedSize(kAddress, data));
190 EXPECT_EQ(14u, Encoder::MaxEncodedSize(kEscapeAddress, data));
193 TEST(Encoder, MaxEncodedSize_PayloadWithOneEscape) {
194 constexpr auto data = bytes::Array<0x00, 0x01, 0x7e, 0x03>();
195 EXPECT_EQ(14u, Encoder::MaxEncodedSize(kAddress, data));
196 EXPECT_EQ(15u, Encoder::MaxEncodedSize(kEscapeAddress, data));
199 TEST(Encoder, MaxEncodedSize_PayloadWithAllEscapes) {
200 constexpr auto data = bytes::Initialized<8>(0x7e);
201 EXPECT_EQ(25u, Encoder::MaxEncodedSize(kAddress, data));
202 EXPECT_EQ(26u, Encoder::MaxEncodedSize(kEscapeAddress, data));
206 } // namespace internal
207 } // namespace pw::hdlc