blob: 47db7235654318fc6a9edf6033900d52e740b4de [file] [log] [blame]
// Copyright 2023 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 <numeric>
#include "lib/stdcompat/utility.h"
#include "pw_unit_test/framework.h" // IWYU pragma: keep
// clang-format off
// All emboss headers are listed (even if they don't have explicit tests) to
// ensure they are compiled.
#include "pw_bluetooth/hci_commands.emb.h" // IWYU pragma: keep
#include "pw_bluetooth/hci_common.emb.h"
#include "pw_bluetooth/hci_data.emb.h"
#include "pw_bluetooth/hci_events.emb.h" // IWYU pragma: keep
#include "pw_bluetooth/hci_h4.emb.h" // IWYU pragma: keep
#include "pw_bluetooth/hci_test.emb.h"
#include "pw_bluetooth/hci_android.emb.h" // IWYU pragma: keep
#include "pw_bluetooth/l2cap_frames.emb.h" // IWYU pragma: keep
// clang-format on
namespace pw::bluetooth {
namespace {
// Examples are used in docs.rst.
TEST(EmbossExamples, MakeView) {
// DOCSTAG: [pw_bluetooth-examples-make_view]
std::array<uint8_t, 4> buffer = {0x00, 0x01, 0x02, 0x03};
auto view = emboss::MakeTestCommandPacketView(&buffer);
EXPECT_TRUE(view.IsComplete());
EXPECT_EQ(view.payload().Read(), 0x03);
// DOCSTAG: [pw_bluetooth-examples-make_view]
}
TEST(EmbossTest, MakeView) {
std::array<uint8_t, 4> buffer = {0x00, 0x01, 0x02, 0x03};
auto view = emboss::MakeTestCommandPacketView(&buffer);
EXPECT_TRUE(view.IsComplete());
EXPECT_EQ(view.payload().Read(), 0x03);
}
// This definition has a mix of full-width values and bitfields and includes
// conditional bitfields. Let's add this to verify that the structure itself
// doesn't get changed incorrectly and that emboss' size calculation matches
// ours.
TEST(EmbossTest, CheckIsoHeaderSize) {
EXPECT_EQ(emboss::IsoDataFrameHeader::MaxSizeInBytes(), 12);
}
// Test and demonstrate various ways of reading opcodes.
TEST(EmbossTest, ReadOpcodesFromCommandHeader) {
// First two bytes will be used as opcode.
std::array<uint8_t, 4> buffer = {0x00, 0x00, 0x02, 0x03};
auto view = emboss::MakeTestCommandPacketView(&buffer);
EXPECT_TRUE(view.IsComplete());
auto header = view.header();
EXPECT_EQ(header.opcode_enum().Read(), emboss::OpCode::UNSPECIFIED);
EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x0000);
EXPECT_EQ(header.opcode_bits().ogf().Read(), 0x00);
EXPECT_EQ(header.opcode_bits().ocf().Read(), 0x00);
// TODO: https://pwbug.dev/338068316 - Delete these opcode type
// OpCodeBits cases once opcode has type OpCode.
EXPECT_EQ(header.opcode().ogf().Read(), 0x00);
EXPECT_EQ(header.opcode().ocf().Read(), 0x00);
// LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
header.opcode_enum().Write(emboss::OpCode::LINK_KEY_REQUEST_REPLY);
EXPECT_EQ(header.opcode_enum().Read(),
emboss::OpCode::LINK_KEY_REQUEST_REPLY);
EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x040B);
EXPECT_EQ(header.opcode_bits().ogf().Read(), 0x01);
EXPECT_EQ(header.opcode_bits().ocf().Read(), 0x0B);
// TODO: https://pwbug.dev/338068316 - Delete these opcode type
// OpCodeBits cases once opcode has type OpCode.
EXPECT_EQ(header.opcode().ogf().Read(), 0x01);
EXPECT_EQ(header.opcode().ocf().Read(), 0x0B);
}
// Test and demonstrate various ways of writing opcodes.
TEST(EmbossTest, WriteOpcodesFromCommandHeader) {
std::array<uint8_t, 4> buffer = {};
buffer.fill(0xFF);
auto view = emboss::MakeTestCommandPacketView(&buffer);
EXPECT_TRUE(view.IsComplete());
auto header = view.header();
header.opcode_enum().Write(emboss::OpCode::UNSPECIFIED);
EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x0000);
header.opcode().ocf().Write(0x0B);
EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x000B);
header.opcode().ogf().Write(0x01);
EXPECT_EQ(header.opcode().BackingStorage().ReadUInt(), 0x040B);
// LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
EXPECT_EQ(header.opcode_enum().Read(),
emboss::OpCode::LINK_KEY_REQUEST_REPLY);
}
// Test and demonstrate using to_underlying with OpCodes enums
TEST(EmbossTest, OPCodeEnumsWithToUnderlying) {
EXPECT_EQ(0x0000, cpp23::to_underlying(emboss::OpCode::UNSPECIFIED));
}
TEST(EmbossTest, ReadAndWriteOpcodesInCommandResponseHeader) {
// First two bytes will be used as opcode.
std::array<uint8_t,
emboss::ReadBufferSizeCommandCompleteEventView::SizeInBytes()>
buffer;
std::iota(buffer.begin(), buffer.end(), 100);
auto view = emboss::MakeReadBufferSizeCommandCompleteEventView(&buffer);
EXPECT_TRUE(view.IsComplete());
auto header = view.command_complete();
header.command_opcode().BackingStorage().WriteUInt(0x0000);
EXPECT_EQ(header.command_opcode_enum().Read(), emboss::OpCode::UNSPECIFIED);
EXPECT_EQ(header.command_opcode().BackingStorage().ReadUInt(), 0x0000);
EXPECT_EQ(header.command_opcode_bits().ogf().Read(), 0x00);
EXPECT_EQ(header.command_opcode_bits().ocf().Read(), 0x00);
// TODO: https://pwbug.dev/338068316 - Delete these command_opcode type
// OpCodeBits cases once command_opcode has type OpCode.
EXPECT_EQ(header.command_opcode().ogf().Read(), 0x00);
EXPECT_EQ(header.command_opcode().ocf().Read(), 0x00);
// LINK_KEY_REQUEST_REPLY is OGF 0x01 and OCF 0x0B.
header.command_opcode_enum().Write(emboss::OpCode::LINK_KEY_REQUEST_REPLY);
EXPECT_EQ(header.command_opcode_enum().Read(),
emboss::OpCode::LINK_KEY_REQUEST_REPLY);
EXPECT_EQ(header.command_opcode().BackingStorage().ReadUInt(), 0x040B);
EXPECT_EQ(header.command_opcode_bits().ogf().Read(), 0x01);
EXPECT_EQ(header.command_opcode_bits().ocf().Read(), 0x0B);
// TODO: https://pwbug.dev/338068316 - Delete these command_opcode type
// OpCodeBits cases once command_opcode has type OpCode.
EXPECT_EQ(header.command_opcode().ogf().Read(), 0x01);
EXPECT_EQ(header.command_opcode().ocf().Read(), 0x0B);
}
TEST(EmbossTest, ReadAndWriteEventCodesInEventHeader) {
std::array<uint8_t, emboss::EventHeaderWriter::SizeInBytes()> buffer;
std::iota(buffer.begin(), buffer.end(), 100);
auto header = emboss::MakeEventHeaderView(&buffer);
EXPECT_TRUE(header.IsComplete());
header.event_code_uint().Write(
cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
EXPECT_EQ(header.event_code_enum().Read(),
emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS);
EXPECT_EQ(
header.event_code_uint().Read(),
cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
// TODO: https://pwbug.dev/338068316 - Delete these event_code type
// UInt cases once event_code has type EventCode.
EXPECT_EQ(
header.event_code().Read(),
cpp23::to_underlying(emboss::EventCode::NUMBER_OF_COMPLETED_PACKETS));
header.event_code().Write(
cpp23::to_underlying(emboss::EventCode::CONNECTION_REQUEST));
EXPECT_EQ(header.event_code_uint().Read(),
cpp23::to_underlying(emboss::EventCode::CONNECTION_REQUEST));
}
} // namespace
} // namespace pw::bluetooth