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_lite/encoder.h"
21 #include "gtest/gtest.h"
22 #include "pw_bytes/array.h"
23 #include "pw_hdlc_lite_private/protocol.h"
24 #include "pw_stream/memory_stream.h"
28 namespace pw::hdlc_lite {
31 constexpr uint8_t kAddress = 0x7B; // 123
32 constexpr byte kControl = byte{0};
34 class WriteInfoFrame : public ::testing::Test {
36 WriteInfoFrame() : writer_(buffer_) {}
38 stream::MemoryWriter writer_;
39 std::array<byte, 32> buffer_;
42 #define EXPECT_ENCODER_WROTE(...) \
44 constexpr auto expected_data = (__VA_ARGS__); \
45 EXPECT_EQ(writer_.bytes_written(), expected_data.size()); \
48 writer_.data(), expected_data.data(), writer_.bytes_written()), \
52 TEST_F(WriteInfoFrame, EmptyPayload) {
53 ASSERT_EQ(Status::Ok(),
54 WriteInformationFrame(kAddress, std::span<byte>(), writer_));
56 bytes::Concat(kFlag, kAddress, kControl, uint32_t{0x8D12B2C2}, kFlag));
59 TEST_F(WriteInfoFrame, OneBytePayload) {
60 ASSERT_EQ(Status::Ok(),
61 WriteInformationFrame(kAddress, bytes::String("A"), writer_));
62 EXPECT_ENCODER_WROTE(bytes::Concat(
63 kFlag, kAddress, kControl, 'A', uint32_t{0xA63E2FA5}, kFlag));
66 TEST_F(WriteInfoFrame, OneBytePayload_Escape0x7d) {
67 ASSERT_EQ(Status::Ok(),
68 WriteInformationFrame(kAddress, bytes::Array<0x7d>(), writer_));
69 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
73 byte{0x7d} ^ byte{0x20},
78 TEST_F(WriteInfoFrame, OneBytePayload_Escape0x7E) {
79 ASSERT_EQ(Status::Ok(),
80 WriteInformationFrame(kAddress, bytes::Array<0x7e>(), writer_));
81 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
85 byte{0x7e} ^ byte{0x20},
90 TEST_F(WriteInfoFrame, AddressNeedsEscaping) {
91 ASSERT_EQ(Status::Ok(),
92 WriteInformationFrame(0x7d, bytes::String("A"), writer_));
93 EXPECT_ENCODER_WROTE(bytes::Concat(
94 kFlag, kEscape, byte{0x5d}, kControl, 'A', uint32_t{0xA2B35317}, kFlag));
97 TEST_F(WriteInfoFrame, Crc32NeedsEscaping) {
98 ASSERT_EQ(Status::Ok(),
99 WriteInformationFrame(kAddress, bytes::String("abcdefg"), writer_));
101 // The CRC-32 is 0x38B9FC7E, so the 0x7E must be escaped.
102 constexpr auto expected_crc32 = bytes::Array<0x7d, 0x5e, 0xfc, 0xb9, 0x38>();
103 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
106 bytes::String("abcdefg"),
111 TEST_F(WriteInfoFrame, MultiplePayloads) {
112 ASSERT_EQ(Status::Ok(),
113 WriteInformationFrame(kAddress, bytes::String("ABC"), writer_));
114 ASSERT_EQ(Status::Ok(),
115 WriteInformationFrame(kAddress, bytes::String("DEF"), writer_));
116 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
119 bytes::String("ABC"),
120 uint32_t{0x14E2FC99},
125 bytes::String("DEF"),
126 uint32_t{0x2D025C3A},
130 TEST_F(WriteInfoFrame, PayloadWithNoEscapes) {
131 ASSERT_EQ(Status::Ok(),
132 WriteInformationFrame(
133 kAddress, bytes::String("123456789012345678901234"), writer_));
135 // Fill the memory writer's buffer.
136 ASSERT_EQ(writer_.bytes_written(), buffer_.size());
138 EXPECT_ENCODER_WROTE(bytes::Concat(kFlag,
141 bytes::String("123456789012345678901234"),
142 uint32_t{0x50AA35EC},
146 TEST_F(WriteInfoFrame, PayloadWithMultipleEscapes) {
147 ASSERT_EQ(Status::Ok(),
148 WriteInformationFrame(
150 bytes::Array<0x7E, 0x7B, 0x61, 0x62, 0x63, 0x7D, 0x7E>(),
152 EXPECT_ENCODER_WROTE(bytes::Concat(
157 Array<0x7D, 0x5E, 0x7B, 0x61, 0x62, 0x63, 0x7D, 0x5D, 0x7D, 0x5E>(),
158 uint32_t{0x1B8D505E},
162 TEST_F(WriteInfoFrame, WriterError) {
163 constexpr auto data = bytes::Initialized<sizeof(buffer_)>(0x7e);
165 EXPECT_EQ(Status::ResourceExhausted(),
166 WriteInformationFrame(kAddress, data, writer_));
170 } // namespace pw::hdlc_lite