532 lines
24 KiB
C++
532 lines
24 KiB
C++
// Copyright 2021 The Pigweed Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
|
// use this file except in compliance with the License. You may obtain a copy of
|
|
// the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
#include "pw_bluetooth_hci/packet.h"
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "pw_bytes/array.h"
|
|
#include "pw_bytes/byte_builder.h"
|
|
#include "pw_status/status.h"
|
|
|
|
namespace pw::bluetooth_hci {
|
|
namespace {
|
|
|
|
class PacketTest : public ::testing::Test {
|
|
protected:
|
|
constexpr static size_t kMaxHeaderSizeBytes = std::max({
|
|
CommandPacket::kHeaderSizeBytes,
|
|
AsyncDataPacket::kHeaderSizeBytes,
|
|
SyncDataPacket::kHeaderSizeBytes,
|
|
EventPacket::kHeaderSizeBytes,
|
|
});
|
|
// Arbitrarily add at most 2 bytes worth of payload (data or parameters).
|
|
constexpr static size_t kArbitraryMaxPayloadSizeBytes = 2;
|
|
constexpr static size_t kMaxPacketSizeBytes =
|
|
kMaxHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes;
|
|
std::array<std::byte, kMaxPacketSizeBytes> packet_buffer_;
|
|
};
|
|
|
|
TEST_F(PacketTest, CommandPacketHeaderUndersizedEncode) {
|
|
const CommandPacket packet(0u, ConstByteSpan());
|
|
EXPECT_EQ(0u, packet.parameters().size_bytes());
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(
|
|
{packet_buffer_.data(), CommandPacket::kHeaderSizeBytes - 1});
|
|
EXPECT_EQ(Status::ResourceExhausted(), encode_result.status());
|
|
}
|
|
|
|
TEST_F(PacketTest, CommandPacketHeaderUndersizedDecode) {
|
|
EXPECT_FALSE(CommandPacket::Decode(
|
|
{packet_buffer_.data(), CommandPacket::kHeaderSizeBytes - 1})
|
|
.has_value());
|
|
}
|
|
|
|
TEST_F(PacketTest, CommandPacketHeaderOnlyEncodeAndDecode) {
|
|
constexpr uint16_t kOpcodeCommandField = 0b00'0000'0000;
|
|
constexpr uint8_t kOpcodeGroupField = 0b11'1111;
|
|
|
|
constexpr uint16_t kOpcode = (kOpcodeGroupField << 10) | kOpcodeCommandField;
|
|
|
|
const CommandPacket packet(kOpcode, ConstByteSpan());
|
|
EXPECT_EQ(packet.type(), Packet::Type::kCommandPacket);
|
|
EXPECT_EQ(packet.size_bytes(), CommandPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(packet.opcode(), kOpcode);
|
|
EXPECT_EQ(packet.opcode_command_field(), kOpcodeCommandField);
|
|
EXPECT_EQ(packet.opcode_group_field(), kOpcodeGroupField);
|
|
EXPECT_EQ(packet.parameters().size_bytes(), 0u);
|
|
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(packet_buffer_);
|
|
ASSERT_EQ(OkStatus(), encode_result.status());
|
|
|
|
constexpr std::array<const std::byte, CommandPacket::kHeaderSizeBytes>
|
|
kExpectedEncodedPacket = bytes::MakeArray<const std::byte>(
|
|
0b0000'0000, 0b1111'1100, 0b0000'0000);
|
|
const ConstByteSpan& encoded_packet = encode_result.value();
|
|
EXPECT_TRUE(std::equal(kExpectedEncodedPacket.begin(),
|
|
kExpectedEncodedPacket.end(),
|
|
encoded_packet.begin(),
|
|
encoded_packet.end()));
|
|
|
|
// First, decode it from a perfectly sized span which we just encoded.
|
|
std::optional<CommandPacket> possible_packet =
|
|
CommandPacket::Decode(encoded_packet);
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
CommandPacket& decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kCommandPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(), CommandPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(decoded_packet.opcode(), kOpcode);
|
|
EXPECT_EQ(decoded_packet.opcode_command_field(), kOpcodeCommandField);
|
|
EXPECT_EQ(decoded_packet.opcode_group_field(), kOpcodeGroupField);
|
|
EXPECT_EQ(decoded_packet.parameters().size_bytes(), 0u);
|
|
|
|
// Second, decode it from an oversized buffer.
|
|
possible_packet = CommandPacket::Decode({packet_buffer_});
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kCommandPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(), CommandPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(decoded_packet.opcode(), kOpcode);
|
|
EXPECT_EQ(decoded_packet.opcode_command_field(), kOpcodeCommandField);
|
|
EXPECT_EQ(decoded_packet.opcode_group_field(), kOpcodeGroupField);
|
|
EXPECT_EQ(decoded_packet.parameters().size_bytes(), 0u);
|
|
}
|
|
|
|
TEST_F(PacketTest, CommandPacketWithParametersEncodeAndDecode) {
|
|
constexpr uint16_t kOpcodeCommandField = 0b10'1010'1010;
|
|
constexpr uint8_t kOpcodeGroupField = 0b10'1010;
|
|
|
|
constexpr uint16_t kOpcode = (kOpcodeGroupField << 10) | kOpcodeCommandField;
|
|
|
|
constexpr std::array<const std::byte, kArbitraryMaxPayloadSizeBytes>
|
|
kParameters = bytes::MakeArray<const std::byte>(1, 2);
|
|
const CommandPacket packet(kOpcode, kParameters);
|
|
EXPECT_EQ(packet.type(), Packet::Type::kCommandPacket);
|
|
EXPECT_EQ(packet.size_bytes(),
|
|
CommandPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(packet.opcode(), kOpcode);
|
|
EXPECT_EQ(packet.opcode_command_field(), kOpcodeCommandField);
|
|
EXPECT_EQ(packet.opcode_group_field(), kOpcodeGroupField);
|
|
EXPECT_EQ(packet.parameters().size_bytes(), kArbitraryMaxPayloadSizeBytes);
|
|
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(packet_buffer_);
|
|
ASSERT_EQ(OkStatus(), encode_result.status());
|
|
|
|
constexpr std::array<const std::byte,
|
|
CommandPacket::kHeaderSizeBytes +
|
|
kArbitraryMaxPayloadSizeBytes>
|
|
kExpectedEncodedPacket = bytes::MakeArray<const std::byte>(
|
|
0b1010'1010, 0b1010'1010, 0b0000'0010, 1, 2);
|
|
const ConstByteSpan& encoded_packet = encode_result.value();
|
|
EXPECT_TRUE(std::equal(kExpectedEncodedPacket.begin(),
|
|
kExpectedEncodedPacket.end(),
|
|
encoded_packet.begin(),
|
|
encoded_packet.end()));
|
|
|
|
// First, decode it from a perfectly sized span which we just encoded.
|
|
std::optional<CommandPacket> possible_packet =
|
|
CommandPacket::Decode(encoded_packet);
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
CommandPacket& decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kCommandPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(),
|
|
CommandPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(decoded_packet.opcode(), kOpcode);
|
|
EXPECT_EQ(decoded_packet.opcode_command_field(), kOpcodeCommandField);
|
|
EXPECT_EQ(decoded_packet.opcode_group_field(), kOpcodeGroupField);
|
|
EXPECT_EQ(decoded_packet.parameters().size_bytes(),
|
|
kArbitraryMaxPayloadSizeBytes);
|
|
|
|
// Second, decode it from an oversized buffer.
|
|
possible_packet = CommandPacket::Decode({packet_buffer_});
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kCommandPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(),
|
|
CommandPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(decoded_packet.opcode(), kOpcode);
|
|
EXPECT_EQ(decoded_packet.opcode_command_field(), kOpcodeCommandField);
|
|
EXPECT_EQ(decoded_packet.opcode_group_field(), kOpcodeGroupField);
|
|
EXPECT_EQ(decoded_packet.parameters().size_bytes(),
|
|
kArbitraryMaxPayloadSizeBytes);
|
|
}
|
|
|
|
TEST_F(PacketTest, AsyncDataPacketHeaderUndersizedEncode) {
|
|
const AsyncDataPacket packet(0u, ConstByteSpan());
|
|
EXPECT_EQ(0u, packet.data().size_bytes());
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(
|
|
{packet_buffer_.data(), AsyncDataPacket::kHeaderSizeBytes - 1});
|
|
EXPECT_EQ(Status::ResourceExhausted(), encode_result.status());
|
|
}
|
|
|
|
TEST_F(PacketTest, AsyncDataPacketHeaderUndersizedDecode) {
|
|
EXPECT_FALSE(AsyncDataPacket::Decode({packet_buffer_.data(),
|
|
AsyncDataPacket::kHeaderSizeBytes - 1})
|
|
.has_value());
|
|
}
|
|
|
|
TEST_F(PacketTest, AsyncDataPacketHeaderOnlyEncodeAndDecode) {
|
|
constexpr uint16_t kHandle = 0b00'0000'0000;
|
|
constexpr uint8_t kPbFlag = 0b01;
|
|
constexpr uint8_t kBcFlag = 0b10;
|
|
|
|
constexpr uint16_t kHandleAndFragmentationBits =
|
|
kHandle | (kPbFlag << 12) | (kBcFlag << 14);
|
|
|
|
const AsyncDataPacket packet(kHandleAndFragmentationBits, ConstByteSpan());
|
|
EXPECT_EQ(packet.type(), Packet::Type::kAsyncDataPacket);
|
|
EXPECT_EQ(packet.size_bytes(), AsyncDataPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(packet.handle_and_fragmentation_bits(),
|
|
kHandleAndFragmentationBits);
|
|
EXPECT_EQ(packet.handle(), kHandle);
|
|
EXPECT_EQ(packet.pb_flag(), kPbFlag);
|
|
EXPECT_EQ(packet.bc_flag(), kBcFlag);
|
|
EXPECT_EQ(packet.data().size_bytes(), 0u);
|
|
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(packet_buffer_);
|
|
ASSERT_EQ(OkStatus(), encode_result.status());
|
|
|
|
constexpr std::array<const std::byte, AsyncDataPacket::kHeaderSizeBytes>
|
|
kExpectedEncodedPacket = bytes::MakeArray<const std::byte>(
|
|
0b0000'0000, 0b1001'0000, 0b0000'0000, 0b0000'0000);
|
|
const ConstByteSpan& encoded_packet = encode_result.value();
|
|
EXPECT_TRUE(std::equal(kExpectedEncodedPacket.begin(),
|
|
kExpectedEncodedPacket.end(),
|
|
encoded_packet.begin(),
|
|
encoded_packet.end()));
|
|
|
|
// First, decode it from a perfectly sized span which we just encoded.
|
|
std::optional<AsyncDataPacket> possible_packet =
|
|
AsyncDataPacket::Decode(encoded_packet);
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
AsyncDataPacket& decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kAsyncDataPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(), AsyncDataPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(decoded_packet.handle_and_fragmentation_bits(),
|
|
kHandleAndFragmentationBits);
|
|
EXPECT_EQ(decoded_packet.handle(), kHandle);
|
|
EXPECT_EQ(decoded_packet.pb_flag(), kPbFlag);
|
|
EXPECT_EQ(decoded_packet.bc_flag(), kBcFlag);
|
|
EXPECT_EQ(decoded_packet.data().size_bytes(), 0u);
|
|
|
|
// Second, decode it from an oversized buffer.
|
|
possible_packet = AsyncDataPacket::Decode({packet_buffer_});
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kAsyncDataPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(), AsyncDataPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(decoded_packet.handle_and_fragmentation_bits(),
|
|
kHandleAndFragmentationBits);
|
|
EXPECT_EQ(decoded_packet.handle(), kHandle);
|
|
EXPECT_EQ(decoded_packet.pb_flag(), kPbFlag);
|
|
EXPECT_EQ(decoded_packet.bc_flag(), kBcFlag);
|
|
EXPECT_EQ(decoded_packet.data().size_bytes(), 0u);
|
|
}
|
|
|
|
TEST_F(PacketTest, AsyncDataPacketWithDataEncodeAndDecode) {
|
|
constexpr uint16_t kHandle = 0b00'0000'0000;
|
|
constexpr uint8_t kPbFlag = 0b01;
|
|
constexpr uint8_t kBcFlag = 0b10;
|
|
|
|
constexpr uint16_t kHandleAndFragmentationBits =
|
|
kHandle | (kPbFlag << 12) | (kBcFlag << 14);
|
|
|
|
constexpr std::array<const std::byte, kArbitraryMaxPayloadSizeBytes> kData =
|
|
bytes::MakeArray<const std::byte>(1, 2);
|
|
const AsyncDataPacket packet(kHandleAndFragmentationBits, kData);
|
|
EXPECT_EQ(packet.type(), Packet::Type::kAsyncDataPacket);
|
|
EXPECT_EQ(packet.size_bytes(),
|
|
AsyncDataPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(packet.handle_and_fragmentation_bits(),
|
|
kHandleAndFragmentationBits);
|
|
EXPECT_EQ(packet.handle(), kHandle);
|
|
EXPECT_EQ(packet.pb_flag(), kPbFlag);
|
|
EXPECT_EQ(packet.bc_flag(), kBcFlag);
|
|
EXPECT_EQ(packet.data().size_bytes(), kArbitraryMaxPayloadSizeBytes);
|
|
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(packet_buffer_);
|
|
ASSERT_EQ(OkStatus(), encode_result.status());
|
|
|
|
constexpr std::array<const std::byte,
|
|
AsyncDataPacket::kHeaderSizeBytes +
|
|
kArbitraryMaxPayloadSizeBytes>
|
|
kExpectedEncodedPacket = bytes::MakeArray<const std::byte>(
|
|
0b0000'0000, 0b1001'0000, 0b0000'0010, 0b0000'0000, 1, 2);
|
|
const ConstByteSpan& encoded_packet = encode_result.value();
|
|
EXPECT_TRUE(std::equal(kExpectedEncodedPacket.begin(),
|
|
kExpectedEncodedPacket.end(),
|
|
encoded_packet.begin(),
|
|
encoded_packet.end()));
|
|
|
|
// First, decode it from a perfectly sized span which we just encoded.
|
|
std::optional<AsyncDataPacket> possible_packet =
|
|
AsyncDataPacket::Decode(encoded_packet);
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
AsyncDataPacket& decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kAsyncDataPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(),
|
|
AsyncDataPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(decoded_packet.handle_and_fragmentation_bits(),
|
|
kHandleAndFragmentationBits);
|
|
EXPECT_EQ(decoded_packet.handle(), kHandle);
|
|
EXPECT_EQ(decoded_packet.pb_flag(), kPbFlag);
|
|
EXPECT_EQ(decoded_packet.bc_flag(), kBcFlag);
|
|
EXPECT_EQ(decoded_packet.data().size_bytes(), kArbitraryMaxPayloadSizeBytes);
|
|
|
|
// Second, decode it from an oversized buffer.
|
|
possible_packet = AsyncDataPacket::Decode({packet_buffer_});
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kAsyncDataPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(),
|
|
AsyncDataPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(decoded_packet.handle_and_fragmentation_bits(),
|
|
kHandleAndFragmentationBits);
|
|
EXPECT_EQ(decoded_packet.handle(), kHandle);
|
|
EXPECT_EQ(decoded_packet.pb_flag(), kPbFlag);
|
|
EXPECT_EQ(decoded_packet.bc_flag(), kBcFlag);
|
|
EXPECT_EQ(decoded_packet.data().size_bytes(), kArbitraryMaxPayloadSizeBytes);
|
|
}
|
|
|
|
TEST_F(PacketTest, SyncDataPacketHeaderUndersizedEncode) {
|
|
const SyncDataPacket packet(0u, ConstByteSpan());
|
|
EXPECT_EQ(0u, packet.data().size_bytes());
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(
|
|
{packet_buffer_.data(), SyncDataPacket::kHeaderSizeBytes - 1});
|
|
EXPECT_EQ(Status::ResourceExhausted(), encode_result.status());
|
|
}
|
|
|
|
TEST_F(PacketTest, SyncDataPacketHeaderUndersizedDecode) {
|
|
EXPECT_FALSE(SyncDataPacket::Decode({packet_buffer_.data(),
|
|
SyncDataPacket::kHeaderSizeBytes - 1})
|
|
.has_value());
|
|
}
|
|
|
|
TEST_F(PacketTest, SyncDataPacketHeaderOnlyEncodeAndDecode) {
|
|
constexpr uint16_t kHandle = 0b00'0000'0000;
|
|
constexpr uint8_t kPacketStatusFlag = 0b11;
|
|
constexpr uint8_t kReservedBits = 0;
|
|
|
|
constexpr uint16_t kHandleAndStatusBits =
|
|
kHandle | (kPacketStatusFlag << 12) | (kReservedBits << 14);
|
|
|
|
const SyncDataPacket packet(kHandleAndStatusBits, ConstByteSpan());
|
|
EXPECT_EQ(packet.type(), Packet::Type::kSyncDataPacket);
|
|
EXPECT_EQ(packet.size_bytes(), SyncDataPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(packet.handle_and_status_bits(), kHandleAndStatusBits);
|
|
EXPECT_EQ(packet.handle(), kHandle);
|
|
EXPECT_EQ(packet.packet_status_flag(), kPacketStatusFlag);
|
|
EXPECT_EQ(packet.data().size_bytes(), 0u);
|
|
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(packet_buffer_);
|
|
ASSERT_EQ(OkStatus(), encode_result.status());
|
|
|
|
constexpr std::array<const std::byte, SyncDataPacket::kHeaderSizeBytes>
|
|
kExpectedEncodedPacket = bytes::MakeArray<const std::byte>(
|
|
0b0000'0000, 0b0011'0000, 0b0000'0000);
|
|
const ConstByteSpan& encoded_packet = encode_result.value();
|
|
EXPECT_TRUE(std::equal(kExpectedEncodedPacket.begin(),
|
|
kExpectedEncodedPacket.end(),
|
|
encoded_packet.begin(),
|
|
encoded_packet.end()));
|
|
|
|
// First, decode it from a perfectly sized span which we just encoded.
|
|
std::optional<SyncDataPacket> possible_packet =
|
|
SyncDataPacket::Decode(encoded_packet);
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
SyncDataPacket& decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kSyncDataPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(), SyncDataPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(packet.handle_and_status_bits(), kHandleAndStatusBits);
|
|
EXPECT_EQ(decoded_packet.packet_status_flag(), kPacketStatusFlag);
|
|
EXPECT_EQ(decoded_packet.handle(), kHandle);
|
|
EXPECT_EQ(decoded_packet.data().size_bytes(), 0u);
|
|
|
|
// Second, decode it from an oversized buffer.
|
|
possible_packet = SyncDataPacket::Decode({packet_buffer_});
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kSyncDataPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(), SyncDataPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(packet.handle_and_status_bits(), kHandleAndStatusBits);
|
|
EXPECT_EQ(decoded_packet.handle(), kHandle);
|
|
EXPECT_EQ(decoded_packet.packet_status_flag(), kPacketStatusFlag);
|
|
EXPECT_EQ(decoded_packet.data().size_bytes(), 0u);
|
|
}
|
|
|
|
TEST_F(PacketTest, SyncDataPacketWithDataEncodeAndDecode) {
|
|
constexpr uint16_t kHandle = 0b00'0000'0000;
|
|
constexpr uint8_t kPacketStatusFlag = 0b11;
|
|
constexpr uint8_t kReservedBits = 0;
|
|
|
|
constexpr uint16_t kHandleAndStatusBits =
|
|
kHandle | (kPacketStatusFlag << 12) | (kReservedBits << 14);
|
|
|
|
constexpr std::array<const std::byte, kArbitraryMaxPayloadSizeBytes> kData =
|
|
bytes::MakeArray<const std::byte>(1, 2);
|
|
const SyncDataPacket packet(kHandleAndStatusBits, kData);
|
|
EXPECT_EQ(packet.type(), Packet::Type::kSyncDataPacket);
|
|
EXPECT_EQ(packet.size_bytes(),
|
|
SyncDataPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(packet.handle_and_status_bits(), kHandleAndStatusBits);
|
|
EXPECT_EQ(packet.handle(), kHandle);
|
|
EXPECT_EQ(packet.packet_status_flag(), kPacketStatusFlag);
|
|
EXPECT_EQ(packet.data().size_bytes(), kArbitraryMaxPayloadSizeBytes);
|
|
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(packet_buffer_);
|
|
ASSERT_EQ(OkStatus(), encode_result.status());
|
|
|
|
constexpr std::array<const std::byte,
|
|
SyncDataPacket::kHeaderSizeBytes +
|
|
kArbitraryMaxPayloadSizeBytes>
|
|
kExpectedEncodedPacket = bytes::MakeArray<const std::byte>(
|
|
0b0000'0000, 0b0011'0000, 0b0000'0010, 1, 2);
|
|
const ConstByteSpan& encoded_packet = encode_result.value();
|
|
EXPECT_TRUE(std::equal(kExpectedEncodedPacket.begin(),
|
|
kExpectedEncodedPacket.end(),
|
|
encoded_packet.begin(),
|
|
encoded_packet.end()));
|
|
|
|
// First, decode it from a perfectly sized span which we just encoded.
|
|
std::optional<SyncDataPacket> possible_packet =
|
|
SyncDataPacket::Decode(encoded_packet);
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
SyncDataPacket& decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kSyncDataPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(),
|
|
SyncDataPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(packet.handle_and_status_bits(), kHandleAndStatusBits);
|
|
EXPECT_EQ(packet.handle(), kHandle);
|
|
EXPECT_EQ(packet.packet_status_flag(), kPacketStatusFlag);
|
|
EXPECT_EQ(decoded_packet.data().size_bytes(), kArbitraryMaxPayloadSizeBytes);
|
|
|
|
// Second, decode it from an oversized buffer.
|
|
possible_packet = SyncDataPacket::Decode({packet_buffer_});
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kSyncDataPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(),
|
|
SyncDataPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(packet.handle_and_status_bits(), kHandleAndStatusBits);
|
|
EXPECT_EQ(packet.handle(), kHandle);
|
|
EXPECT_EQ(packet.packet_status_flag(), kPacketStatusFlag);
|
|
EXPECT_EQ(decoded_packet.data().size_bytes(), kArbitraryMaxPayloadSizeBytes);
|
|
}
|
|
|
|
TEST_F(PacketTest, EventPacketHeaderUndersizedEncode) {
|
|
const EventPacket packet(0u, ConstByteSpan());
|
|
EXPECT_EQ(0u, packet.parameters().size_bytes());
|
|
const Result<ConstByteSpan> encode_result =
|
|
packet.Encode({packet_buffer_.data(), EventPacket::kHeaderSizeBytes - 1});
|
|
EXPECT_EQ(Status::ResourceExhausted(), encode_result.status());
|
|
}
|
|
|
|
TEST_F(PacketTest, EventPacketHeaderUndersizedDecode) {
|
|
EXPECT_FALSE(EventPacket::Decode(
|
|
{packet_buffer_.data(), EventPacket::kHeaderSizeBytes - 1})
|
|
.has_value());
|
|
}
|
|
|
|
TEST_F(PacketTest, EventPacketHeaderOnlyEncodeAndDecode) {
|
|
constexpr uint8_t kEventCode = 0b1111'1111;
|
|
|
|
const EventPacket packet(kEventCode, ConstByteSpan());
|
|
EXPECT_EQ(packet.type(), Packet::Type::kEventPacket);
|
|
EXPECT_EQ(packet.size_bytes(), EventPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(packet.event_code(), kEventCode);
|
|
EXPECT_EQ(packet.parameters().size_bytes(), 0u);
|
|
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(packet_buffer_);
|
|
ASSERT_EQ(OkStatus(), encode_result.status());
|
|
|
|
constexpr std::array<const std::byte, EventPacket::kHeaderSizeBytes>
|
|
kExpectedEncodedPacket =
|
|
bytes::MakeArray<const std::byte>(0b1111'11111, 0b0000'0000);
|
|
const ConstByteSpan& encoded_packet = encode_result.value();
|
|
EXPECT_TRUE(std::equal(kExpectedEncodedPacket.begin(),
|
|
kExpectedEncodedPacket.end(),
|
|
encoded_packet.begin(),
|
|
encoded_packet.end()));
|
|
|
|
// First, decode it from a perfectly sized span which we just encoded.
|
|
std::optional<EventPacket> possible_packet =
|
|
EventPacket::Decode(encoded_packet);
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
EventPacket& decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kEventPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(), EventPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(decoded_packet.event_code(), kEventCode);
|
|
EXPECT_EQ(decoded_packet.parameters().size_bytes(), 0u);
|
|
|
|
// Second, decode it from an oversized buffer.
|
|
possible_packet = EventPacket::Decode({packet_buffer_});
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kEventPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(), EventPacket::kHeaderSizeBytes);
|
|
EXPECT_EQ(decoded_packet.event_code(), kEventCode);
|
|
EXPECT_EQ(decoded_packet.parameters().size_bytes(), 0u);
|
|
}
|
|
|
|
TEST_F(PacketTest, EventPacketWithParametersEncodeAndDecode) {
|
|
constexpr uint8_t kEventCode = 0b1111'0000;
|
|
|
|
constexpr std::array<const std::byte, kArbitraryMaxPayloadSizeBytes>
|
|
kParameters = bytes::MakeArray<const std::byte>(1, 2);
|
|
const EventPacket packet(kEventCode, kParameters);
|
|
EXPECT_EQ(packet.type(), Packet::Type::kEventPacket);
|
|
EXPECT_EQ(packet.size_bytes(),
|
|
EventPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(packet.event_code(), kEventCode);
|
|
EXPECT_EQ(packet.parameters().size_bytes(), kArbitraryMaxPayloadSizeBytes);
|
|
|
|
const Result<ConstByteSpan> encode_result = packet.Encode(packet_buffer_);
|
|
ASSERT_EQ(OkStatus(), encode_result.status());
|
|
|
|
constexpr std::array<const std::byte,
|
|
EventPacket::kHeaderSizeBytes +
|
|
kArbitraryMaxPayloadSizeBytes>
|
|
kExpectedEncodedPacket =
|
|
bytes::MakeArray<const std::byte>(0b1111'0000, 0b0000'0010, 1, 2);
|
|
const ConstByteSpan& encoded_packet = encode_result.value();
|
|
EXPECT_TRUE(std::equal(kExpectedEncodedPacket.begin(),
|
|
kExpectedEncodedPacket.end(),
|
|
encoded_packet.begin(),
|
|
encoded_packet.end()));
|
|
|
|
// First, decode it from a perfectly sized span which we just encoded.
|
|
std::optional<EventPacket> possible_packet =
|
|
EventPacket::Decode(encoded_packet);
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
EventPacket& decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kEventPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(),
|
|
EventPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(decoded_packet.event_code(), kEventCode);
|
|
EXPECT_EQ(decoded_packet.parameters().size_bytes(),
|
|
kArbitraryMaxPayloadSizeBytes);
|
|
|
|
// Second, decode it from an oversized buffer.
|
|
possible_packet = EventPacket::Decode({packet_buffer_});
|
|
ASSERT_TRUE(possible_packet.has_value());
|
|
decoded_packet = possible_packet.value();
|
|
EXPECT_EQ(decoded_packet.type(), Packet::Type::kEventPacket);
|
|
EXPECT_EQ(decoded_packet.size_bytes(),
|
|
EventPacket::kHeaderSizeBytes + kArbitraryMaxPayloadSizeBytes);
|
|
EXPECT_EQ(decoded_packet.event_code(), kEventCode);
|
|
EXPECT_EQ(decoded_packet.parameters().size_bytes(),
|
|
kArbitraryMaxPayloadSizeBytes);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace pw::bluetooth_hci
|