/*
 * Copyright 2019 The Android Open Source Project
 *
 * 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
 *
 *      http://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 "hci/hci_layer.h"

#include <gtest/gtest.h>

#include <list>
#include <memory>

#include "hal/hci_hal_fake.h"
#include "hci/hci_packets.h"
#include "module.h"
#include "os/thread.h"
#include "packet/bit_inserter.h"
#include "packet/raw_builder.h"

using bluetooth::os::Thread;
using bluetooth::packet::BitInserter;
using bluetooth::packet::RawBuilder;
using std::vector;

namespace {
vector<uint8_t> information_request = {
        0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
};
// 0x00, 0x01, 0x02, 0x03, ...
vector<uint8_t> counting_bytes;
// 0xFF, 0xFE, 0xFD, 0xFC, ...
vector<uint8_t> counting_down_bytes;
const size_t count_size = 0x8;

}  // namespace

namespace bluetooth {
namespace hci {
namespace {

constexpr std::chrono::milliseconds kTimeout = HciLayer::kHciTimeoutMs / 2;

class DependsOnHci : public Module {
public:
  DependsOnHci() : Module() {}

  void SendHciCommandExpectingStatus(std::unique_ptr<CommandBuilder> command) {
    hci_->EnqueueCommand(
            std::move(command),
            GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandStatusView>));
  }

  void SendHciCommandExpectingComplete(std::unique_ptr<CommandBuilder> command) {
    hci_->EnqueueCommand(
            std::move(command),
            GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandCompleteView>));
  }

  void SendSecurityCommandExpectingComplete(std::unique_ptr<SecurityCommandBuilder> command) {
    if (security_interface_ == nullptr) {
      security_interface_ = hci_->GetSecurityInterface(
              GetHandler()->BindOn(this, &DependsOnHci::handle_event<EventView>));
    }
    hci_->EnqueueCommand(
            std::move(command),
            GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandCompleteView>));
  }

  void SendLeSecurityCommandExpectingComplete(std::unique_ptr<LeSecurityCommandBuilder> command) {
    if (le_security_interface_ == nullptr) {
      le_security_interface_ = hci_->GetLeSecurityInterface(
              GetHandler()->BindOn(this, &DependsOnHci::handle_event<LeMetaEventView>));
    }
    hci_->EnqueueCommand(
            std::move(command),
            GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandCompleteView>));
  }

  void SendAclData(std::unique_ptr<AclBuilder> acl) {
    outgoing_acl_.push(std::move(acl));
    auto queue_end = hci_->GetAclQueueEnd();
    queue_end->RegisterEnqueue(
            GetHandler(), common::Bind(&DependsOnHci::handle_enqueue, common::Unretained(this)));
  }

  void SendIsoData(std::unique_ptr<IsoBuilder> iso) {
    outgoing_iso_.push(std::move(iso));
    auto queue_end = hci_->GetIsoQueueEnd();
    queue_end->RegisterEnqueue(GetHandler(), common::Bind(&DependsOnHci::handle_enqueue_iso,
                                                          common::Unretained(this)));
  }

  std::optional<EventView> GetReceivedEvent(std::chrono::milliseconds timeout = kTimeout) {
    if (!incoming_events_.wait_to_take(timeout)) {
      return {};
    }
    auto event = EventView::Create(incoming_events_.take());
    log::assert_that(event.IsValid(), "assert failed: event.IsValid()");
    return event;
  }

  std::optional<AclView> GetReceivedAcl(
          std::chrono::milliseconds timeout = std::chrono::seconds(1)) {
    if (!incoming_acl_.wait_to_take(timeout)) {
      return {};
    }
    auto acl = AclView::Create(incoming_acl_.take());
    log::assert_that(acl.IsValid(), "assert failed: acl.IsValid()");
    return acl;
  }

  std::optional<IsoView> GetReceivedIso(
          std::chrono::milliseconds timeout = std::chrono::seconds(1)) {
    if (!incoming_iso_.wait_to_take(timeout)) {
      return {};
    }
    auto iso = IsoView::Create(incoming_iso_.take());
    log::assert_that(iso.IsValid(), "assert failed: iso.IsValid()");
    return iso;
  }

  void Start() {
    hci_ = GetDependency<HciLayer>();
    hci_->RegisterEventHandler(EventCode::CONNECTION_COMPLETE,
                               GetHandler()->BindOn(this, &DependsOnHci::handle_event<EventView>));
    hci_->RegisterLeEventHandler(
            SubeventCode::CONNECTION_COMPLETE,
            GetHandler()->BindOn(this, &DependsOnHci::handle_event<LeMetaEventView>));
    hci_->GetAclQueueEnd()->RegisterDequeue(
            GetHandler(), common::Bind(&DependsOnHci::handle_acl, common::Unretained(this)));
    hci_->GetIsoQueueEnd()->RegisterDequeue(
            GetHandler(), common::Bind(&DependsOnHci::handle_iso, common::Unretained(this)));
  }

  void Stop() {
    hci_->GetAclQueueEnd()->UnregisterDequeue();
    hci_->GetIsoQueueEnd()->UnregisterDequeue();
  }

  void ListDependencies(ModuleList* list) const { list->add<HciLayer>(); }

  std::string ToString() const override { return std::string("DependsOnHci"); }

  static const ModuleFactory Factory;

private:
  HciLayer* hci_ = nullptr;
  const SecurityInterface* security_interface_;
  const LeSecurityInterface* le_security_interface_;
  common::BlockingQueue<EventView> incoming_events_;
  common::BlockingQueue<AclView> incoming_acl_;
  common::BlockingQueue<IsoView> incoming_iso_;

  void handle_acl() {
    auto acl_ptr = hci_->GetAclQueueEnd()->TryDequeue();
    incoming_acl_.push(*acl_ptr);
  }

  template <typename T>
  void handle_event(T event) {
    incoming_events_.push(event);
  }

  void handle_iso() {
    auto iso_ptr = hci_->GetIsoQueueEnd()->TryDequeue();
    incoming_iso_.push(*iso_ptr);
  }

  std::queue<std::unique_ptr<AclBuilder>> outgoing_acl_;

  std::unique_ptr<AclBuilder> handle_enqueue() {
    hci_->GetAclQueueEnd()->UnregisterEnqueue();
    auto acl = std::move(outgoing_acl_.front());
    outgoing_acl_.pop();
    return acl;
  }

  std::queue<std::unique_ptr<IsoBuilder>> outgoing_iso_;

  std::unique_ptr<IsoBuilder> handle_enqueue_iso() {
    hci_->GetIsoQueueEnd()->UnregisterEnqueue();
    auto iso = std::move(outgoing_iso_.front());
    outgoing_iso_.pop();
    return iso;
  }
};

const ModuleFactory DependsOnHci::Factory = ModuleFactory([]() { return new DependsOnHci(); });

class HciTest : public ::testing::Test {
public:
  void SetUp() override {
    counting_bytes.reserve(count_size);
    counting_down_bytes.reserve(count_size);
    for (size_t i = 0; i < count_size; i++) {
      counting_bytes.push_back(i);
      counting_down_bytes.push_back(~i);
    }
    hal = new hal::TestHciHal();

    fake_registry_.InjectTestModule(&hal::HciHal::Factory, hal);
    fake_registry_.Start<DependsOnHci>(&fake_registry_.GetTestThread());
    hci = static_cast<HciLayer*>(fake_registry_.GetModuleUnderTest(&HciLayer::Factory));
    upper = static_cast<DependsOnHci*>(fake_registry_.GetModuleUnderTest(&DependsOnHci::Factory));
    ASSERT_TRUE(fake_registry_.IsStarted<HciLayer>());

    // Verify that reset was received
    auto sent_command = hal->GetSentCommand();
    ASSERT_TRUE(sent_command.has_value());
    auto reset_view = ResetView::Create(CommandView::Create(*sent_command));
    ASSERT_TRUE(reset_view.IsValid());

    // Send the response event
    uint8_t num_packets = 1;
    ErrorCode error_code = ErrorCode::SUCCESS;
    hal->callbacks->hciEventReceived(
            GetPacketBytes(ResetCompleteBuilder::Create(num_packets, error_code)));
  }

  void TearDown() override { fake_registry_.StopAll(); }

  std::vector<uint8_t> GetPacketBytes(std::unique_ptr<packet::BasePacketBuilder> packet) {
    std::vector<uint8_t> bytes;
    BitInserter i(bytes);
    bytes.reserve(packet->size());
    packet->Serialize(i);
    return bytes;
  }

  DependsOnHci* upper = nullptr;
  hal::TestHciHal* hal = nullptr;
  HciLayer* hci = nullptr;
  TestModuleRegistry fake_registry_;
};

TEST_F(HciTest, initAndClose) {}

TEST_F(HciTest, leMetaEvent) {
  // Send an LE event
  ErrorCode status = ErrorCode::SUCCESS;
  uint16_t handle = 0x123;
  Role role = Role::CENTRAL;
  AddressType peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
  Address peer_address = Address::kAny;
  uint16_t conn_interval = 0x0ABC;
  uint16_t conn_latency = 0x0123;
  uint16_t supervision_timeout = 0x0B05;
  ClockAccuracy central_clock_accuracy = ClockAccuracy::PPM_50;
  hal->callbacks->hciEventReceived(GetPacketBytes(LeConnectionCompleteBuilder::Create(
          status, handle, role, peer_address_type, peer_address, conn_interval, conn_latency,
          supervision_timeout, central_clock_accuracy)));

  // Wait for the event
  auto event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ASSERT_TRUE(LeConnectionCompleteView::Create(LeMetaEventView::Create(EventView::Create(*event)))
                      .IsValid());
}

TEST_F(HciTest, postEventsOnceOnHciHandler) {
  // Send a CreateConnection command.
  Address addr;
  Address::FromString("01:02:03:04:05:06", addr);
  upper->SendHciCommandExpectingStatus(CreateConnectionBuilder::Create(
          addr, 0, PageScanRepetitionMode::R0, 0, ClockOffsetValid::INVALID,
          CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH));

  // Validate the received command.
  auto sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());
  auto command = CreateConnectionView::Create(
          ConnectionManagementCommandView::Create(AclCommandView::Create(*sent_command)));
  ASSERT_TRUE(command.IsValid());

  // Send a status and a connection complete at the same time.
  uint8_t num_packets = 1;
  hal->callbacks->hciEventReceived(
          GetPacketBytes(CreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, num_packets)));
  hal->callbacks->hciEventReceived(GetPacketBytes(ConnectionCompleteBuilder::Create(
          ErrorCode::SUCCESS, 0x123, addr, LinkType::ACL, Enable::DISABLED)));

  // Make sure the status comes first.
  auto event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ASSERT_TRUE(
          CreateConnectionStatusView::Create(CommandStatusView::Create(EventView::Create(*event)))
                  .IsValid());
}

TEST_F(HciTest, DISABLED_hciTimeOut) {
  upper->SendHciCommandExpectingComplete(ResetBuilder::Create());
  auto sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());
  auto reset = ResetView::Create(*sent_command);
  ASSERT_TRUE(reset.IsValid());

  auto event = upper->GetReceivedEvent(HciLayer::kHciTimeoutMs);
  ASSERT_FALSE(event.has_value());

  sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());
  auto debug = ControllerDebugInfoView::Create(VendorCommandView::Create(*sent_command));
  ASSERT_TRUE(debug.IsValid());
}

TEST_F(HciTest, noOpCredits) {
  // Send 0 credits
  uint8_t num_packets = 0;
  hal->callbacks->hciEventReceived(GetPacketBytes(NoCommandCompleteBuilder::Create(num_packets)));

  upper->SendHciCommandExpectingComplete(ReadLocalVersionInformationBuilder::Create());

  // Verify that nothing was sent
  ASSERT_FALSE(hal->GetSentCommand(std::chrono::milliseconds(10)).has_value());

  num_packets = 1;
  hal->callbacks->hciEventReceived(GetPacketBytes(NoCommandCompleteBuilder::Create(num_packets)));

  // Verify that one was sent
  auto sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());

  // Send the response event
  ErrorCode error_code = ErrorCode::SUCCESS;
  LocalVersionInformation local_version_information;
  local_version_information.hci_version_ = HciVersion::V_5_0;
  local_version_information.hci_revision_ = 0x1234;
  local_version_information.lmp_version_ = LmpVersion::V_4_2;
  local_version_information.manufacturer_name_ = 0xBAD;
  local_version_information.lmp_subversion_ = 0x5678;
  hal->callbacks->hciEventReceived(
          GetPacketBytes(ReadLocalVersionInformationCompleteBuilder::Create(
                  num_packets, error_code, local_version_information)));

  // Wait for the event
  auto event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ASSERT_TRUE(ReadLocalVersionInformationCompleteView::Create(
                      CommandCompleteView::Create(EventView::Create(*event)))
                      .IsValid());
}

TEST_F(HciTest, creditsTest) {
  auto sent_command = hal->GetSentCommand(std::chrono::milliseconds(10));
  ASSERT_FALSE(sent_command.has_value());

  // Send all three commands
  upper->SendHciCommandExpectingComplete(ReadLocalVersionInformationBuilder::Create());
  upper->SendHciCommandExpectingComplete(ReadLocalSupportedCommandsBuilder::Create());
  upper->SendHciCommandExpectingComplete(ReadLocalSupportedFeaturesBuilder::Create());

  // Verify that the first one is sent
  sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());
  auto version_view = ReadLocalVersionInformationView::Create(CommandView::Create(*sent_command));
  ASSERT_TRUE(version_view.IsValid());

  // Verify that only one was sent
  sent_command = hal->GetSentCommand(std::chrono::milliseconds(10));
  ASSERT_FALSE(sent_command.has_value());

  // Send the response event
  uint8_t num_packets = 1;
  ErrorCode error_code = ErrorCode::SUCCESS;
  LocalVersionInformation local_version_information;
  local_version_information.hci_version_ = HciVersion::V_5_0;
  local_version_information.hci_revision_ = 0x1234;
  local_version_information.lmp_version_ = LmpVersion::V_4_2;
  local_version_information.manufacturer_name_ = 0xBAD;
  local_version_information.lmp_subversion_ = 0x5678;
  hal->callbacks->hciEventReceived(
          GetPacketBytes(ReadLocalVersionInformationCompleteBuilder::Create(
                  num_packets, error_code, local_version_information)));

  // Wait for the event
  auto event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ASSERT_TRUE(ReadLocalVersionInformationCompleteView::Create(
                      CommandCompleteView::Create(EventView::Create(*event)))
                      .IsValid());

  // Verify that the second one is sent
  sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());
  auto supported_commands_view =
          ReadLocalSupportedCommandsView::Create(CommandView::Create(*sent_command));
  ASSERT_TRUE(supported_commands_view.IsValid());

  // Verify that only one was sent
  sent_command = hal->GetSentCommand(std::chrono::milliseconds(10));
  ASSERT_FALSE(sent_command.has_value());

  // Send the response event
  std::array<uint8_t, 64> supported_commands;
  for (uint8_t i = 0; i < 64; i++) {
    supported_commands[i] = i;
  }
  hal->callbacks->hciEventReceived(GetPacketBytes(ReadLocalSupportedCommandsCompleteBuilder::Create(
          num_packets, error_code, supported_commands)));

  // Wait for the event
  event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ASSERT_TRUE(ReadLocalSupportedCommandsCompleteView::Create(CommandCompleteView::Create(*event))
                      .IsValid());
  // Verify that the third one is sent
  sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());
  auto supported_features_view =
          ReadLocalSupportedFeaturesView::Create(CommandView::Create(*sent_command));
  ASSERT_TRUE(supported_features_view.IsValid());

  // Verify that only one was sent
  sent_command = hal->GetSentCommand(std::chrono::milliseconds(10));
  ASSERT_FALSE(sent_command.has_value());

  // Send the response event
  uint64_t lmp_features = 0x012345678abcdef;
  hal->callbacks->hciEventReceived(GetPacketBytes(ReadLocalSupportedFeaturesCompleteBuilder::Create(
          num_packets, error_code, lmp_features)));

  // Wait for the event
  event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ASSERT_TRUE(ReadLocalSupportedFeaturesCompleteView::Create(CommandCompleteView::Create(*event))
                      .IsValid());
}

TEST_F(HciTest, leSecurityInterfaceTest) {
  // Send LeRand to the controller
  upper->SendLeSecurityCommandExpectingComplete(LeRandBuilder::Create());

  // Check the command
  auto sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());
  LeRandView view =
          LeRandView::Create(LeSecurityCommandView::Create(CommandView::Create(*sent_command)));
  ASSERT_TRUE(view.IsValid());

  // Send a Command Complete to the host
  uint8_t num_packets = 1;
  ErrorCode status = ErrorCode::SUCCESS;
  uint64_t rand = 0x0123456789abcdef;
  hal->callbacks->hciEventReceived(
          GetPacketBytes(LeRandCompleteBuilder::Create(num_packets, status, rand)));

  // Verify the event
  auto event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ASSERT_TRUE(LeRandCompleteView::Create(CommandCompleteView::Create(*event)).IsValid());
}

TEST_F(HciTest, securityInterfacesTest) {
  // Send WriteSimplePairingMode to the controller
  Enable enable = Enable::ENABLED;
  upper->SendSecurityCommandExpectingComplete(WriteSimplePairingModeBuilder::Create(enable));

  // Check the command
  auto sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());
  auto view = WriteSimplePairingModeView::Create(
          SecurityCommandView::Create(CommandView::Create(*sent_command)));
  ASSERT_TRUE(view.IsValid());

  // Send a Command Complete to the host
  uint8_t num_packets = 1;
  ErrorCode status = ErrorCode::SUCCESS;
  hal->callbacks->hciEventReceived(
          GetPacketBytes(WriteSimplePairingModeCompleteBuilder::Create(num_packets, status)));

  // Verify the event
  auto event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ASSERT_TRUE(WriteSimplePairingModeCompleteView::Create(CommandCompleteView::Create(*event))
                      .IsValid());
}

TEST_F(HciTest, createConnectionTest) {
  // Send CreateConnection to the controller
  Address bd_addr;
  ASSERT_TRUE(Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
  uint16_t packet_type = 0x1234;
  PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R0;
  uint16_t clock_offset = 0x3456;
  ClockOffsetValid clock_offset_valid = ClockOffsetValid::VALID;
  CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
  upper->SendHciCommandExpectingStatus(
          CreateConnectionBuilder::Create(bd_addr, packet_type, page_scan_repetition_mode,
                                          clock_offset, clock_offset_valid, allow_role_switch));

  // Check the command
  auto sent_command = hal->GetSentCommand();
  ASSERT_TRUE(sent_command.has_value());
  CreateConnectionView view = CreateConnectionView::Create(ConnectionManagementCommandView::Create(
          AclCommandView::Create(CommandView::Create(*sent_command))));
  ASSERT_TRUE(view.IsValid());
  ASSERT_EQ(bd_addr, view.GetBdAddr());
  ASSERT_EQ(packet_type, view.GetPacketType());
  ASSERT_EQ(page_scan_repetition_mode, view.GetPageScanRepetitionMode());
  ASSERT_EQ(clock_offset, view.GetClockOffset());
  ASSERT_EQ(clock_offset_valid, view.GetClockOffsetValid());
  ASSERT_EQ(allow_role_switch, view.GetAllowRoleSwitch());

  // Send a Command Status to the host
  ErrorCode status = ErrorCode::SUCCESS;
  uint16_t handle = 0x123;
  LinkType link_type = LinkType::ACL;
  Enable encryption_enabled = Enable::DISABLED;
  hal->callbacks->hciEventReceived(
          GetPacketBytes(CreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 1)));

  // Verify the event
  auto event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ASSERT_TRUE(CreateConnectionStatusView::Create(CommandStatusView::Create(*event)).IsValid());

  // Send a ConnectionComplete to the host
  hal->callbacks->hciEventReceived(GetPacketBytes(ConnectionCompleteBuilder::Create(
          status, handle, bd_addr, link_type, encryption_enabled)));

  // Verify the event
  event = upper->GetReceivedEvent();
  ASSERT_TRUE(event.has_value());
  ConnectionCompleteView connection_complete_view = ConnectionCompleteView::Create(*event);
  ASSERT_TRUE(connection_complete_view.IsValid());
  ASSERT_EQ(status, connection_complete_view.GetStatus());
  ASSERT_EQ(handle, connection_complete_view.GetConnectionHandle());
  ASSERT_EQ(link_type, connection_complete_view.GetLinkType());
  ASSERT_EQ(encryption_enabled, connection_complete_view.GetEncryptionEnabled());

  // Send an ACL packet from the remote
  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
  BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
  auto acl_payload = std::make_unique<RawBuilder>();
  acl_payload->AddOctets(bd_addr.address);
  acl_payload->AddOctets2(handle);
  hal->callbacks->aclDataReceived(GetPacketBytes(AclBuilder::Create(
          handle, packet_boundary_flag, broadcast_flag, std::move(acl_payload))));

  // Verify the ACL packet
  auto acl_view_result = upper->GetReceivedAcl();
  ASSERT_TRUE(acl_view_result.has_value());
  auto acl_view = *acl_view_result;
  ASSERT_TRUE(acl_view.IsValid());
  ASSERT_EQ(bd_addr.length() + sizeof(handle), acl_view.GetPayload().size());
  auto itr = acl_view.GetPayload().begin();
  ASSERT_EQ(bd_addr, itr.extract<Address>());
  ASSERT_EQ(handle, itr.extract<uint16_t>());

  // Send an ACL packet from DependsOnHci
  PacketBoundaryFlag packet_boundary_flag2 = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
  BroadcastFlag broadcast_flag2 = BroadcastFlag::POINT_TO_POINT;
  auto acl_payload2 = std::make_unique<RawBuilder>();
  acl_payload2->AddOctets2(handle);
  acl_payload2->AddOctets(bd_addr.address);
  upper->SendAclData(AclBuilder::Create(handle, packet_boundary_flag2, broadcast_flag2,
                                        std::move(acl_payload2)));

  // Verify the ACL packet
  auto sent_acl = hal->GetSentAcl();
  ASSERT_TRUE(sent_acl.has_value());
  AclView sent_acl_view = AclView::Create(*sent_acl);
  ASSERT_TRUE(sent_acl_view.IsValid());
  ASSERT_EQ(bd_addr.length() + sizeof(handle), sent_acl_view.GetPayload().size());
  auto sent_itr = sent_acl_view.GetPayload().begin();
  ASSERT_EQ(handle, sent_itr.extract<uint16_t>());
  ASSERT_EQ(bd_addr, sent_itr.extract<Address>());
}

TEST_F(HciTest, receiveMultipleAclPackets) {
  Address bd_addr;
  ASSERT_TRUE(Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
  uint16_t handle = 0x0001;
  const uint16_t num_packets = 100;
  PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
  BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
  for (uint16_t i = 0; i < num_packets; i++) {
    auto acl_payload = std::make_unique<RawBuilder>();
    acl_payload->AddOctets(bd_addr.address);
    acl_payload->AddOctets2(handle);
    acl_payload->AddOctets2(i);
    hal->callbacks->aclDataReceived(GetPacketBytes(AclBuilder::Create(
            handle, packet_boundary_flag, broadcast_flag, std::move(acl_payload))));
  }

  for (uint16_t i = 0; i < num_packets; i++) {
    auto acl_opt = upper->GetReceivedAcl();
    ASSERT_TRUE(acl_opt.has_value());
    auto acl_view = *acl_opt;
    ASSERT_TRUE(acl_view.IsValid());
    ASSERT_EQ(bd_addr.length() + sizeof(handle) + sizeof(i), acl_view.GetPayload().size());
    auto itr = acl_view.GetPayload().begin();
    ASSERT_EQ(bd_addr, itr.extract<Address>());
    ASSERT_EQ(handle, itr.extract<uint16_t>());
    ASSERT_EQ(i, itr.extract<uint16_t>());
  }
}

TEST_F(HciTest, receiveMultipleIsoPackets) {
  uint16_t handle = 0x0001;
  const uint16_t num_packets = 100;
  IsoPacketBoundaryFlag packet_boundary_flag = IsoPacketBoundaryFlag::COMPLETE_SDU;
  TimeStampFlag timestamp_flag = TimeStampFlag::NOT_PRESENT;
  for (uint16_t i = 0; i < num_packets; i++) {
    auto iso_payload = std::make_unique<RawBuilder>();
    iso_payload->AddOctets2(handle);
    iso_payload->AddOctets2(i);
    hal->callbacks->isoDataReceived(GetPacketBytes(IsoBuilder::Create(
            handle, packet_boundary_flag, timestamp_flag, std::move(iso_payload))));
  }
  for (uint16_t i = 0; i < num_packets; i++) {
    auto iso_opt = upper->GetReceivedIso();
    ASSERT_TRUE(iso_opt.has_value());
    auto iso_view = *iso_opt;
    ASSERT_TRUE(iso_view.IsValid());
    ASSERT_EQ(sizeof(handle) + sizeof(i), iso_view.GetPayload().size());
    auto itr = iso_view.GetPayload().begin();
    ASSERT_EQ(handle, itr.extract<uint16_t>());
    ASSERT_EQ(i, itr.extract<uint16_t>());
  }
}

}  // namespace
}  // namespace hci
}  // namespace bluetooth
